A Fabric mod for Minecraft 26.2 holding compatibility fixes between mods that do not know about each other. Each feature is gated on the mods it bridges and is inert without them.
| Feature | Needs | What it does |
|---|---|---|
| Figura in ReplayMod | Figura + ReplayMod | Makes Figura avatars survive into recordings, playback and video exports |
| Figura chat heads | Figura + Chatting | Draws the Figura avatar's face in Chatting's chat heads instead of the vanilla skin |
| Lootr fast item frames | Lootr + Fast Item Frames | Converts Lootr item-frame entities into blocks while preserving per-player loot |
| Underground Village fixes | Underground Village 2.1.1 | Repairs obsolete/absent-mod loot tables and worldgen structure/pool data defects |
| Additional Lanterns chunk loading | Additional Lanterns 1.1.2 | Prevents redstone neighbor checks from synchronously loading unloaded chunks |
| Mob Filter worldgen safety and dimension context | Mob Filter | Prevents C2ME worldgen deadlock on rejected mobs and provides dimension context for worldgen rules |
| Visual Workbench tag rebinding | Visual Workbench + Puzzles Lib | Prevents replay loading and tag reload crashes from stale Visual Workbench tags |
| Incendium tick optimization | Incendium Legacy 5.5.0, 5.5.1 | Removes a redundant 20 Hz entity-ID scan and throttles living-mob initialization |
| Gravestones death inscription and glow | Gravestones | Suppresses technical death grave text and renders a glowing outline only on your own graves |
| Jade nameplates and Custom Name | Client Jade; server TAB name sync | Suppresses vanilla in-world entity/player nameplates and shows server-synced player display names in Jade |
| Custom Name multi-word names | Custom Name 0.4.4-26.2 | Permits spaces in nickname, prefix, and suffix commands for non-operators |
| Virtual Resource & Datapack Patches | MVS, MNS, Formations Overworld, Grim Kingdoms, Pyrite, Easter's Delight, Better Lib | Transparently repairs malformed pack.mcmeta formats and POI tags at runtime |
| Wilder Wild stone pool | Wilder Wild 4.2.11-mc26.2 or 4.3 | Keeps the mesoglea stone pool inside C2ME's safe worldgen read/write radius |
| Bee and spawner structure DFU validation | Exact Trek and Stoneholm fixtures | Verifies repaired bee inventories and zombie spawner payloads survive structure loading |
| Boat water-mask compatibility | EMF 3.3.5, 3.3.8 or 3.3.11 + audited boat providers | Restores the vanilla water mask for plain hulls when the selected Fresh Animations mask is incompatible |
| Better Lib demo villager suppression | Better Lib | Suppresses hardcoded demo villager registration that causes RemapException registry sync disconnects |
| Beautiful item-model reloads | Beautiful Enchanted Books 6.0.0 and/or Beautiful Potions 2.0.1 | Clears stale extra-model keys so each resource reload uses the keys registered for that reload |
| IllagerBlabber voice registry | IllagerBlabber 1.1.0 | Releases per-illager voice state on unload, follows illagers across dimensions, and drops per-tick lock and log overhead |
For Plasmo Voice 2.1.16, a client-only compatibility hook requests microphone capture stop and UDP disconnection before Plasmo unregisters its listeners and unloads add-ons. The upstream UDP close method also shuts down its Netty event loop. This addresses the surviving non-daemon voice threads reported in the Minecraft shutdown watchdog crash. Other Plasmo versions and clients without Plasmo skip the hook; servers do not load it.
The fix uses upstream cleanup APIs, preserves capture-stop event cancellation, and logs cleanup exceptions while allowing remaining cleanup and upstream shutdown to proceed. It does not forcibly terminate threads or wait on them from the render thread.
Verified with unit tests and an isolated Fabric client using the exact installed Plasmo JAR: the mixin applied, an idle capture thread and started UDP event loop terminated, and the client exited normally. Full-pack multiplayer microphone use, add-on interaction, and disconnect/reconnect testing remain pending. See verification evidence. Upstream report: plasmoapp/plasmo-voice#539.
Beautiful Enchanted Books 6.0.0 and Beautiful Potions 2.0.1 keep their Fabric extra-model
keys in a static REGISTERED_MODELS map. Each resource reload creates new keys, while
putIfAbsent leaves the map pointing at keys from the earlier reload. Model resolution then asks
for a key that the current ModelManager does not know and receives null.
The client-only mixins clear that map at the start of each mod's exact
initialize(Set, ModelLoadingPlugin.Context) overload. Each mixin has an independent gate requiring
the matching mod ID, exact metadata version, and full installed-JAR SHA-256. Missing, unreadable,
multi-path, or changed artifacts leave only that target's mixin disabled.
Exact-artifact isolated client probes reproduce and repair the reload failure. Without the override, the initial load resolved all 695 book and 828 potion keys, then a resource reload resolved none of them. With the override, two successive reloads resolved all 695 and 828 keys. A resource-pack check removed the selected Sharpness and Swiftness extra models as expected, and removing that pack restored all keys. Blocking all matching models cleared both maps to zero, then restoration repopulated them. Controlled item-resolver checks preserved the custom book/potion particle sprites after reload and restoration. Both mixins appeared in the client log and both clients exited normally.
The resolver uses synthetic stacks without world registry synchronization. Full-pack behavior and visible inventory rendering remain unverified. See reload compatibility evidence, the probe runner, and recorded probe data.
IllagerBlabber 1.1.0 keeps every illager's voice state in static ConcurrentHashMaps on
IllagerVoiceRegistry, keyed by entity UUID, and never removes it. Each IllagerVoiceManager holds
its AbstractIllager, so every pillager, vindicator and evoker that ever ticked stays reachable until
the server stops. After a dimension change the new copy (same UUID) keeps using the manager that
holds the removed old copy, so its lines are voiced at the old position. Every tick, each illager
also interns its UUID string, locks on it and writes a tick marker whose "already processed" guard can
never fire, and new managers log at INFO.
On the server, Lampas2 Overrides takes over IllagerVoiceRegistry.updateIllager at HEAD. It reuses a
manager only when that manager holds this exact entity instance. Otherwise it clears the UUID's
per-entity state and creates a manager for the current instance, then runs the same manager update
and state update as upstream, without the intern, lock or tick marker. On entity unload the UUID's
state is cleared only if the unloading instance still owns it, so a newer same-UUID copy keeps its
state. All registry maps are cleared when a server stops. The per-illager INFO logs are demoted to
DEBUG.
The fix is common-side and runs on dedicated and integrated servers. It applies only when the
installed mod is exactly illagerblabber 1.1.0 with the audited JAR SHA-256; otherwise it logs a
warning naming the installed version and stays disabled. It changes only in-memory state, so it is
safe to add or remove on an existing world. IllagerBlabber is optional and is never bundled.
A disposable dedicated-server probe with 200 pillagers showed 200 managers and 200 dead pillagers
still reachable after the kill without the fix, and 0 of each with it. After a real Nether portal
crossing, the old copy stayed reachable without the fix and was released with it. Vanilla briefly
keeps entities removed during a tick in EntityTickList's last snapshot; the probe forces one
mid-tick removal before counting so that vanilla retention is not mistaken for the leak. Audible
playback position on a client and long-uptime heap behaviour on the live server remain unverified.
See the probe runner and recorded probe data.
The inspected Mob Filter 0.28.1+26.2 artifact has two major defects during world generation:
-
Unsafe
Entity.removeworldgen discard (deadlock): When rejecting disallowed mobs fromWorldGenRegion#addFreshEntity, Mob Filter callsEntity.remove(DISCARDED)before returningfalse. During threaded C2ME worldgen, that removal can enterLivingEntitydismount collision resolution, ask Lithium for a chunk, and synchronously join the server thread while the same chunk is still waiting for its C2MEFEATURESstage:Mob Filter rejection -> Entity.remove -> dismount collision search -> Lithium getChunk -> server thread -> same C2ME generation future -> deadlockLampas2 Overrides suppresses only that
Entity.remove(...)call inside Mob Filter'sWorldGenRegion_addFreshEntitycallback. Mob Filter still performs its complete rule evaluation and its existingCallbackInfoReturnable#setReturnValue(false), so rejected worldgen mobs remain absent. TheServerLevel_addFreshEntitycallback is deliberately untouched; normal server-thread rejections retain their ordinary removal behavior. -
Missing worldgen dimension context: Mob Filter's
WorldgenThreadSpawnAttemptcannot resolve the dimension on its own, returningnullfromgetDimensionId(). ItsDimensionChecktreatsnullas matching every dimension rule. Consequently, dimension-specific rules (such as disabling mob spawning in a custom dimension likelampas:aria) match all worldgen spawns across every dimension, silently wiping out Overworld village villagers, iron golems, and cats during structure placement.Lampas2 Overrides wraps
WorldGenRegion_addFreshEntityto capture the region level's dimension (worldGenRegion.getLevel().dimension().identifier()) in a thread-local context (WorldgenDimensionContext), and injects intoWorldgenThreadSpawnAttempt#getDimensionIdto return that scoped dimension. This allows dimension-restricted rules to evaluate against the actual dimension being generated without leaking across threads or tasks.
These common-side mixins activate whenever Mob Filter is present, without checking its version. Their
compile-time and bytecode contract is pinned to Modrinth version EDuF1CWZ (0.28.1+26.2). Other
Mob Filter versions also activate, but have not been inspected or tested against this contract. C2ME,
Lithium, and Chunky are not activation requirements: Chunky exposed the issue through aggressive
generation, but the unsafe side effects belong to Mob Filter's worldgen logic. Both mixins keep a hard
require = 1 contract, so startup fails if an installed version changes a call site.
A disposable dedicated-server probe with 0.28.1+26.2 verified that Overworld structure mobs are
admitted, Aria worldgen mobs are vetoed, and rejecting a zombie nautilus carrying a drowned avoids
removal on both the main thread and a worker thread. It also verified dimension-context restoration,
ordinary server-level discard, and startup without Mob Filter. The prior JAR reproduced the incorrect
Overworld rejection in the same fixture. Full-pack C2ME pregeneration and production recovery remain
unverified until the new JAR is deployed and the affected generation path is exercised.
This integration comprises two independent client features:
When Jade is installed, entity and player identification is handled through Jade's HUD tooltip rather than floating vanilla world nameplates:
- Suppresses vanilla in-world nameplate rendering: Wraps and suppresses
SubmitNodeCollector#submitNameTagcalls insideEntityRenderer#submitNameDisplay. This hides floating player usernames, custom-named mobs, named pets, armor-stand nameplates, below-name scoreboard objective text, and Figura entity nameplates, while allowing surrounding method lifecycles (such as Figura'sNameplateRenderContext.begin/end) to execute cleanly. - Preserves render-state extraction and data queries: Render-state properties (
state.nameTag,state.scoreText,state.nameTagAttachment) and entity data methods (getName(),getCustomName(),getDisplayName(),hasCustomName()) remain fully populated, allowing Jade and other mods to inspect them normally. - Genuine
TextDisplayentities remain visible: Content rendered viaDisplayRenderer.TextDisplayRendererdoes not rely on entity nameplates and continues to render uninterrupted. - Fail-safe: When Jade is not installed, the mixin is disabled and vanilla nameplates render normally.
Jade resolves player titles using the server-synced TAB display name. Custom Name runs on the server; the client bridge needs only Jade and the standard player-info packet:
- Data flow:
Custom Name (server) ↓ (ClientboundPlayerInfoUpdatePacket.UPDATE_DISPLAY_NAME) PlayerInfo.tabListDisplayName (client) ↓ JadeCustomNameResolver (Lampas2 Overrides) ↓ Jade ObjectNameProvider#getEntityName - Transparent fallback: If a player has no custom display name or
PlayerInfois missing, the resolver falls back immediately to vanillaEntity#getDisplayName(). Unnamed and custom-named mobs, villagers, and item entities follow Jade's standard logic. - Custom Name configuration: Custom Name's optional floating above-head labels use fake clientbound
TextDisplaypassengers rather than vanilla nameplates. Keepdisplay_above_player.enabled = false(the default) ineclipsescustomname.jsonso Jade handles all entity identity presentation.
In Custom Name 0.4.4-26.2, CustomNameUtil#playerNameArgumentToComponent passes operatorsBypassRestrictions
directly as the spaceAllowed parameter to nameArgumentToComponent. When a player without operator permissions
executes /name nickname, /name prefix, or /name suffix, spaceAllowed evaluates to false. The underlying
component parser silently truncates the argument at the first ASCII space character:
/name nickname The Administrator -> silently sets nickname to "The"
/name prefix [Admin] The Boss -> silently sets prefix to "[Admin]"
Lampas2 Overrides applies a server-safe, common mixin to CustomNameUtil that sets spaceAllowed = true for
playerNameArgumentToComponent. This allows non-operator players to set multi-word nicknames, prefixes, and suffixes
while keeping name length limits, regex validation, and blacklist enforcement fully active.
The mixin is common-side (runs on both dedicated servers and clients) and is version-gated to Custom Name 0.4.4-26.2.
Gravestones normally renders an inscription on technical player death graves showing the owner's name, death date, and death time.
Lampas2 Overrides implements a client-only override whenever Gravestones is present:
- Technical/death graves render no text at all:
TechnicalGravestoneBlockEntityRenderer#getSignTextreturns a blankSignText, eliminating in-world text inscriptions. - Your own graves receive a vanilla-style glowing outline: local player ownership is determined
during
extractRenderStateand attached to the render state. DuringAbstractGravestoneBlockEntityRenderer#submit, an outline pass for the grave's block model is submitted usingRenderTypes.outline(TextureAtlas.LOCATION_BLOCKS). - Other players' graves render with no outline and no inscription.
- Aesthetic/decorative gravestones remain untouched, keeping their custom text and normal rendering.
- Player skulls/heads on the grave remain untouched, honoring Gravestones'
SHOW_HEADSconfiguration.
The mixin is client-only and is not restricted to a specific Gravestones version.
Visual Workbench dynamically creates replacement crafting-table blocks and copies the source block's bound tags into them.
Puzzles Lib's BlockConversionHelper.copyBoundTags assumes a target block's tags are either empty or
identical. ReplayMod playback and repeated client configuration reloads trigger client tag updates
in the same process, leaving the generated target block with stale tags and causing Puzzles Lib to throw
IllegalStateException.
Lampas2 Overrides intercepts BlockConversionHelper.copyBoundTags and rebinds the tags when the target
block belongs to the visualworkbench namespace. Puzzles Lib's strict invariant remains untouched for
all other targets and callers. The mixin is client-only and gated on both visualworkbench and
puzzleslib.
Incendium Legacy 5.5.0 and 5.5.1 scan every living non-player entity each tick to repair missing or invalid entity IDs, even though the same clock initializes previously unseen mobs. Lampas2 Overrides installs an always-enabled built-in datapack that removes that redundant scan and runs only the unseen living-mob initialization pass every five ticks (4 Hz). Existing ticking mobs, frozen-state updates, particles, player logic, altar items, and short-lived projectile initialization remain at 20 Hz.
The pack also makes the 15-bit ID rollover safe without relying on the removed validation pass. It resets before assigning 32768, immediately reassigns every existing player and initialized mob, and then assigns the entity that triggered the rollover exactly once.
This feature fails closed using explicit version profiles:
- Incendium 5.5.0: registers
incendium_5_5_0_optimizationswhen verified against 5.5.0's exact SHA-256 fingerprints. - Incendium 5.5.1: registers
incendium_5_5_1_optimizationswhen verified against 5.5.1's exact SHA-256 fingerprints. The 5.5.1 optimization semantically rebases on upstream's newentity/chillingcall while removing the redundant ID check.
A modified or unsupported Incendium release is left untouched and produces a warning in the server log instead of receiving potentially stale function overrides.
Wilder Wild 4.2.11-mc26.2 and 4.3 ship identical stone-pool resources with a sampled
radius of 12–15. FrozenLib 2.5.3 and 3.0.1's circular waterlogged vegetation feature adds one
block to the sampled radius before placement, then checks the four horizontal neighbors of
each placed block. At a chunk edge, the upstream maximum reaches two chunks away.
Historical C2ME 0.4.2-alpha.0.43 logs report unsafe worldgen reads from
mesoglea_caves_stone_pool.
The virtual resource patch keeps the feature type, stone ground, depth, vertical range, minimum
radius, and placement unchanged, and changes only xz_radius.max_inclusive from 15 to 14. The
largest sampled radius is then 15 and the four-neighbor checks reach at most 16 blocks, which fits
the active chunk and its one-chunk write radius even at positive, negative, edge, and corner
coordinates. The patch is version and SHA-256 gated; an unknown Wilder Wild release or changed
stone_pool.json remains untouched.
Verification on 4 October 2026 passed all 103 unit tests, exact installed-artifact and fixture checks, and a disposable production-JAR dedicated-server probe with Wilder Wild 4.3 and FrozenLib 3.0.1. The resource mixin applied, the selected stone-pool JSON matched the replacement, and Minecraft decoded its configured-feature radius as 12–14 before normal shutdown. Fresh cave generation with C2ME/Lithium and full-pack gameplay remain unverified.
The former 2.5.3/4.2.11 wind shim was removed for the latest supported FrozenLib 3.0 and Wilder Wild 4.3 pair. An unpatched isolated client showed that FrozenLib now clears its reset flag and Wilder Wild updates the existing cloud extension in place. Worker decoding still changes the wind singleton; no missing-extension failure was observed in this probe. See the wind-state evidence for the scope and remaining gameplay checks.
EMF 3.3.5, 3.3.8 and 3.3.11 can replace Minecraft's shared boat water-patch layer with the Fresh Animations
assets/minecraft/optifine/cem/boat_patch.jem model. That model's animation expects var.base_*
values supplied by Fresh Animations hull models. Plain hulls from the audited Pyrite 0.18.3+26.2,
Promenade 5.6.0, Wilder Wild 4.2.11-mc26.2 or the exact audited 4.3 artifact, BetterEnd 26.201.2, and BetterNether 26.201.2
providers do not supply those values.
The client-only compatibility hook runs at the end of each BoatRenderer construction. It checks
the exact provider layer, provider version, EMF version, selected resource bytes, and EMF's actual
minecraft:optifine/cem/boat_patch.jem root. It replaces the water patch with the vanilla
BoatModel.createWaterPatch() geometry only when the hull root is ordinary vanilla geometry.
Custom EMF hulls or animations, disabled or different resource packs, absent or mismatched versions,
the BetterEnd/BetterNether wover-item companion mismatch, and unlisted boat layers remain
untouched. The explicit provider list and verification limits are recorded in
docs/boat-water-mask.md. The exact EMF profile pairs are recorded in
the focused 3.3.8 evidence and the current-pipeline
probe evidence linked from the feature document.
The isolated probe verifies artifact identities from the audited pipeline inventory:
./tools/boat-water-mask-probe/run.ps1 -Mode baseline -Strict `
-InventoryPath build/pipeline-validation-2026-10-06/inventory.json
./tools/boat-water-mask-probe/run.ps1 -Mode patched -Strict `
-InventoryPath build/pipeline-validation-2026-10-06/inventory.json `
-OverrideArtifactPath build/libs/lampas2-overrides-1.0.0.jarThe runner verifies selected JAR metadata and SHA-256 before creating each fresh fixture, preserves prior run evidence, discovers Biolith through the inventory, and uses fixture-only FrozenLib and shutdown guards. The guards do not affect the installed client. The earlier EMF 3.3.8 isolated validation covers four strict reload stages plus baseline and patched shader-off and shader-on visual runs; see the focused evidence for result, log, input, override, harness, and shader hashes. This evidence does not establish pack staging, deployment, or behavior in the live installed instance. Manual review found rectangular baseline water transparency and continuous candidate water; shader-on logs had nonfatal GTAO option warnings but no invalid-pack or fallback messages. Mounted rowing and turning covered vanilla oak only. Current EMF 3.3.11 coverage is checked separately against the pipeline artifact hashes; earlier visual and movement observations do not establish rendering for this newer artifact.
Additional Lanterns 1.1.2 hooks ServerLevel neighbor updates (updateNeighborsAt and
updateNeighborsAtExceptFromFacing) and inspects each adjacent block to convert powered vanilla
lanterns into Additional Lanterns equivalents.
At chunk boundaries, the inspected position can belong to an unloaded chunk. Level#getBlockState
then synchronously requests that chunk from ServerChunkCache, stalling the server thread.
Lampas2 Overrides cancels Additional Lanterns' VanillaLanternEvents.handleLanternRedstone call
when the target position's chunk is not currently loaded in ServerChunkCache. Loaded chunks retain
the original behavior. The mixin is version-gated to Additional Lanterns 1.1.2.
Underground Village 2.1.1 contains several upstream data bugs:
- Loot table defects: Bundles three Create integration loot tables that hard-reference Create items even when Create is absent, plus a cleric table using the removed
minecraft:set_nbtfunction. Before registry-aware loot validation, this compatibility layer substitutes empty tables for Create-only rooms when Create is absent and upgrades cleric potion functions tominecraft:set_potion. - Worldgen structure & template pool defects:
poi/v4/founten.nbtwas corrupted in commit23b7f51f("Fix Pool") with invalid gzip CRC/ISIZE and malformed NBT tags; repaired using the clean parent structure.poi/v4/sidebed_bedroom.nbtandabandoned_poi/v4/sidebed_bedroom.nbtreference non-existentstoneholm:iron_golm; corrected tostoneholm:iron_golem.poi/v4/tall_bedroom.nbtreferences non-existentstoneholm:villager; corrected tostoneholm:villagers.better_villagers_point_of_interest.jsonandbetter_villagers_abandoned_point_of_interest.jsonreference non-existentstoneholm:addons/better_villager/poi/...(singular); corrected tostoneholm:addons/better_villagers/poi/...(plural).
Worldgen data fixes are packaged in an always-enabled built-in datapack (stoneholm_2_1_1_fixes), version-gated to Underground Village 2.1.1 and protected by SHA-256 fingerprints of all six upstream target resources. Other Stoneholm structures and pools are untouched.
Better Lib 2.1.0 and 2.1.1 scanned bundled JSON villager definitions by opening their own jar as a ZIP
filesystem. Fabric Loader already had that filesystem open, so the second open threw
FileSystemAlreadyExistsException and aborted mod initialization, while subsequent filesystem closure
corrupted Fabric Loader's shared jar filesystem. Additionally, Better Lib's generated data added disabled
demo professions to minecraft:acquirable_job_site.
Better Lib 2.1.2 resolved both issues upstream by checking FileSystems.getFileSystem(uri) first,
only closing filesystems it created itself, and cleaning up its POI tags. The betterlib mixins were
therefore retired in Lampas2 Overrides.
Minecraft 26.2 enforces strict pack format metadata checks via PackMetadataSection and PackFormat.
Several mods bundle data or built-in datapacks with malformed pack.mcmeta files (such as declaring
format ranges without supported_formats, or specifying obsolete maximum format versions like 81 instead of 107)
or malformed JSON files.
Lampas2 Overrides implements a low-overhead runtime virtual patch system (ResourcePatchResolver) that intercepts
mod resource streams. Each patch is strictly version-gated and SHA-256 fingerprinted: if an upstream mod updates
or fixes the bug, the patch fails closed and leaves the upstream resource untouched.
Patched mods and resources:
- Moog's Voyager Structures (MVS 5.0.11 & 5.0.14):
- Defect: Upstream 5.0.11 and 5.0.14 declare
pack_format: 48withoutsupported_formatsor declaremin_format: 48, max_format: 107.1withoutsupported_formats, causing Minecraft 26.2'sPackMetadataSectionparser to reject the pack. - Fix: Virtually replaces
pack.mcmetawith validsupported_formats: [48, 107]andmax_format: [107, 1]. - Note: MVS 5.1.1 fixed this upstream and requires no patch.
- Defect: Upstream 5.0.11 and 5.0.14 declare
- Moog's Nether Structures (MNS 3.0.0):
- Defect: Missing
supported_formatsin rootpack.mcmeta. - Fix: Virtually replaces
pack.mcmetawith validsupported_formats: [48, 107].
- Defect: Missing
- Formations Overworld (1.0.5+a and 1.0.5+c):
- Defect: Version
1.0.5+ais missingsupported_formatsin rootpack.mcmeta, and its structure smithing loot tables (stone_tower/smithing.jsonandwitch_tower/smithing.json) reference pre-26.2minecraft:chaininstead ofminecraft:iron_chain, causingDataResult.Error['Unknown registry key...']loot table parse errors on 26.2. Version1.0.5+cstill needs the root metadata format range; its audited loot tables contain no exactminecraft:chainitem reference. - Fix: Version
1.0.5+avirtually replacespack.mcmetawith validsupported_formats: [48, 107]and replaces both smithing loot tables withminecraft:iron_chain. Version1.0.5+creceives only thepack.mcmetareplacement because its audited loot tables contain no exactminecraft:chainitem reference. - Evidence: Candidate artifact identity and resource hashes are recorded in
docs/evidence/formations-overworld-1.0.5c.json.
- Defect: Version
- Grim Kingdoms Lost Structures Ruins (2.0.3):
- Defect: Missing
supported_formatsin rootpack.mcmeta. - Fix: Virtually replaces
pack.mcmetawith validsupported_formats: [48, 107].
- Defect: Missing
- Pyrite (0.18.3+26.2):
- Defect: All four built-in datapacks (
pyrite_azalea,pyrite_crafting_tables,pyrite_mushrooms, andpyrite_oddities) declaremax_format: 81inpack.mcmeta. In MC 26.2 (which requires format up to 107), Minecraft flags the datapacks as incompatible or fails to load them. - Fix: Replaces
pack.mcmetaacross all 4 built-in packs withsupported_formats: [48, 107]andmax_format: 107.
- Defect: All four built-in datapacks (
- Easter's Delight (1.3.1):
- Defect: Built-in recipe override datapack
resourcepacks/farmersdelight_overrides/pack.mcmetais missingsupported_formats. - Fix: Replaces
pack.mcmetawith validsupported_formats: [48, 107].
- Defect: Built-in recipe override datapack
- Better Lib (2.1.1):
- Defect: Bundles
data/minecraft/tags/point_of_interest_type/acquirable_job_site.jsonprefixed with illegal JSON comments (//{), causing strict JSON parsers to throw exceptions on tag reload. - Fix: Virtually substitutes the clean, comment-free POI tag definition.
- Note: Better Lib 2.1.2 fixed this upstream by replacing the malformed comments with valid JSON.
- Defect: Bundles
Fast Item Frames normally converts vanilla item-frame entities into block entities, but does not
recognize Lootr's custom lootr:item_frame entity. This bridge adds that entity type to the
conversion set and transfers its UUID, reference inventory and opened state into the resulting Fast
Item Frames block entity. The converted frame continues to use Lootr's per-player inventory,
protection, advancement and refresh behavior instead of becoming a shared vanilla item frame.
The common hooks run on the server and the renderer hooks run on the client, so the mod must be installed on both sides when this feature is used. Lootr and Fast Item Frames remain optional; the bridge is not applied unless both are present.
Live testing confirmed conversion, per-player looting and Lootr refresh behavior. Once a player takes their item, the converted frame renders empty for that player; refreshing it through Lootr repopulates it, and its Lootr identity and properties remain intact.
The bridge is compiled against Lootr 1.24.41.124 and Puzzles Lib 26.2.4. Converted frames delegate Lootr's random tick-scheduling offset to their existing per-instance state, so the value remains stable while the frame instance is live.
Chatting draws a chat head from the player's skin texture, so someone wearing a Figura avatar shows
up in chat as their vanilla face rather than the character everyone can see in the world. Figura
already substitutes its avatars for skin faces in the tab list and the permissions screen, through
Avatar#renderPortrait; this extends the same treatment to chat, so a chat head matches the face
Figura draws everywhere else.
The bridge intercepts ChatHeads.draw and its drawFace calls, using the PlayerInfo supplied
for that draw. This covers Chatting's cached texture and skin fallback paths. Shadow and main
face calls share one scope, which ends even if drawing throws. Players without an avatar keep
their skin face.
Activation requires Figura and Chatting. There is no Chatting version or artifact-hash gate. The required draw descriptors were inspected in Chatting 3.2.2; a changed target causes a clear mixin failure at startup. Authenticated avatar rendering still requires a live client check.
Chatting's sender detector is also enhanced with ChatPlayerResolver to associate multi-word,
formatted, or custom TAB display names (e.g. from CustomName or server prefixes such as
The Administrator or [Admin] The Administrator) with their authentic PlayerInfo. Display names
are used strictly to discover the player; the player's real UUID remains the identity for Figura avatar
lookups and permissions.
Chat screenshots pick it up too, since they resolve the head owner the same way.
Figura avatars are fetched from Figura's own backend over a websocket, keyed by player UUID. Nothing about them travels over the Minecraft protocol, so a ReplayMod recording — which is a capture of the packet stream — contains no trace of them. Play such a replay back and the best Figura can do is ask the backend what those players are wearing right now: wrong for anyone who has since changed avatar, and nothing at all for players who went offline, deleted the avatar, or were wearing a local one that was never uploaded.
The same is true of an avatar's state. A toggled animation is a Lua variable its owner flips with
a keybind and broadcasts with pings.setSomething(state); the broadcast goes over the backend, so
without the pings every avatar plays back with every toggle off.
Two further problems only show up when exporting video, and both make avatars look broken rather than absent:
- Figura advances Blockbench animations off the wall clock. An export renders frames at whatever rate the machine manages, not at real time, so animations run at whatever ratio those two happen to differ by — frequently 10× or worse. The same applies, less dramatically, to watching a replay at anything other than 1× speed.
- Figura applies and clears animation transforms in
Minecraft#runTick. ReplayMod's export pipeline drivesMinecraft#tickand the world renderer directly and never entersrunTick, so exported footage shows every avatar frozen in whatever pose it held when rendering started.
| While recording | Watches the tab list and copies each player's avatar into the .mcpr as it is seen. Blobs are keyed by content hash, so players sharing an avatar cost one copy, and a player swapping avatars mid-recording is recorded as a change with a timestamp. Serialisation and archive writes happen off-thread. |
| Script state | Records the pings that carry it. Avatar#runPing is where received pings and the owner's own both land, so recording there captures exactly what the recording client was rendering. |
| While watching | Applies the recorded avatars for the current point in the replay and suppresses Figura's backend fetch for those players, so a recorded avatar cannot be replaced by a current one. Replays play back with no network connection at all. Pings fire as their timestamps pass. |
| Animation timing | Replaces Figura's animation clock with one derived from the replay's own timeline for as long as a replay is open, so animations track playback speed, stop when playback is paused, and advance one video frame at a time during an export. |
| Video export | Drives Figura's animation apply/clear once per exported frame — once per frame, not once per view, so cubic and stereoscopic exports do not advance animations several times over. |
| Post-processing | Carries the data into the files ReplayMod's cut/split pass produces. That pass copies only metadata, markers, mod info and resource packs into its fresh output files, and it runs on most recordings — ReplayMod writes a _RM_START_CUT/_RM_SPLIT pair whenever you stop recording by hand — so without this almost every replay would come out empty. |
| On close | Hands every player it touched back to Figura, restoring the local avatar you had loaded before opening the replay. |
Storage layout inside the .mcpr:
figura/index.json changes as [{time, uuid, hash}], time in ms into the recording
figura/avatars/<hash>.nbt gzipped avatar data, one entry per distinct avatar
figura/pings.bin (time, uuid, pingId, payload) records, in order
A player's first recorded avatar applies from the start of the replay regardless of its timestamp. That timestamp records when the recording client finished downloading the avatar, not when the player put it on, so honouring it literally would leave players briefly vanilla-skinned for reasons that have nothing to do with what was recorded.
- Change timestamps are not remapped across cuts and splits. The data is carried into post-processed replays, but the times in the index still refer to the original recording. Because a player's first avatar applies from the start regardless, this is invisible unless someone changed avatar mid-recording and the replay was cut or split — in which case that switch can land early or late. Remapping properly means reproducing ReplayMod's internal cut/split state machine, which is not worth the risk of putting avatars at confidently wrong times.
- Seeking backwards restarts the avatar scripts. Lua state cannot be rewound, so a backward seek
reloads every avatar and re-runs its pings from the beginning. That is exact below 2000 pings; past
it the oldest are skipped, which is invisible for the usual
pings.setX(state)shape — a later ping overwrites what a skipped one would have set — but can lose state for a ping that flips a value rather than setting it. Ping replay also waits (up to 10s) for scripts to finish loading, since Figura silently drops pings aimed at an unloaded script. - Avatars are not host-mode during playback. Figura decides
isHostfrom the local player UUID, which during a replay is ReplayMod's camera entity. Avatars that gate visuals onhost:isHost()therefore render the way other players saw them, not the way the recorder did. This also means a replayed avatar's script cannot send chat, set the clipboard, or react to keybinds — which is why it has been left as is. client:getSystemTime()still returns real time. Scripts that animate off it drift during an export. OnlyTimeController, which drives Blockbench animations, is switched to the replay clock.
Requires Minecraft 26.2, Fabric Loader 0.19.3+ and Java 25. Each feature additionally needs the
mods it bridges; anything absent simply switches that feature off. Drop the jar
from Releases — or from the build
workflow's artifacts — into your mods folder.
./gradlew build # jar lands in build/libs/
./gradlew runClient # dev client; put figura + replaymod jars in run/mods/ firstNeither Figura nor ReplayMod is a build dependency. The optional Lootr and Fast Item Frames bridge uses compile-only artifacts for Lootr, Fast Item Frames, Puzzles Lib and Fabric API; none are bundled into this mod. See CLAUDE.md for how the bridges are structured and how changes get verified.
The trinkets_updated V1460 schema repair has separate exact profiles for 4.1.0+26.2 and
4.1.1+26.2. The latter's upstream shape differs and still drops modern flat slot inventories and
unrelated Cardinal components during typed round trips. The repair preserves grouped legacy
slots, flat Items/cosmetic slots, unknown data, and sibling components while retaining the
vanilla tail responsible for item migration. It fails closed on version, class-hash, or schema
mismatch. See the repair evidence and verification limits.
Phase 2B validates the exact Trek and Stoneholm runtime fixtures that previously produced bee and spawner decode failures. The complete fixture provenance, hashes, coordinates, and vanilla-reference comparisons are recorded in docs/bee-spawner-dfu-validation.md and docs/evidence/phase2b-bees-spawner.json.
The virtual resource patcher repairs 10 audited Grim Kingdoms structure templates, removing 32 zero-level enchantment entries from their item components. This includes the "way of the fisherman" rods and affected wooden hoes. Minecraft 26.2 requires serialized enchantment levels in 1..255. Positive levels, names, lore, attributes, inventory slots, entities, blocks, and DataVersion remain unchanged; vanilla STRUCTURE DFU still performs schema migration.
Each replacement requires mod ID mr_grim_kingdomsloststructuresruins, version 2.0.3,
and the exact original resource SHA-256. Missing/unreadable or changed originals are not patched.
The source JAR is never modified. Resource hashes and all removed NBT paths are recorded in
docs/evidence/grim-zero-enchantments.json. Reproduce or verify against the audited JAR with
Python and nbtlib==2.0.4:
python tools/repair_grim_zero_enchantments.py <grim-kingdoms-2.0.3.jar>
Add --write to regenerate the replacement assets and evidence. Gradle tests independently
read original and replacement fixtures with Minecraft NbtIo and compare complete NBT after
only the recorded zero-level removals, alongside version/hash/missing-resource gate tests.
Automated tests and packaging are verified; live structure placement remains unverified.
This prevents malformed items in subsequently loaded templates; it does not restore items
already lost from saved chests. Deployment is a separate step.