Skip to content

Commit

Permalink
feat(p2p): Port overrides for Splatoon and MK8
Browse files Browse the repository at this point in the history
  • Loading branch information
ashquarky committed Nov 29, 2024
1 parent 727f11d commit a6b91be
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 14 deletions.
55 changes: 51 additions & 4 deletions src/patches/game_peertopeer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,56 @@
#include "utils/replace_mem.h"

#include <optional>
#include <algorithm>
#include <string_view>
using namespace std::string_view_literals;

static struct {
std::array<uint64_t, 3> tid;
uint32_t min_port_addr;
uint32_t max_port_addr;
std::string_view rpx;
} generic_patch_games [] = {
{ // MARIO KART 8
{ 0x00050000'1010ec00, 0x00050000'1010ed00, 0x00050000'1010eb00 },
0x101a9a52,
0x101a9a54,
"Turbo.rpx"sv,
},
{ // Splatoon
{ 0x00050000'10176900, 0x00050000'10176a00, 0x00050000'10162b00 },
0x101e8952,
0x101e8954,
"Gambit.rpx"sv,
},
};

static void generic_peertopeer_patch() {
uint64_t tid = OSGetTitleID();

for (const auto& patch : generic_patch_games) {
if (std::ranges::find(patch.tid, tid) == patch.tid.end()) continue;

std::optional<OSDynLoad_NotifyData> game = search_for_rpl(patch.rpx);
if (!game) {
DEBUG_FUNCTION_LINE("Couldn't find game rpx! (%s)", patch.rpx.data());
return;
}

auto port = get_console_peertopeer_port();
DEBUG_FUNCTION_LINE_VERBOSE("Will use port %d. %08x", port, game->textAddr);

auto target = (uint16_t *)rpl_addr(*game, patch.min_port_addr);
replace_unsigned<uint16_t>(target, 0xc000, port);

target = (uint16_t *)rpl_addr(*game, patch.max_port_addr);
replace_unsigned<uint16_t>(target, 0xffff, port);
break;
}
}

static void minecraft_peertopeer_patch() {
std::optional<OSDynLoad_NotifyData> minecraft = search_for_rpl("Minecraft.Client.rpx");
std::optional<OSDynLoad_NotifyData> minecraft = search_for_rpl("Minecraft.Client.rpx"sv);
if (!minecraft) {
DEBUG_FUNCTION_LINE("Couldn't find minecraft rpx!");
return;
Expand All @@ -33,12 +80,12 @@ static void minecraft_peertopeer_patch() {
auto port = get_console_peertopeer_port();
DEBUG_FUNCTION_LINE_VERBOSE("Will use port %d. %08x", port, minecraft->textAddr);

uint32_t *target_func = rpl_addr(*minecraft, 0x03579530);
auto target_func = (uint32_t *)rpl_addr(*minecraft, 0x03579530);
replace_instruction(&target_func[0], 0x3c600001, 0x3c600000); // li r3, 0
replace_instruction(&target_func[1], 0x3863c000, 0x60630000 | port); // ori r3, r3, port
// blr

target_func = rpl_addr(*minecraft, 0x0357953c);
target_func = (uint32_t *)rpl_addr(*minecraft, 0x0357953c);
replace_instruction(&target_func[0], 0x3c600001, 0x3c600000); // li r3, 0
replace_instruction(&target_func[1], 0x3863ffff, 0x60630000 | port); // ori r3, r3, port
// blr
Expand All @@ -56,6 +103,6 @@ void peertopeer_patch() {

minecraft_peertopeer_patch();
} else {
DEBUG_FUNCTION_LINE_VERBOSE("Game has no p2p patches, will skip.\n");
generic_peertopeer_patch();
}
}
25 changes: 19 additions & 6 deletions src/utils/replace_mem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,17 +73,30 @@ void replaceBulk(uint32_t start, uint32_t size, std::span<const replacement> rep
#endif
}

bool replace_instruction(uint32_t *inst, uint32_t orignal_value, uint32_t new_value) {
if (*inst != orignal_value) return false;
template <typename U>
requires std::integral<U>
bool replace_unsigned(U *addr, U original_value, U new_value) {
if (*addr != original_value) return false;

KernelCopyData(
OSEffectiveToPhysical((uint32_t) inst),
OSEffectiveToPhysical((uint32_t) addr),
OSEffectiveToPhysical((uint32_t) &new_value),
sizeof(new_value)
);
DCFlushRange(inst, sizeof(new_value));
ICInvalidateRange(inst, sizeof(new_value));
DCFlushRange(addr, sizeof(new_value));

DEBUG_FUNCTION_LINE_VERBOSE("%08x is now %08x", inst, *inst);
return *inst == new_value;
return *addr == new_value;
}
template bool replace_unsigned<uint64_t>(uint64_t *, uint64_t, uint64_t);
template bool replace_unsigned<uint32_t>(uint32_t *, uint32_t, uint32_t);
template bool replace_unsigned<uint16_t>(uint16_t *, uint16_t, uint16_t);
template bool replace_unsigned<uint8_t>(uint8_t *, uint8_t, uint8_t);

bool replace_instruction(uint32_t *inst, uint32_t original_value, uint32_t new_value) {
bool res = replace_unsigned<uint32_t>(inst, original_value, new_value);
if (!res) return res;

ICInvalidateRange(inst, sizeof(new_value));
return true;
}
6 changes: 5 additions & 1 deletion src/utils/replace_mem.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,8 @@ struct replacement {

void replaceBulk(uint32_t start, uint32_t size, std::span<const replacement> replacements);

bool replace_instruction(uint32_t *inst, uint32_t orignal_value, uint32_t new_value);
template <typename U>
requires std::integral<U>
bool replace_unsigned(U *addr, U original_value, U new_value);

bool replace_instruction(uint32_t *inst, uint32_t original_value, uint32_t new_value);
6 changes: 3 additions & 3 deletions src/utils/rpl_info.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@

std::optional<OSDynLoad_NotifyData> search_for_rpl(std::string_view name);

constexpr uint32_t *rpl_addr(OSDynLoad_NotifyData rpl, uint32_t cemu_addr) {
constexpr void *rpl_addr(OSDynLoad_NotifyData rpl, uint32_t cemu_addr) {
if (cemu_addr < 0x1000'0000) {
return (uint32_t *)(rpl.textAddr + cemu_addr - 0x0200'0000);
return (void *)(rpl.textAddr + cemu_addr - 0x0200'0000);
} else {
return (uint32_t *)(rpl.dataAddr + cemu_addr - 0x1000'0000);
return (void *)(rpl.dataAddr + cemu_addr - 0x1000'0000);
}
}

0 comments on commit a6b91be

Please sign in to comment.