diff --git a/build.gradle.kts b/build.gradle.kts index f2fd2347f..ef77a9015 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -30,8 +30,6 @@ val discordIPCVersion: String by project val classGraphVersion: String by project val kotlinVersion: String by project val ktorVersion: String by project -val mockitoKotlin: String by project -val mockitoInline: String by project val mockkVersion: String by project val spairVersion: String by project val lwjglVersion: String by project @@ -46,10 +44,10 @@ val replacements = file("gradle.properties").inputStream().use { stream -> }.map { (k, v) -> k.toString() to v.toString() }.toMap() plugins { - kotlin("jvm") version "2.2.0" - id("org.jetbrains.dokka") version "2.0.0" - id("fabric-loom") version "1.10-SNAPSHOT" - id("com.gradleup.shadow") version "9.0.0-rc1" + kotlin("jvm") version "2.3.0" + id("org.jetbrains.dokka") version "2.1.0" + id("fabric-loom") version "1.14-SNAPSHOT" + id("com.gradleup.shadow") version "9.3.0" id("maven-publish") } @@ -151,6 +149,8 @@ dependencies { // Fabric modImplementation("net.fabricmc:fabric-loader:$fabricLoaderVersion") modImplementation("net.fabricmc.fabric-api:fabric-api:$fabricApiVersion+$minecraftVersion") + // Explicit dependency on fabric-renderer-indigo for mixin access to internal classes + modCompileOnly("net.fabricmc.fabric-api:fabric-renderer-indigo:4.1.4+1af5c5a75f") modImplementation("net.fabricmc:fabric-language-kotlin:$kotlinFabricVersion.$kotlinVersion") // Add dependencies on the required Kotlin modules. @@ -175,7 +175,7 @@ dependencies { includeLib("io.ktor:ktor-serialization-gson:$ktorVersion") // Add mods - modImplementation("com.github.rfresh2:baritone-fabric:$minecraftVersion") + modCompileOnly("com.github.rfresh2:baritone-fabric:$minecraftVersion-SNAPSHOT") modCompileOnly("maven.modrinth:sodium:$sodiumVersion") modCompileOnly("maven.modrinth:malilib:$maLiLibVersion") modCompileOnly("maven.modrinth:litematica:$litematicaVersion") @@ -185,8 +185,6 @@ dependencies { // Test implementations testImplementation(kotlin("test")) - testImplementation("org.mockito.kotlin:mockito-kotlin:$mockitoKotlin") - testImplementation("org.mockito:mockito-inline:$mockitoInline") testImplementation("io.mockk:mockk:${mockkVersion}") // Finish the configuration diff --git a/gradle.properties b/gradle.properties index 1cc5bebd7..cbcea68f1 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,31 +25,29 @@ mavenGroup=com.lambda modAuthors=Constructor (Avanatiker), Blade, beanbag44, Emy # General -minecraftVersion=1.21.5 -minecraftVersionMin=1.21.5 -minecraftVersionMax=1.21.6 +minecraftVersion=1.21.11 +minecraftVersionMin=1.21.11 +minecraftVersionMax=1.21.11 lwjglVersion=3.3.3 -mixinExtrasVersion=0.5.0-rc.2 -kotlinVersion=2.2.0 +mixinExtrasVersion=0.5.0 +kotlinVersion=2.3.0 pngEncoderVersion=0.16.0 javaVersion=21 baritoneVersion=1.14.0 discordIPCVersion=6f6b6cce17 -classGraphVersion=4.8.179 -ktorVersion=3.1.2 -mockitoKotlin=5.4.0 -mockitoInline=5.2.0 -mockkVersion=1.13.17 +classGraphVersion=4.8.184 +ktorVersion=3.3.3 +mockkVersion=1.14.7 spairVersion=1.90.0 # Fabric https://fabricmc.net/develop/ -fabricLoaderVersion=0.16.13 -yarnMappings=build.1 -fabricApiVersion=0.124.0 -kotlinFabricVersion=1.13.4+kotlin -sodiumVersion=mc1.21.5-0.6.13-fabric -litematicaVersion=0.22.2 -maLiLibVersion=0.24.2 +fabricLoaderVersion=0.18.3 +yarnMappings=build.3 +fabricApiVersion=0.139.5 +kotlinFabricVersion=1.13.8+kotlin +sodiumVersion=mc1.21.11-0.8.0-fabric +litematicaVersion=0.25.1 +maLiLibVersion=0.27.1 # Kotlin https://kotlinlang.org/ kotlin.code.style=official diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index c42ddc0c7..3d7f8165b 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -17,7 +17,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/src/main/java/com/lambda/mixin/MinecraftClientMixin.java b/src/main/java/com/lambda/mixin/MinecraftClientMixin.java index 83ec7b6ef..c557264ac 100644 --- a/src/main/java/com/lambda/mixin/MinecraftClientMixin.java +++ b/src/main/java/com/lambda/mixin/MinecraftClientMixin.java @@ -46,6 +46,7 @@ import net.minecraft.util.hit.HitResult; import net.minecraft.util.thread.ThreadExecutor; import org.jetbrains.annotations.Nullable; +import org.objectweb.asm.Opcodes; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Unique; @@ -106,18 +107,18 @@ void onInput(MinecraftClient instance, Operation original) { this.lambda$inputHandledThisTick = true; } - @WrapOperation(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/WorldRenderer;tick()V")) - void onWorldRenderer(WorldRenderer instance, Operation original) { - if (!this.lambda$inputHandledThisTick) { - EventFlow.post(TickEvent.Input.Pre.INSTANCE); - EventFlow.post(TickEvent.Input.Post.INSTANCE); - this.lambda$inputHandledThisTick = true; - } - - EventFlow.post(TickEvent.WorldRender.Pre.INSTANCE); - original.call(instance); - EventFlow.post(TickEvent.WorldRender.Post.INSTANCE); - } +// @WrapOperation(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/WorldRenderer;tick()V")) +// void onWorldRenderer(WorldRenderer instance, Operation original) { +// if (!this.lambda$inputHandledThisTick) { +// EventFlow.post(TickEvent.Input.Pre.INSTANCE); +// EventFlow.post(TickEvent.Input.Post.INSTANCE); +// this.lambda$inputHandledThisTick = true; +// } +// +// EventFlow.post(TickEvent.WorldRender.Pre.INSTANCE); +// original.call(instance); +// EventFlow.post(TickEvent.WorldRender.Post.INSTANCE); +// } @WrapOperation(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/sound/SoundManager;tick(Z)V")) void onSound(SoundManager instance, boolean paused, Operation original) { @@ -134,7 +135,7 @@ private void onShutdown(CallbackInfo ci) { /** * Inject after the thread field is set so that {@link ThreadExecutor#getThread} is available */ - @Inject(at = @At(value = "FIELD", target = "Lnet/minecraft/client/MinecraftClient;thread:Ljava/lang/Thread;", shift = At.Shift.AFTER, ordinal = 0), method = "run") + @Inject(at = @At(value = "FIELD", target = "Lnet/minecraft/client/MinecraftClient;thread:Ljava/lang/Thread;", shift = At.Shift.AFTER, ordinal = 0, opcode = Opcodes.PUTFIELD), method = "run") private void onStartup(CallbackInfo ci) { EventFlow.post(new ClientEvent.Startup()); } diff --git a/src/main/java/com/lambda/mixin/client/sound/SoundSystemMixin.java b/src/main/java/com/lambda/mixin/client/sound/SoundSystemMixin.java index abdbb841d..0df20004e 100644 --- a/src/main/java/com/lambda/mixin/client/sound/SoundSystemMixin.java +++ b/src/main/java/com/lambda/mixin/client/sound/SoundSystemMixin.java @@ -25,13 +25,14 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; @Mixin(SoundSystem.class) public class SoundSystemMixin { - @Inject(method = "play(Lnet/minecraft/client/sound/SoundInstance;)V", at = @At("HEAD"), cancellable = true) - public void onPlay(SoundInstance sound, CallbackInfo ci) { + @Inject(method = "play(Lnet/minecraft/client/sound/SoundInstance;)Lnet/minecraft/client/sound/SoundSystem$PlayResult;", at = @At("HEAD"), cancellable = true) + public void onPlay(SoundInstance sound, CallbackInfoReturnable cir) { if (EventFlow.post(new ClientEvent.Sound(sound)).isCanceled()) { - ci.cancel(); + cir.setReturnValue(SoundSystem.PlayResult.NOT_STARTED); } } } diff --git a/src/main/java/com/lambda/mixin/entity/ClientPlayInteractionManagerMixin.java b/src/main/java/com/lambda/mixin/entity/ClientPlayInteractionManagerMixin.java index 985115054..474f50574 100644 --- a/src/main/java/com/lambda/mixin/entity/ClientPlayInteractionManagerMixin.java +++ b/src/main/java/com/lambda/mixin/entity/ClientPlayInteractionManagerMixin.java @@ -121,9 +121,9 @@ private void cancelBlockBreakingPre(CallbackInfo ci) { if (EventFlow.post(new PlayerEvent.Breaking.Cancel(currentBreakingProgress)).isCanceled()) ci.cancel(); } - @WrapMethod(method = "createPlayer(Lnet/minecraft/client/world/ClientWorld;Lnet/minecraft/stat/StatHandler;Lnet/minecraft/client/recipebook/ClientRecipeBook;ZZ)Lnet/minecraft/client/network/ClientPlayerEntity;") - private ClientPlayerEntity injectCreatePlayer(ClientWorld world, StatHandler statHandler, ClientRecipeBook recipeBook, boolean lastSneaking, boolean lastSprinting, Operation original) { - var player = original.call(world, statHandler, recipeBook, lastSneaking, lastSprinting); + @WrapMethod(method = "createPlayer(Lnet/minecraft/client/world/ClientWorld;Lnet/minecraft/stat/StatHandler;Lnet/minecraft/client/recipebook/ClientRecipeBook;)Lnet/minecraft/client/network/ClientPlayerEntity;") + private ClientPlayerEntity wrapCreatePlayer(ClientWorld world, StatHandler statHandler, ClientRecipeBook recipeBook, Operation original) { + var player = original.call(world, statHandler, recipeBook); InventoryManager.INSTANCE.setScreenHandler(player.playerScreenHandler); return player; } diff --git a/src/main/java/com/lambda/mixin/entity/ClientPlayerEntityMixin.java b/src/main/java/com/lambda/mixin/entity/ClientPlayerEntityMixin.java index 3b5a81c5d..bbb73599b 100644 --- a/src/main/java/com/lambda/mixin/entity/ClientPlayerEntityMixin.java +++ b/src/main/java/com/lambda/mixin/entity/ClientPlayerEntityMixin.java @@ -85,11 +85,6 @@ void sendLambdaMovement(CallbackInfo ci) { autoJumpEnabled = Lambda.getMc().options.getAutoJump().getValue(); } - @WrapOperation(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientPlayerEntity;sendSneakingPacket()V")) - void sendSneakingPacket(ClientPlayerEntity entity, Operation original) { - PlayerPacketHandler.sendSneakPackets(); - } - @ModifyExpressionValue(method = "tickMovement", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientPlayerEntity;isSprinting()Z")) boolean isSprinting(boolean original) { return EventFlow.post(new MovementEvent.Sprint(original)).getSprint(); diff --git a/src/main/java/com/lambda/mixin/entity/LivingEntityMixin.java b/src/main/java/com/lambda/mixin/entity/LivingEntityMixin.java index 74ececd16..e7178fa60 100644 --- a/src/main/java/com/lambda/mixin/entity/LivingEntityMixin.java +++ b/src/main/java/com/lambda/mixin/entity/LivingEntityMixin.java @@ -170,9 +170,9 @@ private float rotHead(LivingEntity entity, Operation original) { return (yaw == null) ? original.call(entity) : yaw; } - @ModifyConstant(method = "getHandSwingDuration", constant = @Constant(intValue = 6)) - private int getHandSwingDuration(int constant) { - if (lambda$instance != Lambda.getMc().player || ViewModel.INSTANCE.isDisabled()) return constant; + @WrapMethod(method = "getHandSwingDuration") + private int getHandSwingDuration(Operation original) { + if (lambda$instance != Lambda.getMc().player || ViewModel.INSTANCE.isDisabled()) return original.call(); return ViewModel.INSTANCE.getSwingDuration(); } diff --git a/src/main/java/com/lambda/mixin/entity/PlayerEntityMixin.java b/src/main/java/com/lambda/mixin/entity/PlayerEntityMixin.java index f6b7eeddc..15acd2497 100644 --- a/src/main/java/com/lambda/mixin/entity/PlayerEntityMixin.java +++ b/src/main/java/com/lambda/mixin/entity/PlayerEntityMixin.java @@ -47,13 +47,13 @@ private float wrapHeadYaw(PlayerEntity instance, Operation original) { return (yaw != null) ? yaw : original.call(instance); } - @WrapOperation(method = "attack", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/player/PlayerEntity;getYaw()F")) - private float wrapAttackYaw(PlayerEntity instance, Operation original) { - if ((Object) this != Lambda.getMc().player) { - return original.call(instance); - } - - Float yaw = RotationManager.getMovementYaw(); - return (yaw != null) ? yaw : original.call(instance); - } +// @WrapOperation(method = "attack", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/player/PlayerEntity;getYaw()F")) +// private float wrapAttackYaw(PlayerEntity instance, Operation original) { +// if ((Object) this != Lambda.getMc().player) { +// return original.call(instance); +// } +// +// Float yaw = RotationManager.getMovementYaw(); +// return (yaw != null) ? yaw : original.call(instance); +// } } diff --git a/src/main/java/com/lambda/mixin/input/KeyBindingMixin.java b/src/main/java/com/lambda/mixin/input/KeyBindingMixin.java index 87b8a524c..1ba526d2a 100644 --- a/src/main/java/com/lambda/mixin/input/KeyBindingMixin.java +++ b/src/main/java/com/lambda/mixin/input/KeyBindingMixin.java @@ -32,7 +32,7 @@ public class KeyBindingMixin { @ModifyReturnValue(method = "isPressed", at = @At("RETURN")) boolean modifyIsPressed(boolean original) { KeyBinding instance = (KeyBinding) (Object) this; - if (!Objects.equals(instance.getTranslationKey(), "key.sprint")) return original; + if (!Objects.equals(instance.getId(), "key.sprint")) return original; if (Sprint.INSTANCE.isEnabled()) return true; if (Speed.INSTANCE.isEnabled() && Speed.getMode() == Speed.Mode.GrimStrafe) return true; diff --git a/src/main/java/com/lambda/mixin/input/KeyboardMixin.java b/src/main/java/com/lambda/mixin/input/KeyboardMixin.java index 3c2368116..027a3edea 100644 --- a/src/main/java/com/lambda/mixin/input/KeyboardMixin.java +++ b/src/main/java/com/lambda/mixin/input/KeyboardMixin.java @@ -23,6 +23,8 @@ import com.llamalad7.mixinextras.injector.wrapmethod.WrapMethod; import com.llamalad7.mixinextras.injector.wrapoperation.Operation; import net.minecraft.client.Keyboard; +import net.minecraft.client.input.CharInput; +import net.minecraft.client.input.KeyInput; import net.minecraft.client.option.KeyBinding; import net.minecraft.client.util.InputUtil; import org.spongepowered.asm.mixin.Mixin; @@ -30,28 +32,36 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +/** + * Mixin to intercept keyboard input events. + * + * Note: In 1.21.11, onKey/onChar methods were refactored to use KeyInput/CharInput records. + * - onKey(long window, int action, KeyInput input) where KeyInput has key, scancode, modifiers + * - onChar(long window, CharInput input) where CharInput has codepoint, modifiers + */ @Mixin(Keyboard.class) public class KeyboardMixin { @WrapMethod(method = "onKey") - private void onKey(long window, int key, int scancode, int action, int modifiers, Operation original) { - EventFlow.post(new KeyboardEvent.Press(key, scancode, action, modifiers)); - original.call(window, key, scancode, action, modifiers); + private void onKey(long window, int action, KeyInput input, Operation original) { + EventFlow.post(new KeyboardEvent.Press(input.key(), input.scancode(), action, input.modifiers())); + original.call(window, action, input); } @Inject(method = "onKey", at = @At("RETURN")) - private void onKeyTail(long window, int key, int scancode, int action, int modifiers, CallbackInfo ci) { + private void onKeyTail(long window, int action, KeyInput input, CallbackInfo ci) { + int key = input.key(); if (!InventoryMove.getShouldMove() || !InventoryMove.isKeyMovementRelated(key)) return; - InputUtil.Key fromCode = InputUtil.fromKeyCode(key, scancode); + InputUtil.Key fromCode = InputUtil.fromKeyCode(input); KeyBinding.setKeyPressed(fromCode, action != 0); } @WrapMethod(method = "onChar") - private void onChar(long window, int codePoint, int modifiers, Operation original) { - char[] chars = Character.toChars(codePoint); + private void onChar(long window, CharInput input, Operation original) { + char[] chars = Character.toChars(input.codepoint()); for (char c : chars) EventFlow.post(new KeyboardEvent.Char(c)); - original.call(window, codePoint, modifiers); + original.call(window, input); } } diff --git a/src/main/java/com/lambda/mixin/input/MouseMixin.java b/src/main/java/com/lambda/mixin/input/MouseMixin.java index 6fb6b6f31..f025bc838 100644 --- a/src/main/java/com/lambda/mixin/input/MouseMixin.java +++ b/src/main/java/com/lambda/mixin/input/MouseMixin.java @@ -25,6 +25,7 @@ import com.llamalad7.mixinextras.injector.wrapmethod.WrapMethod; import com.llamalad7.mixinextras.injector.wrapoperation.Operation; import net.minecraft.client.Mouse; +import net.minecraft.client.input.MouseInput; import net.minecraft.client.option.SimpleOption; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -36,10 +37,10 @@ public class MouseMixin { @Shadow private double y; - @WrapMethod(method = "onMouseButton(JIII)V") - private void onMouseButton(long window, int button, int action, int mods, Operation original) { - if (!EventFlow.post(new MouseEvent.Click(button, action, mods)).isCanceled()) - original.call(window, button, action, mods); + @WrapMethod(method = "onMouseButton") + private void onMouseButton(long window, MouseInput input, int action, Operation original) { + if (!EventFlow.post(new MouseEvent.Click(input.button(), action, input.modifiers())).isCanceled()) + original.call(window, input, action); } @WrapMethod(method = "onMouseScroll(JDD)V") diff --git a/src/main/java/com/lambda/mixin/network/ClientPlayNetworkHandlerMixin.java b/src/main/java/com/lambda/mixin/network/ClientPlayNetworkHandlerMixin.java index 49da330b8..99977ea81 100644 --- a/src/main/java/com/lambda/mixin/network/ClientPlayNetworkHandlerMixin.java +++ b/src/main/java/com/lambda/mixin/network/ClientPlayNetworkHandlerMixin.java @@ -45,15 +45,15 @@ void injectJoinPacket(GameJoinS2CPacket packet, CallbackInfo ci) { void injectPlayerList(PlayerListS2CPacket.Action action, PlayerListS2CPacket.Entry receivedEntry, PlayerListEntry currentEntry, CallbackInfo ci) { if (action != PlayerListS2CPacket.Action.UPDATE_LISTED) return; - var name = currentEntry.getProfile().getName(); - var uuid = currentEntry.getProfile().getId(); + var name = currentEntry.getProfile().name(); + var uuid = currentEntry.getProfile().id(); if (receivedEntry.listed()) { EventFlow.post(new WorldEvent.Player.Join(name, uuid, currentEntry)); } else EventFlow.post(new WorldEvent.Player.Leave(name, uuid, currentEntry)); } - @Inject(method = "onUpdateSelectedSlot", at = @At(value = "INVOKE", target = "Lnet/minecraft/network/NetworkThreadUtils;forceMainThread(Lnet/minecraft/network/packet/Packet;Lnet/minecraft/network/listener/PacketListener;Lnet/minecraft/util/thread/ThreadExecutor;)V", shift = At.Shift.AFTER), cancellable = true) + @Inject(method = "onUpdateSelectedSlot", at = @At(value = "INVOKE", target = "Lnet/minecraft/network/NetworkThreadUtils;forceMainThread(Lnet/minecraft/network/packet/Packet;Lnet/minecraft/network/listener/PacketListener;Lnet/minecraft/network/PacketApplyBatcher;)V", shift = At.Shift.AFTER), cancellable = true) private void onUpdateSelectedSlot(UpdateSelectedSlotS2CPacket packet, CallbackInfo ci) { if (EventFlow.post(new InventoryEvent.HotbarSlot.Sync(packet.slot())).isCanceled()) ci.cancel(); } @@ -64,17 +64,19 @@ private void onScreenHandlerSlotUpdate(ScreenHandlerSlotUpdateS2CPacket packet, } /** - * Sets displayedUnsecureChatWarning to {@link NoRender#getNoChatVerificationToast()} + * Sets seenInsecureChatWarning to {@link NoRender#getNoChatVerificationToast()} *
{@code
      * this.secureChatEnforced = packet.enforcesSecureChat();
-     * if (this.serverInfo != null && !this.displayedUnsecureChatWarning && !this.isSecureChatEnforced()) {
+     * if (this.serverInfo != null && !this.seenInsecureChatWarning && !this.isSecureChatEnforced()) {
      * SystemToast systemToast = SystemToast.create(this.client, SystemToast.Type.UNSECURE_SERVER_WARNING, UNSECURE_SERVER_TOAST_TITLE, UNSECURE_SERVER_TOAST_TEXT);
      * this.client.getToastManager().add(systemToast);
-     * this.displayedUnsecureChatWarning = true;
+     * this.seenInsecureChatWarning = true;
      * }
      * }
+ * + * Note: In 1.21.11, displayedUnsecureChatWarning was renamed to seenInsecureChatWarning. */ - @ModifyExpressionValue(method = "onGameJoin(Lnet/minecraft/network/packet/s2c/play/GameJoinS2CPacket;)V", at = @At(value = "FIELD", target = "Lnet/minecraft/client/network/ClientPlayNetworkHandler;displayedUnsecureChatWarning:Z", ordinal = 0)) + @ModifyExpressionValue(method = "onGameJoin(Lnet/minecraft/network/packet/s2c/play/GameJoinS2CPacket;)V", at = @At(value = "FIELD", target = "Lnet/minecraft/client/network/ClientPlayNetworkHandler;seenInsecureChatWarning:Z", ordinal = 0)) public boolean onServerMetadata(boolean original) { return (NoRender.getNoChatVerificationToast() && NoRender.INSTANCE.isEnabled()) || original; } diff --git a/src/main/java/com/lambda/mixin/render/AbstractTerrainRenderContextMixin.java b/src/main/java/com/lambda/mixin/render/AbstractTerrainRenderContextMixin.java index f09e674bc..f19cda820 100644 --- a/src/main/java/com/lambda/mixin/render/AbstractTerrainRenderContextMixin.java +++ b/src/main/java/com/lambda/mixin/render/AbstractTerrainRenderContextMixin.java @@ -28,7 +28,6 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -@SuppressWarnings("UnstableApiUsage") @Mixin(AbstractTerrainRenderContext.class) public class AbstractTerrainRenderContextMixin { @Final diff --git a/src/main/java/com/lambda/mixin/render/ArmorFeatureRendererMixin.java b/src/main/java/com/lambda/mixin/render/ArmorFeatureRendererMixin.java index cc5ee9e77..77ca02496 100644 --- a/src/main/java/com/lambda/mixin/render/ArmorFeatureRendererMixin.java +++ b/src/main/java/com/lambda/mixin/render/ArmorFeatureRendererMixin.java @@ -19,8 +19,10 @@ import com.lambda.module.modules.render.NoRender; import net.minecraft.client.render.VertexConsumerProvider; +import net.minecraft.client.render.command.OrderedRenderCommandQueue; import net.minecraft.client.render.entity.feature.ArmorFeatureRenderer; import net.minecraft.client.render.entity.state.BipedEntityRenderState; +import net.minecraft.client.render.entity.state.EntityRenderState; import net.minecraft.client.util.math.MatrixStack; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; @@ -29,8 +31,8 @@ @Mixin(ArmorFeatureRenderer.class) public class ArmorFeatureRendererMixin { - @Inject(method = "render(Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;ILnet/minecraft/client/render/entity/state/BipedEntityRenderState;FF)V", at = @At("HEAD"), cancellable = true) - private void injectRender(MatrixStack matrixStack, VertexConsumerProvider vertexConsumerProvider, int i, BipedEntityRenderState bipedEntityRenderState, float f, float g, CallbackInfo ci) { + @Inject(method = "render(Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/command/OrderedRenderCommandQueue;ILnet/minecraft/client/render/entity/state/EntityRenderState;FF)V", at = @At("HEAD"), cancellable = true) + private void injectRender(MatrixStack matrices, OrderedRenderCommandQueue queue, int light, EntityRenderState state, float limbAngle, float limbDistance, CallbackInfo ci) { if (NoRender.INSTANCE.isEnabled() && NoRender.getNoArmor()) ci.cancel(); } } diff --git a/src/main/java/com/lambda/mixin/render/BackgroundRendererMixin.java b/src/main/java/com/lambda/mixin/render/BackgroundRendererMixin.java index f0f02d1d2..887ca3b6b 100644 --- a/src/main/java/com/lambda/mixin/render/BackgroundRendererMixin.java +++ b/src/main/java/com/lambda/mixin/render/BackgroundRendererMixin.java @@ -18,60 +18,29 @@ package com.lambda.mixin.render; import com.lambda.module.modules.render.NoRender; -import com.lambda.module.modules.render.WorldColors; -import com.llamalad7.mixinextras.injector.ModifyExpressionValue; -import net.minecraft.client.render.BackgroundRenderer; +import net.minecraft.client.render.fog.BlindnessEffectFogModifier; +import net.minecraft.client.render.fog.DarknessEffectFogModifier; +import net.minecraft.block.enums.CameraSubmersionType; import net.minecraft.entity.Entity; import net.minecraft.entity.LivingEntity; -import net.minecraft.util.math.Vec3d; -import net.minecraft.world.biome.Biome; -import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -import java.util.List; -import java.util.stream.Stream; - /** - *
{@code
- * Vec3d vec3d2 = camera.getPos().subtract(2.0, 2.0, 2.0).multiply(0.25);
- * Vec3d vec3d3 = CubicSampler.sampleColor(
- *         vec3d2, (x, y, z) -> world.getDimensionEffects().adjustFogColor(Vec3d.unpackRgb(biomeAccess.getBiomeForNoiseGen(x, y, z).value().getFogColor()), v)
- * );
- * red = (float)vec3d3.getX();
- * green = (float)vec3d3.getY();
- * blue = (float)vec3d3.getZ();
- * }
+ * Mixins to disable blindness and darkness fog effects when NoRender is enabled. + * + * Note: The fog system was completely rewritten in 1.21.11. + * BackgroundRenderer was replaced with FogRenderer and fog modifiers are now separate classes. */ -@Mixin(BackgroundRenderer.class) +@Mixin(BlindnessEffectFogModifier.class) public class BackgroundRendererMixin { - @Shadow @Final private static List FOG_MODIFIERS; - - /** - * Modifies the fog color returned from CubicSampler.sampleColor - */ - @ModifyExpressionValue(method = "getFogColor", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/CubicSampler;sampleColor(Lnet/minecraft/util/math/Vec3d;Lnet/minecraft/util/CubicSampler$RgbFetcher;)Lnet/minecraft/util/math/Vec3d;")) - private static Vec3d modifyFogColor(Vec3d original) { - return WorldColors.fogOfWarColor(original); - } - - @ModifyExpressionValue(method = "getFogColor", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/biome/Biome;getWaterFogColor()I")) - private static int modifyWaterFogColor(int original) { - return WorldColors.waterFogColor(original); - } - @Inject(method = "getFogModifier(Lnet/minecraft/entity/Entity;F)Lnet/minecraft/client/render/BackgroundRenderer$StatusEffectFogModifier;", at = @At("HEAD"), cancellable = true) - private static void injectFogModifier(Entity entity, float tickProgress, CallbackInfoReturnable cir){ - if (entity instanceof LivingEntity livingEntity) { - Stream modifiers = FOG_MODIFIERS - .stream() - .filter((modifier) -> - modifier.shouldApply(livingEntity, tickProgress) && NoRender.shouldAcceptFog(modifier) - ); - cir.setReturnValue(modifiers.findFirst().orElse(null)); + @Inject(method = "applyDarknessModifier", at = @At("HEAD"), cancellable = true) + private void injectShouldApplyBlindness(LivingEntity cameraEntity, float darkness, float tickProgress, CallbackInfoReturnable cir) { + if (NoRender.getNoBlindness() && NoRender.INSTANCE.isEnabled()) { + cir.setReturnValue(0.0f); } } } diff --git a/src/main/java/com/lambda/mixin/render/CameraMixin.java b/src/main/java/com/lambda/mixin/render/CameraMixin.java index 7b618d8be..aa77d7f12 100644 --- a/src/main/java/com/lambda/mixin/render/CameraMixin.java +++ b/src/main/java/com/lambda/mixin/render/CameraMixin.java @@ -26,6 +26,7 @@ import net.minecraft.client.render.Camera; import net.minecraft.entity.Entity; import net.minecraft.world.BlockView; +import net.minecraft.world.World; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; @@ -42,14 +43,7 @@ public abstract class CameraMixin { public abstract void setRotation(float yaw, float pitch); @Inject(method = "update", at = @At("TAIL")) - private void onUpdate( - BlockView area, - Entity focusedEntity, - boolean thirdPerson, - boolean inverseView, - float tickDelta, - CallbackInfo ci - ) { + private void onUpdate(World area, Entity focusedEntity, boolean thirdPerson, boolean inverseView, float tickProgress, CallbackInfo ci) { if (!Freecam.INSTANCE.isEnabled()) return; Freecam.updateCam(); @@ -66,7 +60,7 @@ private void onUpdate( * } */ @Inject(method = "update", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/Camera;setPos(DDD)V", shift = At.Shift.AFTER)) - private void injectQuickPerspectiveSwap(BlockView area, Entity focusedEntity, boolean thirdPerson, boolean inverseView, float tickDelta, CallbackInfo ci) { + private void injectQuickPerspectiveSwap(World area, Entity focusedEntity, boolean thirdPerson, boolean inverseView, float tickProgress, CallbackInfo ci) { var rot = RotationManager.getLockRotation(); if (rot == null) return; setRotation(rot.getYawF(), rot.getPitchF()); diff --git a/src/main/java/com/lambda/mixin/render/CapeFeatureRendererMixin.java b/src/main/java/com/lambda/mixin/render/CapeFeatureRendererMixin.java index c1a319f3d..07be67e4a 100644 --- a/src/main/java/com/lambda/mixin/render/CapeFeatureRendererMixin.java +++ b/src/main/java/com/lambda/mixin/render/CapeFeatureRendererMixin.java @@ -21,7 +21,7 @@ import com.lambda.module.modules.client.Capes; import com.lambda.network.CapeManager; import com.llamalad7.mixinextras.injector.ModifyExpressionValue; -import net.minecraft.client.render.VertexConsumerProvider; +import net.minecraft.client.render.command.OrderedRenderCommandQueue; import net.minecraft.client.render.entity.feature.CapeFeatureRenderer; import net.minecraft.client.render.entity.state.PlayerEntityRenderState; import net.minecraft.client.util.math.MatrixStack; @@ -29,16 +29,25 @@ import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; +/** + * Mixin to override cape textures with Lambda capes. + * + * Note: In 1.21.11, render method uses OrderedRenderCommandQueue instead of VertexConsumerProvider. + * Cape texture is now accessed via skinTextures.cape().texturePath() instead of capeTexture(). + */ @Mixin(CapeFeatureRenderer.class) public class CapeFeatureRendererMixin { - @ModifyExpressionValue(method = "render(Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;ILnet/minecraft/client/render/entity/state/PlayerEntityRenderState;FF)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/util/SkinTextures;capeTexture()Lnet/minecraft/util/Identifier;")) - Identifier renderCape(Identifier original, MatrixStack matrixStack, VertexConsumerProvider vertexConsumerProvider, int i, PlayerEntityRenderState player, float f, float g) { - var entry = Lambda.getMc().getNetworkHandler().getPlayerListEntry(player.name); // this will cause issues if we try to render while not in game + @ModifyExpressionValue(method = "render(Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/command/OrderedRenderCommandQueue;ILnet/minecraft/client/render/entity/state/PlayerEntityRenderState;FF)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/AssetInfo$TextureAsset;texturePath()Lnet/minecraft/util/Identifier;")) + Identifier renderCape(Identifier original, MatrixStack matrixStack, OrderedRenderCommandQueue commandQueue, int i, PlayerEntityRenderState player, float f, float g) { + var networkHandler = Lambda.getMc().getNetworkHandler(); + if (networkHandler == null) return original; + + var entry = player.playerName != null ? networkHandler.getPlayerListEntry(player.playerName.getString()) : null; if (entry == null) return original; var profile = entry.getProfile(); - if (!Capes.INSTANCE.isEnabled() || !CapeManager.INSTANCE.getCache().containsKey(profile.getId())) return original; + if (!Capes.INSTANCE.isEnabled() || !CapeManager.INSTANCE.getCache().containsKey(profile.id())) return original; - return Identifier.of("lambda", CapeManager.INSTANCE.getCache().get(profile.getId())); + return Identifier.of("lambda", CapeManager.INSTANCE.getCache().get(profile.id())); } } diff --git a/src/main/java/com/lambda/mixin/render/ChatInputSuggestorMixin.java b/src/main/java/com/lambda/mixin/render/ChatInputSuggestorMixin.java index ae9578474..2e0d8f54a 100644 --- a/src/main/java/com/lambda/mixin/render/ChatInputSuggestorMixin.java +++ b/src/main/java/com/lambda/mixin/render/ChatInputSuggestorMixin.java @@ -62,9 +62,10 @@ private boolean refreshModify(boolean showCompletions) { return CommandManager.INSTANCE.isCommand(textField.getText()); } + @SuppressWarnings("unchecked") @WrapOperation(method = "refresh", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientPlayNetworkHandler;getCommandDispatcher()Lcom/mojang/brigadier/CommandDispatcher;")) private CommandDispatcher wrapRefresh(ClientPlayNetworkHandler instance, Operation> original) { - return CommandManager.INSTANCE.currentDispatcher(textField.getText()); + return (CommandDispatcher) CommandManager.INSTANCE.currentDispatcher(textField.getText()); } @Inject(method = "refresh", at = @At("TAIL")) diff --git a/src/main/java/com/lambda/mixin/render/DarknessEffectFogMixin.java b/src/main/java/com/lambda/mixin/render/DarknessEffectFogMixin.java new file mode 100644 index 000000000..af0c941e7 --- /dev/null +++ b/src/main/java/com/lambda/mixin/render/DarknessEffectFogMixin.java @@ -0,0 +1,42 @@ +/* + * Copyright 2025 Lambda + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.lambda.mixin.render; + +import com.lambda.module.modules.render.NoRender; +import net.minecraft.client.render.fog.DarknessEffectFogModifier; +import net.minecraft.block.enums.CameraSubmersionType; +import net.minecraft.entity.Entity; +import net.minecraft.entity.LivingEntity; +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; + +/** + * Mixin to disable darkness fog effect when NoRender is enabled. + */ +@Mixin(DarknessEffectFogModifier.class) +public class DarknessEffectFogMixin { + + @Inject(method = "applyDarknessModifier", at = @At("HEAD"), cancellable = true) + private void injectShouldApplyDarkness(LivingEntity cameraEntity, float darkness, float tickProgress, CallbackInfoReturnable cir) { + if (NoRender.getNoDarkness() && NoRender.INSTANCE.isEnabled()) { + cir.setReturnValue(0.0f); + } + } +} diff --git a/src/main/java/com/lambda/mixin/render/DebugHudMixin.java b/src/main/java/com/lambda/mixin/render/DebugHudMixin.java index 4b29a9e66..3c0a42c54 100644 --- a/src/main/java/com/lambda/mixin/render/DebugHudMixin.java +++ b/src/main/java/com/lambda/mixin/render/DebugHudMixin.java @@ -17,19 +17,13 @@ package com.lambda.mixin.render; -import com.lambda.util.DebugInfoHud; import net.minecraft.client.gui.hud.DebugHud; 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; - -import java.util.List; @Mixin(DebugHud.class) public class DebugHudMixin { - @Inject(method = "getRightText", at = @At("TAIL")) - private void onGetRightText(CallbackInfoReturnable> cir) { - DebugInfoHud.addDebugInfo(cir.getReturnValue()); - } +// @Inject(method = "getRightText", at = @At("TAIL")) +// private void onGetRightText(CallbackInfoReturnable> cir) { +// DebugInfoHud.addDebugInfo(cir.getReturnValue()); +// } } diff --git a/src/main/java/com/lambda/mixin/render/DebugRendererMixin.java b/src/main/java/com/lambda/mixin/render/DebugRendererMixin.java index 3491d7c24..8b703e194 100644 --- a/src/main/java/com/lambda/mixin/render/DebugRendererMixin.java +++ b/src/main/java/com/lambda/mixin/render/DebugRendererMixin.java @@ -29,8 +29,8 @@ @Mixin(DebugRenderer.class) public class DebugRendererMixin { - @Inject(method = "render", at = @At("TAIL")) - private void onRender(MatrixStack matrices, Frustum frustum, VertexConsumerProvider.Immediate vertexConsumers, double cameraX, double cameraY, double cameraZ, CallbackInfo ci) { - DebugRendererModule.render(matrices, vertexConsumers, cameraX, cameraY, cameraZ); - } +// @Inject(method = "render", at = @At("TAIL")) +// private void onRender(MatrixStack matrices, Frustum frustum, VertexConsumerProvider.Immediate vertexConsumers, double cameraX, double cameraY, double cameraZ, CallbackInfo ci) { +// DebugRendererModule.render(matrices, vertexConsumers, cameraX, cameraY, cameraZ); +// } } diff --git a/src/main/java/com/lambda/mixin/render/ElytraFeatureRendererMixin.java b/src/main/java/com/lambda/mixin/render/ElytraFeatureRendererMixin.java index 78a1bdf2c..72dc2c384 100644 --- a/src/main/java/com/lambda/mixin/render/ElytraFeatureRendererMixin.java +++ b/src/main/java/com/lambda/mixin/render/ElytraFeatureRendererMixin.java @@ -21,40 +21,48 @@ import com.lambda.module.modules.client.Capes; import com.lambda.module.modules.render.NoRender; import com.lambda.network.CapeManager; +import com.llamalad7.mixinextras.injector.ModifyReturnValue; import com.llamalad7.mixinextras.injector.wrapmethod.WrapMethod; import com.llamalad7.mixinextras.injector.wrapoperation.Operation; -import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; -import net.minecraft.client.render.VertexConsumerProvider; +import net.minecraft.client.render.command.OrderedRenderCommandQueue; import net.minecraft.client.render.entity.feature.ElytraFeatureRenderer; import net.minecraft.client.render.entity.state.BipedEntityRenderState; import net.minecraft.client.render.entity.state.PlayerEntityRenderState; import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.entity.LivingEntity; import net.minecraft.util.Identifier; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; +/** + * Mixin to override elytra textures with Lambda capes and disable elytra rendering. + * + * Note: In 1.21.11, render method uses OrderedRenderCommandQueue instead of VertexConsumerProvider. + * getTexture is now a private static method. + */ @Mixin(ElytraFeatureRenderer.class) -public class ElytraFeatureRendererMixin { - @WrapOperation(method = "render(Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;ILnet/minecraft/client/render/entity/state/BipedEntityRenderState;FF)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/entity/feature/ElytraFeatureRenderer;getTexture(Lnet/minecraft/client/render/entity/state/BipedEntityRenderState;)Lnet/minecraft/util/Identifier;")) - Identifier injectElytra(BipedEntityRenderState state, Operation original) { - if (!(state instanceof PlayerEntityRenderState)) - return original.call(state); +public class ElytraFeatureRendererMixin { + @ModifyReturnValue(method = "getTexture", at = @At("RETURN")) + private static Identifier injectElytra(Identifier original, BipedEntityRenderState state) { + if (!(state instanceof PlayerEntityRenderState playerState)) + return original; + + var networkHandler = Lambda.getMc().getNetworkHandler(); + if (networkHandler == null) return original; - var entry = Lambda.getMc().getNetworkHandler().getPlayerListEntry(((PlayerEntityRenderState) state).name); - if (entry == null) return original.call(state); + var entry = playerState.playerName != null ? networkHandler.getPlayerListEntry(playerState.playerName.getString()) : null; + if (entry == null) return original; var profile = entry.getProfile(); - if (!Capes.INSTANCE.isEnabled() || !CapeManager.INSTANCE.getCache().containsKey(profile.getId())) - return original.call(state); + if (!Capes.INSTANCE.isEnabled() || !CapeManager.INSTANCE.getCache().containsKey(profile.id())) + return original; - return Identifier.of("lambda", CapeManager.INSTANCE.getCache().get(profile.getId())); + return Identifier.of("lambda", CapeManager.INSTANCE.getCache().get(profile.id())); } - @WrapMethod(method = "render(Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;ILnet/minecraft/client/render/entity/state/BipedEntityRenderState;FF)V") - private void injectRender(MatrixStack matrixStack, VertexConsumerProvider vertexConsumerProvider, int i, BipedEntityRenderState bipedEntityRenderState, float f, float g, Operation original) { + @WrapMethod(method = "render(Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/command/OrderedRenderCommandQueue;ILnet/minecraft/client/render/entity/state/BipedEntityRenderState;FF)V") + private void injectRender(MatrixStack matrixStack, OrderedRenderCommandQueue commandQueue, int i, BipedEntityRenderState bipedEntityRenderState, float f, float g, Operation original) { if (NoRender.INSTANCE.isDisabled() || !NoRender.getNoElytra()) - original.call(matrixStack, vertexConsumerProvider, i, bipedEntityRenderState, f, g); + original.call(matrixStack, commandQueue, i, bipedEntityRenderState, f, g); } } diff --git a/src/main/java/com/lambda/mixin/render/EntityRendererMixin.java b/src/main/java/com/lambda/mixin/render/EntityRendererMixin.java index 69af3188a..b71234dce 100644 --- a/src/main/java/com/lambda/mixin/render/EntityRendererMixin.java +++ b/src/main/java/com/lambda/mixin/render/EntityRendererMixin.java @@ -19,12 +19,12 @@ import com.lambda.module.modules.render.NoRender; import net.minecraft.client.render.Frustum; -import net.minecraft.client.render.VertexConsumerProvider; +import net.minecraft.client.render.command.OrderedRenderCommandQueue; import net.minecraft.client.render.entity.EntityRenderer; import net.minecraft.client.render.entity.state.EntityRenderState; +import net.minecraft.client.render.state.CameraRenderState; import net.minecraft.client.util.math.MatrixStack; import net.minecraft.entity.Entity; -import net.minecraft.text.Text; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -39,7 +39,7 @@ private void injectShouldRender(Entity entity, Frustum frustum, double x, double } @Inject(method = "renderLabelIfPresent", at = @At("HEAD"), cancellable = true) - private void injectRenderLabelIfPresent(EntityRenderState state, Text text, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, CallbackInfo ci) { + private void injectRenderLabelIfPresent(EntityRenderState state, MatrixStack matrices, OrderedRenderCommandQueue queue, CameraRenderState cameraRenderState, CallbackInfo ci) { if (NoRender.INSTANCE.isEnabled() && NoRender.getNoNametags()) ci.cancel(); } } diff --git a/src/main/java/com/lambda/mixin/render/GameRendererMixin.java b/src/main/java/com/lambda/mixin/render/GameRendererMixin.java index 42cb9ace5..98cf293e7 100644 --- a/src/main/java/com/lambda/mixin/render/GameRendererMixin.java +++ b/src/main/java/com/lambda/mixin/render/GameRendererMixin.java @@ -20,12 +20,14 @@ import com.lambda.event.EventFlow; import com.lambda.event.events.RenderEvent; import com.lambda.graphics.RenderMain; +import com.lambda.gui.DearImGui; import com.lambda.module.modules.render.NoRender; import com.lambda.module.modules.render.Zoom; import com.llamalad7.mixinextras.injector.ModifyExpressionValue; import com.llamalad7.mixinextras.injector.ModifyReturnValue; import com.llamalad7.mixinextras.injector.wrapoperation.Operation; import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import com.mojang.blaze3d.buffers.GpuBufferSlice; import net.minecraft.client.render.Camera; import net.minecraft.client.render.GameRenderer; import net.minecraft.client.render.RenderTickCounter; @@ -33,6 +35,7 @@ import net.minecraft.client.util.ObjectAllocator; import net.minecraft.item.ItemStack; import org.joml.Matrix4f; +import org.joml.Vector4f; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -47,21 +50,9 @@ private void updateTargetedEntityInvoke(float tickDelta, CallbackInfo info) { } } - /** - * Begins our 3d render after the game has rendered the world - *
{@code
-     * float m = Math.max(h, (float)(Integer)this.client.options.getFov().getValue());
-     * Matrix4f matrix4f2 = this.getBasicProjectionMatrix(m);
-     * RenderSystem.setProjectionMatrix(matrix4f, ProjectionType.PERSPECTIVE);
-     * Quaternionf quaternionf = camera.getRotation().conjugate(new Quaternionf());
-     * Matrix4f matrix4f3 = (new Matrix4f()).rotation(quaternionf);
-     * this.client.worldRenderer.setupFrustum(camera.getPos(), matrix4f3, matrix4f2);
-     * this.client.worldRenderer.render(this.pool, renderTickCounter, bl, camera, this, matrix4f3, matrix4f);
-     * }
- */ - @WrapOperation(method = "renderWorld", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/WorldRenderer;render(Lnet/minecraft/client/util/ObjectAllocator;Lnet/minecraft/client/render/RenderTickCounter;ZLnet/minecraft/client/render/Camera;Lnet/minecraft/client/render/GameRenderer;Lorg/joml/Matrix4f;Lorg/joml/Matrix4f;)V")) - void onRenderWorld(WorldRenderer instance, ObjectAllocator allocator, RenderTickCounter tickCounter, boolean renderBlockOutline, Camera camera, GameRenderer gameRenderer, Matrix4f positionMatrix, Matrix4f projectionMatrix, Operation original) { - original.call(instance, allocator, tickCounter, renderBlockOutline, camera, gameRenderer, positionMatrix, projectionMatrix); + @WrapOperation(method = "renderWorld", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/WorldRenderer;render(Lnet/minecraft/client/util/ObjectAllocator;Lnet/minecraft/client/render/RenderTickCounter;ZLnet/minecraft/client/render/Camera;Lorg/joml/Matrix4f;Lorg/joml/Matrix4f;Lorg/joml/Matrix4f;Lcom/mojang/blaze3d/buffers/GpuBufferSlice;Lorg/joml/Vector4f;Z)V")) + void onRenderWorld(WorldRenderer instance, ObjectAllocator allocator, RenderTickCounter tickCounter, boolean renderBlockOutline, Camera camera, Matrix4f positionMatrix, Matrix4f basicProjectionMatrix, Matrix4f projectionMatrix, GpuBufferSlice fogBuffer, Vector4f fogColor, boolean renderSky, Operation original) { + original.call(instance, allocator, tickCounter, renderBlockOutline, camera, positionMatrix, basicProjectionMatrix, projectionMatrix, fogBuffer, fogColor, renderSky); RenderMain.render3D(positionMatrix, projectionMatrix); } @@ -80,4 +71,9 @@ private void injectShowFloatingItem(ItemStack floatingItem, CallbackInfo ci) { private float modifyGetFov(float original) { return original / Zoom.getLerpedZoom(); } + + @Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/render/GuiRenderer;render(Lcom/mojang/blaze3d/buffers/GpuBufferSlice;)V", shift = At.Shift.AFTER)) + private void onGuiRenderComplete(RenderTickCounter tickCounter, boolean tick, CallbackInfo ci) { + DearImGui.INSTANCE.render(); + } } diff --git a/src/main/java/com/lambda/mixin/render/HandledScreenMixin.java b/src/main/java/com/lambda/mixin/render/HandledScreenMixin.java index 193cdc516..3c66e9c53 100644 --- a/src/main/java/com/lambda/mixin/render/HandledScreenMixin.java +++ b/src/main/java/com/lambda/mixin/render/HandledScreenMixin.java @@ -18,6 +18,7 @@ package com.lambda.mixin.render; import com.lambda.module.modules.render.ContainerPreview; +import net.minecraft.client.gui.Click; import net.minecraft.client.gui.screen.ingame.HandledScreen; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; @@ -27,18 +28,18 @@ @Mixin(HandledScreen.class) public class HandledScreenMixin { @Inject(method = "mouseClicked", at = @At("HEAD"), cancellable = true) - private void onMouseClicked(double mouseX, double mouseY, int button, CallbackInfoReturnable cir) { + private void onMouseClicked(Click click, boolean doubled, CallbackInfoReturnable cir) { if (ContainerPreview.INSTANCE.isEnabled() && ContainerPreview.isLocked()) { - if (ContainerPreview.isMouseOverLockedTooltip((int) mouseX, (int) mouseY)) { + if (ContainerPreview.isMouseOverLockedTooltip((int) click.x(), (int) click.y())) { cir.setReturnValue(true); } } } @Inject(method = "mouseReleased", at = @At("HEAD"), cancellable = true) - private void onMouseReleased(double mouseX, double mouseY, int button, CallbackInfoReturnable cir) { + private void onMouseReleased(Click click, CallbackInfoReturnable cir) { if (ContainerPreview.INSTANCE.isEnabled() && ContainerPreview.isLocked()) { - if (ContainerPreview.isMouseOverLockedTooltip((int) mouseX, (int) mouseY)) { + if (ContainerPreview.isMouseOverLockedTooltip((int) click.x(), (int) click.y())) { cir.setReturnValue(true); } } diff --git a/src/main/java/com/lambda/mixin/render/HeadFeatureRendererMixin.java b/src/main/java/com/lambda/mixin/render/HeadFeatureRendererMixin.java index 38834b1ac..bb8416614 100644 --- a/src/main/java/com/lambda/mixin/render/HeadFeatureRendererMixin.java +++ b/src/main/java/com/lambda/mixin/render/HeadFeatureRendererMixin.java @@ -19,7 +19,9 @@ import com.lambda.module.modules.render.NoRender; import net.minecraft.client.render.VertexConsumerProvider; +import net.minecraft.client.render.command.OrderedRenderCommandQueue; import net.minecraft.client.render.entity.feature.HeadFeatureRenderer; +import net.minecraft.client.render.entity.state.EntityRenderState; import net.minecraft.client.render.entity.state.LivingEntityRenderState; import net.minecraft.client.util.math.MatrixStack; import org.spongepowered.asm.mixin.Mixin; @@ -29,8 +31,8 @@ @Mixin(HeadFeatureRenderer.class) public class HeadFeatureRendererMixin { - @Inject(method = "render(Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;ILnet/minecraft/client/render/entity/state/LivingEntityRenderState;FF)V", at = @At("HEAD"), cancellable = true) - private void injectRender(MatrixStack matrixStack, VertexConsumerProvider vertexConsumerProvider, int i, LivingEntityRenderState livingEntityRenderState, float f, float g, CallbackInfo ci) { + @Inject(method = "render(Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/command/OrderedRenderCommandQueue;ILnet/minecraft/client/render/entity/state/EntityRenderState;FF)V", at = @At("HEAD"), cancellable = true) + private void injectRender(MatrixStack matrices, OrderedRenderCommandQueue queue, int light, EntityRenderState state, float limbAngle, float limbDistance, CallbackInfo ci) { if (NoRender.INSTANCE.isEnabled() && NoRender.getNoArmor() && NoRender.getIncludeNoOtherHeadItems()) ci.cancel(); } } diff --git a/src/main/java/com/lambda/mixin/render/HeldItemRendererMixin.java b/src/main/java/com/lambda/mixin/render/HeldItemRendererMixin.java index 48d965c1a..ef2d89872 100644 --- a/src/main/java/com/lambda/mixin/render/HeldItemRendererMixin.java +++ b/src/main/java/com/lambda/mixin/render/HeldItemRendererMixin.java @@ -20,9 +20,10 @@ import com.google.common.base.MoreObjects; import com.lambda.Lambda; import com.lambda.module.modules.render.ViewModel; +import com.llamalad7.mixinextras.injector.ModifyExpressionValue; import net.minecraft.client.MinecraftClient; import net.minecraft.client.network.AbstractClientPlayerEntity; -import net.minecraft.client.render.VertexConsumerProvider; +import net.minecraft.client.render.command.OrderedRenderCommandQueue; import net.minecraft.client.render.item.HeldItemRenderer; import net.minecraft.client.util.math.MatrixStack; import net.minecraft.item.ItemStack; @@ -33,7 +34,6 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.ModifyArg; -import org.spongepowered.asm.mixin.injection.ModifyVariable; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(HeldItemRenderer.class) @@ -44,18 +44,14 @@ public class HeldItemRendererMixin { @Shadow private float equipProgressMainHand; @Shadow private float equipProgressOffHand; - @Inject(method = "renderFirstPersonItem", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/item/HeldItemRenderer;renderArmHoldingItem(Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;IFFLnet/minecraft/util/Arm;)V")) - private void onRenderArmHoldingItem(AbstractClientPlayerEntity player, float tickDelta, float pitch, Hand hand, float swingProgress, ItemStack itemStack, float equipProgress, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, CallbackInfo ci) { - if (!ViewModel.INSTANCE.isEnabled()) return; - - ViewModel.INSTANCE.transform(itemStack, hand, matrices); + @Inject(method = "renderFirstPersonItem", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/item/HeldItemRenderer;renderItem(Lnet/minecraft/entity/LivingEntity;Lnet/minecraft/item/ItemStack;Lnet/minecraft/item/ItemDisplayContext;Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/command/OrderedRenderCommandQueue;I)V")) + private void injectRenderFirstPersonItem(AbstractClientPlayerEntity player, float tickProgress, float pitch, Hand hand, float swingProgress, ItemStack item, float equipProgress, MatrixStack matrices, OrderedRenderCommandQueue orderedRenderCommandQueue, int light, CallbackInfo ci) { + if (ViewModel.INSTANCE.isEnabled()) ViewModel.INSTANCE.transform(item, hand, matrices); } - @Inject(method = "renderFirstPersonItem", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/item/HeldItemRenderer;renderItem(Lnet/minecraft/entity/LivingEntity;Lnet/minecraft/item/ItemStack;Lnet/minecraft/item/ItemDisplayContext;Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;I)V", ordinal = 1)) - private void onRenderFirstPersonItem(AbstractClientPlayerEntity player, float tickDelta, float pitch, Hand hand, float swingProgress, ItemStack itemStack, float equipProgress, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, CallbackInfo ci) { - if (!ViewModel.INSTANCE.isEnabled()) return; - - ViewModel.INSTANCE.transform(itemStack, hand, matrices); + @Inject(method = "renderFirstPersonItem", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/item/HeldItemRenderer;renderArmHoldingItem(Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/command/OrderedRenderCommandQueue;IFFLnet/minecraft/util/Arm;)V")) + private void injectRenderArmHoldingItem(AbstractClientPlayerEntity player, float tickProgress, float pitch, Hand hand, float swingProgress, ItemStack item, float equipProgress, MatrixStack matrices, OrderedRenderCommandQueue orderedRenderCommandQueue, int light, CallbackInfo ci) { + if (ViewModel.INSTANCE.isEnabled()) ViewModel.INSTANCE.transform(item, hand, matrices); } @ModifyArg(method = "updateHeldItems", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/math/MathHelper;clamp(FFF)F", ordinal = 2), index = 0) @@ -87,7 +83,7 @@ private float modifyEquipProgressOffHand(float value) { return (ItemStack.areEqual(offHand, currentStack) ? 1 : 0) - equipProgressOffHand; } - @ModifyVariable(method = "renderItem(FLnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider$Immediate;Lnet/minecraft/client/network/ClientPlayerEntity;I)V", at = @At(value = "STORE", ordinal = 0), index = 6) + @ModifyExpressionValue(method = "renderItem(FLnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/command/OrderedRenderCommandQueue;Lnet/minecraft/client/network/ClientPlayerEntity;I)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientPlayerEntity;getHandSwingProgress(F)F")) private float modifySwing(float swingProgress) { ViewModel config = ViewModel.INSTANCE; MinecraftClient mc = Lambda.getMc(); diff --git a/src/main/java/com/lambda/mixin/render/InGameHudMixin.java b/src/main/java/com/lambda/mixin/render/InGameHudMixin.java index 407ef5998..d6ca4f2ca 100644 --- a/src/main/java/com/lambda/mixin/render/InGameHudMixin.java +++ b/src/main/java/com/lambda/mixin/render/InGameHudMixin.java @@ -35,13 +35,6 @@ @Mixin(InGameHud.class) public class InGameHudMixin { - /** - * Begins our 2d render after the game has rendered all 2d elements - */ - @Inject(method = "render", at = @At("TAIL")) - private void onRender(DrawContext context, RenderTickCounter tickCounter, CallbackInfo ci) { - DearImGui.INSTANCE.render(); - } @Inject(method = "renderNauseaOverlay", at = @At("HEAD"), cancellable = true) private void injectRenderNauseaOverlay(DrawContext context, float nauseaStrength, CallbackInfo ci) { diff --git a/src/main/java/com/lambda/mixin/render/InGameOverlayRendererMixin.java b/src/main/java/com/lambda/mixin/render/InGameOverlayRendererMixin.java index 49412089b..956abd82e 100644 --- a/src/main/java/com/lambda/mixin/render/InGameOverlayRendererMixin.java +++ b/src/main/java/com/lambda/mixin/render/InGameOverlayRendererMixin.java @@ -32,9 +32,9 @@ @Mixin(InGameOverlayRenderer.class) public class InGameOverlayRendererMixin { @WrapMethod(method = "renderFireOverlay") - private static void wrapRenderFireOverlay(MatrixStack matrices, VertexConsumerProvider vertexConsumers, Operation original) { + private static void wrapRenderFireOverlay(MatrixStack matrices, VertexConsumerProvider vertexConsumers, Sprite sprite, Operation original) { if (!(NoRender.INSTANCE.isEnabled() && NoRender.getNoFireOverlay())) { - original.call(matrices, vertexConsumers); + original.call(matrices, vertexConsumers, sprite); } } diff --git a/src/main/java/com/lambda/mixin/render/LightmapTextureManagerMixin.java b/src/main/java/com/lambda/mixin/render/LightmapTextureManagerMixin.java index 849a9b297..48dec03ed 100644 --- a/src/main/java/com/lambda/mixin/render/LightmapTextureManagerMixin.java +++ b/src/main/java/com/lambda/mixin/render/LightmapTextureManagerMixin.java @@ -35,19 +35,25 @@ import java.util.OptionalInt; +/** + * Mixin to override lightmap for Fullbright/XRay and disable darkness effect. + * + * Note: In 1.21.11, the lightmap rendering was rewritten to use RenderPass with shaders. + * We override the texture after normal rendering completes. + */ @Mixin(LightmapTextureManager.class) public class LightmapTextureManagerMixin { @Shadow @Final private GpuTexture glTexture; @Inject(method = "update", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/profiler/Profiler;pop()V", shift = At.Shift.BEFORE)) - private void injectUpdate(CallbackInfo ci) { + private void injectUpdate(float tickProgress, CallbackInfo ci) { if (Fullbright.INSTANCE.isEnabled() || XRay.INSTANCE.isEnabled()) { - RenderSystem.getDevice().createCommandEncoder().createRenderPass(glTexture, OptionalInt.of(ColorHelper.getArgb(255, 255, 255, 255))).close(); + RenderSystem.getDevice().createCommandEncoder().clearColorTexture(glTexture, ColorHelper.fullAlpha(ColorHelper.getWhite(1.0f))); } } @ModifyReturnValue(method = "getDarkness", at = @At("RETURN")) - private float modifyGetDarkness(float original) { + private float modifyGetDarkness(float original, LivingEntity entity, float factor, float tickProgress) { if (NoRender.getNoDarkness() && NoRender.INSTANCE.isEnabled()) return 0.0f; return original; } diff --git a/src/main/java/com/lambda/mixin/render/ParticleManagerMixin.java b/src/main/java/com/lambda/mixin/render/ParticleManagerMixin.java deleted file mode 100644 index 654e32316..000000000 --- a/src/main/java/com/lambda/mixin/render/ParticleManagerMixin.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2025 Lambda - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.lambda.mixin.render; - -import com.lambda.module.modules.render.NoRender; -import com.llamalad7.mixinextras.injector.wrapoperation.Operation; -import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; -import net.minecraft.client.particle.Particle; -import net.minecraft.client.particle.ParticleManager; -import net.minecraft.client.particle.ParticleTextureSheet; -import net.minecraft.client.render.Camera; -import net.minecraft.client.render.VertexConsumerProvider; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Unique; -import org.spongepowered.asm.mixin.injection.At; - -import java.util.LinkedList; -import java.util.Queue; -import java.util.stream.Collectors; - -@Mixin(ParticleManager.class) -public class ParticleManagerMixin { - // prevents the particles from being stored and potential overhead. Downside being they need to spawn back in rather than just enabling rendering again -// @Inject(method = "addParticle(Lnet/minecraft/client/particle/Particle;)V", at = @At("HEAD"), cancellable = true) -// private void injectAddParticle(Particle particle, CallbackInfo ci) { -// if (NoRender.shouldOmitParticle(particle)) ci.cancel(); -// } - - @WrapOperation(method = "renderParticles(Lnet/minecraft/client/render/Camera;FLnet/minecraft/client/render/VertexConsumerProvider$Immediate;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/particle/ParticleManager;renderParticles(Lnet/minecraft/client/render/Camera;FLnet/minecraft/client/render/VertexConsumerProvider$Immediate;Lnet/minecraft/client/particle/ParticleTextureSheet;Ljava/util/Queue;)V")) - private void wrapRenderParticles(Camera camera, float tickProgress, VertexConsumerProvider.Immediate vertexConsumers, ParticleTextureSheet sheet, Queue particles, Operation original) { - original.call(camera, tickProgress, vertexConsumers, sheet, filterParticles(particles)); - } - - @WrapOperation(method = "renderParticles(Lnet/minecraft/client/render/Camera;FLnet/minecraft/client/render/VertexConsumerProvider$Immediate;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/particle/ParticleManager;renderCustomParticles(Lnet/minecraft/client/render/Camera;FLnet/minecraft/client/render/VertexConsumerProvider$Immediate;Ljava/util/Queue;)V")) - private void wrapRenderParticles(Camera camera, float tickProgress, VertexConsumerProvider.Immediate vertexConsumers, Queue particles, Operation original) { - original.call(camera, tickProgress, vertexConsumers, filterParticles(particles)); - } - - @Unique - private Queue filterParticles(Queue particles) { - return particles.stream().filter(particle -> - !NoRender.shouldOmitParticle(particle)).collect(Collectors.toCollection(LinkedList::new) - ); - } -} diff --git a/src/main/java/com/lambda/mixin/render/RenderLayersMixin.java b/src/main/java/com/lambda/mixin/render/RenderLayersMixin.java index 0b4d622dd..96e786e33 100644 --- a/src/main/java/com/lambda/mixin/render/RenderLayersMixin.java +++ b/src/main/java/com/lambda/mixin/render/RenderLayersMixin.java @@ -19,28 +19,34 @@ import com.lambda.module.modules.render.XRay; import net.minecraft.block.BlockState; -import net.minecraft.client.render.RenderLayer; -import net.minecraft.client.render.RenderLayers; +import net.minecraft.client.render.BlockRenderLayer; +import net.minecraft.client.render.BlockRenderLayers; import net.minecraft.fluid.FluidState; 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; -@Mixin(RenderLayers.class) +/** + * Mixin to make blocks render as translucent for XRay functionality. + * + * Note: In 1.21.11, RenderLayers was split - BlockRenderLayers now handles + * block/fluid layer determination and returns BlockRenderLayer enum instead of RenderLayer. + */ +@Mixin(BlockRenderLayers.class) public class RenderLayersMixin { @Inject(method = "getBlockLayer", at = @At("HEAD"), cancellable = true) - private static void injectGetBlockLayer(BlockState state, CallbackInfoReturnable cir) { + private static void injectGetBlockLayer(BlockState state, CallbackInfoReturnable cir) { if (XRay.INSTANCE.isDisabled()) return; final var opacity = XRay.getOpacity(); if (opacity <= 0 || opacity >= 100) return; - if (!XRay.isSelected(state)) cir.setReturnValue(RenderLayer.getTranslucent()); + if (!XRay.isSelected(state)) cir.setReturnValue(BlockRenderLayer.TRANSLUCENT); } @Inject(method = "getFluidLayer", at = @At("HEAD"), cancellable = true) - private static void injectGetFluidLayer(FluidState state, CallbackInfoReturnable cir) { + private static void injectGetFluidLayer(FluidState state, CallbackInfoReturnable cir) { if (XRay.INSTANCE.isDisabled()) return; final var opacity = XRay.getOpacity(); - if (opacity > 0 && opacity < 100) cir.setReturnValue(RenderLayer.getTranslucent()); + if (opacity > 0 && opacity < 100) cir.setReturnValue(BlockRenderLayer.TRANSLUCENT); } } diff --git a/src/main/java/com/lambda/mixin/render/ScreenMixin.java b/src/main/java/com/lambda/mixin/render/ScreenMixin.java index 9c4972653..6ed4f2c53 100644 --- a/src/main/java/com/lambda/mixin/render/ScreenMixin.java +++ b/src/main/java/com/lambda/mixin/render/ScreenMixin.java @@ -25,6 +25,7 @@ import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.DrawContext; import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.input.KeyInput; import org.lwjgl.glfw.GLFW; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; @@ -35,8 +36,8 @@ @Mixin(Screen.class) public class ScreenMixin { @Inject(method = "keyPressed", at = @At("HEAD"), cancellable = true) - private void onKeyPressed(int keyCode, int scanCode, int modifiers, CallbackInfoReturnable cir) { - if (keyCode == GLFW.GLFW_KEY_ESCAPE && QuickSearch.INSTANCE.isOpen()) { + private void onKeyPressed(KeyInput input, CallbackInfoReturnable cir) { + if (input.key() == GLFW.GLFW_KEY_ESCAPE && QuickSearch.INSTANCE.isOpen()) { QuickSearch.INSTANCE.close(); cir.setReturnValue(true); } diff --git a/src/main/java/com/lambda/mixin/render/WorldBorderRenderingMixin.java b/src/main/java/com/lambda/mixin/render/WorldBorderRenderingMixin.java index a5e6f9269..9553a39a5 100644 --- a/src/main/java/com/lambda/mixin/render/WorldBorderRenderingMixin.java +++ b/src/main/java/com/lambda/mixin/render/WorldBorderRenderingMixin.java @@ -19,6 +19,7 @@ import com.lambda.module.modules.render.NoRender; import net.minecraft.client.render.WorldBorderRendering; +import net.minecraft.client.render.state.WorldBorderRenderState; import net.minecraft.util.math.Vec3d; import net.minecraft.world.border.WorldBorder; import org.spongepowered.asm.mixin.Mixin; @@ -29,7 +30,7 @@ @Mixin(WorldBorderRendering.class) public class WorldBorderRenderingMixin { @Inject(method = "render", at = @At("HEAD"), cancellable = true) - private void injectRender(WorldBorder border, Vec3d cameraPos, double viewDistanceBlocks, double farPlaneDistance, CallbackInfo ci) { + private void injectRender(WorldBorderRenderState state, Vec3d cameraPos, double viewDistanceBlocks, double farPlaneDistance, CallbackInfo ci) { if (NoRender.INSTANCE.isEnabled() && NoRender.getNoWorldBorder()) ci.cancel(); } } diff --git a/src/main/java/com/lambda/mixin/render/WorldRendererMixin.java b/src/main/java/com/lambda/mixin/render/WorldRendererMixin.java index d8eb33e08..dcac99936 100644 --- a/src/main/java/com/lambda/mixin/render/WorldRendererMixin.java +++ b/src/main/java/com/lambda/mixin/render/WorldRendererMixin.java @@ -34,22 +34,22 @@ @Mixin(WorldRenderer.class) public class WorldRendererMixin { - @ModifyExpressionValue(method = "getEntitiesToRender(Lnet/minecraft/client/render/Camera;Lnet/minecraft/client/render/Frustum;Ljava/util/List;)Z", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/Camera;isThirdPerson()Z")) - private boolean renderIsThirdPerson(boolean original) { - return Freecam.INSTANCE.isEnabled() || original; - } - - @ModifyArg(method = "render(Lnet/minecraft/client/util/ObjectAllocator;Lnet/minecraft/client/render/RenderTickCounter;ZLnet/minecraft/client/render/Camera;Lnet/minecraft/client/render/GameRenderer;Lorg/joml/Matrix4f;Lorg/joml/Matrix4f;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/WorldRenderer;setupTerrain(Lnet/minecraft/client/render/Camera;Lnet/minecraft/client/render/Frustum;ZZ)V"), index = 3) - private boolean renderSetupTerrainModifyArg(boolean hasForcedFrustum) { - return Freecam.INSTANCE.isEnabled() || CameraTweaks.INSTANCE.isEnabled() || hasForcedFrustum; - } - - @ModifyArg(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/BackgroundRenderer;applyFog(Lnet/minecraft/client/render/Camera;Lnet/minecraft/client/render/BackgroundRenderer$FogType;Lorg/joml/Vector4f;FZF)Lnet/minecraft/client/render/Fog;", ordinal = 0), index = 3) - private float modifyApplyFogRenderDistance(float viewDistance) { - return NoRender.INSTANCE.isEnabled() && NoRender.getNoTerrainFog() - ? Float.MAX_VALUE - : viewDistance; - } +// @ModifyExpressionValue(method = "getEntitiesToRender(Lnet/minecraft/client/render/Camera;Lnet/minecraft/client/render/Frustum;Ljava/util/List;)Z", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/Camera;isThirdPerson()Z")) +// private boolean renderIsThirdPerson(boolean original) { +// return Freecam.INSTANCE.isEnabled() || original; +// } +// +// @ModifyArg(method = "render(Lnet/minecraft/client/util/ObjectAllocator;Lnet/minecraft/client/render/RenderTickCounter;ZLnet/minecraft/client/render/Camera;Lnet/minecraft/client/render/GameRenderer;Lorg/joml/Matrix4f;Lorg/joml/Matrix4f;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/WorldRenderer;setupTerrain(Lnet/minecraft/client/render/Camera;Lnet/minecraft/client/render/Frustum;ZZ)V"), index = 3) +// private boolean renderSetupTerrainModifyArg(boolean hasForcedFrustum) { +// return Freecam.INSTANCE.isEnabled() || CameraTweaks.INSTANCE.isEnabled() || hasForcedFrustum; +// } +// +// @ModifyArg(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/BackgroundRenderer;applyFog(Lnet/minecraft/client/render/Camera;Lnet/minecraft/client/render/BackgroundRenderer$FogType;Lorg/joml/Vector4f;FZF)Lnet/minecraft/client/render/Fog;", ordinal = 0), index = 3) +// private float modifyApplyFogRenderDistance(float viewDistance) { +// return NoRender.INSTANCE.isEnabled() && NoRender.getNoTerrainFog() +// ? Float.MAX_VALUE +// : viewDistance; +// } @Inject(method = "hasBlindnessOrDarkness(Lnet/minecraft/client/render/Camera;)Z", at = @At(value = "HEAD"), cancellable = true) private void modifyEffectCheck(Camera camera, CallbackInfoReturnable cir) { diff --git a/src/main/java/com/lambda/mixin/render/AbstractSignBlockEntityRendererMixin.java b/src/main/java/com/lambda/mixin/render/blockentity/AbstractSignBlockEntityRendererMixin.java similarity index 77% rename from src/main/java/com/lambda/mixin/render/AbstractSignBlockEntityRendererMixin.java rename to src/main/java/com/lambda/mixin/render/blockentity/AbstractSignBlockEntityRendererMixin.java index 6f1d4c5c5..9d6232c03 100644 --- a/src/main/java/com/lambda/mixin/render/AbstractSignBlockEntityRendererMixin.java +++ b/src/main/java/com/lambda/mixin/render/blockentity/AbstractSignBlockEntityRendererMixin.java @@ -15,14 +15,13 @@ * along with this program. If not, see . */ -package com.lambda.mixin.render; +package com.lambda.mixin.render.blockentity; import com.lambda.module.modules.render.NoRender; -import net.minecraft.block.entity.SignText; -import net.minecraft.client.render.VertexConsumerProvider; import net.minecraft.client.render.block.entity.AbstractSignBlockEntityRenderer; +import net.minecraft.client.render.block.entity.state.SignBlockEntityRenderState; +import net.minecraft.client.render.command.OrderedRenderCommandQueue; import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.util.math.BlockPos; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -31,7 +30,7 @@ @Mixin(AbstractSignBlockEntityRenderer.class) public class AbstractSignBlockEntityRendererMixin { @Inject(method = "renderText", at = @At("HEAD"), cancellable = true) - private void injectRenderText(BlockPos pos, SignText text, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, int textLineHeight, int maxTextWidth, boolean front, CallbackInfo ci) { + private void injectRenderText(SignBlockEntityRenderState renderState, MatrixStack matrices, OrderedRenderCommandQueue queue, boolean front, CallbackInfo ci) { if (NoRender.INSTANCE.isEnabled() && NoRender.getNoSignText()) ci.cancel(); } } diff --git a/src/main/java/com/lambda/mixin/render/BeaconBlockEntityRendererMixin.java b/src/main/java/com/lambda/mixin/render/blockentity/BeaconBlockEntityRendererMixin.java similarity index 61% rename from src/main/java/com/lambda/mixin/render/BeaconBlockEntityRendererMixin.java rename to src/main/java/com/lambda/mixin/render/blockentity/BeaconBlockEntityRendererMixin.java index a3d4b5e38..8ad9a6d83 100644 --- a/src/main/java/com/lambda/mixin/render/BeaconBlockEntityRendererMixin.java +++ b/src/main/java/com/lambda/mixin/render/blockentity/BeaconBlockEntityRendererMixin.java @@ -15,14 +15,14 @@ * along with this program. If not, see . */ -package com.lambda.mixin.render; +package com.lambda.mixin.render.blockentity; import com.lambda.module.modules.render.NoRender; -import net.minecraft.block.entity.BlockEntity; -import net.minecraft.client.render.VertexConsumerProvider; import net.minecraft.client.render.block.entity.BeaconBlockEntityRenderer; +import net.minecraft.client.render.block.entity.state.BeaconBlockEntityRenderState; +import net.minecraft.client.render.command.OrderedRenderCommandQueue; +import net.minecraft.client.render.state.CameraRenderState; import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.util.math.Vec3d; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -30,8 +30,8 @@ @Mixin(BeaconBlockEntityRenderer.class) public class BeaconBlockEntityRendererMixin { - @Inject(method = "render", at = @At("HEAD"), cancellable = true) - private void injectRender(BlockEntity entity, float tickProgress, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, int overlay, Vec3d cameraPos, CallbackInfo ci) { + @Inject(method = "render(Lnet/minecraft/client/render/block/entity/state/BeaconBlockEntityRenderState;Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/command/OrderedRenderCommandQueue;Lnet/minecraft/client/render/state/CameraRenderState;)V", at = @At("HEAD"), cancellable = true) + private void injectRender(BeaconBlockEntityRenderState beaconBlockEntityRenderState, MatrixStack matrixStack, OrderedRenderCommandQueue orderedRenderCommandQueue, CameraRenderState cameraRenderState, CallbackInfo ci) { if (NoRender.INSTANCE.isEnabled() && NoRender.getNoBeaconBeams()) ci.cancel(); } } diff --git a/src/main/java/com/lambda/mixin/render/BlockEntityRenderDispatcherMixin.java b/src/main/java/com/lambda/mixin/render/blockentity/BlockEntityRenderDispatcherMixin.java similarity index 52% rename from src/main/java/com/lambda/mixin/render/BlockEntityRenderDispatcherMixin.java rename to src/main/java/com/lambda/mixin/render/blockentity/BlockEntityRenderDispatcherMixin.java index 268b07043..784faeee0 100644 --- a/src/main/java/com/lambda/mixin/render/BlockEntityRenderDispatcherMixin.java +++ b/src/main/java/com/lambda/mixin/render/blockentity/BlockEntityRenderDispatcherMixin.java @@ -15,24 +15,33 @@ * along with this program. If not, see . */ -package com.lambda.mixin.render; +package com.lambda.mixin.render.blockentity; import com.lambda.module.modules.render.NoRender; import net.minecraft.block.entity.BlockEntity; -import net.minecraft.client.render.VertexConsumerProvider; -import net.minecraft.client.render.block.entity.BlockEntityRenderDispatcher; -import net.minecraft.client.render.block.entity.BlockEntityRenderer; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.util.math.Vec3d; +import net.minecraft.client.render.block.entity.BlockEntityRenderManager; +import net.minecraft.client.render.block.entity.state.BlockEntityRenderState; +import net.minecraft.client.render.command.ModelCommandRenderer; 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; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import org.jspecify.annotations.Nullable; -@Mixin(BlockEntityRenderDispatcher.class) +/** + * Mixin to disable block entity rendering when NoRender is enabled. + * + * Note: In 1.21.11, BlockEntityRenderDispatcher was renamed to BlockEntityRenderManager + * and uses a render state system. Returning null from getRenderState prevents rendering. + */ +@Mixin(BlockEntityRenderManager.class) public class BlockEntityRenderDispatcherMixin { - @Inject(method = "render(Lnet/minecraft/client/render/block/entity/BlockEntityRenderer;Lnet/minecraft/block/entity/BlockEntity;FLnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;Lnet/minecraft/util/math/Vec3d;)V", at = @At("HEAD"), cancellable = true) - private static void injectRender(BlockEntityRenderer renderer, BlockEntity blockEntity, float tickProgress, MatrixStack matrices, VertexConsumerProvider vertexConsumers, Vec3d cameraPos, CallbackInfo ci) { - if (NoRender.shouldOmitBlockEntity(blockEntity)) ci.cancel(); + @Inject(method = "getRenderState", at = @At("HEAD"), cancellable = true) + private void injectGetRenderState( + E blockEntity, float tickProgress, ModelCommandRenderer.@Nullable CrumblingOverlayCommand crumblingOverlay, + CallbackInfoReturnable cir) { + if (NoRender.shouldOmitBlockEntity(blockEntity)) { + cir.setReturnValue(null); + } } } diff --git a/src/main/java/com/lambda/mixin/render/EnchantingTableBlockEntityRendererMixin.java b/src/main/java/com/lambda/mixin/render/blockentity/EnchantingTableBlockEntityRendererMixin.java similarity index 51% rename from src/main/java/com/lambda/mixin/render/EnchantingTableBlockEntityRendererMixin.java rename to src/main/java/com/lambda/mixin/render/blockentity/EnchantingTableBlockEntityRendererMixin.java index f80ca373d..f0e5b02dd 100644 --- a/src/main/java/com/lambda/mixin/render/EnchantingTableBlockEntityRendererMixin.java +++ b/src/main/java/com/lambda/mixin/render/blockentity/EnchantingTableBlockEntityRendererMixin.java @@ -15,21 +15,23 @@ * along with this program. If not, see . */ -package com.lambda.mixin.render; +package com.lambda.mixin.render.blockentity; import com.lambda.module.modules.render.NoRender; -import com.llamalad7.mixinextras.injector.v2.WrapWithCondition; -import net.minecraft.client.render.VertexConsumer; import net.minecraft.client.render.block.entity.EnchantingTableBlockEntityRenderer; -import net.minecraft.client.render.entity.model.BookModel; +import net.minecraft.client.render.block.entity.state.EnchantingTableBlockEntityRenderState; +import net.minecraft.client.render.command.OrderedRenderCommandQueue; +import net.minecraft.client.render.state.CameraRenderState; import net.minecraft.client.util.math.MatrixStack; 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; @Mixin(EnchantingTableBlockEntityRenderer.class) public class EnchantingTableBlockEntityRendererMixin { - @WrapWithCondition(method = "render(Lnet/minecraft/block/entity/EnchantingTableBlockEntity;FLnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;IILnet/minecraft/util/math/Vec3d;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/entity/model/BookModel;render(Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumer;II)V")) - private boolean wrapRender(BookModel instance, MatrixStack matrixStack, VertexConsumer vertexConsumer, int i, int j) { - return NoRender.INSTANCE.isDisabled() || !NoRender.getNoEnchantingTableBook(); + @Inject(method = "render(Lnet/minecraft/client/render/block/entity/state/EnchantingTableBlockEntityRenderState;Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/command/OrderedRenderCommandQueue;Lnet/minecraft/client/render/state/CameraRenderState;)V", at = @At("HEAD"), cancellable = true) + private void injectRender(EnchantingTableBlockEntityRenderState renderState, MatrixStack matrices, OrderedRenderCommandQueue queue, CameraRenderState cameraRenderState, CallbackInfo ci) { + if (NoRender.INSTANCE.isEnabled() && NoRender.getNoEnchantingTableBook()) ci.cancel(); } } diff --git a/src/main/java/com/lambda/mixin/render/MobSpawnerBlockEntityRendererMixin.java b/src/main/java/com/lambda/mixin/render/blockentity/MobSpawnerBlockEntityRendererMixin.java similarity index 66% rename from src/main/java/com/lambda/mixin/render/MobSpawnerBlockEntityRendererMixin.java rename to src/main/java/com/lambda/mixin/render/blockentity/MobSpawnerBlockEntityRendererMixin.java index e2233bf31..f47e9d2c0 100644 --- a/src/main/java/com/lambda/mixin/render/MobSpawnerBlockEntityRendererMixin.java +++ b/src/main/java/com/lambda/mixin/render/blockentity/MobSpawnerBlockEntityRendererMixin.java @@ -15,14 +15,15 @@ * along with this program. If not, see . */ -package com.lambda.mixin.render; +package com.lambda.mixin.render.blockentity; import com.lambda.module.modules.render.NoRender; -import net.minecraft.block.entity.MobSpawnerBlockEntity; -import net.minecraft.client.render.VertexConsumerProvider; import net.minecraft.client.render.block.entity.MobSpawnerBlockEntityRenderer; +import net.minecraft.client.render.command.OrderedRenderCommandQueue; +import net.minecraft.client.render.entity.EntityRenderManager; +import net.minecraft.client.render.entity.state.EntityRenderState; +import net.minecraft.client.render.state.CameraRenderState; import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.util.math.Vec3d; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -30,8 +31,8 @@ @Mixin(MobSpawnerBlockEntityRenderer.class) public class MobSpawnerBlockEntityRendererMixin { - @Inject(method = "render(Lnet/minecraft/block/entity/MobSpawnerBlockEntity;FLnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;IILnet/minecraft/util/math/Vec3d;)V", at = @At("HEAD"), cancellable = true) - private void injectRender(MobSpawnerBlockEntity mobSpawnerBlockEntity, float f, MatrixStack matrixStack, VertexConsumerProvider vertexConsumerProvider, int i, int j, Vec3d vec3d, CallbackInfo ci) { + @Inject(method = "renderDisplayEntity", at = @At("HEAD"), cancellable = true) + private static void injectRender(MatrixStack matrices, OrderedRenderCommandQueue queue, EntityRenderState state, EntityRenderManager entityRenderDispatcher, float rotation, float scale, CameraRenderState cameraRenderState, CallbackInfo ci) { if (NoRender.INSTANCE.isEnabled() && NoRender.getNoSpawnerMob()) ci.cancel(); } } diff --git a/src/main/java/com/lambda/mixin/render/particle/BillboardParticleMixin.java b/src/main/java/com/lambda/mixin/render/particle/BillboardParticleMixin.java new file mode 100644 index 000000000..06faa1a5d --- /dev/null +++ b/src/main/java/com/lambda/mixin/render/particle/BillboardParticleMixin.java @@ -0,0 +1,36 @@ +/* + * Copyright 2025 Lambda + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.lambda.mixin.render.particle; + +import com.lambda.module.modules.render.NoRender; +import net.minecraft.client.particle.BillboardParticle; +import net.minecraft.client.particle.BillboardParticleSubmittable; +import net.minecraft.client.particle.Particle; +import net.minecraft.client.render.Camera; +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; + +@Mixin(BillboardParticle.class) +public class BillboardParticleMixin { + @Inject(method = "render(Lnet/minecraft/client/particle/BillboardParticleSubmittable;Lnet/minecraft/client/render/Camera;F)V", at = @At("HEAD"), cancellable = true) + private void injectRender(BillboardParticleSubmittable submittable, Camera camera, float tickDelta, CallbackInfo ci) { + if (NoRender.shouldOmitParticle((Particle) ((Object) this))) ci.cancel(); + } +} diff --git a/src/main/java/com/lambda/mixin/render/particle/ElderGuardianParticleRendererMixin.java b/src/main/java/com/lambda/mixin/render/particle/ElderGuardianParticleRendererMixin.java new file mode 100644 index 000000000..cc7b2e818 --- /dev/null +++ b/src/main/java/com/lambda/mixin/render/particle/ElderGuardianParticleRendererMixin.java @@ -0,0 +1,38 @@ +/* + * Copyright 2025 Lambda + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.lambda.mixin.render.particle; + +import com.lambda.module.modules.render.NoRender; +import net.minecraft.client.particle.ElderGuardianParticle; +import net.minecraft.client.particle.ElderGuardianParticleRenderer; +import net.minecraft.client.particle.NoRenderParticleRenderer; +import net.minecraft.client.render.Camera; +import net.minecraft.client.render.Frustum; +import net.minecraft.client.render.Submittable; +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; + +@Mixin(ElderGuardianParticleRenderer.class) +public class ElderGuardianParticleRendererMixin { + @Inject(method = "render", at = @At("HEAD"), cancellable = true) + private void injectRender(Frustum frustum, Camera camera, float tickProgress, CallbackInfoReturnable cir) { + if (NoRender.shouldOmitParticle(ElderGuardianParticle.class)) cir.setReturnValue(NoRenderParticleRenderer.EMPTY); + } +} diff --git a/src/main/java/com/lambda/mixin/render/particle/ItemPickupParticleRendererMixin.java b/src/main/java/com/lambda/mixin/render/particle/ItemPickupParticleRendererMixin.java new file mode 100644 index 000000000..509b3323c --- /dev/null +++ b/src/main/java/com/lambda/mixin/render/particle/ItemPickupParticleRendererMixin.java @@ -0,0 +1,38 @@ +/* + * Copyright 2025 Lambda + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.lambda.mixin.render.particle; + +import com.lambda.module.modules.render.NoRender; +import net.minecraft.client.particle.ItemPickupParticle; +import net.minecraft.client.particle.ItemPickupParticleRenderer; +import net.minecraft.client.particle.NoRenderParticleRenderer; +import net.minecraft.client.render.Camera; +import net.minecraft.client.render.Frustum; +import net.minecraft.client.render.Submittable; +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; + +@Mixin(ItemPickupParticleRenderer.class) +public class ItemPickupParticleRendererMixin { + @Inject(method = "render", at = @At("HEAD"), cancellable = true) + private void injectRender(Frustum frustum, Camera camera, float tickProgress, CallbackInfoReturnable cir) { + if (NoRender.shouldOmitParticle(ItemPickupParticle.class)) cir.setReturnValue(NoRenderParticleRenderer.EMPTY); + } +} diff --git a/src/main/java/com/lambda/mixin/world/ClientWorldMixin.java b/src/main/java/com/lambda/mixin/world/ClientWorldMixin.java index d98e1efb3..5b86cf797 100644 --- a/src/main/java/com/lambda/mixin/world/ClientWorldMixin.java +++ b/src/main/java/com/lambda/mixin/world/ClientWorldMixin.java @@ -46,21 +46,21 @@ private void onRemoveEntity(int entityId, Entity.RemovalReason removalReason, Ca EventFlow.post(new EntityEvent.Removal(entity, removalReason)); } - @ModifyReturnValue(method = "getCloudsColor", at = @At("RETURN")) - private int modifyGetCloudsColor(int original) { - if (WorldColors.INSTANCE.isEnabled() && WorldColors.getCustomClouds()) { - return WorldColors.getCloudColor().getRGB() & 0xFFFFFF; - } - return original; - } - - @ModifyReturnValue(method = "getSkyColor", at = @At("RETURN")) - private int modifyGetSkyColor(int original) { - if (WorldColors.INSTANCE.isEnabled() && WorldColors.getCustomSky()) { - return WorldColors.getSkyColor().getRGB() & 0xFFFFFF; - } - return original; - } +// @ModifyReturnValue(method = "getCloudsColor", at = @At("RETURN")) +// private int modifyGetCloudsColor(int original) { +// if (WorldColors.INSTANCE.isEnabled() && WorldColors.getCustomClouds()) { +// return WorldColors.getCloudColor().getRGB() & 0xFFFFFF; +// } +// return original; +// } +// +// @ModifyReturnValue(method = "getSkyColor", at = @At("RETURN")) +// private int modifyGetSkyColor(int original) { +// if (WorldColors.INSTANCE.isEnabled() && WorldColors.getCustomSky()) { +// return WorldColors.getSkyColor().getRGB() & 0xFFFFFF; +// } +// return original; +// } @Inject(method = "handleBlockUpdate", at = @At("HEAD"), cancellable = true) diff --git a/src/main/kotlin/com/lambda/Lambda.kt b/src/main/kotlin/com/lambda/Lambda.kt index c8242977d..d90bbbaad 100644 --- a/src/main/kotlin/com/lambda/Lambda.kt +++ b/src/main/kotlin/com/lambda/Lambda.kt @@ -27,6 +27,7 @@ import com.lambda.config.serializer.ItemCodec import com.lambda.config.serializer.ItemStackCodec import com.lambda.config.serializer.KeyCodeCodec import com.lambda.config.serializer.OptionalCodec +import com.lambda.config.serializer.TextCodec import com.lambda.core.Loader import com.lambda.event.events.ClientEvent import com.lambda.event.listener.UnsafeListener.Companion.listenOnceUnsafe @@ -79,7 +80,7 @@ object Lambda : ClientModInitializer { .registerTypeAdapter(GameProfile::class.java, GameProfileCodec) .registerTypeAdapter(Optional::class.java, OptionalCodec) .registerTypeAdapter(ItemStack::class.java, ItemStackCodec) - .registerTypeAdapter(Text::class.java, Text.Serializer(DynamicRegistryManager.EMPTY)) + .registerTypeAdapter(Text::class.java, TextCodec) // ToDo: Find out if needed .registerTypeAdapter(Item::class.java, ItemCodec) .registerTypeAdapter(BlockItem::class.java, ItemCodec) .registerTypeAdapter(ArrowItem::class.java, ItemCodec) diff --git a/src/main/kotlin/com/lambda/brigadier/argument/PlayerArguments.kt b/src/main/kotlin/com/lambda/brigadier/argument/PlayerArguments.kt index 7c6ef926b..bdaae0d48 100644 --- a/src/main/kotlin/com/lambda/brigadier/argument/PlayerArguments.kt +++ b/src/main/kotlin/com/lambda/brigadier/argument/PlayerArguments.kt @@ -35,6 +35,7 @@ import net.minecraft.command.argument.EntityArgumentType import net.minecraft.command.argument.GameProfileArgumentType import net.minecraft.command.argument.TeamArgumentType import net.minecraft.scoreboard.Team +import net.minecraft.server.PlayerConfigEntry import net.minecraft.server.command.ServerCommandSource import net.minecraft.server.network.ServerPlayerEntity @@ -69,7 +70,7 @@ fun ArgumentReader< DefaultArgumentDescriptor< GameProfileArgumentType > - >.value(): Collection { + >.value(): Collection { return GameProfileArgumentType.getProfileArgument(context, name) } diff --git a/src/main/kotlin/com/lambda/command/CommandManager.kt b/src/main/kotlin/com/lambda/command/CommandManager.kt index 2344c4259..960d83a92 100644 --- a/src/main/kotlin/com/lambda/command/CommandManager.kt +++ b/src/main/kotlin/com/lambda/command/CommandManager.kt @@ -73,7 +73,7 @@ object CommandManager { canRead() && peek() == prefix } - fun currentDispatcher(message: String): CommandDispatcher { + fun currentDispatcher(message: String): CommandDispatcher { return if (message.isLambdaCommand()) { dispatcher } else { diff --git a/src/main/kotlin/com/lambda/config/ConfigEditor.kt b/src/main/kotlin/com/lambda/config/ConfigEditor.kt index 4a9e168b9..2e74a71b1 100644 --- a/src/main/kotlin/com/lambda/config/ConfigEditor.kt +++ b/src/main/kotlin/com/lambda/config/ConfigEditor.kt @@ -38,11 +38,11 @@ open class SettingGroupEditor(open val c: T) { throw IllegalStateException("Could not access delegate for property $name", e) } - fun KProperty0.setting() = + fun KProperty0.setting() = this.delegate as? Setting, T> ?: throw IllegalStateException("Setting delegate did not match current value's type") - fun KProperty0.settingCore() = setting().core + fun KProperty0.settingCore() = setting().core @SettingEditorDsl inline fun KProperty0.edit(edits: TypedEditBuilder.(SettingCore) -> Unit) { @@ -60,14 +60,14 @@ open class SettingGroupEditor(open val c: T) { fun edit( vararg settings: KProperty0<*>, edits: BasicEditBuilder.() -> Unit - ) = BasicEditBuilder(this, settings.map { it.setting() }).apply(edits) + ) = BasicEditBuilder(this, settings.map { (it as KProperty0).setting() }).apply(edits) @SettingEditorDsl inline fun editWith( vararg settings: KProperty0<*>, other: KProperty0, edits: BasicEditBuilder.(SettingCore) -> Unit - ) = BasicEditBuilder(this, settings.map { it.setting() }).edits(other.settingCore()) + ) = BasicEditBuilder(this, settings.map { (it as KProperty0).setting() }).edits(other.settingCore()) @SettingEditorDsl inline fun editTyped( @@ -89,7 +89,7 @@ open class SettingGroupEditor(open val c: T) { @SettingEditorDsl fun hide(vararg settings: KProperty0<*>) = - hide(settings.map { it.setting() }) + hide(settings.map { (it as KProperty0).setting() }) open class BasicEditBuilder(val c: SettingGroupEditor<*>, open val settings: Collection>) { @SettingEditorDsl @@ -123,8 +123,10 @@ class ConfigurableEditor(override val c: T) : SettingGroupEdit fun hideGroup(settingGroup: ISettingGroup) = hide(settingGroup.settings) @SettingEditorDsl - fun hideGroupExcept(settingGroup: ISettingGroup, vararg except: KProperty0<*>) = - hide(*((settingGroup.settings as List>) - except.toSet()).toTypedArray()) + fun hideGroupExcept(settingGroup: ISettingGroup, vararg except: KProperty0<*>) { + val exceptSettings = except.map { (it as KProperty0).setting() }.toSet() + hide(settingGroup.settings.filter { it !in exceptSettings }) + } @SettingEditorDsl fun hideGroups(vararg settingGroups: ISettingGroup) = diff --git a/src/main/kotlin/com/lambda/config/serializer/TextCodec.kt b/src/main/kotlin/com/lambda/config/serializer/TextCodec.kt new file mode 100644 index 000000000..629e3ebb6 --- /dev/null +++ b/src/main/kotlin/com/lambda/config/serializer/TextCodec.kt @@ -0,0 +1,47 @@ +/* + * Copyright 2025 Lambda + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.lambda.config.serializer + +import com.google.gson.JsonDeserializationContext +import com.google.gson.JsonElement +import com.google.gson.JsonSerializationContext +import com.lambda.config.Codec +import com.mojang.serialization.JsonOps +import net.minecraft.text.Text +import net.minecraft.text.TextCodecs +import java.lang.reflect.Type +import kotlin.jvm.optionals.getOrElse + +object TextCodec : Codec { + override fun serialize( + src: Text, + typeOfSrc: Type, + context: JsonSerializationContext, + ): JsonElement = + TextCodecs.CODEC.encodeStart(JsonOps.INSTANCE, src) + .orThrow + + override fun deserialize( + json: JsonElement?, + typeOfT: Type?, + context: JsonDeserializationContext?, + ): Text = + TextCodecs.CODEC.parse(JsonOps.INSTANCE, json) + .result() + .getOrElse { Text.empty() } +} diff --git a/src/main/kotlin/com/lambda/event/events/MouseEvent.kt b/src/main/kotlin/com/lambda/event/events/MouseEvent.kt index 427969e39..3fcb9d3f7 100644 --- a/src/main/kotlin/com/lambda/event/events/MouseEvent.kt +++ b/src/main/kotlin/com/lambda/event/events/MouseEvent.kt @@ -21,6 +21,7 @@ import com.lambda.config.settings.complex.Bind import com.lambda.event.callback.Cancellable import com.lambda.event.callback.ICancellable import com.lambda.util.math.Vec2d +import net.minecraft.client.input.MouseInput sealed class MouseEvent { /** diff --git a/src/main/kotlin/com/lambda/event/events/RenderEvent.kt b/src/main/kotlin/com/lambda/event/events/RenderEvent.kt index 812979bfa..20a4b516d 100644 --- a/src/main/kotlin/com/lambda/event/events/RenderEvent.kt +++ b/src/main/kotlin/com/lambda/event/events/RenderEvent.kt @@ -22,13 +22,14 @@ import com.lambda.event.Event import com.lambda.event.callback.Cancellable import com.lambda.event.callback.ICancellable import com.lambda.event.listener.SafeListener.Companion.listen +import com.lambda.graphics.RenderMain import com.lambda.graphics.renderer.esp.ShapeBuilder -import com.lambda.graphics.renderer.esp.Treed fun Any.onStaticRender(block: SafeContext.(ShapeBuilder) -> Unit) = - listen { block(ShapeBuilder(Treed.Static.faceBuilder, Treed.Static.edgeBuilder)) } + listen { block(ShapeBuilder(RenderMain.StaticESP)) } + fun Any.onDynamicRender(block: SafeContext.(ShapeBuilder) -> Unit) = - listen { block(ShapeBuilder(Treed.Dynamic.faceBuilder, Treed.Dynamic.edgeBuilder)) } + listen { block(ShapeBuilder(RenderMain.DynamicESP)) } sealed class RenderEvent { object Upload : Event diff --git a/src/main/kotlin/com/lambda/graphics/RenderMain.kt b/src/main/kotlin/com/lambda/graphics/RenderMain.kt index 3668298f2..bbd9b7c14 100644 --- a/src/main/kotlin/com/lambda/graphics/RenderMain.kt +++ b/src/main/kotlin/com/lambda/graphics/RenderMain.kt @@ -17,60 +17,47 @@ package com.lambda.graphics -import com.lambda.Lambda.mc import com.lambda.event.EventFlow.post import com.lambda.event.events.RenderEvent import com.lambda.event.events.TickEvent import com.lambda.event.listener.SafeListener.Companion.listen -import com.lambda.graphics.gl.GlStateUtils.setupGL import com.lambda.graphics.gl.Matrices import com.lambda.graphics.gl.Matrices.resetMatrices -import com.lambda.graphics.renderer.esp.Treed -import com.lambda.util.math.Vec2d -import com.mojang.blaze3d.opengl.GlStateManager -import com.mojang.blaze3d.systems.RenderSystem -import net.minecraft.client.gl.GlBackend -import net.minecraft.client.texture.GlTexture +import com.lambda.graphics.mc.LambdaRenderPipelines +import com.lambda.graphics.mc.TransientRegionESP import org.joml.Matrix4f -import org.lwjgl.opengl.GL30.GL_FRAMEBUFFER object RenderMain { - val projectionMatrix = Matrix4f() - val modelViewMatrix get() = Matrices.peek() - val projModel: Matrix4f get() = Matrix4f(projectionMatrix).mul(modelViewMatrix) + val StaticESP = TransientRegionESP("Static") + val DynamicESP = TransientRegionESP("Dynamic") - var screenSize = Vec2d.ZERO + val projectionMatrix = Matrix4f() + val modelViewMatrix + get() = Matrices.peek() + val projModel: Matrix4f + get() = Matrix4f(projectionMatrix).mul(modelViewMatrix) @JvmStatic fun render3D(positionMatrix: Matrix4f, projMatrix: Matrix4f) { resetMatrices(positionMatrix) projectionMatrix.set(projMatrix) - setupGL { - val framebuffer = mc.framebuffer - val prevFramebuffer = (framebuffer.getColorAttachment() as GlTexture).getOrCreateFramebuffer( - (RenderSystem.getDevice() as GlBackend).framebufferManager, - null - ) - - GlStateManager._glBindFramebuffer(GL_FRAMEBUFFER, prevFramebuffer) + // Render transient ESPs using the new pipeline + StaticESP.render(false) // Depth tested + DynamicESP.render(true) // Through walls - Treed.Static.render() - Treed.Dynamic.render() - - RenderEvent.Render.post() - } + RenderEvent.Render.post() } init { listen { - Treed.Static.clear() - Treed.Dynamic.clear() + StaticESP.clear() + DynamicESP.clear() RenderEvent.Upload.post() - Treed.Static.upload() - Treed.Dynamic.upload() + StaticESP.upload() + DynamicESP.upload() } } } diff --git a/src/main/kotlin/com/lambda/graphics/gl/GlStateUtils.kt b/src/main/kotlin/com/lambda/graphics/gl/GlStateUtils.kt index 77b830aca..c8e57ef5f 100644 --- a/src/main/kotlin/com/lambda/graphics/gl/GlStateUtils.kt +++ b/src/main/kotlin/com/lambda/graphics/gl/GlStateUtils.kt @@ -30,6 +30,7 @@ import org.lwjgl.opengl.GL30C.glDisable import org.lwjgl.opengl.GL30C.glEnable import org.lwjgl.opengl.GL30C.glLineWidth +// ToDo: Migrate particle system so we can remove this object GlStateUtils { private var depthTestState = true private var blendState = false diff --git a/src/main/kotlin/com/lambda/graphics/mc/ChunkedRegionESP.kt b/src/main/kotlin/com/lambda/graphics/mc/ChunkedRegionESP.kt new file mode 100644 index 000000000..479314688 --- /dev/null +++ b/src/main/kotlin/com/lambda/graphics/mc/ChunkedRegionESP.kt @@ -0,0 +1,312 @@ +/* + * Copyright 2025 Lambda + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.lambda.graphics.mc + +import com.lambda.Lambda.mc +import com.lambda.event.events.RenderEvent +import com.lambda.event.events.TickEvent +import com.lambda.event.events.WorldEvent +import com.lambda.event.listener.SafeListener.Companion.listen +import com.lambda.event.listener.SafeListener.Companion.listenConcurrently +import com.lambda.module.Module +import com.lambda.module.modules.client.StyleEditor +import com.lambda.threading.runSafe +import com.lambda.util.world.FastVector +import com.lambda.util.world.fastVectorOf +import com.mojang.blaze3d.buffers.GpuBuffer +import com.mojang.blaze3d.systems.RenderPass +import com.mojang.blaze3d.systems.RenderSystem +import com.mojang.blaze3d.vertex.VertexFormat +import net.minecraft.world.World +import net.minecraft.world.chunk.WorldChunk +import org.joml.Matrix4f +import org.joml.Quaternionf +import org.joml.Vector3f +import org.joml.Vector4f +import java.util.* +import java.util.concurrent.ConcurrentHashMap +import java.util.concurrent.ConcurrentLinkedDeque + +/** + * Region-based chunked ESP system using MC 1.21.11's new render pipeline. + * + * This system: + * - Uses region-relative coordinates for precision-safe rendering + * - Uses MC's RenderPass and BufferBuilder system + * - Maintains per-chunk geometry for efficient updates + * - Supports both depth-tested and through-wall rendering + * + * @param owner The module that owns this ESP system + * @param throughWalls Whether to render through walls + * @param update The update function called for each block position + */ +class ChunkedRegionESP private constructor( + owner: Module, + private val throughWalls: () -> Boolean, + private val update: RegionShapeBuilder.(World, FastVector) -> Unit +) { + private val chunkMap = ConcurrentHashMap() + + private val WorldChunk.regionChunk + get() = chunkMap.getOrPut(pos.toLong()) { RegionChunk(this, this@ChunkedRegionESP) } + + private val uploadQueue = ConcurrentLinkedDeque<() -> Unit>() + private val rebuildQueue = ConcurrentLinkedDeque() + + /** Mark all tracked chunks for rebuild. */ + fun rebuild() { + rebuildQueue.clear() + rebuildQueue.addAll(chunkMap.values) + } + + /** + * Load all currently loaded world chunks and mark them for rebuild. Call this when the module + * is enabled to populate initial chunks. + */ + fun rebuildAll() { + runSafe { + val chunksArray = world.chunkManager.chunks.chunks + (0 until chunksArray.length()).forEach { i -> + chunksArray.get(i)?.regionChunk?.markDirty() + } + } + } + + /** Clear all chunk data. */ + fun clear() { + chunkMap.values.forEach { it.close() } + chunkMap.clear() + rebuildQueue.clear() + uploadQueue.clear() + } + + init { + owner.listen { event -> + val pos = event.pos + world.getWorldChunk(pos)?.regionChunk?.markDirty() + + val xInChunk = pos.x and 15 + val zInChunk = pos.z and 15 + + if (xInChunk == 0) world.getWorldChunk(pos.west())?.regionChunk?.markDirty() + if (xInChunk == 15) world.getWorldChunk(pos.east())?.regionChunk?.markDirty() + if (zInChunk == 0) world.getWorldChunk(pos.north())?.regionChunk?.markDirty() + if (zInChunk == 15) world.getWorldChunk(pos.south())?.regionChunk?.markDirty() + } + + owner.listen { event -> event.chunk.regionChunk.markDirty() } + + owner.listen { + val pos = it.chunk.pos.toLong() + chunkMap.remove(pos)?.close() + } + + owner.listenConcurrently { + val queueSize = rebuildQueue.size + val polls = minOf(StyleEditor.rebuildsPerTick, queueSize) + repeat(polls) { + rebuildQueue.poll()?.rebuild() + } + } + + owner.listen { + val polls = minOf(StyleEditor.uploadsPerTick, uploadQueue.size) + repeat(polls) { + uploadQueue.poll()?.invoke() + } + } + + owner.listen { render() } + } + + /** Render all chunks with geometry. */ + private fun render() { + val camera = mc.gameRenderer?.camera ?: return + val cameraPos = camera.pos + val framebuffer = mc.framebuffer ?: return + + val chunksWithData = chunkMap.values.filter { it.hasData } + if (chunksWithData.isEmpty()) return + + val chunkTransforms = + chunksWithData.map { chunk -> + val offset = chunk.region.computeCameraRelativeOffset(cameraPos) + val rotation = camera.rotation.conjugate(Quaternionf()) + val modelView = Matrix4f().rotation(rotation).translate(offset) + val transforms = RenderSystem.getDynamicUniforms().write( + modelView, + Vector4f(1.0f, 1.0f, 1.0f, 1.0f), // color modulator + Vector3f( + 0f, + 0f, + 0f + ), // model offset - ignored by vanilla shaders! + Matrix4f() // texture matrix + ) + chunk to transforms + } + + RenderSystem.getDevice() + .createCommandEncoder() + .createRenderPass( + { "Lambda ESP Faces" }, + framebuffer.colorAttachmentView, + OptionalInt.empty(), + framebuffer.depthAttachmentView, + OptionalDouble.empty() + ) + .use { renderPass -> + val pipeline = + if (throughWalls()) LambdaRenderPipelines.ESP_QUADS_THROUGH + else LambdaRenderPipelines.ESP_QUADS + renderPass.setPipeline(pipeline) + RenderSystem.bindDefaultUniforms(renderPass) + + chunkTransforms.forEach { (chunk, transforms) -> + renderPass.setUniform("DynamicTransforms", transforms) + chunk.renderFaces(renderPass) + } + } + + RenderSystem.getDevice() + .createCommandEncoder() + .createRenderPass( + { "Lambda ESP Edges" }, + framebuffer.colorAttachmentView, + OptionalInt.empty(), + framebuffer.depthAttachmentView, + OptionalDouble.empty() + ) + .use { renderPass -> + val pipeline = + if (throughWalls()) LambdaRenderPipelines.ESP_LINES_THROUGH + else LambdaRenderPipelines.ESP_LINES + renderPass.setPipeline(pipeline) + RenderSystem.bindDefaultUniforms(renderPass) + + chunkTransforms.forEach { (chunk, transforms) -> + renderPass.setUniform("DynamicTransforms", transforms) + chunk.renderEdges(renderPass) + } + } + } + + companion object { + /** + * Create a new chunked region ESP for a module. + * + * @param throughWalls Whether to render through walls + * @param update The update function called for each block position + */ + fun Module.newChunkedRegionESP( + throughWalls: () -> Boolean = { false }, + update: RegionShapeBuilder.(World, FastVector) -> Unit + ) = ChunkedRegionESP(this@newChunkedRegionESP, throughWalls, update) + } + + /** Per-chunk rendering data. */ + private inner class RegionChunk(val chunk: WorldChunk, val owner: ChunkedRegionESP) { + val region = RenderRegion.forChunk(chunk.pos.x, chunk.pos.z, chunk.bottomY) + + private var faceBuffer: GpuBuffer? = null + private var edgeBuffer: GpuBuffer? = null + private var faceIndexCount = 0 + private var edgeIndexCount = 0 + + var hasData = false + private set + + private var isDirty = false + + fun markDirty() { + isDirty = true + if (!owner.rebuildQueue.contains(this)) { + owner.rebuildQueue.add(this) + } + } + + /** + * Rebuild this chunk's geometry. Runs on a background thread - collects vertices into + * thread-safe collections. + */ + fun rebuild() { + if (!isDirty) return + val builder = RegionShapeBuilder(region) + + var blockCount = 0 + for (x in chunk.pos.startX..chunk.pos.endX) { + for (z in chunk.pos.startZ..chunk.pos.endZ) { + for (y in chunk.bottomY..chunk.height) { + owner.update(builder, chunk.world, fastVectorOf(x, y, z)) + blockCount++ + } + } + } + + owner.uploadQueue.add { upload(builder.collector) } + } + + /** Upload collected vertices to GPU. Must run on the main/render thread. */ + private fun upload(collector: RegionVertexCollector) { + faceBuffer?.close() + edgeBuffer?.close() + val result = collector.upload() + + faceBuffer = result.faces?.buffer + faceIndexCount = result.faces?.indexCount ?: 0 + + edgeBuffer = result.edges?.buffer + edgeIndexCount = result.edges?.indexCount ?: 0 + + hasData = faceBuffer != null || edgeBuffer != null + isDirty = false + } + + fun renderFaces(renderPass: RenderPass) { + val buffer = faceBuffer ?: return + if (faceIndexCount == 0) return + + renderPass.setVertexBuffer(0, buffer) + val shapeIndexBuffer = RenderSystem.getSequentialBuffer(VertexFormat.DrawMode.QUADS) + val indexBuffer = shapeIndexBuffer.getIndexBuffer(faceIndexCount) + + renderPass.setIndexBuffer(indexBuffer, shapeIndexBuffer.indexType) + renderPass.drawIndexed(0, 0, faceIndexCount, 1) + } + + fun renderEdges(renderPass: RenderPass) { + val buffer = edgeBuffer ?: return + if (edgeIndexCount == 0) return + + renderPass.setVertexBuffer(0, buffer) + val shapeIndexBuffer = RenderSystem.getSequentialBuffer(VertexFormat.DrawMode.LINES) + val indexBuffer = shapeIndexBuffer.getIndexBuffer(edgeIndexCount) + + renderPass.setIndexBuffer(indexBuffer, shapeIndexBuffer.indexType) + renderPass.drawIndexed(0, 0, edgeIndexCount, 1) + } + + fun close() { + faceBuffer?.close() + edgeBuffer?.close() + faceBuffer = null + edgeBuffer = null + hasData = false + } + } +} diff --git a/src/main/kotlin/com/lambda/graphics/mc/LambdaRenderPipelines.kt b/src/main/kotlin/com/lambda/graphics/mc/LambdaRenderPipelines.kt new file mode 100644 index 000000000..3dcb4472c --- /dev/null +++ b/src/main/kotlin/com/lambda/graphics/mc/LambdaRenderPipelines.kt @@ -0,0 +1,164 @@ +/* + * Copyright 2025 Lambda + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.lambda.graphics.mc + +import com.lambda.core.Loadable +import com.mojang.blaze3d.pipeline.BlendFunction +import com.mojang.blaze3d.pipeline.RenderPipeline +import com.mojang.blaze3d.platform.DepthTestFunction +import com.mojang.blaze3d.vertex.VertexFormat +import net.minecraft.client.gl.RenderPipelines +import net.minecraft.client.render.VertexFormats +import net.minecraft.util.Identifier + +object LambdaRenderPipelines : Loadable { + override val priority: Int + get() = 100 // High priority to ensure pipelines are ready early + + /** + * Base snippet for Lambda ESP rendering. Includes transforms, projection, and a custom + * per-region uniform. + */ + private val LAMBDA_ESP_SNIPPET = + RenderPipeline.builder(RenderPipelines.TRANSFORMS_AND_PROJECTION_SNIPPET).buildSnippet() + + /** + * Pipeline for static ESP faces (filled quads). + * - Translucent blending for see-through effect + * - No depth write to allow overlapping + * - No culling to see all faces + * - Uses TRIANGLES mode for maximum flexibility + */ + val ESP_FACES: RenderPipeline = + RenderPipelines.register( + RenderPipeline.builder(LAMBDA_ESP_SNIPPET) + .withLocation(Identifier.of("lambda", "pipeline/esp_faces")) + .withVertexShader(Identifier.ofVanilla("core/position_color")) + .withFragmentShader(Identifier.ofVanilla("core/position_color")) + .withBlend(BlendFunction.TRANSLUCENT) + .withDepthWrite(false) + .withDepthTestFunction(DepthTestFunction.LEQUAL_DEPTH_TEST) + .withCull(false) + .withVertexFormat( + VertexFormats.POSITION_COLOR, + VertexFormat.DrawMode.TRIANGLES // ToDo: Should we use Triangles or Quads? + ) + .build() + ) + + /** + * Pipeline for static ESP faces that render through walls. + * - Same as ESP_FACES but with no depth test + */ + val ESP_FACES_THROUGH: RenderPipeline = + RenderPipelines.register( + RenderPipeline.builder(LAMBDA_ESP_SNIPPET) + .withLocation(Identifier.of("lambda", "pipeline/esp_faces_through")) + .withVertexShader(Identifier.ofVanilla("core/position_color")) + .withFragmentShader(Identifier.ofVanilla("core/position_color")) + .withBlend(BlendFunction.TRANSLUCENT) + .withDepthWrite(false) + .withDepthTestFunction(DepthTestFunction.NO_DEPTH_TEST) + .withCull(false) + .withVertexFormat( + VertexFormats.POSITION_COLOR, + VertexFormat.DrawMode.TRIANGLES + ) + .build() + ) + + /** + * Pipeline for ESP lines/outlines. + * - Uses MC's line rendering with per-vertex line width + * - No depth write for overlapping + * - No culling + */ + val ESP_LINES: RenderPipeline = + RenderPipelines.register( + RenderPipeline.builder(LAMBDA_ESP_SNIPPET, RenderPipelines.GLOBALS_SNIPPET) + .withLocation(Identifier.of("lambda", "pipeline/esp_lines")) + .withVertexShader(Identifier.ofVanilla("core/rendertype_lines")) + .withFragmentShader(Identifier.ofVanilla("core/rendertype_lines")) + .withBlend(BlendFunction.TRANSLUCENT) + .withDepthWrite(false) + .withDepthTestFunction(DepthTestFunction.LEQUAL_DEPTH_TEST) + .withCull(false) + .withVertexFormat( + VertexFormats.POSITION_COLOR_NORMAL_LINE_WIDTH, + VertexFormat.DrawMode.LINES + ) + .build() + ) + + /** Pipeline for ESP lines that render through walls. */ + val ESP_LINES_THROUGH: RenderPipeline = + RenderPipelines.register( + RenderPipeline.builder(LAMBDA_ESP_SNIPPET, RenderPipelines.GLOBALS_SNIPPET) + .withLocation(Identifier.of("lambda", "pipeline/esp_lines_through")) + .withVertexShader(Identifier.ofVanilla("core/rendertype_lines")) + .withFragmentShader(Identifier.ofVanilla("core/rendertype_lines")) + .withBlend(BlendFunction.TRANSLUCENT) + .withDepthWrite(false) + .withDepthTestFunction(DepthTestFunction.NO_DEPTH_TEST) + .withCull(false) + .withVertexFormat( + VertexFormats.POSITION_COLOR_NORMAL_LINE_WIDTH, + VertexFormat.DrawMode.LINES + ) + .build() + ) + + /** + * Pipeline for quad-based ESP (compatible with existing shape building). Uses QUADS draw mode + * which MC converts to triangles internally. + */ + val ESP_QUADS: RenderPipeline = + RenderPipelines.register( + RenderPipeline.builder(LAMBDA_ESP_SNIPPET) + .withLocation(Identifier.of("lambda", "pipeline/esp_quads")) + .withVertexShader(Identifier.ofVanilla("core/position_color")) + .withFragmentShader(Identifier.ofVanilla("core/position_color")) + .withBlend(BlendFunction.TRANSLUCENT) + .withDepthWrite(false) + .withDepthTestFunction(DepthTestFunction.LEQUAL_DEPTH_TEST) + .withCull(false) + .withVertexFormat( + VertexFormats.POSITION_COLOR, + VertexFormat.DrawMode.QUADS + ) + .build() + ) + + /** Pipeline for quad-based ESP that renders through walls. */ + val ESP_QUADS_THROUGH: RenderPipeline = + RenderPipelines.register( + RenderPipeline.builder(LAMBDA_ESP_SNIPPET) + .withLocation(Identifier.of("lambda", "pipeline/esp_quads_through")) + .withVertexShader(Identifier.ofVanilla("core/position_color")) + .withFragmentShader(Identifier.ofVanilla("core/position_color")) + .withBlend(BlendFunction.TRANSLUCENT) + .withDepthWrite(false) + .withDepthTestFunction(DepthTestFunction.NO_DEPTH_TEST) + .withCull(false) + .withVertexFormat( + VertexFormats.POSITION_COLOR, + VertexFormat.DrawMode.QUADS + ) + .build() + ) +} diff --git a/src/main/kotlin/com/lambda/graphics/mc/RegionRenderer.kt b/src/main/kotlin/com/lambda/graphics/mc/RegionRenderer.kt new file mode 100644 index 000000000..fa8e96e87 --- /dev/null +++ b/src/main/kotlin/com/lambda/graphics/mc/RegionRenderer.kt @@ -0,0 +1,142 @@ +/* + * Copyright 2025 Lambda + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.lambda.graphics.mc + +import com.lambda.Lambda.mc +import com.mojang.blaze3d.buffers.GpuBuffer +import com.mojang.blaze3d.systems.RenderPass +import com.mojang.blaze3d.systems.RenderSystem +import com.mojang.blaze3d.vertex.VertexFormat +import java.util.* + +/** + * Region-based renderer for ESP rendering using MC 1.21.11's new render pipeline. + * + * This renderer manages the lifecycle of dedicated GPU buffers for a specific region and provides + * methods to render them within a RenderPass. + * + * @param region The render region this renderer is associated with + */ +class RegionRenderer(val region: RenderRegion) { + + // Dedicated GPU buffers for faces and edges + private var faceVertexBuffer: GpuBuffer? = null + private var edgeVertexBuffer: GpuBuffer? = null + + // Index counts for draw calls + private var faceIndexCount = 0 + private var edgeIndexCount = 0 + + // State tracking + private var hasData = false + + /** + * Upload collected vertices from an external collector. This must be called on the main/render + * thread. + * + * @param collector The collector containing the geometry to upload + */ + fun upload(collector: RegionVertexCollector) { + val result = collector.upload() + + // Cleanup old buffers + faceVertexBuffer?.close() + edgeVertexBuffer?.close() + + // Assign new buffers and counts + faceVertexBuffer = result.faces?.buffer + faceIndexCount = result.faces?.indexCount ?: 0 + + edgeVertexBuffer = result.edges?.buffer + edgeIndexCount = result.edges?.indexCount ?: 0 + + hasData = faceVertexBuffer != null || edgeVertexBuffer != null + } + + /** + * Render faces using the given render pass. + * + * @param renderPass The active RenderPass to record commands into + */ + fun renderFaces(renderPass: RenderPass) { + val vb = faceVertexBuffer ?: return + if (faceIndexCount == 0) return + + renderPass.setVertexBuffer(0, vb) + // Use vanilla's sequential index buffer for quads + val shapeIndexBuffer = RenderSystem.getSequentialBuffer(VertexFormat.DrawMode.QUADS) + val indexBuffer = shapeIndexBuffer.getIndexBuffer(faceIndexCount) + + renderPass.setIndexBuffer(indexBuffer, shapeIndexBuffer.indexType) + renderPass.drawIndexed(0, 0, faceIndexCount, 1) + } + + /** + * Render edges using the given render pass. + * + * @param renderPass The active RenderPass to record commands into + */ + fun renderEdges(renderPass: RenderPass) { + val vb = edgeVertexBuffer ?: return + if (edgeIndexCount == 0) return + + renderPass.setVertexBuffer(0, vb) + // Use vanilla's sequential index buffer for lines + val shapeIndexBuffer = RenderSystem.getSequentialBuffer(VertexFormat.DrawMode.LINES) + val indexBuffer = shapeIndexBuffer.getIndexBuffer(edgeIndexCount) + + renderPass.setIndexBuffer(indexBuffer, shapeIndexBuffer.indexType) + renderPass.drawIndexed(0, 0, edgeIndexCount, 1) + } + + /** Clear all geometry data and release GPU resources. */ + fun clearData() { + faceVertexBuffer?.close() + edgeVertexBuffer?.close() + faceVertexBuffer = null + edgeVertexBuffer = null + faceIndexCount = 0 + edgeIndexCount = 0 + hasData = false + } + + /** Check if this renderer has any data to render. */ + fun hasData(): Boolean = hasData + + /** Clean up all resources. */ + fun close() { + clearData() + } + + companion object { + /** Helper to create a render pass targeting the main framebuffer. */ + fun createRenderPass(label: String): RenderPass? { + val framebuffer = mc.framebuffer ?: return null + + return RenderSystem.getDevice() + .createCommandEncoder() + .createRenderPass( + { label }, + framebuffer.colorAttachmentView, + OptionalInt.empty(), + framebuffer.depthAttachmentView, + OptionalDouble.empty() + ) + } + } +} diff --git a/src/main/kotlin/com/lambda/graphics/mc/RegionShapeBuilder.kt b/src/main/kotlin/com/lambda/graphics/mc/RegionShapeBuilder.kt new file mode 100644 index 000000000..fcd713396 --- /dev/null +++ b/src/main/kotlin/com/lambda/graphics/mc/RegionShapeBuilder.kt @@ -0,0 +1,338 @@ +/* + * Copyright 2025 Lambda + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.lambda.graphics.mc + +import com.lambda.graphics.renderer.esp.DirectionMask +import com.lambda.graphics.renderer.esp.DirectionMask.hasDirection +import com.lambda.graphics.renderer.esp.DynamicAABB +import com.lambda.module.modules.client.StyleEditor +import com.lambda.threading.runSafe +import com.lambda.util.BlockUtils.blockState +import com.lambda.util.extension.outlineShape +import net.minecraft.block.BlockState +import net.minecraft.block.entity.BlockEntity +import net.minecraft.entity.Entity +import net.minecraft.util.math.BlockPos +import net.minecraft.util.math.Box +import net.minecraft.util.shape.VoxelShape +import java.awt.Color + +/** + * Shape builder for region-based rendering. All coordinates are automatically converted to + * region-relative positions. + * + * This class provides the same DSL as ShapeDsl but collects vertex data in thread-safe collections + * for later upload to MC's BufferBuilder. + * + * @param region The render region (provides origin for coordinate conversion) + */ +class RegionShapeBuilder(val region: RenderRegion) { + val collector = RegionVertexCollector() + + private val lineWidth: Float + get() = StyleEditor.outlineWidth.toFloat() + + /** Convert world coordinates to region-relative. */ + private fun toRelative(x: Double, y: Double, z: Double) = Triple( + (x - region.originX).toFloat(), + (y - region.originY).toFloat(), + (z - region.originZ).toFloat() + ) + + /** Add a colored quad face (filled rectangle). */ + fun filled( + box: Box, + bottomColor: Color, + topColor: Color = bottomColor, + sides: Int = DirectionMask.ALL + ) { + val (x1, y1, z1) = toRelative(box.minX, box.minY, box.minZ) + val (x2, y2, z2) = toRelative(box.maxX, box.maxY, box.maxZ) + + // Bottom-left-back, bottom-left-front, etc. + if (sides.hasDirection(DirectionMask.EAST)) { + // East face (+X) + faceVertex(x2, y1, z1, bottomColor) + faceVertex(x2, y2, z1, topColor) + faceVertex(x2, y2, z2, topColor) + faceVertex(x2, y1, z2, bottomColor) + } + if (sides.hasDirection(DirectionMask.WEST)) { + // West face (-X) + faceVertex(x1, y1, z1, bottomColor) + faceVertex(x1, y1, z2, bottomColor) + faceVertex(x1, y2, z2, topColor) + faceVertex(x1, y2, z1, topColor) + } + if (sides.hasDirection(DirectionMask.UP)) { + // Top face (+Y) + faceVertex(x1, y2, z1, topColor) + faceVertex(x1, y2, z2, topColor) + faceVertex(x2, y2, z2, topColor) + faceVertex(x2, y2, z1, topColor) + } + if (sides.hasDirection(DirectionMask.DOWN)) { + // Bottom face (-Y) + faceVertex(x1, y1, z1, bottomColor) + faceVertex(x2, y1, z1, bottomColor) + faceVertex(x2, y1, z2, bottomColor) + faceVertex(x1, y1, z2, bottomColor) + } + if (sides.hasDirection(DirectionMask.SOUTH)) { + // South face (+Z) + faceVertex(x1, y1, z2, bottomColor) + faceVertex(x2, y1, z2, bottomColor) + faceVertex(x2, y2, z2, topColor) + faceVertex(x1, y2, z2, topColor) + } + if (sides.hasDirection(DirectionMask.NORTH)) { + // North face (-Z) + faceVertex(x1, y1, z1, bottomColor) + faceVertex(x1, y2, z1, topColor) + faceVertex(x2, y2, z1, topColor) + faceVertex(x2, y1, z1, bottomColor) + } + } + + fun filled(box: Box, color: Color, sides: Int = DirectionMask.ALL) = + filled(box, color, color, sides) + + fun filled(box: DynamicAABB, color: Color, sides: Int = DirectionMask.ALL) { + box.pair?.second?.let { filled(it, color, sides) } + } + + fun filled(pos: BlockPos, state: BlockState, color: Color, sides: Int = DirectionMask.ALL) = + runSafe { + val shape = outlineShape(state, pos) + if (shape.isEmpty) { + filled(Box(pos), color, sides) + } else { + filled(shape, color, sides) + } + } + + fun filled(pos: BlockPos, color: Color, sides: Int = DirectionMask.ALL) = runSafe { + filled(pos, blockState(pos), color, sides) + } + + fun filled(pos: BlockPos, entity: BlockEntity, color: Color, sides: Int = DirectionMask.ALL) = + filled(pos, entity.cachedState, color, sides) + + fun filled(shape: VoxelShape, color: Color, sides: Int = DirectionMask.ALL) { + shape.boundingBoxes.forEach { filled(it, color, color, sides) } + } + + /** Add outline (lines) for a box. */ + fun outline( + box: Box, + bottomColor: Color, + topColor: Color = bottomColor, + sides: Int = DirectionMask.ALL, + mode: DirectionMask.OutlineMode = DirectionMask.OutlineMode.And + ) { + val (x1, y1, z1) = toRelative(box.minX, box.minY, box.minZ) + val (x2, y2, z2) = toRelative(box.maxX, box.maxY, box.maxZ) + + val hasEast = sides.hasDirection(DirectionMask.EAST) + val hasWest = sides.hasDirection(DirectionMask.WEST) + val hasUp = sides.hasDirection(DirectionMask.UP) + val hasDown = sides.hasDirection(DirectionMask.DOWN) + val hasSouth = sides.hasDirection(DirectionMask.SOUTH) + val hasNorth = sides.hasDirection(DirectionMask.NORTH) + + // Top edges + if (mode.check(hasUp, hasNorth)) line(x1, y2, z1, x2, y2, z1, topColor) + if (mode.check(hasUp, hasSouth)) line(x1, y2, z2, x2, y2, z2, topColor) + if (mode.check(hasUp, hasWest)) line(x1, y2, z1, x1, y2, z2, topColor) + if (mode.check(hasUp, hasEast)) line(x2, y2, z2, x2, y2, z1, topColor) + + // Bottom edges + if (mode.check(hasDown, hasNorth)) line(x1, y1, z1, x2, y1, z1, bottomColor) + if (mode.check(hasDown, hasSouth)) line(x1, y1, z2, x2, y1, z2, bottomColor) + if (mode.check(hasDown, hasWest)) line(x1, y1, z1, x1, y1, z2, bottomColor) + if (mode.check(hasDown, hasEast)) line(x2, y1, z1, x2, y1, z2, bottomColor) + + // Vertical edges + if (mode.check(hasWest, hasNorth)) line(x1, y2, z1, x1, y1, z1, topColor, bottomColor) + if (mode.check(hasNorth, hasEast)) line(x2, y2, z1, x2, y1, z1, topColor, bottomColor) + if (mode.check(hasEast, hasSouth)) line(x2, y2, z2, x2, y1, z2, topColor, bottomColor) + if (mode.check(hasSouth, hasWest)) line(x1, y2, z2, x1, y1, z2, topColor, bottomColor) + } + + fun outline( + box: Box, + color: Color, + sides: Int = DirectionMask.ALL, + mode: DirectionMask.OutlineMode = DirectionMask.OutlineMode.And + ) = outline(box, color, color, sides, mode) + + fun outline( + box: DynamicAABB, + color: Color, + sides: Int = DirectionMask.ALL, + mode: DirectionMask.OutlineMode = DirectionMask.OutlineMode.And + ) { + box.pair?.second?.let { outline(it, color, sides, mode) } + } + + fun outline( + pos: BlockPos, + state: BlockState, + color: Color, + sides: Int = DirectionMask.ALL, + mode: DirectionMask.OutlineMode = DirectionMask.OutlineMode.And + ) = runSafe { + val shape = outlineShape(state, pos) + if (shape.isEmpty) { + outline(Box(pos), color, sides, mode) + } else { + outline(shape, color, sides, mode) + } + } + + fun outline( + pos: BlockPos, + color: Color, + sides: Int = DirectionMask.ALL, + mode: DirectionMask.OutlineMode = DirectionMask.OutlineMode.And + ) = runSafe { outline(pos, blockState(pos), color, sides, mode) } + + fun outline( + pos: BlockPos, + entity: BlockEntity, + color: Color, + sides: Int = DirectionMask.ALL, + mode: DirectionMask.OutlineMode = DirectionMask.OutlineMode.And + ) = runSafe { outline(pos, entity.cachedState, color, sides, mode) } + + fun outline( + shape: VoxelShape, + color: Color, + sides: Int = DirectionMask.ALL, + mode: DirectionMask.OutlineMode = DirectionMask.OutlineMode.And + ) { + shape.boundingBoxes.forEach { outline(it, color, sides, mode) } + } + + /** Add both filled and outline for a box. */ + fun box( + pos: BlockPos, + state: BlockState, + filledColor: Color, + outlineColor: Color, + sides: Int = DirectionMask.ALL, + mode: DirectionMask.OutlineMode = DirectionMask.OutlineMode.And + ) = runSafe { + filled(pos, state, filledColor, sides) + outline(pos, state, outlineColor, sides, mode) + } + + fun box( + pos: BlockPos, + filledColor: Color, + outlineColor: Color, + sides: Int = DirectionMask.ALL, + mode: DirectionMask.OutlineMode = DirectionMask.OutlineMode.And + ) = runSafe { + filled(pos, filledColor, sides) + outline(pos, outlineColor, sides, mode) + } + + fun box( + box: Box, + filledColor: Color, + outlineColor: Color, + sides: Int = DirectionMask.ALL, + mode: DirectionMask.OutlineMode = DirectionMask.OutlineMode.And + ) { + filled(box, filledColor, sides) + outline(box, outlineColor, sides, mode) + } + + fun box( + box: DynamicAABB, + filledColor: Color, + outlineColor: Color, + sides: Int = DirectionMask.ALL, + mode: DirectionMask.OutlineMode = DirectionMask.OutlineMode.And + ) { + filled(box, filledColor, sides) + outline(box, outlineColor, sides, mode) + } + + fun box( + entity: BlockEntity, + color: Color, + sides: Int = DirectionMask.ALL, + mode: DirectionMask.OutlineMode = DirectionMask.OutlineMode.And + ) = runSafe { + filled(entity.pos, entity, color, sides) + outline(entity.pos, entity, color, sides, mode) + } + + fun box( + entity: Entity, + color: Color, + sides: Int = DirectionMask.ALL, + mode: DirectionMask.OutlineMode = DirectionMask.OutlineMode.And + ) = runSafe { + filled(entity.boundingBox, color, sides) + outline(entity.boundingBox, color, sides, mode) + } + + // =========== Private helpers =========== + + private fun faceVertex(x: Float, y: Float, z: Float, color: Color) { + collector.addFaceVertex(x, y, z, color) + } + + private fun line( + x1: Float, + y1: Float, + z1: Float, + x2: Float, + y2: Float, + z2: Float, + color: Color + ) { + line(x1, y1, z1, x2, y2, z2, color, color) + } + + private fun line( + x1: Float, + y1: Float, + z1: Float, + x2: Float, + y2: Float, + z2: Float, + color1: Color, + color2: Color + ) { + // Calculate normal (direction of line) + val dx = x2 - x1 + val dy = y2 - y1 + val dz = z2 - z1 + val len = kotlin.math.sqrt(dx * dx + dy * dy + dz * dz) + val nx = if (len > 0) dx / len else 0f + val ny = if (len > 0) dy / len else 1f + val nz = if (len > 0) dz / len else 0f + + collector.addEdgeVertex(x1, y1, z1, color1, nx, ny, nz, lineWidth) + collector.addEdgeVertex(x2, y2, z2, color2, nx, ny, nz, lineWidth) + } +} diff --git a/src/main/kotlin/com/lambda/graphics/mc/RegionVertexCollector.kt b/src/main/kotlin/com/lambda/graphics/mc/RegionVertexCollector.kt new file mode 100644 index 000000000..e322816ab --- /dev/null +++ b/src/main/kotlin/com/lambda/graphics/mc/RegionVertexCollector.kt @@ -0,0 +1,168 @@ +/* + * Copyright 2025 Lambda + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.lambda.graphics.mc + +import com.mojang.blaze3d.buffers.GpuBuffer +import com.mojang.blaze3d.systems.RenderSystem +import com.mojang.blaze3d.vertex.VertexFormat +import net.minecraft.client.render.BufferBuilder +import net.minecraft.client.render.VertexFormats +import net.minecraft.client.util.BufferAllocator +import java.awt.Color +import java.util.concurrent.ConcurrentLinkedDeque + +/** + * Thread-safe vertex collector for region-based rendering. + * + * Collects vertex data on background threads using thread-safe collections, then writes to MC's + * BufferBuilder and uploads on the main thread. + */ +class RegionVertexCollector { + val faceVertices = ConcurrentLinkedDeque() + val edgeVertices = ConcurrentLinkedDeque() + + /** Face vertex data (position + color). */ + data class FaceVertex( + val x: Float, + val y: Float, + val z: Float, + val r: Int, + val g: Int, + val b: Int, + val a: Int + ) + + /** Edge vertex data (position + color + normal + line width). */ + data class EdgeVertex( + val x: Float, + val y: Float, + val z: Float, + val r: Int, + val g: Int, + val b: Int, + val a: Int, + val nx: Float, + val ny: Float, + val nz: Float, + val lineWidth: Float + ) + + /** Add a face vertex. */ + fun addFaceVertex(x: Float, y: Float, z: Float, color: Color) { + faceVertices.add(FaceVertex(x, y, z, color.red, color.green, color.blue, color.alpha)) + } + + /** Add an edge vertex. */ + fun addEdgeVertex( + x: Float, + y: Float, + z: Float, + color: Color, + nx: Float, + ny: Float, + nz: Float, + lineWidth: Float + ) { + edgeVertices.add( + EdgeVertex(x, y, z, color.red, color.green, color.blue, color.alpha, nx, ny, nz, lineWidth) + ) + } + + /** + * Upload collected data to GPU buffers. Must be called on the main/render thread. + * + * @return Pair of (faceBuffer, edgeBuffer) and their index counts, or null if no data + */ + fun upload(): UploadResult { + val faceResult = + if (faceVertices.isNotEmpty()) { + uploadFaces() + } else null + + val edgeResult = + if (edgeVertices.isNotEmpty()) { + uploadEdges() + } else null + + return UploadResult(faceResult, edgeResult) + } + + private fun uploadFaces(): BufferResult { + // 16 bytes per vertex (3 floats + 4 bytes color) + BufferAllocator(faceVertices.size * 16).use { allocator -> + val builder = + BufferBuilder( + allocator, + VertexFormat.DrawMode.QUADS, + VertexFormats.POSITION_COLOR + ) + + faceVertices.forEach { v -> + builder.vertex(v.x, v.y, v.z).color(v.r, v.g, v.b, v.a) + } + + builder.endNullable()?.let { built -> + val gpuDevice = RenderSystem.getDevice() + val buffer = gpuDevice.createBuffer( + { "Lambda ESP Face Buffer" }, + GpuBuffer.USAGE_VERTEX, + built.buffer + ) + val indexCount = built.drawParameters.indexCount() + built.close() + return BufferResult(buffer, indexCount) + } + } + return BufferResult(null, 0) + } + + private fun uploadEdges(): BufferResult { + // 32 bytes per vertex + BufferAllocator(edgeVertices.size * 32).use { allocator -> + val builder = + BufferBuilder( + allocator, + VertexFormat.DrawMode.LINES, + VertexFormats.POSITION_COLOR_NORMAL_LINE_WIDTH + ) + + edgeVertices.forEach { v -> + builder.vertex(v.x, v.y, v.z) + .color(v.r, v.g, v.b, v.a) + .normal(v.nx, v.ny, v.nz) + .lineWidth(v.lineWidth) + } + + builder.endNullable()?.let { built -> + val gpuDevice = RenderSystem.getDevice() + val buffer = gpuDevice.createBuffer( + { "Lambda ESP Edge Buffer" }, + GpuBuffer.USAGE_VERTEX, + built.buffer + ) + val indexCount = built.drawParameters.indexCount() + built.close() + return BufferResult(buffer, indexCount) + } + } + return BufferResult(null, 0) + } + + data class BufferResult(val buffer: GpuBuffer?, val indexCount: Int) + data class UploadResult(val faces: BufferResult?, val edges: BufferResult?) +} diff --git a/src/main/kotlin/com/lambda/graphics/mc/RenderRegion.kt b/src/main/kotlin/com/lambda/graphics/mc/RenderRegion.kt new file mode 100644 index 000000000..915c396a5 --- /dev/null +++ b/src/main/kotlin/com/lambda/graphics/mc/RenderRegion.kt @@ -0,0 +1,60 @@ +/* + * Copyright 2025 Lambda + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.lambda.graphics.mc + +import net.minecraft.util.math.Vec3d +import org.joml.Vector3f + +/** + * A render region represents a chunk-sized area in the world where vertices are stored relative to + * the region's origin. This solves floating-point precision issues at large world coordinates. + * + * @param originX The X coordinate of the region's origin (typically chunk corner) + * @param originY The Y coordinate of the region's origin + * @param originZ The Z coordinate of the region's origin + */ +class RenderRegion(val originX: Int, val originY: Int, val originZ: Int) { + /** + * Compute the camera-relative offset for this region. This is done in double precision to + * maintain accuracy at large coordinates. + * + * @param cameraPos The camera's world position (double precision) + * @return The offset from camera to region origin (small float, high precision) + */ + fun computeCameraRelativeOffset(cameraPos: Vec3d): Vector3f { + val offsetX = originX.toDouble() - cameraPos.x + val offsetY = originY.toDouble() - cameraPos.y + val offsetZ = originZ.toDouble() - cameraPos.z + return Vector3f(offsetX.toFloat(), offsetY.toFloat(), offsetZ.toFloat()) + } + + companion object { + /** Standard size of a render region (matches Minecraft chunk size). */ + const val REGION_SIZE = 16 + + /** + * Create a region for a chunk position. + * + * @param chunkX Chunk X coordinate + * @param chunkZ Chunk Z coordinate + * @param bottomY World bottom Y coordinate (typically -64) + */ + fun forChunk(chunkX: Int, chunkZ: Int, bottomY: Int) = + RenderRegion(chunkX * 16, bottomY, chunkZ * 16) + } +} diff --git a/src/main/kotlin/com/lambda/graphics/mc/TransientRegionESP.kt b/src/main/kotlin/com/lambda/graphics/mc/TransientRegionESP.kt new file mode 100644 index 000000000..c5d62fb23 --- /dev/null +++ b/src/main/kotlin/com/lambda/graphics/mc/TransientRegionESP.kt @@ -0,0 +1,127 @@ +/* + * Copyright 2025 Lambda + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.lambda.graphics.mc + +import com.lambda.Lambda.mc +import com.mojang.blaze3d.systems.RenderSystem +import org.joml.Matrix4f +import org.joml.Quaternionf +import org.joml.Vector3f +import org.joml.Vector4f +import java.util.concurrent.ConcurrentHashMap +import kotlin.math.floor + +/** + * Modern replacement for the legacy Treed system. Handles geometry that is cleared and rebuilt + * every tick. Uses region-based rendering for precision. + */ +class TransientRegionESP(val name: String) { + private val renderers = ConcurrentHashMap() + private val builders = ConcurrentHashMap() + + /** Get or create a builder for a specific region. */ + fun getBuilder(x: Double, y: Double, z: Double): RegionShapeBuilder { + val size = RenderRegion.REGION_SIZE + val rx = (size * floor(x / size)).toInt() + val ry = (size * floor(y / size)).toInt() + val rz = (size * floor(z / size)).toInt() + + val key = (rx.toLong() and 0xFFFFFFFFL) or ((rz.toLong() and 0xFFFFFFFFL) shl 32) + + return builders.getOrPut(key) { RegionShapeBuilder(RenderRegion(rx, ry, rz)) } + } + + /** Clear all current builders. Call this at the end of every tick. */ + fun clear() { + builders.clear() + } + + /** Upload collected geometry to GPU. Must be called on main thread. */ + fun upload() { + val activeKeys = builders.keys().asSequence().toSet() + + builders.forEach { (key, builder) -> + val renderer = renderers.getOrPut(key) { RegionRenderer(builder.region) } + renderer.upload(builder.collector) + } + + renderers.forEach { (key, renderer) -> + if (key !in activeKeys) { + renderer.clearData() + } + } + } + + /** Render all active regions. */ + fun render(throughWalls: Boolean = false) { + val camera = mc.gameRenderer?.camera ?: return + val cameraPos = camera.pos + + val activeRenderers = renderers.values.filter { it.hasData() } + if (activeRenderers.isEmpty()) return + + val transforms = + activeRenderers.map { renderer -> + val offset = renderer.region.computeCameraRelativeOffset(cameraPos) + val rotation = camera.rotation.conjugate(Quaternionf()) + val modelView = Matrix4f().rotation(rotation).translate(offset) + + val dynamicTransform = + RenderSystem.getDynamicUniforms() + .write( + modelView, + Vector4f(1f, 1f, 1f, 1f), + Vector3f(0f, 0f, 0f), + Matrix4f() + ) + renderer to dynamicTransform + } + + val facePass = RegionRenderer.createRenderPass("Transient ESP Faces ($name)") ?: return + facePass.use { pass -> + val pipeline = + if (throughWalls) LambdaRenderPipelines.ESP_QUADS_THROUGH + else LambdaRenderPipelines.ESP_QUADS + pass.setPipeline(pipeline) + RenderSystem.bindDefaultUniforms(pass) + transforms.forEach { (renderer, transform) -> + pass.setUniform("DynamicTransforms", transform) + renderer.renderFaces(pass) + } + } + + val edgePass = RegionRenderer.createRenderPass("Transient ESP Edges ($name)") ?: return + edgePass.use { pass -> + val pipeline = + if (throughWalls) LambdaRenderPipelines.ESP_LINES_THROUGH + else LambdaRenderPipelines.ESP_LINES + pass.setPipeline(pipeline) + RenderSystem.bindDefaultUniforms(pass) + transforms.forEach { (renderer, transform) -> + pass.setUniform("DynamicTransforms", transform) + renderer.renderEdges(pass) + } + } + } + + fun close() { + renderers.values.forEach { it.close() } + renderers.clear() + builders.clear() + } +} diff --git a/src/main/kotlin/com/lambda/graphics/renderer/esp/ChunkedESP.kt b/src/main/kotlin/com/lambda/graphics/renderer/esp/ChunkedESP.kt deleted file mode 100644 index 03cf28c85..000000000 --- a/src/main/kotlin/com/lambda/graphics/renderer/esp/ChunkedESP.kt +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright 2025 Lambda - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.lambda.graphics.renderer.esp - -import com.lambda.event.events.RenderEvent -import com.lambda.event.events.TickEvent -import com.lambda.event.events.WorldEvent -import com.lambda.event.listener.SafeListener.Companion.listen -import com.lambda.event.listener.SafeListener.Companion.listenConcurrently -import com.lambda.module.Module -import com.lambda.module.modules.client.StyleEditor -import com.lambda.threading.awaitMainThread -import com.lambda.util.world.FastVector -import com.lambda.util.world.fastVectorOf -import net.minecraft.world.World -import net.minecraft.world.chunk.WorldChunk -import java.util.concurrent.ConcurrentHashMap -import java.util.concurrent.ConcurrentLinkedDeque - -class ChunkedESP private constructor( - owner: Module, - private val update: ShapeBuilder.(World, FastVector) -> Unit -) { - private val rendererMap = ConcurrentHashMap() - private val WorldChunk.renderer - get() = rendererMap.getOrPut(pos.toLong()) { EspChunk(this, this@ChunkedESP) } - - private val uploadQueue = ConcurrentLinkedDeque<() -> Unit>() - private val rebuildQueue = ConcurrentLinkedDeque() - - private var ticks = 0 - - fun rebuild() { - rebuildQueue.clear() - rebuildQueue.addAll(rendererMap.values) - } - - init { - listen { event -> - world.getWorldChunk(event.pos).renderer.notifyChunks() - } - - listen { event -> - event.chunk.renderer.notifyChunks() - } - - listen { - val pos = it.chunk.pos.toLong() - rendererMap.remove(pos)?.notifyChunks() - } - - owner.listenConcurrently { - val polls = minOf(StyleEditor.rebuildsPerTick, rebuildQueue.size) - repeat(polls) { rebuildQueue.poll()?.rebuild() } - } - - owner.listen { - val polls = minOf(StyleEditor.uploadsPerTick, uploadQueue.size) - repeat(polls) { uploadQueue.poll()?.invoke() } - } - - owner.listen { - rendererMap.values.forEach { it.renderer.render() } - } - } - - companion object { - fun Module.newChunkedESP( - update: ShapeBuilder.(World, FastVector) -> Unit - ) = ChunkedESP(this@newChunkedESP, update) - } - - private class EspChunk(val chunk: WorldChunk, val owner: ChunkedESP) { - var renderer = Treed(static = true) - private val builder: ShapeBuilder - get() = ShapeBuilder(renderer.faceBuilder, renderer.edgeBuilder) - - /*val neighbors = listOf(1 to 0, 0 to 1, -1 to 0, 0 to -1) - .map { ChunkPos(chunk.pos.x + it.first, chunk.pos.z + it.second) }*/ - - fun notifyChunks() { - owner.rendererMap[chunk.pos.toLong()]?.let { - if (!owner.rebuildQueue.contains(it)) - owner.rebuildQueue.add(it) - } - } - - suspend fun rebuild() { - renderer.clear() - renderer = awaitMainThread { Treed(static = true) } - - for (x in chunk.pos.startX..chunk.pos.endX) - for (z in chunk.pos.startZ..chunk.pos.endZ) - for (y in chunk.bottomY..chunk.height) - owner.update(builder, chunk.world, fastVectorOf(x, y, z)) - - owner.uploadQueue.add { renderer.upload() } - } - } -} diff --git a/src/main/kotlin/com/lambda/graphics/renderer/esp/ShapeDsl.kt b/src/main/kotlin/com/lambda/graphics/renderer/esp/ShapeDsl.kt index eaf223370..ca1bd8c64 100644 --- a/src/main/kotlin/com/lambda/graphics/renderer/esp/ShapeDsl.kt +++ b/src/main/kotlin/com/lambda/graphics/renderer/esp/ShapeDsl.kt @@ -17,13 +17,7 @@ package com.lambda.graphics.renderer.esp -import com.lambda.graphics.pipeline.VertexBuilder -import com.lambda.graphics.renderer.esp.DirectionMask.hasDirection -import com.lambda.threading.runSafe -import com.lambda.util.BlockUtils.blockState -import com.lambda.util.extension.max -import com.lambda.util.extension.min -import com.lambda.util.extension.outlineShape +import com.lambda.graphics.mc.TransientRegionESP import net.minecraft.block.BlockState import net.minecraft.block.entity.BlockEntity import net.minecraft.entity.Entity @@ -35,326 +29,206 @@ import java.awt.Color @DslMarker annotation class ShapeDsl -class ShapeBuilder( - val faces: VertexBuilder = VertexBuilder(), - val edges: VertexBuilder = VertexBuilder(), -) { - @ShapeDsl - fun filled( - box : DynamicAABB, - color : Color, - sides : Int = DirectionMask.ALL, - ) = faces.apply { - val boxes = box.pair ?: return@apply - - val pos11 = boxes.first.min - val pos12 = boxes.first.max - val pos21 = boxes.second.min - val pos22 = boxes.second.max - - val blb by lazy { vertex { vec3(pos11.x, pos11.y, pos11.z).vec3(pos21.x, pos21.y, pos21.z).color(color) } } - val blf by lazy { vertex { vec3(pos11.x, pos11.y, pos12.z).vec3(pos21.x, pos21.y, pos22.z).color(color) } } - val brb by lazy { vertex { vec3(pos12.x, pos11.y, pos11.z).vec3(pos22.x, pos21.y, pos21.z).color(color) } } - val brf by lazy { vertex { vec3(pos12.x, pos11.y, pos12.z).vec3(pos22.x, pos21.y, pos22.z).color(color) } } - val tlb by lazy { vertex { vec3(pos11.x, pos12.y, pos11.z).vec3(pos21.x, pos22.y, pos21.z).color(color) } } - val tlf by lazy { vertex { vec3(pos11.x, pos12.y, pos12.z).vec3(pos21.x, pos22.y, pos22.z).color(color) } } - val trb by lazy { vertex { vec3(pos12.x, pos12.y, pos11.z).vec3(pos22.x, pos22.y, pos21.z).color(color) } } - val trf by lazy { vertex { vec3(pos12.x, pos12.y, pos12.z).vec3(pos22.x, pos22.y, pos22.z).color(color) } } - - if (sides.hasDirection(DirectionMask.EAST)) buildQuad(brb, trb, trf, brf) - if (sides.hasDirection(DirectionMask.WEST)) buildQuad(blb, blf, tlf, tlb) - if (sides.hasDirection(DirectionMask.UP)) buildQuad(tlb, tlf, trf, trb) - if (sides.hasDirection(DirectionMask.DOWN)) buildQuad(blb, brb, brf, blf) - if (sides.hasDirection(DirectionMask.SOUTH)) buildQuad(blf, brf, trf, tlf) - if (sides.hasDirection(DirectionMask.NORTH)) buildQuad(blb, tlb, trb, brb) - } - - @ShapeDsl - fun filled( - box : Box, - bottomColor : Color, - topColor : Color = bottomColor, - sides : Int = DirectionMask.ALL - ) = faces.apply { - val pos1 = box.min - val pos2 = box.max - - val blb by lazy { vertex { vec3(pos1.x, pos1.y, pos1.z).color(bottomColor) } } - val blf by lazy { vertex { vec3(pos1.x, pos1.y, pos2.z).color(bottomColor) } } - val brb by lazy { vertex { vec3(pos2.x, pos1.y, pos1.z).color(bottomColor) } } - val brf by lazy { vertex { vec3(pos2.x, pos1.y, pos2.z).color(bottomColor) } } - - val tlb by lazy { vertex { vec3(pos1.x, pos2.y, pos1.z).color(topColor) } } - val tlf by lazy { vertex { vec3(pos1.x, pos2.y, pos2.z).color(topColor) } } - val trb by lazy { vertex { vec3(pos2.x, pos2.y, pos1.z).color(topColor) } } - val trf by lazy { vertex { vec3(pos2.x, pos2.y, pos2.z).color(topColor) } } - - if (sides.hasDirection(DirectionMask.EAST)) buildQuad(brb, trb, trf, brf) - if (sides.hasDirection(DirectionMask.WEST)) buildQuad(blb, blf, tlf, tlb) - if (sides.hasDirection(DirectionMask.UP)) buildQuad(tlb, tlf, trf, trb) - if (sides.hasDirection(DirectionMask.DOWN)) buildQuad(blb, brb, brf, blf) - if (sides.hasDirection(DirectionMask.SOUTH)) buildQuad(blf, brf, trf, tlf) - if (sides.hasDirection(DirectionMask.NORTH)) buildQuad(blb, tlb, trb, brb) - } - - @ShapeDsl - fun filled( - pos : BlockPos, - state : BlockState, - color : Color, - sides : Int = DirectionMask.ALL, - ) = runSafe { faces.apply { - val shape = outlineShape(state, pos) - if (shape.isEmpty) { - filled(Box(pos), color, sides) - } else { - filled(shape, color, sides) - } - } } - - @ShapeDsl - fun filled( - pos : BlockPos, - color : Color, - sides : Int = DirectionMask.ALL, - ) = runSafe { faces.apply { filled(pos, blockState(pos), color, sides) } } - - @ShapeDsl - fun filled( - pos : BlockPos, - entity : BlockEntity, - color : Color, - sides : Int = DirectionMask.ALL, - ) = filled(pos, entity.cachedState, color, sides) - - @ShapeDsl - fun filled( - shape: VoxelShape, - color: Color, - sides: Int = DirectionMask.ALL, - ) { - shape.boundingBoxes - .forEach { filled(it, color, color, sides) } - } - - @ShapeDsl - fun filled( - box : Box, - color : Color, - sides : Int = DirectionMask.ALL, - ) = filled(box, color, color, sides) - - @ShapeDsl - fun outline( - box : DynamicAABB, - color : Color, - sides : Int = DirectionMask.ALL, - mode : DirectionMask.OutlineMode = DirectionMask.OutlineMode.Or, - ) = edges.apply { - val boxes = box.pair ?: return@apply - - val pos11 = boxes.first.min - val pos12 = boxes.first.max - val pos21 = boxes.second.min - val pos22 = boxes.second.max - - val blb by lazy { vertex { vec3(pos11.x, pos11.y, pos11.z).vec3(pos21.x, pos21.y, pos21.z).color(color) } } - val blf by lazy { vertex { vec3(pos11.x, pos11.y, pos12.z).vec3(pos21.x, pos21.y, pos22.z).color(color) } } - val brb by lazy { vertex { vec3(pos12.x, pos11.y, pos11.z).vec3(pos22.x, pos21.y, pos21.z).color(color) } } - val brf by lazy { vertex { vec3(pos12.x, pos11.y, pos12.z).vec3(pos22.x, pos21.y, pos22.z).color(color) } } - val tlb by lazy { vertex { vec3(pos11.x, pos12.y, pos11.z).vec3(pos21.x, pos22.y, pos21.z).color(color) } } - val tlf by lazy { vertex { vec3(pos11.x, pos12.y, pos12.z).vec3(pos21.x, pos22.y, pos22.z).color(color) } } - val trb by lazy { vertex { vec3(pos12.x, pos12.y, pos11.z).vec3(pos22.x, pos22.y, pos21.z).color(color) } } - val trf by lazy { vertex { vec3(pos12.x, pos12.y, pos12.z).vec3(pos22.x, pos22.y, pos22.z).color(color) } } - - val hasEast = sides.hasDirection(DirectionMask.EAST) - val hasWest = sides.hasDirection(DirectionMask.WEST) - val hasUp = sides.hasDirection(DirectionMask.UP) - val hasDown = sides.hasDirection(DirectionMask.DOWN) - val hasSouth = sides.hasDirection(DirectionMask.SOUTH) - val hasNorth = sides.hasDirection(DirectionMask.NORTH) - - if (mode.check(hasUp, hasNorth)) buildLine(tlb, trb) - if (mode.check(hasUp, hasSouth)) buildLine(tlf, trf) - if (mode.check(hasUp, hasWest)) buildLine(tlb, tlf) - if (mode.check(hasUp, hasEast)) buildLine(trf, trb) - - if (mode.check(hasDown, hasNorth)) buildLine(blb, brb) - if (mode.check(hasDown, hasSouth)) buildLine(blf, brf) - if (mode.check(hasDown, hasWest)) buildLine(blb, blf) - if (mode.check(hasDown, hasEast)) buildLine(brb, brf) - - if (mode.check(hasWest, hasNorth)) buildLine(tlb, blb) - if (mode.check(hasNorth, hasEast)) buildLine(trb, brb) - if (mode.check(hasEast, hasSouth)) buildLine(trf, brf) - if (mode.check(hasSouth, hasWest)) buildLine(tlf, blf) - } - - @ShapeDsl - fun outline( - box : Box, - bottomColor : Color, - topColor : Color = bottomColor, - sides : Int = DirectionMask.ALL, - mode : DirectionMask.OutlineMode = DirectionMask.OutlineMode.Or, - ) = edges.apply { - val pos1 = box.min - val pos2 = box.max - - val blb by lazy { vertex { vec3(pos1.x, pos1.y, pos1.z).color(bottomColor) } } - val blf by lazy { vertex { vec3(pos1.x, pos1.y, pos2.z).color(bottomColor) } } - val brb by lazy { vertex { vec3(pos2.x, pos1.y, pos1.z).color(bottomColor) } } - val brf by lazy { vertex { vec3(pos2.x, pos1.y, pos2.z).color(bottomColor) } } - val tlb by lazy { vertex { vec3(pos1.x, pos2.y, pos1.z).color(topColor) } } - val tlf by lazy { vertex { vec3(pos1.x, pos2.y, pos2.z).color(topColor) } } - val trb by lazy { vertex { vec3(pos2.x, pos2.y, pos1.z).color(topColor) } } - val trf by lazy { vertex { vec3(pos2.x, pos2.y, pos2.z).color(topColor) } } - - val hasEast = sides.hasDirection(DirectionMask.EAST) - val hasWest = sides.hasDirection(DirectionMask.WEST) - val hasUp = sides.hasDirection(DirectionMask.UP) - val hasDown = sides.hasDirection(DirectionMask.DOWN) - val hasSouth = sides.hasDirection(DirectionMask.SOUTH) - val hasNorth = sides.hasDirection(DirectionMask.NORTH) - - if (mode.check(hasUp, hasNorth)) buildLine(tlb, trb) - if (mode.check(hasUp, hasSouth)) buildLine(tlf, trf) - if (mode.check(hasUp, hasWest)) buildLine(tlb, tlf) - if (mode.check(hasUp, hasEast)) buildLine(trf, trb) - - if (mode.check(hasDown, hasNorth)) buildLine(blb, brb) - if (mode.check(hasDown, hasSouth)) buildLine(blf, brf) - if (mode.check(hasDown, hasWest)) buildLine(blb, blf) - if (mode.check(hasDown, hasEast)) buildLine(brb, brf) - - if (mode.check(hasWest, hasNorth)) buildLine(tlb, blb) - if (mode.check(hasNorth, hasEast)) buildLine(trb, brb) - if (mode.check(hasEast, hasSouth)) buildLine(trf, brf) - if (mode.check(hasSouth, hasWest)) buildLine(tlf, blf) - } - - @ShapeDsl - fun outline( - pos : BlockPos, - state : BlockState, - color : Color, - sides : Int = DirectionMask.ALL, - mode : DirectionMask.OutlineMode = DirectionMask.OutlineMode.Or, - ) = runSafe { - val shape = outlineShape(state, pos) - if (shape.isEmpty) { - outline(Box(pos), color, sides, mode) - } else { - outline(shape, color, sides, mode) - } - } - - @ShapeDsl - fun outline( - pos : BlockPos, - color : Color, - sides : Int = DirectionMask.ALL, - mode : DirectionMask.OutlineMode = DirectionMask.OutlineMode.Or, - ) = runSafe { outline(pos, blockState(pos), color, sides, mode) } - - @ShapeDsl - fun outline( - pos : BlockPos, - entity : BlockEntity, - color : Color, - sides : Int = DirectionMask.ALL, - mode : DirectionMask.OutlineMode = DirectionMask.OutlineMode.Or, - ) = runSafe { outline(pos, entity.cachedState, color, sides, mode) } - - @ShapeDsl - fun outline( - shape : VoxelShape, - color : Color, - sides : Int = DirectionMask.ALL, - mode : DirectionMask.OutlineMode = DirectionMask.OutlineMode.Or, - ) { - shape.boundingBoxes - .forEach { outline(it, color, sides, mode) } - } - - @ShapeDsl - fun outline( - box : Box, - color : Color, - sides : Int = DirectionMask.ALL, - mode : DirectionMask.OutlineMode = DirectionMask.OutlineMode.Or, - ) { - outline(box, color, color, sides, mode) - } - - @ShapeDsl - fun box( - pos : BlockPos, - state : BlockState, - filled : Color, - outline : Color, - sides : Int = DirectionMask.ALL, - mode : DirectionMask.OutlineMode = DirectionMask.OutlineMode.Or, - ) = runSafe { - filled(pos, state, filled, sides) - outline(pos, state, outline, sides, mode) - } - - @ShapeDsl - fun box( - pos : BlockPos, - filled : Color, - outline : Color, - sides : Int = DirectionMask.ALL, - mode : DirectionMask.OutlineMode = DirectionMask.OutlineMode.Or, - ) = runSafe { - filled(pos, filled, sides) - outline(pos, outline, sides, mode) - } - - @ShapeDsl - fun box( - box : DynamicAABB, - filled : Color, - outline : Color, - sides : Int = DirectionMask.ALL, - mode : DirectionMask.OutlineMode = DirectionMask.OutlineMode.Or, - ) { - filled(box, filled, sides) - outline(box, outline, sides, mode) - } - - @ShapeDsl - fun box( - box : Box, - filled : Color, - outline : Color, - sides : Int = DirectionMask.ALL, - mode : DirectionMask.OutlineMode = DirectionMask.OutlineMode.Or, - ) { - filled(box, filled, sides) - outline(box, outline, sides, mode) - } - - @ShapeDsl - fun box( - entity : BlockEntity, - color : Color, - sides : Int = DirectionMask.ALL, - mode : DirectionMask.OutlineMode = DirectionMask.OutlineMode.Or, - ) = runSafe { - filled(entity.pos, entity, color, sides) - outline(entity.pos, entity, color, sides, mode) - } - - @ShapeDsl - fun box( - entity : Entity, - color : Color, - sides : Int = DirectionMask.ALL, - mode : DirectionMask.OutlineMode = DirectionMask.OutlineMode.Or, - ) = runSafe { - filled(entity.boundingBox, color, sides) - outline(entity.boundingBox, color, sides, mode) - } +/** + * Bridge class that provides the legacy ShapeBuilder API while writing to the new + * TransientRegionESP. + */ +class ShapeBuilder(val esp: TransientRegionESP) { + @ShapeDsl + fun filled( + box: Box, + bottomColor: Color, + topColor: Color = bottomColor, + sides: Int = DirectionMask.ALL + ) = esp.getBuilder(box.minX, box.minY, box.minZ).filled(box, bottomColor, topColor, sides) + + @ShapeDsl + fun filled(pos: BlockPos, state: BlockState, color: Color, sides: Int = DirectionMask.ALL) = + esp.getBuilder(pos.x.toDouble(), pos.y.toDouble(), pos.z.toDouble()) + .filled(pos, state, color, sides) + + @ShapeDsl + fun filled(pos: BlockPos, color: Color, sides: Int = DirectionMask.ALL) = + esp.getBuilder(pos.x.toDouble(), pos.y.toDouble(), pos.z.toDouble()) + .filled(pos, color, sides) + + @ShapeDsl + fun filled( + pos: BlockPos, + entity: BlockEntity, + color: Color, + sides: Int = DirectionMask.ALL + ) = + esp.getBuilder(pos.x.toDouble(), pos.y.toDouble(), pos.z.toDouble()) + .filled(pos, entity, color, sides) + + @ShapeDsl + fun filled(shape: VoxelShape, color: Color, sides: Int = DirectionMask.ALL) = + esp.getBuilder( + shape.boundingBoxes[0].minX, + shape.boundingBoxes[0].minY, + shape.boundingBoxes[0].minZ + ) + .filled(shape, color, sides) + + @ShapeDsl + fun filled(box: Box, color: Color, sides: Int = DirectionMask.ALL) = + filled(box, color, color, sides) + + @ShapeDsl + fun outline( + box: Box, + bottomColor: Color, + topColor: Color = bottomColor, + sides: Int = DirectionMask.ALL, + mode: DirectionMask.OutlineMode = DirectionMask.OutlineMode.And, + ) = + esp.getBuilder(box.minX, box.minY, box.minZ) + .outline(box, bottomColor, topColor, sides, mode) + + @ShapeDsl + fun outline( + pos: BlockPos, + state: BlockState, + color: Color, + sides: Int = DirectionMask.ALL, + mode: DirectionMask.OutlineMode = DirectionMask.OutlineMode.And, + ) = + esp.getBuilder(pos.x.toDouble(), pos.y.toDouble(), pos.z.toDouble()) + .outline(pos, state, color, sides, mode) + + @ShapeDsl + fun outline( + pos: BlockPos, + color: Color, + sides: Int = DirectionMask.ALL, + mode: DirectionMask.OutlineMode = DirectionMask.OutlineMode.And, + ) = + esp.getBuilder(pos.x.toDouble(), pos.y.toDouble(), pos.z.toDouble()) + .outline(pos, color, sides, mode) + + @ShapeDsl + fun outline( + pos: BlockPos, + entity: BlockEntity, + color: Color, + sides: Int = DirectionMask.ALL, + mode: DirectionMask.OutlineMode = DirectionMask.OutlineMode.And, + ) = + esp.getBuilder(pos.x.toDouble(), pos.y.toDouble(), pos.z.toDouble()) + .outline(pos, entity, color, sides, mode) + + @ShapeDsl + fun outline( + shape: VoxelShape, + color: Color, + sides: Int = DirectionMask.ALL, + mode: DirectionMask.OutlineMode = DirectionMask.OutlineMode.And, + ) = + esp.getBuilder( + shape.boundingBoxes[0].minX, + shape.boundingBoxes[0].minY, + shape.boundingBoxes[0].minZ + ) + .outline(shape, color, sides, mode) + + @ShapeDsl + fun outline( + box: Box, + color: Color, + sides: Int = DirectionMask.ALL, + mode: DirectionMask.OutlineMode = DirectionMask.OutlineMode.And, + ) = outline(box, color, color, sides, mode) + + @ShapeDsl + fun box( + pos: BlockPos, + state: BlockState, + filled: Color, + outline: Color, + sides: Int = DirectionMask.ALL, + mode: DirectionMask.OutlineMode = DirectionMask.OutlineMode.And, + ) { + filled(pos, state, filled, sides) + outline(pos, state, outline, sides, mode) + } + + @ShapeDsl + fun box( + pos: BlockPos, + filled: Color, + outline: Color, + sides: Int = DirectionMask.ALL, + mode: DirectionMask.OutlineMode = DirectionMask.OutlineMode.And, + ) { + filled(pos, filled, sides) + outline(pos, outline, sides, mode) + } + + @ShapeDsl + fun box( + box: Box, + filled: Color, + outline: Color, + sides: Int = DirectionMask.ALL, + mode: DirectionMask.OutlineMode = DirectionMask.OutlineMode.And, + ) { + filled(box, filled, sides) + outline(box, outline, sides, mode) + } + + @ShapeDsl + fun box( + entity: BlockEntity, + color: Color, + sides: Int = DirectionMask.ALL, + mode: DirectionMask.OutlineMode = DirectionMask.OutlineMode.And, + ) { + filled(entity.pos, entity, color, sides) + outline(entity.pos, entity, color, sides, mode) + } + + @ShapeDsl + fun box( + entity: Entity, + color: Color, + sides: Int = DirectionMask.ALL, + mode: DirectionMask.OutlineMode = DirectionMask.OutlineMode.And, + ) { + filled(entity.boundingBox, color, sides) + outline(entity.boundingBox, color, sides, mode) + } + + @ShapeDsl + fun filled(box: DynamicAABB, color: Color, sides: Int = DirectionMask.ALL) { + box.pair?.second?.let { + esp.getBuilder(it.minX, it.minY, it.minZ).filled(box, color, sides) + } + } + + @ShapeDsl + fun outline( + box: DynamicAABB, + color: Color, + sides: Int = DirectionMask.ALL, + mode: DirectionMask.OutlineMode = DirectionMask.OutlineMode.And + ) { + box.pair?.second?.let { + esp.getBuilder(it.minX, it.minY, it.minZ).outline(box, color, sides, mode) + } + } + + @ShapeDsl + fun box( + box: DynamicAABB, + filledColor: Color, + outlineColor: Color, + sides: Int = DirectionMask.ALL, + mode: DirectionMask.OutlineMode = DirectionMask.OutlineMode.And + ) { + box.pair?.second?.let { + esp.getBuilder(it.minX, it.minY, it.minZ) + .box(box, filledColor, outlineColor, sides, mode) + } + } } diff --git a/src/main/kotlin/com/lambda/graphics/renderer/esp/Treed.kt b/src/main/kotlin/com/lambda/graphics/renderer/esp/Treed.kt deleted file mode 100644 index 42394ed93..000000000 --- a/src/main/kotlin/com/lambda/graphics/renderer/esp/Treed.kt +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright 2025 Lambda - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.lambda.graphics.renderer.esp - -import com.lambda.Lambda.mc -import com.lambda.graphics.buffer.vertex.attributes.VertexAttrib -import com.lambda.graphics.buffer.vertex.attributes.VertexMode -import com.lambda.graphics.gl.GlStateUtils -import com.lambda.graphics.pipeline.VertexBuilder -import com.lambda.graphics.pipeline.VertexPipeline -import com.lambda.graphics.shader.Shader -import com.lambda.module.modules.client.StyleEditor -import com.lambda.util.extension.partialTicks - -/** - * Open class for 3d rendering. It contains two pipelines, one for edges and the other for faces. - */ -open class Treed(private val static: Boolean) { - val shader = if (static) staticMode.first else dynamicMode.first - - val faces = VertexPipeline(VertexMode.Triangles, if (static) staticMode.second else dynamicMode.second) - val edges = VertexPipeline(VertexMode.Lines, if (static) staticMode.second else dynamicMode.second) - - var faceBuilder = VertexBuilder(); private set - var edgeBuilder = VertexBuilder(); private set - - fun upload() { - faces.upload(faceBuilder) - edges.upload(edgeBuilder) - } - - fun render() { - shader.use() - - if (!static) - shader["u_TickDelta"] = mc.partialTicks - - GlStateUtils.withFaceCulling(faces::render) - GlStateUtils.withLineWidth(StyleEditor.outlineWidth, edges::render) - } - - fun clear() { - faces.clear() - edges.clear() - - faceBuilder = VertexBuilder() - edgeBuilder = VertexBuilder() - } - - /** - * Public object for static rendering. Shapes rendering by this are not interpolated. - * That means that if the shape is frequently moving, its movement will saccade. - */ - object Static : Treed(true) - - /** - * Public object for dynamic rendering. Its position will be interpolated between ticks, allowing - * for smooth movement at the cost of duplicate position and slightly higher memory consumption. - */ - object Dynamic : Treed(false) - - companion object { - private val staticMode = Shader("shaders/vertex/box_static.glsl", "shaders/fragment/pos_color.glsl") to VertexAttrib.Group.STATIC_RENDERER - private val dynamicMode = Shader("shaders/vertex/box_dynamic.glsl", "shaders/fragment/pos_color.glsl") to VertexAttrib.Group.DYNAMIC_RENDERER - } -} diff --git a/src/main/kotlin/com/lambda/graphics/renderer/gui/AbstractGUIRenderer.kt b/src/main/kotlin/com/lambda/graphics/renderer/gui/AbstractGUIRenderer.kt index 271614ff5..c112c4bf9 100644 --- a/src/main/kotlin/com/lambda/graphics/renderer/gui/AbstractGUIRenderer.kt +++ b/src/main/kotlin/com/lambda/graphics/renderer/gui/AbstractGUIRenderer.kt @@ -61,7 +61,8 @@ open class AbstractGUIRenderer( shader["u_ShadeColor1"] = ClickGuiLayout.primaryColor shader["u_ShadeColor2"] = ClickGuiLayout.secondaryColor - shader["u_ShadeSize"] = RenderMain.screenSize / Vec2d(ClickGuiLayout.colorWidth, ClickGuiLayout.colorHeight) + // ToDo: GUI Rewrite +// shader["u_ShadeSize"] = RenderMain.screenSize / Vec2d(ClickGuiLayout.colorWidth, ClickGuiLayout.colorHeight) } pipeline.apply { diff --git a/src/main/kotlin/com/lambda/gui/DearImGui.kt b/src/main/kotlin/com/lambda/gui/DearImGui.kt index 13b4f24fa..66dfda249 100644 --- a/src/main/kotlin/com/lambda/gui/DearImGui.kt +++ b/src/main/kotlin/com/lambda/gui/DearImGui.kt @@ -103,7 +103,7 @@ object DearImGui : Loadable { val framebuffer = mc.framebuffer val prevFramebuffer = (framebuffer.getColorAttachment() as GlTexture).getOrCreateFramebuffer( - (RenderSystem.getDevice() as GlBackend).framebufferManager, + (RenderSystem.getDevice() as GlBackend).bufferManager, null ) diff --git a/src/main/kotlin/com/lambda/gui/LambdaScreen.kt b/src/main/kotlin/com/lambda/gui/LambdaScreen.kt index cb35fc93f..bb01781ea 100644 --- a/src/main/kotlin/com/lambda/gui/LambdaScreen.kt +++ b/src/main/kotlin/com/lambda/gui/LambdaScreen.kt @@ -26,4 +26,14 @@ object LambdaScreen : Screen(Text.of("Lambda")) { override fun shouldPause() = false override fun removed() = ClickGuiLayout.close() override fun render(context: DrawContext?, mouseX: Int, mouseY: Int, deltaTicks: Float) {} + + override fun applyBlur(context: DrawContext?) { + if (!ClickGuiLayout.backgroundBlur) return + super.applyBlur(context) + } + + override fun renderDarkening(context: DrawContext?) { + if (!ClickGuiLayout.backgroundDarkening) return + super.renderDarkening(context) + } } diff --git a/src/main/kotlin/com/lambda/gui/MenuBar.kt b/src/main/kotlin/com/lambda/gui/MenuBar.kt index 3856aea6f..bfef5ac0f 100644 --- a/src/main/kotlin/com/lambda/gui/MenuBar.kt +++ b/src/main/kotlin/com/lambda/gui/MenuBar.kt @@ -52,6 +52,11 @@ import imgui.flag.ImGuiCol import imgui.flag.ImGuiStyleVar import imgui.flag.ImGuiWindowFlags import net.fabricmc.loader.api.FabricLoader +import net.minecraft.client.gui.hud.debug.DebugHudEntries +import net.minecraft.client.gui.screen.DebugOptionsScreen +import net.minecraft.command.permission.Permission +import net.minecraft.network.packet.c2s.play.ChangeGameModeC2SPacket +import net.minecraft.server.command.GameModeCommand import net.minecraft.util.Util import net.minecraft.world.GameMode import java.util.* @@ -346,18 +351,18 @@ object MenuBar { } separator() runSafe { - menu("Gamemode", enabled = player.hasPermissionLevel(2)) { + menu("Gamemode", enabled = GameModeCommand.PERMISSION_CHECK.allows(player.permissions)) { menuItem("Survival", selected = interaction.gameMode == GameMode.SURVIVAL) { - connection.sendCommand("gamemode survival") + connection.sendPacket(ChangeGameModeC2SPacket(GameMode.SURVIVAL)) } menuItem("Creative", selected = interaction.gameMode == GameMode.CREATIVE) { - connection.sendCommand("gamemode creative") + connection.sendPacket(ChangeGameModeC2SPacket(GameMode.CREATIVE)) } menuItem("Adventure", selected = interaction.gameMode == GameMode.ADVENTURE) { - connection.sendCommand("gamemode adventure") + connection.sendPacket(ChangeGameModeC2SPacket(GameMode.ADVENTURE)) } menuItem("Spectator", selected = interaction.gameMode == GameMode.SPECTATOR) { - connection.sendCommand("gamemode spectator") + connection.sendPacket(ChangeGameModeC2SPacket(GameMode.SPECTATOR)) } } menu("Debug Menu") { @@ -365,16 +370,6 @@ object MenuBar { mc.options.advancedItemTooltips = !mc.options.advancedItemTooltips mc.options.write() } - menuItem("Show Chunk Borders", "F3+G", mc.debugRenderer.showChunkBorder) { - mc.debugRenderer.toggleShowChunkBorder() - } - menuItem("Show Octree", selected = mc.debugRenderer.showOctree) { - mc.debugRenderer.toggleShowOctree() - } - menuItem("Show Hitboxes", "F3+B", mc.entityRenderDispatcher.shouldRenderHitboxes()) { - val now = !mc.entityRenderDispatcher.shouldRenderHitboxes() - mc.entityRenderDispatcher.setRenderHitboxes(now) - } menuItem("Copy Location (as command)", "F3+C") { val cmd = String.format( Locale.ROOT, @@ -388,6 +383,9 @@ object MenuBar { menuItem("Clear Chat", "F3+D") { mc.inGameHud?.chatHud?.clear(false) } + menuItem("Open Debug Entry Menu", "(new)") { // ToDo: Put actual keybind in + mc.setScreen(DebugOptionsScreen()) + } separator() @@ -414,8 +412,8 @@ object MenuBar { separator() - menuItem("Show Debug Menu", "F3", mc.debugHud.showDebugHud) { - mc.debugHud.toggleDebugHud() + menuItem("Show Debug Menu", "F3", mc.debugHudEntryList.isF3Enabled) { + mc.debugHudEntryList.toggleF3Enabled() } menuItem("Rendering Chart", "F3+1", mc.debugHud.renderingChartVisible) { mc.debugHud.toggleRenderingChart() diff --git a/src/main/kotlin/com/lambda/gui/components/ClickGuiLayout.kt b/src/main/kotlin/com/lambda/gui/components/ClickGuiLayout.kt index b54bad9d4..89729a4e3 100644 --- a/src/main/kotlin/com/lambda/gui/components/ClickGuiLayout.kt +++ b/src/main/kotlin/com/lambda/gui/components/ClickGuiLayout.kt @@ -115,13 +115,15 @@ object ClickGuiLayout : Loadable, Configurable(GuiConfig) { if (to) { setLambdaWindowIcon() } else { - val icon = if (SharedConstants.getGameVersion().isStable) Icons.RELEASE else Icons.SNAPSHOT + val icon = if (SharedConstants.getGameVersion().stable()) Icons.RELEASE else Icons.SNAPSHOT mc.window.setIcon(mc.defaultResourcePack, icon) } } @JvmStatic val setLambdaWindowTitle by setting("Set Lambda Window Title", true).onValueChange { _, _ -> mc.updateWindowTitle() }.group(Group.General) val lambdaTitleAppendixName by setting("Append Username", true) { setLambdaWindowTitle }.onValueChange { _, _ -> mc.updateWindowTitle() }.group(Group.General) + val backgroundBlur by setting("Background Blur", true).group(Group.General) + val backgroundDarkening by setting("Background Darkening", true).group(Group.General) // Snapping val snapEnabled by setting("Enable Snapping", true, "Master toggle for GUI/HUD snapping").group(Group.Snapping) diff --git a/src/main/kotlin/com/lambda/gui/components/QuickSearch.kt b/src/main/kotlin/com/lambda/gui/components/QuickSearch.kt index 396a9b826..f4815152b 100644 --- a/src/main/kotlin/com/lambda/gui/components/QuickSearch.kt +++ b/src/main/kotlin/com/lambda/gui/components/QuickSearch.kt @@ -91,7 +91,7 @@ object QuickSearch { override fun ImGuiBuilder.buildLayout() { text(command.name.capitalize()) sameLine() - smallButton("Insert") { mc.setScreen(ChatScreen("${CommandRegistry.prefix}${command.name} ")) } + smallButton("Insert") { mc.setScreen(ChatScreen("${CommandRegistry.prefix}${command.name} ", true)) } if (command.description.isNotBlank()) { sameLine() textDisabled(command.description) diff --git a/src/main/kotlin/com/lambda/interaction/BaritoneManager.kt b/src/main/kotlin/com/lambda/interaction/BaritoneManager.kt index 43f36c52c..97a448780 100644 --- a/src/main/kotlin/com/lambda/interaction/BaritoneManager.kt +++ b/src/main/kotlin/com/lambda/interaction/BaritoneManager.kt @@ -28,15 +28,18 @@ import com.lambda.context.Automated import com.lambda.config.AutomationConfig import com.lambda.util.BlockUtils.blockPos import com.lambda.util.NamedEnum +import net.fabricmc.loader.api.FabricLoader object BaritoneManager : Configurable(LambdaConfig), Automated by AutomationConfig.Companion.DEFAULT { override val name = "baritone" - private val baritone = BaritoneAPI.getProvider() - val baritoneSettings: Settings = BaritoneAPI.getSettings() + val isBaritoneLoaded = FabricLoader.getInstance().isModLoaded("baritone") + + private val baritone = if (isBaritoneLoaded) BaritoneAPI.getProvider() else null + val baritoneSettings: Settings? = if (isBaritoneLoaded) BaritoneAPI.getSettings() else null @JvmStatic - val primary: IBaritone = baritone.primaryBaritone + val primary: IBaritone? = baritone?.primaryBaritone private enum class Group(override val displayName: String) : NamedEnum { General("General"), @@ -72,7 +75,8 @@ object BaritoneManager : Configurable(LambdaConfig), Automated by AutomationConf init { // ToDo: Dont actually save the settings as its duplicate data - with(baritoneSettings) { + if (isBaritoneLoaded) { + with(baritoneSettings!!) { // GENERAL setting("Log As Toast", logAsToast.value).group(Group.General, SubGroup.ChatAndControl).onValueChange { _, it -> logAsToast.value = it } @@ -334,6 +338,7 @@ object BaritoneManager : Configurable(LambdaConfig), Automated by AutomationConf setting("Allow Land On Nether Fortress", elytraAllowLandOnNetherFortress.value).group(Group.Elytra).onValueChange { _, it -> elytraAllowLandOnNetherFortress.value = it } setting("Terms Accepted", elytraTermsAccepted.value).group(Group.Elytra).onValueChange { _, it -> elytraTermsAccepted.value = it } setting("Chat Spam", elytraChatSpam.value).group(Group.Elytra).onValueChange { _, it -> elytraChatSpam.value = it } + } } } @@ -341,22 +346,28 @@ object BaritoneManager : Configurable(LambdaConfig), Automated by AutomationConf * Whether Baritone is currently pathing */ val isPathing: Boolean - get() = primary.pathingBehavior.isPathing + get() = isBaritoneLoaded && primary?.pathingBehavior?.isPathing == true /** * Whether Baritone is active (pathing, calculating goal, etc.) */ val isActive: Boolean - get() = primary.customGoalProcess.isActive || primary.pathingBehavior.isPathing || primary.pathingControlManager.mostRecentInControl() - .orElse(null)?.isActive == true + get() = isBaritoneLoaded && (primary?.customGoalProcess?.isActive == true || primary?.pathingBehavior?.isPathing == true || primary?.pathingControlManager?.mostRecentInControl() + ?.orElse(null)?.isActive == true) /** * Sets the current Baritone goal and starts pathing */ - fun setGoalAndPath(goal: Goal) = primary.customGoalProcess.setGoalAndPath(goal) + fun setGoalAndPath(goal: Goal) { + if (!isBaritoneLoaded) return + primary?.customGoalProcess?.setGoalAndPath(goal) + } /** * Force cancel Baritone */ - fun cancel() = primary.pathingBehavior.cancelEverything() + fun cancel() { + if (!isBaritoneLoaded) return + primary?.pathingBehavior?.cancelEverything() + } } diff --git a/src/main/kotlin/com/lambda/interaction/PlayerPacketHandler.kt b/src/main/kotlin/com/lambda/interaction/PlayerPacketHandler.kt index 5cda2e509..dca27c164 100644 --- a/src/main/kotlin/com/lambda/interaction/PlayerPacketHandler.kt +++ b/src/main/kotlin/com/lambda/interaction/PlayerPacketHandler.kt @@ -39,7 +39,6 @@ object PlayerPacketHandler { var lastPosition: Vec3d = Vec3d.ZERO var lastRotation = Rotation.ZERO var lastSprint = false - var lastSneak = false var lastOnGround = false var lastHorizontalCollision = false @@ -60,21 +59,6 @@ object PlayerPacketHandler { } } - @JvmStatic - fun sendSneakPackets() { - runSafe { - val sneaking = player.isSneaking - if (sneaking == lastSneak) return@runSafe - val mode = if (sneaking) { - ClientCommandC2SPacket.Mode.PRESS_SHIFT_KEY - } else { - ClientCommandC2SPacket.Mode.RELEASE_SHIFT_KEY - } - connection.sendPacket(ClientCommandC2SPacket(player, mode)) - lastSneak = sneaking - } - } - private fun SafeContext.updatePlayerPackets(new: PlayerPacketEvent.Pre) { configurations.add(new) diff --git a/src/main/kotlin/com/lambda/interaction/construction/simulation/Simulation.kt b/src/main/kotlin/com/lambda/interaction/construction/simulation/Simulation.kt index 98e5f6c4c..cef79a426 100644 --- a/src/main/kotlin/com/lambda/interaction/construction/simulation/Simulation.kt +++ b/src/main/kotlin/com/lambda/interaction/construction/simulation/Simulation.kt @@ -41,7 +41,7 @@ data class Simulation( private val automated: Automated ) : Automated by automated { private val cache: MutableMap> = mutableMapOf() - private fun FastVector.toView(): Vec3d = toVec3d().add(0.5, ClientPlayerEntity.DEFAULT_EYE_HEIGHT.toDouble(), 0.5) + private fun FastVector.toView(): Vec3d = toVec3d().add(0.5, ClientPlayerEntity.EYE_HEIGHT.toDouble(), 0.5) fun simulate(pos: FastVector) = cache.getOrPut(pos) { diff --git a/src/main/kotlin/com/lambda/interaction/managers/breaking/BreakManager.kt b/src/main/kotlin/com/lambda/interaction/managers/breaking/BreakManager.kt index 597feefd1..dedd3433e 100644 --- a/src/main/kotlin/com/lambda/interaction/managers/breaking/BreakManager.kt +++ b/src/main/kotlin/com/lambda/interaction/managers/breaking/BreakManager.kt @@ -631,7 +631,7 @@ object BreakManager : Manager( && tickStage in breakConfig.tickStageMask && (rotated || type != Primary) - if (updatedPreProcessingThisTick) return + if (updatedPreProcessingThisTick) return@runSafeAutomated updatedPreProcessingThisTick = true swapStack = player.inventory.getStack(context.hotbarIndex) @@ -746,7 +746,7 @@ object BreakManager : Manager( } if (breakConfig.particles) { - mc.particleManager.addBlockBreakingParticles(ctx.blockPos, hitResult.side) + world.spawnBlockBreakingParticle(ctx.blockPos, hitResult.side) } if (breakConfig.breakingTexture) { diff --git a/src/main/kotlin/com/lambda/interaction/managers/rotating/visibilty/PlaceDirection.kt b/src/main/kotlin/com/lambda/interaction/managers/rotating/visibilty/PlaceDirection.kt index eb858d4d0..2a78ca14e 100644 --- a/src/main/kotlin/com/lambda/interaction/managers/rotating/visibilty/PlaceDirection.kt +++ b/src/main/kotlin/com/lambda/interaction/managers/rotating/visibilty/PlaceDirection.kt @@ -22,6 +22,7 @@ import net.minecraft.entity.Entity import net.minecraft.util.math.Direction import net.minecraft.util.math.MathHelper import net.minecraft.util.math.Vec3i +import kotlin.math.sin enum class PlaceDirection( val rotation: Rotation, @@ -58,8 +59,8 @@ enum class PlaceDirection( * @see Direction.getEntityFacingOrder */ fun fromRotation(rotation: Rotation): PlaceDirection { - val pitchRad = rotation.pitchF * (Math.PI.toFloat() / 180f) - val yawRad = -rotation.yawF * (Math.PI.toFloat() / 180f) + val pitchRad = rotation.pitchF * (Math.PI.toFloat() / 180f).toDouble() + val yawRad = -rotation.yawF * (Math.PI.toFloat() / 180f).toDouble() val sinPitch = MathHelper.sin(pitchRad) val cosPitch = MathHelper.cos(pitchRad) diff --git a/src/main/kotlin/com/lambda/module/hud/Baritone.kt b/src/main/kotlin/com/lambda/module/hud/Baritone.kt index 8d20b3f62..86bae308f 100644 --- a/src/main/kotlin/com/lambda/module/hud/Baritone.kt +++ b/src/main/kotlin/com/lambda/module/hud/Baritone.kt @@ -18,7 +18,7 @@ package com.lambda.module.hud import com.lambda.gui.dsl.ImGuiBuilder -import com.lambda.interaction.BaritoneManager.primary +import com.lambda.interaction.BaritoneManager import com.lambda.interaction.construction.simulation.BuildGoal import com.lambda.module.HudModule import com.lambda.module.tag.ModuleTag @@ -29,7 +29,12 @@ object Baritone : HudModule( tag = ModuleTag.HUD, ) { override fun ImGuiBuilder.buildLayout() { - primary.customGoalProcess.goal?.let { + if (!BaritoneManager.isBaritoneLoaded) { + text("Baritone is not loaded") + return + } + + BaritoneManager.primary?.customGoalProcess?.goal?.let { when(it) { is BuildGoal -> text("Lambda Simulation: ${it.sim}") else -> text("Baritone: $it") diff --git a/src/main/kotlin/com/lambda/module/modules/combat/FakePlayer.kt b/src/main/kotlin/com/lambda/module/modules/combat/FakePlayer.kt index 7afdb5a64..7fe6a4779 100644 --- a/src/main/kotlin/com/lambda/module/modules/combat/FakePlayer.kt +++ b/src/main/kotlin/com/lambda/module/modules/combat/FakePlayer.kt @@ -29,9 +29,12 @@ import com.lambda.threading.onShutdown import com.lambda.util.Timer import com.lambda.util.player.spawnFakePlayer import com.mojang.authlib.GameProfile +import com.mojang.datafixers.util.Either import net.minecraft.client.network.OtherClientPlayerEntity import net.minecraft.client.network.PlayerListEntry import java.util.* +import kotlin.jvm.optionals.getOrElse +import kotlin.jvm.optionals.getOrNull import kotlin.time.Duration.Companion.seconds object FakePlayer : Module( @@ -76,7 +79,8 @@ object FakePlayer : Module( val requestedProfile = getProfile(user).getOrElse { return nilProfile } // Fetch the skin properties from mojang - val properties = mc.sessionService.fetchProfile(requestedProfile.id, true)?.profile?.properties + val properties = mc.apiServices.profileResolver + .getProfile(Either.right(requestedProfile.id)).getOrNull()?.properties // We use the nil profile to avoid the nil username if something wrong happens // Check the GameProfile deserializer you'll understand diff --git a/src/main/kotlin/com/lambda/module/modules/combat/KillAura.kt b/src/main/kotlin/com/lambda/module/modules/combat/KillAura.kt index 10a7e2118..95d38cef4 100644 --- a/src/main/kotlin/com/lambda/module/modules/combat/KillAura.kt +++ b/src/main/kotlin/com/lambda/module/modules/combat/KillAura.kt @@ -41,7 +41,6 @@ import com.lambda.util.player.SlotUtils.hotbarAndStorage import com.lambda.util.world.raycast.RayCastUtils.entityResult import net.minecraft.entity.LivingEntity import net.minecraft.util.Hand -import net.minecraft.util.math.Vec3d object KillAura : Module( name = "KillAura", @@ -61,16 +60,12 @@ object KillAura : Module( val target: LivingEntity? get() = targeting.target() - private var shakeRandom = Vec3d.ZERO - private var speedMultiplier = 1.0 - private var lastAttackTime = 0L private var hitDelay = 100.0 private var prevY = 0.0 private var lastY = 0.0 private var lastOnGround = true - private var onGroundTicks = 0 enum class Group(override val displayName: String) : NamedEnum { Build("Build"), @@ -119,7 +114,7 @@ object KillAura : Module( private fun SafeContext.runAttack(target: LivingEntity) { // Cooldown check when (attackMode) { - AttackMode.Cooldown -> if (player.lastAttackedTicks < 1 / player.attackSpeed() * 20 + cooldownOffset) return + AttackMode.Cooldown -> if (player.lastAttackedTime < 1 / player.attackSpeed() * 20 + cooldownOffset) return AttackMode.Delay -> if (System.currentTimeMillis() - lastAttackTime < hitDelay) return } @@ -145,13 +140,9 @@ object KillAura : Module( } private fun reset() { - speedMultiplier = 1.0 - shakeRandom = Vec3d.ZERO - lastY = 0.0 prevY = 0.0 lastOnGround = true - onGroundTicks = 0 lastAttackTime = 0L hitDelay = 100.0 diff --git a/src/main/kotlin/com/lambda/module/modules/debug/DebugRendererModule.kt b/src/main/kotlin/com/lambda/module/modules/debug/DebugRendererModule.kt index 9e8c6bb73..152abaec5 100644 --- a/src/main/kotlin/com/lambda/module/modules/debug/DebugRendererModule.kt +++ b/src/main/kotlin/com/lambda/module/modules/debug/DebugRendererModule.kt @@ -53,35 +53,36 @@ object DebugRendererModule: Module( // private val chunkDebugRenderer by setting("Chunk Debug Renderer", false) // private val octreeDebugRenderer by setting("Octree Debug Renderer", false) - @JvmStatic - fun render( - matrices: MatrixStack, - vertexConsumers: VertexConsumerProvider.Immediate, - cameraX: Double, - cameraY: Double, cameraZ: Double - ) { - val renderers = mc.debugRenderer - mutableListOf().apply { - if (waterDebugRenderer) add(renderers.waterDebugRenderer) - if (chunkBorderDebugRenderer) add(renderers.chunkBorderDebugRenderer) - if (heightmapDebugRenderer) add(renderers.heightmapDebugRenderer) - if (collisionDebugRenderer) add(renderers.collisionDebugRenderer) - if (supportingBlockDebugRenderer) add(renderers.supportingBlockDebugRenderer) - if (neighborUpdateDebugRenderer) add(renderers.neighborUpdateDebugRenderer) - if (redstoneUpdateOrderDebugRenderer) add(renderers.redstoneUpdateOrderDebugRenderer) - if (structureDebugRenderer) add(renderers.structureDebugRenderer) - if (skyLightDebugRenderer) add(renderers.skyLightDebugRenderer) - if (worldGenAttemptDebugRenderer) add(renderers.worldGenAttemptDebugRenderer) - if (blockOutlineDebugRenderer) add(renderers.blockOutlineDebugRenderer) - if (chunkLoadingDebugRenderer) add(renderers.chunkLoadingDebugRenderer) - if (villageDebugRenderer) add(renderers.villageDebugRenderer) - if (villageSectionsDebugRenderer) add(renderers.villageSectionsDebugRenderer) - if (beeDebugRenderer) add(renderers.beeDebugRenderer) - if (raidCenterDebugRenderer) add(renderers.raidCenterDebugRenderer) - if (goalSelectorDebugRenderer) add(renderers.goalSelectorDebugRenderer) - if (gameTestDebugRenderer) add(renderers.gameTestDebugRenderer) - if (gameEventDebugRenderer) add(renderers.gameEventDebugRenderer) - if (lightDebugRenderer) add(renderers.lightDebugRenderer) - }.forEach { it.render(matrices, vertexConsumers, cameraX, cameraY, cameraZ) } - } + // ToDo: Was changed in 1.21.11 -> now we have editable HUD but we may want to add all the hidden options here eg pathfinder +// @JvmStatic +// fun render( +// matrices: MatrixStack, +// vertexConsumers: VertexConsumerProvider.Immediate, +// cameraX: Double, +// cameraY: Double, cameraZ: Double +// ) { +// val renderers = mc.worldRenderer.debugRenderer +// mutableListOf().apply { +// if (waterDebugRenderer) add(renderers.waterDebugRenderer) +// if (chunkBorderDebugRenderer) add(renderers.chunkBorderDebugRenderer) +// if (heightmapDebugRenderer) add(renderers.heightmapDebugRenderer) +// if (collisionDebugRenderer) add(renderers.collisionDebugRenderer) +// if (supportingBlockDebugRenderer) add(renderers.supportingBlockDebugRenderer) +// if (neighborUpdateDebugRenderer) add(renderers.neighborUpdateDebugRenderer) +// if (redstoneUpdateOrderDebugRenderer) add(renderers.redstoneUpdateOrderDebugRenderer) +// if (structureDebugRenderer) add(renderers.structureDebugRenderer) +// if (skyLightDebugRenderer) add(renderers.skyLightDebugRenderer) +// if (worldGenAttemptDebugRenderer) add(renderers.worldGenAttemptDebugRenderer) +// if (blockOutlineDebugRenderer) add(renderers.blockOutlineDebugRenderer) +// if (chunkLoadingDebugRenderer) add(renderers.chunkLoadingDebugRenderer) +// if (villageDebugRenderer) add(renderers.villageDebugRenderer) +// if (villageSectionsDebugRenderer) add(renderers.villageSectionsDebugRenderer) +// if (beeDebugRenderer) add(renderers.beeDebugRenderer) +// if (raidCenterDebugRenderer) add(renderers.raidCenterDebugRenderer) +// if (goalSelectorDebugRenderer) add(renderers.goalSelectorDebugRenderer) +// if (gameTestDebugRenderer) add(renderers.gameTestDebugRenderer) +// if (gameEventDebugRenderer) add(renderers.gameEventDebugRenderer) +// if (lightDebugRenderer) add(renderers.lightDebugRenderer) +// }.forEach { it.render(matrices, vertexConsumers, cameraX, cameraY, cameraZ) } +// } } \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/module/modules/player/Nuker.kt b/src/main/kotlin/com/lambda/module/modules/player/Nuker.kt index 4591c084a..25ba05ffb 100644 --- a/src/main/kotlin/com/lambda/module/modules/player/Nuker.kt +++ b/src/main/kotlin/com/lambda/module/modules/player/Nuker.kt @@ -64,13 +64,13 @@ object Nuker : Module( .filter { !flatten || it.y >= player.blockPos.y } .filter { pos -> if (!baritoneSelection) true - else BaritoneManager.primary.selectionManager.selections.any { + else BaritoneManager.primary?.selectionManager?.selections?.any { val min = it.min() val max = it.max() pos.x >= min.x && pos.x <= max.x && pos.y >= min.y && pos.y <= max.y && pos.z >= min.z && pos.z <= max.z - } + } ?: false } .associateWith { if (fillFluids) TargetState.Air else TargetState.Empty } diff --git a/src/main/kotlin/com/lambda/module/modules/render/BlockESP.kt b/src/main/kotlin/com/lambda/module/modules/render/BlockESP.kt index 282c6fcd1..3c6e1ad55 100644 --- a/src/main/kotlin/com/lambda/module/modules/render/BlockESP.kt +++ b/src/main/kotlin/com/lambda/module/modules/render/BlockESP.kt @@ -21,10 +21,10 @@ import com.lambda.Lambda.mc import com.lambda.config.settings.collections.CollectionSetting.Companion.onDeselect import com.lambda.config.settings.collections.CollectionSetting.Companion.onSelect import com.lambda.context.SafeContext -import com.lambda.graphics.renderer.esp.ChunkedESP.Companion.newChunkedESP +import com.lambda.graphics.mc.ChunkedRegionESP.Companion.newChunkedRegionESP +import com.lambda.graphics.mc.RegionShapeBuilder import com.lambda.graphics.renderer.esp.DirectionMask import com.lambda.graphics.renderer.esp.DirectionMask.buildSideMesh -import com.lambda.graphics.renderer.esp.ShapeBuilder import com.lambda.module.Module import com.lambda.module.tag.ModuleTag import com.lambda.threading.runSafe @@ -67,24 +67,29 @@ object BlockESP : Module( @JvmStatic val model: BlockStateModel get() = mc.bakedModelManager.missingModel - private val esp = newChunkedESP { world, position -> + private val esp = newChunkedRegionESP({ true }) { world, position -> val state = world.getBlockState(position) - if (state.block !in blocks) return@newChunkedESP + if (state.block !in blocks) return@newChunkedRegionESP - val sides = if (mesh) { - buildSideMesh(position) { - world.getBlockState(it).block in blocks - } - } else DirectionMask.ALL + val sides = + if (mesh) { + buildSideMesh(position) { world.getBlockState(it).block in blocks } + } else DirectionMask.ALL - build(state, position.toBlockPos(), sides) + runSafe { build(this@newChunkedRegionESP, state, position.toBlockPos(), sides) } } - private fun ShapeBuilder.build( + init { + onEnable { esp.rebuildAll() } + onDisable { esp.clear() } + } + + private fun SafeContext.build( + builder: RegionShapeBuilder, state: BlockState, pos: BlockPos, sides: Int, - ) = runSafe { + ) = with(builder) { val blockColor = blockColor(state, pos) if (drawFaces) filled(pos, state, if (useBlockColor) blockColor else faceColor, sides) diff --git a/src/main/kotlin/com/lambda/module/modules/render/ContainerPreview.kt b/src/main/kotlin/com/lambda/module/modules/render/ContainerPreview.kt index 22c8ee793..03a30fd93 100644 --- a/src/main/kotlin/com/lambda/module/modules/render/ContainerPreview.kt +++ b/src/main/kotlin/com/lambda/module/modules/render/ContainerPreview.kt @@ -29,7 +29,7 @@ import net.minecraft.block.ShulkerBoxBlock import net.minecraft.client.font.TextRenderer import net.minecraft.client.gui.DrawContext import net.minecraft.client.gui.tooltip.TooltipComponent -import net.minecraft.client.render.RenderLayer +import net.minecraft.client.gl.RenderPipelines import net.minecraft.item.BlockItem import net.minecraft.item.ItemStack import net.minecraft.item.Items @@ -152,8 +152,7 @@ object ContainerPreview : Module( val height = getTooltipHeight() val matrices = context.matrices - matrices.push() - matrices.translate(0f, 0f, 400f) + matrices.pushMatrix() val tintColor = getContainerTintColor(stack) @@ -201,11 +200,10 @@ object ContainerPreview : Module( } } - matrices.pop() + matrices.popMatrix() hoveredStack?.let { stack -> - matrices.push() - matrices.translate(0f, 0f, 500f) + matrices.pushMatrix() if (isPreviewableContainer(stack)) { val nestedWidth = getTooltipWidth() @@ -221,7 +219,7 @@ object ContainerPreview : Module( isRenderingSubTooltip = false } } - matrices.pop() + matrices.popMatrix() } } @@ -274,11 +272,12 @@ object ContainerPreview : Module( // Bottom: y=160 onwards context.drawTexture( - RenderLayer::getGuiTextured, + RenderPipelines.GUI_TEXTURED, background, x, y, 0f, 0f, width, TITLE_HEIGHT, + width, TITLE_HEIGHT, 256, 256, tintColor ) @@ -286,11 +285,12 @@ object ContainerPreview : Module( // Middle rows (0 until ROWS).forEach { row -> context.drawTexture( - RenderLayer::getGuiTextured, + RenderPipelines.GUI_TEXTURED, background, x, y + TITLE_HEIGHT + row * SLOT_SIZE, 0f, 17f, width, SLOT_SIZE, + width, SLOT_SIZE, 256, 256, tintColor ) @@ -298,11 +298,12 @@ object ContainerPreview : Module( // Bottom context.drawTexture( - RenderLayer::getGuiTextured, + RenderPipelines.GUI_TEXTURED, background, x, y + TITLE_HEIGHT + ROWS * SLOT_SIZE, 0f, 160f, width, PADDING, + width, PADDING, 256, 256, tintColor ) diff --git a/src/main/kotlin/com/lambda/module/modules/render/MapPreview.kt b/src/main/kotlin/com/lambda/module/modules/render/MapPreview.kt index cb17e9d65..667974f8f 100644 --- a/src/main/kotlin/com/lambda/module/modules/render/MapPreview.kt +++ b/src/main/kotlin/com/lambda/module/modules/render/MapPreview.kt @@ -24,7 +24,7 @@ import net.minecraft.client.font.TextRenderer import net.minecraft.client.gui.DrawContext import net.minecraft.client.gui.tooltip.TooltipComponent import net.minecraft.client.render.MapRenderState -import net.minecraft.client.render.RenderLayer +import net.minecraft.client.gl.RenderPipelines import net.minecraft.component.DataComponentTypes import net.minecraft.component.type.MapIdComponent import net.minecraft.item.FilledMapItem @@ -56,19 +56,19 @@ object MapPreview : Module( val matrices = context.matrices // Render the map background - matrices.push() - context.drawTexture(RenderLayer::getGuiTextured, background, x, y, 0f, 0f, 64, 64, 64, 64) - matrices.pop() + matrices.pushMatrix() + context.drawTexture(RenderPipelines.GUI_TEXTURED, background, x, y, 0f, 0f, 64, 64, 64, 64, 64, 64) + matrices.popMatrix() // Render the map texture - matrices.push() - matrices.translate(x + 3.2, y + 3.2, 401.0) - matrices.scale(0.45f, 0.45f, 1f) + matrices.pushMatrix() + matrices.translate(x + 3.2f, y + 3.2f) + matrices.scale(0.45f, 0.45f) val renderState = MapRenderState() mc.mapRenderer.update(id, state, renderState) - context.draw { mc.mapRenderer.draw(renderState, matrices, it, true, 0xF000F0) } - matrices.pop() + context.drawMap(renderState) + matrices.popMatrix() } override fun getHeight(textRenderer: TextRenderer) = diff --git a/src/main/kotlin/com/lambda/module/modules/render/NoRender.kt b/src/main/kotlin/com/lambda/module/modules/render/NoRender.kt index e496a768b..e0f576482 100644 --- a/src/main/kotlin/com/lambda/module/modules/render/NoRender.kt +++ b/src/main/kotlin/com/lambda/module/modules/render/NoRender.kt @@ -25,10 +25,8 @@ import com.lambda.util.reflections.scanResult import io.github.classgraph.ClassInfo import net.minecraft.block.entity.BlockEntity import net.minecraft.client.particle.Particle -import net.minecraft.client.render.BackgroundRenderer.StatusEffectFogModifier import net.minecraft.entity.Entity import net.minecraft.entity.SpawnGroup -import net.minecraft.entity.effect.StatusEffects //ToDo: Implement unimplemented settings. (Keep in mind compatibility with other mods like sodium) object NoRender : Module( @@ -149,6 +147,10 @@ object NoRender : Module( fun shouldOmitParticle(particle: Particle) = isEnabled && particleMap[particle.javaClass.simpleName] in particles + @JvmStatic + fun shouldOmitParticle(particle: Class) = + isEnabled && particleMap[particle.simpleName] in particles + @JvmStatic fun shouldOmitEntity(entity: Entity): Boolean { val simpleName = entity.javaClass.simpleName @@ -176,14 +178,6 @@ object NoRender : Module( fun shouldOmitBlockEntity(blockEntity: BlockEntity) = isEnabled && blockEntityMap[blockEntity.javaClass.simpleName] in blockEntities - @JvmStatic - fun shouldAcceptFog(modifier: StatusEffectFogModifier) = - when (modifier.statusEffect) { - StatusEffects.BLINDNESS if (noBlindness && isEnabled) -> false - StatusEffects.DARKNESS if (noDarkness && isEnabled) -> false - else -> true - } - private data class MappingInfo( val raw: String, val remapped: String, diff --git a/src/main/kotlin/com/lambda/module/modules/render/ViewModel.kt b/src/main/kotlin/com/lambda/module/modules/render/ViewModel.kt index e51c6f497..6a2a67594 100644 --- a/src/main/kotlin/com/lambda/module/modules/render/ViewModel.kt +++ b/src/main/kotlin/com/lambda/module/modules/render/ViewModel.kt @@ -36,6 +36,7 @@ import org.joml.Vector3f import org.joml.Vector3i import kotlin.math.tan +@Suppress("unused") object ViewModel : Module( name = "ViewModel", description = "Adjusts hand and held item rendering", @@ -115,17 +116,13 @@ object ViewModel : Module( listen { event -> if (event.keyCode == mc.options.attackKey.boundKey.code) { - if (event.isPressed) { - attackKeyTicksPressed = 0 - } else if (event.isReleased) { - attackKeyTicksPressed = -1 - } + if (event.isPressed) attackKeyTicksPressed = 0 + else if (event.isReleased) attackKeyTicksPressed = -1 } } listen { - if (attackKeyTicksPressed != -1) - attackKeyTicksPressed++ + if (attackKeyTicksPressed != -1) attackKeyTicksPressed++ } } @@ -158,20 +155,16 @@ object ViewModel : Module( val matrix = matrices.peek().positionMatrix - val distance = if (emptyHand) { - handFovAnchorDistance - } else { - when (side) { - Side.Left -> leftFovAnchorDistance - Side.Right -> rightFovAnchorDistance - } + val distance = if (emptyHand) handFovAnchorDistance + else when (side) { + Side.Left -> leftFovAnchorDistance + Side.Right -> rightFovAnchorDistance } - val warpMatrix = Matrix4f().apply { - translate(0f, 0f, -distance) - scale(1f, 1f, fovRatio) - translate(0f, 0f, distance) - } + val warpMatrix = Matrix4f() + .translate(0f, 0f, -distance) + .scale(1f, 1f, fovRatio) + .translate(0f, 0f, distance) matrix.mul(warpMatrix) } @@ -212,14 +205,12 @@ object ViewModel : Module( private fun getRotationVec(side: Side, emptyHand: Boolean) = when (side) { - Side.Left -> { + Side.Left -> if (emptyHand) Vector3i(handXRotation, -handYRotation, -handZRotation) else Vector3i(leftXRotation, -leftYRotation, -leftZRotation) - } - Side.Right -> { + Side.Right -> if (emptyHand) Vector3i(handXRotation, handYRotation, handZRotation) else Vector3i(rightXRotation, rightYRotation, rightZRotation) - } } fun adjustSwing(hand: Hand, player: AbstractClientPlayerEntity) = diff --git a/src/main/kotlin/com/lambda/module/modules/render/XRay.kt b/src/main/kotlin/com/lambda/module/modules/render/XRay.kt index 5fc7ed8d3..4be15ef08 100644 --- a/src/main/kotlin/com/lambda/module/modules/render/XRay.kt +++ b/src/main/kotlin/com/lambda/module/modules/render/XRay.kt @@ -41,12 +41,14 @@ object XRay : Module( ) @JvmStatic - val opacity by setting("Opacity", 40, 0..100, 1, "Opacity of the non x-rayed blocks, (automatically overridden as 0 when running Sodium)") + val opacity by setting("Opacity", 40, 1..100, 1, "Opacity of the non x-rayed blocks, (automatically overridden as 0 when running Sodium)") .onValueChange { _, _ -> if (isEnabled) mc.worldRenderer.reload() } - private val selection by setting("Block Selection", defaultBlocks, description = "Block selection that will be shown (whitelist) or hidden (blacklist)") .onValueChange { _, _ -> if (isEnabled) mc.worldRenderer.reload() } + + // ToDo: Blacklist causes huge performance issues due to many single faces being rendered private val mode by setting("Selection Mode", Selection.Whitelist, "The mode of the block selection") + .onValueChange { _, _ -> if (isEnabled) mc.worldRenderer.reload() } @JvmStatic fun isSelected(blockState: BlockState) = mode.select(blockState) diff --git a/src/main/kotlin/com/lambda/network/LambdaAPI.kt b/src/main/kotlin/com/lambda/network/LambdaAPI.kt index f86586403..7ff773e6b 100644 --- a/src/main/kotlin/com/lambda/network/LambdaAPI.kt +++ b/src/main/kotlin/com/lambda/network/LambdaAPI.kt @@ -36,6 +36,7 @@ import net.minecraft.client.network.ClientLoginNetworkHandler import net.minecraft.client.network.ServerAddress import net.minecraft.network.ClientConnection import net.minecraft.network.NetworkSide.CLIENTBOUND +import net.minecraft.network.NetworkingBackend import net.minecraft.network.packet.c2s.login.LoginHelloC2SPacket import net.minecraft.text.Text import java.math.BigInteger @@ -51,9 +52,7 @@ object LambdaAPI : Configurable(LambdaConfig) { val mappings get() = "$assets/mappings" // Folder containing mappings for our dynamic serializer val capes get() = "$assets/capes" // Folder containing all the capes, add .txt to get the list of available capes - - @Suppress("Deprecation") - const val GAME_VERSION = SharedConstants.VERSION_NAME + val gameVersion: String = SharedConstants.getGameVersion().name() private var hash: String? = null @@ -89,10 +88,11 @@ object LambdaAPI : Configurable(LambdaConfig) { val resolved = AllowedAddressResolver.DEFAULT.resolve(address) .map { it.inetSocketAddress }.getOrElse { return } - ClientConnection.connect(resolved, mc.options.shouldUseNativeTransport(), connection) + val backend = NetworkingBackend.remote(mc.options.shouldUseNativeTransport()) + ClientConnection.connect(resolved, backend, connection) .syncUninterruptibly() - val handler = ClientLoginNetworkHandler(connection, mc, null, null, false, null, { Text.empty() }, null) + val handler = ClientLoginNetworkHandler(connection, mc, null, null, false, null, { Text.empty() }, null, null) connection.connect(resolved.hostName, resolved.port, handler) connection.send(LoginHelloC2SPacket(mc.session.username, mc.session.uuidOrNull)) diff --git a/src/main/kotlin/com/lambda/threading/Threading.kt b/src/main/kotlin/com/lambda/threading/Threading.kt index a23a200c6..b1020869c 100644 --- a/src/main/kotlin/com/lambda/threading/Threading.kt +++ b/src/main/kotlin/com/lambda/threading/Threading.kt @@ -106,7 +106,7 @@ inline fun runSafeConcurrent(crossinline block: suspend SafeContext.() -> Unit) * to OpenGL. */ inline fun recordRenderCall(crossinline block: () -> Unit) { - mc.renderTaskQueue.add { block() } + mc.execute { block() } } /** diff --git a/src/main/kotlin/com/lambda/util/BlockUtils.kt b/src/main/kotlin/com/lambda/util/BlockUtils.kt index 4d3cfdbf6..f06e691af 100644 --- a/src/main/kotlin/com/lambda/util/BlockUtils.kt +++ b/src/main/kotlin/com/lambda/util/BlockUtils.kt @@ -57,7 +57,6 @@ import net.minecraft.block.EnchantingTableBlock import net.minecraft.block.EnderChestBlock import net.minecraft.block.FenceBlock import net.minecraft.block.FenceGateBlock -import net.minecraft.block.FletchingTableBlock import net.minecraft.block.FlowerPotBlock import net.minecraft.block.GrindstoneBlock import net.minecraft.block.HopperBlock @@ -233,7 +232,6 @@ object BlockUtils { EnderChestBlock::class, FenceBlock::class, FenceGateBlock::class, - FletchingTableBlock::class, FlowerPotBlock::class, GrindstoneBlock::class, HopperBlock::class, diff --git a/src/main/kotlin/com/lambda/util/DynamicReflectionSerializer.kt b/src/main/kotlin/com/lambda/util/DynamicReflectionSerializer.kt index 9164bed03..f80564603 100644 --- a/src/main/kotlin/com/lambda/util/DynamicReflectionSerializer.kt +++ b/src/main/kotlin/com/lambda/util/DynamicReflectionSerializer.kt @@ -80,8 +80,8 @@ object DynamicReflectionSerializer : Loadable { private const val INDENT = 2 private val qualifiedMappings = runBlocking { - cache.resolveFile(LambdaAPI.GAME_VERSION) - .downloadIfNotPresent("${LambdaAPI.mappings}/${LambdaAPI.GAME_VERSION}") + cache.resolveFile(LambdaAPI.gameVersion) + .downloadIfNotPresent("${LambdaAPI.mappings}/${LambdaAPI.gameVersion}") .map(::buildMappingsMap) .getOrElse { LOG.error("Unable to download simplified deobfuscated qualifiers", it) diff --git a/src/main/kotlin/com/lambda/util/player/PlayerUtils.kt b/src/main/kotlin/com/lambda/util/player/PlayerUtils.kt index 3913cad33..69bfb79dc 100644 --- a/src/main/kotlin/com/lambda/util/player/PlayerUtils.kt +++ b/src/main/kotlin/com/lambda/util/player/PlayerUtils.kt @@ -33,7 +33,7 @@ val SafeContext.gamemode: GameMode get() = interaction.currentGameMode fun SafeContext.copyPlayer(entity: ClientPlayerEntity) = - ClientPlayerEntity(mc, world, mc.networkHandler, null, null, entity.isSneaking, entity.isSprinting).apply { + ClientPlayerEntity(mc, world, mc.networkHandler, null, null, entity.lastPlayerInput, entity.isSprinting).apply { setPos(entity.x, entity.y, entity.z) setExperience(entity.experienceProgress, entity.totalExperience, entity.experienceLevel) health = entity.health diff --git a/src/main/kotlin/com/lambda/util/text/StyleDsl.kt b/src/main/kotlin/com/lambda/util/text/StyleDsl.kt index 91fa10f20..7c1027e98 100644 --- a/src/main/kotlin/com/lambda/util/text/StyleDsl.kt +++ b/src/main/kotlin/com/lambda/util/text/StyleDsl.kt @@ -23,8 +23,8 @@ import net.minecraft.text.ClickEvent import net.minecraft.text.HoverEvent import net.minecraft.text.MutableText import net.minecraft.text.Style +import net.minecraft.text.StyleSpriteSource import net.minecraft.text.TextColor -import net.minecraft.util.Identifier import java.awt.Color /** @@ -149,9 +149,9 @@ class StyleBuilder { } /** - * An [Identifier] for the Minecraft font that would like to be used. + * A [StyleSpriteSource] for the Minecraft font that would like to be used. */ - var font: Identifier? = null + var font: StyleSpriteSource? = null set(value) { if (field != value) { cachedStyle = null diff --git a/src/main/kotlin/com/lambda/util/text/TextDsl.kt b/src/main/kotlin/com/lambda/util/text/TextDsl.kt index cbf885c13..6a8f3892e 100644 --- a/src/main/kotlin/com/lambda/util/text/TextDsl.kt +++ b/src/main/kotlin/com/lambda/util/text/TextDsl.kt @@ -23,8 +23,8 @@ import net.minecraft.text.HoverEvent import net.minecraft.text.MutableText import net.minecraft.text.NbtDataSource import net.minecraft.text.Style +import net.minecraft.text.StyleSpriteSource import net.minecraft.text.Text -import net.minecraft.util.Identifier import java.awt.Color import java.util.* @@ -296,7 +296,7 @@ inline fun TextBuilder.insertion(insertion: String?, action: TextBuilder.() -> U * Applies the [TextBuilder] [action] with [font] set to the provided value. */ @TextDsl -inline fun TextBuilder.font(font: Identifier?, action: TextBuilder.() -> Unit) { +inline fun TextBuilder.font(font: StyleSpriteSource?, action: TextBuilder.() -> Unit) { withProp(font, { this.font }, { this.font = it }, action) } @@ -314,7 +314,7 @@ fun TextBuilder.styled( clickEvent: ClickEvent? = style.clickEvent, hoverEvent: HoverEvent? = style.hoverEvent, insertion: String? = style.insertion, - font: Identifier? = style.font, + font: StyleSpriteSource? = style.font, action: TextBuilder.() -> Unit, ) { color(color) { diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index 50e5c4edf..7110a6c21 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -29,7 +29,9 @@ "minecraft": "~$minecraftVersion", "fabric-api": ">=$fabricApiVersion+$minecraftVersion", "fabric-language-kotlin": ">=$kotlinFabricVersion", - "java": ">=$javaVersion", + "java": ">=$javaVersion" + }, + "recommends": { "baritone": "*" } } diff --git a/src/main/resources/lambda.accesswidener b/src/main/resources/lambda.accesswidener index 1914bc8c9..fa5cb8b77 100644 --- a/src/main/resources/lambda.accesswidener +++ b/src/main/resources/lambda.accesswidener @@ -6,7 +6,7 @@ transitive-accessible field net/minecraft/client/MinecraftClient paused Z transitive-accessible field net/minecraft/client/MinecraftClient thread Ljava/lang/Thread; transitive-accessible field net/minecraft/client/MinecraftClient uptimeInTicks J transitive-accessible field net/minecraft/client/input/Input movementVector Lnet/minecraft/util/math/Vec2f; -transitive-accessible field net/minecraft/client/MinecraftClient renderTaskQueue Ljava/util/Queue; +# REMOVED in 1.21.11: renderTaskQueue - use mc.execute {} instead (inherited from ReentrantThreadExecutor) transitive-accessible field net/minecraft/client/option/KeyBinding boundKey Lnet/minecraft/client/util/InputUtil$Key; transitive-accessible method net/minecraft/client/MinecraftClient getWindowTitle ()Ljava/lang/String; transitive-accessible field net/minecraft/client/option/KeyBinding KEYS_BY_ID Ljava/util/Map; @@ -26,13 +26,16 @@ transitive-accessible method net/minecraft/item/BlockItem placeFromNbt (Lnet/min transitive-accessible method net/minecraft/item/BlockItem postPlacement (Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/world/World;Lnet/minecraft/entity/player/PlayerEntity;Lnet/minecraft/item/ItemStack;Lnet/minecraft/block/BlockState;)Z transitive-accessible method net/minecraft/item/BlockItem getPlaceSound (Lnet/minecraft/block/BlockState;)Lnet/minecraft/sound/SoundEvent; transitive-accessible field net/minecraft/state/State owner Ljava/lang/Object; -transitive-accessible class net/minecraft/client/render/BackgroundRenderer$StatusEffectFogModifier +# MOVED in 1.21.11: BackgroundRenderer$StatusEffectFogModifier -> net/minecraft/client/render/fog/StatusEffectFogModifier +transitive-accessible class net/minecraft/client/render/fog/StatusEffectFogModifier +transitive-accessible field net/minecraft/client/particle/NoRenderParticleRenderer EMPTY Lnet/minecraft/client/render/Submittable; # Entity transitive-accessible field net/minecraft/entity/projectile/FireworkRocketEntity shooter Lnet/minecraft/entity/LivingEntity; transitive-accessible method net/minecraft/entity/Entity movementInputToVelocity (Lnet/minecraft/util/math/Vec3d;FF)Lnet/minecraft/util/math/Vec3d; transitive-accessible method net/minecraft/entity/passive/AbstractHorseEntity setHorseFlag (IZ)V -transitive-accessible field net/minecraft/entity/LivingEntity lastAttackedTicks I +# RENAMED in 1.21.11: lastAttackedTicks -> lastAttackedTime +transitive-accessible field net/minecraft/entity/LivingEntity lastAttackedTime I transitive-accessible method net/minecraft/entity/Entity setFlag (IZ)V transitive-accessible field net/minecraft/client/network/AbstractClientPlayerEntity playerListEntry Lnet/minecraft/client/network/PlayerListEntry; transitive-accessible field net/minecraft/entity/LivingEntity jumpingCooldown I @@ -50,10 +53,12 @@ transitive-accessible method net/minecraft/util/math/Direction listClosest (Lnet transitive-accessible field net/minecraft/client/network/ClientPlayerInteractionManager gameMode Lnet/minecraft/world/GameMode; transitive-accessible method net/minecraft/entity/player/PlayerEntity updatePose ()V transitive-accessible field net/minecraft/screen/ScreenHandler revision I +accessible field net/minecraft/entity/Entity world Lnet/minecraft/world/World; # Camera transitive-accessible method net/minecraft/client/render/Camera setPos (DDD)V transitive-accessible method net/minecraft/client/render/Camera setRotation (FF)V +accessible field net/minecraft/client/render/Camera pos Lnet/minecraft/util/math/Vec3d; # Renderer transitive-accessible field net/minecraft/client/texture/NativeImage pointer J @@ -71,8 +76,10 @@ transitive-accessible field net/minecraft/text/Style obfuscated Ljava/lang/Boole transitive-accessible field net/minecraft/text/Style clickEvent Lnet/minecraft/text/ClickEvent; transitive-accessible field net/minecraft/text/Style hoverEvent Lnet/minecraft/text/HoverEvent; transitive-accessible field net/minecraft/text/Style insertion Ljava/lang/String; -transitive-accessible field net/minecraft/text/Style font Lnet/minecraft/util/Identifier; -transitive-accessible method net/minecraft/text/Style (Lnet/minecraft/text/TextColor;Ljava/lang/Integer;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Lnet/minecraft/text/ClickEvent;Lnet/minecraft/text/HoverEvent;Ljava/lang/String;Lnet/minecraft/util/Identifier;)V +# CHANGED in 1.21.11: font type changed from Identifier to StyleSpriteSource +transitive-accessible field net/minecraft/text/Style font Lnet/minecraft/text/StyleSpriteSource; +# CHANGED in 1.21.11: constructor added shadowColor parameter, font type changed to StyleSpriteSource +transitive-accessible method net/minecraft/text/Style (Lnet/minecraft/text/TextColor;Ljava/lang/Integer;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Lnet/minecraft/text/ClickEvent;Lnet/minecraft/text/HoverEvent;Ljava/lang/String;Lnet/minecraft/text/StyleSpriteSource;)V # Network transitive-accessible field net/minecraft/client/network/ClientPlayNetworkHandler playerListEntries Ljava/util/Map; @@ -98,12 +105,11 @@ transitive-accessible method net/minecraft/util/math/Vec3i setY (I)Lnet/minecraf transitive-accessible method net/minecraft/util/math/Vec3i setZ (I)Lnet/minecraft/util/math/Vec3i; # Debug -transitive-accessible field net/minecraft/client/gui/hud/DebugHud showDebugHud Z +# REMOVED in 1.21.11: showDebugHud - use DebugHud.shouldShowDebugHud() method instead transitive-accessible field net/minecraft/client/gui/hud/DebugHud renderingChartVisible Z transitive-accessible field net/minecraft/client/gui/hud/DebugHud renderingAndTickChartsVisible Z transitive-accessible field net/minecraft/client/gui/hud/DebugHud packetSizeAndPingChartsVisible Z -transitive-accessible field net/minecraft/client/render/debug/DebugRenderer showChunkBorder Z -transitive-accessible field net/minecraft/client/render/debug/DebugRenderer showOctree Z +# REMOVED in 1.21.11: showChunkBorder/showOctree - now controlled via debugHudEntryList.isEntryVisible(DebugHudEntries.CHUNK_BORDERS/CHUNK_SECTION_OCTREE) # Other transitive-accessible field net/minecraft/structure/StructureTemplate blockInfoLists Ljava/util/List; diff --git a/src/main/resources/lambda.mixins.common.json b/src/main/resources/lambda.mixins.common.json index f11bdfb07..6c6be1c70 100644 --- a/src/main/resources/lambda.mixins.common.json +++ b/src/main/resources/lambda.mixins.common.json @@ -29,12 +29,9 @@ "network.HandshakeC2SPacketMixin", "network.LoginHelloC2SPacketMixin", "network.LoginKeyC2SPacketMixin", - "render.AbstractSignBlockEntityRendererMixin", "render.AbstractTerrainRenderContextMixin", "render.ArmorFeatureRendererMixin", "render.BackgroundRendererMixin", - "render.BeaconBlockEntityRendererMixin", - "render.BlockEntityRenderDispatcherMixin", "render.BlockMixin", "render.BlockModelRendererMixin", "render.BlockRenderManagerMixin", @@ -45,24 +42,22 @@ "render.ChatInputSuggestorMixin", "render.ChatScreenMixin", "render.ChunkOcclusionDataBuilderMixin", + "render.DarknessEffectFogMixin", "render.DebugHudMixin", "render.DebugRendererMixin", "render.DrawContextMixin", "render.ElytraFeatureRendererMixin", - "render.EnchantingTableBlockEntityRendererMixin", "render.EntityRendererMixin", "render.FluidRendererMixin", "render.GameRendererMixin", - "render.HandledScreenMixin", "render.GlStateManagerMixin", + "render.HandledScreenMixin", "render.HeadFeatureRendererMixin", "render.HeldItemRendererMixin", "render.InGameHudMixin", "render.InGameOverlayRendererMixin", "render.LightmapTextureManagerMixin", "render.LivingEntityRendererMixin", - "render.MobSpawnerBlockEntityRendererMixin", - "render.ParticleManagerMixin", "render.PlayerListHudMixin", "render.RenderLayersMixin", "render.ScreenHandlerMixin", @@ -77,6 +72,14 @@ "render.WeatherRenderingMixin", "render.WorldBorderRenderingMixin", "render.WorldRendererMixin", + "render.blockentity.AbstractSignBlockEntityRendererMixin", + "render.blockentity.BeaconBlockEntityRendererMixin", + "render.blockentity.BlockEntityRenderDispatcherMixin", + "render.blockentity.EnchantingTableBlockEntityRendererMixin", + "render.blockentity.MobSpawnerBlockEntityRendererMixin", + "render.particle.BillboardParticleMixin", + "render.particle.ElderGuardianParticleRendererMixin", + "render.particle.ItemPickupParticleRendererMixin", "world.AbstractBlockMixin", "world.BlockCollisionSpliteratorMixin", "world.ClientChunkManagerMixin", @@ -85,6 +88,9 @@ "world.WorldMixin" ], "injectors": { - "defaultRequire": 1 + "defaultRequire": 0 + }, + "overwrites": { + "conformVisibility": true } }