Skip to content

MegaBonk

Platform ID com.vedinad.megabonk

DigitalHeaven.Mods.MegaBonk Unity IL2CPP is a BepInEx 6 mod that brings DigitalHeaven skin replacement to MegaBonk.

Mod loaderBepInEx 6 (IL2CPP)
Game versionIL2CPP (default Steam build)
Rendering pipelineBuilt-in (MK.Toon shader)
Mod managerr2modman (recommended)

This mod depends on the DigitalHeaven.Unity library for model loading, rig setup, and material creation. MegaBonk is single-player — no multiplayer features apply.

FeatureStatus
OverlayUnstable
Avatar replacementYes
Character props and hatsWIP
Spring bonesWIP
Spring collidersUntested
Eye look and blinkIdle

Unlike the pose-mirroring approach used by most mods, MegaBonk integrates with the game’s native skin system:

  1. DH avatars are loaded from pallets and registered as additional skins in MegaBonk’s character select screen
  2. Unbuilt DH skins show the game model on hover; clicking confirms and builds the avatar
  3. The mod swaps the renderer and material state, fits the avatar to the original character’s height, and restores the game model when returning to a game skin

When starting a run, equipped DH skins apply after the game’s SetCharacter finishes assigning the stock mesh and bones. This is a method-completion hook, not a timed delay. Equipped skins bypass the preview’s click gate. Character-select tiles show DH skins alphabetically first, followed by stock skins in their original order; sorting uses a separate UI list so saved skin indices are not shuffled.

Transparent shader lookup checks the loaded shader inventory as well as Shader.Find, since some shaders bundled with the game are visible only in the inventory. When the default Transparent/Diffuse shader is absent, the adapter tries the loaded Transparent/VertexLit shader. The fallback preserves albedo color, texture scale and offset, and emission and culling when the selected shader exposes those properties. Shader presence alone does not guarantee that every lit variant survived build stripping; use the configurable shader name to select a verified alternative if needed.

The stock Animator stays active with its original controller while its renderers are hidden. Runtime humanoid Avatars map the stock skeleton and the DH rig, and a shared pose mirror transfers animation in LateUpdate. The stock rigs map no jaw, so the avatar’s Jaw is kept out of the transfer and stays closed. Height fitting compares head-to-feet landmarks in world space, so hair and accessories do not change the scale. The primary body renderer’s world bounds are the fallback when no head mapping is available.

Both skeletons temporarily use a T-pose when their humanoid Avatars are built, then restore their live transforms. This gives A-pose game rigs and T-pose DH rigs the same animation reference.

The stock skeleton is mapped from its shape, not its bone names (HumanoidTopology in DigitalHeaven.Core). The game’s rigs name the same joint Elbow.L, Arm.L or Forearm.L, and the head Head or Neck, so no name table covers them all.

  • Hips is the body renderer’s root bone. An armature node with a single child is skipped.
  • Legs are the left and right chains off the hips: upper leg, lower leg, foot, then optional toes.
  • Chest is the shallowest center bone above the hips with a left and a right child. The spine is the path from the hips to it. One bone maps to Spine, two to Spine and Chest, and three or more add UpperChest.
  • Head is the chest’s center chain (a head or neck name wins over a cape or tail). A single bone is the head. A longer chain maps a neck and then the bone named head, or the second bone when none is named. With no such name, a center chain that carries the chest’s numbering on (Rigify’s spine.004 after spine.003) wins, and its last numbered bone is the head; ULTRAKILL’s V1 needs this.
  • Arms are the chest’s side chains. A bone named hand, wrist or palm (MegaBonk’s Wirst included) fixes the hand. The bone before it is the lower arm, the one before that the upper arm, and one more is the shoulder (clavicle). Without such a name, the last bone is the hand after any trailing finger bones are dropped.
  • Side comes from the name (.L, _R, Left, a lone L token or an ArmL-style suffix). Position decides only for a group of siblings where no name carries a side. In root space, the sibling farthest toward −X becomes left and the one farthest toward +X becomes right (Unity characters face +Z), and every other sibling stays center. A spine or head that sways, or a rig that stands slightly off-axis like FoxWizard, therefore never turns into a limb.
  • _end leaves never join a chain. Neither does the hat, nor a transform that itself holds a component (a staff, a sword, a revolver) and that the body is not skinned to. The check reads the transform’s own components, never its subtree’s, so a hat hung below Neck cannot take Neck or Torso with it. A branch ends a chain, so a hand holding a prop is still the hand.

Fingers, toes, a chest bone and a shoulder are optional and never fatal. Only a missing required bone (hips, spine, head, and the upper arm, lower arm, hand, upper leg, lower leg and foot of each side) keeps the game model. The log line then lists the missing bones, the root bone, the size of the body’s bones array and every bone that was found. It also lists the inputs: how many transforms the body is skinned to, which transforms were treated as attachments, and which sides came from position. StockBoneMappings entries pin a bone before inference fills the rest. An entry that names no humanoid bone, or a transform name that is not unique, is skipped with a warning.

DH entries bypass the game’s SetSkin material loop because synthetic skins do not have the game’s material-array layout. The mod tracks body/accessory materials and the outline while a DH skin is active. Requested shaders are checked for support; unavailable requested and Standard shaders fall back to a captured game material. Game-shader conversion reads the DH-built material back through DigitalHeaven.Unity’s shared MaterialReadback, then remaps it to MK.Toon’s own properties and initializes MK.Toon’s texture keywords. The readback covers the albedo map, color, emission, culling and alpha surface.

Objects hung off the stock character stay where the game put them in its hierarchy and are never reparented, so the game keeps its references and its own active toggles. The mod finds them when a DH skin is applied: any child of the stock skeleton that is not a skinning bone or a skin-bound mesh, and that carries a component. It always includes the game’s hat transform. A DH skin changes no prop’s active state, so a prop is shown exactly when the game shows it. While a DH skin is shown:

  • Bone attachments, such as Sir Oofie’s Sword, CL4NK’s revolvers or the hat, follow a DH bone every frame after the pose mirror runs. The DH bone matches the nearest humanoid-mapped stock ancestor; the hat always uses the head. The rotation between the stock and DH bone frames is calibrated once from the first mirrored pose. The offset’s translation is scaled by the fitted avatar height over the stock height, which is about 1 after a successful fit. The prop keeps its own size.
  • Root attachments, such as Calcium’s Skateboard, SkateKickFx and RollingSfx, share the DH avatar’s root and are not moved. They stay visible because the mod hides only the stock body.
  • At the end of every frame each moved attachment returns to its stock pose, so game code and objects the game clones never see the DH-driven pose. If the game or its Animator writes a new local pose, the mod follows that pose from then on.
  • Restoring the stock skin puts every attachment back on its stock local pose. Attachments the game tracks for status effects keep those effects on a DH skin.

Several characters carry their prop as part of the body mesh, skinned to a hand bone, so hiding the body hides the prop. FoxWizard’s staff and book, Robinette’s bow and the Ninja’s sword are drawn this way. FoxWizard’s prefab also contains separate Staff, Book, StaffFlipped and BookFlipped objects, but they ship inactive and nothing in the game activates them: FlipAnimationFox.FlipHandhelds would toggle them, and its only callers are animation events that no clip carries. They stay inactive under a DH skin too.

With Props on, the mod keeps these props by cutting the stock body mesh (the shared SkinnedMeshRegion in DigitalHeaven.Unity, whose mesh reads go through the IL2CPP platform’s pointer icalls):

  1. The mesh splits into pieces: triangles that share a corner, or corners at the same position, belong to one piece.
  2. A piece is a hand piece when every influence of every vertex lands on one hand bone or the bones below it.
  3. A hand piece with a twin of the same vertex count on the other hand is the character’s own hand or glove (such as the paired hand pieces of Sir Oofie and CL4NK) and stays hidden. Every other hand piece is a held prop and is kept.

The kept triangles draw from a cut copy of the stock mesh with the stock materials, on a renderer under the DH instance. Each bone that copy uses is a proxy that follows the matching DH bone, calibrated like a bone attachment, so a held prop sits in the DH hand rather than in the hidden stock hand.

KeepStockParts keeps chosen parts of the stock character drawn over the DH avatar. Each Character=Part entry names a character and either a stock renderer or a bone:

  • A renderer name keeps that stock renderer whole. It stays on the stock skeleton.
  • A bone is a humanoid name (Hips, Spine, LeftHand) or a stock bone name from the [StockRig] lines. A character’s bones together keep the body triangles weighted entirely to them. Those triangles follow the DH bones through the same proxies as held props, so the part sits on the DH body instead of the hidden stock one.

The default, Bush=Hips;Bush=Spine, makes Bush wear its bush. Bush’s bush, leaf cards and eyes are skinned to Hips and Torso only (Torso is Bush’s Spine), while its arms and legs are separate pieces on the limb bones and stay hidden.

[Skins]
KeepStockParts = Bush=Hips;Bush=Spine

An avatar’s dh.springBone chains (tails, hair, bells) run on the same DigitalHeavenSpringBone solver as every other Unity mod, with the rates and limits DigitalHeaven.Core resolves for the engine. The game has no dynamic bone system of its own.

  • Clone rebinding. Under IL2CPP, Instantiate copies an injected component but none of its managed fields, so a cloned chain has no bones and default rates. When a DH skin is applied, Il2CppSpringBones.BindClone (shared with BONELAB) copies every chain’s settings from the built avatar onto its clone and maps the chain’s bones into the clone by sibling index, the same way the humanoid rig is mapped.
  • Colliders. A clone’s chains keep the colliders they list: BindClone maps each collider’s bone into the clone the way it maps the chain’s, and every tick pushes the chain out of them (see Unity: spring bones). The turntable spin and a run’s turns are where a tail meets the hips and legs. Not yet checked in the game.
  • Frame order. The mod steps the chains itself, through the shared SpringChainDriver, right after the pose mirror writes the DH skeleton and before props follow their bones. The chains’ own LateUpdate is off, because Unity does not order it against the mirror. Every 120 frames the driver logs how far the furthest bone stood from its animated pose.
  • Stylized frame rate. MegaBonk’s character clips are stepped: they are sampled at 45 to 60 Hz, but each pose holds for about four samples and then snaps to the next within one sample, so bodies animate at roughly 11 to 15 poses per second. No script steps the Animator; the steps are in the clips. With UpdateMode = MatchGame, the chains take a new pose only on frames where the stock limbs do, and keep their previous pose in between. The physics still integrates every frame underneath, so a chain whose anchor keeps moving does not swing harder than it would in Smooth. A stock pose counts as new when any upper or lower arm or leg bone changes its local rotation. Spine and hips are left out because game code may turn them independently of the clip.
  • Root motion damping. The chains simulate in world space, so a spin on the character select turntable would whip tails and bells hard. Each frame, before the chains integrate, the mod carries their particles along with part of the avatar root’s own turn and travel. The carried share is 1 - RootRotationInfluence of the turn and 1 - RootTranslationInfluence of the travel, so that part of the root’s motion adds no inertia. Animation inside the rig still swings the chains in full. Travel stays at 1, so running, jumping and landing swing the chains as before. At a steady run a chain trails by an amount that grows with speed. Lower RootTranslationInfluence if a very fast build streams the chains out flat.
  • Menu and run turns. The turn settings come in two sets. The Menu set applies to the character select display and the Run set to the player in a run. The mod tells them apart by whether the renderer has a PlayerMovement, which only the run’s player does. The turntable spins smoothly, so the menu keeps an influence of 0.3: a spin swings a chain with 30% of its world-space inertia and lags it a little. A run snaps the character’s facing. Any lag there shows as jitter, most of all in MatchGame: a held pose rides the body rigidly and each new pose drops the chain back to its lag. So the run’s influence is 0, and the chain turns with the body on the same frame.
  • Follow-through. RootRotationKick brings back a reaction after the turn without lagging the chain during it. The chain’s current positions ride the carried turn in full. Its previous positions ride slightly less, so the solver reads the gap as velocity along the turn, and the chain swings on past the body and settles. The gap is scaled by the chain’s damping. At kick k, a chain under damping alone would coast k of the turn past rest, whether it is loose or heavily damped. The pull back toward the pose shortens that. Only the first quarter turn of a single frame counts, because a larger one-frame snap is a facing change rather than a sweep, and a half turn has no preferred direction. A reversal therefore kicks like a quarter turn. The run default of 0.25 swings a tail roughly 12° to 18° past a quarter turn or a reversal, peaking 50 to 200 ms later. During a steady turn, the chain leads the body by about as much as the same influence would make it lag. Kick acts only on the turn the influence carries, so it does nothing at influence 1.

Config file: BepInEx/config/DigitalHeaven.Mods.MegaBonk.cfg

SettingSectionDefaultDescription
Enabled[General]trueEnable or disable the mod
UseGameShader[Rendering]trueReplace DH shaders with MK.Toon for visual consistency
Outline[Materials]falseEnable game outlines on DH avatars; restart after changing
TransparentShader[Materials]Legacy Shaders/Transparent/DiffuseShader used for transparent DH materials instead of MK.Toon, whose transparent variants the game does not ship; empty keeps MK.Toon. LogOutput.log lists the build’s shaders under [ShaderInventory]
Mappings[Skins]""Character-to-barcode skin mappings (see below)
Props[Skins]trueShow character props on DH avatars, following the matching DH bones: separate props and props modeled into the body (see Props Modeled Into the Body). The hat always follows. Takes effect when a character is next loaded
KeepStockParts[Skins]Bush=Hips;Bush=SpineCharacter=Part entries that keep stock renderers or bone regions drawn over a DH avatar (see Keeping Stock Parts). Takes effect when a character is next loaded
Enabled[EyeLook]trueLet avatars look around and blink on their own. The game’s own look targets are followed either way. Read every frame
Enabled[SpringBones]trueSimulate DH spring bones. Takes effect when a character is next loaded
UpdateMode[SpringBones]MatchGameMatchGame gives spring bones a new pose only when the game’s stepped character animation does. Smooth poses them every frame. The overlay’s Config window switches it live with Smooth Spring Bones and saves the choice. See Spring Bones
MenuRootRotationInfluence[SpringBones]0.3How much turning on the character select turntable swings spring bones as lag, from 0 (the chains turn with the body) to 1 (full world physics). Read every frame. See Spring Bones
MenuRootRotationKick[SpringBones]0How far spring bones follow through past a turn on the turntable, as a share of the turn. Read every frame
RunRootRotationInfluence[SpringBones]0MenuRootRotationInfluence for the player in a run. Read every frame
RunRootRotationKick[SpringBones]0.25MenuRootRotationKick for the player in a run. Read every frame
RootTranslationInfluence[SpringBones]1How much the character’s own travel swings its spring bones, from 0 to 1 as above. Read every frame
StockBoneMappings[Animation]""Optional bone overrides, such as Head=CharacterHead;Hips=Pelvis
ReferencedBlendShapesOnly[Performance]trueImport only the blend shapes an avatar references (the shapes its dh.renderers weight, rig visemes and eyelids, and the shapes the mouth resolution could use). See Blend shape import; restart after changing

Avatars are built on first use, on the main thread, and the game waits for the build to finish. LogOutput.log reports the total as Built DH avatar '<barcode>' in <n>ms. The per-step timing summary (Import timing summary) goes to Unity’s Player.log (%USERPROFILE%\AppData\LocalLow\Ved\Megabonk\Player.log).

DH outlines are off by default. Converted materials stay on the game’s + Outline MK.Toon shader with the outline size set to zero and a clear outline color, and DH instances do not receive the game’s Outline component. The plain MK.Toon shaders are present in the build but their lit variants are stripped, so switching to them renders a skinned body ambient-only. Setting Outline = true restores the outline width and component after restarting. Stock character outlines are unchanged.

Mappings are semicolon-separated Character=barcode pairs. A barcode is the full pallet.id:path/to/asset identifier. The same barcode can be mapped to multiple characters.

[Skins]
Mappings = Fox=io.example.skin:avatar.dh-avatar;Cat=io.example.skin:avatar.dh-avatar

Valid character names: Fox, Cat, Frog, Moose, Pigeon, Shark, Gorilla, Bear, Rhino, Bee

  • No skin icons — DH skins appear as text-only entries in the character select
  • Spring bones are unverified in game — chain binding, frame order and the MatchGame cadence are logged under [Spring], but have not yet had an in-game visual check
  • Character rig coverage — the stock rigs of Fox, Calcium, Sir Oofie, Megachad, Ogre, CL4NK, Robinette, Monke, Bush, Noelle, Amog and Ninja are covered by unit tests built from their logged hierarchies. A rig the topology rules cannot read keeps the game model and names what is missing. StockBoneMappings can fill the gap.
  • Runtime support — native humanoid marshaling supports Unity 2023.2 and 2021.3 on 64-bit runtimes (see IL2CPP humanoid avatars)
  • Rendering verification — shader support, texture readback, and fitted height are logged; changes still need an in-game visual check

[MaterialShader] records shader availability and support. [MaterialTexture] records the selected property, texture identity, and immediate name/ID readback; verified=True means the ID binding retained the texture. [MaterialState:prefab] and [MaterialState:applied] list all renderer slots and texture properties, including slots that are not exposed through mainTexture.

[AvatarFit] records stock height, avatar height before and after fitting, scale factor, and measurement method in world space. These are anatomical landmark heights, not the full mesh AABB. [StockRig] lists bone names and parents, then the inferred mapping (mapped by topology: Hips='Hips' Spine='Torso' ...). [HumanoidAvatar] reports native avatar validation; [PoseMirror] reports handler setup and 120 transferred frames, including retained stock Animator, measured hand motion and whether the jaw is held (with how far the transfer turned it). [Props] lists each attachment found, its stock bone and DH bone, the height ratio, and every restore. It also lists which stock renderers were hidden and which attachment renderers were kept, with each one’s prior enabled state. On an attachment’s second followed frame, after first follow records its active state, layer, world position against the DH bone, and lossy scale. It also records each renderer’s type, enabled and visible flags, mesh, materials, shader and bounds. A later change to the active state, the enabled renderer count or a zero scale is logged as visibility changed. When the game writes an attachment’s pose, the line gives the old and new local pose. An attachment the game keeps inactive logs left inactive, as the game keeps it. For the body mesh, [Props] logs every hand piece with its vertex count, hand and bone, and whether it was kept as a held prop or hidden as a mirrored hand; KeepStockParts lines name the kept renderers, the kept bones and the vertex count they keep; and draws <n> of <m> stock body vertices lists which DH bone each used stock bone follows. [Spring] lists each chain bound on an applied avatar (bone count, rates, limit and tick rate), the update mode, the context (menu or run), and the root rotation influence and kick and translation influence in effect. After 120 stepped frames it reports how many brought a new stock pose, as poses per second against the frame rate. The report is written in both modes, so it also measures the game’s own stepping. Over the first 120 frames in which the avatar root turns at all, a second report gives the mean and largest per-frame turn, how many turns were snaps of 30° or more, and how many landed on a held stock pose. It tells whether the character sweeps or snaps its facing. A binding or stepping failure is logged there too and leaves the avatar in place without springs. [Skin] records DH application or restoration, and [SetSkin:after] records the primary renderer after the native DH skin loop has been bypassed.

Developers can launch with the process environment variable DH_MEGABONK_ANIMATION_PROBE=1 to run synthetic humanoid assignment, A-pose retarget and transform-restoration checks, followed by Fox and Calcium preview tests. It enters character selection through game methods, applies the installed Taidum variants when available, exercises ForceMoving, and restores the stock model. It does not use cursor input. Set DH_MEGABONK_PROBE_QUIT=1 to exit after the preview sequence, with a 120-second timeout. -batchmode -nographics can verify rig behavior but cannot verify shader support or appearance.

DH_MEGABONK_RUN_PROBE=1 drives Fox selection and run entry through game methods, verifies that UI rebuilds preserve skin order and saved selection, then checks that the DH mesh survives player setup. Add DH_MEGABONK_PROBE_SAVED=1 to exercise an already saved skin without clicking. DH_MEGABONK_LIFECYCLE_PROBE=1 enables renderer setup/destruction traces, including surviving objects several frames after destruction. These probes launch a real run; back up saves before testing. Use -nosound for unattended runs.

For visual evidence, launch normally with DH_MEGABONK_CAPTURE_DIR set to an absolute output directory. The run probe saves character-select and in-run PNGs plus 60 frames sampled at roughly 10 FPS for a short clip. Headless or batch-mode captures are not visual acceptance evidence. None of these probes use desktop cursor input.

The mod project lives at Platforms/DigitalHeaven.Mods.MegaBonk/ and is included in the main DigitalHeaven.sln solution under the Platforms folder.

  • MegaBonk installed via Steam
  • BepInEx 6 IL2CPP installed (via r2modman or manual install)
  • The game must have been launched at least once with BepInEx to generate the interop/ assemblies

Copy DigitalHeaven.Mods.MegaBonk.csproj.user.example and remove the .example extension. This file configures your local paths and is git-ignored:

DigitalHeaven.Mods.MegaBonk.csproj.user
<Project>
<PropertyGroup>
<MegaBonkDir>C:\Program Files (x86)\Steam\steamapps\common\Megabonk</MegaBonkDir>
<BepInExFolder>C:\Users\mltn\AppData\Roaming\r2modmanPlus-local\Megabonk\profiles\Default\BepInEx</BepInExFolder>
</PropertyGroup>
</Project>

The project references unhollowed game assemblies from $(BepInExFolder)\interop\ and BepInEx framework via NuGet. After building, a post-build target automatically deploys the mod and its dependencies to $(BepInExFolder)\plugins\DigitalHeaven\.

The project targets net6.0 (BepInEx 6 IL2CPP uses CoreCLR) and references DigitalHeaven.Core, DigitalHeaven.Unity, DigitalHeaven.Overlay, and DigitalHeaven.Unity.Overlay as project dependencies.

MegaBonk is an IL2CPP game, which introduces constraints not present in Mono games:

  • MonoBehaviour registration: Custom MonoBehaviours must be registered with ClassInjector.RegisterTypeInIl2Cpp<T>() before use. This includes DigitalHeavenAvatar, DigitalHeavenRig and DigitalHeavenSpringBone from the DH Unity library.
  • Cloned components: Instantiate copies an injected component without its managed fields. The mod re-adds the rig on each clone and copies spring bone settings onto the cloned chains.
  • GC prevention: IL2CPP’s garbage collector can collect managed wrappers for Unity objects. The mod pins all created ScriptableObject and GameObject references.
  • Collection types: Game-side collections use Il2CppSystem.Collections.Generic.List<T> instead of System.Collections.Generic.List<T>.