The project code was created with help of Artificial Intelligence.
An open source mod with mix of small optimizations for your Minecraft. Less stutters, slightly faster resource loading and world generation, less memory usage.
The main thing Lomka does is reduce the number of redundant garbage (memory) allocations and improves game calcs.
Optimizations
Frame time
- Fewer allocations in the render, tick and collision loops (vertex writes, pose stacks, entity block sweeps)
- Cached font glyph advances (deprecated)
- Cheaper math and color engine
- Faster texture atlas animation (lazily cycle)
- Playing a sound skips the wait for the sound thread
- Removing
Thread.yield()from the client tick loop
Loading and memory
- Bulk NBT array reads for world, player and structure data on the server side (chunks, heightmaps and saves load in blocks instead of per-element stream calls)
- Cheaper resource scanning and cached pack metadata reads
- Generated mip levels releases after upload
- Fewer native buffer reallocations (audio streaming and mesh building)
World and network
- Cached voxel shape boxes and block face-sturdiness
- Faster block and section traversal, heightmapping for world generation, and in-place worldgen RNG reseeds (also, check the incompatibilities list first)
- Leaner network buffers and packet compression (without affecting your connection)
And some other small bugfixes in the game's code.
Measured effect
Isolated microbenchmarks on JDK 25, one operation at a time.
That's not in game frame rates benchmarks:
| Patch | Measured | What you notice it in |
|---|---|---|
| Voxel shape decomposition | toAabbs(): 40 ns vs 8584 ns, 199x+ (14 ns vs 8879 ns on 368 cells) |
Every block an entity touches while moving |
MixinLegacyRandomSource |
next(int): 7.1x |
Every random draw a new chunk needs, on the client and dedicated server. |
MixinBlockPos.betweenClosed |
one 16³: 61 ms -> 11 ms, 5.61x | /fill and other volume edits, the lighting pass after a large build, structure and feature placement, explosion block lists. |
MixinBlockStateBaseCache |
isFaceSturdy: 4.1-5.8x |
Checks such as walking on slabs and stairs, collision resolution between mobs and players, support recomputation when a neighbour changes. |
MixinCompressionDecoder |
setupInflaterInput: 37.5 ns -> 18.1 ns and 128 B -> 0 B per packet |
Every incoming compressed packet |
MixinSoundEngine |
sound acquisition: 400 us -> 20 us, stall per tick 512 us -> 27 us | Client thread stops waiting for the sound thread. |
MixinAutoStorageIndexBuffer |
index buffer grows x4: 1.47-2.9x less time reallocating (85.4 ms -> 29.5 ms, 21 -> 11 reallocations; retains 40 MiB instead of 34) | Geometry spikes (for example, pulling the render distance) |
MixinFallbackResourceManager |
metadata lookup: 5.33x (2.71 ms -> 0.51 ms for 20k files) | Startup and every resource reload (F3+T, still slightly improving) |
MixinMth |
ceillog2 and log2: 3.93 ns -> 0.85 ns (4.6x), 4.83 ns -> 0.84 ns (5.7x) |
Palette sizes, section and buffer counts, every place vanilla asks for a bit length |
Versions
1.21.11 is the main version. It carries the full set of optimizations and gets the most testing.
Modern variants:
| Minecraft | Loaders |
|---|---|
| 1.16.5 | Fabric |
| 1.18.2 | Fabric, Forge |
| 1.19.2 | Fabric, Forge |
| 1.20-1.20.1 | Fabric, Forge |
| 1.21-1.21.1 | Fabric, NeoForge |
| 1.21.4 | Fabric, NeoForge |
| 1.21.6-1.21.8 | Fabric, NeoForge |
| 1.21.9-1.21.10 | Fabric, NeoForge |
| 1.21.11 | Fabric, NeoForge |
| 26.1-26.1.2 | Fabric, NeoForge |
| 26.2 | Fabric, NeoForge |
| 26.3 | Fabric, NeoForge |
Legacy builds cover 1.7.10, 1.8.9 and 1.12.2, on Forge and on Ornithe. These are a separate port with a much smaller patch set and their own patch list. The Forge variants need a mixin runtime installed alongside Lomka (MixinBooter 11.17 on 1.8.9 and 1.12.2, UniMixins on 1.7.10); the Ornithe variants need nothing, because the Ornithe loader ships the mixin runtime itself. See Mixin Configuration (legacy).
❗ Everything outside 1.21.11 is a port of the same or other ideas with a smaller improvement.
FAQ
I see performance drops with Lomka installed
Update to the latest build for your Minecraft version first.
Still bad? Report it (link below) with your game version, loader, mod list, and which config you had turned off.
Does it change vanilla behaviour?
Nope, of course, but if it does weird game changes reply in the issue tracker.
Is it server-side compatible?
Yes, it is.
Does it need any dependencies?
No. The only external requirement is the mixin runtime, and only on the legacy Forge builds (1.7.10-1.12.2). The Ornithe ones ship their own.
Can I add this mod in my modpack?
Sure. Lomka is free and open source. Check out how it goes on your modpack first.
Configuration
Lomka has no in-game GUI. Instead, on first launch it creates config/lomka-mixins.properties with basic mixin configuration.
The full list of mixins with descriptions lives in the wiki:
Mixin Configuration for 1.16.5-26.3.
Mixin Configuration (legacy) for 1.7.10-1.12.2.
Compatibility
This should work fine with most mods (like Sodium, Lithium, Iris, FerriteCore, ModernFix, ImmediatelyFast and even VulkanMod) but no guarantees at all.
Known conflicts are listed with Lomka versions in the incompatibilities list.
Bug reports
Found something that only happens with Lomka?
- Try reproducing it without Lomka first, and with the individual patches disabled.
- Still there? Post it on the issue tracker with an optional log attached.
Please don't report Lomka-related crashes to other mod authors, because Lomka's mixins are cruel that could break unrelated systems.
Credits
Lomka was created by Starlev and contributors.
Also, other mods credits for their's effecient work!
VecDeltaCodeczero-delta path adapted from Collections Of Optimizations by Misanthropy (LGPL-3.0).Vec3iPhiMix hashing credits EfficientHashing by ZZZank (CC0-1.0).- The legacy hardware-blit presentation path references from Tritium (MIT), but popularized in VulkanMod (LGPL-3.0-only).
How to Install Lomka (Mod)
Lomka by Starlev is verified for Fabric, Forge, Neoforge, Ornithe, Quilt across Minecraft versions 1.12.2, 1.16.5, 1.18.2, 1.19.2, 1.20, 1.20.1, 1.21, 1.21.1 (latest release: mc26.3-0.7.0-neoforge, file size: 175 KB). Follow the steps below to install it safely from ModCraft.tv:
- Click the Download button above and select your Minecraft version (1.12.2, 1.16.5, 1.18.2, 1.19.2, 1.20, 1.20.1, 1.21, 1.21.1) and platform (Fabric, Forge, Neoforge, Ornithe, Quilt).
- Make sure you have the compatible loader or environment installed for Fabric, Forge, Neoforge, Ornithe, Quilt.
- Move the downloaded Lomka file into your Minecraft
.minecraft/modsfolder and launch the game.
All Versions
+ Add Version| Name | Game version | Platforms | Published | Downloads | Actions |
|---|---|---|---|---|---|
| 19d ago | 1 | ||||
| 19d ago | 1 | ||||
| 19d ago | 1 | ||||
| 19d ago | 1 | ||||
| 19d ago | 1 | ||||
| 19d ago | 1 | ||||
| 19d ago | 1 | ||||
| 19d ago | 1 | ||||
| 19d ago | 1 | ||||
| 19d ago | 1 | ||||
| 19d ago | 1 | ||||
| 19d ago | 1 | ||||
| 19d ago | 1 | ||||
| 19d ago | 1 | ||||
| 19d ago | 1 | ||||
| 19d ago | 1 | ||||
| 19d ago | 1 | ||||
| 19d ago | 1 | ||||
| 19d ago | 1 | ||||
| 19d ago | 1 | ||||
| 19d ago | 1 | ||||
| 19d ago | 1 | ||||
| 19d ago | 1 | ||||
| 19d ago | 1 | ||||
| 19d ago | 1 | ||||
| 19d ago | 1 | ||||
| 19d ago | 1 | ||||
| 19d ago | 1 | ||||
| 19d ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 2mo ago | 1 | ||||
| 2mo ago | 1 | ||||
| 2mo ago | 1 | ||||
| 2mo ago | 1 | ||||
| 2mo ago | 1 | ||||
| 2mo ago | 1 | ||||
| 2mo ago | 1 | ||||
| 2mo ago | 1 | ||||
| 2mo ago | 1 | ||||
| 2mo ago | 1 | ||||
| 2mo ago | 1 | ||||
| 2mo ago | 1 | ||||
| 2mo ago | 1 | ||||
| 2mo ago | 1 | ||||
| 2mo ago | 1 | ||||
| 2mo ago | 1 | ||||
| 2mo ago | 1 | ||||
| 2mo ago | 1 | ||||
| 2mo ago | 1 | ||||
| 2mo ago | 1 | ||||
| 2mo ago | 1 | ||||
| 2mo ago | 1 | ||||
| 2mo ago | 1 | ||||
| 2mo ago | 1 | ||||
| 2mo ago | 1 | ||||
| 2mo ago | 1 | ||||
| 2mo ago | 1 | ||||
| 2mo ago | 1 | ||||
| 2mo ago | 1 | ||||
| 2mo ago | 1 | ||||
| 2mo ago | 1 | ||||
| 2mo ago | 1 | ||||
| 2mo ago | 1 | ||||
| 2mo ago | 1 | ||||
| 2mo ago | 1 | ||||
| 2mo ago | 1 | ||||
| 2mo ago | 1 | ||||
| 2mo ago | 1 | ||||
| 2mo ago | 1 | ||||
| 2mo ago | 1 | ||||
| 2mo ago | 1 | ||||
| 2mo ago | 1 | ||||
| 2mo ago | 1 | ||||
| 2mo ago | 1 | ||||
| 2mo ago | 1 | ||||
| 2mo ago | 1 | ||||
| 2mo ago | 1 | ||||
| 2mo ago | 1 | ||||
| 2mo ago | 1 | ||||
| 2mo ago | 1 | ||||
| 2mo ago | 1 | ||||
| 2mo ago | 1 | ||||
| 2mo ago | 1 | ||||
| 2mo ago | 1 | ||||
| 2mo ago | 1 | ||||
| 2mo ago | 1 | ||||
| 2mo ago | 1 | ||||
| 2mo ago | 1 | ||||
| 2mo ago | 1 | ||||
| 2mo ago | 1 | ||||
| 2mo ago | 1 | ||||
| 2mo ago | 1 | ||||
| 2mo ago | 1 | ||||
| 2mo ago | 1 | ||||
| 2mo ago | 1 | ||||
| 3mo ago | 1 | ||||
| 3mo ago | 1 | ||||
| 3mo ago | 1 | ||||
| 3mo ago | 1 | ||||
| 3mo ago | 1 | ||||
| 3mo ago | 1 | ||||
| 3mo ago | 1 | ||||
| 3mo ago | 1 | ||||
| 3mo ago | 1 | ||||
| 3mo ago | 1 | ||||
| 3mo ago | 1 | ||||
| 3mo ago | 1 | ||||
| 3mo ago | 1 | ||||
| 3mo ago | 1 | ||||
| 3mo ago | 1 | ||||
| 3mo ago | 1 | ||||
| 3mo ago | 1 | ||||
| 3mo ago | 1 | ||||
| 3mo ago | 1 | ||||
| 3mo ago | 1 | ||||
| 3mo ago | 1 | ||||
| 3mo ago | 1 | ||||
| 3mo ago | 1 | ||||
| 3mo ago | 1 | ||||
| 3mo ago | 1 | ||||
| 3mo ago | 1 | ||||
| 3mo ago | 1 | ||||
| 3mo ago | 1 | ||||
| 3mo ago | 1 | ||||
| 3mo ago | 1 | ||||
| 3mo ago | 1 | ||||
| 3mo ago | 1 | ||||
| 3mo ago | 1 | ||||
| 3mo ago | 1 | ||||
| 3mo ago | 1 | ||||
| 3mo ago | 1 | ||||
| 3mo ago | 1 | ||||
| 3mo ago | 1 | ||||
| 3mo ago | 1 | ||||
| 3mo ago | 1 | ||||
| 3mo ago | 1 | ||||
| 3mo ago | 1 | ||||
| 3mo ago | 1 | ||||
| 3mo ago | 1 | ||||
| 4mo ago | 1 | ||||
| 4mo ago | 1 | ||||
| 4mo ago | 1 | ||||
| 4mo ago | 1 | ||||
| 4mo ago | 1 | ||||
| 4mo ago | 1 | ||||
| 4mo ago | 1 | ||||
| 4mo ago | 1 | ||||
| 4mo ago | 1 | ||||
| 4mo ago | 1 | ||||
| 7mo ago | 1 | ||||
| 7mo ago | 1 | ||||
| 7mo ago | 1 | ||||
| 7mo ago | 1 | ||||
| 7mo ago | 1 | ||||
| 7mo ago | 1 | ||||
| 7mo ago | 1 | ||||
| 7mo ago | 1 | ||||
| 7mo ago | 1 | ||||
| 7mo ago | 1 | ||||
| 7mo ago | 1 | ||||
| 7mo ago | 1 | ||||
| 7mo ago | 1 | ||||
| 7mo ago | 1 | ||||
| 7mo ago | 1 | ||||
| 7mo ago | 1 | ||||
| 8mo ago | 1 | ||||
| 8mo ago | 1 | ||||
| 8mo ago | 1 | ||||
| 9mo ago | 1 |
- New
DiscreteVoxelShapecache: the greedy box decomposition is memoised as cell indices (MixinDiscreteVoxelShape+IDiscreteVoxelShape) and replayed byVoxelShape#forAllBoxes, instead of cloning the whole BitSet and re-decomposing it on every call.VoxelShape#moveallocates a fresh wrapper each time, so a wrapper-keyed cache is cold on every call, while the decomposition itself is a pure function of the shape bits - boxes are recorded through vanilla's ownIntLineConsumer, so the order is whatever upstream produces. Shapes whose decomposition is too fragmented to retain (>32 boxes) answer with the empty sentinel and keep vanilla's path. This is the per-touched-block pathEntity.movewalks. (all versions) **NEW** - New
ModelPart#rotateByoverwrite: reuses two scratchMatrix3fand one scratchVector3f(thread-confined, same convention asMixinPose) instead of allocating per call. The Euler -> matrix -> Euler round trip is unchanged and bit-identical over 200k random rotations. Call sites are narrow (end crystals, player capes), so this is an allocation reduction, not a frame-time change. (1.21.4+) **NEW** - New
DisplayRendererredirect: the billboarding quaternion comes from a reusable scratch instead of a freshQuaternionfper display entity per frame. Every branch ofcalculateOrientationassigns rather than accumulates and the result is only read, so a shared instance is sound. (>=1.20) **NEW** - New
BlockGetter#forEachBlockIntersectedBetweenoverwrite plus theBlockStepSweephelper: replaces the per-cellIterable+AbstractIterator+MutableBlockPostrio and theOptional<Vec3>box clip of the DDA sweep with one reused cursor and a primitive clip returningt. Vanilla's arithmetic, iteration order, deduplication and abort semantics are reproduced exactly - this runs on every entity move viaEntity#checkInsideBlocks, and onGhast#tick. (>=1.21.9) **NEW** SoundEnginehandle pool now replenishes on hits as well as misses, gated on a live per-pool size counter and topping up below half the cap. A miss costs a fullcreateHandle().join()- exactly what vanilla costs - so a miss-only pool can improve the median but never the tail: its hit rate settled at 50% (30% on 32-sound bursts) and p99 was vanilla's. Topping up on every call reaches a 100% hit rate. The win holds while a tick plays at most about cap/2 sounds and decays to vanilla beyond that; it is never worse. (all versions) **REWORK**PalettedContainer's uniform-section cache moved into one immutableUniformPaletteCache(Data, value)holder behind a single volatile reference, so the hot path is still one volatile load, one identity check and one plain load. (all versions) **REWORK**- New
BlockModelLighterstate-read memo: while a section's immutable render region is meshed, the repeatedBlockAndTintGetter#getBlockStatereads of ambient occlusion are answered from a 512-slot open-addressed table keyed on the packed bl
- 6** on 1.7.10 Ornithe, **10** on 1.8.9, **11** on 1.12.2.
### New
- Forge support for **1.7.10**, **1.8.9** and **1.12.2**, in a separate tree with its own Gradle builds.
so a patch is version-gated by a
//$ if >=1.12 marker on line 1, processed by gradle/preprocess.gradle- the same directive syntax the modern
json5config uses. Each build's mixin config is **generated**
config.
- Ornithe support for the same three versions**, alongside the Forge ones:
lomka-<version>-ornithe+<mc>.jar. It is a second source tree rather than a loader switch, becauseFeather - the mapping set Ornithe compiles against - names classes the way 1.16+ does (
Direction,Box, NbtIntArray, Identifier), a different namespace from the MCP names the Forge tree has touse. The two trees share only the pure-math kernels; every
@Mixin shell is per-namespace.One toolchain covers all three (
fabric-loom + Ploceus), where Forge needs three: ForgeGradle 1.2on Gradle 6.9.1 for 1.7.10, ForgeGradle 2.1.6 on Gradle 2.14.1 for 1.8.9 (the only line that serves
1.8.9
userdev), and RetroFuturaGradle 2.0.6 on Gradle 9 for 1.12.2 - and RetroFuturaGradlesupports 1.7.10 and 1.12.2 only, never 1.8.9.
- No external mixin runtime on Ornithe.** The Ornithe loader ships sponge-mixin and
mcmod.info dependency block to get the modid:range format right, and nothing to ask players toinstall. Access widening is an access widener on all three versions, where 1.12.2 Forge has none.
The Ornithe entrypoint is OSL's
net.ornithemc.osl.entrypoints.api.ModInitializer - the Fabric APIclasses do not exist on these Minecraft versions - and the same runtime toggle and
//$ if gatingrun through the same preprocessor.
- The legacy Forge build directories are now
legacy/legacy-forge-<mc>rather than
legacy/legacy-<mc>, so they read as a pair with legacy/legacy-ornithe-<mc>.- Runtime per-mixin toggle (
config/lomka-mixins.properties) through a legacy-specific
LomkaMixinPlugin: Log4j instead of SLF4J (which only arrives in 1.17), no Gson (parseString needs2.8.6, 1.12.2 ships 2.8.0), and no JOML system properties (these versions use Mojang math).
- Mixin runtime is an external mod, never shaded: **MixinBooter 11.17** on 1.8.9 and 1.12.2,
- UniMixins 1.7.10-0.3.1** on 1.7.10. Registration is the
MixinConfigsmanifest attribute, so there
IFMLLoadingPlugin class. 1.12.2 ships lomka.refmap.json; 1.7.10 and 1.8.9 remap inthe reobf step and need no refmap.
- Per-version
mcmod.info, withlogoFileas a bare `lo
- New
IntArrayTagandLongArrayTagmixins, where vanilla reads these arrays element by element, so every int costs four and every long eightread()calls on aDataInputStream. The array is now read in 8 KB blocks through a big-endianByteBuffer. The bulk path only triggers onDataInputStreaminputs, so in practice it accelerates server-side disk reads (chunk NBT with itsHeightmapslong arrays, player data,level.dat, saved data, structure templates). **NEW** - New
Vec3#normalizemixin: replaces three divisions with one reciprocal and three multiplications. Results may differ from vanilla by up to 1 ULP. (1.21.4+) **NEW** - New
ARGB#multiplyoverwrite that folds the four per-channel/255integer divisions into exact reciprocal multiplies, which runs on every entity's model tint each frame. Results are bit-identical to vanilla. (all versions) **NEW** - New
MixinSoundEnginechannel-handle pool. Playing a sound no longer makes the client threadjoin()a hand-off to the sound executor, so a sound plays as soon as its handle is already acquired. (all versions) **NEW**
### Bug Fixes
- Register common optimizations under the standard
mixinskey so they actually run. The key was spelledmain, which Mixin does not read, so every common patch (Mth,ARGB,BlockPos,Direction,AABB,PalettedContainer,Heightmap, NBT tags, ...) **was silently dropped in every release from 0.3.0 to 0.5.5**. Only theclientsection was live, so the mod has been running at roughly half its intended patch set for its entire published history. **CRITICAL** - Fixed the 1.19.2 manifests advertising Minecraft up to
1.19.4, which the 1.19.2 artifacts cannot run on: the 1.19.3 JOML transition is binary-incompatible. Both loaders now declare[1.19,1.19.2], and the range generator collapses to the single-element form when the minimum equals the maximum, because Forge's version parser rejects a range with identical boundaries. - Fixed a crash of the Forge mod list on 1.19.2, where the generated manifest pointed
logoFileatassets/lomka/icon.png, and 1.19.2 feeds that value toAbstractPackResources#getRootResource(String), which throwsIllegalArgumentExceptionon any name containing/, so clicking the mod in the mod list always crashed. The Forge manifest now uses a barelogo.pngat the jar root, which both 1.19.2 and 1.20.1 resolve. - Fixed missing mixin visibility and 26.3 API drift that aborted the launch on several versions (
MixinBitSetDiscreteVoxelShape,MixinPalettedContainer,MixinArrayListDeque,MixinUtil,MixinDirection,MixinFriendlyByteBuf). - Fixed
MixinTextureAtlason 1.21.6-1.21.10: the texture field is inherited fromAbstractTexture, so@Shadowcould not resolve it and aborted the launch. A newaccessor.AbstractTextureAccessorbridge reads it through the superclass. (1.21.6-1.21.10) - Fixed
MixinCompressionDecoderdropping the connection:ByteBuf#internalNioBufferis absent
- New KeyframeAnimation mixin: scratch
Vector3freused per animation instead ofnew Vector3f()perapply()(24 B/frame, measured), indexed entry walk instead of iterator, exact zero-scale early-out. (1.21.6+) **NEW** - New Entry bridge mixin:
IKeyframeAnimationEntryduck to the privateKeyframeAnimation$Entryrecord so the caller scratch vector flows into vanillaapply()search/interpolation stay vanilla. (1.21.6+) **NEW** - New Heightmap mixin:
primeHeightmapsrewritten without the per-YChunkAccess#getBlockStatewalk flatHeightmap[]/Predicate[]pair, int bitmask for pending types, section-local scans,O(1)skip of null/hasOnlyAirsections and one predicate test per uniform section. Bit-identical, no per-column alloc. (all versions) **NEW** - New PalettedContainer probe:
lomka$uniformValue()answers the Heightmap uniform-section check via the same(value, volatile Data)pair as the hotget()path, heterogeneous containers return null and are never cached. (all versions) **NEW** - New XoroshiroRandomSource mixin:
setSeedreseeds the liveXoroshiro128PlusPlusin place (seedLo/seedHiwrites +gaussianSource.reset()) instead ofnew Xoroshiro128PlusPlus(...)persetFeatureSeed/setDecorationSeedone generator alloc saved per structure/feature per chunk, sequence bit-identical. (all versions) **NEW** - New StringRenderOutput mixin: one-slot
FontSetmemo per laid-out string consecutive codepoints of a styled run skip the font-map walk, identity hit withequalsfallback. Ported from Collections Of Optimizations by Misanthropy (LGPL v3). (1.19.2-1.21.8) **NEW** - New VecDeltaCodec mixin: zero-delta fast path returns
Vec3.ZEROinstead ofsubtract+ newVec3one alloc saved per unchanged tracker delta. Ported from Collections Of Optimizations by Misanthropy (LGPLv3, with authority), priority 999 for CoO compat. (all versions) **NEW** - PoseStack on 1.19.2 (Mojang math): per-stack scratch
Matrix4f/Matrix3freuse instead of vanilla per-call allocations inmulPose(Quaternion); bit-identical. (1.19.2) **NEW** - Font mixins (
MixinFont,MixinGlyphSource,MixinFontSet,MixinSource) widened down to 1.21.9+ (were 1.21.11+). (1.21.9+) **NEW from OLD** - GlStateCache rework:
int[] STATE+get/setreplaced with plain public static fields; viewport/scissor/polygon compare via single XOR-OR, FBO read/write via direct field compare no array bounds checks / interface dispatch on the dedup path. (all versions) **REWORK**
### Bug Fixes
- Util
sanitizeNameparity fix: now runstoLowerCase(ROOT)on the whole string first (handles length-changing lowercases like U+0130) and only then patches rejected chars previous version lowercased per-char. Zero-alloc fast path for all-valid input kept. - Util
offsetByCodepointsbounds fix: out-of-range single steps returniunchanged instead of clamping tolen/0.
### Removed
- Removed low-value/parity-risky Util overwrites: `getPlatfor
### Performance
- VertexConsumer
putBulkData/putBakedQuad: pose-matrix loads hoisted out of the per-vertex loop and the 4-vertex loop fully unrolled - no per-vertex interface dispatch, friendlier to auto-vectorization. (1.21.11+ / 26.1+) - FriendlyByteBuf
writeMap: cached reusableBiConsumerkeepsHashMap.forEachinternal iteration (measured faster than an entry-set loop) with zero per-packet lambda allocations;writeEnumSet/readEnumSetrewritten as sparse bit packing (O(set size)instead ofO(enum length)), noBitSettemporaries. (all versions) - FallbackResourceManager
listResources: derived base->meta index built after pack filtering - zero-alloc metadata attach per file with exact vanilla filter semantics; logger handle cached instead of a registry lookup per call. (all versions)
### Removed
- Removed MixinDataLayer and MixinSoundEngine (rare scenarios).
- Removed Frustum
offsetToFullyIncludeCameraCube(branchless int casts measured slower thanMath.floor/ceilintrinsics). - Removed SectionPos
asLong/x/blockToSectionoverwrites.
### Changed
- ChunkStatus status-list cache is now published via
volatile- safe for worldgen worker threads at no steady-state cost. (1.21+) - Bench harness: standalone
scripts/benchrunners (world / core-util / packs / client) with correctness fuzz; source comments no longer carry benchmark figures perRULES.mdsection 4.
### Bug Fixes
- Mod dev version -> Normal mod version
### Performance
- New Level mixin:
ThreadLocalscratch forgetEntities(Entity,AABB,Predicate)— hottest entity query (all) **NEW** - New PalettedContainer mixin: uniform-section fast path via
volatile Dataidentity (all) **NEW** - New FrameBufferCache mixin: zero-alloc probe
CacheKeyforgetFbo(26.3) **NEW** - DynamicGpuDataStorageMapped mixin:
renderpearlsuccessor ofDynamicUniformStorage(26.3)
### Bug Fixes
- Refmaps fix for 1.20.1 Forge
- Lightmap profiler/pipeline +
RenderStateExtractorvectors - 26.3
ResourceManager.Selectorcompat for pack managers, WindowonResizesignature
### Changed
- 26.3
renderpearlreplacements (GpuBuffer,GlProgram, etc.) — 19 variants,PoseStack/GlProgramgated<26.3,neoforge-moddev2.0.147
- Refmaps fix for 1.20.1 Forge.
- VoxelShape.toAabbs is computed once per shape and cached —
clip()no longer allocates an ArrayList + AABBs on every raycast miss (crosshair raycast runs every frame). (all versions) **NEW** - BitSetDiscreteVoxelShape.join accumulates contiguous bit runs and flushes them with bulk
BitSet.set(from, to)word writes instead of oneset()per voxel. (all versions) - New AABB mixin: allocation-free
clippaths — nodouble[1]box, no per-iterationAABB.movein theIterablevariant, direct face tests. Keeps Lithium's AABB mixin intact. (all versions) **NEW** - New BlockPos mixin:
betweenClosedreplaces2 div + 2 modper block with incremental stepped counters, preserving the vanilla X→Y→Z order. (all versions) **NEW** - AutoStorageIndexBuffer warmup lands the first allocation at 16384 indices (~32 KB SHORT) with the x4 growth no early mid-frame regen hitches. (all versions) **NEW**
- New Vec3i mixin: exhaustive switch for
get(Axis), int-exactdistManhattan, phi-mixhashCode(fromefficient_hashingby ZZZank, CC0). (all versions) **NEW** - New LegacyRandomSource mixin: plain-field LCG draws instead of volatile + CAS per call; the vanilla seed-install guard stays, worldgen parity is bit-for-bit. (all versions) **NEW**
- New Util mixin: cached OS/arch detection, array-backed shuffles, allocation-free URI scheme checks, single-step
offsetByCodepoints, shared predicate constants. (all versions) **NEW** - New Direction mixin:
getClockWise/getCounterClockWisevia a flat 1D LUT instead of nested enum-switch dispatch; branch-freegetApproximateNearest. (all versions, nearest optimization one: 1.21.4+) **NEW** - New ByteBufferBuilder mixin: inlined
reservefast path, max growth step raised from 2 MB to 8 MB — no repeated native reallocations on chunk/batch surges. (1.21+) **NEW** - BufferBuilder per-vertex writes (
setColor(IIII),setUv(FF),uvShort) collapsed to single int/long stores; the packed-color path stays on BSWAP + ROR. (1.21+) **NEW** - VertexConsumer transforms rewritten with per-era coverage: scalar fma
addVertex(1.21+), 2DaddVertexWith2DPose(1.21.6+),setNormalvia the widenedtrustedNormalsfield (1.21-1.21.11),putBulkDatawithout bridge arrays (1.21.11+), fmaputBakedQuad(26.1+). **NEW** - Mth:
smallestEncompassingPowerOfTwovia a single LZCNT instruction, fmalerp(float/double) with single rounding — ported from SuperFastMath (elias, permission granted). (all versions) **NEW** - GlStateManager state dedup (viewport/scissor/polygonMode, cancellable HEAD injections) extended to all versions; GlStateCache now tracks bound read/write FBOs and dedups
_glBindFramebufferback to 1.20.1, replicating vanilla's own 1.21.2+ mirror logic. (all versions) **NEW from OLD** - Pose scratch-matrix optimization covers the outer
PoseStack.mulPose(Matrix4f)era (1.21-1.21.4) too, unified in MixinPose. (1.21+, not 26.x) **NEW from OLD** - Std140Builder / Std140SizeCalculator: blanket per
- Frame-end present replaced with a single hardware
glBlitFramebuffer(NEAREST)call instead of the blit-shader fullscreen quad — no per-frame Matrix4f/Tesselator/MeshData allocations, no mid-frame shader program bind. (<1.21.4) **NEW**
### Bug Fixes
- Fixed entity tick crash (
ClassCastExceptionintickNonPassenger) — the cached profiler name path now casts to theLevelsuperclass directly instead of relying on a separate Level mixin being applied. - Mixin config (
lomka-mixins.properties) keys now match full/short/simple mixin names. Toggles are no longer silently ignored or falsely reported as unknown.
### Removed
- Removed MixinLevel and the ILevelProfiler duck interface (superseded by the direct superclass cast).
### Changed
- Removed duplicated license headers and stale javadoc tags in several mixins.
- Shared sequential index buffer grows x4 instead of x2, with an 8192-index warmup floor — no more mid-frame regen hitches on chunk/GUI/cloud spikes. (all versions) **NEW**
- GlStateManager skips redundant viewport/scissor/polygonMode driver calls, cache resets on resize. (1.21.6+) **NEW from OLD**
- Frustum setup uses branchless integer floor/ceil instead of Math calls. (all versions) **NEW**
- PoseStack push/pop pooled and mulPose runs through a scratch matrix. Zero allocations per entity part. (mulPose scratch: 1.21.6–1.21.11)
- VertexBuffer caches its GL primitive mode, format check by reference. (<1.21.6) **NEW**
- VertexFormatElement caches hashCode and drops Usage lambdas in attribute setup. (<1.21) **NEW**
- Multi-consumer fan-out walks delegates with direct indexed loops instead of per-vertex lambdas. (1.20.1–26.1) **NEW**
- VertexConsumer gains an affine fast path for applying pose matrices. (1.21+) **NEW**
- Material hash cached instead of allocating an Object[] per sprite lookup. (1.20.1–1.21.11) **NEW from OLD**
- SectionPos cheaper packed math with allocation-free stream traversal. (all versions) **NEW**
- StatType registration is a lambda-free get-then-put. (all versions) **NEW**
- ChunkStatus progression list cached instead of rebuilt per chunk layer. (1.21+) **NEW**
- Light storage reuses one consumer instead of allocating a lambda per block change. (all versions) **NEW**
- CompressionEncoder reuses its input buffer between packets. (all versions) **NEW**
- Entity tick profiler names cached per entity type, removing vanilla's capturing lambda. (<26.1) **NEW**
- Vulkan host-visible buffers map through a persistent address, no driver round-trip per frame. (26.2) **NEW**
### New
- Mixin configuration is REAL in
config/lomka-mixins.properties. - Mixin configs now declare minVersion: 0.8.
### Removed
- Removed low-value mixins: MixinKey, MixinNativeImage, MixinSoundBufferLibrary, MixinIdMapper.
- Removed accessors: AccessorCache, AccessorNearPlane, InvokerBuilder. (changed by aw/at)
### Changed
- License changed from **MIT** to **LGPL-3.0-only**.
- Mod icon, mod description.
- LomkaFabric, LomkaNeoForge and LomkaForge all-in-one in just Lomka with conditionals.
- GpuBuffer patch disabled on 26.2, vanilla caches the full-buffer slice natively.
- Numerous existing mixins received further tweaks and version-condition adjustments.
- Font glyph widths cached per codepoint/bold pair — text rendering does fewer glyph source lookups. (1.21.11+) **NEW**
- Resource pack loading overhaul:
- FallbackResourceManager listResources fast-path for
.mcmeta— eliminates thousands of useless Identifier allocations and map lookups. **NEW** - MultiPackResourceManager bypasses redundant secondary TreeMap allocation when only one namespace manager is present. **NEW**
- VanillaPackResources fast-path namespace check, zero-allocation path resolution, and cached parsed
pack.mcmeta. (<26.1) **NEW** - Block collision shapes now served from the cached shape instead of virtual
getCollisionShapedispatch. (non-dynamic blocks) **NEW** - Light queues swapped from
LongLinkedOpenHashSetto bit-packedSpatialLongSet— less heap churn during chunk loading. **NEW** - Shader uniform lookup via fastutil open-addressing map instead of HashMap. (1.21.6+) **NEW**
- ChunkedSampleByteBuf no longer allocates a fresh native buffer per chunk. (1.21+) **NEW**
- Lighting precomputes a buffer slice per entry and skips redundant GPU UBO writes when the cardinal light type is unchanged. (1.21.6+)
- NativeImage fillRect/copyRect rewritten with bulk MemoryUtil.memCopy — whole-image and whole-row transfers in a single call.
- Std140 builder and size calculator put* methods rewritten with bitwise alignment and absolute indexed writes. (1.21.6+)
- ModelPart rotateBy composes rotations through a single quaternion instead of a full 3x3 matrix multiply.
- ArrayListDeque removes from the front half by advancing head instead of shifting the tail.
- ARGB reciprocal lookup table computed in O(1) per entry instead of an inner loop.
### Bug Fixes
- NativeImage fillRect/copyRect now validate format and bounds explicitly instead of silently corrupting memory.
- Fixed Lightmap and LightmapRenderStateExtractor 26.2 API calls (
mapBuffer,getMainCamera,getBossOverlay,getNightVisionScale). - MixinMth clampedLerp is now version-conditional so the correct argument order is used on 1.21.11+ and older.
- Camera 26.1+ near-plane path kept on the lightweight custom structure.
### New
- New duck interfaces:
IBitSetDiscreteVoxelShape,IGlyphSource. - New accessors:
AccessorCache,InvokerBlockBehaviour.
### Compatibility
- Per-version mixin configs, access wideners and access transformers are now generated from Stonecutter templates (
src/stonecutter/) instead of committed per-version files. - Mixin source exclusions are auto-derived from the processed mixin config — no more hand-maintained exclude tables in build scripts.
### Removed
- Removed low-impact mixins: MixinSamplerCache, MixinSortState, MixinQuadrant, MixinItemTransform, MixinMipmapGenerator.
- Removed DiscreteVoxelShapeHelper — replaced with the IBitSetDiscreteVoxelShape duck interface.
- Removed per-version committed
lomka.mixins.json,*.accesswidenerandaccesstransformer.cfgfiles.
### Changed
- Build system refactored: `bui
- Sampler cache lookup rewritten — no per-call enum comparisons.
- Cursor3D advance rewritten — no divisions/modulos per voxel.
- Tiny holder sets use linear scan instead of Set allocation.
- Lighting coordinate calculations now applied. (26.1+)
- BlockableEventLoop submit runs inline with no future allocations.
- GameRenderer extractCamera removed null-conditional.
- Key inputs hashCode caching simplified.
- Removed Thread.yield() from runTick for lower frame latency. (before it was just commented I dunno why, bruh)
### Bug Fixes
- Fixed NativeImage region fill writing wrong color byte order.
- Fixed SoundEngine skipping camera updates before sound engine loads.
- Reverted Mth power-of-two calculation to vanilla.
- Raised ItemInHandRenderer and LightTexture(Lightmaps) mixins priority to avoid conflicts. [#18](https://github.com/Starlevka/Lomka/issues/18)
### Compatibility
- Light texture and light state extraction now use cancellable injects instead of overwrites.
### Removed
- Removed strict mixins: FaceBakery, SpriteContents, PalettedPermutations.
- Removed commented AccessorQuadCollection.
- Lightmap pipeline rewritten — less GPU/CPU allocations per frame.
- PoseStack uses pure
mulPoserotation with cached axis transforms. - Sound buffer library optimized.
- VertexFormat
hashCode()cached. - Lighting coordinate calculations optimized.
- TextureAtlas ported to new rendering API.
- ARGB and Mth math minor optimizations.
## Bug Fixes
- Fixed item in hand rendering desync. ([#15](https://github.com/Starlevka/Lomka/issues/15))
- Fixed mipmap generation issues.
- Fixed Mth math edge cases.
## Removed
- Removed RAM-heavy optimizations (Material and Resource caching).
- Removed incompatible mixins: TextureUtil, MeshData, KeyframeAnimation.
- Chunks load smoother — faster lighting and biome data access.
- FaceSturdy block state caching.
- Bitset shapes create slightly less garbage.
- Refactored more perfomously game calculations.
- Network packets create less garbage.
- No more per-frame allocation for items held by entity.
- Resource packs now free unused mip levels after loading. Saves 10-50 MB RAM.
- Improved faces building (1.21.11+).
## Bug Fixes
- Fixed a rare crash (
NegativeArraySizeException) in world loading. - Fixed lava fog appearing wrong in some camera positions.
- Fixed sound updates being skipped.
- Fixed game crash with Create Fly ([#10](https://github.com/Starlevka/Lomka/issues/10))
## New
- Added **1.21.4** and **1.21.6-1.21.8** support.
## Removed
- Old low-impact and uncareful optimizations to keep the mod cleaner.