mirror of
https://github.com/PretendoNetwork/Inkay.git
synced 2026-04-24 15:37:24 -05:00
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.
This commit is contained in:
parent
cc967126fe
commit
f4aeee8034
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)
|
||||
|
|
|
|||
45
Makefile
45
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)
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
|
|
|
|||
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
|
||||
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
|
||||
#-------------------------------------------------------------------------------
|
||||
31
plugin/src/Notification.cpp
Normal file
31
plugin/src/Notification.cpp
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
/* 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 "Notification.h"
|
||||
#include <notifications/notification_defines.h>
|
||||
#include <notifications/notifications.h>
|
||||
|
||||
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);
|
||||
}
|
||||
3
plugin/src/Notification.h
Normal file
3
plugin/src/Notification.h
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
#pragma once
|
||||
|
||||
void ShowNotification(const char* notification);
|
||||
258
plugin/src/config.cpp
Normal file
258
plugin/src/config.cpp
Normal file
|
|
@ -0,0 +1,258 @@
|
|||
/* 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 "utils/sysconfig.h"
|
||||
|
||||
#include <wups.h>
|
||||
#include <wups/storage.h>
|
||||
#include <wups/config_api.h>
|
||||
#include <wups/config/WUPSConfigItemBoolean.h>
|
||||
|
||||
#include <coreinit/title.h>
|
||||
#include <coreinit/launch.h>
|
||||
#include <sysapp/title.h>
|
||||
#include <sysapp/launch.h>
|
||||
#include <nn/act.h>
|
||||
|
||||
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<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);
|
||||
|
||||
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);
|
||||
}
|
||||
42
plugin/src/config.h
Normal file
42
plugin/src/config.h
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
//
|
||||
// Created by ash on 10/12/22.
|
||||
//
|
||||
|
||||
#ifndef INKAY_CONFIG_H
|
||||
#define INKAY_CONFIG_H
|
||||
|
||||
#include <string_view>
|
||||
#include <nn/swkbd.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;
|
||||
};
|
||||
|
||||
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
|
||||
92
plugin/src/main.cpp
Normal file
92
plugin/src/main.cpp
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
/* 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 <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <wups.h>
|
||||
#include <optional>
|
||||
#include <nsysnet/nssl.h>
|
||||
#include <sysapp/title.h>
|
||||
#include <coreinit/cache.h>
|
||||
#include <coreinit/dynload.h>
|
||||
#include <coreinit/mcp.h>
|
||||
#include <coreinit/memory.h>
|
||||
#include <coreinit/memorymap.h>
|
||||
#include <coreinit/memexpheap.h>
|
||||
#include <coreinit/title.h>
|
||||
#include <notifications/notifications.h>
|
||||
#include <utils/logger.h>
|
||||
#include "config.h"
|
||||
#include "module.h"
|
||||
#include "Notification.h"
|
||||
|
||||
#include <coreinit/filesystem.h>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <nn/erreula/erreula_cpp.h>
|
||||
#include <nn/act/client_cpp.h>
|
||||
|
||||
#include <gx2/surface.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();
|
||||
|
||||
#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() {
|
||||
|
||||
}
|
||||
38
plugin/src/module.cpp
Normal file
38
plugin/src/module.cpp
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
/* 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 <coreinit/dynload.h>
|
||||
|
||||
#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<void * *>(&moduleInitialize)) != OS_DYNLOAD_OK) {
|
||||
DEBUG_FUNCTION_LINE("Failed to find initialization function");
|
||||
return;
|
||||
}
|
||||
|
||||
moduleInitialize(apply_patches);
|
||||
|
||||
OSDynLoad_Release(module);
|
||||
}
|
||||
19
plugin/src/module.h
Normal file
19
plugin/src/module.h
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
/* 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 Inkay_Initialize(bool apply_patches);
|
||||
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
|
||||
57
plugin/src/utils/sysconfig.cpp
Normal file
57
plugin/src/utils/sysconfig.cpp
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
/* Copyright 2024 Pretendo Network contributors <pretendo.network>
|
||||
Copyright 2024 Ash Logan <ash@heyquark.com>
|
||||
Copyright 2020-2022 V10lator <v10lator@myway.de>
|
||||
Copyright 2022 Xpl0itU <DaThinkingChair@protonmail.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 "sysconfig.h"
|
||||
#include "utils/logger.h"
|
||||
|
||||
#include <coreinit/userconfig.h>
|
||||
#include <optional>
|
||||
|
||||
nn::swkbd::LanguageType get_system_language() {
|
||||
static std::optional <nn::swkbd::LanguageType> 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;
|
||||
}
|
||||
}
|
||||
12
plugin/src/utils/sysconfig.h
Normal file
12
plugin/src/utils/sysconfig.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
//
|
||||
// Created by ash on 9/04/24.
|
||||
//
|
||||
|
||||
#ifndef INKAY_SYSCONFIG_H
|
||||
#define INKAY_SYSCONFIG_H
|
||||
|
||||
#include <nn/swkbd.h>
|
||||
|
||||
nn::swkbd::LanguageType get_system_language();
|
||||
|
||||
#endif //INKAY_SYSCONFIG_H
|
||||
41
plugin/src/wut_extra.h
Normal file
41
plugin/src/wut_extra.h
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
#pragma once
|
||||
|
||||
#include <assert.h>
|
||||
#include <cstdint>
|
||||
|
||||
#include <nn/act.h>
|
||||
|
||||
#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
|
||||
209
src/config.cpp
209
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 <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;
|
||||
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<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);
|
||||
}
|
||||
|
|
|
|||
11
src/config.h
11
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 {
|
||||
|
|
|
|||
78
src/main.cpp
78
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>
|
||||
|
|
@ -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 <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"
|
||||
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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