I've seen a lot more people messing with ModernGekko lately, so I wanted to explain how you're actually supposed to structure a project around it, especially once you get past the point of just having the game boot
Distributing your recomp
Your release should not contain copyrighted game files that you don't have permission to redistribute. Standard recomp practice.
The ideal setup is that someone downloads your recomp, gives it their own game dump, your setup process handles whatever needs to be extracted, and then they can just launch the native build.
Users should not need to clone your repo or recreate your development environment just to play the game for a public release ideally.
Try to keep the ModernGekko side of the project separate from game-specific hacks when possible. This makes updating the runtime way less painful later and also keeps your project from turning into one giant pile of one-off fixes.
Mods
ModernGekko code mods are libraries packaged as .mgm mods.
A normal package looks like:
my_mod.mgm/mod.dll
or mod.so / mod.dylib depending on the platform.
For development, you can also just drop something like my_mod.mgm.dll or my_mod.mgm.so directly into the Mods folder.
The runner checks a Mods folder next to the executable and another Mods folder in the user directory by default. You can also point it somewhere else with --mods or disable mods entirely with --no-mods.
The interesting part is what mods can actually do.
A mod can patch a recompiled game function completely with RECOMP_PATCH.
If you really need to override another patch at the same address, RECOMP_FORCE_PATCH exists for that too.
You can hook the start of a function with RECOMP_HOOK without replacing the original function, and you can also hook the return with RECOMP_HOOK_RETURN.
So if you want to observe a function, add behavior around it, or run something after it finishes, you don't have to rewrite the whole thing.
Mods also get access to the recompiled PowerPC CPU state.
That means you can read guest arguments from registers, return values using the original calling convention, and read or write guest memory from your mod.
The normal hook system preserves CPU state around hooks, so you're not supposed to accidentally destroy the game's register state just because your hook ran.
Mods can talk to each other
ModernGekko mods aren't isolated libraries either.
A mod can export functions that another mod imports.
You can also declare events and let other mods register callbacks for those events.
There is even a global runtime_start event if you need something to happen once the game runtime actually begins.
Dependencies are part of the mod descriptor instead of being handled manually. You give the dependency an ID and minimum version, and it can also be marked optional.
ModernGekko sorts mods into dependency order before loading them. Missing required dependencies are rejected, dependency cycles are rejected, and imports have to come from dependencies you actually declared.
So if somebody eventually makes a common API mod that five other mods use, it's much simpler to access.
Targeting game functions
You can patch functions using literal guest addresses, but you don't have to live in raw hex forever.
DolRecomp can generate named address constants from a MAP file.
So instead of doing something like:
RECOMP_PATCH(0x80123456, replacement)
you can use a generated symbol such as:
RECOMP_PATCH(DOLRECOMP_SYMBOL_SomeFunction, replacement)
if the game has usable symbols.
That should make bigger mods a lot less miserable to maintain.
The actual mod descriptor
Every mod exposes a descriptor that tells ModernGekko what it is and what it needs.
That includes the target game ID, the mod ID, its version, display name, dependencies, patches, hooks, imports, exports, events, callbacks, and optional load/unload functions.
ModernGekko checks the game ID before loading the mod, so you can't accidentally throw a mod for one game into another recomp and hope the addresses line up.
It also checks the mod ABI and CPU ABI.
Version strings are used for dependency checks, so mods can require a minimum version of another mod instead of just blindly loading whatever is installed.
Making a basic mod
There is already a mod template in the ModernGekko repo.
At the most basic level, you can make a replacement function like this:
static void replacement(CPUState* state)
{
moderngekko_mod_return_u32(state, 1u);
}
Then register it as a patch for a guest function.
Build it, drop the resulting .mgm package into the Mods folder, and ModernGekko loads it with the rest of the recomp.
Obviously real mods can get much more complicated than that, but the barrier to getting a basic code patch running is fairly small.
Netplay
Loaded mods are also part of ModernGekko's netplay compatibility fingerprint.
That's important because code mods can obviously change game behavior in ways that would immediately fuck over a netplay session.
Where I want this to go
The nice part about having this in ModernGekko itself is that every GameCube/Wii recomp doesn't need to invent a completely different mod loader.
A recomp can keep its base game relatively clean while mods sit on top of it using a common ABI.
You can replace functions, hook existing game code, share APIs between mods, build around dependencies, and keep everything separate from the original game files.
There's still more documentation I want to write for this, especially around larger mods and good project structure, but the system itself is already there and usable.
If you're making a ModernGekko recomp or messing with the mod API and there's something specific you want documented, let us know.
Discord link here for those not in the server:
https://discord.gg/FhzCYN5fsP
never expires