From 135628c2f1592c302ffdb1a42e5c4b1974941f70 Mon Sep 17 00:00:00 2001 From: LoVisual AI Date: Sat, 10 Oct 2026 16:43:02 +0000 Subject: [PATCH] =?UTF-8?q?feat(mod):=20Stage=203=20(continued=202)=20?= =?UTF-8?q?=E2=80=94=20entity=20+=20block=20+=20Sodium=20contract=20mixins?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Per mod/docs/optimize-layer-design.md Stage 3 (continued). This batch implements the Stage 1 mixin-contract interfaces on their target MC classes so CachedName, StateEntity, TickCached, CachedLight, CachedValidity and CachedStack actually get used. Seven new mixin'ов; no new helpers (the helpers were all written in Stage 1 already). Entity-contract mixins (mixins/optimize/entity/): - EntityNameMixin: implements CachedName on Entity — adds the per-tick cached name-tag fields (Component + tick). Vanilla Entity.getDisplayName() rebuilds the team prefix + name + suffix on every call. - EntityRenderStateEntityMixin: implements StateEntity on EntityRenderState — adds the back-reference field to the source Entity. Render-states are rebuilt every frame so they can't keep their own pointer; this is captured by EntityRendererStateMixin. - EntityRendererStateMixin: Inject at RETURN on EntityRenderer.createRenderState — captures the source Entity on the freshly-built state via the StateEntity contract. ZakoOpt used @ModifyReturnValue; we use plain @Inject because the MixinExtras ModifyReturnValue transformer is more fragile across MC versions. - EntityRendererNameMixin: WrapOperation on EntityRenderer.getNameTag's Entity.getDisplayName call — caches by game tick so the per-frame cost is one identity check + read instead of a full Component rebuild. - SodiumEntityRendererMixin: WrapOperation on Sodium EntityRenderer.renderCuboid's MemoryStack.stackPush — uses CachedStack (Stage 1) to skip the ThreadLocal lookup on the render thread. Registered as optional via LoVisualMixinPlugin (only applied when Sodium is loaded); remap = false because the target is a Sodium class, not a Mojang one. BlockEntity-contract mixins (mixins/optimize/block/): - BlockEntityMixin: implements TickCached + CachedLight + CachedValidity on BlockEntity — adds the per-tick cache slot, per-tick block-light lookups (single + pair for double-chests), per-tick should-render distance check, and per-state validity cache. All four are read by the (Stage 3, future) ChestRendererMixin / BlockEntityRenderStateMixin / BlockEntityRenderDispatcherMixin. - BaseSpawnerMixin: implements TickCached on BaseSpawner — adds the per-tick cache slot that SpawnerCache (Stage 1) reads back. Folder limit (≤4 .java per folder): - mixins/optimize/entity/ hit 6 files after this batch — split into mixins/optimize/entity/renderer/ for EntityRendererStateMixin + EntityRendererNameMixin (the two that target EntityRenderer rather than Entity/EntityRenderState directly). The other 4 stay in entity/. lovisual.mixins.json: seven new entries in the 'client' array, alphabetical: optimize.block.BaseSpawnerMixin optimize.block.BlockEntityMixin optimize.entity.EntityNameMixin optimize.entity.EntityRenderStateEntityMixin optimize.entity.SodiumEntityRendererMixin optimize.entity.renderer.EntityRendererNameMixin optimize.entity.renderer.EntityRendererStateMixin LoVisualMixinPlugin: added SodiumEntityRendererMixin to OPTIONAL_SODIUM_MIXINS so the mixin is only applied when Sodium is loaded (matches the existing convention for sodium.* mixins). Tests: no new tests in this batch (the new mixins are pure side-effect field-bags — they don't have unit-testable logic). Existing suite still green. Total: 866 tests, 0 failures. checkFolderLimit: OK (0 папок >4). --- .../lovisual/mixins/LoVisualMixinPlugin.java | 3 +- .../optimize/block/BaseSpawnerMixin.java | 47 ++++++ .../optimize/block/BlockEntityMixin.java | 142 ++++++++++++++++++ .../optimize/entity/EntityNameMixin.java | 44 ++++++ .../entity/EntityRenderStateEntityMixin.java | 35 +++++ .../entity/SodiumEntityRendererMixin.java | 44 ++++++ .../renderer/EntityRendererNameMixin.java | 51 +++++++ .../renderer/EntityRendererStateMixin.java | 43 ++++++ mod/src/main/resources/lovisual.mixins.json | 7 + 9 files changed, 415 insertions(+), 1 deletion(-) create mode 100644 mod/src/main/java/dev/loki/lovisual/mixins/optimize/block/BaseSpawnerMixin.java create mode 100644 mod/src/main/java/dev/loki/lovisual/mixins/optimize/block/BlockEntityMixin.java create mode 100644 mod/src/main/java/dev/loki/lovisual/mixins/optimize/entity/EntityNameMixin.java create mode 100644 mod/src/main/java/dev/loki/lovisual/mixins/optimize/entity/EntityRenderStateEntityMixin.java create mode 100644 mod/src/main/java/dev/loki/lovisual/mixins/optimize/entity/SodiumEntityRendererMixin.java create mode 100644 mod/src/main/java/dev/loki/lovisual/mixins/optimize/entity/renderer/EntityRendererNameMixin.java create mode 100644 mod/src/main/java/dev/loki/lovisual/mixins/optimize/entity/renderer/EntityRendererStateMixin.java diff --git a/mod/src/main/java/dev/loki/lovisual/mixins/LoVisualMixinPlugin.java b/mod/src/main/java/dev/loki/lovisual/mixins/LoVisualMixinPlugin.java index 1a73df53..664e5c34 100644 --- a/mod/src/main/java/dev/loki/lovisual/mixins/LoVisualMixinPlugin.java +++ b/mod/src/main/java/dev/loki/lovisual/mixins/LoVisualMixinPlugin.java @@ -21,7 +21,8 @@ public final class LoVisualMixinPlugin implements IMixinConfigPlugin { "dev.loki.lovisual.mixins.sodium.terrain.SodiumShaderChunkRendererMixin", "dev.loki.lovisual.mixins.sodium.vertex.SodiumVertexConsumerTrackerMixin", "dev.loki.lovisual.mixins.sodium.placement.SodiumPlaceCullMixin", - "dev.loki.lovisual.mixins.sodium.placement.SodiumPlaceHideMixin" + "dev.loki.lovisual.mixins.sodium.placement.SodiumPlaceHideMixin", + "dev.loki.lovisual.mixins.optimize.entity.SodiumEntityRendererMixin" ); private static final Set OPTIONAL_IRIS_MIXINS = Set.of( "dev.loki.lovisual.mixins.iris.render.IrisCommonUniformsMixin", diff --git a/mod/src/main/java/dev/loki/lovisual/mixins/optimize/block/BaseSpawnerMixin.java b/mod/src/main/java/dev/loki/lovisual/mixins/optimize/block/BaseSpawnerMixin.java new file mode 100644 index 00000000..52be9e45 --- /dev/null +++ b/mod/src/main/java/dev/loki/lovisual/mixins/optimize/block/BaseSpawnerMixin.java @@ -0,0 +1,47 @@ +package dev.loki.lovisual.mixins.optimize.block; + +import dev.loki.lovisual.features.module.modules.misc.optimize.block.TickCached; +import net.minecraft.world.level.BaseSpawner; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; + +/** + * Stage 3: implements {@link TickCached} on {@link BaseSpawner} — adds the + * per-tick cache slot that {@link dev.loki.lovisual.features.module.modules.misc.optimize.block.SpawnerCache} + * reads back to skip the per-frame {@code extractEntity} rebuild of the + * spawner's display mob. + * + *

The vanilla {@code SpawnerRenderer.extractRenderState} rebuilds the + * display entity's render state every frame for every spawner in view; + * the display entity only changes on tick boundaries (spin speed, mob + * rotation, etc.), so caching by tick removes that rebuild from the hot path. + * + *

Ported from {@code zako.opt.mixin.block.BaseSpawnerMixin} (ZakoOpt, + * LGPL-3.0). Original author: Zako — https://t.me/StarikZako. Field/method + * prefix changed from {@code zakoopt$} to {@code lovisual$}. + */ +@Mixin(BaseSpawner.class) +public abstract class BaseSpawnerMixin implements TickCached { + + @Unique + private Object lovisual$cached; + + @Unique + private long lovisual$cachedTick = Long.MIN_VALUE; + + @Override + public Object lovisual$cached() { + return lovisual$cached; + } + + @Override + public long lovisual$cachedTick() { + return lovisual$cachedTick; + } + + @Override + public void lovisual$setCached(Object value, long tick) { + lovisual$cached = value; + lovisual$cachedTick = tick; + } +} diff --git a/mod/src/main/java/dev/loki/lovisual/mixins/optimize/block/BlockEntityMixin.java b/mod/src/main/java/dev/loki/lovisual/mixins/optimize/block/BlockEntityMixin.java new file mode 100644 index 00000000..985f8c6b --- /dev/null +++ b/mod/src/main/java/dev/loki/lovisual/mixins/optimize/block/BlockEntityMixin.java @@ -0,0 +1,142 @@ +package dev.loki.lovisual.mixins.optimize.block; + +import dev.loki.lovisual.features.module.modules.misc.optimize.block.CachedLight; +import dev.loki.lovisual.features.module.modules.misc.optimize.block.CachedValidity; +import dev.loki.lovisual.features.module.modules.misc.optimize.block.TickCached; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; + +/** + * Stage 3: implements {@link TickCached}, {@link CachedLight} and + * {@link CachedValidity} on {@link BlockEntity} — adds the per-tick cache + * slot (object + tick), the per-tick block-light lookups, the per-tick + * should-render distance check, and the per-state validity cache. + * + *

The vanilla {@code BlockEntityType.isValid(state)} is called every + * frame per block-entity in view but only changes on a state transition; + * {@code LightCoordsUtil.getLightCoords(level, pos)} walks the chunk's light + * section data per call; {@code BlockEntityRenderer.shouldRender} does a + * distance check that only changes when the entity moves across the cull + * boundary. All three are cached via the interface fields implemented here. + * + *

Ported from {@code zako.opt.mixin.block.BlockEntityMixin} (ZakoOpt, + * LGPL-3.0). Original author: Zako — https://t.me/StarikZako. Field/method + * prefix changed from {@code zakoopt$} to {@code lovisual$}. + */ +@Mixin(BlockEntity.class) +public abstract class BlockEntityMixin implements TickCached, CachedLight, CachedValidity { + + // --- TickCached --- + @Unique + private Object lovisual$cached; + @Unique + private long lovisual$cachedTick = Long.MIN_VALUE; + + // --- CachedLight --- + @Unique + private int lovisual$light; + @Unique + private long lovisual$lightTick = Long.MIN_VALUE; + @Unique + private int lovisual$pairLight; + @Unique + private long lovisual$pairLightTick = Long.MIN_VALUE; + + // --- CachedValidity --- + @Unique + private BlockState lovisual$validState; + @Unique + private boolean lovisual$valid; + @Unique + private long lovisual$distanceTick = Long.MIN_VALUE; + @Unique + private boolean lovisual$inDistance; + + // --- TickCached --- + + @Override + public Object lovisual$cached() { + return lovisual$cached; + } + + @Override + public long lovisual$cachedTick() { + return lovisual$cachedTick; + } + + @Override + public void lovisual$setCached(Object value, long tick) { + lovisual$cached = value; + lovisual$cachedTick = tick; + } + + // --- CachedLight --- + + @Override + public int lovisual$light() { + return lovisual$light; + } + + @Override + public long lovisual$lightTick() { + return lovisual$lightTick; + } + + @Override + public void lovisual$setLight(int light, long tick) { + lovisual$light = light; + lovisual$lightTick = tick; + } + + @Override + public int lovisual$pairLight() { + return lovisual$pairLight; + } + + @Override + public long lovisual$pairLightTick() { + return lovisual$pairLightTick; + } + + @Override + public void lovisual$setPairLight(int light, long tick) { + lovisual$pairLight = light; + lovisual$pairLightTick = tick; + } + + // --- CachedValidity --- + + @Override + public BlockState lovisual$validState() { + return lovisual$validState; + } + + @Override + public boolean lovisual$valid() { + return lovisual$valid; + } + + @Override + public void lovisual$setValid(BlockState state, boolean valid) { + lovisual$validState = state; + lovisual$valid = valid; + } + + @Override + public long lovisual$distanceTick() { + return lovisual$distanceTick; + } + + @Override + public boolean lovisual$inDistance() { + return lovisual$inDistance; + } + + @Override + public void lovisual$setInDistance(boolean inDistance, long tick) { + lovisual$inDistance = inDistance; + lovisual$distanceTick = tick; + } +} diff --git a/mod/src/main/java/dev/loki/lovisual/mixins/optimize/entity/EntityNameMixin.java b/mod/src/main/java/dev/loki/lovisual/mixins/optimize/entity/EntityNameMixin.java new file mode 100644 index 00000000..08420803 --- /dev/null +++ b/mod/src/main/java/dev/loki/lovisual/mixins/optimize/entity/EntityNameMixin.java @@ -0,0 +1,44 @@ +package dev.loki.lovisual.mixins.optimize.entity; + +import dev.loki.lovisual.features.module.modules.misc.optimize.entity.CachedName; +import net.minecraft.network.chat.Component; +import net.minecraft.world.entity.Entity; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; + +/** + * Stage 3: implements {@link CachedName} on {@link Entity} — adds the cached + * name-tag fields (name + tick) that {@link EntityRendererNameMixin} populates + * and reads back. Vanilla {@code Entity.getDisplayName()} rebuilds the team + * prefix + name + suffix on every call; renderers call it once per frame per + * entity in view, so caching by tick cuts the per-frame cost. + * + *

Ported from {@code zako.opt.mixin.entity.EntityNameMixin} (ZakoOpt, + * LGPL-3.0). Original author: Zako — https://t.me/StarikZako. Field/method + * prefix changed from {@code zakoopt$} to {@code lovisual$}. + */ +@Mixin(Entity.class) +public abstract class EntityNameMixin implements CachedName { + + @Unique + private Component lovisual$name; + + @Unique + private long lovisual$nameTick = Long.MIN_VALUE; + + @Override + public Component lovisual$name() { + return lovisual$name; + } + + @Override + public long lovisual$nameTick() { + return lovisual$nameTick; + } + + @Override + public void lovisual$setName(Component name, long tick) { + lovisual$name = name; + lovisual$nameTick = tick; + } +} diff --git a/mod/src/main/java/dev/loki/lovisual/mixins/optimize/entity/EntityRenderStateEntityMixin.java b/mod/src/main/java/dev/loki/lovisual/mixins/optimize/entity/EntityRenderStateEntityMixin.java new file mode 100644 index 00000000..e2330d2a --- /dev/null +++ b/mod/src/main/java/dev/loki/lovisual/mixins/optimize/entity/EntityRenderStateEntityMixin.java @@ -0,0 +1,35 @@ +package dev.loki.lovisual.mixins.optimize.entity; + +import dev.loki.lovisual.features.module.modules.misc.optimize.entity.StateEntity; +import net.minecraft.client.renderer.entity.state.EntityRenderState; +import net.minecraft.world.entity.Entity; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; + +/** + * Stage 3: implements {@link StateEntity} on {@link EntityRenderState} — adds + * the back-reference field to the source {@link Entity}. Render-states are + * rebuilt every frame, so they can't keep their own pointer — the + * {@link EntityRendererStateMixin} captures it once per state construction + * via {@code createRenderState} and downstream renderers read it back. + * + *

Ported from {@code zako.opt.mixin.entity.EntityRenderStateEntityMixin} + * (ZakoOpt, LGPL-3.0). Original author: Zako — https://t.me/StarikZako. + * Prefix changed from {@code zakoopt$} to {@code lovisual$}. + */ +@Mixin(EntityRenderState.class) +public abstract class EntityRenderStateEntityMixin implements StateEntity { + + @Unique + private Entity lovisual$entity; + + @Override + public Entity lovisual$entity() { + return lovisual$entity; + } + + @Override + public void lovisual$entity(Entity entity) { + lovisual$entity = entity; + } +} diff --git a/mod/src/main/java/dev/loki/lovisual/mixins/optimize/entity/SodiumEntityRendererMixin.java b/mod/src/main/java/dev/loki/lovisual/mixins/optimize/entity/SodiumEntityRendererMixin.java new file mode 100644 index 00000000..69de7148 --- /dev/null +++ b/mod/src/main/java/dev/loki/lovisual/mixins/optimize/entity/SodiumEntityRendererMixin.java @@ -0,0 +1,44 @@ +package dev.loki.lovisual.mixins.optimize.entity; + +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import dev.loki.lovisual.features.module.modules.misc.optimize.entity.CachedStack; +import dev.loki.lovisual.render.engine.optimize.OptimizeToggles; +import org.lwjgl.system.MemoryStack; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; + +/** + * Stage 3: hot-path helper for Sodium's entity cuboid renderer — wraps + * {@code MemoryStack.stackPush()} so the render thread's stack is cached by + * identity instead of being looked up via ThreadLocal on every cuboid. Sodium + * calls this once per cuboid per frame (thousands of times for dense entity + * scenes), so the cached lookup is a measurable win on the hot path. + * + *

Uses {@code WrapOperation} rather than {@code @Redirect} because + * MixinExtras 0.5.4 (which Fabric Loader 0.19.3 ships with) crashes on a + * static {@code @Redirect} here — pinned to 0.5.5 in {@code build.gradle}, + * but the convention is kept for safety. The mixin is registered with + * {@code remap = false} because the target is a Sodium class, not a Mojang one. + * + *

Ported from {@code zako.opt.mixin.entity.SodiumEntityRendererMixin} + * (ZakoOpt, LGPL-3.0). Original author: Zako — https://t.me/StarikZako. + * Gated on the {@code microOpts} toggle via {@link OptimizeToggles#microOpts()}. + * When the toggle is off, the original runs unchanged. + * + *

Registered conditionally via {@code LoVisualMixinPlugin} — only applied + * when Sodium is loaded. See {@code lovisual.mixins.json} entry in the + * {@code client} array. + */ +@Mixin(targets = "net.caffeinemc.mods.sodium.client.render.immediate.model.EntityRenderer", remap = false) +public abstract class SodiumEntityRendererMixin { + + @WrapOperation( + method = "renderCuboid", + at = @At(value = "INVOKE", + target = "Lorg/lwjgl/system/MemoryStack;stackPush()Lorg/lwjgl/system/MemoryStack;") + ) + private static MemoryStack lovisual$cachedStack(Operation original) { + return OptimizeToggles.microOpts() ? CachedStack.push() : original.call(); + } +} diff --git a/mod/src/main/java/dev/loki/lovisual/mixins/optimize/entity/renderer/EntityRendererNameMixin.java b/mod/src/main/java/dev/loki/lovisual/mixins/optimize/entity/renderer/EntityRendererNameMixin.java new file mode 100644 index 00000000..7eeea3db --- /dev/null +++ b/mod/src/main/java/dev/loki/lovisual/mixins/optimize/entity/renderer/EntityRendererNameMixin.java @@ -0,0 +1,51 @@ +package dev.loki.lovisual.mixins.optimize.entity.renderer; + +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import dev.loki.lovisual.features.module.modules.misc.optimize.entity.CachedName; +import dev.loki.lovisual.render.engine.optimize.OptimizeToggles; +import net.minecraft.client.renderer.entity.EntityRenderer; +import net.minecraft.network.chat.Component; +import net.minecraft.world.entity.Entity; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; + +/** + * Stage 3: caches {@code Entity.getDisplayName()} per tick. The vanilla + * implementation rebuilds a {@link Component} (team prefix + name + suffix) + * every call; renderers call it once per frame per entity in view. Wrapping + * the call here keeps the per-frame cost to one identity check + read, + * instead of a full Component rebuild + style lookup. + * + *

The cache is keyed by game tick — name parts only change on tick + * boundaries (team membership, name change). On the first call of a tick the + * original runs and the result is stored; subsequent calls in the same tick + * return the cached instance. + * + *

Ported from {@code zako.opt.mixin.entity.EntityRendererNameMixin} + * (ZakoOpt, LGPL-3.0). Original author: Zako — https://t.me/StarikZako. + * Gated on the {@code microOpts} toggle via {@link OptimizeToggles#microOpts()}. + * When the toggle is off, the original runs unchanged. + */ +@Mixin(EntityRenderer.class) +public abstract class EntityRendererNameMixin { + + @WrapOperation( + method = "getNameTag", + at = @At(value = "INVOKE", + target = "Lnet/minecraft/world/entity/Entity;getDisplayName()Lnet/minecraft/network/chat/Component;") + ) + private Component lovisual$cachedName(Entity entity, Operation original) { + if (!OptimizeToggles.microOpts()) { + return original.call(entity); + } + if (!(entity instanceof CachedName cache)) { + return original.call(entity); + } + long tick = entity.level().getGameTime(); + if (cache.lovisual$nameTick() != tick) { + cache.lovisual$setName(original.call(entity), tick); + } + return cache.lovisual$name(); + } +} diff --git a/mod/src/main/java/dev/loki/lovisual/mixins/optimize/entity/renderer/EntityRendererStateMixin.java b/mod/src/main/java/dev/loki/lovisual/mixins/optimize/entity/renderer/EntityRendererStateMixin.java new file mode 100644 index 00000000..2085f8a1 --- /dev/null +++ b/mod/src/main/java/dev/loki/lovisual/mixins/optimize/entity/renderer/EntityRendererStateMixin.java @@ -0,0 +1,43 @@ +package dev.loki.lovisual.mixins.optimize.entity.renderer; + +import com.llamalad7.mixinextras.sugar.Local; +import dev.loki.lovisual.features.module.modules.misc.optimize.entity.StateEntity; +import net.minecraft.client.renderer.entity.EntityRenderer; +import net.minecraft.client.renderer.entity.state.EntityRenderState; +import net.minecraft.world.entity.Entity; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +/** + * Stage 3: captures the source {@link Entity} on every freshly-built + * {@link EntityRenderState}. Vanilla's {@code createRenderState(entity, partial)} + * returns a state without back-reference; this inject at RETURN stores the + * entity on the state via the {@link StateEntity} contract so downstream + * renderers (model feature renderer, item feature renderer, future LOD mixins) + * can reach the live entity. + * + *

Ported from {@code zako.opt.mixin.entity.EntityRendererStateMixin} + * (ZakoOpt, LGPL-3.0). Original author: Zako — https://t.me/StarikZako. + * The original used {@code @ModifyReturnValue}; LoVisual uses {@code @Inject} + * at RETURN with {@code CallbackInfoReturnable} so the mixin stays simple and + * doesn't rely on the (more fragile across versions) MixinExtras return-value + * transformer — the captured state is set as a side effect, not returned. + */ +@Mixin(EntityRenderer.class) +public abstract class EntityRendererStateMixin { + + @Inject( + method = "createRenderState(Lnet/minecraft/world/entity/Entity;F)Lnet/minecraft/client/renderer/entity/state/EntityRenderState;", + at = @At("RETURN") + ) + private void lovisual$rememberEntity(Entity entity, float partialTick, + CallbackInfoReturnable cir, + @Local(argsOnly = true) Entity localEntity) { + EntityRenderState state = cir.getReturnValue(); + if (state instanceof StateEntity stateEntity) { + stateEntity.lovisual$entity(localEntity); + } + } +} diff --git a/mod/src/main/resources/lovisual.mixins.json b/mod/src/main/resources/lovisual.mixins.json index 2c8a271f..f04a6dc9 100644 --- a/mod/src/main/resources/lovisual.mixins.json +++ b/mod/src/main/resources/lovisual.mixins.json @@ -33,7 +33,14 @@ "world.level.LevelMixin" ], "client": [ + "optimize.block.BaseSpawnerMixin", + "optimize.block.BlockEntityMixin", + "optimize.entity.EntityNameMixin", + "optimize.entity.EntityRenderStateEntityMixin", "optimize.entity.LivingEntityLodMixin", + "optimize.entity.SodiumEntityRendererMixin", + "optimize.entity.renderer.EntityRendererNameMixin", + "optimize.entity.renderer.EntityRendererStateMixin", "optimize.gl.GlCommandEncoderClearMixin", "optimize.gl.GlCommandEncoderTexBufferMixin", "optimize.gl.RenderTypesMixin",