mirror of
https://github.com/PretendoNetwork/Inkay.git
synced 2026-07-14 15:41:11 -05:00
Merge pull request #50 from DaniElectra/module
Some checks are pending
Inkay-CI / build-inkay (push) Waiting to run
Some checks are pending
Inkay-CI / build-inkay (push) Waiting to run
This commit is contained in:
commit
2bf5f8bd18
6
.github/workflows/ci.yml
vendored
6
.github/workflows/ci.yml
vendored
|
|
@ -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/
|
||||
|
|
|
|||
6
.gitignore
vendored
6
.gitignore
vendored
|
|
@ -1,7 +1,11 @@
|
|||
.cache/
|
||||
.vscode/
|
||||
.idea/
|
||||
/build
|
||||
/plugin/build
|
||||
/dist
|
||||
*.elf
|
||||
*.wms
|
||||
*.wps
|
||||
certs/
|
||||
*.lst
|
||||
*.lst
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
CMD make -f Makefile -j$(nproc)
|
||||
|
|
|
|||
47
Makefile
47
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
|
||||
|
|
@ -21,37 +21,35 @@ WUMS_ROOT := $(DEVKITPRO)/wums
|
|||
#-------------------------------------------------------------------------------
|
||||
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
|
||||
#DEBUG := 1
|
||||
INCLUDES := src src/ext/inih src/lang common
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# options for code generation
|
||||
#-------------------------------------------------------------------------------
|
||||
CFLAGS := -Wall -O2 -ffunction-sections -fdata-sections \
|
||||
CFLAGS := -Wall -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) -Wl,-gc-sections -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))
|
||||
@$(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)
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
|
|
|
|||
44
common/lang.cpp
Normal file
44
common/lang.cpp
Normal file
|
|
@ -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"
|
||||
};
|
||||
}
|
||||
}
|
||||
22
common/lang.h
Normal file
22
common/lang.h
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
#pragma once
|
||||
|
||||
#include <string_view>
|
||||
#include <nn/swkbd.h>
|
||||
|
||||
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);
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
/* Copyright 2024 Pretendo Network contributors <pretendo.network>
|
||||
Copyright 2024 Ash Logan <ash@heyquark.com>
|
||||
Copyright 2023 Maschell
|
||||
Copyright 2020-2022 V10lator <v10lator@myway.de>
|
||||
Copyright 2022 Xpl0itU <DaThinkingChair@protonmail.com>
|
||||
|
||||
|
|
@ -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';
|
||||
}
|
||||
|
||||
uint16_t get_console_peertopeer_port() {
|
||||
const char * serial = get_console_serial();
|
||||
|
||||
uint16_t port = 50000 +
|
||||
(digit(serial[4]) * 1000) +
|
||||
(digit(serial[5]) * 100 ) +
|
||||
(digit(serial[6]) * 10 ) +
|
||||
(digit(serial[7]) * 1 );
|
||||
|
||||
return port;
|
||||
}
|
||||
|
|
@ -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
|
||||
148
plugin/Makefile
Normal file
148
plugin/Makefile
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
#-------------------------------------------------------------------------------
|
||||
.SUFFIXES:
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
ifeq ($(strip $(DEVKITPRO)),)
|
||||
$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to>/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 ../common
|
||||
DATA := data
|
||||
INCLUDES := src ../src/lang ../common
|
||||
#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
|
||||
#-------------------------------------------------------------------------------
|
||||
229
plugin/src/config.cpp
Normal file
229
plugin/src/config.cpp
Normal file
|
|
@ -0,0 +1,229 @@
|
|||
/* Copyright 2022 Pretendo Network contributors <pretendo.network>
|
||||
Copyright 2022 Ash Logan <ash@heyquark.com>
|
||||
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "wut_extra.h"
|
||||
#include "utils/logger.h"
|
||||
#include "sysconfig.h"
|
||||
#include "lang.h"
|
||||
|
||||
#include <wups.h>
|
||||
#include <wups/storage.h>
|
||||
#include <wups/config_api.h>
|
||||
#include <wups/config/WUPSConfigItemBoolean.h>
|
||||
#include <wups/config/WUPSConfigItemStub.h>
|
||||
|
||||
#include <coreinit/title.h>
|
||||
#include <coreinit/launch.h>
|
||||
#include <sysapp/title.h>
|
||||
#include <sysapp/launch.h>
|
||||
#include <nn/act.h>
|
||||
#include <format>
|
||||
|
||||
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 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<bool>("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);
|
||||
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
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<bool>("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<bool>("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<bool>("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);
|
||||
}
|
||||
24
plugin/src/config.h
Normal file
24
plugin/src/config.h
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
//
|
||||
// Created by ash on 10/12/22.
|
||||
//
|
||||
|
||||
#ifndef INKAY_CONFIG_H
|
||||
#define INKAY_CONFIG_H
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
#endif //INKAY_CONFIG_H
|
||||
70
plugin/src/main.cpp
Normal file
70
plugin/src/main.cpp
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
/* Copyright 2022 Pretendo Network contributors <pretendo.network>
|
||||
Copyright 2022 Ash Logan <ash@heyquark.com>
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <wups.h>
|
||||
|
||||
#include <notifications/notifications.h>
|
||||
#include <utils/logger.h>
|
||||
#include "config.h"
|
||||
#include "module.h"
|
||||
|
||||
#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();
|
||||
|
||||
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() {
|
||||
Inkay_Finalize();
|
||||
NotificationModule_DeInitLibrary();
|
||||
|
||||
WHBLogCafeDeinit();
|
||||
WHBLogUdpDeinit();
|
||||
}
|
||||
|
||||
ON_APPLICATION_START() {
|
||||
|
||||
}
|
||||
|
||||
ON_APPLICATION_ENDS() {
|
||||
|
||||
}
|
||||
78
plugin/src/module.cpp
Normal file
78
plugin/src/module.cpp
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
/* Copyright 2024 Pretendo Network contributors <pretendo.network>
|
||||
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "module.h"
|
||||
#include <coreinit/dynload.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "Notification.h"
|
||||
#include "utils/logger.h"
|
||||
#include "sysconfig.h"
|
||||
#include "lang.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;
|
||||
}
|
||||
|
||||
if (OSDynLoad_Acquire("inkay", &module) != OS_DYNLOAD_OK) {
|
||||
DEBUG_FUNCTION_LINE("Failed to acquire module");
|
||||
ShowNotification(get_module_not_found_message());
|
||||
return;
|
||||
}
|
||||
|
||||
if (OSDynLoad_FindExport(module, OS_DYNLOAD_EXPORT_FUNC, "Inkay_Initialize", reinterpret_cast<void * *>(&moduleInitialize)) != OS_DYNLOAD_OK) {
|
||||
DEBUG_FUNCTION_LINE("Failed to find initialization function");
|
||||
ShowNotification(get_module_init_not_found_message());
|
||||
OSDynLoad_Release(module);
|
||||
return;
|
||||
}
|
||||
|
||||
moduleInitialize(apply_patches);
|
||||
}
|
||||
|
||||
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<void * *>(&moduleGetStatus)) != OS_DYNLOAD_OK) {
|
||||
DEBUG_FUNCTION_LINE("Failed to find status function");
|
||||
return InkayStatus::Error;
|
||||
}
|
||||
|
||||
return moduleGetStatus();
|
||||
}
|
||||
29
plugin/src/module.h
Normal file
29
plugin/src/module.h
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
/* Copyright 2024 Pretendo Network contributors <pretendo.network>
|
||||
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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();
|
||||
36
plugin/src/utils/logger.h
Normal file
36
plugin/src/utils/logger.h
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
#pragma once
|
||||
|
||||
#include <string.h>
|
||||
#include <whb/log.h>
|
||||
#include <whb/log_module.h>
|
||||
#include <whb/log_cafe.h>
|
||||
#include <whb/log_udp.h>
|
||||
|
||||
#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
|
||||
252
src/config.cpp
252
src/config.cpp
|
|
@ -17,252 +17,6 @@
|
|||
|
||||
#include "config.h"
|
||||
|
||||
#include "wut_extra.h"
|
||||
#include "utils/logger.h"
|
||||
#include "utils/sysconfig.h"
|
||||
#include "patches/game_peertopeer.h"
|
||||
|
||||
#include <wups.h>
|
||||
#include <wups/storage.h>
|
||||
#include <wups/config_api.h>
|
||||
#include <wups/config/WUPSConfigItemBoolean.h>
|
||||
#include <wups/config/WUPSConfigItemStub.h>
|
||||
|
||||
#include <coreinit/title.h>
|
||||
#include <coreinit/launch.h>
|
||||
#include <sysapp/title.h>
|
||||
#include <sysapp/launch.h>
|
||||
#include <nn/act.h>
|
||||
|
||||
#include <format>
|
||||
|
||||
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 "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"
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
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<bool>("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<bool>("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<bool>("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<bool>("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);
|
||||
}
|
||||
bool Config::connect_to_network = false;
|
||||
bool Config::initialized = false;
|
||||
bool Config::shown_uninitialized_warning = false;
|
||||
|
|
|
|||
27
src/config.h
27
src/config.h
|
|
@ -10,34 +10,11 @@
|
|||
|
||||
class Config {
|
||||
public:
|
||||
static void Init();
|
||||
|
||||
// wups config items
|
||||
static bool connect_to_network;
|
||||
|
||||
// private stuff
|
||||
static bool need_relaunch;
|
||||
static bool initialized;
|
||||
|
||||
// private stuff
|
||||
static bool is_wiiu_menu;
|
||||
|
||||
static bool unregister_task_item_pressed;
|
||||
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;
|
||||
};
|
||||
|
||||
config_strings get_config_strings(nn::swkbd::LanguageType language);
|
||||
|
||||
#endif //INKAY_CONFIG_H
|
||||
|
|
|
|||
25
src/export.h
Normal file
25
src/export.h
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
/* Copyright 2024 Pretendo Network contributors <pretendo.network>
|
||||
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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
|
||||
};
|
||||
|
|
@ -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 = "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)"
|
||||
|
|
|
|||
104
src/main.cpp
104
src/main.cpp
|
|
@ -19,7 +19,7 @@
|
|||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <wups.h>
|
||||
#include <wums.h>
|
||||
#include <optional>
|
||||
#include <nsysnet/nssl.h>
|
||||
#include <sysapp/title.h>
|
||||
|
|
@ -32,6 +32,7 @@
|
|||
#include <coreinit/title.h>
|
||||
#include <notifications/notifications.h>
|
||||
#include <utils/logger.h>
|
||||
#include "export.h"
|
||||
#include "iosu_url_patches.h"
|
||||
#include "config.h"
|
||||
#include "Notification.h"
|
||||
|
|
@ -54,22 +55,28 @@
|
|||
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");
|
||||
WUMS_DEPENDS_ON(homebrew_functionpatcher);
|
||||
WUMS_DEPENDS_ON(homebrew_kernel);
|
||||
WUMS_DEPENDS_ON(homebrew_notifications);
|
||||
|
||||
WUPS_USE_WUT_DEVOPTAB();
|
||||
WUMS_USE_WUT_DEVOPTAB();
|
||||
|
||||
#include <kernel/kernel.h>
|
||||
#include <mocha/mocha.h>
|
||||
#include <function_patcher/function_patching.h>
|
||||
#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"
|
||||
#include "sysconfig.h"
|
||||
#include "lang.h"
|
||||
|
||||
//thanks @Gary#4139 :p
|
||||
static void write_string(uint32_t addr, const char *str) {
|
||||
|
|
@ -111,25 +118,25 @@ static const char *get_pretendo_message() {
|
|||
return get_config_strings(get_system_language()).using_pretendo_network.data();
|
||||
}
|
||||
|
||||
INITIALIZE_PLUGIN() {
|
||||
WHBLogCafeInit();
|
||||
WHBLogUdpInit();
|
||||
static InkayStatus Inkay_GetStatus() {
|
||||
if (!Config::initialized)
|
||||
return InkayStatus::Uninitialized;
|
||||
|
||||
Config::Init();
|
||||
|
||||
auto res = Mocha_InitLibrary();
|
||||
|
||||
if (res != MOCHA_RESULT_SUCCESS) {
|
||||
DEBUG_FUNCTION_LINE("Mocha init failed with code %d!", res);
|
||||
return;
|
||||
if (Config::connect_to_network) {
|
||||
return InkayStatus::Pretendo;
|
||||
} else {
|
||||
return InkayStatus::Nintendo;
|
||||
}
|
||||
}
|
||||
|
||||
if (NotificationModule_InitLibrary() != NOTIFICATION_MODULE_RESULT_SUCCESS) {
|
||||
DEBUG_FUNCTION_LINE("NotificationModule_InitLibrary failed");
|
||||
}
|
||||
static void Inkay_Initialize(bool apply_patches) {
|
||||
if (Config::initialized)
|
||||
return;
|
||||
|
||||
// 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 {
|
||||
|
|
@ -146,18 +153,46 @@ INITIALIZE_PLUGIN() {
|
|||
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;
|
||||
}
|
||||
|
||||
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 +203,30 @@ DEINITIALIZE_PLUGIN() {
|
|||
WHBLogUdpDeinit();
|
||||
}
|
||||
|
||||
ON_APPLICATION_START() {
|
||||
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();
|
||||
patchAccountSettings();
|
||||
|
||||
if (isAccountSettingsTitle()) {
|
||||
patchAccountSettings();
|
||||
}
|
||||
}
|
||||
|
||||
ON_APPLICATION_ENDS() {
|
||||
WUMS_APPLICATION_ENDS() {
|
||||
|
||||
}
|
||||
|
||||
WUMS_EXPORT_FUNCTION(Inkay_Initialize);
|
||||
WUMS_EXPORT_FUNCTION(Inkay_GetStatus);
|
||||
|
|
|
|||
|
|
@ -22,7 +22,8 @@
|
|||
#include "utils/logger.h"
|
||||
#include "utils/replace_mem.h"
|
||||
|
||||
#include <wups.h>
|
||||
#include <function_patcher/function_patching.h>
|
||||
#include <vector>
|
||||
#include <optional>
|
||||
#include <coreinit/debug.h>
|
||||
#include <coreinit/filesystem.h>
|
||||
|
|
@ -54,6 +55,7 @@ const char wave_new[] = "saccount.pretendo.cc";
|
|||
bool isAccountSettingsTitle();
|
||||
|
||||
static std::optional<FSFileHandle> rootca_pem_handle{};
|
||||
std::vector<PatchedFunctionHandle> 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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,4 +17,5 @@
|
|||
|
||||
bool isAccountSettingsTitle();
|
||||
|
||||
bool patchAccountSettings();
|
||||
bool patchAccountSettings();
|
||||
void unpatchAccountSettings();
|
||||
|
|
|
|||
|
|
@ -15,12 +15,16 @@
|
|||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <wups.h>
|
||||
#include <netdb.h>
|
||||
|
||||
#include "utils/logger.h"
|
||||
|
||||
#include "config.h"
|
||||
#include "utils/logger.h"
|
||||
#include <array>
|
||||
#include <vector>
|
||||
#include <function_patcher/function_patching.h>
|
||||
|
||||
std::vector<PatchedFunctionHandle> dns_patches;
|
||||
|
||||
const std::pair<const char *, const char *> 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);
|
||||
|
||||
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();
|
||||
}
|
||||
|
|
|
|||
20
src/patches/dns_hooks.h
Normal file
20
src/patches/dns_hooks.h
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
/* Copyright 2024 Pretendo Network contributors <pretendo.network>
|
||||
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
void patchDNS();
|
||||
void unpatchDNS();
|
||||
|
|
@ -21,7 +21,8 @@
|
|||
#include "utils/logger.h"
|
||||
#include "utils/replace_mem.h"
|
||||
|
||||
#include <wups.h>
|
||||
#include <vector>
|
||||
#include <function_patcher/function_patching.h>
|
||||
#include <optional>
|
||||
#include <coreinit/debug.h>
|
||||
#include <coreinit/filesystem.h>
|
||||
|
|
@ -47,6 +48,7 @@ const char whitelist_new[] = {
|
|||
};
|
||||
|
||||
static std::optional<FSFileHandle> rootca_pem_handle{};
|
||||
std::vector<PatchedFunctionHandle> 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();
|
||||
}
|
||||
|
|
|
|||
20
src/patches/eshop_applet.h
Normal file
20
src/patches/eshop_applet.h
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
/* Copyright 2024 Pretendo Network contributors <pretendo.network>
|
||||
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
void patchEshop();
|
||||
void unpatchEshop();
|
||||
|
|
@ -16,8 +16,8 @@
|
|||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "game_matchmaking.h"
|
||||
#include "config.h"
|
||||
#include "game_matchmaking.h"
|
||||
#include "utils/logger.h"
|
||||
|
||||
#include "ini.h"
|
||||
|
|
|
|||
|
|
@ -15,30 +15,14 @@
|
|||
#include <coreinit/dynload.h>
|
||||
#include "game_peertopeer.h"
|
||||
|
||||
#include "utils/sysconfig.h"
|
||||
#include "config.h"
|
||||
#include "sysconfig.h"
|
||||
#include "utils/logger.h"
|
||||
#include "utils/rpl_info.h"
|
||||
#include "utils/replace_mem.h"
|
||||
|
||||
#include <optional>
|
||||
|
||||
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<OSDynLoad_NotifyData> minecraft = search_for_rpl("Minecraft.Client.rpx");
|
||||
if (!minecraft) {
|
||||
|
|
@ -46,7 +30,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);
|
||||
|
|
@ -61,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
|
||||
|
|
|
|||
|
|
@ -14,4 +14,3 @@
|
|||
#pragma once
|
||||
|
||||
void peertopeer_patch();
|
||||
unsigned short peertopeer_port();
|
||||
|
|
|
|||
|
|
@ -21,11 +21,12 @@
|
|||
#include "utils/logger.h"
|
||||
#include "utils/replace_mem.h"
|
||||
|
||||
#include <wups.h>
|
||||
#include <vector>
|
||||
#include <optional>
|
||||
#include <coreinit/debug.h>
|
||||
#include <coreinit/filesystem.h>
|
||||
#include <nsysnet/nssl.h>
|
||||
#include <function_patcher/function_patching.h>
|
||||
|
||||
#include "ca_pem.h" // generated at buildtime
|
||||
|
||||
|
|
@ -65,6 +66,7 @@ const replacement replacements[] = {
|
|||
};
|
||||
|
||||
static std::optional<FSFileHandle> rootca_pem_handle{};
|
||||
std::vector<PatchedFunctionHandle> 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();
|
||||
}
|
||||
|
|
|
|||
20
src/patches/olv_applet.h
Normal file
20
src/patches/olv_applet.h
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
/* Copyright 2024 Pretendo Network contributors <pretendo.network>
|
||||
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
void patchOlvApplet();
|
||||
void unpatchOlvApplet();
|
||||
|
|
@ -16,8 +16,8 @@
|
|||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "olv_urls.h"
|
||||
#include "config.h"
|
||||
#include "olv_urls.h"
|
||||
#include "utils/logger.h"
|
||||
#include "utils/replace_mem.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
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user