
Collections Of Optimizations
A optimization mod that mainly targets other mods instead of minecraft. Fixes slow code & bugs in other mods. Everything is properly tested so nothing should break.
Expect reduced memory usage and stutters, faster chunk loading, and improved server and client performance with less bugs and crashes.
Compatibility
Patches only load if the mod they target is installed. There's a mixin config plugin that checks the loading mod list, so having none of these mods installed does nothing at all. Not even load. Absolutely 0 impact.
Tested against 507 mods.
Which mods are touched:
- Structurify
- Block Swap
- Blood Magic
- Animus
- Patchouli
- Just Dire Things
- Goety's Delight
- TerraBlender
- FTB Chunks
- Curios API
- Terramity
- Armageddon
- Born In Chaos
- Bosses Rise
- Marium's Soulslike Weaponry
- Kind Of Nice Weapon
- Punchy
- L2 Hostility
- Immersive Aircraft
- Artifacts
- Oculus
- Nature's Aura
- Echelon - Linggango Variant (Still working on it)
- Integrated API (done, gotta ship the version to the curseforge)
- Elysium API (done, gotta ship the version to the curseforge)
- Caelus API
- Lootr
- Xaero's Minimap
- Xaero's + Waystones Compatibility
- GeckoLib
- Vanilla Minecraft (Item Rendering)
Structurify
The problem is four of it's hooks sit on the chunk generation path and not a single one of them was written like it knew that. Vanilla runs createStructures once for every chunk it generates, and inside that it loops over every structure set in the registry. On a big pack that's a few hundred. So anything Structurify does "per structure set" is really "per structure set, per chunk".
Four things fixed here:
- Every spacing, separation, salt and frequency override funnels through one helper that does
containsKeyand thengeton aTreeMapkeyed by structure set id. Two tree descents of full resource location string compares to fetch one value. And it fires way more than you'd think:getPotentialStructureChunkreads thespacingfield five separate times, Structurify's field hook has no ordinal on it so it fires on all five, separation calls the already hookedspacing()on top of that, plus salt. Eight resolutions, sixteen tree descents, per structure set, per chunk. On a few hundred sets that's tens of thousands of string compares for every chunk. Now it's one hash lookup, and since all eight calls use the same String instance in a row, seven of them get answered by a reference compare. checkStructureis four nestedcomputeIfAbsentcalls on fourConcurrentHashMaps bolted onto the ChunkGenerator. Every one boxes a mixed 64 bit id into aLong, and every lambda captures stuff, the outer one captures nine values, so the lambda object gets allocated before the call even runs. You pay for that on cache hits too, and the call happens once per structure set entry per chunk load. On a miss it also writes four entries that nothing ever removes. And all three checks it drives are off by default, so on a stock config every bit of that exists to produce a value that is always true. Now it returns true at the top and touches nothing. It only takes that shortcut while Structurify's own result map is still empty, so it can't ever disagree with something already cached in there. Heads up though: this one goes inert if you turn onprevent_structure_overlapor the global flatness check, because then the checks genuinely have work to do and there's no way inside their lambdas.- The terrain height cache is a thread local
LinkedHashMapwith access ordering on. Per query that's a key object for the get, a second key object for the put, anIntegerbox for the value, another for the return, a map entry, and a relink of the access order list. All replacing one virtual call. Worse, the key holds the ChunkGenerator, the RandomState and the LevelHeightAccessor, which IS the ServerLevel, up to 16384 of them per worldgen thread. So leaving a dimension doesn't let it go, it just sits there. Now it's oneLong2IntOpenHashMapper thread keyed on position and heightmap type only, with the identity guard held weakly so nothing gets pinned. Zero allocations per query, and the answer can't change becausegetBaseHeightis a pure function of its inputs. - The overlap check builds a
LongOpenHashSetbut declares the variable asSet<Long>, so every add boxes, then it copies out throughIterator<Long>and boxes all over again. TwoLongallocations per section of every piece. Only bites you withprevent_structure_overlapon but it was free to fix.
Tested on 2.0.29.
Block Swap
Block Swap hooks ChunkHolder.broadcastChanges, so the first time a chunk gets broadcast it does a full sweep of every block in it. That's up to 98,304 iterations per chunk, each one allocating a BlockPos and calling Level.getBlockState, which re-resolves the chunk and section for a block whose section is already sitting right there in a local variable.
This filters each section through its block state palette first. If the palette doesn't contain any block you configured, the section can't contain one either, so the 4096 block walk gets skipped. Reads come straight from the section now, and BlockPos only gets allocated when something actually swaps.
Was 10.1% of my server tick. Fattest thing in the whole profile.
Blood Magic
Three things fixed:
- The item routing network.
isConnectedis a depth first search from a node back to the master, and thepathargument it walks with is a pure visited set, it only ever getsaddandcontainscalled on it and never backtracks. Blood Magic hands it aLinkedList, so every singlecontainsis a linear scan over everything visited so far. That turns one search from O(V+E) into O(V*E). Thentickruns that search once for every output node AND once for every input node, so the cost of one routing cycle goes up with roughly the CUBE of how big your network is. And the cycle period ismax(1, 20 - itemCount), so if you've got a stack of 19 or more in the master node's acceleration slot it runs the whole thing every single tick. Now the visited set is an actual set. Same nodes visited in the same order, same answer, because membership is the only thing ever read off that list. - The ARC rebuilding its recipe list every tick.
getARCgets called straight out ofTileAlchemicalReactionChambertick, and the ticker Blood Magic registers has no side check on it, so that's client AND server, every tick, for every ARC you own. Any time the input and tool slots are both filled, which is just "the machine is doing its job", it callsgetAllRecipesFor, and in 1.20.1 that'sList.copyOf(byType(type).values()). A brand new immutable list holding every ARC recipe in the pack, twenty times a second per machine, to be walked once and thrown in the bin. Cached now. Same list, same order, rebuilt when recipes reload. - The ARC's furnace mode. It calls
getRecipeFor(SMELTING, ...)from the tick too, on both sides, every tick. That walks every smelting recipe in the pack callingmatches()until something hits, and with KubeJS scripts and a few hundred mods that's thousands of them. Vanilla furnaces don't do this,AbstractFurnaceBlockEntityholds aRecipeManager.CachedCheckspecifically so the hot path retries last tick's recipe before scanning everything. Now the ARC gets the same thing, built with vanilla's owncreateCheck. This one is NOT strictly identical, in the exact same narrow way vanilla furnaces aren't: if two smelting recipes both match one input it can keep handing back the one it matched last, where a fresh scan might pick the other. Recipe map order is arbitrary either way so neither is more right, and it's already how every furnace in the game behaves.
Both ARC caches invalidate on a shared generation counter that bumps on the reload listener pass and on datapack sync. Had to do it that way because RecipeManager.replaceRecipes mutates the existing manager in place, so checking the manager reference alone would happily keep serving you pre reload recipes.
Animus
The one real problem is on the render thread.
The equivalency sigil draws an outline over every matching block around whatever you're looking at, and it rebuilds that outline from scratch every single frame. SigilEquivalencyRenderer#onRenderLevelStage is a RenderLevelStageEvent handler so it runs once per frame, and any time you're holding the sigil and looking at a matching block it calls findMatchingBlocksInRadius. That method allocates an ArrayList, a HashSet, a LinkedList and four BlockPos offset objects, then breadth first searches up to (radius * 2 + 1) ^ 2 positions doing a getBlockState on each one and shoving a BlockPos into the visited set per position.
At 144 fps with the default radius that's tens of thousands of block state reads a second, plus a BlockPos allocated for every single one of them, to redraw an outline that only changes when you look somewhere else.
Now the fill gets reused while the look target, block, radius and clicked face are all unchanged. Not strictly identical but it's bounded: it still recomputes at least once per game tick, so breaking or placing a block inside the region updates the outline within one tick instead of within one frame. You won't see the difference, it's 50ms worst case.
Patchouli
ItemStackUtil#getBookFromStack has a fast path for Patchouli's own book item, and for anything else it walks every registered book in the pack comparing items. Fine on its own. The problem is who calls it:
BookRightClickHandler#onRenderHUDcalls it once per frame on whatever is in your main hand. Not "when you're holding a book", every frame regardless. Sword, pickaxe, empty hand, doesn't matter.TooltipHandler#onTooltipcalls it once for EACH of your nine hotbar slots, on every frame a tooltip is on screen.
So on a pack like mine with a few dozen guide books, hovering an item in your inventory is nine walks of the whole book list per frame. That's thousands of item comparisons a second plus a values iterator allocated nine times a frame, to answer a question about an item that hasn't changed.
Now it's a per item cache. This one is properly behaviour identical and it's nice why: ItemStack.isSameItem in 1.20.1 is literally stack.is(other.getItem()), the item and nothing else, no NBT. So the result of that loop is a pure function of the stack's item and there is nothing else it could depend on. The ItemModBook fast path reads per stack NBT so I left that completely alone, the cache only covers the fallback loop. Rebuilds if the number of registered books ever changes.
Just Dire Things [Forge]
Its level tick walks every entity in the level and calls getBlockState for each item entity. ServerChunkCache.getChunk only has a four entry cache, and every miss goes through ticket creation and a sorted set binary search, for a plain block read.
Routes the read through getChunkNow instead, which grabs an already loaded chunk without making a ticket. Falls back to the original call if the chunk isn't there.
Was 3.7% of tick.. not that much but still sum.
Punchy
This one was shitting on my 1k fps to about 200 the moment my hands were on screen, worse holding a block, and the reason is dumb.
ItemInHandRendererMixin#isResourcePackItemDefinition asks the resource manager for <namespace>:items/<item>.json. That's the 1.21.4 item definition format. 1.20.1 doesn't have that file. So unless a resource pack ships one, every single call is a guaranteed total miss, and a miss is the most expensive answer there is. FallbackResourceManager#getResourceStack allocates a .mcmeta ResourceLocation and an ArrayList, then asks every pack in that namespace, plus every child pack of every pack, whether it has the file. On a big pack the minecraft namespace has an entry for basically every mod that ships assets, so that's a few hundred pack probes to be told no.
And it's not once. It's armed by PunchyArmRenderer#renderItemInHand calling setForceVanillaDisplay right before every held item gets drawn, so it's once per frame, per hand. Then CreatureBucketAnimator goes and asks for the exact same path again.
Now missing paths get remembered on the MultiPackResourceManager instance and repeats get answered with an empty list, which is already what that method hands back for a namespace no pack provides. Only misses get cached, anything actually there resolves normally like nothing happened. Invalidation is free because createReload builds a whole new manager every time you reload resources, so a cached miss can't ever be read under a different pack set than it was measured under. Capped at 16384 paths.
Funny part is Punchy already knows how to do this. ResourcePackItemTransformResolver runs the same probe and caches both the hit and the miss against the resource manager identity. Two other places just didn't get the memo.
Tested on 2.6.2.
Goety's Delight
The cherry blossom cake handler walks every entity in every level, every tick, and does an NBT lookup on each one. 8.2 seconds of CompoundTag.contains in a 21 minute profile.
Runs the sweep every 4 ticks instead. The punishment it drives fires on 20 tick boundaries so you won't notice.
Was 3.2% of tick.
L2 Hostility
CapabilityEvents#livingTickEvent is subscribed to LivingTickEvent, so it runs for every living entity, every tick, on both sides, and calls getCapability(MobTraitCap.CAPABILITY) on every one of them. But MobTraitCap.HOLDER only ever attaches that capability where getType().is(WHITELIST) or the thing is an Enemy thats not in the blacklist tag. Players, villagers, cows, armour stands, boats, item frames, none of them can ever have it. They all still walk their entire CapabilityDispatcher every tick to get told absent, and on a modpack that dispatcher holds a provider for every mod that hangs anything off entities.
Now the first absent answer gets remembered on the entity and after that it just returns the empty result.
This one is properly behaviour identical and I like why. Forge attaches capabilities exactly once, during AttachCapabilitiesEvent when the entity is built, and theres no API anywhere that adds a provider to an entity later. reviveCaps puts back the providers it already had, it doesnt add new ones. So absent can never turn into present, its not a guess. Only other way an absent answer could lie is if you read it while the caps are invalidated, and that cant happen here because L2H only reaches this call inside its own isAlive() branch. A present answer never gets cached at all, it goes through untouched, so the trait tick path is exactly as it was.
Tested on 2.5.19.
Terrablender
TerraBlender wraps every mod's surface rules in a namespace dispatcher, so a mod's rules only get applied inside that mod's own biomes. W idea, but the dispatch runs per block, per column, the whole time surfaces are being built. Every single call allocates a lambda, allocates an Optional, and does two string keyed map lookups, all to answer a question that depends on nothing except which biome you're in..
Now it resolves that once and caches it against the biome, and reuses it until the biome actually changes. Same rule picked, same fallback when a biome's namespace has no rules, just without redoing the lookup for every block.
Behaviour identical and I checked it properly. I built a version that ran the old lookup and the cached one side by side and counted every time they disagreed. Ten million calls through a full world generation, zero disagreements!
Regarding Terrablender Fix
Could've port it. It goes after the same problem but the main thing it does is overwrite getNamespacedRules and throw namespacing out entirely, running every mod's surface rules in one flat list. Namespacing is the whole reason mod A's rules don't paint mod B's biomes, so that's not a fix, that's a different worldgen. An horrible approach!
FTB Chunks
The minimap render does check whether the minimap is actually enabled, or hidden, or whether you're in F3. Problem is that check sits underneath the work instead of on top of it. So every frame it was binding the minimap texture and setting two filter parameters, and every time I crossed a chunk boundary it rebuilt the entire thing. That's a 15 by 15 loop, 225 region lookups and 225 texture uploads, for a minimap that then immediately doesnt get drawn because it's turned off. I never used it.
Now the check happens before the work rather than after. If the minimap is visible nothing changes at all. If it's hidden, the mod was going to return without drawing anyway, so nothing is lost, and turning it back on just triggers one fresh upload.
Curios API
- Bails out of the per tick handler for entity types that have no curio slots at all. Curios itself already returns an empty capability for those, so this changes nothing, it just skips the capability lookup and a couple of allocations for every living entity every tick.
- Caches that slot lookup on the entity, stamped with a generation counter. Invalidation is exact, it happens on datapack reload and client slot sync, so it can't go stale.
- Answers "you're not wearing that" from a per tick set instead of walking your whole curio inventory every single time.
findEquippedCuriowalks every slot on every call, and mods that gate abilities on a worn curio call it once per item per player per tick. One mod in my pack does it from 54 separate tick handlers, 58 call sites, all firing in the same tick, all asking about a different item. Now the inventory gets walked once per entity per tick and the misses come out of that. Only the misses. If you ARE wearing the thing, the call falls through to Curios untouched, so what comes back is exactly Curios' own answer, this can never make something up. The set is built with the same slot walkfindEquippedCuriouses so a wrong miss isn't possible, and it gets thrown away on Curios' own change event plus rebuilt every tick anyway. One caveat: if a curio somehow changes without firing that event, it can read as missing for the rest of that tick, so an ability could land a tick late. Toggle is there if you ever see that. - Skips the client side curios tick on non players.
- Stops the Curios render layer being attached to non player renderers at all. Artifacts bolts one onto every mob renderer, this removes them at registration instead of testing per layer per entity per frame. Zero cost per frame. Downside is curios worn by mobs and armor stands stop rendering, so turn it off if your pack cares about that.
Curios tick sits at 0.28% of tick with this ON. Before it was around 5%.. 8%.. That number is from before the per tick set was added though, so it doesn't include that one.
Terramity
The held item animation handler copies both of your held item stacks, NBT and all, as the literal first thing it does. Before it checks the tick phase. Before it checks whether you're even holding a GeckoLib item. Player tick fires twice per tick on both sides, so that's four full stack copies per player per tick per side, and on a pack like mine held items are dragging enchantment and GeckoLib NBT around with them. Now it checks the conditions first and skips the whole thing.
The entity animation handler is worse.. It's on the living tick event, so it runs for every living entity in the game, and then it goes through 45 instanceof checks in a row with no else on any of them. Every zombie, every cow, every tick, both sides, ALL 45. All 45 classes it's looking for are Terramity's own entities, so if the entity isn't one of those it can't possibly match. Now it works that out once per entity class, caches it, and bails.
Armageddon
It registers 73 separate player tick listeners, one per procedure class. Every one of them is its own event bus subscriber, so every player tick fans out to all 73, twice, on both sides. They all check the phase and bail, but the dispatch already happened by then.
The actual problem is what 54 of them do once they're in. They call findEquippedCurio to check whether you're wearing one specific item, and that walks every curio slot you have. 58 call sites total, all firing in the same tick, all asking about a different item. So if you're wearing curios you're paying something like 58 full inventory walks per tick just so the mod can find out you're not holding 58 things. That's handled by the Curios patch above, one walk instead of 58.
The other thing is the entity animation handler. Same shape as Terramity's, it's on the living tick event so it runs for every living entity in the game, and it's 30 instanceof checks in a row with no else on any of them. Every mob, every tick, both sides, all 30. All 30 classes are Armageddon's own entities, so anything that isn't one can't match. Now it figures that out once per entity class, caches it, and gets out.
Born In Chaos
This one's interesting because it's genuinely the best built MCreator mod I've looked at, and it still has the worst version of the same problem.. ðŸ˜
Bad part is the entity animation handler. It's on the living tick event so it runs for every living entity in the game, and it's 83 instanceof checks in a row with no else on any of them. 83. Every cow, every zombie, every tick, both sides, all 83, matching nothing. That's a long ass chain of checks.. Fixed.
It also has the exact same held item bug as Terramity, copying both your held stacks with their NBT before checking whether it needs to do anything. Same fix.
Bosses Rise
Not as bad as I expected overall, this one actually uses GeckoLib properly and doesn't have the giant instanceof chain the MCreator mods do. But it has the single worst per tick thingy ever!
There's a procedure that runs every player tick, on both sides, and it asks the game for every single entity in a 32x32x32 box around you. Not filtered as well, the predicate is literally "true".
And then the loop throws away everything that isn't one of four boss mobs. The sort was NEVER EVEN needed.. its just invulnerability shit..
Now the query only asks for that mod's own entities, so the list is empty basically all the time and the stream and the sort cost nothing. Same behaviour, the four bosses it cares about are all in the package being filtered for, and the original predicate still gets applied on top.
Tested on 1.0.9.2b this is due to the newer versions being buggy.
Marium's Soulslike Weaponary
The one I could fix: it hooks the start of every entity tick and calls a helper to read a despawn timer. That helper calls getPersistentData three times, checks whether the key exists, and if it doesn't, writes a zero into it before reading it back. Reading a missing NBT int already gives you zero, so that write does nothing at all except permanently stamp a despawn_timer tag onto every single entity in your world, which then gets written to disk on every save forever. Now it just reads the value once and writes nothing.
Two more I found and couldn't touch. It puts a cancellable inject at the very start of the entity render dispatcher, so every entity, every frame, pays an allocation plus an effect lookup, all to just support one stupid invisibility effect. And it adds an interface onto Item itself, which means its own "is this one of my weapons or sum?" check is true for every item in the game, so the guard it wrote does nothing.
Neither is fixable from outside, the expensive code sits inside a mixin handler method whose name gets mangled when it's applied, so there's nowhere stable to inject. The only way would be to disable their mixin and rewrite the feature myself, which means owning their bugs too..
Kind Of Nice Weapon
The only thing wrong with it is the same generated held item bug every single MCreator mod in my pack has, copying both your held stacks with their NBT before checking whether it needs to do anything. Fourth time I've patched that exact code. It's the generator atp, not the author.
Immersive Aircraft
It draws the HUD with the vanilla fill helper, which is fine, except it draws diagonal lines by calling fill once per pixel. Two per pixel if drop shadow is on. And in 1.20.1 every one of those calls ends by flushing the entire GUI buffer, which means disabling depth test, drawing everything queued so far, and re-enabling depth test. So one hundred pixel line with a shadow is two hundred full buffer flushes and four hundred GL state changes. The pitch ladder, the compass tape and the vector indicator are all built out of those lines. It's thousands of flushes every single fucking frame.
Now the whole overlay gets wrapped in the vanilla batching helper so it flushes once at the end instead.
I checked this can't break the layering before shipping it, because normally batching reorders things. The buffer source already ends the current batch whenever the render type changes, so shapes and text still draw in the same order they always did. The only thing that gets merged is consecutive geometry of the same type, which is exactly the thousands of one pixel rectangles.
Artifacts
- Skips the kitty slippers curios scan when the entity has nothing that hurt it. The original check could never pass without an attacker, so this is free.
- Skips the charm of sinking curios scan when the umbrella glide check can't pass anyway. Artifacts evaluates it eagerly even when the result gets thrown away.
- Skips the client side living tick on non players.
Oculus
Shaders render the world twice. Once for what you see, and once more from the sun's point of view to build the shadow map. Plenty of things get drawn into that second pass that cannot possibly show up in it.
This skips four of them while the shadow map is being built:
- Sign text. Font glyphs are flat quads. They cost real draw calls and contribute nothing to a depth map.
- Enchantment glint. The glint is a whole second pass over an item's geometry with a scrolling texture on top. Doubles the cost of every enchanted item in view, for a shimmer nobody can see in a shadow.
- Entity name tags. Same deal as sign text.
- Banner patterns. A fully decorated banner is up to 16 extra model draws stacked on the same cloth. The base cloth still renders so the banner keeps its shadow, the pattern layers just get skipped.
Nature's Aura
Once a second it walks every loaded chunk in every level and calls update() on each one's aura data. To even get the chunk list it goes through ObfuscationReflectionHelper, so that's a reflective Method.invoke into ChunkMap every time. Then for every single chunk it does a capability lookup, which walks that chunk's whole capability provider chain and resolves a LazyOptional, just to find an object that got made once when the chunk loaded and never changes after that.
Three things fixed here:
- Reflection is gone, it's a direct call through an accessor now. Same method, no
Method.invoke. - The capability lookup is now just a field on the chunk.
AuraChunkProviderbuilds its aura chunk once and never swaps it, so there's nothing to look up a second time. The field gets cleared through a capability invalidation listener so it can't outlive the thing it points at. - Chunks with no drain spots and nothing to sync get skipped instead of entered.
update()in that state reads the level, loops over an empty map and returns, so skipping it changes nothing. It also drops one iterator allocation per loaded chunk per second and on a normal world that's basically every chunk.
Caelus API
Returns false straight away for non players that aren't already fall flying. Caelus always returns false in that state anyway, so this just skips the attribute lookup and the chest slot elytra check for every grounded mob every tick.
Lootr
- Skips the container conversion pass entirely while both of its queues are empty. Lootr otherwise allocates two hash sets and copies the whole pending set every single tick with nothing to do.
- Caps how many candidates get examined per tick. With a backlog you're paying a full set copy plus a synchronized block and up to 25
hasChunkcalls per entry per tick, which is the exact clog Lootr's own log warns about at 5000 entries. Lootr discards entries at 18000 ticks so a 512 budget drains a 5000 entry backlog in ten ticks with room to spare.
Xaero's Minimap
Xaero rebuilds the whole minimap every single damn frame!!
Patch I did just caps how many times per second that rebuild happens. Default is 30. Skipped frames just draw the framebuffer from the last rebuild, so the minimap is still there and still looks normal, it only refreshes at the rate you set.
Xaero's + Waystones Compatibility
This one writes your entire waypoint file to disk, synchronously, on the client thread, every time waystone data comes in from the server. And the server sends one update per waystone. So joining a world where you know fifty waystones is fifty full file writes back to back on the render thread, which is exactly the kind of thing you feel as a hitch on join.
Now it just remembers that a save is needed and does one write at the end of the client tick. Same file, same contents, once instead of fifty times.
GeckoLib
GeckoLib builds model geometry by allocating a fresh Vector4f for every single vertex it writes. A cube is 6 quads of 4 vertices, so that's 24 throwaway objects per cube, per bone, per entity, per frame. On a pack with a lot of GeckoLib mobs on screen that adds up to millions of allocations a second, and all of it is garbage the GC has to clean up!!
Neither that vector or the quad normal ever leaves the method. They get transformed, read into the vertex buffer, and dropped. So they don't need to be allocated at all.
This rewrites the vertex writer to transform straight into a reused scratch vector using mulPosition, which skips the Vector4f entirely. Same math, same output, just without the crazy gc pressure.
Note: GeckoLib's renderer methods live on an interface, and Mixin does not allow normal injections into interface default methods. The only way in is a full method overwrite, which means this cannot coexist with other mods that overwrite the same method. It automatically turns itself off if GeckoBetterFPS is installed, so you won't get a crash.
Integrated API
BeardifierMixin injects at RETURN of Beardifier#compute. Beardifier is a DensityFunction and it does NOT override fillArray, so the default fillArray resolves to one compute call per element. That makes it a per sample method on the terrain shaping pass of every chunk you generate.
Every one of those samples gets handed to EnhancedBeardifierHelper#computeDensity, which reads three coords off the context, walks the enhanced rigid iterator, rewinds it with back(Integer.MAX_VALUE), then walks the enhanced junction iterator and rewinds that one too. For any chunk that doesn't have an Integrated API jigsaw structure near it both of those lists are empty, so all of that runs to add 0.0.
Now it returns the density it was given as soon as it sees both iterators are empty.
This one is properly behaviour identical and the reasoning is nice. Both iterators are ALWAYS sitting at position 0 when the method is entered, because forStructuresInChunk builds them fresh and every single exit path of computeDensity rewinds them. So hasNext() coming back false on entry means the backing list is empty. An empty list makes the loop body unreachable AND makes the rewind a no op, so the method could never have returned anything except the density it was handed.
Tested on 1.7.4.
Elysium API
This ones HORRIBLE. Almost made me tear up man..
MultiNoiseBiomeSourceMixin injects at HEAD of getNoiseBiome, which resolves every biome cell during worldgen and backs every level.getBiome at runtime. The first statement of their handler, before any guard at all, is this.getCurrentBiome(x, y, z, sampler). That's a full duplicate of the work the method is about to do anyway. sampler.sample(x, y, z) evaluates the entire climate stack (temperature, humidity, continentalness, erosion, depth, weirdness) and allocates a SinglePointContext and a TargetPoint, then findValuePositional runs an RTree search. Then vanillas own body goes and does the exact same thing again. So every biome resolution in the overworld and the nether costs twice what it should, and the first result gets binned unless a replacement fires.
Below that, still per call, it does registryOrThrow(BIOME_REPLACER).stream().toList(), which is a stream pipeline plus a fresh ArrayList copy of the whole registry, and then replaceBiomeIfNeeded allocates a HashSet and a new Random() before it has any idea whether a replacer even exists.
And the guard saves nobody. BiomeSourceMixin does @Mixin(BiomeSource.class) implements ElysiumBiomeSource, so EVERY biome source in the game passes the instanceof, and ElysiumEvents calls setDimension for both the overworld and the nether at server start. So the whole path runs for every biome lookup in both dimensions even if your pack defines zero biome replacers.
Two things here:
elysiumapi.memoClimateSampleis the safe half and its on by default. Both calls hit the same sampler with the same coords, back to back, on the same thread, so this keeps the last sampler, position and result per thread and answers the second one from that. Behaviour identical becausesampleis a pure function of the sampler and the three coords, so a memo keyed on exactly those can't return anything a recompute wouldn't. Per thread so worldgen threads never share an entry. This kills the climate stack half of the duplication. The second RTree descent still happens, so its about half the waste, not all of it.elysiumapi.skipUnusedBiomeReplacerLookupis the aggressive half. When no replacer of either kind is registered,replaceBiomeIfNeededwalks two empty lists and hands its input straight back, so the comparison is always equal,setReturnValuenever gets called, and the computed biome is never actually READ, only compared against itself. In that state any non null holder gives identical behaviour, so this hands back a remembered one instead of resolving a fresh biome. That removes the duplicate outright instead of halving it.
Ima be honest about the second one: its behaviour identical conditional on my no replacer check being complete. I read overworldBiomes, netherBiomes and the BIOME_REPLACER registry, which are the only three sources replaceBiomeIfNeeded looks at in 1.1.3. If a later version adds a fourth source this would start hiding it. The check is re-run every call rather than cached so a datapack reload takes effect immediately, and it only applies with TerraBlender installed because the other branch is merged into MultiNoiseBiomeSource and has no injection point. If worldgen ever looks wrong turn that one off first, the safe half can stay on by itself.
Tested on 1.1.3.
Echelon - Linggango Variant
ForgeTieredAttributeSubscriber#onItemAttributeModifiers is subscribed to Forge's ItemAttributeModifierEvent, which fires from inside ItemStack#getAttributeModifiers. So it runs on equipment changes, on every tooltip frame, and every single time any other mod asks a stack for its modifiers, which on a pack like mine is a lot.
For each attribute on a tiered item it derives a stable modifier id like this:
UUID.nameUUIDFromBytes((attributeId + "_" + slot.getName() + "_" + salt).getBytes(UTF_8))
I disassembled the JDK to make sure I wasn't imagining it. UUID.nameUUIDFromBytes calls MessageDigest.getInstance("MD5") and runs a fresh digest on EVERY invocation. Its not memoised anywhere. So thats a JCA provider lookup, a MessageDigest instantiation and an MD5 hash, per attribute, per call, plus the string concat and the byte array feeding it, all to produce a value that never changes for the life of the item. MD5 setup is microseconds, not nanoseconds, and it multiplies by attributes per item times however often anything touches getAttributeModifiers.
Cached now. Behaviour identical, nameUUIDFromBytes is a pure function of its input, MD5 of the bytes with the version and variant bits stamped in, so a content keyed memo returns exactly what recomputing would. The key holds the raw bytes rather than a decoded string so it stays exact even if that call site ever passes something that isn't well formed UTF-8. Bounded at 4096 entries, and since the salt is the items own TierUUID the key space grows with distinct item instances rather than tiers, so on overflow it just drops the map. The hot set is whatever gear you actually have equipped or hovered and it refills on the next call.
Vanilla - Item Rendering
When you drop items on the floor, the game draws the item model more than once so the pile looks chunky. A stack of 64 gets drawn five times. Five full model renders, for one item entity, every frame. And if you're running shaders, all five get drawn again for the shadow map, so that's ten renders of one dropped stack per frame.
Now it's capped. Default is 1, you can set it up to 5 or set 0 to get vanilla piles back. Nothing but the render loop reads that number so this is purely cosmetic, big stacks just look flatter on the ground.
Config
Everything has its own toggle in config/collections_of_optimizations-common.toml. There's a master general.enabled if you want to B/A (before/after) test the whole thing