mirror of
https://github.com/wiiu-env/region_free_plugin.git
synced 2024-11-22 11:29:16 +01:00
first commit
This commit is contained in:
commit
6e0fb4080f
58
.github/workflows/ci.yml
vendored
Normal file
58
.github/workflows/ci.yml
vendored
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
name: CI-Release
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-binary:
|
||||||
|
runs-on: ubuntu-18.04
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: build binary
|
||||||
|
run: |
|
||||||
|
docker build . -t builder
|
||||||
|
docker run --rm -v ${PWD}:/project builder make
|
||||||
|
- uses: actions/upload-artifact@master
|
||||||
|
with:
|
||||||
|
name: binary
|
||||||
|
path: "*.wps"
|
||||||
|
deploy-binary:
|
||||||
|
needs: build-binary
|
||||||
|
runs-on: ubuntu-18.04
|
||||||
|
steps:
|
||||||
|
- name: Get environment variables
|
||||||
|
id: get_repository_name
|
||||||
|
run: |
|
||||||
|
echo REPOSITORY_NAME=$(echo "$GITHUB_REPOSITORY" | awk -F / '{print $2}' | sed -e "s/:refs//") >> $GITHUB_ENV
|
||||||
|
echo DATETIME=$(echo $(date '+%Y%m%d-%H%M%S')) >> $GITHUB_ENV
|
||||||
|
- uses: actions/download-artifact@master
|
||||||
|
with:
|
||||||
|
name: binary
|
||||||
|
path: wiiu/plugins
|
||||||
|
- name: zip artifact
|
||||||
|
run: zip -r ${{ env.REPOSITORY_NAME }}_${{ env.DATETIME }}.zip wiiu
|
||||||
|
- name: Create Release
|
||||||
|
id: create_release
|
||||||
|
uses: actions/create-release@v1
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
with:
|
||||||
|
tag_name: ${{ env.REPOSITORY_NAME }}-${{ env.DATETIME }}
|
||||||
|
release_name: Nightly-${{ env.REPOSITORY_NAME }}-${{ env.DATETIME }}
|
||||||
|
draft: false
|
||||||
|
prerelease: true
|
||||||
|
body: |
|
||||||
|
Not a stable release:
|
||||||
|
${{ github.event.head_commit.message }}
|
||||||
|
- name: Upload Release Asset
|
||||||
|
id: upload-release-asset
|
||||||
|
uses: actions/upload-release-asset@v1
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
with:
|
||||||
|
upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps
|
||||||
|
asset_path: ./${{ env.REPOSITORY_NAME }}_${{ env.DATETIME }}.zip
|
||||||
|
asset_name: ${{ env.REPOSITORY_NAME }}_${{ env.DATETIME }}.zip
|
||||||
|
asset_content_type: application/unknown
|
17
.github/workflows/pr.yml
vendored
Normal file
17
.github/workflows/pr.yml
vendored
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
name: CI-PR
|
||||||
|
|
||||||
|
on: [pull_request]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-binary:
|
||||||
|
runs-on: ubuntu-18.04
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: build binary
|
||||||
|
run: |
|
||||||
|
docker build . -t builder
|
||||||
|
docker run --rm -v ${PWD}:/project builder make
|
||||||
|
- uses: actions/upload-artifact@master
|
||||||
|
with:
|
||||||
|
name: binary
|
||||||
|
path: "*.wps"
|
11
.gitignore
vendored
Normal file
11
.gitignore
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
build/*
|
||||||
|
*.mod
|
||||||
|
sysapp.layout
|
||||||
|
sysapp.cbp
|
||||||
|
src/filelist.h
|
||||||
|
cmake-build-debug/CMakeCache.txt
|
||||||
|
cmake-build-debug/
|
||||||
|
.idea/
|
||||||
|
*.wps
|
||||||
|
*.elf
|
||||||
|
CMakeLists.txt
|
6
Dockerfile
Normal file
6
Dockerfile
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
FROM wiiuenv/devkitppc:20210920
|
||||||
|
|
||||||
|
COPY --from=wiiuenv/wiiupluginsystem:20211001 /artifacts $DEVKITPRO
|
||||||
|
COPY --from=wiiuenv/libmappedmemory:20210924 /artifacts $DEVKITPRO
|
||||||
|
|
||||||
|
WORKDIR project
|
137
Makefile
Normal file
137
Makefile
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
.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 := regionfree
|
||||||
|
BUILD := build
|
||||||
|
SOURCES := src
|
||||||
|
DATA := data
|
||||||
|
INCLUDES := src
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
# options for code generation
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
CFLAGS := -g -Wall -O0 -ffunction-sections \
|
||||||
|
$(MACHDEP)
|
||||||
|
|
||||||
|
CFLAGS += $(INCLUDE) -D__WIIU__ -D__WUT__ -D__WUPS__
|
||||||
|
|
||||||
|
CXXFLAGS := $(CFLAGS)
|
||||||
|
|
||||||
|
ASFLAGS := -g $(ARCH)
|
||||||
|
LDFLAGS = -g $(ARCH) $(RPXSPECS) -Wl,-Map,$(notdir $*.map) -T$(WUMS_ROOT)/share/libmappedmemory.ld $(WUPSSPECS)
|
||||||
|
|
||||||
|
LIBS := -lwut -lwups -lmappedmemory -lfreetype -lbz2 -lz -lpng
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
# list of directories containing libraries, this must be the top level
|
||||||
|
# containing include and lib
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
LIBDIRS := $(PORTLIBS) $(WUT_ROOT) $(WUPS_ROOT) $(WUMS_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) -I$(DEVKITPRO)/portlibs/ppc/include/freetype2
|
||||||
|
|
||||||
|
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
|
||||||
|
|
||||||
|
.PHONY: $(BUILD) clean all
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
all: $(BUILD)
|
||||||
|
|
||||||
|
$(BUILD):
|
||||||
|
@[ -d $@ ] || mkdir -p $@
|
||||||
|
@$(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)
|
||||||
|
|
||||||
|
-include $(DEPENDS)
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
endif
|
||||||
|
#-------------------------------------------------------------------------------
|
45
README.md
Normal file
45
README.md
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
# Region Free Plugin
|
||||||
|
|
||||||
|
This plugin allows you to launch an title of an other region and / or force a language of an title.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
Load the plugin with the [Wii U Plugin System Backend](https://github.com/wiiu-env/WiiUPluginLoaderBackend) by placing it on the SD Card into the
|
||||||
|
directory `sd:/wiiu/plugin/`
|
||||||
|
|
||||||
|
At the first launch with the plugin open the config menu (press ZL, DPAD Down and Minus on the gamepad) and set your default language for each region.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
The plugin has a built in auto detection, so in most cases it just works out of the box.
|
||||||
|
|
||||||
|
Via the plugin config menu (press ZL, DPAD Down and Minus on the gamepad) you can configurate the plugin. The avaible options are the following:
|
||||||
|
|
||||||
|
- **Auto Detection**: Enabled/Disabled the auto detection of the region/language. When you disable it, you need/can set the region and language for a title on each title start. Enabled by default.
|
||||||
|
- **Prefer System Settings For Own Region**: Forces the region and language of your console when starting an title or your region (Ignoring "Default Language for Region"). Enabled by default.
|
||||||
|
- **Default Language for EUR**: Sets the default language for EUR titles. Set to English by default.
|
||||||
|
- **Default Language for USA**: Sets the default language for USA titles. Set to English by default.
|
||||||
|
|
||||||
|
If the auto detection fails, the user needs to enter a region/language on the title boot.
|
||||||
|
|
||||||
|
The plugin keeps tracks the region/language the user has selected for an title.
|
||||||
|
|
||||||
|
Scenario:
|
||||||
|
- The User has disabled the auto detection and booted a EUR version of Mario Kart 8 in German on their US console.
|
||||||
|
- The User then enables the auto detection and set the default language for EUR titles to English.
|
||||||
|
- The EUR version of Mario Kart 8 will still boot in German. To change the language the user has to disable the auto detection and reboot the title.
|
||||||
|
|
||||||
|
## Building using the Dockerfile
|
||||||
|
|
||||||
|
It's possible to use a docker image for building. This way you don't need anything installed on your host system.
|
||||||
|
|
||||||
|
```
|
||||||
|
# Build docker image (only needed once)
|
||||||
|
docker build . -t regionfree_plugin-builder
|
||||||
|
|
||||||
|
# make
|
||||||
|
docker run -it --rm -v ${PWD}:/project regionfree_plugin-builder make
|
||||||
|
|
||||||
|
# make clean
|
||||||
|
docker run -it --rm -v ${PWD}:/project regionfree_plugin-builder make clean
|
||||||
|
```
|
362
src/ConfigUtils.cpp
Normal file
362
src/ConfigUtils.cpp
Normal file
@ -0,0 +1,362 @@
|
|||||||
|
#include "ConfigUtils.h"
|
||||||
|
|
||||||
|
#include "utils/logger.h"
|
||||||
|
#include "DrawUtils.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <coreinit/screen.h>
|
||||||
|
#include <memory/mappedmemory.h>
|
||||||
|
#include <vpad/input.h>
|
||||||
|
#include <padscore/kpad.h>
|
||||||
|
#include <coreinit/mcp.h>
|
||||||
|
#include <map>
|
||||||
|
#include "globals.h"
|
||||||
|
|
||||||
|
#define COLOR_BACKGROUND Color(238, 238, 238, 255)
|
||||||
|
#define COLOR_TEXT Color(51, 51, 51, 255)
|
||||||
|
#define COLOR_TEXT2 Color(72, 72, 72, 255)
|
||||||
|
#define COLOR_DISABLED Color(255, 0, 0, 255)
|
||||||
|
#define COLOR_BORDER Color(204, 204, 204, 255)
|
||||||
|
#define COLOR_BORDER_HIGHLIGHTED Color(0x3478e4FF)
|
||||||
|
#define COLOR_WHITE Color(0xFFFFFFFF)
|
||||||
|
#define COLOR_BLACK Color(0, 0, 0, 255)
|
||||||
|
|
||||||
|
#define MAX_BUTTONS_ON_SCREEN 8
|
||||||
|
|
||||||
|
static uint32_t remapWiiMoteButtons(uint32_t buttons) {
|
||||||
|
uint32_t conv_buttons = 0;
|
||||||
|
|
||||||
|
if (buttons & WPAD_BUTTON_LEFT)
|
||||||
|
conv_buttons |= VPAD_BUTTON_LEFT;
|
||||||
|
|
||||||
|
if (buttons & WPAD_BUTTON_RIGHT)
|
||||||
|
conv_buttons |= VPAD_BUTTON_RIGHT;
|
||||||
|
|
||||||
|
if (buttons & WPAD_BUTTON_DOWN)
|
||||||
|
conv_buttons |= VPAD_BUTTON_DOWN;
|
||||||
|
|
||||||
|
if (buttons & WPAD_BUTTON_UP)
|
||||||
|
conv_buttons |= VPAD_BUTTON_UP;
|
||||||
|
|
||||||
|
if (buttons & WPAD_BUTTON_PLUS)
|
||||||
|
conv_buttons |= VPAD_BUTTON_PLUS;
|
||||||
|
|
||||||
|
if (buttons & WPAD_BUTTON_B)
|
||||||
|
conv_buttons |= VPAD_BUTTON_B;
|
||||||
|
|
||||||
|
if (buttons & WPAD_BUTTON_A)
|
||||||
|
conv_buttons |= VPAD_BUTTON_A;
|
||||||
|
|
||||||
|
if (buttons & WPAD_BUTTON_MINUS)
|
||||||
|
conv_buttons |= VPAD_BUTTON_MINUS;
|
||||||
|
|
||||||
|
if (buttons & WPAD_BUTTON_HOME)
|
||||||
|
conv_buttons |= VPAD_BUTTON_HOME;
|
||||||
|
|
||||||
|
return conv_buttons;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t remapClassicButtons(uint32_t buttons) {
|
||||||
|
uint32_t conv_buttons = 0;
|
||||||
|
|
||||||
|
if (buttons & WPAD_CLASSIC_BUTTON_LEFT)
|
||||||
|
conv_buttons |= VPAD_BUTTON_LEFT;
|
||||||
|
|
||||||
|
if (buttons & WPAD_CLASSIC_BUTTON_RIGHT)
|
||||||
|
conv_buttons |= VPAD_BUTTON_RIGHT;
|
||||||
|
|
||||||
|
if (buttons & WPAD_CLASSIC_BUTTON_DOWN)
|
||||||
|
conv_buttons |= VPAD_BUTTON_DOWN;
|
||||||
|
|
||||||
|
if (buttons & WPAD_CLASSIC_BUTTON_UP)
|
||||||
|
conv_buttons |= VPAD_BUTTON_UP;
|
||||||
|
|
||||||
|
if (buttons & WPAD_CLASSIC_BUTTON_PLUS)
|
||||||
|
conv_buttons |= VPAD_BUTTON_PLUS;
|
||||||
|
|
||||||
|
if (buttons & WPAD_CLASSIC_BUTTON_X)
|
||||||
|
conv_buttons |= VPAD_BUTTON_X;
|
||||||
|
|
||||||
|
if (buttons & WPAD_CLASSIC_BUTTON_Y)
|
||||||
|
conv_buttons |= VPAD_BUTTON_Y;
|
||||||
|
|
||||||
|
if (buttons & WPAD_CLASSIC_BUTTON_B)
|
||||||
|
conv_buttons |= VPAD_BUTTON_B;
|
||||||
|
|
||||||
|
if (buttons & WPAD_CLASSIC_BUTTON_A)
|
||||||
|
conv_buttons |= VPAD_BUTTON_A;
|
||||||
|
|
||||||
|
if (buttons & WPAD_CLASSIC_BUTTON_MINUS)
|
||||||
|
conv_buttons |= VPAD_BUTTON_MINUS;
|
||||||
|
|
||||||
|
if (buttons & WPAD_CLASSIC_BUTTON_HOME)
|
||||||
|
conv_buttons |= VPAD_BUTTON_HOME;
|
||||||
|
|
||||||
|
if (buttons & WPAD_CLASSIC_BUTTON_ZR)
|
||||||
|
conv_buttons |= VPAD_BUTTON_ZR;
|
||||||
|
|
||||||
|
if (buttons & WPAD_CLASSIC_BUTTON_ZL)
|
||||||
|
conv_buttons |= VPAD_BUTTON_ZL;
|
||||||
|
|
||||||
|
if (buttons & WPAD_CLASSIC_BUTTON_R)
|
||||||
|
conv_buttons |= VPAD_BUTTON_R;
|
||||||
|
|
||||||
|
if (buttons & WPAD_CLASSIC_BUTTON_L)
|
||||||
|
conv_buttons |= VPAD_BUTTON_L;
|
||||||
|
|
||||||
|
return conv_buttons;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigUtils::displayMenu() {
|
||||||
|
bool redraw = true;
|
||||||
|
uint32_t buttonsTriggered;
|
||||||
|
uint32_t buttonsReleased;
|
||||||
|
|
||||||
|
VPADStatus vpad_data{};
|
||||||
|
VPADReadError vpad_error;
|
||||||
|
KPADStatus kpad_data{};
|
||||||
|
int32_t kpad_error;
|
||||||
|
|
||||||
|
auto selectedBtn = 0;
|
||||||
|
|
||||||
|
std::map<MCPRegion, const char *> region_map{
|
||||||
|
{MCP_REGION_JAPAN, "Japan"},
|
||||||
|
{MCP_REGION_USA, "USA"},
|
||||||
|
{MCP_REGION_EUROPE, "Europe"},
|
||||||
|
};
|
||||||
|
|
||||||
|
std::map<MCPRegion, int32_t> region_map_to_index{
|
||||||
|
{MCP_REGION_JAPAN, 0},
|
||||||
|
{MCP_REGION_USA, 1},
|
||||||
|
{MCP_REGION_EUROPE, 2},
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
std::map<int32_t, MCPRegion> region_index_to_map{
|
||||||
|
{0, MCP_REGION_JAPAN},
|
||||||
|
{1, MCP_REGION_USA},
|
||||||
|
{2, MCP_REGION_EUROPE},
|
||||||
|
};
|
||||||
|
|
||||||
|
auto curSelectedRegion = gCurrentProductArea;
|
||||||
|
DEBUG_FUNCTION_LINE("Current %d", curSelectedRegion);
|
||||||
|
|
||||||
|
std::map<Lanuages, const char *> lang_map{
|
||||||
|
{LANG_JAPANESE, "Japanese"},
|
||||||
|
{LANG_ENGLISH, "English"},
|
||||||
|
{LANG_FRANCAIS, "Francais"},
|
||||||
|
{LANG_DEUTSCH, "Deutsch"},
|
||||||
|
{LANG_ITALIANO, "Italiano"},
|
||||||
|
{LANG_ESPANOL, "Espanol"},
|
||||||
|
{LANG_NEDERLANDS, "Nederlands"},
|
||||||
|
{LANG_PORTUGUES, "Portugues"},
|
||||||
|
{LANG_RUSSKI, "Russki"},
|
||||||
|
};
|
||||||
|
std::map<Lanuages, int32_t> lang_map_to_index{
|
||||||
|
{LANG_JAPANESE, 0},
|
||||||
|
{LANG_ENGLISH, 1},
|
||||||
|
{LANG_FRANCAIS, 2},
|
||||||
|
{LANG_DEUTSCH, 3},
|
||||||
|
{LANG_ITALIANO, 4},
|
||||||
|
{LANG_ESPANOL, 5},
|
||||||
|
{LANG_NEDERLANDS, 6},
|
||||||
|
{LANG_PORTUGUES, 7},
|
||||||
|
{LANG_RUSSKI, 8},
|
||||||
|
};
|
||||||
|
std::map<int32_t, Lanuages> lang_index_to_map{
|
||||||
|
{0, LANG_JAPANESE},
|
||||||
|
{1, LANG_ENGLISH},
|
||||||
|
{2, LANG_FRANCAIS},
|
||||||
|
{3, LANG_DEUTSCH},
|
||||||
|
{4, LANG_ITALIANO},
|
||||||
|
{5, LANG_ESPANOL},
|
||||||
|
{6, LANG_NEDERLANDS},
|
||||||
|
{7, LANG_PORTUGUES},
|
||||||
|
{8, LANG_RUSSKI},
|
||||||
|
};
|
||||||
|
|
||||||
|
auto curSelectedLanguage = gCurrentLanguage;
|
||||||
|
|
||||||
|
int32_t curRegionIndex = region_map_to_index[curSelectedRegion];
|
||||||
|
int32_t curLangIndex = lang_map_to_index[curSelectedLanguage];
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
buttonsTriggered = 0;
|
||||||
|
buttonsReleased = 0;
|
||||||
|
|
||||||
|
VPADRead(VPAD_CHAN_0, &vpad_data, 1, &vpad_error);
|
||||||
|
if (vpad_error == VPAD_READ_SUCCESS) {
|
||||||
|
buttonsTriggered = vpad_data.trigger;
|
||||||
|
buttonsReleased = vpad_data.release;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
if (KPADReadEx((KPADChan) i, &kpad_data, 1, &kpad_error) > 0) {
|
||||||
|
if (kpad_error == KPAD_ERROR_OK) {
|
||||||
|
if (kpad_data.extensionType == WPAD_EXT_CORE || kpad_data.extensionType == WPAD_EXT_NUNCHUK) {
|
||||||
|
buttonsTriggered |= remapWiiMoteButtons(kpad_data.trigger);
|
||||||
|
buttonsReleased |= remapWiiMoteButtons(kpad_data.release);
|
||||||
|
} else {
|
||||||
|
buttonsTriggered |= remapClassicButtons(kpad_data.classic.trigger);
|
||||||
|
buttonsReleased |= remapClassicButtons(kpad_data.classic.release);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buttonsTriggered & VPAD_BUTTON_HOME) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buttonsTriggered & VPAD_BUTTON_DOWN) {
|
||||||
|
selectedBtn++;
|
||||||
|
redraw = true;
|
||||||
|
} else if (buttonsTriggered & VPAD_BUTTON_UP) {
|
||||||
|
selectedBtn--;
|
||||||
|
redraw = true;
|
||||||
|
}
|
||||||
|
if (selectedBtn < 0) {
|
||||||
|
selectedBtn = 0;
|
||||||
|
}
|
||||||
|
if (selectedBtn >= 1) {
|
||||||
|
selectedBtn = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selectedBtn == 0) {
|
||||||
|
if (buttonsTriggered & VPAD_BUTTON_LEFT) {
|
||||||
|
curRegionIndex--;
|
||||||
|
redraw = true;
|
||||||
|
} else if (buttonsTriggered & VPAD_BUTTON_RIGHT) {
|
||||||
|
curRegionIndex++;
|
||||||
|
redraw = true;
|
||||||
|
}
|
||||||
|
if (curRegionIndex < 0) {
|
||||||
|
curRegionIndex = 0;
|
||||||
|
}
|
||||||
|
if (curRegionIndex >= region_map.size()) {
|
||||||
|
curRegionIndex = region_map.size() - 1;
|
||||||
|
}
|
||||||
|
gCurrentProductArea = region_index_to_map[curRegionIndex];
|
||||||
|
curSelectedRegion = gCurrentProductArea;
|
||||||
|
} else if (selectedBtn == 1) {
|
||||||
|
if (buttonsTriggered & VPAD_BUTTON_LEFT) {
|
||||||
|
curLangIndex--;
|
||||||
|
redraw = true;
|
||||||
|
} else if (buttonsTriggered & VPAD_BUTTON_RIGHT) {
|
||||||
|
curLangIndex++;
|
||||||
|
redraw = true;
|
||||||
|
}
|
||||||
|
if (curLangIndex < 0) {
|
||||||
|
curLangIndex = 0;
|
||||||
|
}
|
||||||
|
if (curLangIndex >= lang_map.size()) {
|
||||||
|
curLangIndex = lang_map.size() - 1;
|
||||||
|
}
|
||||||
|
gCurrentLanguage = lang_index_to_map[curLangIndex];
|
||||||
|
curSelectedLanguage = gCurrentLanguage;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (redraw) {
|
||||||
|
DrawUtils::beginDraw();
|
||||||
|
DrawUtils::clear(COLOR_BACKGROUND);
|
||||||
|
|
||||||
|
DrawUtils::setFontColor(COLOR_TEXT);
|
||||||
|
|
||||||
|
std::string headline = "Region Free Plugin";
|
||||||
|
|
||||||
|
// draw top bar
|
||||||
|
DrawUtils::setFontSize(24);
|
||||||
|
DrawUtils::print(16, 6 + 24, headline.c_str());
|
||||||
|
DrawUtils::drawRectFilled(8, 8 + 24 + 4, SCREEN_WIDTH - 8 * 2, 3, COLOR_BLACK);
|
||||||
|
DrawUtils::setFontSize(18);
|
||||||
|
|
||||||
|
// draw buttons
|
||||||
|
uint32_t index = 8 + 24 + 8 + 4;
|
||||||
|
|
||||||
|
DEBUG_FUNCTION_LINE("%d", selectedBtn);
|
||||||
|
|
||||||
|
DrawUtils::setFontColor(COLOR_TEXT);
|
||||||
|
DrawUtils::setFontSize(24);
|
||||||
|
|
||||||
|
if (selectedBtn == 0) {
|
||||||
|
DrawUtils::drawRect(16, index, SCREEN_WIDTH - 16 * 2, 44, 4, COLOR_BORDER_HIGHLIGHTED);
|
||||||
|
} else {
|
||||||
|
DrawUtils::drawRect(16, index, SCREEN_WIDTH - 16 * 2, 44, 2, COLOR_BORDER);
|
||||||
|
}
|
||||||
|
|
||||||
|
DrawUtils::print(16 * 2, index + 8 + 24, "Region");
|
||||||
|
DrawUtils::print(SCREEN_WIDTH - 16 * 2, index + 8 + 24, region_map[curSelectedRegion], true);
|
||||||
|
index += 42 + 8;
|
||||||
|
|
||||||
|
if (selectedBtn == 1) {
|
||||||
|
DrawUtils::drawRect(16, index, SCREEN_WIDTH - 16 * 2, 44, 4, COLOR_BORDER_HIGHLIGHTED);
|
||||||
|
} else {
|
||||||
|
DrawUtils::drawRect(16, index, SCREEN_WIDTH - 16 * 2, 44, 2, COLOR_BORDER);
|
||||||
|
}
|
||||||
|
DrawUtils::print(16 * 2, index + 8 + 24, "Language");
|
||||||
|
|
||||||
|
DrawUtils::print(SCREEN_WIDTH - 16 * 2, index + 8 + 24, lang_map[curSelectedLanguage], true);
|
||||||
|
|
||||||
|
index += 42 + 8;
|
||||||
|
|
||||||
|
// draw bottom bar
|
||||||
|
DrawUtils::drawRectFilled(8, SCREEN_HEIGHT - 24 - 8 - 4, SCREEN_WIDTH - 8 * 2, 3, COLOR_BLACK);
|
||||||
|
DrawUtils::setFontSize(18);
|
||||||
|
DrawUtils::print(16, SCREEN_HEIGHT - 8, "\ue07d Navigate ");
|
||||||
|
DrawUtils::print(SCREEN_WIDTH - 16, SCREEN_HEIGHT - 8, "\ue001 Back", true);
|
||||||
|
|
||||||
|
DrawUtils::endDraw();
|
||||||
|
redraw = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DrawUtils::beginDraw();
|
||||||
|
DrawUtils::clear(COLOR_BLACK);
|
||||||
|
DrawUtils::endDraw();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigUtils::openConfigMenu() {
|
||||||
|
OSScreenInit();
|
||||||
|
|
||||||
|
uint32_t screen_buf0_size = OSScreenGetBufferSizeEx(SCREEN_TV);
|
||||||
|
uint32_t screen_buf1_size = OSScreenGetBufferSizeEx(SCREEN_DRC);
|
||||||
|
void *screenbuffer0 = MEMAllocFromMappedMemoryForGX2Ex(screen_buf0_size, 0x100);
|
||||||
|
void *screenbuffer1 = MEMAllocFromMappedMemoryForGX2Ex(screen_buf1_size, 0x100);
|
||||||
|
|
||||||
|
if (!screenbuffer0 || !screenbuffer1) {
|
||||||
|
DEBUG_FUNCTION_LINE("Failed to alloc buffers");
|
||||||
|
goto error_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSScreenSetBufferEx(SCREEN_TV, screenbuffer0);
|
||||||
|
OSScreenSetBufferEx(SCREEN_DRC, screenbuffer1);
|
||||||
|
|
||||||
|
OSScreenEnableEx(SCREEN_TV, 1);
|
||||||
|
OSScreenEnableEx(SCREEN_DRC, 1);
|
||||||
|
|
||||||
|
// Clear screens
|
||||||
|
OSScreenClearBufferEx(SCREEN_TV, 0);
|
||||||
|
OSScreenClearBufferEx(SCREEN_DRC, 0);
|
||||||
|
|
||||||
|
// Flip buffers
|
||||||
|
OSScreenFlipBuffersEx(SCREEN_TV);
|
||||||
|
OSScreenFlipBuffersEx(SCREEN_DRC);
|
||||||
|
|
||||||
|
DrawUtils::initBuffers(screenbuffer0, screen_buf0_size, screenbuffer1, screen_buf1_size);
|
||||||
|
DrawUtils::initFont();
|
||||||
|
|
||||||
|
displayMenu();
|
||||||
|
|
||||||
|
DrawUtils::deinitFont();
|
||||||
|
|
||||||
|
error_exit:
|
||||||
|
|
||||||
|
if (screenbuffer0) {
|
||||||
|
MEMFreeToMappedMemory(screenbuffer0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (screenbuffer1) {
|
||||||
|
MEMFreeToMappedMemory(screenbuffer1);
|
||||||
|
}
|
||||||
|
}
|
11
src/ConfigUtils.h
Normal file
11
src/ConfigUtils.h
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <gx2/enum.h>
|
||||||
|
|
||||||
|
class ConfigUtils {
|
||||||
|
public:
|
||||||
|
static void openConfigMenu();
|
||||||
|
|
||||||
|
private:
|
||||||
|
static void displayMenu();
|
||||||
|
};
|
252
src/DrawUtils.cpp
Normal file
252
src/DrawUtils.cpp
Normal file
@ -0,0 +1,252 @@
|
|||||||
|
#include "DrawUtils.h"
|
||||||
|
|
||||||
|
#include <coreinit/memory.h>
|
||||||
|
#include <coreinit/screen.h>
|
||||||
|
#include <ft2build.h>
|
||||||
|
#include FT_FREETYPE_H
|
||||||
|
|
||||||
|
// buffer width
|
||||||
|
#define TV_WIDTH 0x500
|
||||||
|
#define DRC_WIDTH 0x380
|
||||||
|
|
||||||
|
bool DrawUtils::isBackBuffer;
|
||||||
|
|
||||||
|
uint8_t *DrawUtils::tvBuffer = nullptr;
|
||||||
|
uint32_t DrawUtils::tvSize = 0;
|
||||||
|
uint8_t *DrawUtils::drcBuffer = nullptr;
|
||||||
|
uint32_t DrawUtils::drcSize = 0;
|
||||||
|
|
||||||
|
// Don't put those into the clase or we have to include ft everywhere
|
||||||
|
static FT_Library ft_lib = nullptr;
|
||||||
|
static FT_Face ft_face = nullptr;
|
||||||
|
static Color font_col(0xFFFFFFFF);
|
||||||
|
|
||||||
|
void DrawUtils::initBuffers(void *tvBuffer_, uint32_t tvSize_, void *drcBuffer_, uint32_t drcSize_) {
|
||||||
|
DrawUtils::tvBuffer = (uint8_t *) tvBuffer_;
|
||||||
|
DrawUtils::tvSize = tvSize_;
|
||||||
|
DrawUtils::drcBuffer = (uint8_t *) drcBuffer_;
|
||||||
|
DrawUtils::drcSize = drcSize_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawUtils::beginDraw() {
|
||||||
|
uint32_t pixel = *(uint32_t *) tvBuffer;
|
||||||
|
|
||||||
|
// check which buffer is currently used
|
||||||
|
OSScreenPutPixelEx(SCREEN_TV, 0, 0, 0xABCDEF90);
|
||||||
|
if (*(uint32_t *) tvBuffer == 0xABCDEF90) {
|
||||||
|
isBackBuffer = false;
|
||||||
|
} else {
|
||||||
|
isBackBuffer = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// restore the pixel we used for checking
|
||||||
|
*(uint32_t *) tvBuffer = pixel;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawUtils::endDraw() {
|
||||||
|
// OSScreenFlipBuffersEx already flushes the cache?
|
||||||
|
// DCFlushRange(tvBuffer, tvSize);
|
||||||
|
// DCFlushRange(drcBuffer, drcSize);
|
||||||
|
|
||||||
|
OSScreenFlipBuffersEx(SCREEN_DRC);
|
||||||
|
OSScreenFlipBuffersEx(SCREEN_TV);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawUtils::clear(Color col) {
|
||||||
|
OSScreenClearBufferEx(SCREEN_TV, col.color);
|
||||||
|
OSScreenClearBufferEx(SCREEN_DRC, col.color);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawUtils::drawPixel(uint32_t x, uint32_t y, uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
|
||||||
|
float opacity = a / 255.0f;
|
||||||
|
|
||||||
|
// put pixel in the drc buffer
|
||||||
|
uint32_t i = (x + y * DRC_WIDTH) * 4;
|
||||||
|
if (i + 3 < drcSize / 2) {
|
||||||
|
if (isBackBuffer) {
|
||||||
|
i += drcSize / 2;
|
||||||
|
}
|
||||||
|
if (a == 0xFF) {
|
||||||
|
drcBuffer[i] = r;
|
||||||
|
drcBuffer[i + 1] = g;
|
||||||
|
drcBuffer[i + 2] = b;
|
||||||
|
} else {
|
||||||
|
drcBuffer[i] = r * opacity + drcBuffer[i] * (1 - opacity);
|
||||||
|
drcBuffer[i + 1] = g * opacity + drcBuffer[i + 1] * (1 - opacity);
|
||||||
|
drcBuffer[i + 2] = b * opacity + drcBuffer[i + 2] * (1 - opacity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// scale and put pixel in the tv buffer
|
||||||
|
for (uint32_t yy = (y * 1.5); yy < ((y * 1.5) + 1); yy++) {
|
||||||
|
for (uint32_t xx = (x * 1.5); xx < ((x * 1.5) + 1); xx++) {
|
||||||
|
uint32_t i = (xx + yy * TV_WIDTH) * 4;
|
||||||
|
if (i + 3 < tvSize / 2) {
|
||||||
|
if (isBackBuffer) {
|
||||||
|
i += tvSize / 2;
|
||||||
|
}
|
||||||
|
if (a == 0xFF) {
|
||||||
|
tvBuffer[i] = r;
|
||||||
|
tvBuffer[i + 1] = g;
|
||||||
|
tvBuffer[i + 2] = b;
|
||||||
|
} else {
|
||||||
|
tvBuffer[i] = r * opacity + tvBuffer[i] * (1 - opacity);
|
||||||
|
tvBuffer[i + 1] = g * opacity + tvBuffer[i + 1] * (1 - opacity);
|
||||||
|
tvBuffer[i + 2] = b * opacity + tvBuffer[i + 2] * (1 - opacity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawUtils::drawRectFilled(uint32_t x, uint32_t y, uint32_t w, uint32_t h, Color col) {
|
||||||
|
for (uint32_t yy = y; yy < y + h; yy++) {
|
||||||
|
for (uint32_t xx = x; xx < x + w; xx++) {
|
||||||
|
drawPixel(xx, yy, col);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawUtils::drawRect(uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint32_t borderSize, Color col) {
|
||||||
|
drawRectFilled(x, y, w, borderSize, col);
|
||||||
|
drawRectFilled(x, y + h - borderSize, w, borderSize, col);
|
||||||
|
drawRectFilled(x, y, borderSize, h, col);
|
||||||
|
drawRectFilled(x + w - borderSize, y, borderSize, h, col);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawUtils::drawBitmap(uint32_t x, uint32_t y, uint32_t target_width, uint32_t target_height, const uint8_t *data) {
|
||||||
|
if (data[0] != 'B' || data[1] != 'M') {
|
||||||
|
// invalid header
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t dataPos = __builtin_bswap32(*(uint32_t *) &(data[0x0A]));
|
||||||
|
uint32_t width = __builtin_bswap32(*(uint32_t *) &(data[0x12]));
|
||||||
|
uint32_t height = __builtin_bswap32(*(uint32_t *) &(data[0x16]));
|
||||||
|
|
||||||
|
if (dataPos == 0) {
|
||||||
|
dataPos = 54;
|
||||||
|
}
|
||||||
|
|
||||||
|
data += dataPos;
|
||||||
|
|
||||||
|
// TODO flip image since bitmaps are stored upside down
|
||||||
|
|
||||||
|
for (uint32_t yy = y; yy < y + target_height; yy++) {
|
||||||
|
for (uint32_t xx = x; xx < x + target_width; xx++) {
|
||||||
|
uint32_t i = (((xx - x) * width / target_width) + ((yy - y) * height / target_height) * width) * 3;
|
||||||
|
drawPixel(xx, yy, data[i + 2], data[i + 1], data[i], 0xFF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawUtils::initFont() {
|
||||||
|
void *font = nullptr;
|
||||||
|
uint32_t size = 0;
|
||||||
|
OSGetSharedData(OS_SHAREDDATATYPE_FONT_STANDARD, 0, &font, &size);
|
||||||
|
|
||||||
|
if (font && size) {
|
||||||
|
FT_Init_FreeType(&ft_lib);
|
||||||
|
FT_New_Memory_Face(ft_lib, (FT_Byte *) font, size, 0, &ft_face);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawUtils::deinitFont() {
|
||||||
|
FT_Done_Face(ft_face);
|
||||||
|
FT_Done_FreeType(ft_lib);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawUtils::setFontSize(uint32_t size) {
|
||||||
|
FT_Set_Pixel_Sizes(ft_face, 0, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawUtils::setFontColor(Color col) {
|
||||||
|
font_col = col;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void draw_freetype_bitmap(FT_Bitmap *bitmap, FT_Int x, FT_Int y) {
|
||||||
|
FT_Int i, j, p, q;
|
||||||
|
FT_Int x_max = x + bitmap->width;
|
||||||
|
FT_Int y_max = y + bitmap->rows;
|
||||||
|
|
||||||
|
for (i = x, p = 0; i < x_max; i++, p++) {
|
||||||
|
for (j = y, q = 0; j < y_max; j++, q++) {
|
||||||
|
if (i < 0 || j < 0 || i >= SCREEN_WIDTH || j >= SCREEN_HEIGHT) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
float opacity = bitmap->buffer[q * bitmap->pitch + p] / 255.0f;
|
||||||
|
DrawUtils::drawPixel(i, j, font_col.r, font_col.g, font_col.b, font_col.a * opacity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawUtils::print(uint32_t x, uint32_t y, const char *string, bool alignRight) {
|
||||||
|
auto *buffer = new wchar_t[strlen(string) + 1];
|
||||||
|
|
||||||
|
size_t num = mbstowcs(buffer, string, strlen(string));
|
||||||
|
if (num > 0) {
|
||||||
|
buffer[num] = 0;
|
||||||
|
} else {
|
||||||
|
wchar_t *tmp = buffer;
|
||||||
|
while ((*tmp++ = *string++));
|
||||||
|
}
|
||||||
|
|
||||||
|
print(x, y, buffer, alignRight);
|
||||||
|
delete[] buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawUtils::print(uint32_t x, uint32_t y, const wchar_t *string, bool alignRight) {
|
||||||
|
FT_GlyphSlot slot = ft_face->glyph;
|
||||||
|
FT_Vector pen = {(int) x, (int) y};
|
||||||
|
|
||||||
|
if (alignRight) {
|
||||||
|
pen.x -= getTextWidth(string);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; *string; string++) {
|
||||||
|
uint32_t charcode = *string;
|
||||||
|
|
||||||
|
if (charcode == '\n') {
|
||||||
|
pen.y += ft_face->size->metrics.height >> 6;
|
||||||
|
pen.x = x;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
FT_Load_Glyph(ft_face, FT_Get_Char_Index(ft_face, charcode), FT_LOAD_DEFAULT);
|
||||||
|
FT_Render_Glyph(slot, FT_RENDER_MODE_NORMAL);
|
||||||
|
|
||||||
|
draw_freetype_bitmap(&slot->bitmap, pen.x + slot->bitmap_left, pen.y - slot->bitmap_top);
|
||||||
|
pen.x += slot->advance.x >> 6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t DrawUtils::getTextWidth(const char *string) {
|
||||||
|
auto *buffer = new wchar_t[strlen(string) + 1];
|
||||||
|
|
||||||
|
size_t num = mbstowcs(buffer, string, strlen(string));
|
||||||
|
if (num > 0) {
|
||||||
|
buffer[num] = 0;
|
||||||
|
} else {
|
||||||
|
wchar_t *tmp = buffer;
|
||||||
|
while ((*tmp++ = *string++));
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t width = getTextWidth(buffer);
|
||||||
|
delete[] buffer;
|
||||||
|
|
||||||
|
return width;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t DrawUtils::getTextWidth(const wchar_t *string) {
|
||||||
|
FT_GlyphSlot slot = ft_face->glyph;
|
||||||
|
uint32_t width = 0;
|
||||||
|
|
||||||
|
for (; *string; string++) {
|
||||||
|
FT_Load_Glyph(ft_face, FT_Get_Char_Index(ft_face, *string), FT_LOAD_BITMAP_METRICS_ONLY);
|
||||||
|
|
||||||
|
width += slot->advance.x >> 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
return width;
|
||||||
|
}
|
74
src/DrawUtils.h
Normal file
74
src/DrawUtils.h
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
// visible screen sizes
|
||||||
|
#define SCREEN_WIDTH 854
|
||||||
|
#define SCREEN_HEIGHT 480
|
||||||
|
|
||||||
|
union Color {
|
||||||
|
explicit Color(uint32_t color) {
|
||||||
|
this->color = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
Color(uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
|
||||||
|
this->r = r;
|
||||||
|
this->g = g;
|
||||||
|
this->b = b;
|
||||||
|
this->a = a;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t color{};
|
||||||
|
struct {
|
||||||
|
uint8_t r;
|
||||||
|
uint8_t g;
|
||||||
|
uint8_t b;
|
||||||
|
uint8_t a;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
class DrawUtils {
|
||||||
|
public:
|
||||||
|
static void initBuffers(void *tvBuffer, uint32_t tvSize, void *drcBuffer, uint32_t drcSize);
|
||||||
|
|
||||||
|
static void beginDraw();
|
||||||
|
|
||||||
|
static void endDraw();
|
||||||
|
|
||||||
|
static void clear(Color col);
|
||||||
|
|
||||||
|
static void drawPixel(uint32_t x, uint32_t y, Color col) { drawPixel(x, y, col.r, col.g, col.b, col.a); }
|
||||||
|
|
||||||
|
static void drawPixel(uint32_t x, uint32_t y, uint8_t r, uint8_t g, uint8_t b, uint8_t a);
|
||||||
|
|
||||||
|
static void drawRectFilled(uint32_t x, uint32_t y, uint32_t w, uint32_t h, Color col);
|
||||||
|
|
||||||
|
static void drawRect(uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint32_t borderSize, Color col);
|
||||||
|
|
||||||
|
static void drawBitmap(uint32_t x, uint32_t y, uint32_t target_width, uint32_t target_height, const uint8_t *data);
|
||||||
|
|
||||||
|
|
||||||
|
static void initFont();
|
||||||
|
|
||||||
|
static void deinitFont();
|
||||||
|
|
||||||
|
static void setFontSize(uint32_t size);
|
||||||
|
|
||||||
|
static void setFontColor(Color col);
|
||||||
|
|
||||||
|
static void print(uint32_t x, uint32_t y, const char *string, bool alignRight = false);
|
||||||
|
|
||||||
|
static void print(uint32_t x, uint32_t y, const wchar_t *string, bool alignRight = false);
|
||||||
|
|
||||||
|
static uint32_t getTextWidth(const char *string);
|
||||||
|
|
||||||
|
static uint32_t getTextWidth(const wchar_t *string);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static bool isBackBuffer;
|
||||||
|
|
||||||
|
static uint8_t *tvBuffer;
|
||||||
|
static uint32_t tvSize;
|
||||||
|
static uint8_t *drcBuffer;
|
||||||
|
static uint32_t drcSize;
|
||||||
|
};
|
19
src/globals.cpp
Normal file
19
src/globals.cpp
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#include "globals.h"
|
||||||
|
|
||||||
|
int gPreferSystemSettings = 1;
|
||||||
|
int gAutoDetection = 1;
|
||||||
|
int gForceSettingsEnabled = 0;
|
||||||
|
Lanuages gDefaultLanguage = LANG_ENGLISH;
|
||||||
|
int32_t gDefaultCountry = 78;
|
||||||
|
MCPRegion gDefaultProductArea = MCP_REGION_EUROPE;
|
||||||
|
|
||||||
|
Lanuages gCurrentLanguage = gDefaultLanguage;
|
||||||
|
int32_t gCurrentCountry = gDefaultCountry;
|
||||||
|
MCPRegion gCurrentProductArea = gDefaultProductArea;
|
||||||
|
|
||||||
|
Lanuages gDefaultLangForEUR = LANG_ENGLISH;
|
||||||
|
int32_t gDefaultCountryForEUR = 110;
|
||||||
|
Lanuages gDefaultLangForUSA = LANG_ENGLISH;
|
||||||
|
int32_t gDefaultCountryForUSA = 49;
|
||||||
|
Lanuages gDefaultLangForJPN = LANG_JAPANESE;
|
||||||
|
int32_t gDefaultCountryForJPN = 1;
|
35
src/globals.h
Normal file
35
src/globals.h
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <coreinit/mcp.h>
|
||||||
|
|
||||||
|
extern int gForceSettingsEnabled;
|
||||||
|
|
||||||
|
enum Lanuages {
|
||||||
|
LANG_JAPANESE = 0,
|
||||||
|
LANG_ENGLISH = 1,
|
||||||
|
LANG_FRANCAIS = 2,
|
||||||
|
LANG_DEUTSCH = 3,
|
||||||
|
LANG_ESPANOL = 5,
|
||||||
|
LANG_ITALIANO = 4,
|
||||||
|
LANG_NEDERLANDS = 8,
|
||||||
|
LANG_PORTUGUES = 9,
|
||||||
|
LANG_RUSSKI = 10,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
extern int gPreferSystemSettings;
|
||||||
|
extern int gAutoDetection;
|
||||||
|
extern Lanuages gDefaultLanguage;
|
||||||
|
extern int32_t gDefaultCountry;
|
||||||
|
extern MCPRegion gDefaultProductArea;
|
||||||
|
|
||||||
|
extern Lanuages gCurrentLanguage;
|
||||||
|
extern int32_t gCurrentCountry;
|
||||||
|
extern MCPRegion gCurrentProductArea;
|
||||||
|
|
||||||
|
extern Lanuages gDefaultLangForEUR;
|
||||||
|
extern int32_t gDefaultCountryForEUR;
|
||||||
|
extern Lanuages gDefaultLangForUSA;
|
||||||
|
extern int32_t gDefaultCountryForUSA;
|
||||||
|
extern Lanuages gDefaultLangForJPN;
|
||||||
|
extern int32_t gDefaultCountryForJPN;
|
577
src/main.cpp
Normal file
577
src/main.cpp
Normal file
@ -0,0 +1,577 @@
|
|||||||
|
#include <wups.h>
|
||||||
|
#include <whb/log_udp.h>
|
||||||
|
#include <nn/acp.h>
|
||||||
|
#include <coreinit/title.h>
|
||||||
|
#include <coreinit/mcp.h>
|
||||||
|
#include <coreinit/userconfig.h>
|
||||||
|
#include <coreinit/filesystem.h>
|
||||||
|
#include <sysapp/title.h>
|
||||||
|
#include <coreinit/thread.h>
|
||||||
|
#include "utils/logger.h"
|
||||||
|
#include "ConfigUtils.h"
|
||||||
|
#include <malloc.h>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <wups/config/WUPSConfigItemMultipleValues.h>
|
||||||
|
#include <map>
|
||||||
|
#include <coreinit/screen.h>
|
||||||
|
#include <vpad/input.h>
|
||||||
|
#include <padscore/kpad.h>
|
||||||
|
#include <wups/config/WUPSConfigItemBoolean.h>
|
||||||
|
#include "globals.h"
|
||||||
|
|
||||||
|
WUPS_PLUGIN_NAME("Region Free Plugin");
|
||||||
|
WUPS_PLUGIN_DESCRIPTION("Allows the user to load titles from other regions");
|
||||||
|
WUPS_PLUGIN_VERSION("0.1");
|
||||||
|
WUPS_PLUGIN_AUTHOR("Maschell");
|
||||||
|
WUPS_PLUGIN_LICENSE("GPL");
|
||||||
|
|
||||||
|
WUPS_USE_WUT_DEVOPTAB();
|
||||||
|
WUPS_USE_STORAGE("region_free_plugin");
|
||||||
|
|
||||||
|
bool getRealProductArea(MCPRegion* out);
|
||||||
|
|
||||||
|
INITIALIZE_PLUGIN() {
|
||||||
|
WHBLogUdpInit();
|
||||||
|
}
|
||||||
|
|
||||||
|
DECL_FUNCTION(int32_t, ACPGetLaunchMetaXml, ACPMetaXml *metaxml) {
|
||||||
|
int result = real_ACPGetLaunchMetaXml(metaxml);
|
||||||
|
if (metaxml != nullptr) {
|
||||||
|
metaxml->region = 0xFFFFFFFF;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DECL_FUNCTION(int, UCReadSysConfig, int IOHandle, int count, struct UCSysConfig *settings) {
|
||||||
|
int result = real_UCReadSysConfig(IOHandle, count, settings);
|
||||||
|
|
||||||
|
if (gForceSettingsEnabled) {
|
||||||
|
if (result != 0) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(settings->name, "cafe.language") == 0) {
|
||||||
|
DEBUG_FUNCTION_LINE_VERBOSE("UCReadSysConfig: cafe.language found!");
|
||||||
|
DEBUG_FUNCTION_LINE_VERBOSE("UCReadSysConfig: forcing language...");
|
||||||
|
DEBUG_FUNCTION_LINE("UCReadSysConfig: original lang %d, new %d", *((int *) settings->data), gCurrentLanguage);
|
||||||
|
*((int *) settings->data) = gCurrentLanguage;
|
||||||
|
}
|
||||||
|
if (strcmp(settings->name, "cafe.cntry_reg") == 0) {
|
||||||
|
DEBUG_FUNCTION_LINE_VERBOSE("UCReadSysConfig: cafe.cntry_reg found!");
|
||||||
|
DEBUG_FUNCTION_LINE_VERBOSE("UCReadSysConfig: forcing cntry_reg...");
|
||||||
|
DEBUG_FUNCTION_LINE("UCReadSysConfig: original cntry_reg %d, new %d", *((int *) settings->data), gCurrentCountry);
|
||||||
|
*((int *) settings->data) = gCurrentCountry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
ON_APPLICATION_ENDS() {
|
||||||
|
gCurrentLanguage = gDefaultLanguage;
|
||||||
|
gCurrentCountry = gDefaultCountry;
|
||||||
|
gCurrentProductArea = gDefaultProductArea;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define CAT_GENERAL_ROOT "root"
|
||||||
|
#define CAT_GENERAL_SETTINGS "general_settings"
|
||||||
|
#define CAT_TITLE_SETTINGS "title_settings"
|
||||||
|
|
||||||
|
#define VAL_LANGUAGE "language"
|
||||||
|
#define VAL_COUNTRY "cntry_reg"
|
||||||
|
#define VAL_PRODUCT_AREA "product_area"
|
||||||
|
|
||||||
|
#define VAL_PREFER_SYSTEM_SETTINGS "prefer_system_settings"
|
||||||
|
#define VAL_AUTO_DETECTION "auto_detection"
|
||||||
|
#define VAL_DEFAULT_LANG_EUR "default_lang_eur"
|
||||||
|
#define VAL_DEFAULT_LANG_USA "default_lang_usa"
|
||||||
|
#define VAL_DEFAULT_LANG_JPN "default_lang_jpn"
|
||||||
|
|
||||||
|
#define VAL_DEFAULT_COUNTRY_EUR "default_cntry_reg_eur"
|
||||||
|
#define VAL_DEFAULT_COUNTRY_USA "default_cntry_reg_usa"
|
||||||
|
#define VAL_DEFAULT_COUNTRY_JPN "default_cntry_reg_jpn"
|
||||||
|
|
||||||
|
extern "C" void ACPInitialize();
|
||||||
|
extern "C" void ACPFinalize();
|
||||||
|
|
||||||
|
DECL_FUNCTION(int32_t, ACPGetTitleMetaXmlByDevice, uint32_t titleid_upper, uint32_t titleid_lower, ACPMetaXml *metaxml, uint32_t device) {
|
||||||
|
int result = real_ACPGetTitleMetaXmlByDevice(titleid_upper, titleid_lower, metaxml, device);
|
||||||
|
if (metaxml != nullptr) {
|
||||||
|
metaxml->region = 0xFFFFFFFF;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
ON_FUNCTIONS_PATCHED() {
|
||||||
|
bool forceConfigMenu = false;
|
||||||
|
auto *acpMetaXml = (ACPMetaXml *) memalign(0x40, 0x4000);
|
||||||
|
|
||||||
|
memset(acpMetaXml, 0, sizeof(ACPMetaXml));
|
||||||
|
auto regionFromXML = 0;
|
||||||
|
if (acpMetaXml) {
|
||||||
|
ACPInitialize();
|
||||||
|
auto res = real_ACPGetLaunchMetaXml(acpMetaXml);
|
||||||
|
if (res >= 0) {
|
||||||
|
regionFromXML = acpMetaXml->region;
|
||||||
|
if (acpMetaXml->region == 1) {
|
||||||
|
DEBUG_FUNCTION_LINE("Set default to JAPAN");
|
||||||
|
gDefaultProductArea = MCP_REGION_JAPAN;
|
||||||
|
gDefaultLanguage = gDefaultLangForJPN;
|
||||||
|
gDefaultCountry = gDefaultCountryForJPN;
|
||||||
|
} else if (acpMetaXml->region == 2) {
|
||||||
|
DEBUG_FUNCTION_LINE("Set default to USA");
|
||||||
|
gDefaultProductArea = MCP_REGION_USA;
|
||||||
|
gDefaultLanguage = gDefaultLangForUSA;
|
||||||
|
gDefaultCountry = gDefaultCountryForUSA;
|
||||||
|
} else if (acpMetaXml->region == 4) {
|
||||||
|
DEBUG_FUNCTION_LINE("Set default to EUR");
|
||||||
|
gDefaultProductArea = MCP_REGION_EUROPE;
|
||||||
|
gDefaultLanguage = gDefaultLangForEUR;
|
||||||
|
gDefaultCountry = gDefaultCountryForEUR;
|
||||||
|
} else {
|
||||||
|
DEBUG_FUNCTION_LINE("Unknown area %d, forcing language will be disabled", acpMetaXml->region);
|
||||||
|
forceConfigMenu = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
forceConfigMenu = true;
|
||||||
|
}
|
||||||
|
ACPFinalize();
|
||||||
|
free(acpMetaXml);
|
||||||
|
} else {
|
||||||
|
forceConfigMenu = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get region and lang from console and set these as default.
|
||||||
|
gCurrentLanguage = gDefaultLanguage;
|
||||||
|
gCurrentCountry = gDefaultCountry;
|
||||||
|
gCurrentProductArea = gDefaultProductArea;
|
||||||
|
|
||||||
|
MCPRegion real_product_area;
|
||||||
|
if(gPreferSystemSettings && getRealProductArea(&real_product_area)){
|
||||||
|
if((regionFromXML & real_product_area) == real_product_area){
|
||||||
|
gCurrentProductArea = real_product_area;
|
||||||
|
|
||||||
|
auto ucHandle = UCOpen();
|
||||||
|
if(ucHandle >= 0){
|
||||||
|
DEBUG_FUNCTION_LINE("Got UCHandle %08X0", ucHandle);
|
||||||
|
UCSysConfig sysConfig;
|
||||||
|
memset((void *) &sysConfig, 0, sizeof(sysConfig));
|
||||||
|
uint32_t data = 0xFFFFFFFF;
|
||||||
|
sysConfig.dataType = UC_DATATYPE_UNSIGNED_INT;
|
||||||
|
sysConfig.dataSize = 4;
|
||||||
|
sysConfig.data = &data;
|
||||||
|
strncpy(sysConfig.name, "cafe.language", 64);
|
||||||
|
int ucRes = real_UCReadSysConfig(ucHandle, 1, &sysConfig);
|
||||||
|
|
||||||
|
if(ucRes >= 0){
|
||||||
|
DEBUG_FUNCTION_LINE("Force default language to system title for own region");
|
||||||
|
gCurrentLanguage = static_cast<Lanuages>(*(uint32_t *) sysConfig.data);
|
||||||
|
gDefaultLanguage = static_cast<Lanuages>(*(uint32_t *) sysConfig.data);
|
||||||
|
} else {
|
||||||
|
DEBUG_FUNCTION_LINE("UCReadSysConfig failed");
|
||||||
|
}
|
||||||
|
UCClose(ucHandle);
|
||||||
|
} else {
|
||||||
|
DEBUG_FUNCTION_LINE("UCOpen failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
wups_storage_item_t *root = nullptr;
|
||||||
|
auto resa = WUPS_GetSubItem(nullptr, CAT_GENERAL_ROOT, &root);
|
||||||
|
if (resa != WUPS_STORAGE_ERROR_SUCCESS) {
|
||||||
|
DEBUG_FUNCTION_LINE("Failed to read %s subitem", CAT_GENERAL_ROOT);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
wups_storage_item_t *title_settings;
|
||||||
|
if (WUPS_GetSubItem(root, CAT_TITLE_SETTINGS, &title_settings) != WUPS_STORAGE_ERROR_SUCCESS) {
|
||||||
|
if (WUPS_CreateSubItem(root, CAT_TITLE_SETTINGS, &title_settings) != WUPS_STORAGE_ERROR_SUCCESS) {
|
||||||
|
DEBUG_FUNCTION_LINE("WUPS_CreateSubItem %s failed", CAT_TITLE_SETTINGS);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char buffer[18];
|
||||||
|
snprintf(buffer, 17, "%016llX", OSGetTitleID());
|
||||||
|
|
||||||
|
wups_storage_item_t *curTitleItem;
|
||||||
|
if (WUPS_GetSubItem(title_settings, buffer, &curTitleItem) != WUPS_STORAGE_ERROR_SUCCESS) {
|
||||||
|
if (WUPS_CreateSubItem(title_settings, buffer, &curTitleItem) != WUPS_STORAGE_ERROR_SUCCESS) {
|
||||||
|
DEBUG_FUNCTION_LINE("WUPS_CreateSubItem %s failed", buffer);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (curTitleItem != nullptr) {
|
||||||
|
if (WUPS_GetInt(curTitleItem, VAL_LANGUAGE, (int32_t *) &gCurrentLanguage) != WUPS_STORAGE_ERROR_SUCCESS) {
|
||||||
|
WUPS_StoreInt(curTitleItem, VAL_LANGUAGE, gDefaultLanguage);
|
||||||
|
gCurrentLanguage = gDefaultLanguage;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (WUPS_GetInt(curTitleItem, VAL_COUNTRY, (int32_t *) &gCurrentCountry) != WUPS_STORAGE_ERROR_SUCCESS) {
|
||||||
|
WUPS_StoreInt(curTitleItem, VAL_COUNTRY, gDefaultCountry);
|
||||||
|
gCurrentCountry = gDefaultCountry;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (WUPS_GetInt(curTitleItem, VAL_PRODUCT_AREA, (int32_t *) &gCurrentProductArea) != WUPS_STORAGE_ERROR_SUCCESS) {
|
||||||
|
WUPS_StoreInt(curTitleItem, VAL_PRODUCT_AREA, gDefaultProductArea);
|
||||||
|
gCurrentProductArea = gDefaultProductArea;
|
||||||
|
}
|
||||||
|
|
||||||
|
// this overrides the current settings
|
||||||
|
if (forceConfigMenu || !gAutoDetection) {
|
||||||
|
ConfigUtils::openConfigMenu();
|
||||||
|
// Save settings to storage
|
||||||
|
WUPS_StoreInt(curTitleItem, VAL_LANGUAGE, gCurrentLanguage);
|
||||||
|
WUPS_StoreInt(curTitleItem, VAL_COUNTRY, gCurrentCountry);
|
||||||
|
WUPS_StoreInt(curTitleItem, VAL_PRODUCT_AREA, gCurrentProductArea);
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG_FUNCTION_LINE("Language will be force to %d", gCurrentLanguage);
|
||||||
|
DEBUG_FUNCTION_LINE("Country will be force to %d", gDefaultCountry);
|
||||||
|
DEBUG_FUNCTION_LINE("Product Area will be forced to %d", gCurrentProductArea);
|
||||||
|
}
|
||||||
|
|
||||||
|
WUPS_CloseStorage();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ON_APPLICATION_START() {
|
||||||
|
WHBLogUdpInit();
|
||||||
|
|
||||||
|
WUPS_OpenStorage();
|
||||||
|
|
||||||
|
wups_storage_item_t *root;
|
||||||
|
if (WUPS_GetSubItem(nullptr, CAT_GENERAL_ROOT, &root) != WUPS_STORAGE_ERROR_SUCCESS) {
|
||||||
|
WUPS_CreateSubItem(nullptr, CAT_GENERAL_ROOT, &root);
|
||||||
|
}
|
||||||
|
|
||||||
|
wups_storage_item_t *general_settings;
|
||||||
|
if (WUPS_GetSubItem(root, CAT_GENERAL_SETTINGS, &general_settings) != WUPS_STORAGE_ERROR_SUCCESS) {
|
||||||
|
WUPS_CreateSubItem(root, CAT_GENERAL_SETTINGS, &general_settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (WUPS_GetInt(general_settings, VAL_AUTO_DETECTION, (int32_t *) &gAutoDetection) != WUPS_STORAGE_ERROR_SUCCESS) {
|
||||||
|
WUPS_StoreInt(general_settings, VAL_AUTO_DETECTION, gAutoDetection);
|
||||||
|
}
|
||||||
|
if (WUPS_GetInt(general_settings, VAL_PREFER_SYSTEM_SETTINGS, (int32_t *) &gPreferSystemSettings) != WUPS_STORAGE_ERROR_SUCCESS) {
|
||||||
|
WUPS_StoreInt(general_settings, VAL_PREFER_SYSTEM_SETTINGS, gPreferSystemSettings);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (WUPS_GetInt(general_settings, VAL_DEFAULT_LANG_EUR, (int32_t *) &gDefaultLangForEUR) != WUPS_STORAGE_ERROR_SUCCESS) {
|
||||||
|
WUPS_StoreInt(general_settings, VAL_DEFAULT_LANG_EUR, gDefaultLangForEUR);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (WUPS_GetInt(general_settings, VAL_DEFAULT_COUNTRY_EUR, &gDefaultCountryForEUR) != WUPS_STORAGE_ERROR_SUCCESS) {
|
||||||
|
WUPS_StoreInt(general_settings, VAL_DEFAULT_COUNTRY_EUR, gDefaultCountryForEUR);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (WUPS_GetInt(general_settings, VAL_DEFAULT_LANG_USA, (int32_t *) &gDefaultLangForUSA) != WUPS_STORAGE_ERROR_SUCCESS) {
|
||||||
|
WUPS_StoreInt(general_settings, VAL_DEFAULT_LANG_USA, gDefaultLangForUSA);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (WUPS_GetInt(general_settings, VAL_DEFAULT_COUNTRY_USA, &gDefaultCountryForUSA) != WUPS_STORAGE_ERROR_SUCCESS) {
|
||||||
|
WUPS_StoreInt(general_settings, VAL_DEFAULT_COUNTRY_USA, gDefaultCountryForUSA);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (WUPS_GetInt(general_settings, VAL_DEFAULT_LANG_JPN, (int32_t *) &gDefaultLangForJPN) != WUPS_STORAGE_ERROR_SUCCESS) {
|
||||||
|
WUPS_StoreInt(general_settings, VAL_DEFAULT_LANG_JPN, gDefaultLangForJPN);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (WUPS_GetInt(general_settings, VAL_DEFAULT_COUNTRY_JPN, &gDefaultCountryForJPN) != WUPS_STORAGE_ERROR_SUCCESS) {
|
||||||
|
WUPS_StoreInt(general_settings, VAL_DEFAULT_COUNTRY_JPN, gDefaultCountryForJPN);
|
||||||
|
}
|
||||||
|
|
||||||
|
gForceSettingsEnabled = 1;
|
||||||
|
if (OSGetTitleID() == 0x0005001010040000L || // Wii U Menu JPN
|
||||||
|
OSGetTitleID() == 0x0005001010040100L || // Wii U Menu USA
|
||||||
|
OSGetTitleID() == 0x0005001010040200L) { // Wii U Menu EUR
|
||||||
|
gForceSettingsEnabled = 0;
|
||||||
|
}
|
||||||
|
DEBUG_FUNCTION_LINE("Start done");
|
||||||
|
}
|
||||||
|
|
||||||
|
void auto_detection_changed(ConfigItemBoolean *item, bool newValue) {
|
||||||
|
DEBUG_FUNCTION_LINE("New value in auto_detection changed: %d", newValue);
|
||||||
|
|
||||||
|
wups_storage_item_t *root;
|
||||||
|
if (WUPS_GetSubItem(nullptr, CAT_GENERAL_ROOT, &root) != WUPS_STORAGE_ERROR_SUCCESS) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
wups_storage_item_t *general_settings;
|
||||||
|
if (WUPS_GetSubItem(root, CAT_GENERAL_SETTINGS, &general_settings) != WUPS_STORAGE_ERROR_SUCCESS) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
WUPS_StoreInt(general_settings, VAL_AUTO_DETECTION, newValue);
|
||||||
|
gAutoDetection = newValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
void prefer_system_changed(ConfigItemBoolean *item, bool newValue) {
|
||||||
|
DEBUG_FUNCTION_LINE("New value in prefer_system_settings changed: %d", newValue);
|
||||||
|
|
||||||
|
wups_storage_item_t *root;
|
||||||
|
if (WUPS_GetSubItem(nullptr, CAT_GENERAL_ROOT, &root) != WUPS_STORAGE_ERROR_SUCCESS) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
wups_storage_item_t *general_settings;
|
||||||
|
if (WUPS_GetSubItem(root, CAT_GENERAL_SETTINGS, &general_settings) != WUPS_STORAGE_ERROR_SUCCESS) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
WUPS_StoreInt(general_settings, VAL_PREFER_SYSTEM_SETTINGS, newValue);
|
||||||
|
gPreferSystemSettings = newValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
void default_lang_changed(ConfigItemMultipleValues *item, uint32_t newValue) {
|
||||||
|
DEBUG_FUNCTION_LINE("New value in %s changed: %d", item->configID, newValue);
|
||||||
|
|
||||||
|
wups_storage_item_t *root;
|
||||||
|
if (WUPS_GetSubItem(nullptr, CAT_GENERAL_ROOT, &root) != WUPS_STORAGE_ERROR_SUCCESS) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
wups_storage_item_t *general_settings;
|
||||||
|
if (WUPS_GetSubItem(root, CAT_GENERAL_SETTINGS, &general_settings) != WUPS_STORAGE_ERROR_SUCCESS) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
WUPS_StoreInt(general_settings, item->configID, (int32_t) newValue);
|
||||||
|
if (strcmp(item->configID, VAL_DEFAULT_LANG_EUR) == 0) {
|
||||||
|
DEBUG_FUNCTION_LINE("Updated default eur lang");
|
||||||
|
gDefaultLangForEUR = (Lanuages) newValue;
|
||||||
|
} else if (strcmp(item->configID, VAL_DEFAULT_LANG_USA) == 0) {
|
||||||
|
DEBUG_FUNCTION_LINE("Updated default usa lang");
|
||||||
|
gDefaultLangForUSA = (Lanuages) newValue;
|
||||||
|
} else if (strcmp(item->configID, VAL_DEFAULT_LANG_JPN) == 0) {
|
||||||
|
DEBUG_FUNCTION_LINE("Updated default jpn lang");
|
||||||
|
gDefaultLangForJPN = (Lanuages) newValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void getConfigInfoForLangMap(std::map<Lanuages, const char *> &curLangMap, ConfigItemMultipleValuesPair *pair, uint32_t default_lang, uint32_t *default_index, uint32_t *len) {
|
||||||
|
uint32_t i = 0;
|
||||||
|
for (auto &curEntry: curLangMap) {
|
||||||
|
if (default_lang == curEntry.first) {
|
||||||
|
*default_index = i;
|
||||||
|
}
|
||||||
|
pair[i].value = curEntry.first;
|
||||||
|
pair[i].valueName = (char *) curEntry.second;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
*len = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
WUPS_GET_CONFIG() {
|
||||||
|
// We open the storage so we can persist the configuration the user did.
|
||||||
|
WUPS_OpenStorage();
|
||||||
|
|
||||||
|
WUPSConfigHandle config;
|
||||||
|
WUPSConfig_CreateHandled(&config, "Region Free Plugin");
|
||||||
|
|
||||||
|
WUPSConfigCategoryHandle cat;
|
||||||
|
WUPSConfig_AddCategoryByNameHandled(config, "Settings", &cat);
|
||||||
|
|
||||||
|
WUPSConfigItemBoolean_AddToCategoryHandled(config, cat, VAL_DEFAULT_LANG_USA, "Auto Detection", gAutoDetection, &auto_detection_changed);
|
||||||
|
WUPSConfigItemBoolean_AddToCategoryHandled(config, cat, VAL_PREFER_SYSTEM_SETTINGS, "Prefer System Settings For Own Region", gPreferSystemSettings, &prefer_system_changed);
|
||||||
|
|
||||||
|
std::map<Lanuages, const char *> eur_lang_map{
|
||||||
|
{LANG_ENGLISH, "English"},
|
||||||
|
{LANG_FRANCAIS, "Francais"},
|
||||||
|
{LANG_DEUTSCH, "Deutsch"},
|
||||||
|
{LANG_ITALIANO, "Italiano"},
|
||||||
|
{LANG_ESPANOL, "Espanol"},
|
||||||
|
{LANG_NEDERLANDS, "Nederlands"},
|
||||||
|
{LANG_PORTUGUES, "Portugues"},
|
||||||
|
{LANG_RUSSKI, "Russki"},
|
||||||
|
};
|
||||||
|
|
||||||
|
std::map<Lanuages, const char *> usa_lang_map{
|
||||||
|
{LANG_ENGLISH, "English"},
|
||||||
|
{LANG_FRANCAIS, "Francais"},
|
||||||
|
{LANG_ESPANOL, "Espanol"},
|
||||||
|
{LANG_PORTUGUES, "Portugues"}
|
||||||
|
};
|
||||||
|
|
||||||
|
ConfigItemMultipleValuesPair lang_eur_pair[eur_lang_map.size()];
|
||||||
|
uint32_t number_lang_eur_values = 0;
|
||||||
|
uint32_t default_index_eur = 0;
|
||||||
|
|
||||||
|
getConfigInfoForLangMap(eur_lang_map, lang_eur_pair, gDefaultLangForEUR, &default_index_eur, &number_lang_eur_values);
|
||||||
|
|
||||||
|
WUPSConfigItemMultipleValues_AddToCategoryHandled(config, cat, VAL_DEFAULT_LANG_EUR, "Default Language for EUR", default_index_eur, lang_eur_pair, number_lang_eur_values,
|
||||||
|
&default_lang_changed);
|
||||||
|
|
||||||
|
ConfigItemMultipleValuesPair lang_usa_pair[eur_lang_map.size()];
|
||||||
|
uint32_t number_lang_usa_values = 0;
|
||||||
|
uint32_t default_index_usa = 0;
|
||||||
|
|
||||||
|
getConfigInfoForLangMap(usa_lang_map, lang_usa_pair, gDefaultLangForUSA, &default_index_usa, &number_lang_usa_values);
|
||||||
|
|
||||||
|
WUPSConfigItemMultipleValues_AddToCategoryHandled(config, cat, VAL_DEFAULT_LANG_USA, "Default Language for USA", default_index_usa, lang_usa_pair, number_lang_usa_values,
|
||||||
|
&default_lang_changed);
|
||||||
|
|
||||||
|
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
WUPS_CONFIG_CLOSED() {
|
||||||
|
// Save all changes
|
||||||
|
WUPS_CloseStorage();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DECL_FUNCTION(int, MCP_GetSysProdSettings, int IOHandle, struct MCPSysProdSettings *settings) {
|
||||||
|
int result = real_MCP_GetSysProdSettings(IOHandle, settings);
|
||||||
|
|
||||||
|
if (gForceSettingsEnabled) {
|
||||||
|
if (result != 0) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG_FUNCTION_LINE_VERBOSE("MCP_GetSysProdSettings: forcing platform region...");
|
||||||
|
DEBUG_FUNCTION_LINE("MCP_GetSysProdSettings: original region %d, new %d...", settings->product_area, gCurrentProductArea);
|
||||||
|
settings->product_area = gCurrentProductArea;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const uint64_t
|
||||||
|
sSysAppTitleId[][3] =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
// Updater
|
||||||
|
0x0005001010040000ull,
|
||||||
|
0x0005001010040100ull,
|
||||||
|
0x0005001010040200ull,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
// System Settings
|
||||||
|
0x0005001010047000ull,
|
||||||
|
0x0005001010047100ull,
|
||||||
|
0x0005001010047200ull,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
// Parental Controls
|
||||||
|
0x0005001010048000ull,
|
||||||
|
0x0005001010048100ull,
|
||||||
|
0x0005001010048200ull,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
// User Settings
|
||||||
|
0x0005001010049000ull,
|
||||||
|
0x0005001010049100ull,
|
||||||
|
0x0005001010049200ull,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
// Mii Maker
|
||||||
|
0x000500101004A000ull,
|
||||||
|
0x000500101004A100ull,
|
||||||
|
0x000500101004A200ull,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
// Account Settings
|
||||||
|
0x000500101004B000ull,
|
||||||
|
0x000500101004B100ull,
|
||||||
|
0x000500101004B200ull,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
// Daily log
|
||||||
|
0x000500101004C000ull,
|
||||||
|
0x000500101004C100ull,
|
||||||
|
0x000500101004C200ull,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
// Notifications
|
||||||
|
0x000500101004D000ull,
|
||||||
|
0x000500101004D100ull,
|
||||||
|
0x000500101004D200ull,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
// Health and Safety Information
|
||||||
|
0x000500101004E000ull,
|
||||||
|
0x000500101004E100ull,
|
||||||
|
0x000500101004E200ull,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
// Electronic Manual
|
||||||
|
0x0005001B10059000ull,
|
||||||
|
0x0005001B10059100ull,
|
||||||
|
0x0005001B10059200ull,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
// Wii U Chat
|
||||||
|
0x000500101005A000ull,
|
||||||
|
0x000500101005A100ull,
|
||||||
|
0x000500101005A200ull,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
// "Software/Data Transfer"
|
||||||
|
0x0005001010062000ull,
|
||||||
|
0x0005001010062100ull,
|
||||||
|
0x0005001010062200ull,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
bool getRealProductArea(MCPRegion* out){
|
||||||
|
if(out == nullptr){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
auto handle = MCP_Open();
|
||||||
|
if (handle >= 0) {
|
||||||
|
auto data = (struct MCPSysProdSettings *) memalign(0x40, sizeof(struct MCPSysProdSettings));
|
||||||
|
auto res = real_MCP_GetSysProdSettings(handle, data);
|
||||||
|
if (res >= 0) {
|
||||||
|
*out = data->product_area;
|
||||||
|
}
|
||||||
|
MCP_Close(handle);
|
||||||
|
free(data);
|
||||||
|
return res >= 0;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
DECL_FUNCTION(uint64_t, _SYSGetSystemApplicationTitleIdByProdArea, SYSTEM_APP_ID param_1, MCPRegion param_2) {
|
||||||
|
MCPRegion cur_product_area;
|
||||||
|
if(!getRealProductArea(&cur_product_area)){
|
||||||
|
DEBUG_FUNCTION_LINE("Failed to get real region");
|
||||||
|
cur_product_area = param_2;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto regionIdx = 1u;
|
||||||
|
|
||||||
|
if (cur_product_area == MCP_REGION_JAPAN) {
|
||||||
|
regionIdx = 0u;
|
||||||
|
} else if (cur_product_area == MCP_REGION_EUROPE || cur_product_area == 0x08) {
|
||||||
|
regionIdx = 2u;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t res = sSysAppTitleId[param_1][regionIdx];
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
WUPS_MUST_REPLACE(ACPGetTitleMetaXmlByDevice, WUPS_LOADER_LIBRARY_NN_ACP, ACPGetTitleMetaXmlByDevice);
|
||||||
|
WUPS_MUST_REPLACE(ACPGetLaunchMetaXml, WUPS_LOADER_LIBRARY_NN_ACP, ACPGetLaunchMetaXml);
|
||||||
|
WUPS_MUST_REPLACE(MCP_GetSysProdSettings, WUPS_LOADER_LIBRARY_COREINIT, MCP_GetSysProdSettings);
|
||||||
|
WUPS_MUST_REPLACE(UCReadSysConfig, WUPS_LOADER_LIBRARY_COREINIT, UCReadSysConfig);
|
||||||
|
WUPS_MUST_REPLACE(_SYSGetSystemApplicationTitleIdByProdArea, WUPS_LOADER_LIBRARY_SYSAPP, _SYSGetSystemApplicationTitleIdByProdArea);
|
||||||
|
|
32
src/utils/logger.h
Normal file
32
src/utils/logger.h
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
#ifndef __LOGGER_H_
|
||||||
|
#define __LOGGER_H_
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <whb/log.h>
|
||||||
|
|
||||||
|
#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("[%s]%s@L%04d: " FMT "",__FILENAME__,__FUNCTION__, __LINE__, ## ARGS); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define DEBUG_FUNCTION_LINE(FMT, ARGS...)do { \
|
||||||
|
WHBLogPrintf("[%23s]%30s@L%04d: " FMT "",__FILENAME__,__FUNCTION__, __LINE__, ## ARGS); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define DEBUG_FUNCTION_LINE_VERBOSE(FMT, ARGS...) while (0)
|
||||||
|
|
||||||
|
#define DEBUG_FUNCTION_LINE_WRITE(FMT, ARGS...)do { \
|
||||||
|
WHBLogWritef("[%23s]%30s@L%04d: " FMT "",__FILENAME__,__FUNCTION__, __LINE__, ## ARGS); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in New Issue
Block a user