All Projects
MegaAPI

MegaAPI

C#IL2CPPMelonLoaderReverse EngineeringModding
View on GitHub

Mik is a fast-paced first-person platformer on Steam — wall running, dashing, vaulting, precision movement, the whole package. It was built in Unity 6000 and ships with IL2CPP, which means the entire C# game logic gets compiled down to native machine code. There's no Assembly-CSharp.dll to open in dnSpy. There's no managed bytecode to decompile. You're working against a native binary.

MegaAPI is a modding framework built on top of that game — giving modders a clean, event-driven C# API to hook into Mik's internals without ever touching the game's source code.


The IL2CPP Problem

When Unity exports a game with IL2CPP, the build pipeline translates every C# class and method into C++ source, then compiles that into a platform-native binary — on Windows, that's a GameAssembly.dll. What ships with the game is not managed .NET code. It's compiled x86-64 machine instructions with no symbolic metadata beyond what IDA or similar tools can recover.

This is a fundamental problem for modding. The C# class names, method names, and field names that existed at development time are stripped or mangled. What you're left with is a binary full of functions named things like sub_1403A2D80 until you figure out what they actually do.


Reversing with IDA

The process of building MegaAPI started with loading GameAssembly.dll into IDA Pro. IL2CPP does leave some recoverable metadata though — Unity ships a global-metadata.dat file alongside the game binary that contains string tables, type information, and method indexes. With the right IDA plugin (commonly Il2CppDumper or similar), you can feed this metadata back into IDA to restore class names, method names, and field offsets across the binary.

Once the metadata is applied, IDA populates the function list with names like PlayerMovement$$OnJump, PlayerMenu$$Die, PlayerExtraMovement$$SetWallRunTiltEnabled — the actual game logic, now readable. From there it's a matter of reading the decompiled pseudocode to understand what arguments each method takes, what it returns, and how game state flows between components.

This analysis identified the key classes MegaAPI is built around:

  • PlayerMovement — movement state: speed, gravity, noclip, grounded, jumping, slopes, wall running, checkpoints, FOV, sensitivity
  • PlayerExtraMovement — extended movement: wall run tilt, wall jumping
  • PlayerMenu — game state management: pause, resume, die, restart, back to menu, crosshair, audio
  • SoundManager — every player audio trigger: jump, dash, vault, double jump, death, zoom

Each of these maps directly to a Harmony-patchable method in the recovered binary, which is what MegaAPI hooks into.


MelonLoader & Il2CppInterop

Injecting managed C# code into an IL2CPP game requires a bridge. MegaAPI uses MelonLoader (specifically nightly build 0.7.2-ci.2385) which handles injecting a .NET runtime into the game process and providing Il2CppInterop — the layer that lets you call IL2CPP-compiled game methods from managed C# as if they were regular .NET objects.

Il2CppInterop generates proxy types from the recovered metadata. So instead of calling raw function pointers, you can write:

using Il2Cpp;

player.Base.Jump();
player.Base.SetNoClip(true);
player.Base.FOV = 90f;

These are real method calls routed through interop thunks into the native GameAssembly.dll. To the caller they look like normal C#. Under the hood they're marshalling arguments into the IL2CPP ABI and executing native code.


The Player Wrapper

The centerpiece of MegaAPI is the Player class — a managed C# wrapper around the IL2CPP PlayerMovement component, built from what was recovered from IDA. Every property and method on it corresponds to a field or method found in the reversed binary.

public class Player : IWrapper<PlayerMovement>
{
    public float FOV
    {
        get => Base.FOV;
        set => Base.FOV = value;
    }

    public bool IsWallRunning => PlayerExtraMovement.isWallRunning;
    public bool IsDead => Base.dead;

    public void Kill(bool withMessage = true) => PlayerMenu.Die(withMessage);
    public void ForceJump() => Base.Jump();
    public void ShakeCamera(float velocity) => SoundManager.HandleCameraShake(velocity);
}

The full Player surface covers movement state reads, physics overrides (speed, jump force, gravity), game state controls, audio triggers, and camera controls — all of it discovered through the IDA analysis of GameAssembly.dll.

One important design note: properties like MaxSpeedGround, MaxSpeedAir, Speed, and JumpForce all flip Console.Instance.Cheats = true when set. This was discovered through IDA — the game itself tracks a cheat flag on the console component, and writing to certain physics values is the same thing the game's internal debug console does.


The Event System

MegaAPI exposes a custom event system styled similarly to EXILED — static event handlers with typed EventArgs, all firing before the underlying game action executes, giving mods the ability to cancel or modify behavior.

Each event is backed by a HarmonyLib [HarmonyPrefix] patch on the recovered game method. For example, the jump event:

[HarmonyPatch(typeof(PlayerMovement), nameof(PlayerMovement.OnJump))]
public class OnPlayerJumpingEvent
{
    [HarmonyPrefix]
    private static bool Prefix(PlayerMovement __instance)
    {
        PlayerJumpingEventArgs ev = new();
        PlayerEventsHandler.OnPlayerJumping(ev);
        return ev.IsAllowed;
    }
}

Returning false from a Harmony prefix cancels the original method. So setting ev.IsAllowed = false in a subscriber fully blocks the jump — the game method never runs.

The full current event list covers every major player action:

Event Fires Before
PlayerJumping PlayerMovement.OnJump
PlayerDashing Dash logic
PlayerCrouching StartCrouch
PlayerDying PlayerMenu.Die
PlayerEndingLevel Level completion
PlayerReachingCheckpoint Checkpoint save
PlayerChangingFov FOV update
PlayerNoClipping Noclip toggle
PlayerOpeningMenu Menu open
PlayerSpawning Spawn finalization

Custom Commands

MegaAPI auto-discovers and registers any class implementing ICommand at startup via reflection — scanning every loaded assembly for types that implement the interface and have a parameterless constructor:

public interface ICommand
{
    string Name { get; }
    string Description { get; }
    string[] Aliases { get; }
    bool Execute(string[] arguments, out string response);
}

Any mod that ships a class implementing ICommand will have it picked up automatically when MegaAPI initializes — no manual registration step required.


Setup

The game's IL2CPP-generated assembly stubs are required to compile against. These are produced by MelonLoader when it first runs on the game — it generates a MelonLoader/Il2CppAssemblies/ folder containing the interop proxies for every class in the game.

  1. Install MelonLoader nightly 0.7.2-ci.2385 into your Mik installation
  2. Run the game once to generate the Il2Cpp assembly proxies
  3. Reference Assembly-CSharp.dll (the generated proxy, not a real managed DLL) from your mod project
  4. Build against MegaAPI and implement MelonMod or subscribe to events via PlayerEventsHandler