diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 792dce0..792cd37 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,11 +11,13 @@ jobs: runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v7 + with: + submodules: 'true' - name: build toolchain container run: docker build . -t builder - uses: ammaraskar/gcc-problem-matcher@master - name: build Inkay - run: docker run --rm -v ${PWD}:/app -w /app builder + run: docker run --rm -v ${PWD}:${PWD} -w ${PWD} builder - uses: actions/upload-artifact@v7 with: name: inkay diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..c40d066 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "src/ext/libplum"] + path = src/ext/libplum + url = https://github.com/PretendoNetwork/libplum diff --git a/Makefile b/Makefile index fa5360d..55b7692 100644 --- a/Makefile +++ b/Makefile @@ -21,9 +21,9 @@ WUT_ROOT := $(DEVKITPRO)/wut #------------------------------------------------------------------------------- TARGET := Inkay-pretendo BUILD := build -SOURCES := src src/patches src/utils src/ext/inih common +SOURCES := src src/patches src/utils src/ext/inih src/ext/libplum/src common DATA := data -INCLUDES := src src/ext/inih src/lang common +INCLUDES := src src/ext/inih src/ext/libplum/include/plum src/lang common #------------------------------------------------------------------------------- # options for code generation diff --git a/common/wut_ac_missing.h b/common/wut_ac_missing.h new file mode 100644 index 0000000..43f6e82 --- /dev/null +++ b/common/wut_ac_missing.h @@ -0,0 +1,8 @@ +#pragma once + +#include + +NNResult ACGetAssignedAlternativeDns(uint32_t *ip); +NNResult ACGetAssignedGateway(uint32_t *ip); +NNResult ACGetAssignedPreferedDns(uint32_t *ip); // sic +NNResult ACGetAssignedSubnet(uint32_t *ip); diff --git a/src/ext/libplum b/src/ext/libplum new file mode 160000 index 0000000..79e85e6 --- /dev/null +++ b/src/ext/libplum @@ -0,0 +1 @@ +Subproject commit 79e85e61e638e04c10f74f65e1e06957d7658ac7 diff --git a/src/main.cpp b/src/main.cpp index df482b3..1139f0d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -23,6 +23,7 @@ #include "patches/olv_urls.h" #include "patches/game_matchmaking.h" +#include #include #include @@ -189,6 +190,12 @@ WUMS_INITIALIZE() { if (NotificationModule_InitLibrary() != NOTIFICATION_MODULE_RESULT_SUCCESS) { DEBUG_FUNCTION_LINE("NotificationModule_InitLibrary failed"); } + + const plum_config_t plum_config = { + .log_level = PLUM_LOG_LEVEL_VERBOSE, + .log_callback = [](const plum_log_level_t level, const char *message) { DEBUG_FUNCTION_LINE("[PLUM-%d] %s", level, message) }, + }; + plum_init(&plum_config); } WUMS_DEINITIALIZE() { @@ -202,6 +209,8 @@ WUMS_DEINITIALIZE() { NotificationModule_DeInitLibrary(); FunctionPatcher_DeInitLibrary(); + plum_cleanup(); + WHBLogCafeDeinit(); WHBLogUdpDeinit(); } @@ -237,6 +246,7 @@ WUMS_ALL_APPLICATION_STARTS_DONE() { } WUMS_APPLICATION_ENDS() { + peertopeer_notify_titleswitch(); } WUMS_EXPORT_FUNCTION(Inkay_Initialize); diff --git a/src/patches/dns_hooks.cpp b/src/patches/dns_hooks.cpp index a4f0840..2fa2bf3 100644 --- a/src/patches/dns_hooks.cpp +++ b/src/patches/dns_hooks.cpp @@ -34,6 +34,7 @@ constexpr std::pair dns_replacements[] = { static const char * replace_dns_name(const char *dns_name) { if (!Config::connect_to_network) return dns_name; + if (!dns_name) return dns_name; for (auto [original, replacement] : dns_replacements) { if (strcmp(original, dns_name) == 0) diff --git a/src/patches/game_peertopeer.cpp b/src/patches/game_peertopeer.cpp index d986f36..3a54018 100644 --- a/src/patches/game_peertopeer.cpp +++ b/src/patches/game_peertopeer.cpp @@ -13,6 +13,7 @@ #include #include +#include #include "game_peertopeer.h" #include "config.h" @@ -26,6 +27,31 @@ #include using namespace std::string_view_literals; +static std::optional upnp_id; + +static void upnp_cb(int id, plum_state_t state, const plum_mapping_t *mapping) { + DEBUG_FUNCTION_LINE("Plum result %d, %s:%hu", state, mapping->external_host, mapping->external_port); +} + +static void upnp_go() { + const plum_mapping_t mapping = { + .protocol = PLUM_IP_PROTOCOL_UDP, + .internal_port = get_console_peertopeer_port(), + .user_ptr = nullptr, + }; + int id = plum_create_mapping(&mapping, upnp_cb); + if (id < 0) return; + + upnp_id = id; +} + +static void upnp_stop() { + if (!upnp_id) return; + + plum_destroy_mapping(*upnp_id); + upnp_id = std::nullopt; +} + static struct { std::array tid; uint16_t version; @@ -51,24 +77,25 @@ static struct { }, }; -static void generic_peertopeer_patch() { +static bool generic_peertopeer_patch() { uint64_t tid = OSGetTitleID(); uint16_t title_version = 0; if (const auto version_opt = get_current_title_version(); !version_opt) { DEBUG_FUNCTION_LINE("Failed to detect current title version"); - return; + return false; } else { title_version = *version_opt; DEBUG_FUNCTION_LINE("Title version detected: %d", title_version); } + bool result = false; for (const auto &patch: generic_patch_games) { if (std::ranges::find(patch.tid, tid) == patch.tid.end()) continue; std::optional game = search_for_rpl(patch.rpx); if (!game) { DEBUG_FUNCTION_LINE("Couldn't find game rpx! (%s)", patch.rpx.data()); - return; + return false; } if (title_version != patch.version) { @@ -85,19 +112,23 @@ static void generic_peertopeer_patch() { target = (uint16_t *)rpl_addr(*game, patch.max_port_addr); replace_unsigned(target, 0xffff, port); + + result = true; break; } + + return result; } -static void minecraft_peertopeer_patch() { +static bool minecraft_peertopeer_patch() { std::optional minecraft = search_for_rpl("Minecraft.Client.rpx"sv); if (!minecraft) { DEBUG_FUNCTION_LINE("Couldn't find minecraft rpx!"); - return; + return false; } if (const auto version_opt = get_current_title_version(); !version_opt || *version_opt != 688) { DEBUG_FUNCTION_LINE("Wrong mincecraft version detected"); - return; + return false; } auto port = get_console_peertopeer_port(); @@ -112,6 +143,8 @@ static void minecraft_peertopeer_patch() { replace_instruction(&target_func[0], 0x3c600001, 0x3c600000); // li r3, 0 replace_instruction(&target_func[1], 0x3863ffff, 0x60630000 | port); // ori r3, r3, port // blr + + return true; } void peertopeer_patch() { @@ -119,13 +152,21 @@ void peertopeer_patch() { return; } - uint64_t tid = OSGetTitleID(); + bool patched; + const uint64_t tid = OSGetTitleID(); if (tid == 0x00050000'101D7500 || // EUR tid == 0x00050000'101D9D00 || // USA tid == 0x00050000'101DBE00) { // JPN - minecraft_peertopeer_patch(); + patched = minecraft_peertopeer_patch(); } else { - generic_peertopeer_patch(); + patched = generic_peertopeer_patch(); } + + if (patched) + upnp_go(); +} + +void peertopeer_notify_titleswitch() { + upnp_stop(); } diff --git a/src/patches/game_peertopeer.h b/src/patches/game_peertopeer.h index 8211c00..d8dc714 100644 --- a/src/patches/game_peertopeer.h +++ b/src/patches/game_peertopeer.h @@ -14,3 +14,4 @@ #pragma once void peertopeer_patch(); +void peertopeer_notify_titleswitch();