First commit

This commit is contained in:
Maschell 2023-01-24 21:11:53 +01:00
commit 2d49133dea
26 changed files with 26150 additions and 0 deletions

67
.clang-format Normal file
View File

@ -0,0 +1,67 @@
# Generated from CLion C/C++ Code Style settings
BasedOnStyle: LLVM
AccessModifierOffset: -4
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: Consecutive
AlignConsecutiveMacros: AcrossEmptyLinesAndComments
AlignOperands: Align
AllowAllArgumentsOnNextLine: false
AllowAllConstructorInitializersOnNextLine: false
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortBlocksOnASingleLine: Always
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: All
AllowShortIfStatementsOnASingleLine: Always
AllowShortLambdasOnASingleLine: All
AllowShortLoopsOnASingleLine: true
AlwaysBreakAfterReturnType: None
AlwaysBreakTemplateDeclarations: Yes
BreakBeforeBraces: Custom
BraceWrapping:
AfterCaseLabel: false
AfterClass: false
AfterControlStatement: Never
AfterEnum: false
AfterFunction: false
AfterNamespace: false
AfterUnion: false
BeforeCatch: false
BeforeElse: false
IndentBraces: false
SplitEmptyFunction: false
SplitEmptyRecord: true
BreakBeforeBinaryOperators: None
BreakBeforeTernaryOperators: true
BreakConstructorInitializers: BeforeColon
BreakInheritanceList: BeforeColon
ColumnLimit: 0
CompactNamespaces: false
ContinuationIndentWidth: 8
IndentCaseLabels: true
IndentPPDirectives: None
IndentWidth: 4
KeepEmptyLinesAtTheStartOfBlocks: true
MaxEmptyLinesToKeep: 2
NamespaceIndentation: All
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PointerAlignment: Right
ReflowComments: false
SpaceAfterCStyleCast: true
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: false
SpaceBeforeAssignmentOperators: true
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInCStyleCastParentheses: false
SpacesInContainerLiterals: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
TabWidth: 4
UseTab: Never

59
.github/workflows/ci.yml vendored Normal file
View File

@ -0,0 +1,59 @@
name: CI-Release
on:
push:
branches:
- main
jobs:
clang-format:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v3
- name: clang-format
run: |
docker run --rm -v ${PWD}:/src wiiuenv/clang-format:13.0.0-2 -r ./src --exclude ./src/utils/json.hpp
build-binary:
runs-on: ubuntu-22.04
needs: clang-format
steps:
- uses: actions/checkout@v3
- name: create version.h
run: |
git_hash=$(git rev-parse --short "$GITHUB_SHA")
cat <<EOF > ./src/version.h
#pragma once
#define PLUGIN_VERSION_EXTRA " (nightly-$git_hash)"
EOF
- 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-22.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
- name: zip artifact
run: zip -r ${{ env.REPOSITORY_NAME }}_${{ env.DATETIME }}.zip *.wps
- name: Create Release
uses: "softprops/action-gh-release@v1"
with:
tag_name: ${{ env.REPOSITORY_NAME }}-${{ env.DATETIME }}
draft: false
prerelease: true
generate_release_notes: true
name: Nightly-${{ env.REPOSITORY_NAME }}-${{ env.DATETIME }}
files: |
./${{ env.REPOSITORY_NAME }}_${{ env.DATETIME }}.zip

32
.github/workflows/pr.yml vendored Normal file
View File

@ -0,0 +1,32 @@
name: CI-PR
on: [ pull_request ]
jobs:
clang-format:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v3
- name: clang-format
run: |
docker run --rm -v ${PWD}:/src wiiuenv/clang-format:13.0.0-2 -r ./src --exclude ./src/utils/json.hpp
build-binary:
runs-on: ubuntu-22.04
needs: clang-format
steps:
- uses: actions/checkout@v3
- name: create version.h
run: |
git_hash=$(git rev-parse --short "${{ github.event.pull_request.head.sha }}")
cat <<EOF > ./src/version.h
#pragma once
#define PLUGIN_VERSION_EXTRA " (nightly-$git_hash)"
EOF
- 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"

9
.gitignore vendored Normal file
View File

@ -0,0 +1,9 @@
build/*
*.mod
sysapp.layout
sysapp.cbp
*.elf
*.wps
.idea/
cmake-build-debug/
CMakeLists.txt

8
Dockerfile Normal file
View File

@ -0,0 +1,8 @@
FROM wiiuenv/devkitppc:20221228
COPY --from=wiiuenv/wiiupluginsystem:20230126 /artifacts $DEVKITPRO
COPY --from=wiiuenv/libnotifications:20230126 /artifacts $DEVKITPRO
COPY --from=wiiuenv/librpxloader:20220903 /artifacts $DEVKITPRO
COPY --from=wiiuenv/libcurlwrapper:20230121 /artifacts $DEVKITPRO
WORKDIR project

146
Makefile Normal file
View File

@ -0,0 +1,146 @@
#-------------------------------------------------------------------------------
.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
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
# 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 := AromaBasePlugin
BUILD := build
SOURCES := src src/utils
DATA := data
INCLUDES := src
#-------------------------------------------------------------------------------
# options for code generation
#-------------------------------------------------------------------------------
CFLAGS := -g -Wall -O2 -ffunction-sections \
$(MACHDEP)
CFLAGS += $(INCLUDE) -D__WIIU__ -D__WUT__ -D__WUPS__
CXXFLAGS := $(CFLAGS)
ASFLAGS := -g $(ARCH)
LDFLAGS = -g $(ARCH) $(RPXSPECS) -Wl,-Map,$(notdir $*.map) $(WUPSSPECS)
ifeq ($(DEBUG),1)
CXXFLAGS += -DDEBUG -g
CFLAGS += -DDEBUG -g
endif
ifeq ($(DEBUG),VERBOSE)
CXXFLAGS += -DDEBUG -DVERBOSE_DEBUG -g
CFLAGS += -DDEBUG -DVERBOSE_DEBUG -g
endif
LIBS := -lcurlwrapper -lnotifications -lrpxloader -lwups -lwut
#-------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level
# containing include and lib
#-------------------------------------------------------------------------------
LIBDIRS := $(PORTLIBS) $(WUPS_ROOT) $(WUMS_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)
-include $(DEPENDS)
#-------------------------------------------------------------------------------
endif
#-------------------------------------------------------------------------------

50
README.md Normal file
View File

@ -0,0 +1,50 @@
# Aroma Base Plugin
Provides some simple patches for Wii U Menu and checks for Aroma updates.
## Installation
(`[ENVIRONMENT]` is a placeholder for the actual environment name.)
1. Copy the file `AromaBasePlugin.wps` into `sd:/wiiu/environments/[ENVIRONMENT]/plugins`.
2. Requires the [WiiUPluginLoaderBackend](https://github.com/wiiu-env/WiiUPluginLoaderBackend) in `sd:/wiiu/environments/[ENVIRONMENT]/modules`.
3. Requires the [CURLWrapperModule](https://github.com/wiiu-env/CURLWrapperModule) in `sd:/wiiu/environments/[ENVIRONMENT]/modules`.
4. Requires the [NotificationModule](https://github.com/wiiu-env/NotificationModule) in `sd:/wiiu/environments/[ENVIRONMENT]/modules`.
5. Requires the [RPXLoadingModule](https://github.com/wiiu-env/RPXLoadingModule) in `sd:/wiiu/environments/[ENVIRONMENT]/modules`.
## Usage
Via the plugin config menu (press L, DPAD Down and Minus on the GamePad, Pro Controller or Classic Controller) you can configure the plugin. The available options are the following:
- **Wii U Menu patches**:
- Avoid "Format" dialog on Wii U Menu (UStealth): (Default is false)
- Skips the "Format"-nag when launching the Wii U Menu with a non-formatted external drive.
- Skip "Shutdown warning" on boot: (Default is true)
- Hide the "Shutdown warning" after shutting the console down by pressing the power button for 4 seconds.
## Building
For building you need:
- [wups](https://github.com/wiiu-env/WiiUPluginSystem)
- [wut](https://github.com/decaf-emu/wut)
- [libnotifications](https://github.com/wiiu-env/libnotifications)
- [librpxloader](https://github.com/wiiu-env/librpxloader)
- [libcurlwrapper](https://github.com/wiiu-env/libcurlwrapper)
## 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 aroma-base-plugin-builder
# make
docker run -it --rm -v ${PWD}:/project aroma-base-plugin-builder make
# make clean
docker run -it --rm -v ${PWD}:/project aroma-base-plugin-builder make clean
```
## Format the code via docker
`docker run --rm -v ${PWD}:/src wiiuenv/clang-format:13.0.0-2 -r ./src --exclude ./src/utils/json.hpp -i`

55
src/Hints.cpp Normal file
View File

@ -0,0 +1,55 @@
#include "Hints.h"
#include "utils/config.h"
#include <coreinit/cache.h>
#include <coreinit/thread.h>
#include <notifications/notification_defines.h>
#include <notifications/notifications.h>
#include <thread>
std::unique_ptr<std::thread> sShowHintThread;
static bool sShutdownHintThread = false;
void ShowHints() {
bool isOverlayReady = false;
while (!sShutdownHintThread &&
NotificationModule_IsOverlayReady(&isOverlayReady) == NOTIFICATION_MODULE_RESULT_SUCCESS && !isOverlayReady) {
OSSleepTicks(OSMillisecondsToTicks(16));
}
if (sShutdownHintThread || !isOverlayReady) {
return;
}
if (!gConfigMenuHintShown) {
NotificationModuleStatus err;
if ((err = NotificationModule_SetDefaultValue(NOTIFICATION_MODULE_NOTIFICATION_TYPE_INFO, NOTIFICATION_MODULE_DEFAULT_OPTION_DURATION_BEFORE_FADE_OUT, 15.0f)) == NOTIFICATION_MODULE_RESULT_SUCCESS &&
(err = NotificationModule_AddInfoNotification("Tip: You can open a configuration menu by pressing \ue052 + \ue07A + \ue046")) == NOTIFICATION_MODULE_RESULT_SUCCESS) {
if (WUPS_OpenStorage() == WUPS_STORAGE_ERROR_SUCCESS) {
gConfigMenuHintShown = true;
wups_storage_item_t *cat_other = nullptr;
if (WUPS_GetSubItem(nullptr, CAT_OTHER, &cat_other) == WUPS_STORAGE_ERROR_SUCCESS) {
WUPS_StoreInt(cat_other, CONFIG_MENU_HINT_SHOWN_ID, gConfigMenuHintShown);
}
WUPS_CloseStorage();
}
} else {
DEBUG_FUNCTION_LINE_ERR("Failed to show Notification: %d %s", err, NotificationModule_GetStatusStr(err));
}
}
}
void StartHintThread() {
if (!gConfigMenuHintShown) {
sShutdownHintThread = false;
sShowHintThread = std::make_unique<std::thread>(ShowHints);
} else {
sShowHintThread.reset();
}
}
void StopHintThread() {
if (sShowHintThread != nullptr) {
sShutdownHintThread = true;
OSMemoryBarrier();
sShowHintThread->join();
sShowHintThread.reset();
}
}

5
src/Hints.h Normal file
View File

@ -0,0 +1,5 @@
#pragma once
void StartHintThread();
void StopHintThread();

194
src/UpdaterCheck.cpp Normal file
View File

@ -0,0 +1,194 @@
#include "common.h"
#include "utils/DownloadUtils.h"
#include "utils/LatestVersion.h"
#include "utils/config.h"
#include "utils/input.h"
#include <coreinit/cache.h>
#include <coreinit/thread.h>
#include <coreinit/time.h>
#include <memory>
#include <notifications/notifications.h>
#include <padscore/wpad.h>
#include <rpxloader/rpxloader.h>
#include <string>
#include <thread>
#include <vpad/input.h>
static NotificationModuleHandle sAromaUpdateHandle = 0;
std::unique_ptr<std::thread> sCheckUpdateThread;
static bool sShutdownUpdateThread = false;
void UpdateCheckThreadEntry();
constexpr uint32_t HIDE_UPDATE_WARNING_VPAD_COMBO = VPAD_BUTTON_MINUS;
constexpr uint32_t LAUNCH_AROMA_UPDATER_VPAD_COMBO = VPAD_BUTTON_PLUS;
constexpr uint32_t sHoldForFramesTarget = 60;
void StartUpdaterCheckThread() {
if (!gUpdateChecked && DownloadUtils::Init()) {
sShutdownUpdateThread = false;
sCheckUpdateThread = std::make_unique<std::thread>(UpdateCheckThreadEntry);
} else {
sCheckUpdateThread.reset();
}
}
void StopUpdaterCheckThread() {
if (sCheckUpdateThread != nullptr) {
sShutdownUpdateThread = true;
OSMemoryBarrier();
sCheckUpdateThread->join();
sCheckUpdateThread.reset();
}
}
void UpdateCheckThreadEntry() {
bool isOverlayReady = false;
while (!sShutdownUpdateThread &&
NotificationModule_IsOverlayReady(&isOverlayReady) == NOTIFICATION_MODULE_RESULT_SUCCESS && !isOverlayReady) {
OSSleepTicks(OSMillisecondsToTicks(16));
}
if (sShutdownUpdateThread || !isOverlayReady) {
return;
}
std::string outBuffer;
int responseCodeOut;
int errorOut;
std::string errorTextOut;
float progress;
if (DownloadUtils::DownloadFileToBuffer(AROMA_UPDATER_LAST_UPDATE_URL, outBuffer, responseCodeOut, errorOut, errorTextOut, &progress) == 0) {
try {
AromaUpdater::LatestVersion data = nlohmann::json::parse(outBuffer);
gUpdateChecked = true;
if (gLastHash.empty()) { // don't show update warning on first boot
gLastHash = data.getHash();
} else if (gLastHash != data.getHash()) {
struct stat st {};
if (stat(AROMA_UPDATER_PATH_FULL, &st) >= 0 && S_ISREG(st.st_mode)) {
NotificationModuleStatus err;
if ((err = NotificationModule_AddDynamicNotification("A new Aroma Update is available. "
"Hold \ue045 to launch the Aroma Updater, press \ue046 to hide this message",
&sAromaUpdateHandle)) != NOTIFICATION_MODULE_RESULT_SUCCESS) {
DEBUG_FUNCTION_LINE_ERR("Failed to add update notification. %s", NotificationModule_GetStatusStr(err));
sAromaUpdateHandle = 0;
}
} else {
NotificationModule_SetDefaultValue(NOTIFICATION_MODULE_NOTIFICATION_TYPE_INFO, NOTIFICATION_MODULE_DEFAULT_OPTION_DURATION_BEFORE_FADE_OUT, 15.0f);
NotificationModule_AddInfoNotification("A new Aroma Update is available. Please launch the Aroma Updater!");
}
gLastHash = data.getHash();
} else {
DEBUG_FUNCTION_LINE_VERBOSE("We don't need to update the hash");
return;
}
if (WUPS_OpenStorage() == WUPS_STORAGE_ERROR_SUCCESS) {
wups_storage_item_t *cat_other = nullptr;
if (WUPS_GetSubItem(nullptr, CAT_OTHER, &cat_other) == WUPS_STORAGE_ERROR_SUCCESS) {
WUPS_StoreString(cat_other, LAST_UPDATE_HASH_ID, gLastHash.c_str());
}
WUPS_CloseStorage();
}
} catch (std::exception &e) {
DEBUG_FUNCTION_LINE_WARN("Failed to parse AromaUpdater::LatestVersion");
}
} else {
DEBUG_FUNCTION_LINE_INFO("Download failed: %d %s", errorOut, errorTextOut.c_str());
}
}
extern "C" uint32_t VPADGetButtonProcMode(uint32_t);
static bool updaterLaunched = false;
static uint32_t sHoldForXFrames = 0;
bool CheckForButtonCombo(uint32_t trigger, uint32_t hold, uint32_t &holdForXFrames, uint32_t holdForFramesTarget) {
if (trigger == HIDE_UPDATE_WARNING_VPAD_COMBO) {
NotificationModule_FinishDynamicNotification(sAromaUpdateHandle, 0.0f);
sAromaUpdateHandle = 0;
return true;
}
if (hold == LAUNCH_AROMA_UPDATER_VPAD_COMBO) {
if (++holdForXFrames > holdForFramesTarget) {
RPXLoaderStatus err;
if ((err = RPXLoader_LaunchHomebrew(AROMA_UPDATER_PATH)) == RPX_LOADER_RESULT_SUCCESS) {
NotificationModule_FinishDynamicNotification(sAromaUpdateHandle, 2.0f);
sAromaUpdateHandle = 0;
updaterLaunched = true;
return true;
} else {
DEBUG_FUNCTION_LINE_ERR("RPXLoader_LaunchHomebrew failed: %s", RPXLoader_GetStatusStr(err));
}
}
} else {
holdForXFrames = 0;
}
return false;
}
DECL_FUNCTION(int32_t, VPADRead, VPADChan chan,
VPADStatus *buffers,
uint32_t count,
VPADReadError *outError) {
if (!sAromaUpdateHandle) {
return real_VPADRead(chan, buffers, count, outError);
}
VPADReadError real_error;
auto result = real_VPADRead(chan, buffers, count, &real_error);
if (!updaterLaunched && result > 0 && real_error == VPAD_READ_SUCCESS) {
uint32_t end = 1;
// Fix games like TP HD
if (VPADGetButtonProcMode(chan) == 1) {
end = result;
}
for (uint32_t i = 0; i < end; i++) {
if (CheckForButtonCombo((buffers[i].trigger & 0x000FFFFF), (buffers[i].hold & 0x000FFFFF), sHoldForXFrames, sHoldForFramesTarget)) {
break;
}
}
}
if (outError) {
*outError = real_error;
}
return result;
}
static uint32_t sWPADLastButtonHold[4] = {0, 0, 0, 0};
static uint32_t sHoldForXFramesWPAD[4] = {0, 0, 0, 0};
DECL_FUNCTION(void, WPADRead, WPADChan chan, WPADStatusProController *data) {
real_WPADRead(chan, data);
if (!sAromaUpdateHandle) {
return;
}
if (data && !updaterLaunched && chan >= 0 && chan < 4) {
if (data[0].err == 0) {
if (data[0].extensionType != 0xFF) {
uint32_t curButtonHold = 0;
if (data[0].extensionType == WPAD_EXT_CORE || data[0].extensionType == WPAD_EXT_NUNCHUK) {
// button data is in the first 2 bytes for wiimotes
curButtonHold = remapWiiMoteButtons(((uint16_t *) data)[0]);
} else if (data[0].extensionType == WPAD_EXT_CLASSIC) {
curButtonHold = remapClassicButtons(((uint32_t *) data)[10] & 0xFFFF);
} else if (data[0].extensionType == WPAD_EXT_PRO_CONTROLLER) {
curButtonHold = remapProButtons(data[0].buttons);
}
uint32_t curButtonTrigger = (curButtonHold & (~(sWPADLastButtonHold[chan])));
if (CheckForButtonCombo(curButtonTrigger, curButtonHold, sHoldForXFramesWPAD[chan], sHoldForFramesTarget * 2)) {
return;
}
sWPADLastButtonHold[chan] = curButtonHold;
}
}
}
}
// We only want to patch Wii U Menu
WUPS_MUST_REPLACE_FOR_PROCESS(VPADRead, WUPS_LOADER_LIBRARY_VPAD, VPADRead, WUPS_FP_TARGET_PROCESS_WII_U_MENU);
WUPS_MUST_REPLACE_FOR_PROCESS(WPADRead, WUPS_LOADER_LIBRARY_PADSCORE, WPADRead, WUPS_FP_TARGET_PROCESS_WII_U_MENU);

4
src/UpdaterCheck.h Normal file
View File

@ -0,0 +1,4 @@
#pragma once
void StartUpdaterCheckThread();
void StopUpdaterCheckThread();

5
src/common.h Normal file
View File

@ -0,0 +1,5 @@
#pragma once
#define SD_CARD_PATH "fs:/vol/external01/"
#define AROMA_UPDATER_PATH "wiiu/apps/AromaUpdater.wuhb"
#define AROMA_UPDATER_PATH_FULL SD_CARD_PATH AROMA_UPDATER_PATH
#define AROMA_UPDATER_LAST_UPDATE_URL "https://aroma.foryour.cafe/api/latest_version"

116
src/main.cpp Normal file
View File

@ -0,0 +1,116 @@
#include "main.h"
#include "Hints.h"
#include "UpdaterCheck.h"
#include "utils/DownloadUtils.h"
#include "utils/LatestVersion.h"
#include "utils/config.h"
#include <coreinit/title.h>
#include <malloc.h>
#include <nn/spm.h>
#include <notifications/notifications.h>
#include <rpxloader/rpxloader.h>
#include <utils/logger.h>
#include <wups.h>
WUPS_PLUGIN_NAME("AromaBasePlugin");
WUPS_PLUGIN_DESCRIPTION("Implements small patches and checks for Aroma updates.");
WUPS_PLUGIN_VERSION(PLUGIN_VERSION_FULL);
WUPS_PLUGIN_AUTHOR("Maschell");
WUPS_PLUGIN_LICENSE("GPL");
WUPS_USE_WUT_DEVOPTAB();
WUPS_USE_STORAGE("aroma_base_plugin"); // Unique id for the storage api
INITIALIZE_PLUGIN() {
initLogging();
if (NotificationModule_InitLibrary() != NOTIFICATION_MODULE_RESULT_SUCCESS) {
DEBUG_FUNCTION_LINE_ERR("NotificationModule_InitLibrary failed");
}
if (RPXLoader_InitLibrary() != RPX_LOADER_RESULT_SUCCESS) {
DEBUG_FUNCTION_LINE_ERR("RPXLoader_InitLibrary failed");
}
// Open storage to read values
WUPSStorageError storageRes = WUPS_OpenStorage();
if (storageRes == WUPS_STORAGE_ERROR_SUCCESS) {
wups_storage_item_t *cat_config = nullptr;
if (WUPS_GetSubItem(nullptr, CAT_CONFIG, &cat_config) == WUPS_STORAGE_ERROR_NOT_FOUND) {
if (WUPS_CreateSubItem(nullptr, CAT_CONFIG, &cat_config) != WUPS_STORAGE_ERROR_SUCCESS) {
cat_config = nullptr;
}
}
if (cat_config != nullptr) {
LOAD_BOOL_FROM_STORAGE(cat_config, USTEALTH_CONFIG_ID, gActivateUStealth);
LOAD_BOOL_FROM_STORAGE(cat_config, POWEROFFWARNING_CONFIG_ID, gSkip4SecondOffStatusCheck);
}
wups_storage_item_t *cat_other = nullptr;
if (WUPS_GetSubItem(nullptr, CAT_OTHER, &cat_other) != WUPS_STORAGE_ERROR_SUCCESS) {
if (WUPS_CreateSubItem(nullptr, CAT_OTHER, &cat_other) != WUPS_STORAGE_ERROR_SUCCESS) {
cat_other = nullptr;
}
}
if (cat_other != nullptr) {
LOAD_BOOL_FROM_STORAGE(cat_other, CONFIG_MENU_HINT_SHOWN_ID, gConfigMenuHintShown);
char hash[41];
memset(hash, 0, sizeof(hash));
LOAD_STRING_FROM_STORAGE(cat_other, LAST_UPDATE_HASH_ID, hash, sizeof(hash));
gLastHash = hash;
}
// Close storage
if (WUPS_CloseStorage() != WUPS_STORAGE_ERROR_SUCCESS) {
DEBUG_FUNCTION_LINE_ERR("Failed to close storage");
}
} else {
DEBUG_FUNCTION_LINE_ERR("Failed to open storage %s (%d)", WUPS_GetStorageStatusStr(storageRes), storageRes);
}
}
ON_APPLICATION_START() {
initLogging();
uint64_t titleID = OSGetTitleID();
if (titleID == 0x0005001010040000L || // Wii U Menu
titleID == 0x0005001010040100L ||
titleID == 0x0005001010040200L) {
StartHintThread();
StartUpdaterCheckThread();
}
}
ON_APPLICATION_ENDS() {
StopHintThread();
StopUpdaterCheckThread();
deinitLogging();
}
DEINITIALIZE_PLUGIN() {
NotificationModule_DeInitLibrary();
RPXLoader_DeInitLibrary();
}
DECL_FUNCTION(int32_t, IsStorageMaybePcFormatted, bool *isPcFormatted, nn::spm::StorageIndex *index) {
// Make sure the index is valid
int32_t res = real_IsStorageMaybePcFormatted(isPcFormatted, index);
if (gActivateUStealth && res == 0) {
// always return false which makes the Wii U menu stop nagging about this drive
*isPcFormatted = false;
}
return res;
}
DECL_FUNCTION(bool, MCP_Get4SecondOffStatus, int32_t handle) {
if (gSkip4SecondOffStatusCheck) {
return false;
}
return real_MCP_Get4SecondOffStatus(handle);
}
// Only replace for the Wii U Menu
WUPS_MUST_REPLACE_FOR_PROCESS(IsStorageMaybePcFormatted, WUPS_LOADER_LIBRARY_NN_SPM, IsStorageMaybePcFormatted__Q2_2nn3spmFPbQ3_2nn3spm12StorageIndex, WUPS_FP_TARGET_PROCESS_WII_U_MENU);
WUPS_MUST_REPLACE_FOR_PROCESS(MCP_Get4SecondOffStatus, WUPS_LOADER_LIBRARY_COREINIT, MCP_Get4SecondOffStatus, WUPS_FP_TARGET_PROCESS_WII_U_MENU);

5
src/main.h Normal file
View File

@ -0,0 +1,5 @@
#pragma once
#include "version.h"
#define PLUGIN_VERSION "v0.1"
#define PLUGIN_VERSION_FULL PLUGIN_VERSION PLUGIN_VERSION_EXTRA

137
src/utils/DownloadUtils.cpp Normal file
View File

@ -0,0 +1,137 @@
#include "DownloadUtils.h"
#include "logger.h"
#include <coreinit/cache.h>
#include <curl/curl.h>
#define IO_BUFSIZE (128 * 1024) // 128 KB
bool DownloadUtils::libInitDone = false;
static int initSocket(void *ptr, curl_socket_t socket, curlsocktype type) {
int o = 1;
// Activate WinScale
int r;
if ((uint32_t) ptr != 0x13371337) {
r = reinterpret_cast<decltype(&setsockopt)>(ptr)(socket, SOL_SOCKET, SO_WINSCALE, &o, sizeof(o));
} else {
r = setsockopt(socket, SOL_SOCKET, SO_WINSCALE, &o, sizeof(o));
}
if (r != 0) {
DEBUG_FUNCTION_LINE_ERR("initSocket: Error setting WinScale: %d", r);
return CURL_SOCKOPT_ERROR;
}
o = IO_BUFSIZE;
// Set receive buffersize
if ((uint32_t) ptr != 0x13371337) {
r = reinterpret_cast<decltype(&setsockopt)>(ptr)(socket, SOL_SOCKET, SO_RCVBUF, &o, sizeof(o));
} else {
r = setsockopt(socket, SOL_SOCKET, SO_RCVBUF, &o, sizeof(o));
}
if (r != 0) {
DEBUG_FUNCTION_LINE_ERR("initSocket: Error setting RBS: %d", r);
return CURL_SOCKOPT_ERROR;
}
return CURL_SOCKOPT_OK;
}
size_t writeCallback(char *buf, size_t size, size_t nmemb, void *up) {
auto *data = (std::string *) up;
data->append(buf, size * nmemb);
return size * nmemb; //tell curl how many bytes we handled
}
int progress_callback(void *clientp,
curl_off_t dltotal,
curl_off_t dlnow,
curl_off_t ultotal,
curl_off_t ulnow) {
if (clientp != nullptr) {
auto *progress = (float *) clientp;
if (dltotal > 0 && dlnow > 0) {
*progress = (float) dlnow / (float) dltotal;
} else {
*progress = 0.0f;
}
OSMemoryBarrier();
}
return 0;
}
bool DownloadUtils::Init() {
if (libInitDone) {
return true;
}
CURLcode res = curl_global_init(CURL_GLOBAL_DEFAULT);
if (res != CURLE_OK) {
return false;
}
libInitDone = true;
return true;
}
void DownloadUtils::Deinit() {
if (!libInitDone) {
return;
}
curl_global_cleanup();
libInitDone = false;
}
int DownloadUtils::DownloadFileToBuffer(const std::string &url, std::string &outBuffer, int &responseCodeOut, int &errorOut, std::string &errorTextOut, float *progress) {
if (!libInitDone) {
return -1;
}
// Start a curl session
CURL *curl = curl_easy_init();
if (!curl) {
curl_global_cleanup();
return -1;
}
// Enable optimizations
curl_easy_setopt(curl, CURLOPT_SOCKOPTDATA, 0x13371337);
curl_easy_setopt(curl, CURLOPT_SOCKOPTFUNCTION, initSocket);
// Follow redirects
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
// Set the download URL
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
if (progress != nullptr) {
/* pass struct to callback */
curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, progress);
curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, progress_callback);
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L);
}
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *) &outBuffer);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &writeCallback);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 5L);
char error[CURL_ERROR_SIZE]; /* needs to be at least this big */
memset(error, 0, sizeof(error));
curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, error);
errorTextOut = {};
errorOut = 0;
responseCodeOut = -1;
if ((errorOut = curl_easy_perform(curl)) != CURLE_OK) {
errorTextOut = error;
curl_easy_cleanup(curl);
return -1;
}
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &responseCodeOut);
curl_easy_cleanup(curl);
return 0;
}

12
src/utils/DownloadUtils.h Normal file
View File

@ -0,0 +1,12 @@
#pragma once
#include <string>
class DownloadUtils {
public:
static bool Init();
static void Deinit();
static int DownloadFileToBuffer(const std::string &url, std::string &outBuffer, int &responseCodeOut, int &errorOut, std::string &errorTextOut, float *progress);
static bool libInitDone;
};

61
src/utils/LatestVersion.h Normal file
View File

@ -0,0 +1,61 @@
// To parse this JSON data, first install
//
// json.hpp https://github.com/nlohmann/json
//
// Then include this file, and then do
//
// LatestVersion data = nlohmann::json::parse(jsonString);
#pragma once
#include "json.hpp"
#include <optional>
#include <regex>
#include <stdexcept>
namespace AromaUpdater {
using nlohmann::json;
#ifndef NLOHMANN_UNTYPED_AromaUpdater_HELPERHELPER
#define NLOHMANN_UNTYPED_AromaUpdater_HELPERHELPER
inline json get_untyped(const json &j, const char *property) {
if (j.find(property) != j.end()) {
return j.at(property).get<json>();
}
return json();
}
inline json get_untyped(const json &j, std::string property) {
return get_untyped(j, property.data());
}
#endif
class LatestVersion {
public:
LatestVersion() = default;
virtual ~LatestVersion() = default;
private:
std::string hash;
std::string description;
public:
const std::string &getHash() const { return hash; }
std::string &getMutableHash() { return hash; }
void setHash(const std::string &value) { this->hash = value; }
const std::string &getDescription() const { return description; }
std::string &getMutableDescription() { return description; }
void setDescription(const std::string &value) { this->description = value; }
};
} // namespace AromaUpdater
namespace AromaUpdater {
void from_json(const json &j, LatestVersion &x);
inline void from_json(const json &j, LatestVersion &x) {
x.setHash(j.at("hash").get<std::string>());
x.setDescription(j.at("description").get<std::string>());
}
} // namespace AromaUpdater

43
src/utils/config.cpp Normal file
View File

@ -0,0 +1,43 @@
#include "config.h"
bool gActivateUStealth = false;
bool gSkip4SecondOffStatusCheck = true;
bool gConfigMenuHintShown = false;
bool gUpdateChecked = false;
std::string gLastHash = {};
void boolItemChangedConfig(ConfigItemBoolean *item, bool newValue) {
wups_storage_item_t *cat_config;
if (WUPS_GetSubItem(nullptr, CAT_CONFIG, &cat_config) == WUPS_STORAGE_ERROR_SUCCESS) {
PROCESS_BOOL_ITEM_CHANGED(cat_config, USTEALTH_CONFIG_ID, gActivateUStealth);
PROCESS_BOOL_ITEM_CHANGED(cat_config, POWEROFFWARNING_CONFIG_ID, gSkip4SecondOffStatusCheck);
} else {
DEBUG_FUNCTION_LINE_ERR("Failed to get sub item: %s", CAT_CONFIG);
}
}
WUPS_GET_CONFIG() {
// We open the storage, so we can persist the configuration the user did.
if (WUPS_OpenStorage() != WUPS_STORAGE_ERROR_SUCCESS) {
DEBUG_FUNCTION_LINE("Failed to open storage");
return 0;
}
WUPSConfigHandle config;
WUPSConfig_CreateHandled(&config, "Aroma Base Plugin");
WUPSConfigCategoryHandle cat;
WUPSConfig_AddCategoryByNameHandled(config, "Wii U Menu patches", &cat);
WUPSConfigItemBoolean_AddToCategoryHandled(config, cat, USTEALTH_CONFIG_ID, "Avoid \"Format\" dialog on Wii U Menu", gActivateUStealth, &boolItemChangedConfig);
WUPSConfigItemBoolean_AddToCategoryHandled(config, cat, POWEROFFWARNING_CONFIG_ID, "Skip \"Shutdown warning\" on boot", gSkip4SecondOffStatusCheck, &boolItemChangedConfig);
return config;
}
WUPS_CONFIG_CLOSED() {
// Save all changes
if (WUPS_CloseStorage() != WUPS_STORAGE_ERROR_SUCCESS) {
DEBUG_FUNCTION_LINE_ERR("Failed to close storage");
}
}

51
src/utils/config.h Normal file
View File

@ -0,0 +1,51 @@
#pragma once
#include "logger.h"
#include <string>
#include <wups/config/WUPSConfigItemBoolean.h>
#include <wups/storage.h>
#define CAT_CONFIG "config"
#define CAT_OTHER "other"
#define USTEALTH_CONFIG_ID "ustealth"
#define POWEROFFWARNING_CONFIG_ID "SkipPowerOffWarning"
#define CONFIG_MENU_HINT_SHOWN_ID "configMenuHintShown"
#define LAST_UPDATE_HASH_ID "lastUpdateHash"
#define LOAD_BOOL_FROM_STORAGE(__cat, config_name, __variable__) \
if ((storageRes = WUPS_GetBool(__cat, config_name, &__variable__)) == WUPS_STORAGE_ERROR_NOT_FOUND) { \
if (WUPS_StoreBool(__cat, config_name, __variable__) != WUPS_STORAGE_ERROR_SUCCESS) { \
DEBUG_FUNCTION_LINE_WARN("Failed to store bool"); \
} \
} else if (storageRes != WUPS_STORAGE_ERROR_SUCCESS) { \
DEBUG_FUNCTION_LINE_WARN("Failed to get bool %s (%d)", WUPS_GetStorageStatusStr(storageRes), storageRes); \
} \
while (0)
#define LOAD_STRING_FROM_STORAGE(__cat, config_name, __string, __string_length) \
if ((storageRes = WUPS_GetString(__cat, config_name, __string, __string_length)) == WUPS_STORAGE_ERROR_NOT_FOUND) { \
if (WUPS_StoreString(__cat, config_name, __string) != WUPS_STORAGE_ERROR_SUCCESS) { \
DEBUG_FUNCTION_LINE_WARN("Failed to store string"); \
} \
} else if (storageRes != WUPS_STORAGE_ERROR_SUCCESS) { \
DEBUG_FUNCTION_LINE_WARN("Failed to get bool %s (%d)", WUPS_GetStorageStatusStr(storageRes), storageRes); \
} \
while (0)
#define PROCESS_BOOL_ITEM_CHANGED(cat, __config__name, __variable__) \
if (std::string_view(item->configId) == __config__name) { \
DEBUG_FUNCTION_LINE_ERR("New value in %s: %d", __config__name, newValue); \
__variable__ = newValue; \
WUPS_StoreInt(cat, __config__name, __variable__); \
return; \
} \
while (0)
extern bool gActivateUStealth;
extern bool gSkip4SecondOffStatusCheck;
extern bool gConfigMenuHintShown;
extern std::string gLastHash;
extern bool gUpdateChecked;

150
src/utils/input.cpp Normal file
View File

@ -0,0 +1,150 @@
#include "input.h"
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;
}
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;
}
uint32_t remapProButtons(uint32_t buttons) {
uint32_t conv_buttons = 0;
if (buttons & WPAD_PRO_BUTTON_LEFT) {
conv_buttons |= VPAD_BUTTON_LEFT;
}
if (buttons & WPAD_PRO_BUTTON_RIGHT) {
conv_buttons |= VPAD_BUTTON_RIGHT;
}
if (buttons & WPAD_PRO_BUTTON_DOWN) {
conv_buttons |= VPAD_BUTTON_DOWN;
}
if (buttons & WPAD_PRO_BUTTON_UP) {
conv_buttons |= VPAD_BUTTON_UP;
}
if (buttons & WPAD_PRO_BUTTON_PLUS) {
conv_buttons |= VPAD_BUTTON_PLUS;
}
if (buttons & WPAD_PRO_BUTTON_X) {
conv_buttons |= VPAD_BUTTON_X;
}
if (buttons & WPAD_PRO_BUTTON_Y) {
conv_buttons |= VPAD_BUTTON_Y;
}
if (buttons & WPAD_PRO_BUTTON_B) {
conv_buttons |= VPAD_BUTTON_B;
}
if (buttons & WPAD_PRO_BUTTON_A) {
conv_buttons |= VPAD_BUTTON_A;
}
if (buttons & WPAD_PRO_BUTTON_MINUS) {
conv_buttons |= VPAD_BUTTON_MINUS;
}
if (buttons & WPAD_PRO_BUTTON_HOME) {
conv_buttons |= VPAD_BUTTON_HOME;
}
if (buttons & WPAD_PRO_TRIGGER_ZR) {
conv_buttons |= VPAD_BUTTON_ZR;
}
if (buttons & WPAD_PRO_TRIGGER_ZL) {
conv_buttons |= VPAD_BUTTON_ZL;
}
if (buttons & WPAD_PRO_TRIGGER_R) {
conv_buttons |= VPAD_BUTTON_R;
}
if (buttons & WPAD_PRO_TRIGGER_L) {
conv_buttons |= VPAD_BUTTON_L;
}
if (buttons & WPAD_PRO_BUTTON_STICK_L) {
conv_buttons |= VPAD_BUTTON_STICK_L;
}
if (buttons & WPAD_PRO_BUTTON_STICK_R) {
conv_buttons |= VPAD_BUTTON_STICK_R;
}
return conv_buttons;
}

9
src/utils/input.h Normal file
View File

@ -0,0 +1,9 @@
#pragma once
#include <cstdint>
#include <padscore/kpad.h>
#include <vpad/input.h>
uint32_t remapWiiMoteButtons(uint32_t buttons);
uint32_t remapClassicButtons(uint32_t buttons);
uint32_t remapProButtons(uint32_t buttons);

24642
src/utils/json.hpp Normal file

File diff suppressed because it is too large Load Diff

178
src/utils/json_fwd.hpp Normal file
View File

@ -0,0 +1,178 @@
/* clang-format off */
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
// | | |__ | | | | | | version 3.11.2
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
#ifndef INCLUDE_NLOHMANN_JSON_FWD_HPP_
#define INCLUDE_NLOHMANN_JSON_FWD_HPP_
#include <cstdint> // int64_t, uint64_t
#include <map> // map
#include <memory> // allocator
#include <string> // string
#include <vector> // vector
// #include <nlohmann/detail/abi_macros.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
// | | |__ | | | | | | version 3.11.2
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
// This file contains all macro definitions affecting or depending on the ABI
#ifndef JSON_SKIP_LIBRARY_VERSION_CHECK
#if defined(NLOHMANN_JSON_VERSION_MAJOR) && defined(NLOHMANN_JSON_VERSION_MINOR) && defined(NLOHMANN_JSON_VERSION_PATCH)
#if NLOHMANN_JSON_VERSION_MAJOR != 3 || NLOHMANN_JSON_VERSION_MINOR != 11 || NLOHMANN_JSON_VERSION_PATCH != 2
#warning "Already included a different version of the library!"
#endif
#endif
#endif
#define NLOHMANN_JSON_VERSION_MAJOR 3 // NOLINT(modernize-macro-to-enum)
#define NLOHMANN_JSON_VERSION_MINOR 11 // NOLINT(modernize-macro-to-enum)
#define NLOHMANN_JSON_VERSION_PATCH 2 // NOLINT(modernize-macro-to-enum)
#ifndef JSON_DIAGNOSTICS
#define JSON_DIAGNOSTICS 0
#endif
#ifndef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON
#define JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON 0
#endif
#if JSON_DIAGNOSTICS
#define NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS _diag
#else
#define NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS
#endif
#if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON
#define NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON _ldvcmp
#else
#define NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON
#endif
#ifndef NLOHMANN_JSON_NAMESPACE_NO_VERSION
#define NLOHMANN_JSON_NAMESPACE_NO_VERSION 0
#endif
// Construct the namespace ABI tags component
#define NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b) json_abi ## a ## b
#define NLOHMANN_JSON_ABI_TAGS_CONCAT(a, b) \
NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b)
#define NLOHMANN_JSON_ABI_TAGS \
NLOHMANN_JSON_ABI_TAGS_CONCAT( \
NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS, \
NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON)
// Construct the namespace version component
#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) \
_v ## major ## _ ## minor ## _ ## patch
#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT(major, minor, patch) \
NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch)
#if NLOHMANN_JSON_NAMESPACE_NO_VERSION
#define NLOHMANN_JSON_NAMESPACE_VERSION
#else
#define NLOHMANN_JSON_NAMESPACE_VERSION \
NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT(NLOHMANN_JSON_VERSION_MAJOR, \
NLOHMANN_JSON_VERSION_MINOR, \
NLOHMANN_JSON_VERSION_PATCH)
#endif
// Combine namespace components
#define NLOHMANN_JSON_NAMESPACE_CONCAT_EX(a, b) a ## b
#define NLOHMANN_JSON_NAMESPACE_CONCAT(a, b) \
NLOHMANN_JSON_NAMESPACE_CONCAT_EX(a, b)
#ifndef NLOHMANN_JSON_NAMESPACE
#define NLOHMANN_JSON_NAMESPACE \
nlohmann::NLOHMANN_JSON_NAMESPACE_CONCAT( \
NLOHMANN_JSON_ABI_TAGS, \
NLOHMANN_JSON_NAMESPACE_VERSION)
#endif
#ifndef NLOHMANN_JSON_NAMESPACE_BEGIN
#define NLOHMANN_JSON_NAMESPACE_BEGIN \
namespace nlohmann \
{ \
inline namespace NLOHMANN_JSON_NAMESPACE_CONCAT( \
NLOHMANN_JSON_ABI_TAGS, \
NLOHMANN_JSON_NAMESPACE_VERSION) \
{
#endif
#ifndef NLOHMANN_JSON_NAMESPACE_END
#define NLOHMANN_JSON_NAMESPACE_END \
} /* namespace (inline namespace) NOLINT(readability/namespace) */ \
} // namespace nlohmann
#endif
/*!
@brief namespace for Niels Lohmann
@see https://github.com/nlohmann
@since version 1.0.0
*/
NLOHMANN_JSON_NAMESPACE_BEGIN
/*!
@brief default JSONSerializer template argument
This serializer ignores the template arguments and uses ADL
([argument-dependent lookup](https://en.cppreference.com/w/cpp/language/adl))
for serialization.
*/
template<typename T = void, typename SFINAE = void>
struct adl_serializer;
/// a class to store JSON values
/// @sa https://json.nlohmann.me/api/basic_json/
template<template<typename U, typename V, typename... Args> class ObjectType =
std::map,
template<typename U, typename... Args> class ArrayType = std::vector,
class StringType = std::string, class BooleanType = bool,
class NumberIntegerType = std::int64_t,
class NumberUnsignedType = std::uint64_t,
class NumberFloatType = double,
template<typename U> class AllocatorType = std::allocator,
template<typename T, typename SFINAE = void> class JSONSerializer =
adl_serializer,
class BinaryType = std::vector<std::uint8_t>, // cppcheck-suppress syntaxError
class CustomBaseClass = void>
class basic_json;
/// @brief JSON Pointer defines a string syntax for identifying a specific value within a JSON document
/// @sa https://json.nlohmann.me/api/json_pointer/
template<typename RefStringType>
class json_pointer;
/*!
@brief default specialization
@sa https://json.nlohmann.me/api/json/
*/
using json = basic_json<>;
/// @brief a minimal map-like container that preserves insertion order
/// @sa https://json.nlohmann.me/api/ordered_map/
template<class Key, class T, class IgnoredLess, class Allocator>
struct ordered_map;
/// @brief specialization that maintains the insertion order of object keys
/// @sa https://json.nlohmann.me/api/ordered_json/
using ordered_json = basic_json<nlohmann::ordered_map>;
NLOHMANN_JSON_NAMESPACE_END
#endif // INCLUDE_NLOHMANN_JSON_FWD_HPP_

36
src/utils/logger.c Normal file
View File

@ -0,0 +1,36 @@
#ifdef DEBUG
#include <stdint.h>
#include <whb/log_cafe.h>
#include <whb/log_module.h>
#include <whb/log_udp.h>
uint32_t moduleLogInit = false;
uint32_t cafeLogInit = false;
uint32_t udpLogInit = false;
#endif // DEBUG
void initLogging() {
#ifdef DEBUG
if (!(moduleLogInit = WHBLogModuleInit())) {
cafeLogInit = WHBLogCafeInit();
udpLogInit = WHBLogUdpInit();
}
#endif // DEBUG
}
void deinitLogging() {
#ifdef DEBUG
if (moduleLogInit) {
WHBLogModuleDeinit();
moduleLogInit = false;
}
if (cafeLogInit) {
WHBLogCafeDeinit();
cafeLogInit = false;
}
if (udpLogInit) {
WHBLogUdpDeinit();
udpLogInit = false;
}
#endif // DEBUG
}

74
src/utils/logger.h Normal file
View File

@ -0,0 +1,74 @@
#pragma once
#include <coreinit/debug.h>
#include <string.h>
#include <whb/log.h>
#ifdef __cplusplus
extern "C" {
#endif
#define LOG_APP_TYPE "P"
#define LOG_APP_NAME "AromaBasePlugin"
#define __FILENAME__ ({ \
const char *__filename = __FILE__; \
const char *__pos = strrchr(__filename, '/'); \
if (!__pos) __pos = strrchr(__filename, '\\'); \
__pos ? __pos + 1 : __filename; \
})
#define LOG(LOG_FUNC, FMT, ARGS...) LOG_EX_DEFAULT(LOG_FUNC, "", "", FMT, ##ARGS)
#define LOG_EX_DEFAULT(LOG_FUNC, LOG_LEVEL, LINE_END, FMT, ARGS...) LOG_EX(__FILENAME__, __FUNCTION__, __LINE__, LOG_FUNC, LOG_LEVEL, LINE_END, FMT, ##ARGS)
#define LOG_EX(FILENAME, FUNCTION, LINE, LOG_FUNC, LOG_LEVEL, LINE_END, FMT, ARGS...) \
do { \
LOG_FUNC("[(%s)%18s][%23s]%30s@L%04d: " LOG_LEVEL "" FMT "" LINE_END, LOG_APP_TYPE, LOG_APP_NAME, FILENAME, FUNCTION, LINE, ##ARGS); \
} while (0)
#ifdef DEBUG
#ifdef VERBOSE_DEBUG
#define DEBUG_FUNCTION_LINE_VERBOSE(FMT, ARGS...) LOG(WHBLogPrintf, FMT, ##ARGS)
#define DEBUG_FUNCTION_LINE_VERBOSE_EX(FILENAME, FUNCTION, LINE, FMT, ARGS...) LOG_EX(FILENAME, FUNCTION, LINE, WHBLogPrintf, "", "", FMT, ##ARGS);
#else
#define DEBUG_FUNCTION_LINE_VERBOSE(FMT, ARGS...) while (0)
#define DEBUG_FUNCTION_LINE_VERBOSE_EX(FMT, ARGS...) while (0)
#endif
#define DEBUG_FUNCTION_LINE(FMT, ARGS...) LOG(WHBLogPrintf, FMT, ##ARGS)
#define DEBUG_FUNCTION_LINE_WRITE(FMT, ARGS...) LOG(WHBLogWritef, FMT, ##ARGS)
#define DEBUG_FUNCTION_LINE_ERR(FMT, ARGS...) LOG_EX_DEFAULT(WHBLogPrintf, "##ERROR## ", "", FMT, ##ARGS)
#define DEBUG_FUNCTION_LINE_WARN(FMT, ARGS...) LOG_EX_DEFAULT(WHBLogPrintf, "##WARN ## ", "", FMT, ##ARGS)
#define DEBUG_FUNCTION_LINE_INFO(FMT, ARGS...) LOG_EX_DEFAULT(WHBLogPrintf, "##INFO ## ", "", FMT, ##ARGS)
#define DEBUG_FUNCTION_LINE_ERR_LAMBDA(FILENAME, FUNCTION, LINE, FMT, ARGS...) LOG_EX(FILENAME, FUNCTION, LINE, WHBLogPrintf, "##ERROR## ", "", FMT, ##ARGS);
#else
#define DEBUG_FUNCTION_LINE_VERBOSE_EX(FMT, ARGS...) while (0)
#define DEBUG_FUNCTION_LINE_VERBOSE(FMT, ARGS...) while (0)
#define DEBUG_FUNCTION_LINE(FMT, ARGS...) while (0)
#define DEBUG_FUNCTION_LINE_WRITE(FMT, ARGS...) while (0)
#define DEBUG_FUNCTION_LINE_ERR(FMT, ARGS...) LOG_EX_DEFAULT(OSReport, "##ERROR## ", "\n", FMT, ##ARGS)
#define DEBUG_FUNCTION_LINE_WARN(FMT, ARGS...) LOG_EX_DEFAULT(OSReport, "##WARN ## ", "\n", FMT, ##ARGS)
#define DEBUG_FUNCTION_LINE_INFO(FMT, ARGS...) LOG_EX_DEFAULT(OSReport, "##INFO ## ", "\n", FMT, ##ARGS)
#define DEBUG_FUNCTION_LINE_ERR_LAMBDA(FILENAME, FUNCTION, LINE, FMT, ARGS...) LOG_EX(FILENAME, FUNCTION, LINE, OSReport, "##ERROR## ", "\n", FMT, ##ARGS);
#endif
void initLogging();
void deinitLogging();
#ifdef __cplusplus
}
#endif

2
src/version.h Normal file
View File

@ -0,0 +1,2 @@
#pragma once
#define PLUGIN_VERSION_EXTRA ""