Minecraft Forge for the Wii (WIP)
- Channel scripting, custom GUI, more..
Kuribo is a Wii Channel and standalone binary (for use in ROM hacks).
Kuribo loads mods from the mods
folder on your SD card, allowing drag-and-drop installation.
- .kxe: Kuribo executable
- Supports any compiler: GCC, Clang, and CodeWarrior.
- Supports compression, encryption, linking across mods.
- Supports embedded romfs
- .kmk: Kamek executables (legacy support)
- Only works with CodeWarrior (ANSI C/C++98)
This is for MKW PAL:
- Grab the loader cheat code here.
- Grab the PAL kernel here. Alternatively build the project with cmake.
- Place this in
Kuribo!/System/KuriboKernel.bin
in your extracted ISO. TheKuribo!
folder should be on the same level as theRace
folder - (Steps for riivolution): Alternatively use [this](here, placing a .gct containing the loader cheatcode in a "Kuribo!" folder on your SD card named RMCP01.gct. (You still need
sd://Kuribo!/System/KuriboKernel.bin
)
- Place this in
- Place mods (.kxe files) in the Kuribo!/Mods folder
... ├───hbm │ ├───.svn ├───Kuribo! │ ├───Mods │ └───System ├───Race ...
Gecko codes are run through Kuribo's GeckoJIT engine. GeckoJIT is the fastest code handler, by a considerable margin:
Averaged across a minute of data (3600 samples). Tested on the first quarter of the FKW .gct for PAL MKW. This was necessary to support the USB Gecko codehandler, which has an extremely limited hard restriction on code length. The source code of the instrumentation code can be found here. A cheat code version is available here, although its measurements will be a bit biased (in favor of the codehandler), as the cache will be primed when the test occurs (as it is itself a code).
- .gct: Standard binary format
- .txt: Text version of codes. Kuribo can convert these to a GCT for you.
Here is an example Kuribo module. (C++)
// Make sure to add the /sdk/ folder to your include path
#include "kuribo_sdk.h"
KURIBO_MODULE_BEGIN("DemoModule", "riidefi", "Beta")
{
KURIBO_EXECUTE_ON_LOAD { OSReport("Loading DemoModule\n"); }
KURIBO_EXECUTE_ON_UNLOAD { OSReport("Unloading DemoModule!\n"); }
}
KURIBO_MODULE_END();
- Compile your .cpp files:
g++ DemoModule.cpp -o DemoModule.elf -IKuribo/sdk
- Build a .kxe file:
KuriboConverter.exe DemoModule.elf DemoModule.kxe
- You're done! Add to your mods folder and boot Kuribo.
When we launch the game, we see:
[OSREPORT]: ~~~~~~~~~~~~~~~~~~~~~~~
[OSREPORT]: [KURIBO] Loading module
[OSREPORT]: Name: DemoModule
[OSREPORT]: Author: riidefi
[OSREPORT]: Version: Beta
[OSREPORT]:
[OSREPORT]: Built: Dec 11 2020 at 13:27:54
[OSREPORT]: Compiler: GCC 10.2.0
[OSREPORT]: ~~~~~~~~~~~~~~~~~~~~~~~
[OSREPORT]: Loading DemoModule!
Between our MODULE_BEGIN and MODULE_END block, we have the following APIs:
- KURIBO_PATCH_B(addr, value)
- KURIBO_PATCH_BL(addr, value)
- KURIBO_PATCH_32(addr, value)
Example:
#include "kuribo_sdk.h"
static void MyGetBMGID(u32 /*track_id*/) {
return 0x245C;
}
KURIBO_MODULE_BEGIN("DemoModule", "riidefi", "Beta")
{
KURIBO_EXECUTE_ON_LOAD { OSReport("Loading DemoModule\n"); }
KURIBO_EXECUTE_ON_UNLOAD { OSReport("Unloading DemoModule!\n"); }
KURIBO_PATCH_B(0x80833668, MyGetBMGID);
}
KURIBO_MODULE_END();
When compiling as C++11, we can also use the following form:
#include "kuribo_sdk.h"
KURIBO_MODULE_BEGIN("DemoModule", "riidefi", "Beta")
{
KURIBO_EXECUTE_ON_LOAD { OSReport("Loading DemoModule\n"); }
KURIBO_EXECUTE_ON_UNLOAD { OSReport("Unloading DemoModule!\n"); }
kBranch(0x80833668, { return 0x245C; });
}
KURIBO_MODULE_END();
By using KURIBO_EXPORT, functions from one module can be made available to others.
KURIBO_EXPORT(MyFunction);
For example, you could put all your shared logic in MyLibrary.kxe
and have two codes MyItemRain.kxe
and My200cc.kxe
both use MyLibrary.kxe
The following code accesses the GeckoJIT API:
KURIBO_EXECUTE_ON_LOAD {
static char my_heap[1024];
static const u32 my_code[2] = {
// Officially cancel THP
0x04552C28, 0x60000000
};
kxCompiledFunction my_func = kxGeckoJitCompileCodes(
my_heap, sizeof(my_heap),
my_code, sizeof(my_code)
);
if (my_func != nullptr) {
// NOTE: We call this code once. Many codes need to be ran
// every frame.
my_func();
} else {
OSReport("Failed to compile my_func :{\n");
}
}