Skip to content

MiracleLoader 1.4.0: Transubstantiation (redirect)

Choose a tag to compare

@Hronosin Hronosin released this 03 Oct 13:01

Transubstantiation: RGCT can now replace one call inside a game method, right where the method makes it, at no cost per call. Mods for 1.3 work as they are.

rgct.target("net.minecraft.client.renderer.LevelRenderer")
    .method("extractSectionDrawGroups")
    .redirect(ChunkSectionLayer::values, Layers::cached);
  • Free. The call becomes an invokedynamic site, bound once to the replacement. There's no context object, no boxing and no array, and the JIT inlines it as if the game had written it. This is the tool for hot paths, where intercept hooks would make garbage.
  • Checked by the compiler. The call and the replacement have the same shape (Redirect.Call0..Call9, Do0..Do9), so the replacement has to fit. It may take wider types, or return Object to name a class that moved between versions.
  • Safe in transform(). Writing Player::getName there doesn't load Player. As a mod class loads, RGCT rewrites its redirect lambdas so they are written down by name. This works in Java agent mode too.
  • One mod per call. Two mods redirecting the same call in the same method stop the game with an error naming both. Redirects show up in the startup report and in miracle.lock. A call the method never makes gets a warning, the same way a missing method does.
  • Baking translates them. A redirect of Player::getName becomes one of o.a::c on 1.21.11.
  • Intercepts of methods without arguments no longer allocate an empty array per call.

Checked

  • test.sh: 481 of 481, also with the loader as a Java agent. That includes redirects on the obfuscated fake game and the clash error.
  • Real clients 26.3, 26.2, 26.1.2 and 1.21.11, with Ultra Somnia 0.2. It redirects calls inside the chunk and entity renderers: up to 7 values, with fallbacks per version, translated for 1.21.11.