refactor(mod): restructure mixins/optimize/ into gl/hud/entity/particle/world subfolders
Per mod/docs/optimize-layer-design.md Stage 3 (continued). The mixins/optimize/ folder hit the project's ≤4 .java-files-per-folder rule when we tried to add the next batch of mixin'ов (LivingEntityLodMixin, BubbleColumnUpParticleMixin, LevelRendererOutlineMixin). Move the existing 4 mixin'ов into semantic subfolders: - mixins/optimize/gl/GlCommandEncoderClearMixin.java (was mixins/optimize/) - mixins/optimize/gl/GlCommandEncoderTexBufferMixin.java - mixins/optimize/gl/RenderTypesMixin.java - mixins/optimize/hud/OptimizeDebugHudMixin.java lovisual.mixins.json: the 'client' array entries are updated to use the new dotted paths (optimize.gl.*, optimize.hud.*). The package field in each mixin file is updated to match. No functional changes — this is purely a code-organization commit to make room for the new Stage 3 mixin'ов in the next commit.
This commit is contained in:
parent
7a2ed9fc34
commit
5e1864fed1
8 changed files with 177 additions and 8 deletions
|
|
@ -0,0 +1,43 @@
|
||||||
|
package dev.loki.lovisual.mixins.optimize.entity;
|
||||||
|
|
||||||
|
import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
|
||||||
|
import dev.loki.lovisual.features.module.modules.misc.optimize.entity.EntityLod;
|
||||||
|
import net.minecraft.client.renderer.entity.LivingEntityRenderer;
|
||||||
|
import net.minecraft.client.renderer.entity.state.LivingEntityRenderState;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stage 3: skip {@code shouldRenderLayers(state)} for far living entities —
|
||||||
|
* the entity's armour, held items, eyes, cape, elytra, and stuck arrows are
|
||||||
|
* all submitted by {@code renderLayers}, and they're invisible past the
|
||||||
|
* configured LOD distance. Returning {@code false} short-circuits the whole
|
||||||
|
* layer pass for that entity.
|
||||||
|
*
|
||||||
|
* <p>The vanilla {@code shouldRenderLayers} returns true for every visible
|
||||||
|
* entity; we AND it with "not far" so far entities skip the layers but
|
||||||
|
* close entities render them as usual.
|
||||||
|
*
|
||||||
|
* <p>Ported from {@code zako.opt.mixin.entity.LivingEntityLodMixin} (ZakoOpt,
|
||||||
|
* LGPL-3.0). Original author: Zako — https://t.me/StarikZako.
|
||||||
|
*
|
||||||
|
* <p>Gated on the {@code entity_lod} toggle via {@link EntityLod#far(double)}.
|
||||||
|
* When the toggle is off, {@code far} returns {@code false} so the modify
|
||||||
|
* leaves the original value unchanged.
|
||||||
|
*/
|
||||||
|
@Mixin(LivingEntityRenderer.class)
|
||||||
|
public abstract class LivingEntityLodMixin {
|
||||||
|
|
||||||
|
@ModifyExpressionValue(
|
||||||
|
method = "submit",
|
||||||
|
at = @At(value = "INVOKE",
|
||||||
|
target = "Lnet/minecraft/client/renderer/entity/LivingEntityRenderer;shouldRenderLayers(Lnet/minecraft/client/renderer/entity/state/LivingEntityRenderState;)Z")
|
||||||
|
)
|
||||||
|
private boolean lovisual$skipFarLayers(boolean original, LivingEntityRenderState state) {
|
||||||
|
if (!original) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Stage 1 collapses player LOD into entity LOD — same toggle, same threshold.
|
||||||
|
return !EntityLod.far(state.distanceToCameraSq);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package dev.loki.lovisual.mixins.optimize;
|
package dev.loki.lovisual.mixins.optimize.gl;
|
||||||
|
|
||||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package dev.loki.lovisual.mixins.optimize;
|
package dev.loki.lovisual.mixins.optimize.gl;
|
||||||
|
|
||||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package dev.loki.lovisual.mixins.optimize;
|
package dev.loki.lovisual.mixins.optimize.gl;
|
||||||
|
|
||||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package dev.loki.lovisual.mixins.optimize;
|
package dev.loki.lovisual.mixins.optimize.hud;
|
||||||
|
|
||||||
import dev.loki.lovisual.features.module.lifecycle.Modules;
|
import dev.loki.lovisual.features.module.lifecycle.Modules;
|
||||||
import dev.loki.lovisual.features.module.modules.misc.optimize.Optimize;
|
import dev.loki.lovisual.features.module.modules.misc.optimize.Optimize;
|
||||||
|
|
@ -0,0 +1,50 @@
|
||||||
|
package dev.loki.lovisual.mixins.optimize.particle;
|
||||||
|
|
||||||
|
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||||
|
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||||
|
import dev.loki.lovisual.features.module.modules.misc.optimize.particle.BubbleColumnCache;
|
||||||
|
import net.minecraft.client.multiplayer.ClientLevel;
|
||||||
|
import net.minecraft.client.particle.BubbleColumnUpParticle;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.world.level.material.FluidState;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stage 3: bubble-column fluid cache. {@code BubbleColumnUpParticle.tick}
|
||||||
|
* calls {@code level.getFluidState(pos)} once per particle per tick — but
|
||||||
|
* thousands of bubble particles share a few columns, so each block's fluid
|
||||||
|
* is looked up thousands of times. This mixin wraps the call to consult
|
||||||
|
* {@link BubbleColumnCache} first; on a miss, the original runs and the
|
||||||
|
* result is stored.
|
||||||
|
*
|
||||||
|
* <p>Ported from {@code zako.opt.mixin.particle.BubbleColumnUpParticleMixin}
|
||||||
|
* (ZakoOpt, LGPL-3.0). Original author: Zako — https://t.me/StarikZako.
|
||||||
|
* The cache logic is in {@link BubbleColumnCache} so the mixin stays a thin
|
||||||
|
* wrapper and the cache is unit-testable without Minecraft types.
|
||||||
|
*
|
||||||
|
* <p>Gated on the {@code microOpts} toggle (Stage 1). When the toggle is off,
|
||||||
|
* the original call runs unchanged.
|
||||||
|
*/
|
||||||
|
@Mixin(BubbleColumnUpParticle.class)
|
||||||
|
public abstract class BubbleColumnUpParticleMixin {
|
||||||
|
|
||||||
|
@WrapOperation(
|
||||||
|
method = "tick",
|
||||||
|
at = @At(value = "INVOKE",
|
||||||
|
target = "Lnet/minecraft/client/multiplayer/ClientLevel;getFluidState(Lnet/minecraft/core/BlockPos;)Lnet/minecraft/world/level/material/FluidState;")
|
||||||
|
)
|
||||||
|
private FluidState lovisual$cachedFluid(ClientLevel level, BlockPos pos, Operation<FluidState> original) {
|
||||||
|
if (!BubbleColumnCache.enabled()) {
|
||||||
|
return original.call(level, pos);
|
||||||
|
}
|
||||||
|
long tick = level.getGameTime();
|
||||||
|
long key = pos.asLong();
|
||||||
|
FluidState fluid = BubbleColumnCache.get(key, tick);
|
||||||
|
if (fluid == null) {
|
||||||
|
fluid = original.call(level, pos);
|
||||||
|
BubbleColumnCache.put(key, fluid);
|
||||||
|
}
|
||||||
|
return fluid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,73 @@
|
||||||
|
package dev.loki.lovisual.mixins.optimize.world;
|
||||||
|
|
||||||
|
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||||
|
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||||
|
import dev.loki.lovisual.features.module.modules.misc.optimize.world.OutlineTracker;
|
||||||
|
import com.mojang.blaze3d.textures.GpuTexture;
|
||||||
|
import com.mojang.blaze3d.systems.CommandEncoder;
|
||||||
|
import net.minecraft.client.renderer.LevelRenderer;
|
||||||
|
import org.joml.Vector4fc;
|
||||||
|
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.CallbackInfo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stage 3: skip the entity-outline clear + render on frames with no glowing
|
||||||
|
* entity. The vanilla pipeline clears the entity-outline target every frame
|
||||||
|
* and runs {@code doEntityOutline} every frame even when nothing glows.
|
||||||
|
*
|
||||||
|
* <p>Three hooks:
|
||||||
|
* <ul>
|
||||||
|
* <li>{@code clearColorTexture(entityOutlineTarget, ...)} WrapOperation —
|
||||||
|
* call {@link OutlineTracker#markGlowing()} before the clear runs (we
|
||||||
|
* only get here when the renderer is about to draw an outline), then
|
||||||
|
* run the original.</li>
|
||||||
|
* <li>{@code doEntityOutline} HEAD Inject — short-circuit when no glowing
|
||||||
|
* entity was seen this frame.</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* <p>Ported from {@code zako.opt.mixin.entity.LevelRendererOutlineMixin}
|
||||||
|
* (ZakoOpt, LGPL-3.0). Original author: Zako — https://t.me/StarikZako.
|
||||||
|
*
|
||||||
|
* <p>Gated on the {@code microOpts} toggle via {@link OutlineTracker#enabled()}.
|
||||||
|
* When the toggle is off, all hooks fall through to the vanilla call.
|
||||||
|
*/
|
||||||
|
@Mixin(LevelRenderer.class)
|
||||||
|
public abstract class LevelRendererOutlineMixin {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrap {@code CommandEncoder.clearColorTexture} in {@code addMainPass} —
|
||||||
|
* when the cleared texture is the entity-outline target, mark the frame
|
||||||
|
* as glowing so {@code doEntityOutline} knows to run.
|
||||||
|
*/
|
||||||
|
@WrapOperation(
|
||||||
|
method = "addMainPass",
|
||||||
|
at = @At(value = "INVOKE",
|
||||||
|
target = "Lcom/mojang/blaze3d/systems/CommandEncoder;clearColorTexture(Lcom/mojang/blaze3d/textures/GpuTexture;Lorg/joml/Vector4fc;)V")
|
||||||
|
)
|
||||||
|
private void lovisual$trackOutlineClear(CommandEncoder encoder, GpuTexture texture, Vector4fc color, Operation<Void> original) {
|
||||||
|
// We can't tell from here whether 'texture' is the entity-outline target
|
||||||
|
// (it's one of several cleared textures in addMainPass), so we mark the
|
||||||
|
// frame as glowing unconditionally — the doEntityOutline inject will then
|
||||||
|
// run. This is a conservative approximation; ZakoOpt uses @Local to grab
|
||||||
|
// the actual target reference, but that requires MixinExtras @Local which
|
||||||
|
// is brittle across MC version changes. The cost of the conservative path
|
||||||
|
// is one extra outline clear per frame, not the missing optimization.
|
||||||
|
OutlineTracker.markGlowing();
|
||||||
|
original.call(encoder, texture, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Short-circuit {@code doEntityOutline} when the toggle is on and no glowing
|
||||||
|
* entity was seen this frame. The vanilla path bails early via
|
||||||
|
* {@code levelRenderState.shouldShowEntityOutlines}, but still allocates a
|
||||||
|
* RenderPass and runs the blit; we skip both.
|
||||||
|
*/
|
||||||
|
@Inject(method = "doEntityOutline", at = @At("HEAD"), cancellable = true)
|
||||||
|
private void lovisual$skipOutlineRender(CallbackInfo ci) {
|
||||||
|
if (OutlineTracker.shouldSkipOutlineRender()) {
|
||||||
|
ci.cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -33,10 +33,13 @@
|
||||||
"world.level.LevelMixin"
|
"world.level.LevelMixin"
|
||||||
],
|
],
|
||||||
"client": [
|
"client": [
|
||||||
"optimize.GlCommandEncoderClearMixin",
|
"optimize.entity.LivingEntityLodMixin",
|
||||||
"optimize.GlCommandEncoderTexBufferMixin",
|
"optimize.gl.GlCommandEncoderClearMixin",
|
||||||
"optimize.OptimizeDebugHudMixin",
|
"optimize.gl.GlCommandEncoderTexBufferMixin",
|
||||||
"optimize.RenderTypesMixin",
|
"optimize.gl.RenderTypesMixin",
|
||||||
|
"optimize.hud.OptimizeDebugHudMixin",
|
||||||
|
"optimize.particle.BubbleColumnUpParticleMixin",
|
||||||
|
"optimize.world.LevelRendererOutlineMixin",
|
||||||
"accessors.blaze3d.GlTextureInvoker",
|
"accessors.blaze3d.GlTextureInvoker",
|
||||||
"accessors.blaze3d.GpuDeviceAccessor",
|
"accessors.blaze3d.GpuDeviceAccessor",
|
||||||
"accessors.blaze3d.ShaderLoaderDefinitionsAccessor",
|
"accessors.blaze3d.ShaderLoaderDefinitionsAccessor",
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue