Fabric mods, converted onto Horizon

A port compiler for Fabric jars: it reads every Mixin and finds the Horizon hook that runs at the same moment, carries the jar's content over, and writes a native bundle that compiles, applies to the game and carries a small JVM so the mod's own Java runs as it is. Measured on the 145 most downloaded Fabric mods for 26.3.

141/145jars read
3,816patch sites
229on a hook
12%of listening sites
13,572methods interpreted
63/229hook handlers running

How a Java patch becomes a running Horizon mod

Read the jarfabric.mod.json, every mixin config, and every class file: constant pool, methods, annotations and bytecode.
Find each site@Mixin targets, then @Inject/@Redirect/@Modify*/@Overwrite with the method and @At they patch.
Match the momentA listening hook stands in for @Inject at HEAD/RETURN/TAIL. A call-site patch needs a hook that replaces the call — reported, never guessed.
Emit a bundlehorizon-mixin.toml with one injection per hook, a helper per injection naming the Java handler, and a runtime crate holding the jar's classes.
Run the JavaThe bundle's interpreter runs the mod's own methods; each call into the game it can't answer becomes a bridge with a name.

It runs the mod's own Java — and a real JVM agrees

The interpreter (fabric/vm.rs) executes decoded bytecode: strings, boxes, maths, collections with iterators, Optional, exceptions, Kotlin's intrinsics, and lambdas. Before trusting it, every method it ran with default arguments was put to java (Temurin 25) through a reflection harness and compared.

307methods both could run
307same answer
0different

Across the whole corpus the interpreter ran 13,572 of 36,993 methods it tried (37%), and 63 of 229 converted hook handlers ran start to finish with no game at all. The rest stop at the game, and say where:

What stops a converted handler: the game bridge, ranked

  • net/minecraft/client/Minecraft#getInstance()Lnet/minecraft/client/Minecraft;428
  • java/util/function/Supplier#get()Ljava/lang/Object;109
  • java/util/Collections#emptyList()Ljava/util/List;106
  • net/fabricmc/loader/api/FabricLoader#getInstance()Lnet/fabricmc/loader/api/FabricLoader;101
  • net/minecraft/world/level/block/state/BlockState#getValue(Lnet/minecraft/world/level/block/state/properties/Property;)Ljava/lang/Comparable;67
  • net/neoforged/neoforge/common/ModConfigSpec$DoubleValue#get()Ljava/lang/Object;67
  • net/minecraft/core/BlockPos#getX()I63
  • new net/minecraft/world/level/biome/MobSpawnSettings$Builder63
  • com/teamresourceful/resourcefullib/common/registry/RegistryEntry#get()Ljava/lang/Object;53
  • mod/crend/libbamboo/opt/ConfigStore#config()Ljava/lang/Object;47

The hooks the corpus lands on

  • net_from_server74
  • hud34
  • tick15
  • client_level_load9
  • screen_init_post9
  • block_changed8
  • client_start8
  • frame8
  • screen_opening8
  • player_logged_in6
  • render_needs6
  • client_disconnecting5
  • key5
  • client_stopping4

Run it

cargo run -p horizon-port-pack -- \
  fabric mod.jar out/mod

# out/mod/port.json    every site, hook and bridge
# out/mod/PORT.md      the verdict as a page
# out/mod/carry/       the content mod
# out/mod/native/      the bundle + runtime crate

horizon-mixins apply --workspace . \
  --mods out/mod --out /tmp/modded

horizon-port-pack fabric-run out/mod \
  pkg/Class method 3 "arg"

What Horizon is missing: moments

  • net/minecraft/world/level/chunk/PalettedContainer#<init> @RETURN6
  • net/minecraft/world/level/chunk/PalettedContainer#<init> @TAIL6
  • net/minecraft/client/gui/components/debug/DebugScreenEntries#<clinit> @RETURN5
  • net/minecraft/client/renderer/texture/TextureAtlas#upload @RETURN5
  • com/mojang/blaze3d/platform/Window#<init> @TAIL4
  • net/minecraft/client/Options#load @HEAD4
  • net/minecraft/client/gui/GuiGraphicsExtractor#blitSprite @HEAD4
  • net/minecraft/client/renderer/GameRenderer#renderLevel @HEAD4
  • net/minecraft/client/renderer/fog/FogRenderer#setupFog @RETURN4
  • net/minecraft/world/entity/ai/Brain#<init> @RETURN4

What Horizon is missing: call sites

  • net/minecraft/world/level/Level#getEntities @INVOKE (redirect)12
  • org/apache/commons/lang3/Validate#inclusiveBetween @INVOKE (redirect)12
  • net/minecraft/client/gui/Gui#extractRenderState @INVOKE8
  • net/minecraft/client/renderer/GameRenderer#render @INVOKE8
  • net/minecraft/core/BlockPos#above @OVERWRITE8
  • net/minecraft/core/BlockPos#below @OVERWRITE8
  • net/minecraft/core/BlockPos#east @OVERWRITE8
  • net/minecraft/core/BlockPos#north @OVERWRITE8
  • net/minecraft/core/BlockPos#south @OVERWRITE8
  • net/minecraft/core/BlockPos#west @OVERWRITE8

Every mod, converted as far as it goes

Coverage is the share of a mod's listening patch sites that found a hook. Performance mods come out Doesn’t run on purpose: their patches replace a renderer or an allocator, which Horizon has its own of.

ModVerdictSitesListening On a hookCoverage
HighlighterhighlighterPartly311
100%
Pick Up NotifierpickupnotifierPartly311
100%
Xaero's World MapxaeroworldmapPartly281818
100%
Xaero's MinimapxaerominimapPartly392823
82%
BiomesOPlentybiomesoplentyPartly332
67%
ResourcifyresourcifyPartly532
67%
Simple Voice ChatvoicechatPartly1185
62%
AppleSkinappleskinPartly10106
60%
TCDCommons APItcdcommonsPartly1053
60%
EnchantmentDescriptionsenchdescPartly421
50%
EnhancedVisualsenhancedvisualsPartly621
50%
Gamma UtilsgammautilsPartly763
50%
IxerisixerisPartly821
50%
Presence FootstepspresencefootstepsPartly321
50%
Veinminer Clientveinminer_clientPartly221
50%
Sound Physics Remasteredsound_physics_remasteredPartly1694
44%
Explorer's CompassexplorerscompassPartly552
40%
Nature's CompassnaturescompassPartly552
40%
JourneymapjourneymapPartly35207
35%
Shoulder Surfing ReloadedshouldersurfingPartly46269
35%
ControlifycontrolifyPartly673010
33%
Crash Assistantcrash_assistantPartly762
33%
NuitnuitPartly731
33%
SkyboxifyskyboxifyPartly1131
33%
Roughly Enough ItemsroughlyenoughitemsPartly11103
30%
Inventory Profiles NextinventoryprofilesnextPartly37318
26%
Falling LeavesfallingleavesPartly1282
25%
LitematicalitematicaPartly50398
21%
Replay ModreplaymodPartly89449
20%
Shulker Box TooltipshulkerboxtooltipPartly16102
20%
Chat Headschat_headsDoesn’t run49214
19%
Distant HorizonsdistanthorizonsDoesn’t run24214
19%
DebugifydebugifyDoesn’t run62163
19%
Not Enough CrashesnotenoughcrashesDoesn’t run18112
18%
LambDynamicLightslambdynlightsDoesn’t run19132
15%
XaeroPlusxaeroplusDoesn’t run1637311
15%
BobbybobbyDoesn’t run32203
15%
ScalableLuxscalableluxDoesn’t run1971
14%
Smooth ScrollingsmoothscrollDoesn’t run2971
14%
WaystoneswaystonesDoesn’t run871
14%
ImmediatelyFastimmediatelyfastDoesn’t run34152
13%
ImmediatelyFastimmediatelyfastDoesn’t run33152
13%
SoundssoundsDoesn’t run38293
10%
BetterF3betterf3Doesn’t run14101
10%
Traveler's BackpacktravelersbackpackDoesn’t run25222
9%
FreecamfreecamDoesn’t run37343
9%
Carry OncarryonDoesn’t run15121
8%
NotEnoughAnimationsnotenoughanimationsDoesn’t run15131
8%
IrisirisDoesn’t run23914411
8%
LootrlootrDoesn’t run32161
6%
PolytonepolytoneDoesn’t run106644
6%
Sodium Extrasodium-extraDoesn’t run67483
6%
Friends&FoesfriendsandfoesDoesn’t run33171
6%
No Chat ReportsnochatreportsDoesn’t run35342
6%
ModernFixmodernfixDoesn’t run129533
6%
IMBlockerimblockerDoesn’t run107975
5%
SodiumsodiumDoesn’t run94482
4%
SodiumsodiumDoesn’t run101512
4%
LithiumlithiumDoesn’t run4191384
3%
LithiumlithiumDoesn’t run4171404
3%
Subtle Effectssubtle_effectsDoesn’t run147481
2%
Advancement PlaquesadvancementplaquesWorks000
0%
Alternate Currentalternate-currentDoesn’t run850
0%
AttributeFixattributefixDoesn’t run000
0%
BadOptimizationsbadoptimizationsDoesn’t run1190
0%
Better AdvancementsbetteradvancementsDoesn’t run100
0%
Better Mount HUDbettermounthudDoesn’t run500
0%
Better NetherbetternetherDoesn’t run32270
0%
Better Statistics ScreenbetterstatsWorks000
0%
Boat Item ViewboativiewDoesn’t run100
0%
Concurrent Chunk Management Enginec2meDoesn’t run000
0%
CapescapesDoesn’t run540
0%
ChatAnimationchatanimationDoesn’t run840
0%
Cherished WorldscherishedworldsDoesn’t run950
0%
ChunkychunkyDoesn’t run400
0%
ClumpsclumpsDoesn’t run960
0%
ContinuitycontinuityDoesn’t run1460
0%
ControllingcontrollingDoesn’t run100
0%
CustomSkinLoader Bootstrapcustomskinloader-bootstrapDoesn’t run000
0%
Cut ThroughcutthroughDoesn’t run300
0%
Cubes Without BorderscwbDoesn’t run1840
0%
Default OptionsdefaultoptionsDoesn’t run540
0%
Drippy Loading ScreendrippyloadingscreenDoesn’t run28140
0%
Durability TooltipdurabilitytooltipDoesn’t run000
0%
Dynamic FPSdynamic_fpsDoesn’t run110
0%
Dynamic CrosshairdynamiccrosshairDoesn’t run100
0%
e4mce4mcDoesn’t run3080
0%
Easy AnvilseasyanvilsDoesn’t run200
0%
Easy MagiceasymagicDoesn’t run220
0%
EntityCullingentitycullingDoesn’t run440
0%
EntityCullingentitycullingDoesn’t run440
0%
Fabric APIfabric-apiDoesn’t run000
0%
FabrishotfabrishotDoesn’t run410
0%
FallingTreefallingtreeDoesn’t run330
0%
Farmer's DelightfarmersdelightDoesn’t run26170
0%
Fast IP PingfastippingDoesn’t run100
0%
FastQuitfastquitDoesn’t run25120
0%
FerriteCoreferritecoreDoesn’t run1890
0%
FerriteCoreferritecoreDoesn’t run1890
0%
FirstPersonfirstpersonDoesn’t run19170
0%
Global PacksglobalpacksDoesn’t run410
0%
InvMoveinvmoveDoesn’t run320
0%
Just Enough CharactersjecharactersDoesn’t run110
0%
KryptonkryptonDoesn’t run1120
0%
Language ReloadlanguagereloadDoesn’t run22130
0%
Leaves Be GoneleavesbegoneDoesn’t run960
0%
LetMeDespawnletmedespawnDoesn’t run1480
0%
Make Bubbles Popmake_bubbles_popDoesn’t run1470
0%
Mod MenumodmenuDoesn’t run400
0%
More Chat HistorymorechathistoryDoesn’t run100
0%
Mouse TweaksmousetweaksDoesn’t run000
0%
Trekmr_trekWorks000
0%
NetherPortalFixnetherportalfixWorks000
0%
OptiGUIoptiguiDoesn’t run760
0%
Packet FixerpacketfixerDoesn’t run3120
0%
Paginated AdvancementspaginatedadvancementsDoesn’t run100
0%
Particle Coreparticle_coreDoesn’t run1740
0%
Particle RainparticlerainDoesn’t run1680
0%
Ping WheelpingwheelDoesn’t run200
0%
Reese's Sodium Optionsreeses-sodium-optionsDoesn’t run110
0%
Repurposed Structuresrepurposed_structuresDoesn’t run19100
0%
Right Click HarvestrightclickharvestWorks000
0%
Remove Reloading ScreenrrlsDoesn’t run4260
0%
ServerCoreservercoreDoesn’t run64180
0%
3d-Skin-Layersskinlayers3dDoesn’t run12100
0%
sparksparkDoesn’t run000
0%
Sodium Shadowy Path BlockssspbDoesn’t run400
0%
Towns and Towerst_and_tWorks000
0%
TectonictectonicDoesn’t run1160
0%
TerralithterralithWorks000
0%
Tom's Simple Storage Modtoms_storageWorks000
0%
VeinminerveinminerDoesn’t run110
0%
Veinminer Enchantmentveinminer_enchantmentDoesn’t run000
0%
Villager NamesvillagernamesDoesn’t run210
0%
VisualityvisualityDoesn’t run550
0%
Visual WorkbenchvisualworkbenchWorks000
0%
Very Many PlayersvmpDoesn’t run52150
0%
WaveyCapeswaveycapesDoesn’t run330
0%
Yeetus ExperimentusyeetusexperimentusDoesn’t run300
0%
YOSBRyosbrDoesn’t run000
0%
ZoomifyzoomifyDoesn’t run400
0%