From f4aeee80341a5272af303fc21a26a24ed63a751e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20L=C3=B3pez=20Guimaraes?= Date: Sat, 19 Oct 2024 19:10:08 +0100 Subject: [PATCH 1/9] feat!: Split Inkay into a module and a plugin This is necessary for a future Aroma feature. This also makes more clear the immutability of the patches that Pretendo requires, since they cannot be reverted easily. All patching code is now managed inside the module, which the plugin triggers by calling an exported function from it. The WWP reset code remains within the plugin as it isn't strictly tied to the patches. --- .github/workflows/ci.yml | 6 +- .gitignore | 6 +- Dockerfile | 3 +- Makefile | 45 +++--- plugin/Makefile | 148 ++++++++++++++++++ plugin/src/Notification.cpp | 31 ++++ plugin/src/Notification.h | 3 + plugin/src/config.cpp | 258 +++++++++++++++++++++++++++++++ plugin/src/config.h | 42 +++++ plugin/src/main.cpp | 92 +++++++++++ plugin/src/module.cpp | 38 +++++ plugin/src/module.h | 19 +++ plugin/src/utils/logger.h | 36 +++++ plugin/src/utils/sysconfig.cpp | 57 +++++++ plugin/src/utils/sysconfig.h | 12 ++ plugin/src/wut_extra.h | 41 +++++ src/config.cpp | 209 +------------------------ src/config.h | 11 -- src/main.cpp | 78 ++++++---- src/patches/account_settings.cpp | 27 +++- src/patches/account_settings.h | 3 +- src/patches/dns_hooks.cpp | 35 ++++- src/patches/dns_hooks.h | 20 +++ src/patches/eshop_applet.cpp | 29 +++- src/patches/eshop_applet.h | 20 +++ src/patches/game_matchmaking.cpp | 2 +- src/patches/olv_applet.cpp | 29 +++- src/patches/olv_applet.h | 20 +++ src/patches/olv_urls.cpp | 2 +- src/utils/logger.h | 6 +- 30 files changed, 1034 insertions(+), 294 deletions(-) create mode 100644 plugin/Makefile create mode 100644 plugin/src/Notification.cpp create mode 100644 plugin/src/Notification.h create mode 100644 plugin/src/config.cpp create mode 100644 plugin/src/config.h create mode 100644 plugin/src/main.cpp create mode 100644 plugin/src/module.cpp create mode 100644 plugin/src/module.h create mode 100644 plugin/src/utils/logger.h create mode 100644 plugin/src/utils/sysconfig.cpp create mode 100644 plugin/src/utils/sysconfig.h create mode 100644 plugin/src/wut_extra.h create mode 100644 src/patches/dns_hooks.h create mode 100644 src/patches/eshop_applet.h create mode 100644 src/patches/olv_applet.h diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index adfbbeb..60c8bf2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,13 +6,13 @@ jobs: build-inkay: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - 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 - - uses: actions/upload-artifact@master + - uses: actions/upload-artifact@v4 with: name: inkay - path: "*.wps" + path: dist/ diff --git a/.gitignore b/.gitignore index 982b963..3f9ac48 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,11 @@ +.cache/ .vscode/ .idea/ /build +/plugin/build +/dist *.elf +*.wms *.wps certs/ -*.lst \ No newline at end of file +*.lst diff --git a/Dockerfile b/Dockerfile index 4147038..0f51ffa 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,7 +4,8 @@ COPY --from=ghcr.io/wiiu-env/libnotifications:20240426 /artifacts $DEVKITPRO COPY --from=ghcr.io/wiiu-env/libfunctionpatcher:20230621 /artifacts $DEVKITPRO COPY --from=ghcr.io/wiiu-env/libkernel:20230621 /artifacts $DEVKITPRO COPY --from=ghcr.io/wiiu-env/libmocha:20231127 /artifacts $DEVKITPRO +COPY --from=ghcr.io/wiiu-env/wiiumodulesystem:20240424 /artifacts $DEVKITPRO COPY --from=ghcr.io/wiiu-env/wiiupluginsystem:20240505 /artifacts $DEVKITPRO WORKDIR /app -CMD make -f Makefile -j$(nproc) \ No newline at end of file +CMD make -f Makefile -j$(nproc) diff --git a/Makefile b/Makefile index 2d63adc..c645f43 100644 --- a/Makefile +++ b/Makefile @@ -8,10 +8,10 @@ endif TOPDIR ?= $(CURDIR) -include $(DEVKITPRO)/wups/share/wups_rules +include $(DEVKITPRO)/wums/share/wums_rules -WUT_ROOT := $(DEVKITPRO)/wut WUMS_ROOT := $(DEVKITPRO)/wums +WUT_ROOT := $(DEVKITPRO)/wut #------------------------------------------------------------------------------- # TARGET is the name of the output # BUILD is the directory where object files & intermediate files will be placed @@ -24,34 +24,32 @@ BUILD := build SOURCES := src src/patches src/utils src/ext/inih DATA := data INCLUDES := src src/ext/inih -#DEBUG := 1 #------------------------------------------------------------------------------- # options for code generation #------------------------------------------------------------------------------- -CFLAGS := -Wall -O2 -ffunction-sections -fdata-sections \ +CFLAGS := -Wall -Wextra -O2 -ffunction-sections\ $(MACHDEP) -CFLAGS += $(INCLUDE) -D__WIIU__ -D__WUT__ -D__WUPS__ - -ifeq ($(DEBUG),1) - CFLAGS += -DDEBUG -g -endif +CFLAGS += $(INCLUDE) -D__WIIU__ -D__WUT__ CXXFLAGS := $(CFLAGS) -std=c++20 ASFLAGS := -g $(ARCH) -LDFLAGS = -g $(ARCH) $(RPXSPECS) -Wl,-Map,$(notdir $*.map) -Wl,-gc-sections +LDFLAGS = -g $(ARCH) $(RPXSPECS) -Wl,-Map,$(notdir $*.map) -T$(WUMS_ROOT)/share/libkernel.ld $(WUMSSPECS) -LDFLAGS += -T$(WUMS_ROOT)/share/libkernel.ld $(WUPSSPECS) +ifeq ($(DEBUG),1) +CXXFLAGS += -DDEBUG -g +CFLAGS += -DDEBUG -g +endif -LIBS := -lwups -lmocha -lkernel -lwut -lnotifications -lfunctionpatcher +LIBS := -lwums -lmocha -lkernel -lwut -lfunctionpatcher -lnotifications #------------------------------------------------------------------------------- # list of directories containing libraries, this must be the top level # containing include and lib #------------------------------------------------------------------------------- -LIBDIRS := $(PORTLIBS) $(WUMS_ROOT) $(WUPS_ROOT) $(WUT_ROOT) $(WUT_ROOT)/usr +LIBDIRS := $(PORTLIBS) $(WUT_ROOT) $(WUMS_ROOT) $(WUT_ROOT)/usr #------------------------------------------------------------------------------- # no real need to edit anything past this point unless you need to add additional @@ -103,14 +101,20 @@ export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) #------------------------------------------------------------------------------- all: $(BUILD) + $(BUILD): - @$(shell [ ! -d $(BUILD) ] && mkdir -p $(BUILD)) + @[ -d $@ ] || mkdir -p $@ @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile + @$(MAKE) --no-print-directory -C $(CURDIR)/plugin -f $(CURDIR)/plugin/Makefile + mkdir -p dist/ + cp *.wms dist/ + cp plugin/*.wps dist/ #------------------------------------------------------------------------------- clean: @echo clean ... - @rm -fr $(BUILD) $(TARGET).wps $(TARGET).elf + @rm -fr dist $(BUILD) $(TARGET).wms $(TARGET).elf + @$(MAKE) --no-print-directory -C $(CURDIR)/plugin -f $(CURDIR)/plugin/Makefile clean #------------------------------------------------------------------------------- else @@ -121,10 +125,10 @@ DEPENDS := $(OFILES:.o=.d) #------------------------------------------------------------------------------- # main targets #------------------------------------------------------------------------------- -all : $(OUTPUT).wps +all : $(OUTPUT).wms -$(OUTPUT).wps : $(OUTPUT).elf -$(OUTPUT).elf : $(OFILES) +$(OUTPUT).wms : $(OUTPUT).elf +$(OUTPUT).elf : $(OFILES) $(OFILES_SRC) : $(HFILES_BIN) @@ -141,6 +145,11 @@ $(OFILES_SRC) : $(HFILES_BIN) @echo $(notdir $<) @$(bin2o) +#--------------------------------------------------------------------------------- +%.o: %.s + @echo $(notdir $<) + @$(CC) -MMD -MP -MF $(DEPSDIR)/$*.d -x assembler-with-cpp $(ASFLAGS) -c $< -o $@ $(ERROR_FILTER) + -include $(DEPENDS) #------------------------------------------------------------------------------- diff --git a/plugin/Makefile b/plugin/Makefile new file mode 100644 index 0000000..125fb0c --- /dev/null +++ b/plugin/Makefile @@ -0,0 +1,148 @@ +#------------------------------------------------------------------------------- +.SUFFIXES: +#------------------------------------------------------------------------------- + +ifeq ($(strip $(DEVKITPRO)),) +$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=/devkitpro") +endif + +TOPDIR ?= $(CURDIR) + +include $(DEVKITPRO)/wups/share/wups_rules + +WUT_ROOT := $(DEVKITPRO)/wut +WUMS_ROOT := $(DEVKITPRO)/wums +#------------------------------------------------------------------------------- +# TARGET is the name of the output +# BUILD is the directory where object files & intermediate files will be placed +# SOURCES is a list of directories containing source code +# DATA is a list of directories containing data files +# INCLUDES is a list of directories containing header files +#------------------------------------------------------------------------------- +TARGET := Inkay-pretendo +BUILD := build +SOURCES := src src/utils +DATA := data +INCLUDES := src ../src/lang +#DEBUG := 1 + +#------------------------------------------------------------------------------- +# options for code generation +#------------------------------------------------------------------------------- +CFLAGS := -Wall -O2 -ffunction-sections -fdata-sections \ + $(MACHDEP) + +CFLAGS += $(INCLUDE) -D__WIIU__ -D__WUT__ -D__WUPS__ + +ifeq ($(DEBUG),1) + CFLAGS += -DDEBUG -g +endif + +CXXFLAGS := $(CFLAGS) -std=c++20 + +ASFLAGS := -g $(ARCH) +LDFLAGS = -g $(ARCH) $(RPXSPECS) -Wl,-Map,$(notdir $*.map) -Wl,-gc-sections + +LDFLAGS += $(WUPSSPECS) + +LIBS := -lwups -lwut -lnotifications + +#------------------------------------------------------------------------------- +# list of directories containing libraries, this must be the top level +# containing include and lib +#------------------------------------------------------------------------------- +LIBDIRS := $(PORTLIBS) $(WUMS_ROOT) $(WUPS_ROOT) $(WUT_ROOT) + +#------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#------------------------------------------------------------------------------- +ifneq ($(BUILD),$(notdir $(CURDIR))) +#------------------------------------------------------------------------------- + +export OUTPUT := $(CURDIR)/$(TARGET) +export TOPDIR := $(CURDIR) + +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ + $(foreach dir,$(DATA),$(CURDIR)/$(dir)) + +export DEPSDIR := $(CURDIR)/$(BUILD) + +CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) +CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) +SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) +BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) + +#------------------------------------------------------------------------------- +# use CXX for linking C++ projects, CC for standard C +#------------------------------------------------------------------------------- +ifeq ($(strip $(CPPFILES)),) +#------------------------------------------------------------------------------- + export LD := $(CC) +#------------------------------------------------------------------------------- +else +#------------------------------------------------------------------------------- + export LD := $(CXX) +#------------------------------------------------------------------------------- +endif +#------------------------------------------------------------------------------- + +export OFILES_BIN := $(addsuffix .o,$(BINFILES)) +export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) +export OFILES := $(OFILES_BIN) $(OFILES_SRC) +export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES))) + +export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + -I$(CURDIR)/$(BUILD) + +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) + +.PHONY: $(BUILD) clean all + +#------------------------------------------------------------------------------- +all: $(BUILD) + +$(BUILD): + @$(shell [ ! -d $(BUILD) ] && mkdir -p $(BUILD)) + @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile + +#------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(BUILD) $(TARGET).wps $(TARGET).elf + +#------------------------------------------------------------------------------- +else +.PHONY: all + +DEPENDS := $(OFILES:.o=.d) + +#------------------------------------------------------------------------------- +# main targets +#------------------------------------------------------------------------------- +all : $(OUTPUT).wps + +$(OUTPUT).wps : $(OUTPUT).elf +$(OUTPUT).elf : $(OFILES) + +$(OFILES_SRC) : $(HFILES_BIN) + +#------------------------------------------------------------------------------- +# you need a rule like this for each extension you use as binary data +#------------------------------------------------------------------------------- +%.bin.o %_bin.h : %.bin +#------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + +%.pem.o %_pem.h : %.pem +#------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + +-include $(DEPENDS) + +#------------------------------------------------------------------------------- +endif +#------------------------------------------------------------------------------- diff --git a/plugin/src/Notification.cpp b/plugin/src/Notification.cpp new file mode 100644 index 0000000..cc6177e --- /dev/null +++ b/plugin/src/Notification.cpp @@ -0,0 +1,31 @@ +/* Copyright 2024 Pretendo Network contributors + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "Notification.h" +#include +#include + +void ShowNotification(const char* notification) { + auto err1 = NotificationModule_SetDefaultValue(NOTIFICATION_MODULE_NOTIFICATION_TYPE_INFO, + NOTIFICATION_MODULE_DEFAULT_OPTION_KEEP_UNTIL_SHOWN, true); + auto err2 = NotificationModule_SetDefaultValue(NOTIFICATION_MODULE_NOTIFICATION_TYPE_INFO, + NOTIFICATION_MODULE_DEFAULT_OPTION_DURATION_BEFORE_FADE_OUT, + 15.0f); + + if (err1 != NOTIFICATION_MODULE_RESULT_SUCCESS || err2 != NOTIFICATION_MODULE_RESULT_SUCCESS) return; + + NotificationModule_AddInfoNotification(notification); +} diff --git a/plugin/src/Notification.h b/plugin/src/Notification.h new file mode 100644 index 0000000..ebdc7a3 --- /dev/null +++ b/plugin/src/Notification.h @@ -0,0 +1,3 @@ +#pragma once + +void ShowNotification(const char* notification); diff --git a/plugin/src/config.cpp b/plugin/src/config.cpp new file mode 100644 index 0000000..a0fc590 --- /dev/null +++ b/plugin/src/config.cpp @@ -0,0 +1,258 @@ +/* Copyright 2022 Pretendo Network contributors + Copyright 2022 Ash Logan + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "config.h" + +#include "wut_extra.h" +#include "utils/logger.h" +#include "utils/sysconfig.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +bool Config::connect_to_network = true; +bool Config::need_relaunch = false; +bool Config::unregister_task_item_pressed = false; +bool Config::is_wiiu_menu = false; + +static config_strings strings; + +config_strings get_config_strings(nn::swkbd::LanguageType language) { + switch (language) { + case nn::swkbd::LanguageType::English: + default: return { +#include "en_US.lang" + }; + case nn::swkbd::LanguageType::Spanish: return { +#include "es_ES.lang" + }; + case nn::swkbd::LanguageType::French: return { +#include "fr_FR.lang" + }; + case nn::swkbd::LanguageType::Italian: return { +#include "it_IT.lang" + }; + case nn::swkbd::LanguageType::German: return { +#include "de_DE.lang" + }; + case nn::swkbd::LanguageType::SimplifiedChinese: return { +#include "zh_CN.lang" + }; + case nn::swkbd::LanguageType::TraditionalChinese: return { +#include "zh_Hant.lang" + }; + case nn::swkbd::LanguageType::Portuguese: return { +#include "pt_BR.lang" + }; + case nn::swkbd::LanguageType::Japanese: return { +#include "ja_JP.lang" + }; + case nn::swkbd::LanguageType::Dutch: return { +#include "nl_NL.lang" + }; + case nn::swkbd::LanguageType::Russian: return { +#include "ru_RU.lang" + }; + } +} + +static WUPSConfigAPICallbackStatus report_error(WUPSConfigAPIStatus err) { + DEBUG_FUNCTION_LINE_VERBOSE("WUPS config error: %s", WUPSConfigAPI_GetStatusStr(err)); + return WUPSCONFIG_API_CALLBACK_RESULT_ERROR; +} + +static void report_storage_error(WUPSStorageError err) { + DEBUG_FUNCTION_LINE_VERBOSE("WUPS storage error: %s", WUPSStorageAPI_GetStatusStr(err)); +} + +static void connect_to_network_changed(ConfigItemBoolean* item, bool new_value) { + DEBUG_FUNCTION_LINE_VERBOSE("connect_to_network changed to: %d", new_value); + if (new_value != Config::connect_to_network) { + Config::need_relaunch = true; + } + Config::connect_to_network = new_value; + + WUPSStorageError res; + res = WUPSStorageAPI::Store("connect_to_network", Config::connect_to_network); + if (res != WUPS_STORAGE_ERROR_SUCCESS) return report_storage_error(res); +} + +static void unregister_task_item_on_input_cb(void *context, WUPSConfigSimplePadData input) { + if (!Config::unregister_task_item_pressed && Config::is_wiiu_menu && ((input.buttons_d & WUPS_CONFIG_BUTTON_A) == WUPS_CONFIG_BUTTON_A)) { + + nn::act::Initialize(); + Initialize__Q2_2nn4bossFv(); + + for (uint8_t i = 1; i <= nn::act::GetNumOfAccounts(); i++) + { + if (nn::act::IsSlotOccupied(i) && nn::act::IsNetworkAccountEx(i)) + { + nn::boss::Task task{}; + nn::act::PersistentId persistentId = nn::act::GetPersistentIdEx(i); + + __ct__Q3_2nn4boss4TaskFv(&task); + Initialize__Q3_2nn4boss4TaskFPCcUi(&task, "oltopic", persistentId); + + // bypasses compiler warning about unused variable + #ifdef DEBUG + uint32_t res = Unregister__Q3_2nn4boss4TaskFv(&task); + DEBUG_FUNCTION_LINE_VERBOSE("Unregistered oltopic for: SlotNo %d | Persistent ID %08x -> 0x%08x", i, persistentId, res); + #else + Unregister__Q3_2nn4boss4TaskFv(&task); + #endif + } + } + + Finalize__Q2_2nn4bossFv(); + nn::act::Finalize(); + + Config::unregister_task_item_pressed = !Config::unregister_task_item_pressed; + Config::need_relaunch = true; + } +} + +static int32_t unregister_task_item_get_display_value(void *context, char *out_buf, int32_t out_size) { + auto string = strings.need_menu_action; + if (Config::is_wiiu_menu) { + if (Config::unregister_task_item_pressed) { + string = strings.restart_to_apply_action; + } else { + string = strings.press_a_action; + } + } + + if ((int)string.length() > out_size - 1) return -1; + string.copy(out_buf, string.length()); + out_buf[string.length()] = '\0'; + + return 0; +} + +static WUPSConfigAPICallbackStatus ConfigMenuOpenedCallback(WUPSConfigCategoryHandle rootHandle) { + WUPSConfigAPIStatus err; + bool res; + + uint64_t current_title_id = OSGetTitleID(); + uint64_t wiiu_menu_tid = _SYSGetSystemApplicationTitleId(SYSTEM_APP_ID_WII_U_MENU); + Config::is_wiiu_menu = (current_title_id == wiiu_menu_tid); + + // get translation strings + strings = get_config_strings(get_system_language()); + + // create root config category + WUPSConfigCategory root = WUPSConfigCategory(rootHandle); + + auto network_cat = WUPSConfigCategory::Create(strings.network_category, err); + if (!network_cat) return report_error(err); + + // config id display name default current value changed callback + auto connect_item = WUPSConfigItemBoolean::Create("connect_to_network", strings.connect_to_network_setting, true, Config::connect_to_network, &connect_to_network_changed, err); + if (!connect_item) return report_error(err); + + res = network_cat->add(std::move(*connect_item), err); + if (!res) return report_error(err); + + res = root.add(std::move(*network_cat), err); + if (!res) return report_error(err); + + auto other_cat = WUPSConfigCategory::Create(strings.other_category, err); + if (!other_cat) return report_error(err); + + WUPSConfigAPIItemCallbacksV2 unregisterTasksItemCallbacks = { + .getCurrentValueDisplay = unregister_task_item_get_display_value, + .getCurrentValueSelectedDisplay = unregister_task_item_get_display_value, + .onSelected = nullptr, + .restoreDefault = nullptr, + .isMovementAllowed = nullptr, + .onCloseCallback = nullptr, + .onInput = unregister_task_item_on_input_cb, + .onInputEx = nullptr, + .onDelete = nullptr + }; + + WUPSConfigAPIItemOptionsV2 unregisterTasksItemOptions = { + .displayName = strings.reset_wwp_setting.data(), + .context = nullptr, + .callbacks = unregisterTasksItemCallbacks, + }; + + WUPSConfigItemHandle unregisterTasksItem; + err = WUPSConfigAPI_Item_Create(unregisterTasksItemOptions, &unregisterTasksItem); + if (err != WUPSCONFIG_API_RESULT_SUCCESS) return report_error(err); + + err = WUPSConfigAPI_Category_AddItem(other_cat->getHandle(), unregisterTasksItem); + if (err != WUPSCONFIG_API_RESULT_SUCCESS) return report_error(err); + + res = root.add(std::move(*other_cat), err); + if (!res) return report_error(err); + + return WUPSCONFIG_API_CALLBACK_RESULT_SUCCESS; +} + +static void ConfigMenuClosedCallback() { + // Save all changes + WUPSStorageError res; + res = WUPSStorageAPI::SaveStorage(); + if (res != WUPS_STORAGE_ERROR_SUCCESS) return report_storage_error(res); + + if (Config::need_relaunch) { + // Need to reload the console so the patches reset + OSForceFullRelaunch(); + SYSLaunchMenu(); + Config::need_relaunch = false; + } +} + +void Config::Init() { + WUPSConfigAPIStatus cres; + + // Init the config api + WUPSConfigAPIOptionsV1 configOptions = { .name = "Inkay" }; + cres = WUPSConfigAPI_Init(configOptions, ConfigMenuOpenedCallback, ConfigMenuClosedCallback); + if (cres != WUPSCONFIG_API_RESULT_SUCCESS) return (void)report_error(cres); + + WUPSStorageError res; + // Try to get value from storage + res = WUPSStorageAPI::Get("connect_to_network", Config::connect_to_network); + if (res == WUPS_STORAGE_ERROR_NOT_FOUND) { + DEBUG_FUNCTION_LINE("Connect to network value not found, attempting to migrate/create"); + + bool skipPatches = false; + if (WUPSStorageAPI::Get("skipPatches", skipPatches) == WUPS_STORAGE_ERROR_SUCCESS) { + // Migrate old config value + Config::connect_to_network = !skipPatches; + WUPSStorageAPI::DeleteItem("skipPatches"); + } + + // Add the value to the storage if it's missing. + res = WUPSStorageAPI::Store("connect_to_network", connect_to_network); + if (res != WUPS_STORAGE_ERROR_SUCCESS) return report_storage_error(res); + } + else if (res != WUPS_STORAGE_ERROR_SUCCESS) return report_storage_error(res); + + // Save storage + res = WUPSStorageAPI::SaveStorage(); + if (res != WUPS_STORAGE_ERROR_SUCCESS) return report_storage_error(res); +} diff --git a/plugin/src/config.h b/plugin/src/config.h new file mode 100644 index 0000000..2fa9812 --- /dev/null +++ b/plugin/src/config.h @@ -0,0 +1,42 @@ +// +// Created by ash on 10/12/22. +// + +#ifndef INKAY_CONFIG_H +#define INKAY_CONFIG_H + +#include +#include + +class Config { +public: + static void Init(); + + // wups config items + static bool connect_to_network; + + // private stuff + static bool need_relaunch; + + // private stuff + static bool is_wiiu_menu; + + static bool unregister_task_item_pressed; +}; + +struct config_strings { + const char *plugin_name; + std::string_view network_category; + std::string_view connect_to_network_setting; + std::string_view other_category; + std::string_view reset_wwp_setting; + std::string_view press_a_action; + std::string_view restart_to_apply_action; + std::string_view need_menu_action; + std::string_view using_nintendo_network; + std::string_view using_pretendo_network; +}; + +config_strings get_config_strings(nn::swkbd::LanguageType language); + +#endif //INKAY_CONFIG_H diff --git a/plugin/src/main.cpp b/plugin/src/main.cpp new file mode 100644 index 0000000..5cb5b19 --- /dev/null +++ b/plugin/src/main.cpp @@ -0,0 +1,92 @@ +/* Copyright 2022 Pretendo Network contributors + Copyright 2022 Ash Logan + Copyright 2019 Maschell + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "config.h" +#include "module.h" +#include "Notification.h" + +#include +#include +#include +#include +#include + +#include + +#define INKAY_VERSION "v2.6.0" + +/** + Mandatory plugin information. + If not set correctly, the loader will refuse to use the plugin. +**/ +WUPS_PLUGIN_NAME("Inkay"); +WUPS_PLUGIN_DESCRIPTION("Pretendo Network Patcher"); +WUPS_PLUGIN_VERSION(INKAY_VERSION); +WUPS_PLUGIN_AUTHOR("Pretendo contributors"); +WUPS_PLUGIN_LICENSE("GPLv3"); + +WUPS_USE_STORAGE("inkay"); + +WUPS_USE_WUT_DEVOPTAB(); + +#include "utils/sysconfig.h" + +INITIALIZE_PLUGIN() { + WHBLogCafeInit(); + WHBLogUdpInit(); + + Config::Init(); + + if (NotificationModule_InitLibrary() != NOTIFICATION_MODULE_RESULT_SUCCESS) { + DEBUG_FUNCTION_LINE("NotificationModule_InitLibrary failed"); + } + + // if using pretendo then (try to) apply the ssl patches + Inkay_Initialize(Config::connect_to_network); +} + +DEINITIALIZE_PLUGIN() { + NotificationModule_DeInitLibrary(); + + WHBLogCafeDeinit(); + WHBLogUdpDeinit(); +} + +ON_APPLICATION_START() { + +} + +ON_APPLICATION_ENDS() { + +} diff --git a/plugin/src/module.cpp b/plugin/src/module.cpp new file mode 100644 index 0000000..6a201fa --- /dev/null +++ b/plugin/src/module.cpp @@ -0,0 +1,38 @@ +/* Copyright 2024 Pretendo Network contributors + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include + +#include "utils/logger.h" + +void Inkay_Initialize(bool apply_patches) { + OSDynLoad_Module module; + void (*moduleInitialize)(bool) = nullptr; + + if (OSDynLoad_Acquire("inkay", &module) != OS_DYNLOAD_OK) { + DEBUG_FUNCTION_LINE("Failed to acquire module"); + return; + } + + if (OSDynLoad_FindExport(module, OS_DYNLOAD_EXPORT_FUNC, "Inkay_Initialize", reinterpret_cast(&moduleInitialize)) != OS_DYNLOAD_OK) { + DEBUG_FUNCTION_LINE("Failed to find initialization function"); + return; + } + + moduleInitialize(apply_patches); + + OSDynLoad_Release(module); +} diff --git a/plugin/src/module.h b/plugin/src/module.h new file mode 100644 index 0000000..3da8b0a --- /dev/null +++ b/plugin/src/module.h @@ -0,0 +1,19 @@ +/* Copyright 2024 Pretendo Network contributors + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#pragma once + +void Inkay_Initialize(bool apply_patches); diff --git a/plugin/src/utils/logger.h b/plugin/src/utils/logger.h new file mode 100644 index 0000000..f7278b6 --- /dev/null +++ b/plugin/src/utils/logger.h @@ -0,0 +1,36 @@ +#pragma once + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define __FILENAME_X__ (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__) +#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILENAME_X__) + +#define OSFATAL_FUNCTION_LINE(FMT, ARGS...)do { \ + OSFatal_printf("[(P) Inkay][%23s]%30s@L%04d: " FMT "",__FILENAME__,__FUNCTION__, __LINE__, ## ARGS); \ + } while (0) + +#define DEBUG_FUNCTION_LINE(FMT, ARGS...)do { \ + WHBLogPrintf("[(P) Inkay][%23s]%30s@L%04d: " FMT "",__FILENAME__,__FUNCTION__, __LINE__, ## ARGS); \ + } while (0); + +#define DEBUG_FUNCTION_LINE_WRITE(FMT, ARGS...)do { \ + WHBLogWritef("[(P) Inkay][%23s]%30s@L%04d: " FMT "",__FILENAME__,__FUNCTION__, __LINE__, ## ARGS); \ + } while (0); + +#ifdef DEBUG +#define DEBUG_FUNCTION_LINE_VERBOSE(FMT, ARGS...) DEBUG_FUNCTION_LINE(FMT, ##ARGS) +#else +#define DEBUG_FUNCTION_LINE_VERBOSE(FMT, ARGS...) while (0); +#endif + +#ifdef __cplusplus +} +#endif diff --git a/plugin/src/utils/sysconfig.cpp b/plugin/src/utils/sysconfig.cpp new file mode 100644 index 0000000..cef6d78 --- /dev/null +++ b/plugin/src/utils/sysconfig.cpp @@ -0,0 +1,57 @@ +/* Copyright 2024 Pretendo Network contributors + Copyright 2024 Ash Logan + Copyright 2020-2022 V10lator + Copyright 2022 Xpl0itU + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "sysconfig.h" +#include "utils/logger.h" + +#include +#include + +nn::swkbd::LanguageType get_system_language() { + static std::optional cached_language{}; + if (cached_language) return *cached_language; + + UCHandle handle = UCOpen(); + if (handle >= 0) { + nn::swkbd::LanguageType language; + + UCSysConfig settings __attribute__((__aligned__(0x40))) = { + .name = "cafe.language", + .access = 0, + .dataType = UC_DATATYPE_UNSIGNED_INT, + .error = UC_ERROR_OK, + .dataSize = sizeof(language), + .data = &language, + }; + + UCError err = UCReadSysConfig(handle, 1, &settings); + UCClose(handle); + if (err != UC_ERROR_OK) { + DEBUG_FUNCTION_LINE("Error reading UC: %d!", err); + return nn::swkbd::LanguageType::English; + } else { + DEBUG_FUNCTION_LINE_VERBOSE("System language found: %d", language); + cached_language = language; + return language; + } + } else { + DEBUG_FUNCTION_LINE("Error opening UC: %d", handle); + return nn::swkbd::LanguageType::English; + } +} diff --git a/plugin/src/utils/sysconfig.h b/plugin/src/utils/sysconfig.h new file mode 100644 index 0000000..3bac817 --- /dev/null +++ b/plugin/src/utils/sysconfig.h @@ -0,0 +1,12 @@ +// +// Created by ash on 9/04/24. +// + +#ifndef INKAY_SYSCONFIG_H +#define INKAY_SYSCONFIG_H + +#include + +nn::swkbd::LanguageType get_system_language(); + +#endif //INKAY_SYSCONFIG_H diff --git a/plugin/src/wut_extra.h b/plugin/src/wut_extra.h new file mode 100644 index 0000000..b6a65c3 --- /dev/null +++ b/plugin/src/wut_extra.h @@ -0,0 +1,41 @@ +#pragma once + +#include +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +namespace nn::boss { + class Task { + public: + nn::act::PersistentId persistentId; + uint32_t unk1; + char task_name[8]; + uint64_t title_id; + uint32_t unk2; + uint32_t unk3; + }; + + static_assert(sizeof(Task) == 32, "nn::boss::Task must be 32 bytes."); +} + +extern "C" uint32_t Initialize__Q2_2nn4bossFv(); +extern "C" uint32_t Finalize__Q2_2nn4bossFv(); + +extern "C" void __ct__Q3_2nn4boss4TaskFv(nn::boss::Task *task); +extern "C" uint32_t Initialize__Q3_2nn4boss4TaskFPCcUi(nn::boss::Task *task, char const *, unsigned int); +extern "C" uint32_t Unregister__Q3_2nn4boss4TaskFv(nn::boss::Task *task); +extern "C" void __dt__Q3_2nn4boss4TaskFv(nn::boss::Task *task); +extern "C" uint32_t StartScheduling__Q3_2nn4boss4TaskFb(nn::boss::Task *task, bool queueTaskOnCall); +extern "C" uint32_t GetState__Q3_2nn4boss4TaskCFPUi(nn::boss::Task *task, uint32_t *outExecCount); +extern "C" uint32_t Run__Q3_2nn4boss4TaskFb(nn::boss::Task *task, bool unk); +extern "C" uint32_t UpdateIntervalSec__Q3_2nn4boss4TaskFUi(nn::boss::Task *task, uint32_t seconds); +extern "C" bool IsRegistered__Q3_2nn4boss4TaskCFv(nn::boss::Task *task); + +#ifdef __cplusplus +} +#endif diff --git a/src/config.cpp b/src/config.cpp index d7e6ffc..4923515 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -17,29 +17,7 @@ #include "config.h" -#include "wut_extra.h" -#include "utils/logger.h" -#include "utils/sysconfig.h" -#include "patches/game_peertopeer.h" - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include - -bool Config::connect_to_network = true; -bool Config::need_relaunch = false; -bool Config::unregister_task_item_pressed = false; -bool Config::is_wiiu_menu = false; +bool Config::connect_to_network = false; static config_strings strings; @@ -81,188 +59,3 @@ config_strings get_config_strings(nn::swkbd::LanguageType language) { }; } } - -static WUPSConfigAPICallbackStatus report_error(WUPSConfigAPIStatus err) { - DEBUG_FUNCTION_LINE_VERBOSE("WUPS config error: %s", WUPSConfigAPI_GetStatusStr(err)); - return WUPSCONFIG_API_CALLBACK_RESULT_ERROR; -} - -static void report_storage_error(WUPSStorageError err) { - DEBUG_FUNCTION_LINE_VERBOSE("WUPS storage error: %s", WUPSStorageAPI_GetStatusStr(err)); -} - -static void connect_to_network_changed(ConfigItemBoolean* item, bool new_value) { - DEBUG_FUNCTION_LINE_VERBOSE("connect_to_network changed to: %d", new_value); - if (new_value != Config::connect_to_network) { - Config::need_relaunch = true; - } - Config::connect_to_network = new_value; - - WUPSStorageError res; - res = WUPSStorageAPI::Store("connect_to_network", Config::connect_to_network); - if (res != WUPS_STORAGE_ERROR_SUCCESS) return report_storage_error(res); -} - -static void unregister_task_item_on_input_cb(void *context, WUPSConfigSimplePadData input) { - if (!Config::unregister_task_item_pressed && Config::is_wiiu_menu && ((input.buttons_d & WUPS_CONFIG_BUTTON_A) == WUPS_CONFIG_BUTTON_A)) { - - nn::act::Initialize(); - Initialize__Q2_2nn4bossFv(); - - for (uint8_t i = 1; i <= nn::act::GetNumOfAccounts(); i++) - { - if (nn::act::IsSlotOccupied(i) && nn::act::IsNetworkAccountEx(i)) - { - nn::boss::Task task{}; - nn::act::PersistentId persistentId = nn::act::GetPersistentIdEx(i); - - __ct__Q3_2nn4boss4TaskFv(&task); - Initialize__Q3_2nn4boss4TaskFPCcUi(&task, "oltopic", persistentId); - - // bypasses compiler warning about unused variable - #ifdef DEBUG - uint32_t res = Unregister__Q3_2nn4boss4TaskFv(&task); - DEBUG_FUNCTION_LINE_VERBOSE("Unregistered oltopic for: SlotNo %d | Persistent ID %08x -> 0x%08x", i, persistentId, res); - #else - Unregister__Q3_2nn4boss4TaskFv(&task); - #endif - } - } - - Finalize__Q2_2nn4bossFv(); - nn::act::Finalize(); - - Config::unregister_task_item_pressed = !Config::unregister_task_item_pressed; - Config::need_relaunch = true; - } -} - -static int32_t unregister_task_item_get_display_value(void *context, char *out_buf, int32_t out_size) { - auto string = strings.need_menu_action; - if (Config::is_wiiu_menu) { - if (Config::unregister_task_item_pressed) { - string = strings.restart_to_apply_action; - } else { - string = strings.press_a_action; - } - } - - if ((int)string.length() > out_size - 1) return -1; - string.copy(out_buf, string.length()); - out_buf[string.length()] = '\0'; - - return 0; -} - -static WUPSConfigAPICallbackStatus ConfigMenuOpenedCallback(WUPSConfigCategoryHandle rootHandle) { - WUPSConfigAPIStatus err; - bool res; - - uint64_t current_title_id = OSGetTitleID(); - uint64_t wiiu_menu_tid = _SYSGetSystemApplicationTitleId(SYSTEM_APP_ID_WII_U_MENU); - Config::is_wiiu_menu = (current_title_id == wiiu_menu_tid); - - // get translation strings - strings = get_config_strings(get_system_language()); - - // create root config category - WUPSConfigCategory root = WUPSConfigCategory(rootHandle); - - auto network_cat = WUPSConfigCategory::Create(strings.network_category, err); - if (!network_cat) return report_error(err); - - // config id display name default current value changed callback - auto connect_item = WUPSConfigItemBoolean::Create("connect_to_network", strings.connect_to_network_setting, true, Config::connect_to_network, &connect_to_network_changed, err); - if (!connect_item) return report_error(err); - - res = network_cat->add(std::move(*connect_item), err); - if (!res) return report_error(err); - - { - std::string multiplayer_port_text = std::vformat(strings.multiplayer_port_display, std::make_format_args(peertopeer_port())); - res = network_cat->add(WUPSConfigItemStub::Create(multiplayer_port_text), err); - if (!res) return report_error(err); - } - - res = root.add(std::move(*network_cat), err); - if (!res) return report_error(err); - - auto other_cat = WUPSConfigCategory::Create(strings.other_category, err); - if (!other_cat) return report_error(err); - - WUPSConfigAPIItemCallbacksV2 unregisterTasksItemCallbacks = { - .getCurrentValueDisplay = unregister_task_item_get_display_value, - .getCurrentValueSelectedDisplay = unregister_task_item_get_display_value, - .onSelected = nullptr, - .restoreDefault = nullptr, - .isMovementAllowed = nullptr, - .onCloseCallback = nullptr, - .onInput = unregister_task_item_on_input_cb, - .onInputEx = nullptr, - .onDelete = nullptr - }; - - WUPSConfigAPIItemOptionsV2 unregisterTasksItemOptions = { - .displayName = strings.reset_wwp_setting.data(), - .context = nullptr, - .callbacks = unregisterTasksItemCallbacks, - }; - - WUPSConfigItemHandle unregisterTasksItem; - err = WUPSConfigAPI_Item_Create(unregisterTasksItemOptions, &unregisterTasksItem); - if (err != WUPSCONFIG_API_RESULT_SUCCESS) return report_error(err); - - err = WUPSConfigAPI_Category_AddItem(other_cat->getHandle(), unregisterTasksItem); - if (err != WUPSCONFIG_API_RESULT_SUCCESS) return report_error(err); - - res = root.add(std::move(*other_cat), err); - if (!res) return report_error(err); - - return WUPSCONFIG_API_CALLBACK_RESULT_SUCCESS; -} - -static void ConfigMenuClosedCallback() { - // Save all changes - WUPSStorageError res; - res = WUPSStorageAPI::SaveStorage(); - if (res != WUPS_STORAGE_ERROR_SUCCESS) return report_storage_error(res); - - if (Config::need_relaunch) { - // Need to reload the console so the patches reset - OSForceFullRelaunch(); - SYSLaunchMenu(); - Config::need_relaunch = false; - } -} - -void Config::Init() { - WUPSConfigAPIStatus cres; - - // Init the config api - WUPSConfigAPIOptionsV1 configOptions = { .name = "Inkay" }; - cres = WUPSConfigAPI_Init(configOptions, ConfigMenuOpenedCallback, ConfigMenuClosedCallback); - if (cres != WUPSCONFIG_API_RESULT_SUCCESS) return (void)report_error(cres); - - WUPSStorageError res; - // Try to get value from storage - res = WUPSStorageAPI::Get("connect_to_network", Config::connect_to_network); - if (res == WUPS_STORAGE_ERROR_NOT_FOUND) { - DEBUG_FUNCTION_LINE("Connect to network value not found, attempting to migrate/create"); - - bool skipPatches = false; - if (WUPSStorageAPI::Get("skipPatches", skipPatches) == WUPS_STORAGE_ERROR_SUCCESS) { - // Migrate old config value - Config::connect_to_network = !skipPatches; - WUPSStorageAPI::DeleteItem("skipPatches"); - } - - // Add the value to the storage if it's missing. - res = WUPSStorageAPI::Store("connect_to_network", connect_to_network); - if (res != WUPS_STORAGE_ERROR_SUCCESS) return report_storage_error(res); - } - else if (res != WUPS_STORAGE_ERROR_SUCCESS) return report_storage_error(res); - - // Save storage - res = WUPSStorageAPI::SaveStorage(); - if (res != WUPS_STORAGE_ERROR_SUCCESS) return report_storage_error(res); -} diff --git a/src/config.h b/src/config.h index 51c888b..99b2bdc 100644 --- a/src/config.h +++ b/src/config.h @@ -10,18 +10,7 @@ class Config { public: - static void Init(); - - // wups config items static bool connect_to_network; - - // private stuff - static bool need_relaunch; - - // private stuff - static bool is_wiiu_menu; - - static bool unregister_task_item_pressed; }; struct config_strings { diff --git a/src/main.cpp b/src/main.cpp index 560ec42..c3bf833 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include #include #include @@ -54,20 +54,23 @@ Mandatory plugin information. If not set correctly, the loader will refuse to use the plugin. **/ -WUPS_PLUGIN_NAME("Inkay"); -WUPS_PLUGIN_DESCRIPTION("Pretendo Network Patcher"); -WUPS_PLUGIN_VERSION(INKAY_VERSION); -WUPS_PLUGIN_AUTHOR("Pretendo contributors"); -WUPS_PLUGIN_LICENSE("GPLv3"); +WUMS_MODULE_EXPORT_NAME("inkay"); +WUMS_MODULE_DESCRIPTION("Pretendo Network Patcher"); +WUMS_MODULE_VERSION(INKAY_VERSION); +WUMS_MODULE_AUTHOR("Pretendo contributors"); +WUMS_MODULE_LICENSE("GPLv3"); WUPS_USE_STORAGE("inkay"); -WUPS_USE_WUT_DEVOPTAB(); +WUMS_USE_WUT_DEVOPTAB(); #include #include #include #include "patches/account_settings.h" +#include "patches/dns_hooks.h" +#include "patches/eshop_applet.h" +#include "patches/olv_applet.h" #include "patches/game_peertopeer.h" #include "utils/sysconfig.h" @@ -111,25 +114,11 @@ static const char *get_pretendo_message() { return get_config_strings(get_system_language()).using_pretendo_network.data(); } -INITIALIZE_PLUGIN() { - WHBLogCafeInit(); - WHBLogUdpInit(); - - Config::Init(); - - auto res = Mocha_InitLibrary(); - - if (res != MOCHA_RESULT_SUCCESS) { - DEBUG_FUNCTION_LINE("Mocha init failed with code %d!", res); - return; - } - - if (NotificationModule_InitLibrary() != NOTIFICATION_MODULE_RESULT_SUCCESS) { - DEBUG_FUNCTION_LINE("NotificationModule_InitLibrary failed"); - } - +static void Inkay_Initialize(bool apply_patches) { // if using pretendo then (try to) apply the ssl patches - if (Config::connect_to_network) { + if (apply_patches) { + Config::connect_to_network = true; + if (is555(get_console_os_version())) { Mocha_IOSUKernelWrite32(0xE1019F78, 0xE3A00001); // mov r0, #1 } else { @@ -150,14 +139,40 @@ INITIALIZE_PLUGIN() { DEBUG_FUNCTION_LINE_VERBOSE("Pretendo URL and NoSSL patches skipped."); ShowNotification(get_nintendo_network_message()); + return; } if (FunctionPatcher_InitLibrary() == FUNCTION_PATCHER_RESULT_SUCCESS) { + patchDNS(); + patchEshop(); + patchOlvApplet(); install_matchmaking_patches(); + } else { + DEBUG_FUNCTION_LINE("FunctionPatcher_InitLibrary failed"); } } -DEINITIALIZE_PLUGIN() { +WUMS_INITIALIZE() { + WHBLogCafeInit(); + WHBLogUdpInit(); + + auto res = Mocha_InitLibrary(); + + if (res != MOCHA_RESULT_SUCCESS) { + DEBUG_FUNCTION_LINE("Mocha init failed with code %d!", res); + return; + } + + if (NotificationModule_InitLibrary() != NOTIFICATION_MODULE_RESULT_SUCCESS) { + DEBUG_FUNCTION_LINE("NotificationModule_InitLibrary failed"); + } +} + +WUMS_DEINITIALIZE() { + unpatchDNS(); + unpatchEshop(); + unpatchOlvApplet(); + unpatchAccountSettings(); remove_matchmaking_patches(); Mocha_DeInitLibrary(); @@ -168,15 +183,20 @@ DEINITIALIZE_PLUGIN() { WHBLogUdpDeinit(); } -ON_APPLICATION_START() { +WUMS_APPLICATION_STARTS() { DEBUG_FUNCTION_LINE_VERBOSE("Inkay " INKAY_VERSION " starting up...\n"); setup_olv_libs(); peertopeer_patch(); matchmaking_notify_titleswitch(); - patchAccountSettings(); + + if (isAccountSettingsTitle()) { + patchAccountSettings(); + } } -ON_APPLICATION_ENDS() { +WUMS_APPLICATION_ENDS() { } + +WUMS_EXPORT_FUNCTION(Inkay_Initialize); diff --git a/src/patches/account_settings.cpp b/src/patches/account_settings.cpp index efea324..57af0b9 100644 --- a/src/patches/account_settings.cpp +++ b/src/patches/account_settings.cpp @@ -22,7 +22,8 @@ #include "utils/logger.h" #include "utils/replace_mem.h" -#include +#include +#include #include #include #include @@ -54,6 +55,7 @@ const char wave_new[] = "saccount.pretendo.cc"; bool isAccountSettingsTitle(); static std::optional rootca_pem_handle{}; +std::vector account_patches; DECL_FUNCTION(int, FSOpenFile_accSettings, FSClient *client, FSCmdBlock *block, char *path, const char *mode, uint32_t *handle, int error) { @@ -131,10 +133,27 @@ bool patchAccountSettings() { DEBUG_FUNCTION_LINE_VERBOSE("Inkay: We didn't find the whitelist /)>~<(\\"); return false; } + + account_patches.reserve(3); + + auto add_patch = [](function_replacement_data_t repl, const char *name) { + PatchedFunctionHandle handle = 0; + if (FunctionPatcher_AddFunctionPatch(&repl, &handle, nullptr) != FUNCTION_PATCHER_RESULT_SUCCESS) { + DEBUG_FUNCTION_LINE("Inkay/Account: Failed to patch %s!", name); + } + account_patches.push_back(handle); + }; + + add_patch(REPLACE_FUNCTION_FOR_PROCESS(FSOpenFile_accSettings, LIBRARY_COREINIT, FSOpenFile, FP_TARGET_PROCESS_GAME), "FSOpenFile_accSettings"); + add_patch(REPLACE_FUNCTION_FOR_PROCESS(FSReadFile_accSettings, LIBRARY_COREINIT, FSReadFile, FP_TARGET_PROCESS_GAME), "FSReadFile_accSettings"); + add_patch(REPLACE_FUNCTION_FOR_PROCESS(FSCloseFile_accSettings, LIBRARY_COREINIT, FSReadFile, FP_TARGET_PROCESS_GAME), "FSCloseFile_accSettings"); return true; } -WUPS_MUST_REPLACE_FOR_PROCESS(FSOpenFile_accSettings, WUPS_LOADER_LIBRARY_COREINIT, FSOpenFile, WUPS_FP_TARGET_PROCESS_GAME); -WUPS_MUST_REPLACE_FOR_PROCESS(FSReadFile_accSettings, WUPS_LOADER_LIBRARY_COREINIT, FSReadFile, WUPS_FP_TARGET_PROCESS_GAME); -WUPS_MUST_REPLACE_FOR_PROCESS(FSCloseFile_accSettings, WUPS_LOADER_LIBRARY_COREINIT, FSCloseFile, WUPS_FP_TARGET_PROCESS_GAME); +void unpatchAccountSettings() { + for (auto handle: account_patches) { + FunctionPatcher_RemoveFunctionPatch(handle); + } + account_patches.clear(); +} diff --git a/src/patches/account_settings.h b/src/patches/account_settings.h index 6d09e68..4cc77be 100644 --- a/src/patches/account_settings.h +++ b/src/patches/account_settings.h @@ -17,4 +17,5 @@ bool isAccountSettingsTitle(); -bool patchAccountSettings(); \ No newline at end of file +bool patchAccountSettings(); +void unpatchAccountSettings(); diff --git a/src/patches/dns_hooks.cpp b/src/patches/dns_hooks.cpp index d832a57..d51520b 100644 --- a/src/patches/dns_hooks.cpp +++ b/src/patches/dns_hooks.cpp @@ -15,12 +15,16 @@ along with this program. If not, see . */ -#include #include -#include "utils/logger.h" + #include "config.h" +#include "utils/logger.h" #include +#include +#include + +std::vector dns_patches; const std::pair dns_replacements[] = { // NNCS servers @@ -42,10 +46,31 @@ static const char * replace_dns_name(const char *dns_name) { DECL_FUNCTION(struct hostent *, gethostbyname, const char *dns_name) { return real_gethostbyname(replace_dns_name(dns_name)); } -// might need a WUPS_MUST_REPLACE_FOR_PROCESS for Friends -WUPS_MUST_REPLACE(gethostbyname, WUPS_LOADER_LIBRARY_NSYSNET, gethostbyname); DECL_FUNCTION(int, getaddrinfo, const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res) { return real_getaddrinfo(replace_dns_name(node), service, hints, res); } -WUPS_MUST_REPLACE(getaddrinfo, WUPS_LOADER_LIBRARY_NSYSNET, getaddrinfo); \ No newline at end of file + +void patchDNS() { + dns_patches.reserve(2); + + auto add_patch = [](function_replacement_data_t repl, const char *name) { + PatchedFunctionHandle handle = 0; + if (FunctionPatcher_AddFunctionPatch(&repl, &handle, nullptr) != FUNCTION_PATCHER_RESULT_SUCCESS) { + DEBUG_FUNCTION_LINE("Inkay/DNS: Failed to patch %s!", name); + } + dns_patches.push_back(handle); + }; + + // might need a REPLACE_FUNCTION_FOR_PROCESS for Friends + add_patch(REPLACE_FUNCTION(gethostbyname, LIBRARY_NSYSNET, gethostbyname), "gethostbyname"); + + add_patch(REPLACE_FUNCTION(getaddrinfo, LIBRARY_NSYSNET, getaddrinfo), "getaddrinfo"); +} + +void unpatchDNS() { + for (auto handle: dns_patches) { + FunctionPatcher_RemoveFunctionPatch(handle); + } + dns_patches.clear(); +} diff --git a/src/patches/dns_hooks.h b/src/patches/dns_hooks.h new file mode 100644 index 0000000..9bbc216 --- /dev/null +++ b/src/patches/dns_hooks.h @@ -0,0 +1,20 @@ +/* Copyright 2024 Pretendo Network contributors + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#pragma once + +void patchDNS(); +void unpatchDNS(); diff --git a/src/patches/eshop_applet.cpp b/src/patches/eshop_applet.cpp index d3ee43c..33467ac 100644 --- a/src/patches/eshop_applet.cpp +++ b/src/patches/eshop_applet.cpp @@ -21,7 +21,8 @@ #include "utils/logger.h" #include "utils/replace_mem.h" -#include +#include +#include #include #include #include @@ -47,6 +48,7 @@ const char whitelist_new[] = { }; static std::optional rootca_pem_handle{}; +std::vector eshop_patches; DECL_FUNCTION(int, FSOpenFile_eShop, FSClient *client, FSCmdBlock *block, char *path, const char *mode, uint32_t *handle, int error) { @@ -102,6 +104,25 @@ DECL_FUNCTION(FSStatus, FSCloseFile_eShop, FSClient *client, FSCmdBlock *block, return real_FSCloseFile_eShop(client, block, handle, errorMask); } -WUPS_MUST_REPLACE_FOR_PROCESS(FSOpenFile_eShop, WUPS_LOADER_LIBRARY_COREINIT, FSOpenFile, WUPS_FP_TARGET_PROCESS_ESHOP); -WUPS_MUST_REPLACE_FOR_PROCESS(FSReadFile_eShop, WUPS_LOADER_LIBRARY_COREINIT, FSReadFile, WUPS_FP_TARGET_PROCESS_ESHOP); -WUPS_MUST_REPLACE_FOR_PROCESS(FSCloseFile_eShop, WUPS_LOADER_LIBRARY_COREINIT, FSCloseFile, WUPS_FP_TARGET_PROCESS_ESHOP); +void patchEshop() { + eshop_patches.reserve(3); + + auto add_patch = [](function_replacement_data_t repl, const char *name) { + PatchedFunctionHandle handle = 0; + if (FunctionPatcher_AddFunctionPatch(&repl, &handle, nullptr) != FUNCTION_PATCHER_RESULT_SUCCESS) { + DEBUG_FUNCTION_LINE("Inkay/eShop: Failed to patch %s!", name); + } + eshop_patches.push_back(handle); + }; + + add_patch(REPLACE_FUNCTION_FOR_PROCESS(FSOpenFile_eShop, LIBRARY_COREINIT, FSOpenFile, FP_TARGET_PROCESS_ESHOP), "FSOpenFile_eShop"); + add_patch(REPLACE_FUNCTION_FOR_PROCESS(FSReadFile_eShop, LIBRARY_COREINIT, FSReadFile, FP_TARGET_PROCESS_ESHOP), "FSReadFile_eShop"); + add_patch(REPLACE_FUNCTION_FOR_PROCESS(FSCloseFile_eShop, LIBRARY_COREINIT, FSCloseFile, FP_TARGET_PROCESS_ESHOP), "FSCloseFile_eShop"); +} + +void unpatchEshop() { + for (auto handle: eshop_patches) { + FunctionPatcher_RemoveFunctionPatch(handle); + } + eshop_patches.clear(); +} diff --git a/src/patches/eshop_applet.h b/src/patches/eshop_applet.h new file mode 100644 index 0000000..6f978ea --- /dev/null +++ b/src/patches/eshop_applet.h @@ -0,0 +1,20 @@ +/* Copyright 2024 Pretendo Network contributors + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#pragma once + +void patchEshop(); +void unpatchEshop(); diff --git a/src/patches/game_matchmaking.cpp b/src/patches/game_matchmaking.cpp index c78d56c..fe26eed 100644 --- a/src/patches/game_matchmaking.cpp +++ b/src/patches/game_matchmaking.cpp @@ -16,8 +16,8 @@ along with this program. If not, see . */ -#include "game_matchmaking.h" #include "config.h" +#include "game_matchmaking.h" #include "utils/logger.h" #include "ini.h" diff --git a/src/patches/olv_applet.cpp b/src/patches/olv_applet.cpp index 9bafd44..256b3fd 100644 --- a/src/patches/olv_applet.cpp +++ b/src/patches/olv_applet.cpp @@ -21,11 +21,12 @@ #include "utils/logger.h" #include "utils/replace_mem.h" -#include +#include #include #include #include #include +#include #include "ca_pem.h" // generated at buildtime @@ -65,6 +66,7 @@ const replacement replacements[] = { }; static std::optional rootca_pem_handle{}; +std::vector olv_patches; DECL_FUNCTION(int, FSOpenFile, FSClient *client, FSCmdBlock *block, char *path, const char *mode, uint32_t *handle, int error) { @@ -123,6 +125,25 @@ DECL_FUNCTION(FSStatus, FSCloseFile, FSClient *client, FSCmdBlock *block, FSFile return real_FSCloseFile(client, block, handle, errorMask); } -WUPS_MUST_REPLACE_FOR_PROCESS(FSOpenFile, WUPS_LOADER_LIBRARY_COREINIT, FSOpenFile, WUPS_FP_TARGET_PROCESS_MIIVERSE); -WUPS_MUST_REPLACE_FOR_PROCESS(FSReadFile, WUPS_LOADER_LIBRARY_COREINIT, FSReadFile, WUPS_FP_TARGET_PROCESS_MIIVERSE); -WUPS_MUST_REPLACE_FOR_PROCESS(FSCloseFile, WUPS_LOADER_LIBRARY_COREINIT, FSCloseFile, WUPS_FP_TARGET_PROCESS_MIIVERSE); +void patchOlvApplet() { + olv_patches.reserve(3); + + auto add_patch = [](function_replacement_data_t repl, const char *name) { + PatchedFunctionHandle handle = 0; + if (FunctionPatcher_AddFunctionPatch(&repl, &handle, nullptr) != FUNCTION_PATCHER_RESULT_SUCCESS) { + DEBUG_FUNCTION_LINE("Inkay/OLV: Failed to patch %s!", name); + } + olv_patches.push_back(handle); + }; + + add_patch(REPLACE_FUNCTION_FOR_PROCESS(FSOpenFile, LIBRARY_COREINIT, FSOpenFile, FP_TARGET_PROCESS_MIIVERSE), "FSOpenFile"); + add_patch(REPLACE_FUNCTION_FOR_PROCESS(FSReadFile, LIBRARY_COREINIT, FSReadFile, FP_TARGET_PROCESS_MIIVERSE), "FSReadFile"); + add_patch(REPLACE_FUNCTION_FOR_PROCESS(FSCloseFile, LIBRARY_COREINIT, FSCloseFile, FP_TARGET_PROCESS_MIIVERSE), "FSCloseFile"); +} + +void unpatchOlvApplet() { + for (auto handle: olv_patches) { + FunctionPatcher_RemoveFunctionPatch(handle); + } + olv_patches.clear(); +} diff --git a/src/patches/olv_applet.h b/src/patches/olv_applet.h new file mode 100644 index 0000000..4f307c7 --- /dev/null +++ b/src/patches/olv_applet.h @@ -0,0 +1,20 @@ +/* Copyright 2024 Pretendo Network contributors + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#pragma once + +void patchOlvApplet(); +void unpatchOlvApplet(); diff --git a/src/patches/olv_urls.cpp b/src/patches/olv_urls.cpp index 862453d..849d29b 100644 --- a/src/patches/olv_urls.cpp +++ b/src/patches/olv_urls.cpp @@ -16,8 +16,8 @@ along with this program. If not, see . */ -#include "olv_urls.h" #include "config.h" +#include "olv_urls.h" #include "utils/logger.h" #include "utils/replace_mem.h" diff --git a/src/utils/logger.h b/src/utils/logger.h index f7278b6..e26a487 100644 --- a/src/utils/logger.h +++ b/src/utils/logger.h @@ -14,15 +14,15 @@ extern "C" { #define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILENAME_X__) #define OSFATAL_FUNCTION_LINE(FMT, ARGS...)do { \ - OSFatal_printf("[(P) Inkay][%23s]%30s@L%04d: " FMT "",__FILENAME__,__FUNCTION__, __LINE__, ## ARGS); \ + OSFatal_printf("[(M) Inkay][%23s]%30s@L%04d: " FMT "",__FILENAME__,__FUNCTION__, __LINE__, ## ARGS); \ } while (0) #define DEBUG_FUNCTION_LINE(FMT, ARGS...)do { \ - WHBLogPrintf("[(P) Inkay][%23s]%30s@L%04d: " FMT "",__FILENAME__,__FUNCTION__, __LINE__, ## ARGS); \ + WHBLogPrintf("[(M) Inkay][%23s]%30s@L%04d: " FMT "",__FILENAME__,__FUNCTION__, __LINE__, ## ARGS); \ } while (0); #define DEBUG_FUNCTION_LINE_WRITE(FMT, ARGS...)do { \ - WHBLogWritef("[(P) Inkay][%23s]%30s@L%04d: " FMT "",__FILENAME__,__FUNCTION__, __LINE__, ## ARGS); \ + WHBLogWritef("[(M) Inkay][%23s]%30s@L%04d: " FMT "",__FILENAME__,__FUNCTION__, __LINE__, ## ARGS); \ } while (0); #ifdef DEBUG From 3460feeeafd212380c791c1b9c26a37e7acb4938 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20L=C3=B3pez=20Guimaraes?= Date: Tue, 29 Oct 2024 18:21:40 +0000 Subject: [PATCH 2/9] fix(Makefile): Replicate original compiler settings --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index c645f43..8c961de 100644 --- a/Makefile +++ b/Makefile @@ -28,7 +28,7 @@ INCLUDES := src src/ext/inih #------------------------------------------------------------------------------- # options for code generation #------------------------------------------------------------------------------- -CFLAGS := -Wall -Wextra -O2 -ffunction-sections\ +CFLAGS := -Wall -O2 -ffunction-sections\ $(MACHDEP) CFLAGS += $(INCLUDE) -D__WIIU__ -D__WUT__ @@ -36,7 +36,7 @@ CFLAGS += $(INCLUDE) -D__WIIU__ -D__WUT__ CXXFLAGS := $(CFLAGS) -std=c++20 ASFLAGS := -g $(ARCH) -LDFLAGS = -g $(ARCH) $(RPXSPECS) -Wl,-Map,$(notdir $*.map) -T$(WUMS_ROOT)/share/libkernel.ld $(WUMSSPECS) +LDFLAGS = -g $(ARCH) $(RPXSPECS) -Wl,-Map,$(notdir $*.map) -Wl,-gc-sections -T$(WUMS_ROOT)/share/libkernel.ld $(WUMSSPECS) ifeq ($(DEBUG),1) CXXFLAGS += -DDEBUG -g From d3ff378cc49d782b41a15bec048499fce98c2b49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20L=C3=B3pez=20Guimaraes?= Date: Tue, 29 Oct 2024 18:22:37 +0000 Subject: [PATCH 3/9] chore: Remove unnecesary file `wut_extra.h` is only used in the plugin, not in the module. --- src/wut_extra.h | 41 ----------------------------------------- 1 file changed, 41 deletions(-) delete mode 100644 src/wut_extra.h diff --git a/src/wut_extra.h b/src/wut_extra.h deleted file mode 100644 index b6a65c3..0000000 --- a/src/wut_extra.h +++ /dev/null @@ -1,41 +0,0 @@ -#pragma once - -#include -#include - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -namespace nn::boss { - class Task { - public: - nn::act::PersistentId persistentId; - uint32_t unk1; - char task_name[8]; - uint64_t title_id; - uint32_t unk2; - uint32_t unk3; - }; - - static_assert(sizeof(Task) == 32, "nn::boss::Task must be 32 bytes."); -} - -extern "C" uint32_t Initialize__Q2_2nn4bossFv(); -extern "C" uint32_t Finalize__Q2_2nn4bossFv(); - -extern "C" void __ct__Q3_2nn4boss4TaskFv(nn::boss::Task *task); -extern "C" uint32_t Initialize__Q3_2nn4boss4TaskFPCcUi(nn::boss::Task *task, char const *, unsigned int); -extern "C" uint32_t Unregister__Q3_2nn4boss4TaskFv(nn::boss::Task *task); -extern "C" void __dt__Q3_2nn4boss4TaskFv(nn::boss::Task *task); -extern "C" uint32_t StartScheduling__Q3_2nn4boss4TaskFb(nn::boss::Task *task, bool queueTaskOnCall); -extern "C" uint32_t GetState__Q3_2nn4boss4TaskCFPUi(nn::boss::Task *task, uint32_t *outExecCount); -extern "C" uint32_t Run__Q3_2nn4boss4TaskFb(nn::boss::Task *task, bool unk); -extern "C" uint32_t UpdateIntervalSec__Q3_2nn4boss4TaskFUi(nn::boss::Task *task, uint32_t seconds); -extern "C" bool IsRegistered__Q3_2nn4boss4TaskCFv(nn::boss::Task *task); - -#ifdef __cplusplus -} -#endif From 7958373394bb6574cb09f67a535d481e49ef1ea5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20L=C3=B3pez=20Guimaraes?= Date: Tue, 29 Oct 2024 18:24:13 +0000 Subject: [PATCH 4/9] feat: Improvements in module exports Add new `Inkay_GetStatus` which can be used for retrieving the status of the module. Also add better handling of module initialization, and show a notification from the plugin if the module can't be found. --- plugin/src/main.cpp | 1 + plugin/src/module.cpp | 37 +++++++++++++++++++++++++++++++++---- plugin/src/module.h | 10 ++++++++++ src/config.cpp | 2 ++ src/config.h | 4 ++++ src/export.h | 25 +++++++++++++++++++++++++ src/main.cpp | 31 ++++++++++++++++++++++++++++++- 7 files changed, 105 insertions(+), 5 deletions(-) create mode 100644 src/export.h diff --git a/plugin/src/main.cpp b/plugin/src/main.cpp index 5cb5b19..dfb4ba6 100644 --- a/plugin/src/main.cpp +++ b/plugin/src/main.cpp @@ -77,6 +77,7 @@ INITIALIZE_PLUGIN() { } DEINITIALIZE_PLUGIN() { + Inkay_Finalize(); NotificationModule_DeInitLibrary(); WHBLogCafeDeinit(); diff --git a/plugin/src/module.cpp b/plugin/src/module.cpp index 6a201fa..4e3fb8e 100644 --- a/plugin/src/module.cpp +++ b/plugin/src/module.cpp @@ -14,25 +14,54 @@ along with this program. If not, see . */ +#include "module.h" #include +#include "Notification.h" #include "utils/logger.h" +static OSDynLoad_Module module; +static void (*moduleInitialize)(bool) = nullptr; +static InkayStatus (*moduleGetStatus)() = nullptr; + void Inkay_Initialize(bool apply_patches) { - OSDynLoad_Module module; - void (*moduleInitialize)(bool) = nullptr; + if (module) { + return; + } if (OSDynLoad_Acquire("inkay", &module) != OS_DYNLOAD_OK) { DEBUG_FUNCTION_LINE("Failed to acquire module"); + ShowNotification("Cannot find Inkay module. Ensure the Inkay module is properly installed"); return; } if (OSDynLoad_FindExport(module, OS_DYNLOAD_EXPORT_FUNC, "Inkay_Initialize", reinterpret_cast(&moduleInitialize)) != OS_DYNLOAD_OK) { DEBUG_FUNCTION_LINE("Failed to find initialization function"); + ShowNotification("Cannot find Inkay module initialization function. Ensure the Inkay module is properly installed"); + OSDynLoad_Release(module); return; } moduleInitialize(apply_patches); - - OSDynLoad_Release(module); +} + +void Inkay_Finalize() { + if (module) { + OSDynLoad_Release(module); + moduleInitialize = nullptr; + moduleGetStatus = nullptr; + } +} + +InkayStatus Inkay_GetStatus() { + if (!module) { + return InkayStatus::Error; + } + + if (!moduleGetStatus && OSDynLoad_FindExport(module, OS_DYNLOAD_EXPORT_FUNC, "Inkay_GetStatus", reinterpret_cast(&moduleGetStatus)) != OS_DYNLOAD_OK) { + DEBUG_FUNCTION_LINE("Failed to find status function"); + return InkayStatus::Error; + } + + return moduleGetStatus(); } diff --git a/plugin/src/module.h b/plugin/src/module.h index 3da8b0a..b6247a4 100644 --- a/plugin/src/module.h +++ b/plugin/src/module.h @@ -16,4 +16,14 @@ #pragma once +enum class InkayStatus { + Uninitialized, ///< The module isn't initialized + Nintendo, ///< The module is initialized but hasn't applied any patches + Pretendo, ///< The module is initialized and has applied the Pretendo patches + + Error = -1 ///< Failed to retrieve the module status +}; + void Inkay_Initialize(bool apply_patches); +void Inkay_Finalize(); +InkayStatus Inkay_GetStatus(); diff --git a/src/config.cpp b/src/config.cpp index 4923515..67519c8 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -18,6 +18,8 @@ #include "config.h" bool Config::connect_to_network = false; +bool Config::initialized = false; +bool Config::shown_uninitialized_warning = false; static config_strings strings; diff --git a/src/config.h b/src/config.h index 99b2bdc..b816876 100644 --- a/src/config.h +++ b/src/config.h @@ -11,6 +11,10 @@ class Config { public: static bool connect_to_network; + + static bool initialized; + + static bool shown_uninitialized_warning; }; struct config_strings { diff --git a/src/export.h b/src/export.h new file mode 100644 index 0000000..ecc7d99 --- /dev/null +++ b/src/export.h @@ -0,0 +1,25 @@ +/* Copyright 2024 Pretendo Network contributors + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#pragma once + +enum class InkayStatus { + Uninitialized, ///< The module isn't initialized + Nintendo, ///< The module is initialized but hasn't applied any patches + Pretendo, ///< The module is initialized and has applied the Pretendo patches + + Error = -1 ///< Failed to retrieve the module status +}; diff --git a/src/main.cpp b/src/main.cpp index c3bf833..0d2c066 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -32,6 +32,7 @@ #include #include #include +#include "export.h" #include "iosu_url_patches.h" #include "config.h" #include "Notification.h" @@ -60,7 +61,9 @@ WUMS_MODULE_VERSION(INKAY_VERSION); WUMS_MODULE_AUTHOR("Pretendo contributors"); WUMS_MODULE_LICENSE("GPLv3"); -WUPS_USE_STORAGE("inkay"); +WUMS_DEPENDS_ON(homebrew_functionpatcher); +WUMS_DEPENDS_ON(homebrew_kernel); +WUMS_DEPENDS_ON(homebrew_notifications); WUMS_USE_WUT_DEVOPTAB(); @@ -114,7 +117,21 @@ static const char *get_pretendo_message() { return get_config_strings(get_system_language()).using_pretendo_network.data(); } +static InkayStatus Inkay_GetStatus() { + if (!Config::initialized) + return InkayStatus::Uninitialized; + + if (Config::connect_to_network) { + return InkayStatus::Pretendo; + } else { + return InkayStatus::Nintendo; + } +} + static void Inkay_Initialize(bool apply_patches) { + if (Config::initialized) + return; + // if using pretendo then (try to) apply the ssl patches if (apply_patches) { Config::connect_to_network = true; @@ -135,10 +152,12 @@ static void Inkay_Initialize(bool apply_patches) { DEBUG_FUNCTION_LINE_VERBOSE("Pretendo URL and NoSSL patches applied successfully."); ShowNotification(get_pretendo_message()); + Config::initialized = true; } else { DEBUG_FUNCTION_LINE_VERBOSE("Pretendo URL and NoSSL patches skipped."); ShowNotification(get_nintendo_network_message()); + Config::initialized = true; return; } @@ -186,6 +205,15 @@ WUMS_DEINITIALIZE() { WUMS_APPLICATION_STARTS() { DEBUG_FUNCTION_LINE_VERBOSE("Inkay " INKAY_VERSION " starting up...\n"); + // TODO - Add a way to reliably check this. We can't do it here since this path gets triggered before + // the plugin gets initialized. + // + // if (!Config::initialized && !Config::shown_uninitialized_warning) { + // DEBUG_FUNCTION_LINE("Inkay module not initialized"); + // ShowNotification("Inkay module was not initialized. Ensure you have the Inkay plugin loaded"); + // Config::shown_uninitialized_warning = true; + // } + setup_olv_libs(); peertopeer_patch(); matchmaking_notify_titleswitch(); @@ -200,3 +228,4 @@ WUMS_APPLICATION_ENDS() { } WUMS_EXPORT_FUNCTION(Inkay_Initialize); +WUMS_EXPORT_FUNCTION(Inkay_GetStatus); From 68bc066c7bb06a9f69a76e5d5ca0febbfb026b6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20L=C3=B3pez=20Guimaraes?= Date: Tue, 29 Oct 2024 19:00:22 +0000 Subject: [PATCH 5/9] feat: Add translation for module not found errors --- plugin/src/config.h | 2 ++ plugin/src/module.cpp | 14 ++++++++++++-- src/config.h | 2 ++ src/lang/de_DE.lang | 2 ++ src/lang/en_US.lang | 2 ++ src/lang/es_ES.lang | 2 ++ src/lang/fr_FR.lang | 2 ++ src/lang/it_IT.lang | 2 ++ src/lang/ja_JP.lang | 2 ++ src/lang/nl_NL.lang | 2 ++ src/lang/pt_BR.lang | 2 ++ src/lang/ru_RU.lang | 2 ++ src/lang/zh_CN.lang | 2 ++ src/lang/zh_Hant.lang | 2 ++ 14 files changed, 38 insertions(+), 2 deletions(-) diff --git a/plugin/src/config.h b/plugin/src/config.h index 2fa9812..845f9f5 100644 --- a/plugin/src/config.h +++ b/plugin/src/config.h @@ -35,6 +35,8 @@ struct config_strings { std::string_view need_menu_action; std::string_view using_nintendo_network; std::string_view using_pretendo_network; + std::string_view module_not_found; + std::string_view module_init_not_found; }; config_strings get_config_strings(nn::swkbd::LanguageType language); diff --git a/plugin/src/module.cpp b/plugin/src/module.cpp index 4e3fb8e..77a2249 100644 --- a/plugin/src/module.cpp +++ b/plugin/src/module.cpp @@ -17,13 +17,23 @@ #include "module.h" #include +#include "config.h" #include "Notification.h" #include "utils/logger.h" +#include "utils/sysconfig.h" static OSDynLoad_Module module; static void (*moduleInitialize)(bool) = nullptr; static InkayStatus (*moduleGetStatus)() = nullptr; +static const char *get_module_not_found_message() { + return get_config_strings(get_system_language()).module_not_found.data(); +} + +static const char *get_module_init_not_found_message() { + return get_config_strings(get_system_language()).module_init_not_found.data(); +} + void Inkay_Initialize(bool apply_patches) { if (module) { return; @@ -31,13 +41,13 @@ void Inkay_Initialize(bool apply_patches) { if (OSDynLoad_Acquire("inkay", &module) != OS_DYNLOAD_OK) { DEBUG_FUNCTION_LINE("Failed to acquire module"); - ShowNotification("Cannot find Inkay module. Ensure the Inkay module is properly installed"); + ShowNotification(get_module_not_found_message()); return; } if (OSDynLoad_FindExport(module, OS_DYNLOAD_EXPORT_FUNC, "Inkay_Initialize", reinterpret_cast(&moduleInitialize)) != OS_DYNLOAD_OK) { DEBUG_FUNCTION_LINE("Failed to find initialization function"); - ShowNotification("Cannot find Inkay module initialization function. Ensure the Inkay module is properly installed"); + ShowNotification(get_module_init_not_found_message()); OSDynLoad_Release(module); return; } diff --git a/src/config.h b/src/config.h index b816876..3d6f08f 100644 --- a/src/config.h +++ b/src/config.h @@ -29,6 +29,8 @@ struct config_strings { std::string_view using_nintendo_network; std::string_view using_pretendo_network; std::string_view multiplayer_port_display; + std::string_view module_not_found; + std::string_view module_init_not_found; }; config_strings get_config_strings(nn::swkbd::LanguageType language); diff --git a/src/lang/de_DE.lang b/src/lang/de_DE.lang index 1bfb5e8..a3485cb 100644 --- a/src/lang/de_DE.lang +++ b/src/lang/de_DE.lang @@ -8,3 +8,5 @@ ,.need_menu_action = "Nur vom Wii U-Menü aus" ,.using_nintendo_network = "Nutze Nintendo Network" ,.using_pretendo_network = "Nutze Pretendo Network" +,.module_not_found = "Could not find Inkay module. Ensure the Inkay module is properly installed" +,.module_init_not_found = "Could not initialize Inkay module. Ensure the Inkay module is properly installed" diff --git a/src/lang/en_US.lang b/src/lang/en_US.lang index ed0e423..aa02d40 100644 --- a/src/lang/en_US.lang +++ b/src/lang/en_US.lang @@ -9,3 +9,5 @@ ,.using_nintendo_network = "Using Nintendo Network" ,.using_pretendo_network = "Using Pretendo Network" ,.multiplayer_port_display = "Using UDP port {} for multiplayer" +,.module_not_found = "Could not find Inkay module. Ensure the Inkay module is properly installed" +,.module_init_not_found = "Could not initialize Inkay module. Ensure the Inkay module is properly installed" diff --git a/src/lang/es_ES.lang b/src/lang/es_ES.lang index c6e9188..e03dd7f 100644 --- a/src/lang/es_ES.lang +++ b/src/lang/es_ES.lang @@ -8,3 +8,5 @@ ,.need_menu_action="Solo desde el Menú de Wii U" ,.using_nintendo_network="Usando Nintendo Network" ,.using_pretendo_network="Usando Pretendo Network" +,.module_not_found="No se pudo encontrar el módulo Inkay. Confirme que el módulo Inkay está instalado correctamente" +,.module_init_not_found="No se pudo inicializar el módulo Inkay. Confirme que el módulo Inkay está instalado correctamente" diff --git a/src/lang/fr_FR.lang b/src/lang/fr_FR.lang index 1f8eda7..88776de 100644 --- a/src/lang/fr_FR.lang +++ b/src/lang/fr_FR.lang @@ -8,3 +8,5 @@ ,.need_menu_action = "Depuis le menu Wii U seulement" ,.using_nintendo_network = "Sur Nintendo Network" ,.using_pretendo_network = "Sur Pretendo Network" +,.module_not_found = "Could not find Inkay module. Ensure the Inkay module is properly installed" +,.module_init_not_found = "Could not initialize Inkay module. Ensure the Inkay module is properly installed" diff --git a/src/lang/it_IT.lang b/src/lang/it_IT.lang index 7dbf2ff..d77bc19 100644 --- a/src/lang/it_IT.lang +++ b/src/lang/it_IT.lang @@ -8,3 +8,5 @@ ,.need_menu_action = "Solo dal menu WiiU" ,.using_nintendo_network = "Usando Nintendo Network" ,.using_pretendo_network = "Usando Pretendo Network" +,.module_not_found = "Could not find Inkay module. Ensure the Inkay module is properly installed" +,.module_init_not_found = "Could not initialize Inkay module. Ensure the Inkay module is properly installed" diff --git a/src/lang/ja_JP.lang b/src/lang/ja_JP.lang index 1e88f5a..8740611 100644 --- a/src/lang/ja_JP.lang +++ b/src/lang/ja_JP.lang @@ -8,3 +8,5 @@ ,.need_menu_action = "WiiUメニューからのみ実行可能" ,.using_nintendo_network = "ニンテンドーネットワークを使用中" ,.using_pretendo_network = "Pretendoネットワークを使用中" +,.module_not_found = "Could not find Inkay module. Ensure the Inkay module is properly installed" +,.module_init_not_found = "Could not initialize Inkay module. Ensure the Inkay module is properly installed" diff --git a/src/lang/nl_NL.lang b/src/lang/nl_NL.lang index 6d15650..ef23280 100644 --- a/src/lang/nl_NL.lang +++ b/src/lang/nl_NL.lang @@ -8,3 +8,5 @@ ,.need_menu_action = "Alleen vanuit het WiiU-menu" ,.using_nintendo_network = "Nintendo Network wordt gebruikt" ,.using_pretendo_network = "Pretendo Network wordt gebruikt" +,.module_not_found = "Could not find Inkay module. Ensure the Inkay module is properly installed" +,.module_init_not_found = "Could not initialize Inkay module. Ensure the Inkay module is properly installed" diff --git a/src/lang/pt_BR.lang b/src/lang/pt_BR.lang index 5e60a59..17a4714 100644 --- a/src/lang/pt_BR.lang +++ b/src/lang/pt_BR.lang @@ -8,3 +8,5 @@ ,.need_menu_action = "Apenas no menu do Wii U" ,.using_nintendo_network = "Usando Nintendo Network" ,.using_pretendo_network = "Usando Pretendo Network" +,.module_not_found = "Could not find Inkay module. Ensure the Inkay module is properly installed" +,.module_init_not_found = "Could not initialize Inkay module. Ensure the Inkay module is properly installed" diff --git a/src/lang/ru_RU.lang b/src/lang/ru_RU.lang index 966166b..575c06d 100644 --- a/src/lang/ru_RU.lang +++ b/src/lang/ru_RU.lang @@ -8,3 +8,5 @@ ,.need_menu_action = "Только из меню Wii U" ,.using_nintendo_network = "Используется Nintendo Network" ,.using_pretendo_network = "Используется Pretendo Network" +,.module_not_found = "Could not find Inkay module. Ensure the Inkay module is properly installed" +,.module_init_not_found = "Could not initialize Inkay module. Ensure the Inkay module is properly installed" diff --git a/src/lang/zh_CN.lang b/src/lang/zh_CN.lang index df1bc5a..671122d 100644 --- a/src/lang/zh_CN.lang +++ b/src/lang/zh_CN.lang @@ -8,3 +8,5 @@ ,.need_menu_action = "仅来自WiiU Menu" ,.using_nintendo_network = "使用 Nintendo Network" ,.using_pretendo_network = "使用 Pretendo Network" +,.module_not_found = "Could not find Inkay module. Ensure the Inkay module is properly installed" +,.module_init_not_found = "Could not initialize Inkay module. Ensure the Inkay module is properly installed" diff --git a/src/lang/zh_Hant.lang b/src/lang/zh_Hant.lang index ec3a0ad..d831cc2 100644 --- a/src/lang/zh_Hant.lang +++ b/src/lang/zh_Hant.lang @@ -8,3 +8,5 @@ ,.need_menu_action = "僅來自WiiU Menu" ,.using_nintendo_network = "使用 Nintendo Network" ,.using_pretendo_network = "使用 Pretendo Network" +,.module_not_found = "Could not find Inkay module. Ensure the Inkay module is properly installed" +,.module_init_not_found = "Could not initialize Inkay module. Ensure the Inkay module is properly installed" From ea71879bb1246cb7bee614add70ce059e292d8b0 Mon Sep 17 00:00:00 2001 From: Ash Logan Date: Thu, 21 Nov 2024 13:19:06 +1100 Subject: [PATCH 6/9] chore: Introduce common directory to deduplicate shared code --- Makefile | 6 +-- {plugin/src => common}/Notification.cpp | 0 {plugin/src => common}/Notification.h | 0 common/lang.cpp | 44 +++++++++++++++++++ common/lang.h | 22 ++++++++++ {src/utils => common}/sysconfig.cpp | 22 ++++++++-- {src/utils => common}/sysconfig.h | 1 + {src => common}/utils/scope_exit.h | 0 plugin/Makefile | 4 +- plugin/src/config.cpp | 54 ++++++----------------- plugin/src/config.h | 20 --------- plugin/src/main.cpp | 25 +---------- plugin/src/module.cpp | 3 +- plugin/src/utils/sysconfig.cpp | 57 ------------------------- plugin/src/utils/sysconfig.h | 12 ------ src/Notification.cpp | 31 -------------- src/Notification.h | 3 -- src/config.cpp | 41 ------------------ src/config.h | 18 -------- src/main.cpp | 3 +- src/patches/game_peertopeer.cpp | 21 +-------- src/patches/game_peertopeer.h | 1 - 22 files changed, 110 insertions(+), 278 deletions(-) rename {plugin/src => common}/Notification.cpp (100%) rename {plugin/src => common}/Notification.h (100%) create mode 100644 common/lang.cpp create mode 100644 common/lang.h rename {src/utils => common}/sysconfig.cpp (83%) rename {src/utils => common}/sysconfig.h (86%) rename {src => common}/utils/scope_exit.h (100%) delete mode 100644 plugin/src/utils/sysconfig.cpp delete mode 100644 plugin/src/utils/sysconfig.h delete mode 100644 src/Notification.cpp delete mode 100644 src/Notification.h diff --git a/Makefile b/Makefile index 8c961de..72a3a66 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 +SOURCES := src src/patches src/utils src/ext/inih common DATA := data -INCLUDES := src src/ext/inih +INCLUDES := src src/ext/inih src/lang common #------------------------------------------------------------------------------- # options for code generation @@ -103,7 +103,7 @@ all: $(BUILD) $(BUILD): - @[ -d $@ ] || mkdir -p $@ + @$(shell [ ! -d $(BUILD) ] && mkdir -p $(BUILD)) @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile @$(MAKE) --no-print-directory -C $(CURDIR)/plugin -f $(CURDIR)/plugin/Makefile mkdir -p dist/ diff --git a/plugin/src/Notification.cpp b/common/Notification.cpp similarity index 100% rename from plugin/src/Notification.cpp rename to common/Notification.cpp diff --git a/plugin/src/Notification.h b/common/Notification.h similarity index 100% rename from plugin/src/Notification.h rename to common/Notification.h diff --git a/common/lang.cpp b/common/lang.cpp new file mode 100644 index 0000000..3f32b17 --- /dev/null +++ b/common/lang.cpp @@ -0,0 +1,44 @@ +// +// Created by ash on 21/11/24. +// + +#include "lang.h" + +config_strings get_config_strings(nn::swkbd::LanguageType language) { + switch (language) { + case nn::swkbd::LanguageType::English: + default: return { +#include "en_US.lang" + }; + case nn::swkbd::LanguageType::Spanish: return { +#include "es_ES.lang" + }; + case nn::swkbd::LanguageType::French: return { +#include "fr_FR.lang" + }; + case nn::swkbd::LanguageType::Italian: return { +#include "it_IT.lang" + }; + case nn::swkbd::LanguageType::German: return { +#include "de_DE.lang" + }; + case nn::swkbd::LanguageType::SimplifiedChinese: return { +#include "zh_CN.lang" + }; + case nn::swkbd::LanguageType::TraditionalChinese: return { +#include "zh_Hant.lang" + }; + case nn::swkbd::LanguageType::Portuguese: return { +#include "pt_BR.lang" + }; + case nn::swkbd::LanguageType::Japanese: return { +#include "ja_JP.lang" + }; + case nn::swkbd::LanguageType::Dutch: return { +#include "nl_NL.lang" + }; + case nn::swkbd::LanguageType::Russian: return { +#include "ru_RU.lang" + }; + } +} diff --git a/common/lang.h b/common/lang.h new file mode 100644 index 0000000..6e557fe --- /dev/null +++ b/common/lang.h @@ -0,0 +1,22 @@ +#pragma once + +#include +#include + +struct config_strings { + const char *plugin_name; + std::string_view network_category; + std::string_view connect_to_network_setting; + std::string_view other_category; + std::string_view reset_wwp_setting; + std::string_view press_a_action; + std::string_view restart_to_apply_action; + std::string_view need_menu_action; + std::string_view using_nintendo_network; + std::string_view using_pretendo_network; + std::string_view multiplayer_port_display; + std::string_view module_not_found; + std::string_view module_init_not_found; +}; + +config_strings get_config_strings(nn::swkbd::LanguageType language); diff --git a/src/utils/sysconfig.cpp b/common/sysconfig.cpp similarity index 83% rename from src/utils/sysconfig.cpp rename to common/sysconfig.cpp index 97ae4a3..102a3cf 100644 --- a/src/utils/sysconfig.cpp +++ b/common/sysconfig.cpp @@ -1,6 +1,5 @@ /* Copyright 2024 Pretendo Network contributors Copyright 2024 Ash Logan - Copyright 2023 Maschell Copyright 2020-2022 V10lator Copyright 2022 Xpl0itU @@ -81,8 +80,8 @@ static void get_mcp_config() { mcp_os_version = os_version; DEBUG_FUNCTION_LINE_VERBOSE("Running on %d.%d.%d%c; %s%s", - os_version.major, os_version.minor, os_version.patch, os_version.region - config.code_id, config.serial_id + os_version.major, os_version.minor, os_version.patch, os_version.region + config.code_id, config.serial_id ); } @@ -97,3 +96,20 @@ MCPSystemVersion get_console_os_version() { return mcp_os_version.value_or((MCPSystemVersion) { .major = 5, .minor = 5, .patch = 5, .region = 'E' }); } + +static inline int digit(char a) { + if (a < '0' || a > '9') return 0; + return a - '0'; +} + +unsigned short get_console_peertopeer_port() { + const char * serial = get_console_serial(); + + unsigned short port = 50000 + + (digit(serial[4]) * 1000) + + (digit(serial[5]) * 100 ) + + (digit(serial[6]) * 10 ) + + (digit(serial[7]) * 1 ); + + return port; +} diff --git a/src/utils/sysconfig.h b/common/sysconfig.h similarity index 86% rename from src/utils/sysconfig.h rename to common/sysconfig.h index 3b3e075..d517fc7 100644 --- a/src/utils/sysconfig.h +++ b/common/sysconfig.h @@ -11,5 +11,6 @@ nn::swkbd::LanguageType get_system_language(); const char * get_console_serial(); MCPSystemVersion get_console_os_version(); +unsigned short get_console_peertopeer_port(); #endif //INKAY_SYSCONFIG_H diff --git a/src/utils/scope_exit.h b/common/utils/scope_exit.h similarity index 100% rename from src/utils/scope_exit.h rename to common/utils/scope_exit.h diff --git a/plugin/Makefile b/plugin/Makefile index 125fb0c..fee7a0b 100644 --- a/plugin/Makefile +++ b/plugin/Makefile @@ -21,9 +21,9 @@ WUMS_ROOT := $(DEVKITPRO)/wums #------------------------------------------------------------------------------- TARGET := Inkay-pretendo BUILD := build -SOURCES := src src/utils +SOURCES := src src/utils ../common DATA := data -INCLUDES := src ../src/lang +INCLUDES := src ../src/lang ../common #DEBUG := 1 #------------------------------------------------------------------------------- diff --git a/plugin/src/config.cpp b/plugin/src/config.cpp index a0fc590..5ce07a8 100644 --- a/plugin/src/config.cpp +++ b/plugin/src/config.cpp @@ -19,65 +19,29 @@ #include "wut_extra.h" #include "utils/logger.h" -#include "utils/sysconfig.h" +#include "sysconfig.h" +#include "lang.h" #include #include #include #include +#include #include #include #include #include #include +#include + +static config_strings strings; bool Config::connect_to_network = true; bool Config::need_relaunch = false; bool Config::unregister_task_item_pressed = false; bool Config::is_wiiu_menu = false; -static config_strings strings; - -config_strings get_config_strings(nn::swkbd::LanguageType language) { - switch (language) { - case nn::swkbd::LanguageType::English: - default: return { -#include "en_US.lang" - }; - case nn::swkbd::LanguageType::Spanish: return { -#include "es_ES.lang" - }; - case nn::swkbd::LanguageType::French: return { -#include "fr_FR.lang" - }; - case nn::swkbd::LanguageType::Italian: return { -#include "it_IT.lang" - }; - case nn::swkbd::LanguageType::German: return { -#include "de_DE.lang" - }; - case nn::swkbd::LanguageType::SimplifiedChinese: return { -#include "zh_CN.lang" - }; - case nn::swkbd::LanguageType::TraditionalChinese: return { -#include "zh_Hant.lang" - }; - case nn::swkbd::LanguageType::Portuguese: return { -#include "pt_BR.lang" - }; - case nn::swkbd::LanguageType::Japanese: return { -#include "ja_JP.lang" - }; - case nn::swkbd::LanguageType::Dutch: return { -#include "nl_NL.lang" - }; - case nn::swkbd::LanguageType::Russian: return { -#include "ru_RU.lang" - }; - } -} - static WUPSConfigAPICallbackStatus report_error(WUPSConfigAPIStatus err) { DEBUG_FUNCTION_LINE_VERBOSE("WUPS config error: %s", WUPSConfigAPI_GetStatusStr(err)); return WUPSCONFIG_API_CALLBACK_RESULT_ERROR; @@ -174,6 +138,12 @@ static WUPSConfigAPICallbackStatus ConfigMenuOpenedCallback(WUPSConfigCategoryHa res = network_cat->add(std::move(*connect_item), err); if (!res) return report_error(err); + { + std::string multiplayer_port_text = std::vformat(strings.multiplayer_port_display, std::make_format_args(get_console_peertopeer_port())); + res = network_cat->add(WUPSConfigItemStub::Create(multiplayer_port_text), err); + if (!res) return report_error(err); + } + res = root.add(std::move(*network_cat), err); if (!res) return report_error(err); diff --git a/plugin/src/config.h b/plugin/src/config.h index 845f9f5..0928d5e 100644 --- a/plugin/src/config.h +++ b/plugin/src/config.h @@ -5,9 +5,6 @@ #ifndef INKAY_CONFIG_H #define INKAY_CONFIG_H -#include -#include - class Config { public: static void Init(); @@ -24,21 +21,4 @@ public: static bool unregister_task_item_pressed; }; -struct config_strings { - const char *plugin_name; - std::string_view network_category; - std::string_view connect_to_network_setting; - std::string_view other_category; - std::string_view reset_wwp_setting; - std::string_view press_a_action; - std::string_view restart_to_apply_action; - std::string_view need_menu_action; - std::string_view using_nintendo_network; - std::string_view using_pretendo_network; - std::string_view module_not_found; - std::string_view module_init_not_found; -}; - -config_strings get_config_strings(nn::swkbd::LanguageType language); - #endif //INKAY_CONFIG_H diff --git a/plugin/src/main.cpp b/plugin/src/main.cpp index dfb4ba6..4845a38 100644 --- a/plugin/src/main.cpp +++ b/plugin/src/main.cpp @@ -16,33 +16,12 @@ along with this program. If not, see . */ -#include -#include -#include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include + #include #include #include "config.h" #include "module.h" -#include "Notification.h" - -#include -#include -#include -#include -#include - -#include #define INKAY_VERSION "v2.6.0" @@ -60,8 +39,6 @@ WUPS_USE_STORAGE("inkay"); WUPS_USE_WUT_DEVOPTAB(); -#include "utils/sysconfig.h" - INITIALIZE_PLUGIN() { WHBLogCafeInit(); WHBLogUdpInit(); diff --git a/plugin/src/module.cpp b/plugin/src/module.cpp index 77a2249..5fd9c2a 100644 --- a/plugin/src/module.cpp +++ b/plugin/src/module.cpp @@ -20,7 +20,8 @@ #include "config.h" #include "Notification.h" #include "utils/logger.h" -#include "utils/sysconfig.h" +#include "sysconfig.h" +#include "lang.h" static OSDynLoad_Module module; static void (*moduleInitialize)(bool) = nullptr; diff --git a/plugin/src/utils/sysconfig.cpp b/plugin/src/utils/sysconfig.cpp deleted file mode 100644 index cef6d78..0000000 --- a/plugin/src/utils/sysconfig.cpp +++ /dev/null @@ -1,57 +0,0 @@ -/* Copyright 2024 Pretendo Network contributors - Copyright 2024 Ash Logan - Copyright 2020-2022 V10lator - Copyright 2022 Xpl0itU - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -#include "sysconfig.h" -#include "utils/logger.h" - -#include -#include - -nn::swkbd::LanguageType get_system_language() { - static std::optional cached_language{}; - if (cached_language) return *cached_language; - - UCHandle handle = UCOpen(); - if (handle >= 0) { - nn::swkbd::LanguageType language; - - UCSysConfig settings __attribute__((__aligned__(0x40))) = { - .name = "cafe.language", - .access = 0, - .dataType = UC_DATATYPE_UNSIGNED_INT, - .error = UC_ERROR_OK, - .dataSize = sizeof(language), - .data = &language, - }; - - UCError err = UCReadSysConfig(handle, 1, &settings); - UCClose(handle); - if (err != UC_ERROR_OK) { - DEBUG_FUNCTION_LINE("Error reading UC: %d!", err); - return nn::swkbd::LanguageType::English; - } else { - DEBUG_FUNCTION_LINE_VERBOSE("System language found: %d", language); - cached_language = language; - return language; - } - } else { - DEBUG_FUNCTION_LINE("Error opening UC: %d", handle); - return nn::swkbd::LanguageType::English; - } -} diff --git a/plugin/src/utils/sysconfig.h b/plugin/src/utils/sysconfig.h deleted file mode 100644 index 3bac817..0000000 --- a/plugin/src/utils/sysconfig.h +++ /dev/null @@ -1,12 +0,0 @@ -// -// Created by ash on 9/04/24. -// - -#ifndef INKAY_SYSCONFIG_H -#define INKAY_SYSCONFIG_H - -#include - -nn::swkbd::LanguageType get_system_language(); - -#endif //INKAY_SYSCONFIG_H diff --git a/src/Notification.cpp b/src/Notification.cpp deleted file mode 100644 index cc6177e..0000000 --- a/src/Notification.cpp +++ /dev/null @@ -1,31 +0,0 @@ -/* Copyright 2024 Pretendo Network contributors - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -#include "Notification.h" -#include -#include - -void ShowNotification(const char* notification) { - auto err1 = NotificationModule_SetDefaultValue(NOTIFICATION_MODULE_NOTIFICATION_TYPE_INFO, - NOTIFICATION_MODULE_DEFAULT_OPTION_KEEP_UNTIL_SHOWN, true); - auto err2 = NotificationModule_SetDefaultValue(NOTIFICATION_MODULE_NOTIFICATION_TYPE_INFO, - NOTIFICATION_MODULE_DEFAULT_OPTION_DURATION_BEFORE_FADE_OUT, - 15.0f); - - if (err1 != NOTIFICATION_MODULE_RESULT_SUCCESS || err2 != NOTIFICATION_MODULE_RESULT_SUCCESS) return; - - NotificationModule_AddInfoNotification(notification); -} diff --git a/src/Notification.h b/src/Notification.h deleted file mode 100644 index ebdc7a3..0000000 --- a/src/Notification.h +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -void ShowNotification(const char* notification); diff --git a/src/config.cpp b/src/config.cpp index 67519c8..56c8740 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -20,44 +20,3 @@ bool Config::connect_to_network = false; bool Config::initialized = false; bool Config::shown_uninitialized_warning = false; - -static config_strings strings; - -config_strings get_config_strings(nn::swkbd::LanguageType language) { - switch (language) { - case nn::swkbd::LanguageType::English: - default: return { -#include "lang/en_US.lang" - }; - case nn::swkbd::LanguageType::Spanish: return { -#include "lang/es_ES.lang" - }; - case nn::swkbd::LanguageType::French: return { -#include "lang/fr_FR.lang" - }; - case nn::swkbd::LanguageType::Italian: return { -#include "lang/it_IT.lang" - }; - case nn::swkbd::LanguageType::German: return { -#include "lang/de_DE.lang" - }; - case nn::swkbd::LanguageType::SimplifiedChinese: return { -#include "lang/zh_CN.lang" - }; - case nn::swkbd::LanguageType::TraditionalChinese: return { -#include "lang/zh_Hant.lang" - }; - case nn::swkbd::LanguageType::Portuguese: return { -#include "lang/pt_BR.lang" - }; - case nn::swkbd::LanguageType::Japanese: return { -#include "lang/ja_JP.lang" - }; - case nn::swkbd::LanguageType::Dutch: return { -#include "lang/nl_NL.lang" - }; - case nn::swkbd::LanguageType::Russian: return { -#include "lang/ru_RU.lang" - }; - } -} diff --git a/src/config.h b/src/config.h index 3d6f08f..96f6775 100644 --- a/src/config.h +++ b/src/config.h @@ -17,22 +17,4 @@ public: static bool shown_uninitialized_warning; }; -struct config_strings { - const char *plugin_name; - std::string_view network_category; - std::string_view connect_to_network_setting; - std::string_view other_category; - std::string_view reset_wwp_setting; - std::string_view press_a_action; - std::string_view restart_to_apply_action; - std::string_view need_menu_action; - std::string_view using_nintendo_network; - std::string_view using_pretendo_network; - std::string_view multiplayer_port_display; - std::string_view module_not_found; - std::string_view module_init_not_found; -}; - -config_strings get_config_strings(nn::swkbd::LanguageType language); - #endif //INKAY_CONFIG_H diff --git a/src/main.cpp b/src/main.cpp index 0d2c066..12ba0e8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -75,7 +75,8 @@ WUMS_USE_WUT_DEVOPTAB(); #include "patches/eshop_applet.h" #include "patches/olv_applet.h" #include "patches/game_peertopeer.h" -#include "utils/sysconfig.h" +#include "sysconfig.h" +#include "lang.h" //thanks @Gary#4139 :p static void write_string(uint32_t addr, const char *str) { diff --git a/src/patches/game_peertopeer.cpp b/src/patches/game_peertopeer.cpp index 01a6fc6..c464117 100644 --- a/src/patches/game_peertopeer.cpp +++ b/src/patches/game_peertopeer.cpp @@ -15,30 +15,13 @@ #include #include "game_peertopeer.h" -#include "utils/sysconfig.h" +#include "sysconfig.h" #include "utils/logger.h" #include "utils/rpl_info.h" #include "utils/replace_mem.h" #include -static inline int digit(char a) { - if (a < '0' || a > '9') return 0; - return a - '0'; -} - -unsigned short peertopeer_port() { - const char * serial = get_console_serial(); - - unsigned short port = 50000 + - (digit(serial[4]) * 1000) + - (digit(serial[5]) * 100 ) + - (digit(serial[6]) * 10 ) + - (digit(serial[7]) * 1 ); - - return port; -} - static void minecraft_peertopeer_patch() { std::optional minecraft = search_for_rpl("Minecraft.Client.rpx"); if (!minecraft) { @@ -46,7 +29,7 @@ static void minecraft_peertopeer_patch() { return; } - auto port = peertopeer_port(); + 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); diff --git a/src/patches/game_peertopeer.h b/src/patches/game_peertopeer.h index e26862b..8211c00 100644 --- a/src/patches/game_peertopeer.h +++ b/src/patches/game_peertopeer.h @@ -14,4 +14,3 @@ #pragma once void peertopeer_patch(); -unsigned short peertopeer_port(); From a710bd985a1af9bfee2479856f569af5eb787b62 Mon Sep 17 00:00:00 2001 From: Ash Logan Date: Thu, 21 Nov 2024 13:45:47 +1100 Subject: [PATCH 7/9] feat(lang): Tell users how to fix module-related errors Realistically, 99% of people will not know how to "ensure the inkay module is properly installed" - Aroma updater is designed to automatically fix random stuff like this It hashes every individual file so it will pick up SD card corruption, partial installs, etc --- src/lang/de_DE.lang | 2 -- src/lang/en_US.lang | 4 ++-- src/lang/es_ES.lang | 2 -- src/lang/fr_FR.lang | 2 -- src/lang/it_IT.lang | 2 -- src/lang/ja_JP.lang | 2 -- src/lang/nl_NL.lang | 2 -- src/lang/pt_BR.lang | 2 -- src/lang/ru_RU.lang | 2 -- src/lang/zh_CN.lang | 2 -- src/lang/zh_Hant.lang | 2 -- 11 files changed, 2 insertions(+), 22 deletions(-) diff --git a/src/lang/de_DE.lang b/src/lang/de_DE.lang index a3485cb..1bfb5e8 100644 --- a/src/lang/de_DE.lang +++ b/src/lang/de_DE.lang @@ -8,5 +8,3 @@ ,.need_menu_action = "Nur vom Wii U-Menü aus" ,.using_nintendo_network = "Nutze Nintendo Network" ,.using_pretendo_network = "Nutze Pretendo Network" -,.module_not_found = "Could not find Inkay module. Ensure the Inkay module is properly installed" -,.module_init_not_found = "Could not initialize Inkay module. Ensure the Inkay module is properly installed" diff --git a/src/lang/en_US.lang b/src/lang/en_US.lang index aa02d40..29fb991 100644 --- a/src/lang/en_US.lang +++ b/src/lang/en_US.lang @@ -9,5 +9,5 @@ ,.using_nintendo_network = "Using Nintendo Network" ,.using_pretendo_network = "Using Pretendo Network" ,.multiplayer_port_display = "Using UDP port {} for multiplayer" -,.module_not_found = "Could not find Inkay module. Ensure the Inkay module is properly installed" -,.module_init_not_found = "Could not initialize Inkay module. Ensure the Inkay module is properly installed" +,.module_not_found = "Pretendo patch failed - use Aroma Updater to repair (686-1001 Module missing)" +,.module_init_not_found = "Pretendo patch failed - use Aroma Updater to repair (686-1002 Module init)" diff --git a/src/lang/es_ES.lang b/src/lang/es_ES.lang index e03dd7f..c6e9188 100644 --- a/src/lang/es_ES.lang +++ b/src/lang/es_ES.lang @@ -8,5 +8,3 @@ ,.need_menu_action="Solo desde el Menú de Wii U" ,.using_nintendo_network="Usando Nintendo Network" ,.using_pretendo_network="Usando Pretendo Network" -,.module_not_found="No se pudo encontrar el módulo Inkay. Confirme que el módulo Inkay está instalado correctamente" -,.module_init_not_found="No se pudo inicializar el módulo Inkay. Confirme que el módulo Inkay está instalado correctamente" diff --git a/src/lang/fr_FR.lang b/src/lang/fr_FR.lang index 88776de..1f8eda7 100644 --- a/src/lang/fr_FR.lang +++ b/src/lang/fr_FR.lang @@ -8,5 +8,3 @@ ,.need_menu_action = "Depuis le menu Wii U seulement" ,.using_nintendo_network = "Sur Nintendo Network" ,.using_pretendo_network = "Sur Pretendo Network" -,.module_not_found = "Could not find Inkay module. Ensure the Inkay module is properly installed" -,.module_init_not_found = "Could not initialize Inkay module. Ensure the Inkay module is properly installed" diff --git a/src/lang/it_IT.lang b/src/lang/it_IT.lang index d77bc19..7dbf2ff 100644 --- a/src/lang/it_IT.lang +++ b/src/lang/it_IT.lang @@ -8,5 +8,3 @@ ,.need_menu_action = "Solo dal menu WiiU" ,.using_nintendo_network = "Usando Nintendo Network" ,.using_pretendo_network = "Usando Pretendo Network" -,.module_not_found = "Could not find Inkay module. Ensure the Inkay module is properly installed" -,.module_init_not_found = "Could not initialize Inkay module. Ensure the Inkay module is properly installed" diff --git a/src/lang/ja_JP.lang b/src/lang/ja_JP.lang index 8740611..1e88f5a 100644 --- a/src/lang/ja_JP.lang +++ b/src/lang/ja_JP.lang @@ -8,5 +8,3 @@ ,.need_menu_action = "WiiUメニューからのみ実行可能" ,.using_nintendo_network = "ニンテンドーネットワークを使用中" ,.using_pretendo_network = "Pretendoネットワークを使用中" -,.module_not_found = "Could not find Inkay module. Ensure the Inkay module is properly installed" -,.module_init_not_found = "Could not initialize Inkay module. Ensure the Inkay module is properly installed" diff --git a/src/lang/nl_NL.lang b/src/lang/nl_NL.lang index ef23280..6d15650 100644 --- a/src/lang/nl_NL.lang +++ b/src/lang/nl_NL.lang @@ -8,5 +8,3 @@ ,.need_menu_action = "Alleen vanuit het WiiU-menu" ,.using_nintendo_network = "Nintendo Network wordt gebruikt" ,.using_pretendo_network = "Pretendo Network wordt gebruikt" -,.module_not_found = "Could not find Inkay module. Ensure the Inkay module is properly installed" -,.module_init_not_found = "Could not initialize Inkay module. Ensure the Inkay module is properly installed" diff --git a/src/lang/pt_BR.lang b/src/lang/pt_BR.lang index 17a4714..5e60a59 100644 --- a/src/lang/pt_BR.lang +++ b/src/lang/pt_BR.lang @@ -8,5 +8,3 @@ ,.need_menu_action = "Apenas no menu do Wii U" ,.using_nintendo_network = "Usando Nintendo Network" ,.using_pretendo_network = "Usando Pretendo Network" -,.module_not_found = "Could not find Inkay module. Ensure the Inkay module is properly installed" -,.module_init_not_found = "Could not initialize Inkay module. Ensure the Inkay module is properly installed" diff --git a/src/lang/ru_RU.lang b/src/lang/ru_RU.lang index 575c06d..966166b 100644 --- a/src/lang/ru_RU.lang +++ b/src/lang/ru_RU.lang @@ -8,5 +8,3 @@ ,.need_menu_action = "Только из меню Wii U" ,.using_nintendo_network = "Используется Nintendo Network" ,.using_pretendo_network = "Используется Pretendo Network" -,.module_not_found = "Could not find Inkay module. Ensure the Inkay module is properly installed" -,.module_init_not_found = "Could not initialize Inkay module. Ensure the Inkay module is properly installed" diff --git a/src/lang/zh_CN.lang b/src/lang/zh_CN.lang index 671122d..df1bc5a 100644 --- a/src/lang/zh_CN.lang +++ b/src/lang/zh_CN.lang @@ -8,5 +8,3 @@ ,.need_menu_action = "仅来自WiiU Menu" ,.using_nintendo_network = "使用 Nintendo Network" ,.using_pretendo_network = "使用 Pretendo Network" -,.module_not_found = "Could not find Inkay module. Ensure the Inkay module is properly installed" -,.module_init_not_found = "Could not initialize Inkay module. Ensure the Inkay module is properly installed" diff --git a/src/lang/zh_Hant.lang b/src/lang/zh_Hant.lang index d831cc2..ec3a0ad 100644 --- a/src/lang/zh_Hant.lang +++ b/src/lang/zh_Hant.lang @@ -8,5 +8,3 @@ ,.need_menu_action = "僅來自WiiU Menu" ,.using_nintendo_network = "使用 Nintendo Network" ,.using_pretendo_network = "使用 Pretendo Network" -,.module_not_found = "Could not find Inkay module. Ensure the Inkay module is properly installed" -,.module_init_not_found = "Could not initialize Inkay module. Ensure the Inkay module is properly installed" From 06847b21e55c4ec74ab41f84bc1330ab6dcdb22f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20L=C3=B3pez=20Guimaraes?= Date: Thu, 21 Nov 2024 20:39:51 +0000 Subject: [PATCH 8/9] fix(p2p): Fix compilation error in multiplayer port text GCC complains about std::make_format_args using non-const references, so we can't pass along the `get_console_peertopeer_port` directly. Also replace `unsigned short` with `uint16_t` for clarity. --- common/sysconfig.cpp | 12 ++++++------ plugin/src/config.cpp | 3 ++- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/common/sysconfig.cpp b/common/sysconfig.cpp index 102a3cf..ec56614 100644 --- a/common/sysconfig.cpp +++ b/common/sysconfig.cpp @@ -102,14 +102,14 @@ static inline int digit(char a) { return a - '0'; } -unsigned short get_console_peertopeer_port() { +uint16_t get_console_peertopeer_port() { const char * serial = get_console_serial(); - unsigned short port = 50000 + - (digit(serial[4]) * 1000) + - (digit(serial[5]) * 100 ) + - (digit(serial[6]) * 10 ) + - (digit(serial[7]) * 1 ); + uint16_t port = 50000 + + (digit(serial[4]) * 1000) + + (digit(serial[5]) * 100 ) + + (digit(serial[6]) * 10 ) + + (digit(serial[7]) * 1 ); return port; } diff --git a/plugin/src/config.cpp b/plugin/src/config.cpp index 5ce07a8..1ca4be4 100644 --- a/plugin/src/config.cpp +++ b/plugin/src/config.cpp @@ -139,7 +139,8 @@ static WUPSConfigAPICallbackStatus ConfigMenuOpenedCallback(WUPSConfigCategoryHa if (!res) return report_error(err); { - std::string multiplayer_port_text = std::vformat(strings.multiplayer_port_display, std::make_format_args(get_console_peertopeer_port())); + uint16_t port = get_console_peertopeer_port(); + std::string multiplayer_port_text = std::vformat(strings.multiplayer_port_display, std::make_format_args(port)); res = network_cat->add(WUPSConfigItemStub::Create(multiplayer_port_text), err); if (!res) return report_error(err); } From 0f3115a40295f008fcefd2bd2890158cdf2eeb1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20L=C3=B3pez=20Guimaraes?= Date: Thu, 21 Nov 2024 20:43:17 +0000 Subject: [PATCH 9/9] fix(p2p): Don't apply patches when not using Pretendo --- src/patches/game_peertopeer.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/patches/game_peertopeer.cpp b/src/patches/game_peertopeer.cpp index c464117..e0e0fa3 100644 --- a/src/patches/game_peertopeer.cpp +++ b/src/patches/game_peertopeer.cpp @@ -15,6 +15,7 @@ #include #include "game_peertopeer.h" +#include "config.h" #include "sysconfig.h" #include "utils/logger.h" #include "utils/rpl_info.h" @@ -44,6 +45,10 @@ static void minecraft_peertopeer_patch() { } void peertopeer_patch() { + if (!Config::connect_to_network) { + return; + } + uint64_t tid = OSGetTitleID(); if (tid == 0x00050000'101D7500 || // EUR tid == 0x00050000'101D9D00 || // USA