mirror of
https://github.com/wiiu-env/WiiUPluginSystem.git
synced 2024-11-13 06:15:11 +01:00
Example: Update the existing example_plugin and add C++ example plugin
This commit is contained in:
parent
476cba8dd4
commit
104fdc3b7b
7
.github/workflows/pr.yml
vendored
7
.github/workflows/pr.yml
vendored
@ -30,6 +30,7 @@ jobs:
|
||||
- name: clang-format
|
||||
run: |
|
||||
docker run --rm -v ${PWD}:/src ghcr.io/wiiu-env/clang-format:13.0.0-2 -r ./plugins/example_plugin/src
|
||||
docker run --rm -v ${PWD}:/src ghcr.io/wiiu-env/clang-format:13.0.0-2 -r ./plugins/example_plugin_cpp/src
|
||||
docker run --rm -v ${PWD}:/src ghcr.io/wiiu-env/clang-format:13.0.0-2 -r ./plugins/storage_test_plugin/src --exclude ./plugins/storage_test_plugin/src/catch2
|
||||
build-examples:
|
||||
runs-on: ubuntu-22.04
|
||||
@ -40,8 +41,10 @@ jobs:
|
||||
run: |
|
||||
docker build . -f Dockerfile.buildexamples -t builder
|
||||
cd ./plugins/example_plugin
|
||||
docker run --rm -v ${PWD}:/project builder make
|
||||
cd ../storage_test_plugin
|
||||
docker run --rm -v ${PWD}:/project builder make
|
||||
cd ../example_plugin_cpp
|
||||
docker run --rm -v ${PWD}:/project builder make
|
||||
cd ../storage_test_plugin
|
||||
docker run --rm -v ${PWD}:/project builder make
|
||||
- uses: actions/upload-artifact@master
|
||||
with:
|
||||
|
8
.github/workflows/push_image.yml
vendored
8
.github/workflows/push_image.yml
vendored
@ -33,6 +33,8 @@ jobs:
|
||||
- name: clang-format
|
||||
run: |
|
||||
docker run --rm -v ${PWD}:/src ghcr.io/wiiu-env/clang-format:13.0.0-2 -r ./plugins/storage_test_plugin/src --exclude ./plugins/storage_test_plugin/src/catch2
|
||||
docker run --rm -v ${PWD}:/src ghcr.io/wiiu-env/clang-format:13.0.0-2 -r ./plugins/example_plugin/src
|
||||
docker run --rm -v ${PWD}:/src ghcr.io/wiiu-env/clang-format:13.0.0-2 -r ./plugins/example_plugin_cpp/src
|
||||
build-examples:
|
||||
runs-on: ubuntu-22.04
|
||||
needs: clang-format-examples
|
||||
@ -42,8 +44,10 @@ jobs:
|
||||
run: |
|
||||
docker build . -f Dockerfile.buildexamples -t builder
|
||||
cd ./plugins/example_plugin
|
||||
docker run --rm -v ${PWD}:/project builder make
|
||||
cd ../storage_test_plugin
|
||||
docker run --rm -v ${PWD}:/project builder make
|
||||
cd ../example_plugin_cpp
|
||||
docker run --rm -v ${PWD}:/project builder make
|
||||
cd ../storage_test_plugin
|
||||
docker run --rm -v ${PWD}:/project builder make
|
||||
build-and-push-image:
|
||||
runs-on: ubuntu-latest
|
||||
|
@ -28,4 +28,4 @@ It's highly recommended to pin the version to the **latest date** instead of usi
|
||||
|
||||
## Format the code via docker
|
||||
|
||||
`docker run --rm -v ${PWD}:/src ghcr.io/wiiu-env/clang-format:13.0.0-2 -r ./include ./libraries ./plugins/example_plugin/src ./plugins/storage_test_plugin/src --exclude ./plugins/storage_test_plugin/src/catch2 -i`
|
||||
`docker run --rm -v ${PWD}:/src ghcr.io/wiiu-env/clang-format:13.0.0-2 -r ./include ./libraries ./plugins/example_plugin/src ./plugins/example_plugin_cpp/src ./plugins/storage_test_plugin/src --exclude ./plugins/storage_test_plugin/src/catch2 -i`
|
||||
|
@ -1,10 +1,12 @@
|
||||
#include "utils/logger.h"
|
||||
#include <coreinit/filesystem.h>
|
||||
#include <malloc.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <wups.h>
|
||||
#include <wups/config/WUPSConfigItemBoolean.h>
|
||||
#include <wups/config/WUPSConfigItemMultipleValues.h>
|
||||
#include <wups/config/WUPSConfigItemStub.h>
|
||||
|
||||
/**
|
||||
Mandatory plugin information.
|
||||
@ -56,7 +58,7 @@ WUPSConfigAPICallbackStatus ConfigMenuOpenedCallback(WUPSConfigCategoryHandle ro
|
||||
}
|
||||
|
||||
// Add a new item to this settings category
|
||||
if (!WUPSConfigItemBoolean_AddToCategory(settingsCategory, LOG_FS_OPEN_CONFIG_ID, "Log FSOpen calls", logFSOpen, &logFSOpenChanged)) {
|
||||
if (WUPSConfigItemBoolean_AddToCategory(settingsCategory, LOG_FS_OPEN_CONFIG_ID, "Log FSOpen calls", true, logFSOpen, &logFSOpenChanged) != WUPSCONFIG_API_RESULT_SUCCESS) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to add item to category");
|
||||
return WUPSCONFIG_API_CALLBACK_RESULT_ERROR;
|
||||
}
|
||||
@ -81,7 +83,7 @@ WUPSConfigAPICallbackStatus ConfigMenuOpenedCallback(WUPSConfigCategoryHandle ro
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to create categoryLevel1");
|
||||
return WUPSCONFIG_API_CALLBACK_RESULT_ERROR;
|
||||
}
|
||||
if (!WUPSConfigItemBoolean_AddToCategory(categoryLevel2, "stubInsideCategory", "This is stub item inside a nested category", false, NULL)) {
|
||||
if (WUPSConfigItemBoolean_AddToCategory(categoryLevel2, "stubInsideCategory", "This is stub item inside a nested category", false, false, NULL) != WUPSCONFIG_API_RESULT_SUCCESS) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to add stub item to root category");
|
||||
return WUPSCONFIG_API_CALLBACK_RESULT_ERROR;
|
||||
}
|
||||
@ -98,10 +100,9 @@ WUPSConfigAPICallbackStatus ConfigMenuOpenedCallback(WUPSConfigCategoryHandle ro
|
||||
return WUPSCONFIG_API_CALLBACK_RESULT_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// We can also directly add items to the root category
|
||||
if (!WUPSConfigItemBoolean_AddToCategory(root, "stub0", "This is stub item without category", false, NULL)) {
|
||||
if (WUPSConfigItemStub_AddToCategory(root, "This is stub item without category") != WUPSCONFIG_API_RESULT_SUCCESS) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to add stub item to root category");
|
||||
return WUPSCONFIG_API_CALLBACK_RESULT_ERROR;
|
||||
}
|
||||
@ -117,11 +118,11 @@ WUPSConfigAPICallbackStatus ConfigMenuOpenedCallback(WUPSConfigCategoryHandle ro
|
||||
values[i].value = i;
|
||||
values[i].valueName = str;
|
||||
}
|
||||
bool multValuesRes = WUPSConfigItemMultipleValues_AddToCategory(root, "multival", "Multiple values", 0, values, numOfElements, NULL);
|
||||
WUPSConfigAPIStatus multValuesRes = WUPSConfigItemMultipleValues_AddToCategory(root, "multival", "Multiple values", 0, 0, values, numOfElements, NULL);
|
||||
for (int i = 0; i < sizeof(values) / sizeof(values[0]); i++) {
|
||||
free(values[i].valueName);
|
||||
free((void *) values[i].valueName);
|
||||
}
|
||||
if (!multValuesRes) {
|
||||
if (multValuesRes != WUPSCONFIG_API_RESULT_SUCCESS) {
|
||||
return WUPSCONFIG_API_CALLBACK_RESULT_ERROR;
|
||||
}
|
||||
}
|
||||
|
67
plugins/example_plugin_cpp/.clang-format
Normal file
67
plugins/example_plugin_cpp/.clang-format
Normal 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
|
5
plugins/example_plugin_cpp/Dockerfile
Normal file
5
plugins/example_plugin_cpp/Dockerfile
Normal file
@ -0,0 +1,5 @@
|
||||
FROM ghcr.io/wiiu-env/devkitppc:20230218
|
||||
|
||||
COPY --from=ghcr.io/wiiu-env/wiiupluginsystem:20230215 /artifacts $DEVKITPRO
|
||||
|
||||
WORKDIR project
|
135
plugins/example_plugin_cpp/Makefile
Normal file
135
plugins/example_plugin_cpp/Makefile
Normal file
@ -0,0 +1,135 @@
|
||||
#-------------------------------------------------------------------------------
|
||||
.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
|
||||
#-------------------------------------------------------------------------------
|
||||
# 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 := ExamplePluginCPP
|
||||
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) -std=c++20
|
||||
|
||||
ASFLAGS := -g $(ARCH)
|
||||
LDFLAGS = -g $(ARCH) $(RPXSPECS) -Wl,-Map,$(notdir $*.map) $(WUPSSPECS)
|
||||
|
||||
LIBS := -lwups -lwut
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# list of directories containing libraries, this must be the top level
|
||||
# containing include and lib
|
||||
#-------------------------------------------------------------------------------
|
||||
LIBDIRS := $(PORTLIBS) $(WUPS_ROOT) $(WUT_ROOT)
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# no real need to edit anything past this point unless you need to add additional
|
||||
# rules for different file extensions
|
||||
#-------------------------------------------------------------------------------
|
||||
ifneq ($(BUILD),$(notdir $(CURDIR)))
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
export OUTPUT := $(CURDIR)/$(TARGET)
|
||||
export TOPDIR := $(CURDIR)
|
||||
|
||||
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
|
||||
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
|
||||
|
||||
export DEPSDIR := $(CURDIR)/$(BUILD)
|
||||
|
||||
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
|
||||
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
|
||||
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
|
||||
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# use CXX for linking C++ projects, CC for standard C
|
||||
#-------------------------------------------------------------------------------
|
||||
ifeq ($(strip $(CPPFILES)),)
|
||||
#-------------------------------------------------------------------------------
|
||||
export LD := $(CC)
|
||||
#-------------------------------------------------------------------------------
|
||||
else
|
||||
#-------------------------------------------------------------------------------
|
||||
export LD := $(CXX)
|
||||
#-------------------------------------------------------------------------------
|
||||
endif
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
export OFILES_BIN := $(addsuffix .o,$(BINFILES))
|
||||
export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
|
||||
export OFILES := $(OFILES_BIN) $(OFILES_SRC)
|
||||
export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES)))
|
||||
|
||||
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
|
||||
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
|
||||
-I$(CURDIR)/$(BUILD)
|
||||
|
||||
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
|
||||
|
||||
.PHONY: $(BUILD) clean all
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
all: $(BUILD)
|
||||
|
||||
$(BUILD):
|
||||
@$(shell [ ! -d $(BUILD) ] && mkdir -p $(BUILD))
|
||||
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
clean:
|
||||
@echo clean ...
|
||||
@rm -fr $(BUILD) $(TARGET).wps $(TARGET).elf
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
else
|
||||
.PHONY: all
|
||||
|
||||
DEPENDS := $(OFILES:.o=.d)
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# main targets
|
||||
#-------------------------------------------------------------------------------
|
||||
all : $(OUTPUT).wps
|
||||
|
||||
$(OUTPUT).wps : $(OUTPUT).elf
|
||||
$(OUTPUT).elf : $(OFILES)
|
||||
|
||||
$(OFILES_SRC) : $(HFILES_BIN)
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# you need a rule like this for each extension you use as binary data
|
||||
#-------------------------------------------------------------------------------
|
||||
%.bin.o %_bin.h : %.bin
|
||||
#-------------------------------------------------------------------------------
|
||||
@echo $(notdir $<)
|
||||
@$(bin2o)
|
||||
|
||||
-include $(DEPENDS)
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
endif
|
||||
#-------------------------------------------------------------------------------
|
57
plugins/example_plugin_cpp/README.md
Normal file
57
plugins/example_plugin_cpp/README.md
Normal file
@ -0,0 +1,57 @@
|
||||
# Example plugin
|
||||
|
||||
This is just a simple example plugin which can be used as a template.
|
||||
The plugin logs the FSOpenFile calls via UDP (**Only when build via `make DEBUG=1`**).
|
||||
|
||||
The logging can be enabled/disabled via the WUPS Config menu (press L, DPAD Down and Minus on the GamePad, Pro Controller or Classic Controller).
|
||||
|
||||
## Installation
|
||||
|
||||
(`[ENVIRONMENT]` is a placeholder for the actual environment name.)
|
||||
|
||||
1. Copy the file `ExamplePlugin.wps` into `sd:/wiiu/environments/[ENVIRONMENT]/plugins`.
|
||||
2. Requires the [WiiUPluginLoaderBackend](https://github.com/wiiu-env/WiiUPluginLoaderBackend) in `sd:/wiiu/environments/[ENVIRONMENT]/modules`.
|
||||
|
||||
Start the environment (e.g Aroma) and the backend should load the plugin.
|
||||
|
||||
## Building
|
||||
|
||||
For building you need:
|
||||
|
||||
- [wups](https://github.com/Maschell/WiiUPluginSystem)
|
||||
- [wut](https://github.com/devkitpro/wut)
|
||||
|
||||
Install them (in this order) according to their README's. Don't forget the dependencies of the libs itself.
|
||||
|
||||
Then you should be able to compile via `make` (with no logging) or `make DEBUG=1` (with logging).
|
||||
|
||||
## Buildflags
|
||||
|
||||
### Logging
|
||||
|
||||
Building via `make` only logs errors (via OSReport). To enable logging via the [LoggingModule](https://github.com/wiiu-env/LoggingModule) set `DEBUG` to `1` or `VERBOSE`.
|
||||
|
||||
`make` Logs errors only (via OSReport).
|
||||
`make DEBUG=1` Enables information and error logging via [LoggingModule](https://github.com/wiiu-env/LoggingModule).
|
||||
`make DEBUG=VERBOSE` Enables verbose information and error logging via [LoggingModule](https://github.com/wiiu-env/LoggingModule).
|
||||
|
||||
If the [LoggingModule](https://github.com/wiiu-env/LoggingModule) is not present, it'll fallback to UDP (Port 4405) and [CafeOS](https://github.com/wiiu-env/USBSerialLoggingModule) logging.
|
||||
|
||||
## 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 example-plugin-builder
|
||||
|
||||
# make
|
||||
docker run -it --rm -v ${PWD}:/project example-plugin-builder make DEBUG=1
|
||||
|
||||
# make clean
|
||||
docker run -it --rm -v ${PWD}:/project example-plugin-builder make clean
|
||||
```
|
||||
|
||||
## Format the code via docker
|
||||
|
||||
`docker run --rm -v ${PWD}:/src ghcr.io/wiiu-env/clang-format:13.0.0-2 -r ./src -i`
|
306
plugins/example_plugin_cpp/src/main.cpp
Normal file
306
plugins/example_plugin_cpp/src/main.cpp
Normal file
@ -0,0 +1,306 @@
|
||||
#include "utils/logger.h"
|
||||
#include <coreinit/filesystem.h>
|
||||
#include <malloc.h>
|
||||
#include <wups.h>
|
||||
#include <wups/config/WUPSConfigItemBoolean.h>
|
||||
#include <wups/config/WUPSConfigItemIntegerRange.h>
|
||||
#include <wups/config/WUPSConfigItemMultipleValues.h>
|
||||
#include <wups/config/WUPSConfigItemStub.h>
|
||||
#include <wups/config_api.h>
|
||||
|
||||
/**
|
||||
Mandatory plugin information.
|
||||
If not set correctly, the loader will refuse to use the plugin.
|
||||
**/
|
||||
WUPS_PLUGIN_NAME("Example plugin C++");
|
||||
WUPS_PLUGIN_DESCRIPTION("This is just an example plugin written in C++");
|
||||
WUPS_PLUGIN_VERSION("v1.0");
|
||||
WUPS_PLUGIN_AUTHOR("Maschell");
|
||||
WUPS_PLUGIN_LICENSE("BSD");
|
||||
|
||||
#define LOG_FS_OPEN_CONFIG_ID "logFSOpen"
|
||||
#define OTHER_EXAMPLE_BOOL_CONFIG_ID "otherBoolItem"
|
||||
#define OTHER_EXAMPLE2_BOOL_CONFIG_ID "other2BoolItem"
|
||||
#define INTEGER_RANGE_EXAMPLE_CONFIG_ID "intRangeExample"
|
||||
#define MULTIPLE_VALUES_EXAMPLE_CONFIG_ID "multValueExample"
|
||||
|
||||
/**
|
||||
All of this defines can be used in ANY file.
|
||||
It's possible to split it up into multiple files.
|
||||
|
||||
**/
|
||||
|
||||
WUPS_USE_WUT_DEVOPTAB(); // Use the wut devoptabs
|
||||
WUPS_USE_STORAGE("example_plugin_cpp"); // Unique id for the storage api
|
||||
|
||||
enum ExampleOptions {
|
||||
EXAMPLE_OPTION_1 = 0,
|
||||
EXAMPLE_OPTION_2 = 1,
|
||||
EXAMPLE_OPTION_3 = 2,
|
||||
};
|
||||
|
||||
#define LOF_FS_OPEN_DEFAULT_VALUE true
|
||||
#define INTEGER_RANGE_DEFAULT_VALUE 10
|
||||
#define MULTIPLE_VALUES_DEFAULT_VALUE EXAMPLE_OPTION_2
|
||||
|
||||
bool sLogFSOpen = LOF_FS_OPEN_DEFAULT_VALUE;
|
||||
int sIntegerRangeValue = INTEGER_RANGE_DEFAULT_VALUE;
|
||||
ExampleOptions sExampleOptionValue = MULTIPLE_VALUES_DEFAULT_VALUE;
|
||||
|
||||
/**
|
||||
* Callback that will be called if the config has been changed
|
||||
*/
|
||||
void boolItemChanged(ConfigItemBoolean *item, bool newValue) {
|
||||
DEBUG_FUNCTION_LINE_INFO("New value in boolItemChanged: %d", newValue);
|
||||
if (std::string_view(LOG_FS_OPEN_CONFIG_ID) == item->identifier) {
|
||||
sLogFSOpen = newValue;
|
||||
// If the value has changed, we store it in the storage.
|
||||
WUPS_StoreInt(nullptr, item->identifier, newValue);
|
||||
} else if (std::string_view(OTHER_EXAMPLE_BOOL_CONFIG_ID) == item->identifier) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Other bool value has changed to %d", newValue);
|
||||
} else if (std::string_view(OTHER_EXAMPLE2_BOOL_CONFIG_ID) == item->identifier) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Other2 bool value has changed to %d", newValue);
|
||||
}
|
||||
}
|
||||
|
||||
void integerRangeItemChanged(ConfigItemIntegerRange *item, int newValue) {
|
||||
DEBUG_FUNCTION_LINE_INFO("New value in integerRangeItemChanged: %d", newValue);
|
||||
// If the value has changed, we store it in the storage.
|
||||
if (std::string_view(LOG_FS_OPEN_CONFIG_ID) == item->identifier) {
|
||||
sIntegerRangeValue = newValue;
|
||||
// If the value has changed, we store it in the storage.
|
||||
WUPS_StoreInt(nullptr, item->identifier, newValue);
|
||||
}
|
||||
}
|
||||
|
||||
void multipleValueItemChanged(ConfigItemIntegerRange *item, uint32_t newValue) {
|
||||
DEBUG_FUNCTION_LINE_INFO("New value in multipleValueItemChanged: %d", newValue);
|
||||
// If the value has changed, we store it in the storage.
|
||||
if (std::string_view(MULTIPLE_VALUES_EXAMPLE_CONFIG_ID) == item->identifier) {
|
||||
sExampleOptionValue = (ExampleOptions) newValue;
|
||||
// If the value has changed, we store it in the storage.
|
||||
WUPS_StoreInt(nullptr, item->identifier, sExampleOptionValue);
|
||||
}
|
||||
}
|
||||
|
||||
WUPSConfigAPICallbackStatus ConfigMenuOpenedCallback(WUPSConfigCategoryHandle rootHandle) {
|
||||
// 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 WUPSCONFIG_API_CALLBACK_RESULT_ERROR;
|
||||
}
|
||||
// To use the C++ API, we create new WUPSConfigCategory from the root handle!
|
||||
WUPSConfigCategory root = WUPSConfigCategory(rootHandle);
|
||||
|
||||
// The functions of the Config API come in two variants: One that throws an exception, and another one which doesn't
|
||||
// To use the Config API without exception see the example below this try/catch block.
|
||||
try {
|
||||
// Then we can simply create a new category
|
||||
auto functionPatchesCat = WUPSConfigCategory::Create("function patches");
|
||||
|
||||
// Add a boolean item to this newly created category
|
||||
functionPatchesCat.add(WUPSConfigItemBoolean::Create(LOG_FS_OPEN_CONFIG_ID, "Log FSOpen calls",
|
||||
LOF_FS_OPEN_DEFAULT_VALUE, sLogFSOpen,
|
||||
boolItemChanged));
|
||||
|
||||
// And finally move that category to the root category.
|
||||
// Note: "functionPatchesCat" can NOT be changed after adding it to root.
|
||||
root.add(std::move(functionPatchesCat));
|
||||
|
||||
// We can also add items directly to root!
|
||||
root.add(WUPSConfigItemBoolean::Create(OTHER_EXAMPLE_BOOL_CONFIG_ID, "Just another bool item",
|
||||
false, false,
|
||||
boolItemChanged));
|
||||
|
||||
// You can also add an item which just displays any text.
|
||||
root.add(WUPSConfigItemStub::Create("This item is just displaying some text"));
|
||||
|
||||
// It's also possible to create and item to select an integer from a range.
|
||||
root.add(WUPSConfigItemIntegerRange::Create(INTEGER_RANGE_EXAMPLE_CONFIG_ID, "Item for selecting an integer between 0 and 50",
|
||||
INTEGER_RANGE_DEFAULT_VALUE, sIntegerRangeValue,
|
||||
0, 50,
|
||||
&integerRangeItemChanged));
|
||||
|
||||
|
||||
// To select value from an enum WUPSConfigItemMultipleValues fits the best.
|
||||
constexpr WUPSConfigItemMultipleValues::ValuePair possibleValues[] = {
|
||||
{EXAMPLE_OPTION_1, "Option 1"},
|
||||
{EXAMPLE_OPTION_2, "Option 2"},
|
||||
{EXAMPLE_OPTION_3, "Option 3"},
|
||||
};
|
||||
|
||||
// It comes in two variants.
|
||||
// - "WUPSConfigItemMultipleValues::CreateFromValue" will take a default and current **value**
|
||||
// - "WUPSConfigItemMultipleValues::CreateFromIndex" will take a default and current **index**
|
||||
root.add(WUPSConfigItemMultipleValues::CreateFromValue(MULTIPLE_VALUES_EXAMPLE_CONFIG_ID, "Select an option!",
|
||||
MULTIPLE_VALUES_DEFAULT_VALUE, sExampleOptionValue,
|
||||
possibleValues,
|
||||
nullptr));
|
||||
|
||||
// It's also possible to have nested categories
|
||||
auto nc1 = WUPSConfigCategory::Create("Category inside root");
|
||||
auto nc2 = WUPSConfigCategory::Create("Category inside subcategory 1");
|
||||
auto nc3 = WUPSConfigCategory::Create("Category inside subcategory 2");
|
||||
|
||||
nc3.add(WUPSConfigItemStub::Create("Item inside subcategory 3"));
|
||||
nc2.add(WUPSConfigItemStub::Create("Item inside subcategory 2"));
|
||||
nc1.add(WUPSConfigItemStub::Create("Item inside subcategory 1"));
|
||||
|
||||
nc2.add(std::move(nc3));
|
||||
nc1.add(std::move(nc2));
|
||||
root.add(std::move(nc1));
|
||||
} catch (std::exception &e) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Creating config menu failed: %s", e.what());
|
||||
return WUPSCONFIG_API_CALLBACK_RESULT_ERROR;
|
||||
}
|
||||
|
||||
// In case we don't like exception, we can use the API as well.
|
||||
// If we add a "WUPSConfigAPIStatus" reference to the API calls, the function won't throw an exception.
|
||||
// Instead it will return std::optionals and write the result into the WUPSConfigAPIStatus.
|
||||
WUPSConfigAPIStatus err;
|
||||
auto categoryOpt = WUPSConfigCategory::Create("Just another Category", err);
|
||||
if (!categoryOpt) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to create category: %s", WUPSConfigAPI_GetStatusStr(err));
|
||||
return WUPSCONFIG_API_CALLBACK_RESULT_ERROR;
|
||||
}
|
||||
|
||||
auto boolItemOpt = WUPSConfigItemBoolean::Create(OTHER_EXAMPLE2_BOOL_CONFIG_ID, "Just another bool item",
|
||||
false, false,
|
||||
boolItemChanged,
|
||||
err);
|
||||
if (!boolItemOpt) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to create bool item: %s", WUPSConfigAPI_GetStatusStr(err));
|
||||
return WUPSCONFIG_API_CALLBACK_RESULT_ERROR;
|
||||
}
|
||||
|
||||
// Add bool item to category
|
||||
if (!categoryOpt->add(std::move(*boolItemOpt), err)) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to add bool item to category: %s", WUPSConfigAPI_GetStatusStr(err));
|
||||
return WUPSCONFIG_API_CALLBACK_RESULT_ERROR;
|
||||
}
|
||||
|
||||
// Add category to root.
|
||||
if (!root.add(std::move(*categoryOpt), err)) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to add category to root: %s", WUPSConfigAPI_GetStatusStr(err));
|
||||
return WUPSCONFIG_API_CALLBACK_RESULT_ERROR;
|
||||
}
|
||||
|
||||
return WUPSCONFIG_API_CALLBACK_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
void ConfigMenuClosedCallback() {
|
||||
// Save all changes
|
||||
if (WUPS_CloseStorage() != WUPS_STORAGE_ERROR_SUCCESS) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to close storage");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Gets called ONCE when the plugin was loaded.
|
||||
**/
|
||||
INITIALIZE_PLUGIN() {
|
||||
// Logging only works when compiled with `make DEBUG=1`. See the README for more information.
|
||||
initLogging();
|
||||
DEBUG_FUNCTION_LINE("INITIALIZE_PLUGIN of example_plugin!");
|
||||
|
||||
WUPSConfigAPIOptionsV1 configOptions = {.name = "example_plugin"};
|
||||
if (WUPSConfigAPI_Init(configOptions, ConfigMenuOpenedCallback, ConfigMenuClosedCallback) != WUPSCONFIG_API_RESULT_SUCCESS) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to init config api");
|
||||
}
|
||||
|
||||
// Open storage to read values
|
||||
WUPSStorageError storageRes = WUPS_OpenStorage();
|
||||
if (storageRes != WUPS_STORAGE_ERROR_SUCCESS) {
|
||||
DEBUG_FUNCTION_LINE("Failed to open storage %s (%d)", WUPS_GetStorageStatusStr(storageRes), storageRes);
|
||||
} else {
|
||||
// Try to get value from storage
|
||||
if ((storageRes = WUPS_GetBool(nullptr, LOG_FS_OPEN_CONFIG_ID, &sLogFSOpen)) == WUPS_STORAGE_ERROR_NOT_FOUND) {
|
||||
// Add the value to the storage if it's missing.
|
||||
if (WUPS_StoreBool(nullptr, LOG_FS_OPEN_CONFIG_ID, sLogFSOpen) != WUPS_STORAGE_ERROR_SUCCESS) {
|
||||
DEBUG_FUNCTION_LINE("Failed to store bool");
|
||||
}
|
||||
} else if (storageRes != WUPS_STORAGE_ERROR_SUCCESS) {
|
||||
DEBUG_FUNCTION_LINE("Failed to get bool %s (%d)", WUPS_GetStorageStatusStr(storageRes), storageRes);
|
||||
}
|
||||
|
||||
// Close storage
|
||||
if (WUPS_CloseStorage() != WUPS_STORAGE_ERROR_SUCCESS) {
|
||||
DEBUG_FUNCTION_LINE("Failed to close storage");
|
||||
}
|
||||
}
|
||||
deinitLogging();
|
||||
}
|
||||
|
||||
/**
|
||||
Gets called when the plugin will be unloaded.
|
||||
**/
|
||||
DEINITIALIZE_PLUGIN() {
|
||||
DEBUG_FUNCTION_LINE("DEINITIALIZE_PLUGIN of example_plugin!");
|
||||
}
|
||||
|
||||
/**
|
||||
Gets called when an application starts.
|
||||
**/
|
||||
ON_APPLICATION_START() {
|
||||
initLogging();
|
||||
|
||||
DEBUG_FUNCTION_LINE("ON_APPLICATION_START of example_plugin!");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets called when an application actually ends
|
||||
*/
|
||||
ON_APPLICATION_ENDS() {
|
||||
deinitLogging();
|
||||
}
|
||||
|
||||
/**
|
||||
Gets called when an application request to exit.
|
||||
**/
|
||||
ON_APPLICATION_REQUESTS_EXIT() {
|
||||
DEBUG_FUNCTION_LINE_INFO("ON_APPLICATION_REQUESTS_EXIT of example_plugin!");
|
||||
}
|
||||
|
||||
/**
|
||||
This defines a function replacement.
|
||||
It allows to replace the system function with an own function.
|
||||
So whenever a game / application calls an overridden function, your function gets called instead.
|
||||
|
||||
Currently it's only possible to override functions that are loaded from .rpl files of OSv10 (00050010-1000400A).
|
||||
|
||||
Signature of this macro:
|
||||
DECL_FUNCTION( RETURN_TYPE, ARBITRARY_NAME_OF_FUNCTION , ARGS_SEPERATED_BY_COMMA){
|
||||
//Your code goes here.
|
||||
}
|
||||
|
||||
Within this macro, two more function get declare you can use.
|
||||
my_ARBITRARY_NAME_OF_FUNCTION and real_ARBITRARY_NAME_OF_FUNCTION
|
||||
|
||||
RETURN_TYPE my_ARBITRARY_NAME_OF_FUNCTION(ARGS_SEPERATED_BY_COMMA):
|
||||
is just name of the function that gets declared in this macro.
|
||||
It has the same effect as calling the overridden function directly.
|
||||
|
||||
RETURN_TYPE real_ARBITRARY_NAME_OF_FUNCTION(ARGS_SEPERATED_BY_COMMA):
|
||||
is the name of the function, that leads to function that was overridden.
|
||||
Use this to call the original function that will be overridden.
|
||||
CAUTION: Other plugins may already have manipulated the return value or arguments.
|
||||
|
||||
Use this macro for each function you want to override
|
||||
**/
|
||||
DECL_FUNCTION(int, FSOpenFile, FSClient *pClient, FSCmdBlock *pCmd, const char *path, const char *mode, int *handle, int error) {
|
||||
int result = real_FSOpenFile(pClient, pCmd, path, mode, handle, error);
|
||||
if (sLogFSOpen) {
|
||||
DEBUG_FUNCTION_LINE_INFO("FSOpenFile called for folder %s! Result %d", path, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
This tells the loader which functions from which library (.rpl) should be replaced with which function from this file.
|
||||
The list of possible libraries can be found in the wiki. (In general it's WUPS_LOADER_LIBRARY_ + the name of the RPL in caps lock)
|
||||
|
||||
WUPS_MUST_REPLACE(FUNCTION_NAME_IN_THIS_FILE, NAME_OF_LIB_WHICH_CONTAINS_THIS_FUNCTION, NAME_OF_FUNCTION_TO_OVERRIDE)
|
||||
|
||||
Define this for each function you want to override.
|
||||
**/
|
||||
WUPS_MUST_REPLACE(FSOpenFile, WUPS_LOADER_LIBRARY_COREINIT, FSOpenFile);
|
36
plugins/example_plugin_cpp/src/utils/logger.c
Normal file
36
plugins/example_plugin_cpp/src/utils/logger.c
Normal 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
plugins/example_plugin_cpp/src/utils/logger.h
Normal file
74
plugins/example_plugin_cpp/src/utils/logger.h
Normal 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 "ExamplePlugin"
|
||||
|
||||
#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
|
Loading…
Reference in New Issue
Block a user