diff --git a/build.gradle.kts b/build.gradle.kts index 843669b4c..c3c4df407 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -30,6 +30,7 @@ val discordIPCVersion: String by project val classGraphVersion: String by project val kotlinVersion: String by project val ktorVersion: String by project +val jacksonVersion: String by project val mockkVersion: String by project val spairVersion: String by project val lwjglVersion: String by project @@ -80,6 +81,7 @@ repositories { } fabricApi { + @Suppress("UnstableApiUsage") configureTests { modId = "${base.archivesName}-tests" eula = true @@ -173,7 +175,10 @@ dependencies { exclude(group = "org.slf4j") } includeLib("io.ktor:ktor-client-content-negotiation:$ktorVersion") - includeLib("io.ktor:ktor-serialization-gson:$ktorVersion") + includeLib("io.ktor:ktor-serialization-jackson:$ktorVersion") + includeLib("tools.jackson.core:jackson-core:$jacksonVersion") + includeLib("tools.jackson.core:jackson-databind:$jacksonVersion") + includeLib("tools.jackson.module:jackson-module-kotlin:$jacksonVersion") // Add mods modImplementation("com.github.rfresh2:baritone-fabric:$minecraftVersion-SNAPSHOT") @@ -221,7 +226,7 @@ tasks { kotlin { compilerOptions { - freeCompilerArgs.addAll("-Xcontext-parameters", "-Xconsistent-data-class-copy-visibility") + freeCompilerArgs.addAll("-Xcontext-parameters", "-Xconsistent-data-class-copy-visibility", "-Xannotation-default-target=param-property") } jvmToolchain(21) @@ -267,4 +272,4 @@ publishing { } } } -} +} \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 6571d170b..c6e8b2555 100644 --- a/gradle.properties +++ b/gradle.properties @@ -35,6 +35,7 @@ baritoneVersion=1.14.0 discordIPCVersion=6f6b6cce17 classGraphVersion=4.8.184 ktorVersion=3.3.3 +jacksonVersion=3.1.1 mockkVersion=1.14.7 spairVersion=1.90.0 diff --git a/src/main/java/com/lambda/mixin/CrashReportMixin.java b/src/main/java/com/lambda/mixin/CrashReportMixin.java index 79cb84581..855308fe6 100644 --- a/src/main/java/com/lambda/mixin/CrashReportMixin.java +++ b/src/main/java/com/lambda/mixin/CrashReportMixin.java @@ -18,12 +18,13 @@ package com.lambda.mixin; import com.lambda.Lambda; -import com.lambda.config.Setting; +import com.lambda.config.SettingLayer; import com.lambda.module.Module; import com.lambda.module.ModuleRegistry; import com.lambda.util.DynamicExceptionKt; import com.llamalad7.mixinextras.injector.wrapmethod.WrapMethod; import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import kotlin.Unit; import net.minecraft.client.MinecraftClient; import net.minecraft.util.crash.CrashReport; import net.minecraft.util.crash.ReportType; @@ -54,7 +55,7 @@ void injectConstructor(String message, Throwable cause, CallbackInfo ci) { @WrapMethod(method = "asString(Lnet/minecraft/util/crash/ReportType;Ljava/util/List;)Ljava/lang/String;") String injectString(ReportType type, List extraInfo, Operation original) { var list = new ArrayList<>(extraInfo); - list.add("If this issue is related to Lambda, check if other users have experienced this too, or create a new issue at " + Lambda.REPO_URL + "/issues.\n\n"); + list.add("If this issue is related to Lambda, check if other users have experienced this too, or create a new issue at " + Lambda.RepoUrl + "/issues.\n\n"); if (MinecraftClient.getInstance() != null) { list.add("Enabled modules:"); @@ -65,10 +66,18 @@ String injectString(ReportType type, List extraInfo, Operation o .forEach(module -> { list.add(String.format("\t%s", module.getName())); - module.getSettings() - .stream() - .filter(Setting::isModified) - .forEach(setting -> list.add(String.format("\t\t%s -> %s", setting.getName(), setting.getValue()))); + module.forEachSetting$lambda( + module.getSettingLayers$lambda(), + true, + null, + (path, single) -> { + final var setting = single.getSetting(); + if (setting.isModified()) { + list.add("\t\t" + String.join(".", path.stream().map(SettingLayer.Multiple::getName).toList()) + "." + setting.getName() + " -> " + setting.getValue()); + } + return Unit.INSTANCE; + } + ); }); } diff --git a/src/main/java/com/lambda/mixin/MinecraftClientMixin.java b/src/main/java/com/lambda/mixin/MinecraftClientMixin.java index bf8646eb9..9bba1faa8 100644 --- a/src/main/java/com/lambda/mixin/MinecraftClientMixin.java +++ b/src/main/java/com/lambda/mixin/MinecraftClientMixin.java @@ -17,7 +17,7 @@ package com.lambda.mixin; -import com.lambda.core.TimerManager; +import com.lambda.core.TimerHandler; import com.lambda.event.EventFlow; import com.lambda.event.events.*; import com.lambda.gui.DearImGui; @@ -127,6 +127,7 @@ private void onShutdown(CallbackInfo ci) { * Inject after the thread field is set so that {@link ThreadExecutor#getThread} * is available */ + @SuppressWarnings("JavadocReference") @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()); @@ -191,10 +192,10 @@ void injectItemPick(Operation original) { @WrapMethod(method = "getTargetMillisPerTick") float getTargetMillisPerTick(float millis, Operation original) { - var length = TimerManager.INSTANCE.getLength(); + var length = TimerHandler.INSTANCE.getLength(); - if (length == TimerManager.DEFAULT_LENGTH) return original.call(millis); - else return (float) TimerManager.INSTANCE.getLength(); + if (length == TimerHandler.DefaultLength) return original.call(millis); + else return (float) TimerHandler.INSTANCE.getLength(); } @Inject(method = "updateWindowTitle", at = @At("HEAD"), cancellable = true) diff --git a/src/main/java/com/lambda/mixin/baritone/BaritonePlayerContextMixin.java b/src/main/java/com/lambda/mixin/baritone/BaritonePlayerContextMixin.java index 0bc8f1b00..2e0a86d85 100644 --- a/src/main/java/com/lambda/mixin/baritone/BaritonePlayerContextMixin.java +++ b/src/main/java/com/lambda/mixin/baritone/BaritonePlayerContextMixin.java @@ -20,7 +20,7 @@ import baritone.Baritone; import baritone.api.utils.Rotation; import baritone.utils.player.BaritonePlayerContext; -import com.lambda.interaction.BaritoneManager; +import com.lambda.interaction.BaritoneHandler; import com.lambda.interaction.managers.rotating.RotationManager; import com.llamalad7.mixinextras.injector.ModifyReturnValue; import org.spongepowered.asm.mixin.Final; @@ -37,7 +37,7 @@ public class BaritonePlayerContextMixin { // Let baritone know the actual rotation @ModifyReturnValue(method = "playerRotations", at = @At("RETURN"), remap = false) Rotation syncRotationWithBaritone(Rotation original) { - if (baritone != BaritoneManager.getPrimary()) + if (baritone != BaritoneHandler.getPrimary()) return original; float yaw = (float) RotationManager.getActiveRotation().getYaw(); diff --git a/src/main/java/com/lambda/mixin/baritone/LookBehaviourMixin.java b/src/main/java/com/lambda/mixin/baritone/LookBehaviourMixin.java index 41eea516b..86ba59cd0 100644 --- a/src/main/java/com/lambda/mixin/baritone/LookBehaviourMixin.java +++ b/src/main/java/com/lambda/mixin/baritone/LookBehaviourMixin.java @@ -21,7 +21,7 @@ import baritone.api.event.events.RotationMoveEvent; import baritone.api.utils.Rotation; import baritone.behavior.LookBehavior; -import com.lambda.interaction.BaritoneManager; +import com.lambda.interaction.BaritoneHandler; import com.lambda.interaction.managers.rotating.RotationManager; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Unique; @@ -37,7 +37,7 @@ public class LookBehaviourMixin { // Redirect baritone's rotations into our rotation engine @Inject(method = "updateTarget", at = @At("HEAD"), cancellable = true) void onTargetUpdate(Rotation rotation, boolean blockInteract, CallbackInfo ci) { - if (instance.baritone != BaritoneManager.getPrimary()) return; + if (instance.baritone != BaritoneHandler.getPrimary()) return; RotationManager.handleBaritoneRotation(rotation.getYaw(), rotation.getPitch()); ci.cancel(); @@ -45,14 +45,14 @@ void onTargetUpdate(Rotation rotation, boolean blockInteract, CallbackInfo ci) { @Inject(method = "onPlayerUpdate", at = @At("HEAD"), cancellable = true) void onUpdate(PlayerUpdateEvent event, CallbackInfo ci) { - if (instance.baritone != BaritoneManager.getPrimary()) return; + if (instance.baritone != BaritoneHandler.getPrimary()) return; ci.cancel(); } @Inject(method = "onPlayerRotationMove", at = @At("HEAD"), cancellable = true) void onMovementUpdate(RotationMoveEvent event, CallbackInfo ci) { - if (instance.baritone != BaritoneManager.getPrimary()) return; + if (instance.baritone != BaritoneHandler.getPrimary()) return; ci.cancel(); } diff --git a/src/main/java/com/lambda/mixin/render/BlockEntityRenderManagerMixin.java b/src/main/java/com/lambda/mixin/render/BlockEntityRenderManagerMixin.java index d67129b26..0bb9c2c3d 100644 --- a/src/main/java/com/lambda/mixin/render/BlockEntityRenderManagerMixin.java +++ b/src/main/java/com/lambda/mixin/render/BlockEntityRenderManagerMixin.java @@ -17,8 +17,8 @@ package com.lambda.mixin.render; -import com.lambda.graphics.outline.OutlineManager; import com.lambda.graphics.outline.OutlineCapturingQueue; +import com.lambda.graphics.outline.OutlineHandler; import com.lambda.graphics.outline.VertexCapture; import com.llamalad7.mixinextras.injector.wrapoperation.Operation; import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; @@ -42,7 +42,7 @@ private void wrapRenderQueue(BlockEntityRende Operation original) { BlockPos pos = renderState.pos; - if (pos != null && OutlineManager.shouldCapture(pos)) { + if (pos != null && OutlineHandler.shouldCapture(pos)) { VertexCapture.INSTANCE.beginCapture(pos); boolean outlineOnly = !Vec3d.ofCenter(pos).isInRange(cameraState.pos, renderer.getRenderDistance()); diff --git a/src/main/java/com/lambda/mixin/render/BlockEntityRendererMixin.java b/src/main/java/com/lambda/mixin/render/BlockEntityRendererMixin.java index d33c9fee4..f2a4d8286 100644 --- a/src/main/java/com/lambda/mixin/render/BlockEntityRendererMixin.java +++ b/src/main/java/com/lambda/mixin/render/BlockEntityRendererMixin.java @@ -17,7 +17,7 @@ package com.lambda.mixin.render; -import com.lambda.graphics.outline.OutlineManager; +import com.lambda.graphics.outline.OutlineHandler; import net.minecraft.block.entity.BlockEntity; import net.minecraft.client.render.block.entity.BlockEntityRenderer; import net.minecraft.util.math.Vec3d; @@ -31,7 +31,7 @@ public interface BlockEntityRendererMixin { @Inject(method = "isInRenderDistance", at = @At("HEAD"), cancellable = true) default void forceOutlineRenderDistance(T blockEntity, Vec3d pos, CallbackInfoReturnable cir) { - if (OutlineManager.INSTANCE.shouldCapture(blockEntity.getPos())) { + if (OutlineHandler.shouldCapture(blockEntity.getPos())) { cir.setReturnValue(true); } } diff --git a/src/main/java/com/lambda/mixin/render/CameraMixin.java b/src/main/java/com/lambda/mixin/render/CameraMixin.java index 20c91d035..38f629489 100644 --- a/src/main/java/com/lambda/mixin/render/CameraMixin.java +++ b/src/main/java/com/lambda/mixin/render/CameraMixin.java @@ -18,9 +18,9 @@ package com.lambda.mixin.render; import com.lambda.interaction.managers.rotating.RotationManager; -import com.lambda.module.modules.render.Freecam; import com.lambda.module.modules.render.CameraTweaks; import com.lambda.module.modules.render.FreeLook; +import com.lambda.module.modules.render.Freecam; import com.lambda.module.modules.render.NoRender; import net.minecraft.block.enums.CameraSubmersionType; import net.minecraft.client.render.Camera; diff --git a/src/main/java/com/lambda/mixin/render/CapeFeatureRendererMixin.java b/src/main/java/com/lambda/mixin/render/CapeFeatureRendererMixin.java index bc81be503..94997a075 100644 --- a/src/main/java/com/lambda/mixin/render/CapeFeatureRendererMixin.java +++ b/src/main/java/com/lambda/mixin/render/CapeFeatureRendererMixin.java @@ -19,7 +19,7 @@ import com.lambda.Lambda; import com.lambda.module.modules.client.Capes; -import com.lambda.network.CapeManager; +import com.lambda.network.CapeHandler; import com.llamalad7.mixinextras.injector.ModifyExpressionValue; import net.minecraft.client.render.command.OrderedRenderCommandQueue; import net.minecraft.client.render.entity.feature.CapeFeatureRenderer; @@ -43,8 +43,8 @@ Identifier renderCape(Identifier original, MatrixStack matrixStack, OrderedRende if (entry == null) return original; var profile = entry.getProfile(); - if (!Capes.INSTANCE.isEnabled() || !CapeManager.INSTANCE.getCache().containsKey(profile.id())) return original; + if (!Capes.INSTANCE.isEnabled() || !CapeHandler.INSTANCE.getCache().containsKey(profile.id())) return original; - return Identifier.of("lambda", CapeManager.INSTANCE.getCache().get(profile.id())); + return Identifier.of("lambda", CapeHandler.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 83ac008b9..f7cd5a5c9 100644 --- a/src/main/java/com/lambda/mixin/render/ChatInputSuggestorMixin.java +++ b/src/main/java/com/lambda/mixin/render/ChatInputSuggestorMixin.java @@ -17,7 +17,7 @@ package com.lambda.mixin.render; -import com.lambda.command.CommandManager; +import com.lambda.command.CommandHandler; import com.llamalad7.mixinextras.injector.wrapoperation.Operation; import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; import com.mojang.brigadier.CommandDispatcher; @@ -40,12 +40,12 @@ public abstract class ChatInputSuggestorMixin { @ModifyVariable(method = "refresh", at = @At(value = "STORE"), index = 3) private boolean refreshModify(boolean showCompletions) { - return CommandManager.INSTANCE.isCommand(textField.getText()); + return CommandHandler.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 (CommandDispatcher) CommandManager.INSTANCE.currentDispatcher(textField.getText()); + return (CommandDispatcher) CommandHandler.INSTANCE.currentDispatcher(textField.getText()); } } diff --git a/src/main/java/com/lambda/mixin/render/ChatScreenMixin.java b/src/main/java/com/lambda/mixin/render/ChatScreenMixin.java index 4215fc37c..c3e22e955 100644 --- a/src/main/java/com/lambda/mixin/render/ChatScreenMixin.java +++ b/src/main/java/com/lambda/mixin/render/ChatScreenMixin.java @@ -17,7 +17,7 @@ package com.lambda.mixin.render; -import com.lambda.command.CommandManager; +import com.lambda.command.CommandHandler; import net.minecraft.client.gui.screen.ChatScreen; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; @@ -28,8 +28,8 @@ public abstract class ChatScreenMixin { @Inject(method = "sendMessage", at = @At("HEAD"), cancellable = true) void sendMessageInject(String chatText, boolean addToHistory, CallbackInfo ci) { - if (!CommandManager.INSTANCE.isLambdaCommand(chatText)) return; - CommandManager.INSTANCE.executeCommand(chatText); + if (!CommandHandler.INSTANCE.isLambdaCommand(chatText)) return; + CommandHandler.INSTANCE.executeCommand(chatText); ci.cancel(); } } diff --git a/src/main/java/com/lambda/mixin/render/ElytraFeatureRendererMixin.java b/src/main/java/com/lambda/mixin/render/ElytraFeatureRendererMixin.java index f9fad2c82..511ab3671 100644 --- a/src/main/java/com/lambda/mixin/render/ElytraFeatureRendererMixin.java +++ b/src/main/java/com/lambda/mixin/render/ElytraFeatureRendererMixin.java @@ -20,7 +20,7 @@ import com.lambda.Lambda; import com.lambda.module.modules.client.Capes; import com.lambda.module.modules.render.NoRender; -import com.lambda.network.CapeManager; +import com.lambda.network.CapeHandler; import com.llamalad7.mixinextras.injector.ModifyReturnValue; import com.llamalad7.mixinextras.injector.wrapmethod.WrapMethod; import com.llamalad7.mixinextras.injector.wrapoperation.Operation; @@ -50,10 +50,10 @@ private static Identifier injectElytra(Identifier original, BipedEntityRenderSta var profile = entry.getProfile(); - if (!Capes.INSTANCE.isEnabled() || !CapeManager.INSTANCE.getCache().containsKey(profile.id())) + if (!Capes.INSTANCE.isEnabled() || !CapeHandler.INSTANCE.getCache().containsKey(profile.id())) return original; - return Identifier.of("lambda", CapeManager.INSTANCE.getCache().get(profile.id())); + return Identifier.of("lambda", CapeHandler.INSTANCE.getCache().get(profile.id())); } @WrapMethod(method = "render(Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/command/OrderedRenderCommandQueue;ILnet/minecraft/client/render/entity/state/BipedEntityRenderState;FF)V") diff --git a/src/main/java/com/lambda/mixin/render/EntityRenderManagerMixin.java b/src/main/java/com/lambda/mixin/render/EntityRenderManagerMixin.java index f9c12ea60..81a864ae9 100644 --- a/src/main/java/com/lambda/mixin/render/EntityRenderManagerMixin.java +++ b/src/main/java/com/lambda/mixin/render/EntityRenderManagerMixin.java @@ -18,8 +18,8 @@ package com.lambda.mixin.render; import com.lambda.graphics.outline.IEntityRenderState; -import com.lambda.graphics.outline.OutlineManager; import com.lambda.graphics.outline.OutlineCapturingQueue; +import com.lambda.graphics.outline.OutlineHandler; import com.lambda.graphics.outline.VertexCapture; import com.llamalad7.mixinextras.injector.wrapoperation.Operation; import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; @@ -51,7 +51,7 @@ private void wrapRenderQueue(EntityRenderer entityId = lambdaState.lambda$getEntityId(); } - if (entityId != -1 && OutlineManager.shouldCapture(entityId)) { + if (entityId != -1 && OutlineHandler.shouldCapture(entityId)) { VertexCapture.INSTANCE.beginCapture(entityId); OrderedRenderCommandQueueImpl wrappedQueue = new OutlineCapturingQueue((OrderedRenderCommandQueueImpl) queue, entityId); diff --git a/src/main/java/com/lambda/mixin/render/EntityRendererMixin.java b/src/main/java/com/lambda/mixin/render/EntityRendererMixin.java index 0de330752..5eba1041d 100644 --- a/src/main/java/com/lambda/mixin/render/EntityRendererMixin.java +++ b/src/main/java/com/lambda/mixin/render/EntityRendererMixin.java @@ -17,7 +17,7 @@ package com.lambda.mixin.render; -import com.lambda.graphics.outline.OutlineManager; +import com.lambda.graphics.outline.OutlineHandler; import com.lambda.module.modules.render.NoRender; import net.minecraft.client.render.Frustum; import net.minecraft.client.render.command.OrderedRenderCommandQueue; @@ -37,7 +37,7 @@ public class EntityRendererMixin { @Inject(method = "shouldRender(Lnet/minecraft/entity/Entity;Lnet/minecraft/client/render/Frustum;DDD)Z", at = @At("HEAD"), cancellable = true) private void injectShouldRender(Entity entity, Frustum frustum, double x, double y, double z, CallbackInfoReturnable cir) { if (NoRender.shouldOmitEntity(entity)) cir.cancel(); - else if (OutlineManager.shouldCapture(entity.getId())) cir.setReturnValue(true); + else if (OutlineHandler.shouldCapture(entity.getId())) cir.setReturnValue(true); } @Inject(method = "renderLabelIfPresent", at = @At("HEAD"), cancellable = true) diff --git a/src/main/java/com/lambda/mixin/render/GameRendererMixin.java b/src/main/java/com/lambda/mixin/render/GameRendererMixin.java index 6c5fb87d6..4925326d3 100644 --- a/src/main/java/com/lambda/mixin/render/GameRendererMixin.java +++ b/src/main/java/com/lambda/mixin/render/GameRendererMixin.java @@ -19,10 +19,9 @@ import com.lambda.event.EventFlow; import com.lambda.event.events.RenderEvent; -import com.lambda.gui.DearImGui; import com.lambda.graphics.RenderMain; import com.lambda.graphics.outline.OutlineCapturingQueue; -import net.minecraft.client.render.command.OrderedRenderCommandQueueImpl; +import com.lambda.gui.DearImGui; import com.lambda.module.modules.render.BlockOutline; import com.lambda.module.modules.render.Bobbing; import com.lambda.module.modules.render.NoRender; @@ -36,6 +35,7 @@ import net.minecraft.client.render.GameRenderer; import net.minecraft.client.render.RenderTickCounter; import net.minecraft.client.render.WorldRenderer; +import net.minecraft.client.render.command.OrderedRenderCommandQueueImpl; import net.minecraft.client.util.ObjectAllocator; import net.minecraft.item.ItemStack; import org.joml.Matrix4f; diff --git a/src/main/java/com/lambda/mixin/render/ItemFrameEntityRendererMixin.java b/src/main/java/com/lambda/mixin/render/ItemFrameEntityRendererMixin.java index 70c5269a9..4039a037d 100644 --- a/src/main/java/com/lambda/mixin/render/ItemFrameEntityRendererMixin.java +++ b/src/main/java/com/lambda/mixin/render/ItemFrameEntityRendererMixin.java @@ -18,6 +18,8 @@ package com.lambda.mixin.render; import com.lambda.graphics.outline.OutlineCapturingQueue; +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; import net.minecraft.client.render.RenderLayer; import net.minecraft.client.render.command.OrderedRenderCommandQueue; import net.minecraft.client.render.entity.ItemFrameEntityRenderer; @@ -25,8 +27,6 @@ import net.minecraft.client.util.math.MatrixStack; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; -import com.llamalad7.mixinextras.injector.wrapoperation.Operation; -import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; @Mixin(ItemFrameEntityRenderer.class) public class ItemFrameEntityRendererMixin { diff --git a/src/main/java/com/lambda/mixin/render/PlayerListHudMixin.java b/src/main/java/com/lambda/mixin/render/PlayerListHudMixin.java index 31734c602..4da66895e 100644 --- a/src/main/java/com/lambda/mixin/render/PlayerListHudMixin.java +++ b/src/main/java/com/lambda/mixin/render/PlayerListHudMixin.java @@ -17,7 +17,7 @@ package com.lambda.mixin.render; -import com.lambda.friend.FriendManager; +import com.lambda.friend.FriendHandler; import com.lambda.module.modules.render.ExtraTab; import com.lambda.util.text.TextBuilder; import com.lambda.util.text.TextDslKt; @@ -26,7 +26,6 @@ import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.hud.PlayerListHud; import net.minecraft.client.network.PlayerListEntry; -import net.minecraft.scoreboard.Team; import net.minecraft.text.MutableText; import net.minecraft.text.Text; import net.minecraft.util.Nullables; @@ -49,10 +48,10 @@ public class PlayerListHudMixin { @Shadow @Final private static Comparator ENTRY_ORDERING; @Unique private static final Comparator FRIENDS_FIRST_ENTRY_ORDERING = Comparator - .comparingInt((PlayerListEntry entry) -> FriendManager.INSTANCE.isFriend(entry.getProfile().name()) ? 0 : 1) + .comparingInt((PlayerListEntry entry) -> FriendHandler.INSTANCE.isFriend(entry.getProfile().name()) ? 0 : 1) .thenComparingInt(entry -> -entry.getListOrder()) .thenComparingInt((entry) -> entry.getGameMode() == GameMode.SPECTATOR ? 1 : 0) - .thenComparing((entry) -> Nullables.mapOrElse(entry.getScoreboardTeam(), Team::getName, "")) + .thenComparing((entry) -> Nullables.mapOrElse(entry.getScoreboardTeam(), team -> team != null ? team.getName() : "", "")) .thenComparing((entry) -> entry.getProfile().name(), String::compareToIgnoreCase); @Shadow @Final private MinecraftClient client; @@ -65,7 +64,7 @@ private void onCollectPlayerEntriesHead(CallbackInfoReturnable !ExtraTab.getFriendsOnly() || FriendManager.INSTANCE.isFriend(entry.getProfile())) + .filter(entry -> !ExtraTab.getFriendsOnly() || FriendHandler.INSTANCE.isFriend(entry.getProfile())) .sorted(ExtraTab.getSortFriendsFirst() ? FRIENDS_FIRST_ENTRY_ORDERING : ENTRY_ORDERING) .limit(ExtraTab.getTabEntries()) .toList() @@ -87,7 +86,7 @@ private int modifyRowLimit(int original) { private @Nullable MutableText modifyName(Text original) { if (ExtraTab.INSTANCE.isDisabled() || !ExtraTab.getHighlightFriends() || - !FriendManager.INSTANCE.isFriend(original.getString())) return original.copy(); + !FriendHandler.INSTANCE.isFriend(original.getString())) return original.copy(); var newText = original.copy(); var textBuilder = new TextBuilder(); TextDslKt.color(textBuilder, ExtraTab.getFriendColor(), builder -> { diff --git a/src/main/java/com/lambda/mixin/render/WorldRendererMixin.java b/src/main/java/com/lambda/mixin/render/WorldRendererMixin.java index f614aec49..95a66dc3f 100644 --- a/src/main/java/com/lambda/mixin/render/WorldRendererMixin.java +++ b/src/main/java/com/lambda/mixin/render/WorldRendererMixin.java @@ -21,42 +21,42 @@ import com.lambda.event.EventFlow; import com.lambda.event.events.RenderEvent; import com.lambda.graphics.RenderMain; -import com.lambda.graphics.outline.OutlineManager; -import com.lambda.module.modules.render.Freecam; +import com.lambda.graphics.outline.OutlineHandler; import com.lambda.module.modules.render.CameraTweaks; +import com.lambda.module.modules.render.Freecam; import com.lambda.module.modules.render.NoRender; -import net.minecraft.client.world.ClientWorld; import com.llamalad7.mixinextras.injector.ModifyExpressionValue; import com.llamalad7.mixinextras.injector.ModifyReturnValue; -import net.minecraft.client.render.*; +import com.llamalad7.mixinextras.sugar.Local; +import com.mojang.blaze3d.buffers.GpuBufferSlice; +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.client.render.Camera; +import net.minecraft.client.render.Frustum; +import net.minecraft.client.render.RenderTickCounter; +import net.minecraft.client.render.WorldRenderer; +import net.minecraft.client.render.block.entity.BlockEntityRenderManager; +import net.minecraft.client.render.block.entity.state.BlockEntityRenderState; import net.minecraft.client.render.state.WorldRenderState; import net.minecraft.client.util.ObjectAllocator; +import net.minecraft.client.world.ClientWorld; import net.minecraft.entity.Entity; import net.minecraft.entity.LivingEntity; import net.minecraft.entity.effect.StatusEffects; -import com.mojang.blaze3d.buffers.GpuBufferSlice; -import net.minecraft.util.math.Vec3d; -import net.minecraft.world.tick.TickManager; +import net.minecraft.util.math.BlockPos; import org.jetbrains.annotations.Nullable; import org.joml.Matrix4f; import org.joml.Vector4f; +import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Unique; 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.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -import org.spongepowered.asm.mixin.injection.callback.LocalCapture; -import net.minecraft.block.entity.BlockEntity; -import net.minecraft.client.render.block.entity.BlockEntityRenderManager; -import net.minecraft.client.render.block.entity.state.BlockEntityRenderState; -import net.minecraft.util.math.BlockPos; -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Shadow; -import java.util.Set; -import java.util.Iterator; +import java.util.Set; @Mixin(WorldRenderer.class) public abstract class WorldRendererMixin { @@ -93,16 +93,15 @@ private boolean renderSetupTerrainModifyArg(boolean spectator) { return Freecam.INSTANCE.isEnabled() || CameraTweaks.INSTANCE.isEnabled() || spectator; } - @Inject(method = "fillEntityRenderStates", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/entity/EntityRenderManager;shouldRender(Lnet/minecraft/entity/Entity;Lnet/minecraft/client/render/Frustum;DDD)Z", shift = At.Shift.BEFORE), locals = LocalCapture.CAPTURE_FAILHARD) - private void injectFillEntityRenderStates(Camera camera, Frustum frustum, RenderTickCounter tickCounter, - WorldRenderState renderStates, CallbackInfo ci, Vec3d vec3d, double d, double e, double f, - TickManager tickManager, boolean bl, Iterator var14, Entity entity) { + @SuppressWarnings("DiscouragedShift") + @Inject(method = "fillEntityRenderStates", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/entity/EntityRenderManager;shouldRender(Lnet/minecraft/entity/Entity;Lnet/minecraft/client/render/Frustum;DDD)Z", shift = At.Shift.BEFORE)) + private void injectFillEntityRenderStates(Camera camera, Frustum frustum, RenderTickCounter tickCounter, WorldRenderState renderStates, CallbackInfo ci, @Local Entity entity) { this.lambda$currentEntity = entity; } @ModifyExpressionValue(method = "fillEntityRenderStates", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/WorldRenderer;isRenderingReady(Lnet/minecraft/util/math/BlockPos;)Z")) private boolean lambda$bypassIsRenderingReady(boolean original) { - if (this.lambda$currentEntity != null && OutlineManager.shouldCapture(this.lambda$currentEntity.getId())) + if (this.lambda$currentEntity != null && OutlineHandler.shouldCapture(this.lambda$currentEntity.getId())) return true; return original; } @@ -122,10 +121,10 @@ boolean modHasBlindnessOrDarkness(boolean original) { @Inject(method = "fillBlockEntityRenderStates", at = @At("TAIL")) private void injectOutlineBlockEntities(Camera camera, float tickProgress, WorldRenderState renderStates, CallbackInfo ci) { - if (!OutlineManager.INSTANCE.hasBlockOutlines()) return; + if (!OutlineHandler.INSTANCE.hasBlockOutlines()) return; - Set xRayTargets = OutlineManager.INSTANCE.getXrayBlockStyles().keySet(); - Set depthTargets = OutlineManager.INSTANCE.getDepthTestedBlockStyles().keySet(); + Set xRayTargets = OutlineHandler.INSTANCE.getXrayBlockStyles().keySet(); + Set depthTargets = OutlineHandler.INSTANCE.getDepthTestedBlockStyles().keySet(); for (BlockPos target : Sets.union(xRayTargets, depthTargets)) { if (!this.world.getChunkManager().isChunkLoaded(target.getX() >> 4, target.getZ() >> 4)) continue; diff --git a/src/main/kotlin/com/lambda/Lambda.kt b/src/main/kotlin/com/lambda/Lambda.kt index 877199f90..1fc8bfbd0 100644 --- a/src/main/kotlin/com/lambda/Lambda.kt +++ b/src/main/kotlin/com/lambda/Lambda.kt @@ -17,89 +17,106 @@ package com.lambda -import com.google.gson.Gson -import com.google.gson.GsonBuilder -import com.lambda.config.serializer.BindCodec -import com.lambda.config.serializer.BlockCodec -import com.lambda.config.serializer.BlockPosCodec -import com.lambda.config.serializer.ColorSerializer -import com.lambda.config.serializer.GameProfileCodec -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.config.serializer.UUIDCodec -import com.lambda.config.settings.complex.Bind +import com.lambda.Lambda.mapper +import com.lambda.config.Deserializer +import com.lambda.config.FallbackDeserializer +import com.lambda.config.FallbackSerializer +import com.lambda.config.FallbackSerializers +import com.lambda.config.Serializer import com.lambda.core.Loader import com.lambda.event.events.ClientEvent import com.lambda.event.listener.UnsafeListener.Companion.listenOnceUnsafe import com.lambda.gui.components.ClickGuiLayout -import com.lambda.util.KeyCode +import com.lambda.util.ReflectionUtils.getInstances import com.lambda.util.WindowUtils.setLambdaWindowIcon -import com.mojang.authlib.GameProfile import net.fabricmc.api.ClientModInitializer import net.fabricmc.loader.api.FabricLoader -import net.minecraft.block.Block import net.minecraft.client.MinecraftClient -import net.minecraft.item.ArrowItem -import net.minecraft.item.BlockItem -import net.minecraft.item.Item -import net.minecraft.item.ItemStack -import net.minecraft.item.PotionItem -import net.minecraft.item.RangedWeaponItem -import net.minecraft.text.Text -import net.minecraft.util.math.BlockPos import org.apache.logging.log4j.LogManager import org.apache.logging.log4j.Logger -import java.awt.Color -import java.util.* - +import tools.jackson.core.util.DefaultIndenter +import tools.jackson.core.util.DefaultPrettyPrinter +import tools.jackson.core.util.Separators +import tools.jackson.databind.SerializationFeature +import tools.jackson.databind.module.SimpleModule +import tools.jackson.databind.type.TypeFactory +import tools.jackson.module.kotlin.KotlinFeature +import tools.jackson.module.kotlin.jsonMapper +import tools.jackson.module.kotlin.kotlinModule object Lambda : ClientModInitializer { - const val MOD_NAME = "Lambda" - const val MOD_ID = "lambda" - const val SYMBOL = "λ" - const val APP_ID = "1221289599427416127" - const val REPO_URL = "https://github.com/lambda-client/lambda" - val VERSION: String = FabricLoader.getInstance() - .getModContainer("lambda").orElseThrow() - .metadata.version.friendlyString + const val ModName = "Lambda" + const val ModId = "lambda" + const val Symbol = "λ" + const val AppId = "1221289599427416127" + const val RepoUrl = "https://github.com/lambda-client/lambda" + val Version: String = + FabricLoader.getInstance() + .getModContainer("lambda").orElseThrow() + .metadata.version.friendlyString + + val Log: Logger = LogManager.getLogger(Symbol) - val LOG: Logger = LogManager.getLogger(SYMBOL) + @JvmStatic + val mc: MinecraftClient by lazy { MinecraftClient.getInstance() } - @JvmStatic - val mc: MinecraftClient by lazy { MinecraftClient.getInstance() } + val isDebug = System.getProperty("lambda.dev") != null - val isDebug = System.getProperty("lambda.dev") != null + /** + * A Jackson [tools.jackson.databind.json.JsonMapper]. + * + * Jackson is used over Gson (unlike Minecraft) as it allows for updating existing objects + * rather than creating new instances when deserializing. + * + * We use the base [tools.jackson.module.kotlin.KotlinModule] with `SingletonSupport` disabled, as it overrides our serialization. + * We also use a simple module for our standard serializers and deserializers. + * Finally, we use a custom module that searches through the supertypes of the given object to find + * the closest related type with a registered serializer or deserializer, depending on the action. + */ + val mapper = jsonMapper { + defaultPrettyPrinter( + DefaultPrettyPrinter( + Separators.createDefaultInstance().withObjectNameValueSpacing(Separators.Spacing.AFTER) + ).apply { + val tabIndenter = DefaultIndenter("\t", DefaultIndenter.SYS_LF) + indentObjectsWith(tabIndenter) + indentArraysWith(tabIndenter) + } + ) + enable(SerializationFeature.INDENT_OUTPUT) + addModules( + object : SimpleModule() { + override fun setupModule(context: SetupContext) { + val fallbackSerializers = FallbackSerializers( + getInstances>().associateBy { it.type }, + getInstances>().associateBy { it.type } + ) + context.addSerializers(fallbackSerializers) + context.addDeserializers(fallbackSerializers) + super.setupModule(context) + } + }, + SimpleModule().apply { + getInstances>().forEach { it.register() } + getInstances>().forEach { it.register() } + }, + kotlinModule { disable(KotlinFeature.SingletonSupport) } + ) + } - val gson: Gson = GsonBuilder() - .setPrettyPrinting() - .registerTypeAdapter(UUID::class.java, UUIDCodec) - .registerTypeAdapter(KeyCode::class.java, KeyCodeCodec) - .registerTypeAdapter(Color::class.java, ColorSerializer) - .registerTypeAdapter(BlockPos::class.java, BlockPosCodec) - .registerTypeAdapter(Block::class.java, BlockCodec) - .registerTypeAdapter(GameProfile::class.java, GameProfileCodec) - .registerTypeAdapter(Optional::class.java, OptionalCodec) - .registerTypeAdapter(ItemStack::class.java, ItemStackCodec) - .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) - .registerTypeAdapter(PotionItem::class.java, ItemCodec) - .registerTypeAdapter(RangedWeaponItem::class.java, ItemCodec) - .registerTypeAdapter(Bind::class.java, BindCodec) - .create() + /** + * The configured [TypeFactory] produced by [mapper]. + */ + val typeFactory: TypeFactory = mapper.typeFactory - override fun onInitializeClient() {} // nop + override fun onInitializeClient() {} // nop - init { - // We want the opengl context to be created - listenOnceUnsafe({ Int.MAX_VALUE }) { - LOG.info("$MOD_NAME $VERSION initialized in ${Loader.initialize()} ms\n") - if (ClickGuiLayout.setLambdaWindowIcon) setLambdaWindowIcon() - true - } - } + init { + // We want the opengl context to be created + listenOnceUnsafe({ Int.MAX_VALUE }) { + Log.info("$ModName $Version initialized in ${Loader.initialize()} ms\n") + if (ClickGuiLayout.setLambdaWindowIcon) setLambdaWindowIcon() + true + } + } } diff --git a/src/main/kotlin/com/lambda/brigadier/CommandExecution.kt b/src/main/kotlin/com/lambda/brigadier/CommandExecution.kt index 18f9db656..b709f961c 100644 --- a/src/main/kotlin/com/lambda/brigadier/CommandExecution.kt +++ b/src/main/kotlin/com/lambda/brigadier/CommandExecution.kt @@ -17,7 +17,7 @@ package com.lambda.brigadier -import com.lambda.util.Communication +import com.lambda.util.CommunicationUtils import com.mojang.brigadier.Command import com.mojang.brigadier.builder.ArgumentBuilder import com.mojang.brigadier.context.CommandContext @@ -53,7 +53,7 @@ sealed class CommandResult { } fun failure(message: String): Failure { - return Failure(Communication.LogLevel.Error.text(message)) + return Failure(CommunicationUtils.LogLevel.Error.text(message)) } /** Creates a [CommandResult.Failure] with the given throwable [t]. */ diff --git a/src/main/kotlin/com/lambda/command/CommandManager.kt b/src/main/kotlin/com/lambda/command/CommandHandler.kt similarity index 86% rename from src/main/kotlin/com/lambda/command/CommandManager.kt rename to src/main/kotlin/com/lambda/command/CommandHandler.kt index 78abe4f90..cfede3547 100644 --- a/src/main/kotlin/com/lambda/command/CommandManager.kt +++ b/src/main/kotlin/com/lambda/command/CommandHandler.kt @@ -21,8 +21,8 @@ import com.lambda.brigadier.CommandException import com.lambda.command.CommandRegistry.prefix import com.lambda.context.SafeContext import com.lambda.threading.runSafe -import com.lambda.util.Communication -import com.lambda.util.Communication.logError +import com.lambda.util.CommunicationUtils +import com.lambda.util.CommunicationUtils.logError import com.lambda.util.text.ClickEvents.suggestCommand import com.lambda.util.text.buildText import com.lambda.util.text.clickEvent @@ -39,8 +39,8 @@ import kotlin.math.max import kotlin.math.min -object CommandManager { - private const val ERROR_PADDING = 10 +object CommandHandler { + private const val ErrorPadding = 10 val dispatcher by lazy { CommandDispatcher() } @@ -58,7 +58,7 @@ object CommandManager { } catch (syntax: CommandSyntaxException) { createFeedback(syntax, reader) } catch (e: CommandException) { - this@CommandManager.logError(e.info) + this@CommandHandler.logError(e.info) } } } @@ -89,7 +89,7 @@ object CommandManager { ) { val debugMessage = syntax.message ?: return - this@CommandManager.logError(debugMessage) + this@CommandHandler.logError(debugMessage) if (syntax.input == null || syntax.cursor < 0) { return } @@ -97,17 +97,17 @@ object CommandManager { player.sendMessage(buildText { clickEvent(suggestCommand("$prefix${reader.string}")) { color(Color.GRAY) { - if (position > ERROR_PADDING) { + if (position > ErrorPadding) { literal("...") } - literal(syntax.input.substring(max(0, (position - ERROR_PADDING)), position)) + literal(syntax.input.substring(max(0, (position - ErrorPadding)), position)) } if (position < syntax.input.length) { - styled(color = Communication.LogLevel.Error.logoColor, underlined = true) { + styled(color = CommunicationUtils.LogLevel.Error.logoColor, underlined = true) { literal(syntax.input.substring(position)) } } - styled(color = Communication.LogLevel.Error.logoColor, italic = true) { + styled(color = CommunicationUtils.LogLevel.Error.logoColor, italic = true) { translatable("command.context.here") } } diff --git a/src/main/kotlin/com/lambda/command/CommandRegistry.kt b/src/main/kotlin/com/lambda/command/CommandRegistry.kt index eefbd62a2..fbad9f4a1 100644 --- a/src/main/kotlin/com/lambda/command/CommandRegistry.kt +++ b/src/main/kotlin/com/lambda/command/CommandRegistry.kt @@ -17,19 +17,21 @@ package com.lambda.command -import com.lambda.command.CommandManager.dispatcher -import com.lambda.config.Configurable -import com.lambda.config.configurations.LambdaConfig +import com.lambda.command.CommandHandler.dispatcher +import com.lambda.config.Config +import com.lambda.config.categories.LambdaCategory import com.lambda.core.Loadable -import com.lambda.util.reflections.getInstances +import com.lambda.util.ReflectionUtils.getInstances import com.mojang.brigadier.tree.CommandNode /** * The [CommandRegistry] object is responsible for managing all [LambdaCommand] instances in the system. */ -object CommandRegistry : Configurable(LambdaConfig), Loadable { +object CommandRegistry : Config( + "command", + LambdaCategory +), Loadable { override val priority get() = -2 - override val name = "command" val prefix by setting("prefix", ';') val commands = getInstances().toMutableList() diff --git a/src/main/kotlin/com/lambda/command/LambdaCommand.kt b/src/main/kotlin/com/lambda/command/LambdaCommand.kt index 6e3e24b10..6410f8fcb 100644 --- a/src/main/kotlin/com/lambda/command/LambdaCommand.kt +++ b/src/main/kotlin/com/lambda/command/LambdaCommand.kt @@ -20,9 +20,9 @@ package com.lambda.command import com.lambda.brigadier.argument.literal import com.lambda.brigadier.execute import com.lambda.brigadier.required -import com.lambda.command.CommandManager.dispatcher +import com.lambda.command.CommandHandler.dispatcher import com.lambda.core.Loadable -import com.lambda.util.Communication.info +import com.lambda.util.CommunicationUtils.info import com.lambda.util.Nameable import com.lambda.util.extension.CommandBuilder import com.lambda.util.text.ClickEvents diff --git a/src/main/kotlin/com/lambda/command/commands/BuildCommand.kt b/src/main/kotlin/com/lambda/command/commands/BuildCommand.kt index 3da8b5c0e..c2db38610 100644 --- a/src/main/kotlin/com/lambda/command/commands/BuildCommand.kt +++ b/src/main/kotlin/com/lambda/command/commands/BuildCommand.kt @@ -25,7 +25,7 @@ import com.lambda.brigadier.argument.value import com.lambda.brigadier.executeWithResult import com.lambda.brigadier.required import com.lambda.command.LambdaCommand -import com.lambda.config.AutomationConfig +import com.lambda.config.automation.AutomationConfig import com.lambda.interaction.construction.StructureRegistry import com.lambda.interaction.construction.blueprint.Blueprint.Companion.toStructure import com.lambda.interaction.construction.blueprint.StaticBlueprint.Companion.toBlueprint @@ -33,7 +33,7 @@ import com.lambda.task.RootTask.run import com.lambda.task.tasks.BuildTask import com.lambda.task.tasks.BuildTask.Companion.build import com.lambda.threading.runSafe -import com.lambda.util.Communication.info +import com.lambda.util.CommunicationUtils.info import com.lambda.util.extension.CommandBuilder import com.lambda.util.extension.move import net.minecraft.command.CommandSource.suggestMatching @@ -62,7 +62,7 @@ object BuildCommand : LambdaCommand( .loadStructureByRelativePath(Path.of(pathString)) .let { template -> info("Building structure $pathString with dimensions ${template.size.toShortString()} created by ${template.author}") - lastBuildTask = with(AutomationConfig.Companion.DEFAULT) { + lastBuildTask = with(AutomationConfig.Companion.Default) { template.toStructure() .move(player.blockPos) .toBlueprint() diff --git a/src/main/kotlin/com/lambda/command/commands/CapeCommand.kt b/src/main/kotlin/com/lambda/command/commands/CapeCommand.kt index bf84956c0..654384223 100644 --- a/src/main/kotlin/com/lambda/command/commands/CapeCommand.kt +++ b/src/main/kotlin/com/lambda/command/commands/CapeCommand.kt @@ -23,13 +23,14 @@ import com.lambda.brigadier.argument.value import com.lambda.brigadier.execute import com.lambda.brigadier.required import com.lambda.command.LambdaCommand -import com.lambda.network.CapeManager.availableCapes -import com.lambda.network.CapeManager.updateCape -import com.lambda.util.Communication.info -import com.lambda.util.Communication.logError +import com.lambda.network.CapeHandler.availableCapes +import com.lambda.network.CapeHandler.updateCape +import com.lambda.util.CommunicationUtils.info +import com.lambda.util.CommunicationUtils.logError import com.lambda.util.extension.CommandBuilder import net.minecraft.command.CommandSource.suggestMatching +@Suppress("unused") object CapeCommand : LambdaCommand( name = "cape", usage = "set ", diff --git a/src/main/kotlin/com/lambda/command/commands/ConfigCommand.kt b/src/main/kotlin/com/lambda/command/commands/ConfigCommand.kt index 306289c48..bfed0d23c 100644 --- a/src/main/kotlin/com/lambda/command/commands/ConfigCommand.kt +++ b/src/main/kotlin/com/lambda/command/commands/ConfigCommand.kt @@ -19,78 +19,93 @@ package com.lambda.command.commands import com.lambda.brigadier.CommandResult.Companion.failure import com.lambda.brigadier.CommandResult.Companion.success +import com.lambda.brigadier.argument.greedyString import com.lambda.brigadier.argument.literal import com.lambda.brigadier.argument.string import com.lambda.brigadier.argument.value import com.lambda.brigadier.executeWithResult import com.lambda.brigadier.required import com.lambda.command.LambdaCommand -import com.lambda.config.Configuration -import com.lambda.util.Communication.info +import com.lambda.config.ConfigLoader +import com.lambda.config.SettingLayer +import com.lambda.util.CommunicationUtils.info import com.lambda.util.extension.CommandBuilder import net.minecraft.command.CommandSource.suggestMatching +//ToDo: Make this command add and remove paths when configs are created or removed. +// Brigadier doesn't allow for removing paths by default, so that's something we might have to look into creating our own small system for. object ConfigCommand : LambdaCommand( name = "config", aliases = setOf("cfg", "settings", "setting"), - usage = "config ", - description = "Save or load configuration files, or set any settings value", + usage = "config [value]", + description = "Save or load configuration files, or set/reset any settings value", examples = listOf("config save", "config load", "config set HighwayTools Pavement_Material minecraft:obsidian") ) { override fun CommandBuilder.create() { required(literal("save")) { executeWithResult { - Configuration.configurations.forEach { config -> - config.trySave(true) + ConfigLoader.configCategories.forEach { config -> + config.trySaveToFile(true) } - this@ConfigCommand.info("Saved ${Configuration.configurations.size} configuration files.") + this@ConfigCommand.info("Saved ${ConfigLoader.configCategories.size} config files.") return@executeWithResult success() } } required(literal("load")) { executeWithResult { - Configuration.configurations.forEach { config -> - config.tryLoad() + ConfigLoader.configCategories.forEach { config -> + config.tryLoadFromFile() } - this@ConfigCommand.info("Loaded ${Configuration.configurations.size} configuration files.") + this@ConfigCommand.info("Loaded ${ConfigLoader.configCategories.size} config files.") return@executeWithResult success() } } required(literal("reset")) { - required(string("config")) { config -> + required(string("config")) { configArg -> suggests { _, builder -> - suggestMatching(Configuration.configurables.map { it.commandName }, builder) + suggestMatching(ConfigLoader.configs.map { it.commandName }, builder) } - required(string("setting")) { setting -> - suggests { ctx, builder -> - val conf = config(ctx).value() - Configuration.configurableByName(conf)?.let { configurable -> - suggestMatching(configurable.settings.map { it.commandName }, builder) - } ?: builder.buildFuture() + required(greedyString("setting")) { settingArg -> + suggests { context, builder -> + val config = ConfigLoader.configByCommandName(configArg(context).value()) ?: return@suggests null + val suggestions = mutableListOf() + config.forEachSetting { path, single -> + val settingLit = + if (path.isEmpty()) single.setting.name + else "${path.joinToString("->") { it.commandName }}->${single.setting.commandName}" + suggestions.add(settingLit) + } + suggestMatching(suggestions, builder) } executeWithResult { - val confName = config().value() - val settingName = setting().value() - val configurable = Configuration.configurableByCommandName(confName) ?: run { - return@executeWithResult failure("$confName is not a valid configurable.") - } - val setting = Configuration.settingByCommandName(configurable, settingName) ?: run { - return@executeWithResult failure("$settingName is not a valid setting for $confName.") + val config = ConfigLoader.configByCommandName(configArg().value()) ?: return@executeWithResult failure("Config not found.") + var currentMultiple: SettingLayer.Multiple = config.settingLayers + val fullSettingPath = settingArg().value().split("->") + fullSettingPath.dropLast(1).forEach { path -> + currentMultiple = currentMultiple.layers + .asSequence() + .filterIsInstance() + .find { it.name == path } ?: return@executeWithResult failure("Setting not found.") } - setting.reset() - return@executeWithResult success() + val settingLayer = currentMultiple.layers + .asSequence() + .filterIsInstance>() + .find { it.setting.commandName == fullSettingPath.last() } ?: return@executeWithResult failure("Setting not found.") + settingLayer.setting.reset() + success() } } } } required(literal("set")) { - Configuration.configurables.forEach { configurable -> - required(literal(configurable.commandName)) { - configurable.settings.forEach { setting -> - required(literal(setting.commandName)) { - with(setting) { - buildCommand(registry) - } + ConfigLoader.configs.forEach { config -> + required(literal(config.commandName)) { + config.forEachSetting { path, single -> + val settingLit = + if (path.isEmpty()) single.setting.commandName + else "${path.joinToString("->") { it.commandName }}->${single.setting.commandName}" + required(literal(settingLit)) { + with(single.setting) { buildCommand(registry) } } } } diff --git a/src/main/kotlin/com/lambda/command/commands/FriendCommand.kt b/src/main/kotlin/com/lambda/command/commands/FriendCommand.kt index e187327a5..38cf16a4c 100644 --- a/src/main/kotlin/com/lambda/command/commands/FriendCommand.kt +++ b/src/main/kotlin/com/lambda/command/commands/FriendCommand.kt @@ -28,11 +28,11 @@ import com.lambda.brigadier.execute import com.lambda.brigadier.executeWithResult import com.lambda.brigadier.required import com.lambda.command.LambdaCommand -import com.lambda.config.configurations.FriendConfig -import com.lambda.friend.FriendManager +import com.lambda.config.categories.FriendCategory +import com.lambda.friend.FriendHandler import com.lambda.network.mojang.getProfile import com.lambda.threading.runIO -import com.lambda.util.Communication.info +import com.lambda.util.CommunicationUtils.info import com.lambda.util.extension.CommandBuilder import com.lambda.util.text.ClickEvents import com.lambda.util.text.buildText @@ -41,8 +41,9 @@ import com.lambda.util.text.styled import kotlinx.coroutines.runBlocking import net.minecraft.command.CommandSource.suggestMatching import java.awt.Color -import java.util.UUID +import java.util.* +@Suppress("unused") object FriendCommand : LambdaCommand( name = "friends", usage = "friends | add-uuid | remove | remove-uuid >", @@ -53,13 +54,13 @@ object FriendCommand : LambdaCommand( runIO { info( buildText { - if (FriendManager.friends.isEmpty()) { + if (FriendHandler.friends.isEmpty()) { literal("You have no friends yet. Go make some! :3\n") } else { - literal("Your friends (${FriendManager.friends.size}):\n") + literal("Your friends (${FriendHandler.friends.size}):\n") - FriendManager.friends.forEachIndexed { index, uuid -> - val profile = FriendManager.latestGameProfile(uuid) + FriendHandler.friends.forEachIndexed { index, uuid -> + val profile = FriendHandler.latestGameProfile(uuid) val displayName = profile?.name ?: uuid.toString() literal(" ${index + 1}. $displayName ") @@ -76,7 +77,7 @@ object FriendCommand : LambdaCommand( styled( color = Color.CYAN, underlined = true, - clickEvent = ClickEvents.openFile(FriendConfig.primary.path), + clickEvent = ClickEvents.openFile(FriendCategory.primaryFile.path), ) { literal("Click to open your friends list as a file") } @@ -100,15 +101,15 @@ object FriendCommand : LambdaCommand( val name = player().value() runBlocking { - val profile = FriendManager.latestGameProfile(name) + val profile = FriendHandler.latestGameProfile(name) ?: return@runBlocking failure("Could not find the player") - if (FriendManager.isFriend(profile.id)) + if (FriendHandler.isFriend(profile.id)) return@runBlocking failure("This player is already in your friend list") - FriendManager.befriend(profile) + FriendHandler.befriend(profile) - info(FriendManager.befriendedText(profile.name)) + info(FriendHandler.befriendedText(profile.name)) success() } } @@ -129,18 +130,18 @@ object FriendCommand : LambdaCommand( executeWithResult { val uuid = player().value() - if (FriendManager.isFriend(uuid)) + if (FriendHandler.isFriend(uuid)) return@executeWithResult failure("This player is already in your friend list") runBlocking { - val profile = FriendManager.latestGameProfile(uuid) + val profile = FriendHandler.latestGameProfile(uuid) if (profile != null) { - FriendManager.befriend(profile) - info(FriendManager.befriendedText(profile.name)) + FriendHandler.befriend(profile) + info(FriendHandler.befriendedText(profile.name)) } else { - FriendManager.befriend(uuid) - info(FriendManager.befriendedText(uuid.toString())) + FriendHandler.befriend(uuid) + info(FriendHandler.befriendedText(uuid.toString())) } success() @@ -152,7 +153,7 @@ object FriendCommand : LambdaCommand( required(literal("remove")) { required(string("player name")) { player -> suggests { _, builder -> - val playerNames = FriendManager.friends.map { FriendManager.friendDisplayName(it) } + val playerNames = FriendHandler.friends.map { FriendHandler.friendDisplayName(it) } suggestMatching(playerNames, builder) } @@ -160,17 +161,17 @@ object FriendCommand : LambdaCommand( val name = player().value() runBlocking { - val uuid = FriendManager.gameProfile(name)?.id + val uuid = FriendHandler.gameProfile(name)?.id ?: getProfile(name).getOrNull()?.id ?: runCatching { UUID.fromString(name) }.getOrNull() ?: return@runBlocking failure("Could not resolve the player name") - if (!FriendManager.isFriend(uuid)) + if (!FriendHandler.isFriend(uuid)) return@runBlocking failure("This player is not in your friend list") - FriendManager.unfriend(uuid) + FriendHandler.unfriend(uuid) - info(FriendManager.unfriendedText(name)) + info(FriendHandler.unfriendedText(name)) success() } } @@ -191,13 +192,13 @@ object FriendCommand : LambdaCommand( executeWithResult { val uuid = player().value() - if (!FriendManager.isFriend(uuid)) + if (!FriendHandler.isFriend(uuid)) return@executeWithResult failure("This player is not in your friend list") - val displayName = FriendManager.friendDisplayName(uuid) - FriendManager.unfriend(uuid) + val displayName = FriendHandler.friendDisplayName(uuid) + FriendHandler.unfriend(uuid) - info(FriendManager.unfriendedText(displayName)) + info(FriendHandler.unfriendedText(displayName)) success() } } diff --git a/src/main/kotlin/com/lambda/command/commands/ModuleCommand.kt b/src/main/kotlin/com/lambda/command/commands/ModuleCommand.kt index 7ede06976..d4f21fd25 100644 --- a/src/main/kotlin/com/lambda/command/commands/ModuleCommand.kt +++ b/src/main/kotlin/com/lambda/command/commands/ModuleCommand.kt @@ -29,9 +29,9 @@ import com.lambda.command.CommandRegistry.prefix import com.lambda.command.LambdaCommand import com.lambda.module.ModuleRegistry import com.lambda.threading.runSafe -import com.lambda.util.Communication.info -import com.lambda.util.Communication.joinToText -import com.lambda.util.Communication.warn +import com.lambda.util.CommunicationUtils.info +import com.lambda.util.CommunicationUtils.joinToText +import com.lambda.util.CommunicationUtils.warn import com.lambda.util.StringUtils.findSimilarStrings import com.lambda.util.extension.CommandBuilder import com.lambda.util.text.ClickEvents.suggestCommand @@ -125,11 +125,8 @@ object ModuleCommand : LambdaCommand( return@runSafe success() } - if (enable().value()) { - module.enable() - } else { - module.disable() - } + if (enable().value()) module.enable() + else module.disable() } this@ModuleCommand.info(buildText { styled(Color.GRAY) { diff --git a/src/main/kotlin/com/lambda/command/commands/PrefixCommand.kt b/src/main/kotlin/com/lambda/command/commands/PrefixCommand.kt index 10db0f55d..7726501a3 100644 --- a/src/main/kotlin/com/lambda/command/commands/PrefixCommand.kt +++ b/src/main/kotlin/com/lambda/command/commands/PrefixCommand.kt @@ -20,21 +20,19 @@ package com.lambda.command.commands import com.lambda.brigadier.CommandResult.Companion.failure import com.lambda.brigadier.CommandResult.Companion.success import com.lambda.brigadier.argument.greedyString -import com.lambda.brigadier.argument.string import com.lambda.brigadier.argument.value import com.lambda.brigadier.execute import com.lambda.brigadier.executeWithResult import com.lambda.brigadier.required import com.lambda.command.CommandRegistry import com.lambda.command.LambdaCommand -import com.lambda.config.Configuration -import com.lambda.config.Setting -import com.lambda.config.SettingCore -import com.lambda.util.Communication.info +import com.lambda.config.settings.CharSetting +import com.lambda.util.CommunicationUtils.info import com.lambda.util.extension.CommandBuilder import com.lambda.util.text.buildText import com.lambda.util.text.literal +@Suppress("unused") object PrefixCommand : LambdaCommand( "prefix", usage = "prefix ", @@ -42,21 +40,18 @@ object PrefixCommand : LambdaCommand( ) { // i have no idea why someone would want to use some of these as a prefix // but ig the people who run 20 clients at once could benefit from this - val ptrn = Regex("^[!\"#$%&'()*+,\\-./:;<=>?@\\[\\\\\\]^_`{|}~]$") + val pattern = Regex("^[!\"#$%&'()*+,\\-./:;<=>?@\\[\\\\\\]^_`{|}~]$") override fun CommandBuilder.create() { required(greedyString("prefix")) { prefixStr -> executeWithResult { val prefix = prefixStr().value() - if (!ptrn.matches(prefix)) { + if (!pattern.matches(prefix)) { return@executeWithResult failure("Prefix must be a single non-alphanumeric ASCII character, excluding spaces.") } val prefixChar = prefix.first() - val configurable = Configuration.configurableByName("command") ?: return@executeWithResult failure("No command configurable found.") - @Suppress("UNCHECKED_CAST") - val setting = configurable.settings.find { it.name == "prefix" } as? Setting, Char> - ?: return@executeWithResult failure("Prefix setting is not a Char or can not be found.") - setting.trySetValue(prefixChar) + @Suppress("unchecked_cast") + (CommandRegistry::prefix.getDelegate() as? CharSetting)?.trySetValue(prefixChar) return@executeWithResult success() } } diff --git a/src/main/kotlin/com/lambda/command/commands/ReplayCommand.kt b/src/main/kotlin/com/lambda/command/commands/ReplayCommand.kt index 3d3685dc4..becf8dfd0 100644 --- a/src/main/kotlin/com/lambda/command/commands/ReplayCommand.kt +++ b/src/main/kotlin/com/lambda/command/commands/ReplayCommand.kt @@ -28,11 +28,12 @@ import com.lambda.brigadier.required import com.lambda.command.LambdaCommand import com.lambda.module.modules.player.Replay import com.lambda.util.FileUtils.listRecursive -import com.lambda.util.FolderRegister +import com.lambda.util.FolderRegistry import com.lambda.util.extension.CommandBuilder import net.minecraft.command.CommandSource.suggestMatching import kotlin.io.path.exists +@Suppress("unused") object ReplayCommand : LambdaCommand( name = "replay", usage = "replay ", @@ -50,7 +51,7 @@ object ReplayCommand : LambdaCommand( required(literal("load")) { required(greedyString("replay filepath")) { replayName -> suggests { _, builder -> - val dir = FolderRegister.replay.toFile() + val dir = FolderRegistry.replay.toFile() val paths = dir .listRecursive { it.isFile } .map { it.relativeTo(dir).path } @@ -59,7 +60,7 @@ object ReplayCommand : LambdaCommand( } executeWithResult { - val replayFile = FolderRegister.replay.resolve(replayName().value()) + val replayFile = FolderRegistry.replay.resolve(replayName().value()) if (!replayFile.exists()) { return@executeWithResult CommandResult.failure("Replay file does not exist") diff --git a/src/main/kotlin/com/lambda/command/commands/TaskCommand.kt b/src/main/kotlin/com/lambda/command/commands/TaskCommand.kt index 026eae3fc..75f1fc42b 100644 --- a/src/main/kotlin/com/lambda/command/commands/TaskCommand.kt +++ b/src/main/kotlin/com/lambda/command/commands/TaskCommand.kt @@ -22,7 +22,7 @@ import com.lambda.brigadier.execute import com.lambda.brigadier.required import com.lambda.command.LambdaCommand import com.lambda.task.RootTask -import com.lambda.util.Communication.info +import com.lambda.util.CommunicationUtils.info import com.lambda.util.extension.CommandBuilder object TaskCommand : LambdaCommand( diff --git a/src/main/kotlin/com/lambda/command/commands/TransferCommand.kt b/src/main/kotlin/com/lambda/command/commands/TransferCommand.kt index 8c11ab082..37a6c46ed 100644 --- a/src/main/kotlin/com/lambda/command/commands/TransferCommand.kt +++ b/src/main/kotlin/com/lambda/command/commands/TransferCommand.kt @@ -27,15 +27,15 @@ import com.lambda.brigadier.argument.value import com.lambda.brigadier.executeWithResult import com.lambda.brigadier.required import com.lambda.command.LambdaCommand -import com.lambda.config.AutomationConfig +import com.lambda.config.automation.AutomationConfig import com.lambda.interaction.material.StackSelection.Companion.selectStack -import com.lambda.interaction.material.container.ContainerManager -import com.lambda.interaction.material.container.ContainerManager.findContainersWithMaterial -import com.lambda.interaction.material.container.ContainerManager.findContainersWithSpace +import com.lambda.interaction.material.container.ContainerHandler +import com.lambda.interaction.material.container.ContainerHandler.findContainersWithMaterial +import com.lambda.interaction.material.container.ContainerHandler.findContainersWithSpace import com.lambda.task.RootTask import com.lambda.task.Task import com.lambda.threading.runSafeAutomated -import com.lambda.util.Communication.info +import com.lambda.util.CommunicationUtils.info import com.lambda.util.extension.CommandBuilder import net.minecraft.command.CommandSource.suggestMatching @@ -54,7 +54,7 @@ object TransferCommand : LambdaCommand( val selection = selectStack(amount(ctx).value()) { isItem(stack(ctx).value().item) } - AutomationConfig.Companion.DEFAULT.runSafeAutomated { + AutomationConfig.Default.runSafeAutomated { val containers = selection.findContainersWithMaterial() val indexedContainers = containers.withIndex() @@ -75,7 +75,7 @@ object TransferCommand : LambdaCommand( val selection = selectStack(amount(ctx).value()) { isItem(stack(ctx).value().item) } - AutomationConfig.Companion.DEFAULT.runSafeAutomated { + AutomationConfig.Default.runSafeAutomated { val containers = selection.findContainersWithSpace() val indexedContainers = containers.withIndex() @@ -95,12 +95,12 @@ object TransferCommand : LambdaCommand( val selection = selectStack(amount().value()) { isItem(stack().value().item) } - AutomationConfig.Companion.DEFAULT.runSafeAutomated { - val fromContainer = ContainerManager.containers().find { + AutomationConfig.Default.runSafeAutomated { + val fromContainer = ContainerHandler.containers().find { it.name == from().value().split(".").last().trim() } ?: return@executeWithResult failure("From container not found") - val toContainer = ContainerManager.containers().find { + val toContainer = ContainerHandler.containers().find { it.name == to().value().split(".").last().trim() } ?: return@executeWithResult failure("To container not found") diff --git a/src/main/kotlin/com/lambda/config/AutomationConfig.kt b/src/main/kotlin/com/lambda/config/AutomationConfig.kt deleted file mode 100644 index 68b721e2d..000000000 --- a/src/main/kotlin/com/lambda/config/AutomationConfig.kt +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright 2026 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 - -import com.lambda.config.configurations.AutomationConfigs -import com.lambda.config.groups.BreakSettings -import com.lambda.config.groups.BuildSettings -import com.lambda.config.groups.EatSettings -import com.lambda.config.groups.HotbarSettings -import com.lambda.config.groups.InteractSettings -import com.lambda.config.groups.InventorySettings -import com.lambda.config.groups.RotationSettings -import com.lambda.context.Automated -import com.lambda.module.Module -import com.lambda.util.NamedEnum - - -open class AutomationConfig( - override val name: String, - configuration: Configuration = AutomationConfigs -) : Configurable(configuration), Automated { - enum class Group(override val displayName: String) : NamedEnum { - Build("Build"), - Break("Break"), - Interact("Interact"), - Rotation("Rotation"), - Inventory("Inventory"), - Hotbar("Hotbar"), - Eat("Eat"), - Render("Render"), - Debug("Debug") - } - - override val buildConfig = BuildSettings(this, Group.Build) - override val breakConfig = BreakSettings(this, Group.Break) - override val interactConfig = InteractSettings(this, Group.Interact) - override val rotationConfig = RotationSettings(this, Group.Rotation) - override val inventoryConfig = InventorySettings(this, Group.Inventory) - override val hotbarConfig = HotbarSettings(this, Group.Hotbar) - override val eatConfig = EatSettings(this, Group.Eat) - - companion object { - context(module: Module) - fun IMutableAutomationConfig.setDefaultAutomationConfig( - name: String = module.name, - edits: (AutomationConfig.() -> Unit)? = null - ) { - this.defaultAutomationConfig = AutomationConfig("$name Automation Config").apply { edits?.invoke(this) } - } - - fun IMutableAutomationConfig.setDefaultAutomationConfig( - name: String, - edits: (AutomationConfig.() -> Unit)? = null - ) { - defaultAutomationConfig = AutomationConfig("$name Automation Config").apply { edits?.invoke(this) } - } - - object DEFAULT : AutomationConfig("Default") - } -} \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/config/Config.kt b/src/main/kotlin/com/lambda/config/Config.kt new file mode 100644 index 000000000..3c3221961 --- /dev/null +++ b/src/main/kotlin/com/lambda/config/Config.kt @@ -0,0 +1,600 @@ +/* + * Copyright 2026 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 + +import com.lambda.Lambda.typeFactory +import com.lambda.config.ConfigLoader.configs +import com.lambda.config.settings.CharSetting +import com.lambda.config.settings.FunctionSetting +import com.lambda.config.settings.StringSetting +import com.lambda.config.settings.collections.BlockCollectionSetting +import com.lambda.config.settings.collections.ClassCollectionSetting +import com.lambda.config.settings.collections.CollectionSetting +import com.lambda.config.settings.collections.ItemCollectionSetting +import com.lambda.config.settings.collections.MapSetting +import com.lambda.config.settings.comparable.BooleanSetting +import com.lambda.config.settings.comparable.EnumSetting +import com.lambda.config.settings.complex.Bind +import com.lambda.config.settings.complex.BlockPosSetting +import com.lambda.config.settings.complex.BlockSetting +import com.lambda.config.settings.complex.ColorSetting +import com.lambda.config.settings.complex.KeybindSetting +import com.lambda.config.settings.complex.Vec3dSetting +import com.lambda.config.settings.numeric.DoubleSetting +import com.lambda.config.settings.numeric.FloatSetting +import com.lambda.config.settings.numeric.IntegerSetting +import com.lambda.config.settings.numeric.LongSetting +import com.lambda.event.Muteable +import com.lambda.imgui.flag.ImGuiInputTextFlags +import com.lambda.util.KeyCode +import com.lambda.util.Nameable +import net.minecraft.block.Block +import net.minecraft.item.Item +import net.minecraft.registry.Registries +import net.minecraft.util.math.BlockPos +import net.minecraft.util.math.Vec3d +import java.awt.Color +import kotlin.collections.plus +import kotlin.reflect.KClass +import kotlin.reflect.KProperty +import kotlin.reflect.full.declaredMemberProperties +import kotlin.reflect.jvm.javaField + +/** + * Represents a set of [SettingCore]s that are associated with the [name] of the [Config]. + * The settings are managed by this [Config] and are saved and loaded as part of the [ConfigCategory]. + * + * This class also provides a series of helper methods ([setting]) for creating different types of settings. + * + * @property settingLayers A set of [SettingCore]s that this config manages. + */ +abstract class Config( + final override val name: String, + configCategory: ConfigCategory +) : Nameable { + internal val settingLayers = SettingLayer.Root() + internal val settingBlockLayers = ConfigBlockLayer.Root() + internal val propertyLayers = PropertyLayer.Root() + private val registrationQueue = ArrayDeque() + + init { + if (configs.any { it.name == name }) throw IllegalStateException("Configs with name $name already exists.") + enqueueConfigEntries(this::class, emptyList(), emptyList()) + configCategory.configs.add(this) + } + + private fun enqueueConfigEntries(klass: KClass<*>, outerPath: List, outerBlockPath: List) { + var childBlockIndex = 0 + forEachConfigEntry( + klass, + onSetting = { enqueuePrimitiveConfigEntry(it, outerPath, outerBlockPath, it.name) }, + onSettingBlock = { settingBlock, blockClass -> + val fullBlockPath = outerBlockPath + childBlockIndex + enqueueConfigEntries( + blockClass, + outerPath + buildPathFromAnnotations(settingBlock), + fullBlockPath + ) + registrationQueue.addLast( + LayerSpecInfo( + emptyList(), + fullBlockPath, + settingBlock.name + ) + ) + childBlockIndex++ + }, + onProperty = { enqueuePrimitiveConfigEntry(it, outerPath, outerBlockPath, it.name) } + ) + } + + private fun enqueuePrimitiveConfigEntry( + property: KProperty<*>, + outerPath: List, + outerBlockPath: List, + propertyName: String + ) { + registrationQueue.addLast( + LayerSpecInfo( + outerPath + buildPathFromAnnotations(property), + outerBlockPath, + propertyName + ) + ) + } + + private fun forEachConfigEntry( + klass: KClass<*>, + onSetting: (property: KProperty<*>) -> Unit, + onSettingBlock: (property: KProperty<*>, blockClass: KClass<*>) -> Unit, + onProperty: (property: KProperty<*>) -> Unit + ) { + val hierarchy = buildList { + var current: KClass<*>? = klass + while (current != null && current != Config::class && current != Any::class) { + add(current) + current = current.supertypes + .mapNotNull { it.classifier as? KClass<*> } + .firstOrNull { !it.java.isInterface } + } + }.reversed() + + hierarchy.forEach { level -> + val fieldOrder = level.java.declaredFields + .withIndex() + .associate { (index, field) -> field.name to index } + + level.declaredMemberProperties + .sortedBy { + val javaField = it.javaField ?: return@sortedBy Int.MAX_VALUE + fieldOrder[javaField.name] ?: Int.MAX_VALUE + } + .forEach { property -> + val fieldType = property.javaField?.type ?: return@forEach + when { + Setting::class.java.isAssignableFrom(fieldType) -> onSetting(property) + ConfigBlockWrapper::class.java.isAssignableFrom(fieldType) -> { + val blockClass = property.returnType.classifier as? KClass<*> + if (blockClass != null) onSettingBlock(property, blockClass) + } + Property::class.java.isAssignableFrom(fieldType) -> onProperty(property) + } + } + } + } + + private fun buildPathFromAnnotations(property: KProperty<*>): List { + val path = mutableListOf() + property.annotations.forEach { annotation -> + when (annotation) { + is Tab -> annotation.tabs.forEach { path.add(SettingLayerSpec(MultipleLayerType.Tab, it)) } + is Group -> annotation.groups.forEach { path.add(SettingLayerSpec(MultipleLayerType.Group, it)) } + } + } + return path + } + + fun reset() { + forEachSettingBlock(settingBlockLayers) { _, single -> + single.setting.reset() + } + } + + @ConfigEntryD5l + fun setting( + name: String, + defaultValue: Boolean, + description: String = "", + visibility: () -> Boolean = { true } + ) = setting(name) { layer -> BooleanSetting(name, description, this, layer, visibility, defaultValue) } + + @ConfigEntryD5l + fun > setting( + name: String, + defaultValue: T, + description: String = "", + visibility: () -> Boolean = { true } + ) = setting(name) { layer -> EnumSetting(name, description, this, layer, visibility, defaultValue) } + + @ConfigEntryD5l + fun setting( + name: String, + defaultValue: Char, + description: String = "", + visibility: () -> Boolean = { true } + ) = setting(name) { layer -> CharSetting(name, description, this, layer, defaultValue, visibility) } + + @ConfigEntryD5l + fun setting( + name: String, + defaultValue: String, + multiline: Boolean = false, + flags: Int = ImGuiInputTextFlags.None, + description: String = "", + visibility: () -> Boolean = { true } + ) = setting(name) { layer -> StringSetting(name, description, this, layer, defaultValue, visibility, multiline, flags) } + + @ConfigEntryD5l + @JvmName("collectionSetting1") + fun setting( + name: String, + defaultValue: Collection, + immutableCollection: Collection = Registries.BLOCK.toList(), + description: String = "", + visibility: () -> Boolean = { true } + ) = setting(name) { layer -> BlockCollectionSetting(name, description, this, layer, visibility, immutableCollection, defaultValue.toMutableList()) } + + @ConfigEntryD5l + @JvmName("collectionSetting2") + fun setting( + name: String, + defaultValue: Collection, + immutableCollection: Collection = Registries.ITEM.toList(), + description: String = "", + visibility: () -> Boolean = { true } + ) = setting(name) { layer -> ItemCollectionSetting(name, description, this, layer, visibility, immutableCollection, defaultValue.toMutableList()) } + + @ConfigEntryD5l + @JvmName("collectionSetting3") + inline fun setting( + name: String, + defaultValue: Collection, + immutableList: Collection = defaultValue, + description: String = "", + displayClassName: Boolean = false, + serialize: Boolean = false, + noinline visibility: () -> Boolean = { true } + ) = setting(name) { layer -> + if (displayClassName) ClassCollectionSetting(name, description, this, layer, visibility, immutableList, defaultValue.toMutableList()) + else CollectionSetting(name, description, this, layer, visibility, defaultValue.toMutableList(), immutableList, typeFactory.constructCollectionType(Collection::class.java, T::class.java), serialize) + } + + @ConfigEntryD5l + inline fun setting( + name: String, + defaultValue: Map, + description: String = "", + noinline visibility: () -> Boolean = { true } + ) = setting(name) { layer -> + MapSetting( + name, description, this, layer, visibility, defaultValue.toMutableMap(), + typeFactory.constructMapType(MutableMap::class.java, K::class.java, V::class.java) + ) + } + + @ConfigEntryD5l + fun setting( + name: String, + defaultValue: Double, + range: ClosedRange, + step: Double = 1.0, + description: String = "", + unit: String = "", + visibility: () -> Boolean = { true } + ) = setting(name) { layer -> DoubleSetting(name, description, this, layer, visibility, defaultValue, range, step, unit) } + + @ConfigEntryD5l + fun setting( + name: String, + defaultValue: Float, + range: ClosedRange, + step: Float = 1f, + description: String = "", + unit: String = "", + visibility: () -> Boolean = { true } + ) = setting(name) { layer -> FloatSetting(name, description, this, layer, visibility, defaultValue, range, step, unit) } + + @ConfigEntryD5l + fun setting( + name: String, + defaultValue: Int, + range: ClosedRange, + step: Int = 1, + description: String = "", + unit: String = "", + visibility: () -> Boolean = { true } + ) = setting(name) { layer -> IntegerSetting(name, description, this, layer, visibility, defaultValue, range, step, unit) } + + @ConfigEntryD5l + fun setting( + name: String, + defaultValue: Long, + range: ClosedRange, + step: Long = 1, + description: String = "", + unit: String = "", + visibility: () -> Boolean = { true } + ) = setting(name) { layer -> LongSetting(name, description, this, layer, visibility, defaultValue, range, step, unit) } + + @ConfigEntryD5l + fun setting( + name: String, + defaultValue: Bind, + description: String = "", + alwaysListening: Boolean = false, + screenCheck: Boolean = true, + visibility: () -> Boolean = { true } + ) = setting(name) { layer -> KeybindSetting(name, description, this, layer, visibility, defaultValue, this as? Muteable, alwaysListening, screenCheck) } + + @ConfigEntryD5l + fun setting( + name: String, + defaultValue: KeyCode, + description: String = "", + alwaysListening: Boolean = false, + screenCheck: Boolean = true, + visibility: () -> Boolean = { true } + ) = setting(name) { layer -> KeybindSetting(name, description, this, layer, visibility, defaultValue, this as? Muteable, alwaysListening, screenCheck) } + + @ConfigEntryD5l + fun setting( + name: String, + defaultValue: Color, + description: String = "", + visibility: () -> Boolean = { true } + ) = setting(name) { layer -> ColorSetting(name, description, this, layer, visibility, defaultValue) } + + @ConfigEntryD5l + fun setting( + name: String, + defaultValue: Vec3d, + description: String = "", + visibility: () -> Boolean = { true } + ) = setting(name) { layer -> Vec3dSetting(name, description, this, layer, visibility, defaultValue) } + + @ConfigEntryD5l + fun setting( + name: String, + defaultValue: BlockPos.Mutable, + description: String = "", + visibility: () -> Boolean = { true } + ) = setting(name) { layer -> BlockPosSetting(name, description, this, layer, visibility, defaultValue) } + + @ConfigEntryD5l + fun setting( + name: String, + defaultValue: BlockPos, + description: String = "", + visibility: () -> Boolean = { true } + ) = setting(name) { layer -> BlockPosSetting(name, description, this, layer, visibility, defaultValue) } + + @ConfigEntryD5l + fun setting( + name: String, + defaultValue: Block, + description: String = "", + visibility: () -> Boolean = { true } + ) = setting(name) { layer -> BlockSetting(name, description, this, layer, visibility, defaultValue) } + + @ConfigEntryD5l + fun R, R> setting( + name: String, + defaultValue: T, + description: String = "", + visibility: () -> Boolean = { true } + ) = setting(name) { layer -> FunctionSetting(name, description, defaultValue, this, layer, visibility) } + + @ConfigEntryD5l + fun configBlock( + configBlock: T + ): ConfigBlockWrapper { + val path = try { + registrationQueue.removeFirst().blockSpecs + } catch (_: NoSuchElementException) { + throw IllegalStateException("Setting block registered from an unknown location for config '$name'. Layer path was not queued before setting block initialization") + } + + var currentLayer: ConfigBlockLayer = settingBlockLayers + path.forEach { index -> + currentLayer = currentLayer.layers.getOrElse(index) { + ConfigBlockLayer.Block(currentLayer).also { currentLayer.layers.add(it) } + } + } + + return ConfigBlockWrapper(configBlock, currentLayer) + } + + @ConfigEntryD5l + fun property(value: T): Property { + val spec = try { + registrationQueue.removeFirst() + } catch (_: NoSuchElementException) { + throw IllegalStateException("Property registered from an unknown location for config '$name'. Layer path was not queued before property initialization") + } + + var currentLayer: PropertyLayer.Multiple = propertyLayers + spec.layerSpecs.forEach { spec -> + currentLayer = + currentLayer.layers + .asSequence() + .filter { it.name == spec.name } + .also { + it.forEach { layer -> + if (layer !is PropertyLayer.Multiple) + throw IllegalStateException("Multiple registered with a name '${layer.name}' matching a Single on the same layer") + } + } + .filterIsInstance() + .firstOrNull() + ?: PropertyLayer.Multiple(spec.name).also { + currentLayer.layers.add(it) + } + } + + if (currentLayer.layers.any { it.name == spec.propertyName }) + throw IllegalStateException("Duplicate layer name ('${spec.propertyName}') within ${currentLayer.name}") + + return Property(value).also { + currentLayer.layers.add(PropertyLayer.Single(it, spec.propertyName)) + } + } + + @ConfigEntryD5l + fun property(valueSupplier: () -> T) = property(valueSupplier()) + + @PublishedApi + internal fun , R> setting(name: String, settingSupplier: (single: SettingLayer.Single) -> T): T { + val layerSpecInfo = try { + registrationQueue.removeFirst() + } catch (_: NoSuchElementException) { + throw IllegalStateException("Setting registered from an unknown location for config '${this@Config.name}'. Layer path was not queued before setting initialization") + } + + var currentSettingLayer: SettingLayer.Multiple = settingLayers + layerSpecInfo.layerSpecs.forEach { spec -> + currentSettingLayer = currentSettingLayer.layers + .asSequence() + .filter { it.name == spec.name } + .also { + it.forEach { layer -> + if (spec.type == MultipleLayerType.Tab && layer !is SettingLayer.Tab || + spec.type == MultipleLayerType.Group && layer !is SettingLayer.Group + ) throw IllegalStateException("Duplicate setting layers with differing types: ('${layer.name}') in '${this@Config.name}'") + } + } + .filterIsInstance() + .firstOrNull() + ?: run { + when (spec.type) { + MultipleLayerType.Tab -> SettingLayer.Tab(spec.name, mutableListOf(), currentSettingLayer) + MultipleLayerType.Group -> SettingLayer.Group(spec.name, mutableListOf(), currentSettingLayer) + MultipleLayerType.Root -> throw IllegalStateException("Multiple root setting layers. Only the base class root layer should ever be created") + }.also { currentSettingLayer.layers.add(it) } + } + } + + if (currentSettingLayer.layers.any { it.name == name }) + throw IllegalStateException("Duplicate layer name ('$name') within ${currentSettingLayer.name}") + + var currentBlockLayer: ConfigBlockLayer = settingBlockLayers + layerSpecInfo.blockSpecs.forEach { index -> + currentBlockLayer = + currentBlockLayer.layers.getOrElse(index) { + ConfigBlockLayer.Block(currentBlockLayer).also { + currentBlockLayer.layers.add(it) + } + } + } + + val layer = SettingLayer.Single(currentSettingLayer, settingSupplier) + currentSettingLayer.layers.add(layer) + currentBlockLayer.settingLayers.add(layer) + return layer.setting + } + + internal fun forEachSetting( + root: SettingLayer.Multiple = settingLayers, + recurse: Boolean = true, + onMultiple: ((path: List, single: SettingLayer.Multiple) -> Unit)? = null, + onSingle: ((path: List, single: SettingLayer.Single<*, *>) -> Unit)? = null + ) { + fun internalForEach(layer: SettingLayer.Multiple, path: List) { + layer.layers.forEach { layer -> + when (layer) { + is SettingLayer.Single<*, *> if onSingle != null -> onSingle(path, layer) + is SettingLayer.Multiple -> { + if (onMultiple != null) onMultiple(path, layer) + if (recurse) internalForEach(layer, path + layer) + } + else -> {} + } + } + } + internalForEach(root, emptyList()) + } + + internal fun forEachSettingBlock( + root: ConfigBlockLayer = settingBlockLayers, + recurse: Boolean = true, + onBlockLayer: ((path: List, block: ConfigBlockLayer.Block) -> Unit)? = null, + onSetting: ((path: List, single: SettingLayer.Single<*, *>) -> Unit)? = null + ) { + fun internalForEach(layer: ConfigBlockLayer, path: List) { + if (onSetting != null) layer.settingLayers.forEach { onSetting(path, it) } + layer.layers.forEachIndexed { index, blockLayer -> + val fullPath = path + index + onBlockLayer?.invoke(fullPath, blockLayer) + if (recurse) internalForEach(blockLayer, fullPath) + } + } + internalForEach(root, emptyList()) + } + + private data class SettingLayerSpec(val type: MultipleLayerType, val name: String) + private data class LayerSpecInfo(val layerSpecs: List, val blockSpecs: List, val propertyName: String) +} + +enum class MultipleLayerType { Root, Tab, Group } + +sealed interface SettingLayer { + val name: String + val parent: SettingLayer? + + sealed class Multiple( + override val name: String, + val multipleType: MultipleLayerType, + val layers: MutableList, + override val parent: Multiple? + ) : SettingLayer, Nameable + + class Root : Multiple( + "Settings", + MultipleLayerType.Root, + mutableListOf(), + null + ) + + class Tab( + name: String, + layers: MutableList, + parent: Multiple + ) : Multiple(name, MultipleLayerType.Tab, layers, parent) + + class Group( + name: String, + layers: MutableList, + parent: Multiple + ) : Multiple(name, MultipleLayerType.Group, layers, parent) + + class Single, R>( + override val parent: Multiple, + settingSupplier: (Single) -> T + ) : SettingLayer { + val setting = settingSupplier(this) + override val name = setting.name + } +} + +sealed class ConfigBlockLayer { + open val parent: ConfigBlockLayer? = null + val layers = mutableListOf() + val settingLayers = mutableListOf>() + + class Root : ConfigBlockLayer() { + override val parent = null + } + + class Block( + override val parent: ConfigBlockLayer? + ) : ConfigBlockLayer() +} + +sealed class PropertyLayer { + abstract val name: String + + open class Multiple( + override val name: String + ) : PropertyLayer() { + val layers = mutableListOf() + } + + class Root : Multiple("Properties") + + class Single( + val property: Property<*>, + override val name: String + ) : PropertyLayer() +} + +@Target(AnnotationTarget.PROPERTY) +@Retention(AnnotationRetention.RUNTIME) +annotation class Tab(vararg val tabs: String) + +@Target(AnnotationTarget.PROPERTY) +@Retention(AnnotationRetention.RUNTIME) +annotation class Group(vararg val groups: String) \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/config/Codec.kt b/src/main/kotlin/com/lambda/config/ConfigBlock.kt similarity index 77% rename from src/main/kotlin/com/lambda/config/Codec.kt rename to src/main/kotlin/com/lambda/config/ConfigBlock.kt index 8fed5594a..cee531f0f 100644 --- a/src/main/kotlin/com/lambda/config/Codec.kt +++ b/src/main/kotlin/com/lambda/config/ConfigBlock.kt @@ -17,9 +17,6 @@ package com.lambda.config -import com.google.gson.JsonDeserializer -import com.google.gson.JsonSerializer - -interface Stringifiable { fun stringify(value: T): String } - -interface Codec : JsonSerializer, JsonDeserializer \ No newline at end of file +interface ConfigBlock { + val c: Config +} \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/config/ConfigBlockWrapper.kt b/src/main/kotlin/com/lambda/config/ConfigBlockWrapper.kt new file mode 100644 index 000000000..313b2e890 --- /dev/null +++ b/src/main/kotlin/com/lambda/config/ConfigBlockWrapper.kt @@ -0,0 +1,28 @@ +/* + * Copyright 2026 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 + +import kotlin.reflect.KProperty + +class ConfigBlockWrapper( + val settingBlock: T, + val layer: ConfigBlockLayer +) { + operator fun getValue(thisRef: Any?, property: KProperty<*>) = settingBlock + operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {} +} \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/config/ConfigCategory.kt b/src/main/kotlin/com/lambda/config/ConfigCategory.kt new file mode 100644 index 000000000..4a92699b3 --- /dev/null +++ b/src/main/kotlin/com/lambda/config/ConfigCategory.kt @@ -0,0 +1,143 @@ +/* + * Copyright 2026 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 + +import com.lambda.Lambda.Log +import com.lambda.Lambda.mapper +import com.lambda.config.ConfigLoader.configCategories +import com.lambda.config.categories.ModuleCategory +import com.lambda.config.migration.ConfigMigrationHandler +import com.lambda.core.Loadable +import com.lambda.event.events.ClientEvent +import com.lambda.event.listener.UnsafeListener.Companion.listenUnsafe +import com.lambda.interaction.BaritoneHandler.primary +import com.lambda.threading.runIO +import com.lambda.util.CommunicationUtils.info +import com.lambda.util.CommunicationUtils.logError +import com.lambda.util.FileUtils.createIfNotExists +import com.lambda.util.FileUtils.ifExists +import com.lambda.util.FileUtils.ifNotExists +import java.io.File +import kotlin.concurrent.fixedRateTimer +import kotlin.time.Duration.Companion.minutes + +/** + * Represents a compound of [Config] objects whose [SettingCore]s + * are saved into a single [ConfigCategory] file ([ConfigCategory.primaryFile]). + * + * This class also handles the concurrent loading and saving of persisted data on the `Dispatchers.IO` thread. + * Each configuration will be loaded concurrently, + * while the underlying configs are populated with the settings in sequence. + * + * See also [ModuleCategory]. + * + * @property name The name of the configuration. + * @property primary The primary file where the configuration is saved. + * @property configs A set of [Config] objects that this configuration manages. + */ +abstract class ConfigCategory : Loadable { + abstract val name: String + abstract val primaryFile: File + private val backup get() = File("${primaryFile.parent}/${primaryFile.nameWithoutExtension}-backup.${primaryFile.extension}") + override val priority = 1 + + val configs = mutableSetOf() + + final override fun load(): String { + if (configCategories.any { it.name == name }) + throw IllegalStateException("Config category with name $name already exists") + + fixedRateTimer( + daemon = true, + name = "Scheduler-config-category-${name}", + initialDelay = 5.minutes.inWholeMilliseconds, + period = 5.minutes.inWholeMilliseconds, + ) { trySaveToFile() } + + configCategories.add(this) + + listenUnsafe({ Int.MIN_VALUE }) { trySaveToFile() } + + return super.load() + } + + fun tryLoadFromFile() = runIO { internalTryLoad() } + fun trySaveToFile(logToChat: Boolean = false) = runIO { internalTrySave(logToChat) } + + protected open fun internalTryLoad() { + loadFromFile(primaryFile) + .onSuccess { + val message = "$name config category loaded." + Log.info(message) + info(message) + } + .onFailure { primaryError -> + Log.error(primaryError) + + runCatching { loadFromFile(backup).getOrThrow() } + .onSuccess { + val message = "$name config category loaded from backup" + Log.info(message) + info(message) + } + .onFailure { error -> + val message = "Failed to load $name config category from backup, unrecoverable error" + Log.error(message, error) + logError(message) + } + } + } + + protected open fun internalTrySave(logToChat: Boolean) { + saveToFile() + .onSuccess { + val message = "Saved $name category." + Log.info(message) + if (logToChat) info(message) + } + .onFailure { + val message = "Failed to save $name category" + Log.error(message, it) + logError(message) + } + } + + private fun loadFromFile(file: File) = runCatching { + file.ifNotExists { Log.warn("No config file found for $name. Creating new file when saving.") } + .ifExists { + val parsed = mapper.readTree(it) + if (!parsed.isObject) return@ifExists + val migrationResult = ConfigMigrationHandler.migrate(this@ConfigCategory, parsed.asObject()) + + if (migrationResult.migrated && file == primaryFile) { + mapper.writeValue(file, migrationResult.json) + file.copyTo(backup, true) + } + + mapper.updateValue(this@ConfigCategory, migrationResult.json) + } + } + + private fun saveToFile() = runCatching { + primaryFile.createIfNotExists() + .let { + mapper.writeValue(it, this) + it.copyTo(backup, true) + } + } +} diff --git a/src/main/kotlin/com/lambda/config/ConfigEditor.kt b/src/main/kotlin/com/lambda/config/ConfigEditor.kt deleted file mode 100644 index 8c2cd6b64..000000000 --- a/src/main/kotlin/com/lambda/config/ConfigEditor.kt +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright 2026 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 - -import com.lambda.util.NamedEnum -import kotlin.reflect.KProperty0 -import kotlin.reflect.jvm.isAccessible - -@DslMarker -annotation class SettingEditorDsl - -@SettingEditorDsl -fun T.applyEdits(edits: ConfigurableEditor.() -> Unit) { - ConfigurableEditor(this).apply(edits) -} - -@Suppress("unchecked_cast", "unused") -open class SettingGroupEditor(open val c: T) { - val KProperty0<*>.delegate - get() = try { - apply { isAccessible = true }.getDelegate() - } catch (e: Exception) { - throw IllegalStateException("Could not access delegate for property $name", e) - } - - fun KProperty0.setting() = - this.delegate as? Setting, T> - ?: throw IllegalStateException("Setting delegate did not match current value's type") - - fun KProperty0.settingCore() = setting().core - - @SettingEditorDsl - inline fun KProperty0.edit(edits: TypedEditBuilder.(SettingCore) -> Unit) { - val delegate = setting() - TypedEditBuilder(this@SettingGroupEditor, listOf(delegate)).edits(delegate.core) - } - - @SettingEditorDsl - inline fun KProperty0.editWith( - other: KProperty0, - edits: TypedEditBuilder.(SettingCore) -> Unit - ) = TypedEditBuilder(this@SettingGroupEditor, listOf(setting())).edits(other.settingCore()) - - @SettingEditorDsl - fun edit( - vararg settings: KProperty0<*>, - edits: BasicEditBuilder.() -> Unit - ) = 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 as KProperty0).setting() }).edits(other.settingCore()) - - @SettingEditorDsl - inline fun editTyped( - vararg settings: KProperty0, - edits: TypedEditBuilder.() -> Unit - ) = TypedEditBuilder(this, settings.map { it.setting() }).apply(edits) - - @SettingEditorDsl - inline fun editTypedWith( - vararg settings: KProperty0, - other: KProperty0, - edits: TypedEditBuilder.(SettingCore) -> Unit - ) = TypedEditBuilder(this, settings.map { it.setting() }).edits(other.settingCore()) - - @SettingEditorDsl - fun hide(settings: Collection>) { - c.settings.removeAll(settings) - } - - @SettingEditorDsl - fun hide(vararg settings: KProperty0<*>) = - hide(settings.map { (it as KProperty0).setting() }) - - open class BasicEditBuilder(val c: SettingGroupEditor<*>, open val settings: Collection>) { - @SettingEditorDsl - fun hide() = c.hide(settings) - - @SettingEditorDsl - fun groups(vararg groups: NamedEnum) = - settings.forEach { it.groups = mutableListOf(groups.toList()) } - - @SettingEditorDsl - fun groups(groups: MutableList>) = - settings.forEach { it.groups = groups } - - @SettingEditorDsl - fun visibility(visibility: (() -> Boolean) -> () -> Boolean) { - settings.forEach { - it.visibility = visibility(it.visibility) - } - } - } - - class TypedEditBuilder( - c: SettingGroupEditor<*>, - override val settings: Collection, T>> - ) : BasicEditBuilder(c, settings) { - @SettingEditorDsl - fun defaultValue(value: T) = - settings.forEach { - it.core.defaultValue = value - it.core.value = value - } - } -} - -@Suppress("unchecked_cast", "unused") -class ConfigurableEditor(override val c: T) : SettingGroupEditor(c) { - @SettingEditorDsl - fun hideGroup(settingGroup: ISettingGroup) = hide(settingGroup.settings) - - @SettingEditorDsl - 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) = - settingGroups.forEach { hide(it.settings) } - - @SettingEditorDsl - fun hideAllGroupsExcept(vararg except: ISettingGroup) = - hideGroups(*(c.settingGroups - except.toSet()).toTypedArray()) -} \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/config/configurations/ConfigLoader.kt b/src/main/kotlin/com/lambda/config/ConfigLoader.kt similarity index 61% rename from src/main/kotlin/com/lambda/config/configurations/ConfigLoader.kt rename to src/main/kotlin/com/lambda/config/ConfigLoader.kt index f7ab1a83a..636b27bb9 100644 --- a/src/main/kotlin/com/lambda/config/configurations/ConfigLoader.kt +++ b/src/main/kotlin/com/lambda/config/ConfigLoader.kt @@ -15,16 +15,25 @@ * along with this program. If not, see . */ -package com.lambda.config.configurations +package com.lambda.config -import com.lambda.config.Configuration import com.lambda.core.Loadable object ConfigLoader: Loadable { + val configCategories = mutableSetOf() + val configs: Set + get() = configCategories.flatMapTo(mutableSetOf()) { it.configs } + override fun load(): String { - Configuration.configurations.forEach { - it.tryLoad() + configCategories.forEach { + it.tryLoadFromFile() } - return "Loading ${Configuration.configurations.size} configurations" + return "Loading ${configCategories.size} config categories" } + + fun configByName(name: String) = + configs.find { it.name == name } + + fun configByCommandName(name: String) = + configs.find { it.commandName == name } } \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/config/Configurable.kt b/src/main/kotlin/com/lambda/config/Configurable.kt deleted file mode 100644 index 7c5e1a8d4..000000000 --- a/src/main/kotlin/com/lambda/config/Configurable.kt +++ /dev/null @@ -1,288 +0,0 @@ -/* - * Copyright 2026 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 - -import com.google.gson.JsonElement -import com.google.gson.JsonObject -import com.google.gson.reflect.TypeToken -import com.lambda.Lambda.LOG -import com.lambda.config.Configuration.Companion.configurables -import com.lambda.config.settings.CharSetting -import com.lambda.config.settings.FunctionSetting -import com.lambda.config.settings.StringSetting -import com.lambda.config.settings.collections.BlockCollectionSetting -import com.lambda.config.settings.collections.ClassCollectionSetting -import com.lambda.config.settings.collections.CollectionSetting -import com.lambda.config.settings.collections.ItemCollectionSetting -import com.lambda.config.settings.collections.MapSetting -import com.lambda.config.settings.comparable.BooleanSetting -import com.lambda.config.settings.comparable.EnumSetting -import com.lambda.config.settings.complex.Bind -import com.lambda.config.settings.complex.BlockPosSetting -import com.lambda.config.settings.complex.BlockSetting -import com.lambda.config.settings.complex.ColorSetting -import com.lambda.config.settings.complex.KeybindSetting -import com.lambda.config.settings.complex.Vec3dSetting -import com.lambda.config.settings.numeric.DoubleSetting -import com.lambda.config.settings.numeric.FloatSetting -import com.lambda.config.settings.numeric.IntegerSetting -import com.lambda.config.settings.numeric.LongSetting -import com.lambda.event.Muteable -import com.lambda.util.Communication.logError -import com.lambda.util.KeyCode -import com.lambda.util.Nameable -import com.lambda.imgui.flag.ImGuiInputTextFlags -import net.minecraft.block.Block -import net.minecraft.item.Item -import net.minecraft.registry.Registries -import net.minecraft.util.math.BlockPos -import net.minecraft.util.math.Vec3d -import java.awt.Color - -/** - * Represents a set of [SettingCore]s that are associated with the [name] of the [Configurable]. - * The settings are managed by this [Configurable] and are saved and loaded as part of the [Configuration]. - * - * This class also provides a series of helper methods ([setting]) for creating different types of settings. - * - * @property settings A set of [SettingCore]s that this configurable manages. - */ -abstract class Configurable( - val configuration: Configuration, -) : Jsonable, Nameable { - val settings = mutableListOf>() - val settingGroups = mutableListOf() - - init { - registerConfigurable() - } - - private fun registerConfigurable() { - if (configurables.any { it.name == name }) - throw IllegalStateException("Configurable with name $name already exists") - configuration.configurables.add(this) - } - - fun , R : Any> Setting.register() = apply { - if (settings.any { it.name == name }) - throw IllegalStateException("Setting with name $name already exists for configurable: ${this@Configurable.name}") - settings.add(this) - } - - override fun toJson() = - JsonObject().apply { - settings.forEach { setting -> - try { - add(setting.name, setting.toJson()) - } catch (e: Exception) { - logError("Failed to serialize $setting in ${this::class.simpleName}", e) - } - } - } - - override fun loadFromJson(serialized: JsonElement) { - serialized.asJsonObject.entrySet().forEach { (name, value) -> - settings.find { it.name == name }?.loadFromJson(value) - ?: LOG.warn("No saved setting found for $name with $value in ${this::class.simpleName}") - } - } - - fun setting( - name: String, - defaultValue: Boolean, - description: String = "", - visibility: () -> Boolean = { true }, - ) = Setting(name, description, BooleanSetting(defaultValue), this, visibility).register() - - inline fun > setting( - name: String, - defaultValue: T, - description: String = "", - noinline - visibility: () -> Boolean = { true }, - ) = Setting(name, description,EnumSetting(defaultValue), this, visibility).register() - - fun setting( - name: String, - defaultValue: Char, - description: String = "", - visibility: () -> Boolean = { true }, - ) = Setting(name, description, CharSetting(defaultValue), this, visibility).register() - - fun setting( - name: String, - defaultValue: String, - multiline: Boolean = false, - flags: Int = ImGuiInputTextFlags.None, - description: String = "", - visibility: () -> Boolean = { true }, - ) = Setting(name, description, StringSetting(defaultValue, multiline, flags), this, visibility).register() - - @JvmName("collectionSetting1") - fun setting( - name: String, - defaultValue: Collection, - immutableCollection: Collection = Registries.BLOCK.toList(), - description: String = "", - visibility: () -> Boolean = { true }, - ) = Setting(name, description, BlockCollectionSetting(immutableCollection, defaultValue.toMutableList()), this, visibility).register() - - @JvmName("collectionSetting2") - fun setting( - name: String, - defaultValue: Collection, - immutableCollection: Collection = Registries.ITEM.toList(), - description: String = "", - visibility: () -> Boolean = { true }, - ) = Setting(name, description, ItemCollectionSetting(immutableCollection, defaultValue.toMutableList()), this, visibility).register() - - @JvmName("collectionSetting3") - inline fun setting( - name: String, - defaultValue: Collection, - immutableList: Collection = defaultValue, - description: String = "", - displayClassName: Boolean = false, - serialize: Boolean = false, - noinline visibility: () -> Boolean = { true }, - ) = Setting( - name, - description, - if (displayClassName) ClassCollectionSetting(immutableList, defaultValue.toMutableList()) - else CollectionSetting(defaultValue.toMutableList(), immutableList, TypeToken.getParameterized(Collection::class.java, T::class.java).type, serialize), - this, - visibility - ).register() - - // ToDo: Actually implement maps - inline fun setting( - name: String, - defaultValue: Map, - description: String = "", - noinline visibility: () -> Boolean = { true }, - ) = Setting( - name, - description, - MapSetting( - defaultValue.toMutableMap(), - TypeToken.getParameterized(MutableMap::class.java, K::class.java, V::class.java).type - ), - this, - visibility - ).register() - - fun setting( - name: String, - defaultValue: Double, - range: ClosedRange, - step: Double = 1.0, - description: String = "", - unit: String = "", - visibility: () -> Boolean = { true }, - ) = Setting(name, description, DoubleSetting(defaultValue, range, step, unit), this, visibility).register() - - fun setting( - name: String, - defaultValue: Float, - range: ClosedRange, - step: Float = 1f, - description: String = "", - unit: String = "", - visibility: () -> Boolean = { true }, - ) = Setting(name, description, FloatSetting(defaultValue, range, step, unit), this, visibility).register() - - fun setting( - name: String, - defaultValue: Int, - range: ClosedRange, - step: Int = 1, - description: String = "", - unit: String = "", - visibility: () -> Boolean = { true }, - ) = Setting(name, description, IntegerSetting(defaultValue, range, step, unit), this, visibility).register() - - fun setting( - name: String, - defaultValue: Long, - range: ClosedRange, - step: Long = 1, - description: String = "", - unit: String = "", - visibility: () -> Boolean = { true }, - ) = Setting(name, description, LongSetting(defaultValue, range, step, unit), this, visibility).register() - - fun setting( - name: String, - defaultValue: Bind, - description: String = "", - alwaysListening: Boolean = false, - screenCheck: Boolean = true, - visibility: () -> Boolean = { true }, - ) = Setting(name, description, KeybindSetting(defaultValue, this as? Muteable, alwaysListening, screenCheck), this, visibility).register() - - fun setting( - name: String, - defaultValue: KeyCode, - description: String = "", - alwaysListening: Boolean = false, - screenCheck: Boolean = true, - visibility: () -> Boolean = { true }, - ) = Setting(name, description, KeybindSetting(defaultValue, this as? Muteable, alwaysListening, screenCheck), this, visibility).register() - - fun setting( - name: String, - defaultValue: Color, - description: String = "", - visibility: () -> Boolean = { true }, - ) = Setting(name, description, ColorSetting(defaultValue), this, visibility).register() - - fun setting( - name: String, - defaultValue: Vec3d, - description: String = "", - visibility: () -> Boolean = { true }, - ) = Setting(name, description, Vec3dSetting(defaultValue), this, visibility).register() - - fun setting( - name: String, - defaultValue: BlockPos.Mutable, - description: String = "", - visibility: () -> Boolean = { true }, - ) = Setting(name, description, BlockPosSetting(defaultValue), this, visibility).register() - - fun setting( - name: String, - defaultValue: BlockPos, - description: String = "", - visibility: () -> Boolean = { true }, - ) = Setting(name, description, BlockPosSetting(defaultValue), this, visibility).register() - - fun setting( - name: String, - defaultValue: Block, - description: String = "", - visibility: () -> Boolean = { true }, - ) = Setting(name, description, BlockSetting(defaultValue), this, visibility).register() - - fun setting( - name: String, - defaultValue: () -> Unit, - description: String = "", - visibility: () -> Boolean = { true } - ) = Setting(name, description, FunctionSetting(defaultValue), this, visibility).register() -} \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/config/Configuration.kt b/src/main/kotlin/com/lambda/config/Configuration.kt deleted file mode 100644 index a8bdbfecf..000000000 --- a/src/main/kotlin/com/lambda/config/Configuration.kt +++ /dev/null @@ -1,197 +0,0 @@ -/* - * Copyright 2026 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 - -import com.google.gson.JsonElement -import com.google.gson.JsonIOException -import com.google.gson.JsonObject -import com.google.gson.JsonParser -import com.google.gson.JsonSyntaxException -import com.lambda.Lambda.LOG -import com.lambda.Lambda.gson -import com.lambda.config.Configuration.Companion.configurables -import com.lambda.config.migration.ConfigMigrations -import com.lambda.config.configurations.ModuleConfigs -import com.lambda.core.Loadable -import com.lambda.event.events.ClientEvent -import com.lambda.event.listener.UnsafeListener.Companion.listenUnsafe -import com.lambda.threading.runIO -import com.lambda.util.Communication.info -import com.lambda.util.Communication.logError -import com.lambda.util.FileUtils.createIfNotExists -import com.lambda.util.FileUtils.ifExists -import com.lambda.util.FileUtils.ifNotExists -import com.lambda.util.StringUtils.capitalize -import java.io.File -import kotlin.concurrent.fixedRateTimer -import kotlin.time.Duration.Companion.minutes - - -/** - * Represents a compound of [Configurable] objects whose [SettingCore]s - * are saved into a single [Configuration] file ([Configuration.primary]). - * - * This class also handles the concurrent loading and saving of persisted data on the `Dispatchers.IO` thread. - * Each configuration will be loaded concurrently, - * while the underlying configurables are populated with the settings in sequence. - * - * See also [ModuleConfigs]. - * - * @property configName The name of the configuration. - * @property primary The primary file where the configuration is saved. - * @property configurables A set of [Configurable] objects that this configuration manages. - */ -abstract class Configuration : Jsonable, Loadable { - override val priority = 1 - abstract val configName: String - abstract val primary: File - - val configurables = mutableSetOf() - private val backup: File - get() = File("${primary.parent}/${primary.nameWithoutExtension}-backup.${primary.extension}") - - override fun load(): String { - listenUnsafe({ Int.MIN_VALUE }) { trySave() } - register() - return super.load() - } - - // Avoid context-leaking warning - private fun register() { - if (configurations.any { it.configName == configName }) - throw IllegalStateException("Configuration with name $configName already exists") - - fixedRateTimer( - daemon = true, - name = "Scheduler-config-${configName}", - initialDelay = 5.minutes.inWholeMilliseconds, - period = 5.minutes.inWholeMilliseconds, - ) { trySave() } - - configurations.add(this) - } - - override fun toJson() = - JsonObject().apply { - val latestSchemaVersion = ConfigMigrations.latestVersion(configName) - if (latestSchemaVersion > 1) { - addProperty( - ConfigMigrations.schemaVersionKey(configName) ?: ConfigMigrations.DEFAULT_SCHEMA_VERSION_KEY, - latestSchemaVersion - ) - } - configurables.forEach { - add(it.name, it.toJson()) - } - } - - override fun loadFromJson(serialized: JsonElement) { - val schemaKey = ConfigMigrations.schemaVersionKey(configName) ?: ConfigMigrations.DEFAULT_SCHEMA_VERSION_KEY - serialized.asJsonObject.entrySet().forEach { (name, value) -> - if (name == schemaKey) return@forEach - configurableByName(name) - ?.loadFromJson(value) - ?: LOG.warn("No matching setting found for saved setting $name with $value in ${configName.capitalize()} config") - } - } - - private fun save() = runCatching { - primary.createIfNotExists() - .let { - it.writeText(gson.toJson(toJson())) - it.copyTo(backup, true) - } - } - - protected open fun internalTrySave(logToChat: Boolean) { - save() - .onSuccess { - val message = "Saved ${configName.capitalize()} config." - LOG.info(message) - if (logToChat) info(message) - } - .onFailure { - val message = "Failed to save ${configName.capitalize()} config" - LOG.error(message, it) - logError(message) - } - } - - /** - * Loads the config from the [file] - * Encapsulates [JsonIOException] and [JsonSyntaxException] in a runCatching block - */ - private fun load(file: File) = runCatching { - file.ifNotExists { LOG.warn("No configuration file found for ${configName.capitalize()}. Creating new file when saving.") } - .ifExists { - val parsed = JsonParser.parseReader(it.reader()).asJsonObject - val migrationResult = ConfigMigrations.migrate(configName, parsed) - - if (migrationResult.migrated && file == primary) { - file.writeText(gson.toJson(migrationResult.json)) - file.copyTo(backup, true) - } - - loadFromJson(migrationResult.json) - } - } - - protected open fun internalTryLoad() { - load(primary) - .onSuccess { - val message = "${configName.capitalize()} config loaded." - LOG.info(message) - info(message) - } - .onFailure { primaryError -> - LOG.error(primaryError) - - runCatching { load(backup) } - .onSuccess { - val message = "${configName.capitalize()} config loaded from backup" - LOG.info(message) - info(message) - } - .onFailure { error -> - val message = "Failed to load ${configName.capitalize()} config from backup, unrecoverable error" - LOG.error(message, error) - logError(message) - } - } - } - - fun tryLoad() = runIO { internalTryLoad() } - fun trySave(logToChat: Boolean = false) = runIO { internalTrySave(logToChat) } - - companion object { - val configurations = mutableSetOf() - val configurables: Set - get() = configurations.flatMapTo(mutableSetOf()) { it.configurables } - val settings: List> - get() = configurables.flatMapTo(mutableListOf()) { it.settings } - - fun configurableByName(name: String) = - configurables.find { it.name == name } - - fun configurableByCommandName(name: String) = - configurables.find { it.commandName == name } - - fun settingByCommandName(configurable: Configurable, name: String) = - configurable.settings.find { it.commandName == name } - } -} diff --git a/src/main/kotlin/com/lambda/config/FallbackSerializers.kt b/src/main/kotlin/com/lambda/config/FallbackSerializers.kt new file mode 100644 index 000000000..f0bcc4e6f --- /dev/null +++ b/src/main/kotlin/com/lambda/config/FallbackSerializers.kt @@ -0,0 +1,87 @@ +/* + * Copyright 2026 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 + +import com.fasterxml.jackson.annotation.JsonFormat +import tools.jackson.databind.BeanDescription +import tools.jackson.databind.DeserializationConfig +import tools.jackson.databind.JavaType +import tools.jackson.databind.SerializationConfig +import tools.jackson.databind.ValueDeserializer +import tools.jackson.databind.ValueSerializer +import tools.jackson.databind.deser.Deserializers +import tools.jackson.databind.ser.Serializers + +/** + * A combined [Serializers] and [Deserializers] implementation that resolves + * serializers/deserializers by walking the class hierarchy to find the closest + * registered supertype. This allows registering a single serializer for a base + * class (e.g., [com.lambda.config.SettingCore]) that handles all its subclasses. + * + * Exact-match serializers registered via [tools.jackson.databind.module.SimpleModule.addSerializer] + * take priority over these fallbacks in Jackson's resolution order. + */ +class FallbackSerializers( + private val serializers: Map, FallbackSerializer<*>>, + private val deserializers: Map, FallbackDeserializer<*>> +) : Serializers, Deserializers { + override fun findSerializer( + config: SerializationConfig, + type: JavaType, + beanDescRef: BeanDescription.Supplier, + formatOverrides: JsonFormat.Value? + ): ValueSerializer<*>? = findClosestSupertype(type.rawClass, serializers) + + override fun findBeanDeserializer( + type: JavaType, + config: DeserializationConfig, + beanDescRef: BeanDescription.Supplier + ): ValueDeserializer<*>? = findClosestSupertype(type.rawClass, deserializers) + + override fun hasDeserializerFor(config: DeserializationConfig, valueType: Class<*>?): Boolean = + valueType != null && findClosestSupertype(valueType, deserializers) != null + + /** + * Finds the value mapped to the closest supertype of [target] among the [candidates] map keys. + * "Closest" is determined by the shortest inheritance distance up the class hierarchy. + */ + private fun findClosestSupertype(target: Class<*>, candidates: Map, V>): V? { + var bestValue: V? = null + var bestDistance = Int.MAX_VALUE + + candidates.forEach { (candidateClass, value) -> + if (!candidateClass.isAssignableFrom(target)) return@forEach + val distance = inheritanceDistance(target, candidateClass) + if (distance < bestDistance) { + bestDistance = distance + bestValue = value + } + } + return bestValue + } + + private fun inheritanceDistance(sub: Class<*>, superClass: Class<*>): Int { + var distance = 0 + var current: Class<*>? = sub + while (current != null && current != superClass) { + distance++ + current = current.superclass + } + return if (current == superClass) distance else Int.MAX_VALUE + } +} diff --git a/src/main/kotlin/com/lambda/config/JsonOps.kt b/src/main/kotlin/com/lambda/config/JsonOps.kt new file mode 100644 index 000000000..7bc235118 --- /dev/null +++ b/src/main/kotlin/com/lambda/config/JsonOps.kt @@ -0,0 +1,409 @@ +/* + * Copyright 2026 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 + +import com.mojang.datafixers.util.Pair +import com.mojang.serialization.DataResult +import com.mojang.serialization.DynamicOps +import com.mojang.serialization.Lifecycle +import com.mojang.serialization.ListBuilder +import com.mojang.serialization.MapLike +import com.mojang.serialization.RecordBuilder +import tools.jackson.databind.JsonNode +import tools.jackson.databind.node.ArrayNode +import tools.jackson.databind.node.JsonNodeFactory +import tools.jackson.databind.node.NullNode +import tools.jackson.databind.node.ObjectNode +import java.math.BigDecimal +import java.math.BigInteger +import java.util.* +import java.util.function.BiConsumer +import java.util.function.Consumer +import java.util.function.UnaryOperator +import java.util.stream.Stream +import java.util.stream.StreamSupport + +/** + * A translation of Minecraft's [com.mojang.serialization.JsonOps], built to use Jackson instead of Gson + */ +class JsonOps private constructor(private val compressed: Boolean) : DynamicOps { + @Suppress("unused") + companion object { + val Uncompressed = JsonOps(false) + val Compressed = JsonOps(true) + } + + override fun empty(): JsonNode = NullNode.getInstance() + + override fun emptyMap(): JsonNode = JsonNodeFactory.instance.objectNode() + + override fun emptyList(): JsonNode = JsonNodeFactory.instance.arrayNode() + + override fun convertTo(outOps: DynamicOps, input: JsonNode): U { + return when { + input.isObject -> convertMap(outOps, input) + input.isArray -> convertList(outOps, input) + input.isNull -> outOps.empty() + input.isString -> outOps.createString(input.stringValue()) + input.isBoolean -> outOps.createBoolean(input.booleanValue()) + input.isNumber -> { + when (val number = input.numberValue()) { + is Byte -> outOps.createByte(number) + is Short -> outOps.createShort(number) + is Int -> { + val asByte = number.toByte() + if (asByte.toInt() == number) outOps.createByte(asByte) + else { + val asShort = number.toShort() + if (asShort.toInt() == number) outOps.createShort(asShort) + else outOps.createInt(number) + } + } + is Long -> { + val asByte = number.toByte() + if (asByte.toLong() == number) outOps.createByte(asByte) + else { + val asShort = number.toShort() + if (asShort.toLong() == number) outOps.createShort(asShort) + else { + val asInt = number.toInt() + if (asInt.toLong() == number) outOps.createInt(asInt) + else outOps.createLong(number) + } + } + } + is Float -> outOps.createFloat(number) + is Double -> outOps.createDouble(number) + else -> { + val big = number as? BigDecimal ?: BigDecimal(number.toString()) + try { + when (val l = big.longValueExact()) { + l.toByte().toLong() -> outOps.createByte(l.toByte()) + l.toShort().toLong() -> outOps.createShort(l.toShort()) + l.toInt().toLong() -> outOps.createInt(l.toInt()) + else -> outOps.createLong(l) + } + } catch (_: ArithmeticException) { + val d = big.toDouble() + if (d.toFloat().toDouble() == d) outOps.createFloat(d.toFloat()) + else outOps.createDouble(d) + } + } + } + } + else -> throw IllegalArgumentException("Unknown JSON node type: $input") + } + } + + override fun getNumberValue(input: JsonNode): DataResult = + when { + input.isNumber -> DataResult.success(input.numberValue()) + compressed && input.isString -> { + try { + DataResult.success(Integer.parseInt(input.stringValue())) + } catch (e: NumberFormatException) { + DataResult.error { "Not a number: $e $input" } + } + } + else -> DataResult.error { "Not a number: $input" } + } + + override fun createNumeric(i: Number): JsonNode = + when (i) { + is Byte -> JsonNodeFactory.instance.numberNode(i) + is Short -> JsonNodeFactory.instance.numberNode(i) + is Int -> JsonNodeFactory.instance.numberNode(i) + is Long -> JsonNodeFactory.instance.numberNode(i) + is BigInteger -> JsonNodeFactory.instance.numberNode(i) + is Float -> JsonNodeFactory.instance.numberNode(i) + is Double -> JsonNodeFactory.instance.numberNode(i) + is BigDecimal -> JsonNodeFactory.instance.numberNode(i) + else -> throw IllegalStateException("Unknown number type: $i") + } + + override fun getBooleanValue(input: JsonNode): DataResult = + if (input.isBoolean) DataResult.success(input.booleanValue()) + else DataResult.error { "Not a boolean: $input" } + + override fun createBoolean(value: Boolean): JsonNode = JsonNodeFactory.instance.booleanNode(value) + + override fun getStringValue(input: JsonNode): DataResult = + when { + input.isString -> DataResult.success(input.stringValue()) + compressed && input.isNumber -> DataResult.success(input.asString()) + else -> DataResult.error { "Not a string: $input" } + } + + override fun createString(value: String): JsonNode = JsonNodeFactory.instance.stringNode(value) + + override fun mergeToList(list: JsonNode, value: JsonNode): DataResult { + if (!list.isArray && list != empty()) { + return DataResult.error({ "mergeToList called with not a list: $list" }, list) + } + + val result = JsonNodeFactory.instance.arrayNode() + if (list != empty()) { + result.addAll(list as ArrayNode) + } + result.add(value) + return DataResult.success(result) + } + + override fun mergeToList(list: JsonNode, values: List): DataResult { + if (!list.isArray && list != empty()) { + return DataResult.error({ "mergeToList called with not a list: $list" }, list) + } + + if (values.isEmpty()) { + return if (list == empty()) DataResult.success(emptyList()) + else DataResult.success(list) + } + + val result = JsonNodeFactory.instance.arrayNode() + if (list != empty()) { + result.addAll(list as ArrayNode) + } + values.forEach(result::add) + return DataResult.success(result) + } + + override fun mergeToMap(map: JsonNode, key: JsonNode, value: JsonNode): DataResult { + if (!map.isObject && map != empty()) { + return DataResult.error({ "mergeToMap called with not a map: $map" }, map) + } + if (!key.isString && !compressed) { + return DataResult.error({ "key is not a string: $key" }, map) + } + + val output = JsonNodeFactory.instance.objectNode() + if (map != empty()) { + output.setAll(map as ObjectNode) + } + val keyStr = if (key.isString) key.stringValue() else key.asString() + output.set(keyStr, value) + + return DataResult.success(output) + } + + override fun mergeToMap(map: JsonNode, values: MapLike): DataResult { + if (!map.isObject && map != empty()) { + return DataResult.error({ "mergeToMap called with not a map: $map" }, map) + } + + val valuesIterator = values.entries().iterator() + if (!valuesIterator.hasNext()) { + return if (map == empty()) DataResult.success(emptyMap()) + else DataResult.success(map) + } + + val output = JsonNodeFactory.instance.objectNode() + if (map != empty()) { + output.setAll(map as ObjectNode) + } + + val missed = mutableListOf() + + valuesIterator.forEachRemaining { (key, value) -> + if (!key.isString && !compressed) { + missed.add(key) + return@forEachRemaining + } + val keyStr = if (key.isString) key.stringValue() else key.asString() + output.set(keyStr, value) + } + + if (missed.isNotEmpty()) { + return DataResult.error({ "some keys are not strings: $missed" }, output) + } + + return DataResult.success(output) + } + + override fun getMapValues(input: JsonNode): DataResult>> { + if (!input.isObject) { + return DataResult.error { "Not a JSON object: $input" } + } + val obj = input as ObjectNode + return DataResult.success(obj.propertyStream().map { (key, value) -> + Pair(createString(key), if (value.isNull) null else value) + }) + } + + override fun getMapEntries(input: JsonNode): DataResult>> { + return if (!input.isObject) { + DataResult.error { "Not a JSON object: $input" } + } else DataResult.success(Consumer { c -> + val obj = input as ObjectNode + obj.propertyStream().map { (key, value) -> + if (!value.isNull) c.accept(createString(key), value) + } + }) + } + + override fun getMap(input: JsonNode): DataResult> { + if (!input.isObject) { + return DataResult.error { "Not a JSON object: $input" } + } + val obj = input as ObjectNode + return DataResult.success(object : MapLike { + override fun get(key: JsonNode): JsonNode? { + if (!key.isString) return null + val element = obj.get(key.stringValue()) + return if (element != null && element.isNull) null else element + } + + override fun get(key: String): JsonNode? { + val element = obj.get(key) + return if (element != null && element.isNull) null else element + } + + override fun entries(): Stream> { + return obj.propertyStream().map { (key, value) -> + Pair(createString(key), value) + } + } + + override fun toString(): String = "MapLike[$obj]" + }) + } + + override fun createMap(map: Stream>): JsonNode { + val result = JsonNodeFactory.instance.objectNode() + map.forEach { (key, value) -> + if (!key.isString) throw IllegalArgumentException("Key is not a string: $key") + result.set(key.stringValue(), value) + } + return result + } + + override fun getStream(input: JsonNode): DataResult> { + return if (input.isArray) { + val array = input as ArrayNode + DataResult.success(StreamSupport.stream(array.spliterator(), false) + .map { if (it.isNull) null else it }) + } else DataResult.error { "Not a json array: $input" } + } + + override fun getList(input: JsonNode): DataResult>> { + if (input.isArray) { + val array = input as ArrayNode + return DataResult.success(Consumer { c -> + array.forEach { element -> + if (!element.isNull) c.accept(element) + } + }) + } + return DataResult.error { "Not a json array: $input" } + } + + override fun createList(input: Stream): JsonNode { + val result = JsonNodeFactory.instance.arrayNode() + input.forEach(result::add) + return result + } + + override fun remove(input: JsonNode, key: String): JsonNode { + if (input.isObject) { + val result = JsonNodeFactory.instance.objectNode() + val obj = input as ObjectNode + obj.propertyStream().forEach { (k, v) -> + if (!Objects.equals(k, key)) { + result.set(k, v) + } + } + return result + } + return input + } + + override fun toString(): String = "JSON" + + override fun listBuilder(): ListBuilder = ArrayBuilder() + + private inner class ArrayBuilder : ListBuilder { + private var builder: DataResult = DataResult.success(JsonNodeFactory.instance.arrayNode(), Lifecycle.stable()) + + override fun ops(): DynamicOps = this@JsonOps + + override fun add(value: JsonNode): ListBuilder = + apply { + builder = builder.map { b -> + b.add(value) + b + } + } + + override fun add(value: DataResult): ListBuilder = + apply { + builder = builder.apply2stable({ b, element -> + b.add(element) + b + }, value) + } + + override fun withErrorsFrom(result: DataResult<*>): ListBuilder = + apply { builder = builder.flatMap { r -> result.map { r } } } + + override fun mapError(onError: UnaryOperator): ListBuilder = + apply { builder = builder.mapError(onError) } + + override fun build(prefix: JsonNode): DataResult { + val result = builder.flatMap { b -> + if (!prefix.isArray && prefix != ops().empty()) { + return@flatMap DataResult.error({ "Cannot append a list to not a list: $prefix" }, prefix) + } + val array = JsonNodeFactory.instance.arrayNode() + if (prefix != ops().empty()) { + array.addAll(prefix as ArrayNode) + } + array.addAll(b) + DataResult.success(array, Lifecycle.stable()) + } + + builder = DataResult.success(JsonNodeFactory.instance.arrayNode(), Lifecycle.stable()) + return result + } + } + + override fun compressMaps(): Boolean = compressed + + override fun mapBuilder(): RecordBuilder = JsonRecordBuilder() + + private inner class JsonRecordBuilder : RecordBuilder.AbstractStringBuilder(this@JsonOps) { + override fun initBuilder(): ObjectNode = JsonNodeFactory.instance.objectNode() + + override fun append(key: String, value: JsonNode, builder: ObjectNode): ObjectNode = + builder.apply { builder.set(key, value) } + + override fun build(builder: ObjectNode, prefix: JsonNode): DataResult { + return when { + prefix.isNull -> DataResult.success(builder) + prefix.isObject -> { + val result = JsonNodeFactory.instance.objectNode() + result.setAll(prefix as ObjectNode) + result.setAll(builder) + DataResult.success(result) + } + else -> DataResult.error({ "mergeToMap called with not a map: $prefix" }, prefix) + } + } + } + + private operator fun Pair.component1(): JsonNode = first + private operator fun Pair.component2(): JsonNode = second +} \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/config/Jsonable.kt b/src/main/kotlin/com/lambda/config/Jsonable.kt deleted file mode 100644 index e3ac6fe8c..000000000 --- a/src/main/kotlin/com/lambda/config/Jsonable.kt +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2026 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 - -import com.google.gson.Gson -import com.google.gson.JsonElement - - -/** - * Interface for objects that can be serialized to and deserialized from JSON ([Gson]). - */ -interface Jsonable { - /** Serializes the object to a [JsonElement] */ - fun toJson(): JsonElement - - /** Loads the object's state from a [JsonElement] */ - fun loadFromJson(serialized: JsonElement) -} diff --git a/src/main/kotlin/com/lambda/config/Property.kt b/src/main/kotlin/com/lambda/config/Property.kt new file mode 100644 index 000000000..946b17a02 --- /dev/null +++ b/src/main/kotlin/com/lambda/config/Property.kt @@ -0,0 +1,25 @@ +/* + * Copyright 2026 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 + +import kotlin.reflect.KProperty + +class Property(var value: T) { + operator fun getValue(thisRef: Any?, property: Any?) = value + operator fun setValue(thisRef: Any?, property: KProperty<*>, newValue: T) { value = newValue } +} \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/config/Serializers.kt b/src/main/kotlin/com/lambda/config/Serializers.kt new file mode 100644 index 000000000..2b26cf14a --- /dev/null +++ b/src/main/kotlin/com/lambda/config/Serializers.kt @@ -0,0 +1,65 @@ +/* + * Copyright 2026 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 . + */ + +@file:Suppress("unused") + +package com.lambda.config + +import com.lambda.Lambda +import tools.jackson.databind.deser.std.StdDeserializer +import tools.jackson.databind.json.JsonMapper +import tools.jackson.databind.module.SimpleModule +import tools.jackson.databind.ser.std.StdSerializer + +abstract class Serializer(type: Class) : BaseSerializer(type) +abstract class Deserializer(type: Class) : BaseDeserializer(type) + +abstract class FallbackSerializer(type: Class) : BaseSerializer(type) +abstract class FallbackDeserializer(type: Class) : BaseDeserializer(type) + +interface Stringifiable { fun stringify(value: T): String } + +sealed class BaseSerializer(final override val type: Class) : StdSerializer(type), JsonModRegisterable { + override val mapper by lazy { Lambda.mapper } + + context(simpleModule: SimpleModule) + override fun register() { + with(simpleModule) { + addSerializer(type, this@BaseSerializer) + } + } +} +sealed class BaseDeserializer(final override val type: Class) : StdDeserializer(type), JsonModRegisterable { + override val mapper by lazy { Lambda.mapper } + + context(simpleModule: SimpleModule) + override fun register() { + with(simpleModule) { + addDeserializer(type, this@BaseDeserializer) + } + } +} + +interface JsonModRegisterable { + val mapper: JsonMapper + val type: Class + + context(simpleModule: SimpleModule) + fun register() + + fun initFromJsonException(objName: String) = IllegalStateException("Attempted to initialize a $objName directly from JSON! All $objName's should be updated after standard initialization.") +} diff --git a/src/main/kotlin/com/lambda/config/Setting.kt b/src/main/kotlin/com/lambda/config/Setting.kt index 9272becfc..b080c1ca6 100644 --- a/src/main/kotlin/com/lambda/config/Setting.kt +++ b/src/main/kotlin/com/lambda/config/Setting.kt @@ -17,10 +17,8 @@ package com.lambda.config -import com.google.gson.JsonElement -import com.google.gson.JsonParser -import com.lambda.Lambda.LOG -import com.lambda.Lambda.gson +import com.google.common.base.Defaults.defaultValue +import com.lambda.Lambda.mapper import com.lambda.brigadier.CommandResult.Companion.failure import com.lambda.brigadier.CommandResult.Companion.success import com.lambda.brigadier.argument.string @@ -29,14 +27,12 @@ import com.lambda.brigadier.executeWithResult import com.lambda.brigadier.required import com.lambda.command.CommandRegistry import com.lambda.command.commands.ConfigCommand -import com.lambda.config.Setting.ValueListener import com.lambda.context.SafeContext import com.lambda.gui.dsl.ImGuiBuilder import com.lambda.threading.runSafe -import com.lambda.util.Communication.info +import com.lambda.util.CommunicationUtils.info import com.lambda.util.Describable import com.lambda.util.Nameable -import com.lambda.util.NamedEnum import com.lambda.util.extension.CommandBuilder import com.lambda.util.text.ClickEvents import com.lambda.util.text.HoverEvents @@ -47,7 +43,6 @@ import com.lambda.util.text.highlighted import com.lambda.util.text.hoverEvent import com.lambda.util.text.literal import net.minecraft.command.CommandRegistryAccess -import java.lang.reflect.Type import kotlin.reflect.KProperty /** @@ -61,7 +56,7 @@ import kotlin.reflect.KProperty * Simple Usage: * ```kotlin * // this uses the delegate (by) association to access the setting value in the code directly. - * val mode by setting("Mode", Modes.FREEZE, { page == Page.CUSTOM }, "The mode of the module.") + * val mode by setting("Mode", Modes.Freeze, { page == Page.Custom }, "The mode of the module.") * * init { * listener { @@ -73,7 +68,7 @@ import kotlin.reflect.KProperty * Advanced usage with listeners: * ```kotlin * // notice how this does not use the delegate (by) association, to access the setting object to register listeners. - * val mode = setting("Mode", Modes.FREEZE, { page == Page.CUSTOM }, "The mode of the module.") + * val mode = setting("Mode", Modes.Freeze, { page == Page.Custom }, "The mode of the module.") * * init { * mode.listener { from, to -> @@ -84,7 +79,7 @@ import kotlin.reflect.KProperty * } * * listener { - * LOG.info("Mode: ${mode.value}") // indirect access of the value + * Log.info("Mode: ${mode.value}") // indirect access of the value * } * } * ``` @@ -92,168 +87,118 @@ import kotlin.reflect.KProperty * @property defaultValue The default value of the setting. * @property type The type reflection of the setting. */ -abstract class SettingCore( - var defaultValue: T, - val type: Type -) { - open var value = defaultValue - set(value) { - val oldValue = field - field = value - listeners.forEach { - if (it.requiresValueChange && oldValue == value) return@forEach - it.execute(oldValue, value) - } - } - val listeners = mutableListOf>() - - context(setting: Setting<*, T>) - abstract fun ImGuiBuilder.buildLayout() - - context(setting: Setting<*, T>) - open fun CommandBuilder.buildCommand(registry: CommandRegistryAccess) { - required(string("value as JSON")) { value -> - executeWithResult { - val valueString = value().value() - val parsed = try { - JsonParser.parseString("\"$valueString\"") - } catch (_: Exception) { - return@executeWithResult failure("$valueString is not a valid JSON string.") - } - ?: return@executeWithResult failure("No config found for $name.") - val previous = this@SettingCore.value - try { - loadFromJson(parsed) - } catch (_: Exception) { - return@executeWithResult failure("Failed to load $valueString as a ${type::class.simpleName} for $name in ${setting.configurable.name}.") - } - ConfigCommand.info(setting.setMessage(previous, this@SettingCore.value)) - return@executeWithResult success() - } - } - } - - context(setting: Setting<*, T>) - open fun toJson(): JsonElement = - gson.toJsonTree(value, type) - - context(setting: Setting<*, T>) - open fun loadFromJson(serialized: JsonElement) { - runCatching { - value = gson.fromJson(serialized, type) - }.onFailure { - LOG.warn("Failed to load setting ${setting.name} with value $serialized. Resetting to default value $defaultValue") - value = defaultValue - } - } -} - -class Setting, R>( +@Suppress("unused") +abstract class Setting( override val name: String, override val description: String, - var core: T, - val configurable: Configurable, - var visibility: () -> Boolean, + var core: SettingCore, + val config: Config, + val layer: SettingLayer.Single<*, *>, + var visibility: () -> Boolean ) : Nameable, Describable { val originalCore = core var disabled = { false } - var groups: MutableList> = mutableListOf() - var buttonMenu: NamedEnum? = null - var value by this + open var value by this + + val listeners = mutableListOf>() - val isModified get() = value != core.defaultValue + open val isModified get() = originalCore.value != originalCore.defaultValue operator fun getValue(thisRef: Any?, property: KProperty<*>) = core.value - operator fun setValue(thisRef: Any?, property: KProperty<*>, value: R) { - core.value = value + operator fun setValue(thisRef: Any?, property: KProperty<*>, newValue: T) { + val oldValue = originalCore.value + originalCore.value = newValue + listeners.forEach { + if (it.requiresValueChange && oldValue == newValue) return@forEach + it.execute(oldValue, newValue) + } } fun reset(silent: Boolean = false) { - if (!silent && value == core.defaultValue) { + if (!silent && originalCore.value == originalCore.defaultValue) { ConfigCommand.info(notChangedMessage()) return } - if (!silent) ConfigCommand.info(resetMessage(value, core.defaultValue)) - value = core.defaultValue + if (!silent) ConfigCommand.info(resetMessage(value, originalCore.defaultValue)) + value = originalCore.defaultValue } fun restoreOriginalCore() { core = originalCore } - fun ImGuiBuilder.buildLayout() = with(core) { buildLayout() } - fun CommandBuilder.buildCommand(registry: CommandRegistryAccess) = with(core) { buildCommand(registry) } - - fun toJson() = originalCore.toJson() - fun loadFromJson(serialized: JsonElement) = originalCore.loadFromJson(serialized) + abstract fun ImGuiBuilder.buildLayout() - class ValueListener(val requiresValueChange: Boolean, val execute: (from: T, to: T) -> Unit) + open fun CommandBuilder.buildCommand(registry: CommandRegistryAccess) { + required(string("value as JSON")) { value -> + executeWithResult { + val valueString = value().value() + val previous = originalCore.value + try { + this@Setting.value = mapper.readValue(valueString, this@Setting.value?.javaClass) + } catch (_: Throwable) { + return@executeWithResult failure("Failed to deserialize $valueString as a ${type::class.simpleName} for $name in ${config.name}.") + } + ConfigCommand.info(setMessage(previous, originalCore.value)) + return@executeWithResult success() + } + } + } /** * Will only register changes of the variable, not the content of the variable! * E.g., if the variable is a list, it will only register if the list reference changes, not if the content of the list changes. */ - fun onValueChange(block: SafeContext.(from: R, to: R) -> Unit) = apply { - core.listeners.add(ValueListener(true) { from, to -> + @ConfigEntryD5l + fun onValueChange(block: SafeContext.(from: T, to: T) -> Unit) = apply { + listeners.add(ValueListener(true) { from, to -> runSafe { block(from, to) } }) } - fun onValueChangeUnsafe(block: (from: R, to: R) -> Unit) = apply { - core.listeners.add(ValueListener(true, block)) + @ConfigEntryD5l + fun onValueChangeUnsafe(block: (from: T, to: T) -> Unit) = apply { + listeners.add(ValueListener(true, block)) } - fun onValueSet(block: (from: R, to: R) -> Unit) = apply { - core.listeners.add(ValueListener(false, block)) + @ConfigEntryD5l + fun onValueSet(block: (from: T, to: T) -> Unit) = apply { + listeners.add(ValueListener(false, block)) } + @ConfigEntryD5l fun disabled(predicate: () -> Boolean) = apply { disabled = predicate } - fun group(path: List, vararg continuation: NamedEnum) = apply { - groups.add(path + continuation) - } - - fun group(vararg path: NamedEnum) = apply { - groups.add(path.toList()) - } - - fun group(path: NamedEnum?) = apply { - path?.let { groups.add(listOf(it)) } - } - - fun buttonMenu(menu: NamedEnum) = apply { - buttonMenu = menu - } - - fun trySetValue(newValue: R) { - if (newValue == value) { + fun trySetValue(newValue: T) { + if (newValue == originalCore.value) { ConfigCommand.info(notChangedMessage()) } else { - val previous = value + val previous = originalCore.value value = newValue ConfigCommand.info(setMessage(previous, newValue)) } } - fun setMessage(previousValue: R, newValue: R) = buildText { + fun setMessage(previousValue: T, newValue: T) = buildText { literal("Set ") changedMessage(previousValue, newValue) - clickEvent(ClickEvents.suggestCommand("${CommandRegistry.prefix}${ConfigCommand.name} reset ${configurable.commandName} $commandName")) { + val commandPath = getConfigCommandPath().joinToString("->", postfix = "->").takeIf { it != "->" } ?: "" + clickEvent(ClickEvents.suggestCommand("${CommandRegistry.prefix}${ConfigCommand.commandName} reset ${config.commandName} $commandPath$commandName")) { hoverEvent(HoverEvents.showText(buildText { literal("Click to reset to default value ") - highlighted(core.defaultValue.toString()) + highlighted(originalCore.defaultValue.toString()) })) { highlighted(" [Reset]") } } } - private fun resetMessage(previousValue: R, newValue: R) = buildText { + private fun resetMessage(previousValue: T, newValue: T) = buildText { literal("Reset ") changedMessage(previousValue, newValue) } @@ -262,12 +207,12 @@ class Setting, R>( literal("No changes made to ") highlighted(name) literal(" as it is already set to ") - highlighted(value.toString()) + highlighted(originalCore.value.toString()) literal(".") } - private fun TextBuilder.changedMessage(previousValue: R, newValue: R) { - highlighted(configurable.name) + private fun TextBuilder.changedMessage(previousValue: T, newValue: T) { + highlighted(config.name) literal(" > ") highlighted(name) literal(" from ") @@ -275,7 +220,8 @@ class Setting, R>( literal(" to ") highlighted(newValue.toString()) literal(".") - clickEvent(ClickEvents.suggestCommand("${CommandRegistry.prefix}${ConfigCommand.name} set ${configurable.commandName} $commandName $previousValue")) { + val commandPath = getConfigCommandPath().joinToString("->", postfix = "->").takeIf { it != "->" } ?: "" + clickEvent(ClickEvents.suggestCommand("${CommandRegistry.prefix}${ConfigCommand.name} set ${config.commandName} $commandPath$commandName $previousValue")) { hoverEvent(HoverEvents.showText(buildText { literal("Click to undo to previous value ") highlighted(previousValue.toString()) @@ -285,8 +231,25 @@ class Setting, R>( } } - override fun toString() = "Setting $name: $value of type ${core.type.typeName}" + internal fun getConfigCommandPath(): Collection = + buildList { + var current: SettingLayer.Multiple = layer.parent + while (true) { + current = current.parent ?: break + if (current.multipleType == MultipleLayerType.Root) break + add(current.commandName) + } + }.asReversed() + + override fun toString() = "Setting $name: $value" + + class ValueListener(val requiresValueChange: Boolean, val execute: (from: T, to: T) -> Unit) +} + +class SettingCore( + var defaultValue: T, + var value: T = defaultValue, +) - override fun equals(other: Any?) = other is Setting<*, *> && name == other.name - override fun hashCode() = name.hashCode() -} \ No newline at end of file +@DslMarker +annotation class ConfigEntryD5l \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/config/SettingEditor.kt b/src/main/kotlin/com/lambda/config/SettingEditor.kt new file mode 100644 index 000000000..b43e0bf87 --- /dev/null +++ b/src/main/kotlin/com/lambda/config/SettingEditor.kt @@ -0,0 +1,211 @@ +/* + * Copyright 2026 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 . + */ + +@file:Suppress("unchecked_cast", "unused") + +package com.lambda.config + +import com.lambda.context.SafeContext +import kotlin.reflect.KProperty0 +import kotlin.reflect.jvm.isAccessible + +@DslMarker +annotation class SettingEditorDsl + +@SettingEditorDsl +fun T.withEdits( + edits: context(EditContext.ConfigEditContext) T.() -> Unit +) = apply { with(EditContext.ConfigEditContext(this)) { edits() } } + +@SettingEditorDsl +context(c: Config) +fun ConfigBlockWrapper.withEdits( + edits: context(EditContext.BlockEditContext) T.() -> Unit +) = apply { with(EditContext.BlockEditContext(c, this)) { this@withEdits.settingBlock.edits() } } + +@SettingEditorDsl +fun ConfigBlockWrapper.withEdits( + c: Config, + edits: context(EditContext.BlockEditContext) T.() -> Unit +) = with(c) { withEdits(edits) } + +sealed class EditContext(internal val c: Config) { + class ConfigEditContext internal constructor(c: Config) : EditContext(c) + class BlockEditContext internal constructor(c: Config, internal val block: ConfigBlockWrapper<*>) : EditContext(c) +} + +object SettingEditor { + @SettingEditorDsl + context(editContext: EditContext.ConfigEditContext) + fun forEachSetting(block: BasicEditBuilder.() -> Unit) { + val settings = mutableListOf>() + editContext.c.forEachSetting { _, single -> settings.add(single.setting) } + BasicEditBuilder(settings).apply(block) + } + + @SettingEditorDsl + context(editContext: EditContext.ConfigEditContext) + fun hideAllBlocksExcept(vararg except: SettingBlockProperty, recursive: Boolean = true) = + hideAllBlocksExcept(editContext.c.settingBlockLayers, *except, recursive = recursive) + + @SettingEditorDsl + context(editContext: EditContext.BlockEditContext) + fun forEachSetting(block: BasicEditBuilder.() -> Unit) { + val settings = mutableListOf>() + editContext.c.forEachSettingBlock(editContext.block.layer) { _, single -> settings.add(single.setting) } + BasicEditBuilder(settings).apply(block) + } + + @SettingEditorDsl + context(editContext: EditContext.BlockEditContext) + fun hideAllBlocksExcept( + vararg except: SettingBlockProperty, + recursive: Boolean = true + ) = + hideAllBlocksExcept(editContext.block.layer, *except, recursive = recursive) + + @SettingEditorDsl + context(_: EditContext) + fun SettingProperty.edit(edits: TypedEditBuilder.() -> Unit) { + TypedEditBuilder(listOf(setting)).edits() + } + + @SettingEditorDsl + context(_: EditContext) + fun edit( + vararg settings: SettingProperty, + edits: BasicEditBuilder.() -> Unit + ) = BasicEditBuilder(settings.map { it.setting }).apply(edits) + + @SettingEditorDsl + context(_: EditContext) + fun editTyped( + vararg settings: SettingProperty, + edits: TypedEditBuilder.() -> Unit + ) = TypedEditBuilder(settings.map { it.setting }).apply(edits) + + @SettingEditorDsl + context(_: EditContext) + fun hide(vararg settings: SettingProperty) = + hide(settings.map { it.setting.layer }) + + @SettingEditorDsl + context(_: EditContext) + fun hideBlock(settingBlock: SettingBlockProperty) { + settingBlock.configBlock.layer.settingLayers.forEach(::hide) + } + + @SettingEditorDsl + context(_: EditContext) + fun hideBlocks(vararg configBlocks: SettingBlockProperty) = + configBlocks.forEach { hideBlock(it) } + + @SettingEditorDsl + context(_: EditContext) + fun hideBlockExcept( + settingBlock: SettingBlockProperty, + vararg except: SettingProperty, + recursive: Boolean = true + ) { + val exceptSettings = except.map { it.setting } + fun processBlock(blockLayer: ConfigBlockLayer) { + blockLayer.settingLayers.forEach { single -> + if (single.setting !in exceptSettings) hide(single) + } + if (recursive) blockLayer.layers.forEach(::processBlock) + } + processBlock(settingBlock.configBlock.layer) + } + + open class BasicEditBuilder internal constructor( + open val settings: Collection> + ) { + @SettingEditorDsl + fun hide() { + settings.forEach { + hide(it.layer) + } + } + + @SettingEditorDsl + fun visibility(visibility: (() -> Boolean) -> () -> Boolean) { + settings.forEach { + it.visibility = visibility(it.visibility) + } + } + + @SettingEditorDsl + fun onValueChange(block: SafeContext.(from: Any?, to: Any?) -> Unit) { + settings.forEach { it.onValueChange(block) } + } + } + + class TypedEditBuilder internal constructor( + override val settings: Collection> + ) : BasicEditBuilder(settings) { + @SettingEditorDsl + fun defaultValue(value: T) = + settings.forEach { + it.originalCore.value = value + it.originalCore.defaultValue = value + } + } + + private fun hide(layers: Collection>) { + layers.forEach(::hide) + } + + private fun hide(layer: SettingLayer.Single<*, *>) { + val parentLayer = layer.parent + parentLayer.layers.remove(layer) + if (parentLayer.layers.isEmpty()) + parentLayer.parent?.layers?.remove(parentLayer) + } + + private fun hideAllBlocksExcept( + root: ConfigBlockLayer, + vararg except: SettingBlockProperty, + recursive: Boolean + ) { + val exceptBlocks = except.map { it.configBlock.layer } + fun processBlock(settingBlockLayer: ConfigBlockLayer) { + val unProtected = settingBlockLayer !in exceptBlocks + if (unProtected) settingBlockLayer.settingLayers.forEach(::hide) + if (unProtected || !recursive) settingBlockLayer.layers.forEach(::processBlock) + } + processBlock(root) + } + + private typealias Property = KProperty0 + private typealias SettingProperty = KProperty0 + private typealias SettingBlockProperty = KProperty0 + + private val Property<*>.delegate + get() = try { + apply { isAccessible = true }.getDelegate() + } catch (e: Exception) { + throw IllegalStateException("Could not access delegate for property $name", e) + } + + private val SettingProperty.setting + get() = this.delegate as? Setting + ?: throw IllegalStateException("Setting delegate did not match the given type") + + private val SettingBlockProperty.configBlock + get() = this.delegate as? ConfigBlockWrapper + ?: throw IllegalStateException("SettingBlock delegate did not match the given type") +} diff --git a/src/main/kotlin/com/lambda/config/automation/AutomationConfig.kt b/src/main/kotlin/com/lambda/config/automation/AutomationConfig.kt new file mode 100644 index 000000000..5e4c4ff36 --- /dev/null +++ b/src/main/kotlin/com/lambda/config/automation/AutomationConfig.kt @@ -0,0 +1,75 @@ +/* + * Copyright 2026 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.automation + +import com.lambda.config.Config +import com.lambda.config.ConfigCategory +import com.lambda.config.Tab +import com.lambda.config.categories.AutomationCategory +import com.lambda.config.settings.blocks.BreakSettings +import com.lambda.config.settings.blocks.BuildSettings +import com.lambda.config.settings.blocks.EatSettings +import com.lambda.config.settings.blocks.HotbarSettings +import com.lambda.config.settings.blocks.InteractSettings +import com.lambda.config.settings.blocks.InventorySettings +import com.lambda.config.settings.blocks.RotationSettings +import com.lambda.context.Automated +import com.lambda.module.Module + + +open class AutomationConfig( + name: String, + configCategory: ConfigCategory = AutomationCategory +) : Config( + name, + configCategory +), Automated { + @Tab(BuildTab) override val buildConfig by configBlock(BuildSettings(this)) + @Tab(BreakTab) override val breakConfig by configBlock(BreakSettings(this)) + @Tab(InteractTab) override val interactConfig by configBlock(InteractSettings(this)) + @Tab(RotationTab) override val rotationConfig by configBlock(RotationSettings(this)) + @Tab(InventoryTab) override val inventoryConfig by configBlock(InventorySettings(this)) + @Tab(HotbarTab) override val hotbarConfig by configBlock(HotbarSettings(this)) + @Tab(EatTab) override val eatConfig by configBlock(EatSettings(this)) + + companion object { + private const val BuildTab = "Build" + private const val BreakTab = "Break" + private const val InteractTab = "Interact" + private const val RotationTab = "Rotation" + private const val InventoryTab = "Inventory" + private const val HotbarTab = "Hotbar" + private const val EatTab = "Eat" + + @DslMarker + private annotation class AutomationConfigMarker + + @AutomationConfigMarker + context(module: Module) + fun IMutableAutomationConfig.setDefaultAutomationConfig( + name: String = module.name + ) = AutomationConfig("$name Automation Config").also { this.defaultAutomationConfig = it } + + @AutomationConfigMarker + fun IMutableAutomationConfig.setDefaultAutomationConfig( + name: String + ) = AutomationConfig("$name Automation Config").also { this.defaultAutomationConfig = it } + + val Default = AutomationConfig("Default") + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/config/IMutableAutomationConfig.kt b/src/main/kotlin/com/lambda/config/automation/IMutableAutomationConfig.kt similarity index 58% rename from src/main/kotlin/com/lambda/config/IMutableAutomationConfig.kt rename to src/main/kotlin/com/lambda/config/automation/IMutableAutomationConfig.kt index 42d35feff..6cb3cd1d2 100644 --- a/src/main/kotlin/com/lambda/config/IMutableAutomationConfig.kt +++ b/src/main/kotlin/com/lambda/config/automation/IMutableAutomationConfig.kt @@ -15,16 +15,19 @@ * along with this program. If not, see . */ -package com.lambda.config +package com.lambda.config.automation -import com.lambda.config.groups.BuildConfig -import com.lambda.config.groups.EatConfig +import com.lambda.config.Setting +import com.lambda.config.SettingCore +import com.lambda.config.SettingLayer +import com.lambda.config.settings.blocks.BreakConfig +import com.lambda.config.settings.blocks.BuildConfig +import com.lambda.config.settings.blocks.EatConfig +import com.lambda.config.settings.blocks.HotbarConfig +import com.lambda.config.settings.blocks.InteractConfig +import com.lambda.config.settings.blocks.InventoryConfig +import com.lambda.config.settings.blocks.RotationConfig import com.lambda.context.Automated -import com.lambda.interaction.managers.breaking.BreakConfig -import com.lambda.interaction.managers.hotbar.HotbarConfig -import com.lambda.interaction.managers.interacting.InteractConfig -import com.lambda.interaction.managers.inventory.InventoryConfig -import com.lambda.interaction.managers.rotating.RotationConfig interface IMutableAutomationConfig : Automated { var defaultAutomationConfig: AutomationConfig @@ -41,7 +44,7 @@ interface IMutableAutomationConfig : Automated { } class MutableAutomationConfig : IMutableAutomationConfig { - override var defaultAutomationConfig: AutomationConfig = AutomationConfig.Companion.DEFAULT + override var defaultAutomationConfig: AutomationConfig = AutomationConfig.Default set(value) { field = value automationConfig = value @@ -51,17 +54,28 @@ class MutableAutomationConfig : IMutableAutomationConfig { set(value) { if (value === defaultAutomationConfig) { if (backingAutomationConfig !== defaultAutomationConfig) { - field.settings.forEach(Setting<*, *>::restoreOriginalCore) + field.forEachSetting { _, single -> single.setting.restoreOriginalCore() } } field = value - } else field.settings.forEach { setting -> - value.settings.forEach { newSetting -> - if (setting.name == newSetting.name) { - if (setting.core.type != newSetting.core.type) - throw IllegalStateException("Settings with the same name do not have the same type.") - @Suppress("UNCHECKED_CAST") - (setting as Setting, Any>).core = newSetting.core as SettingCore + } else { + field.forEachSetting { path, single -> + var otherLayer: SettingLayer.Multiple = value.settingLayers + path.forEach { layer -> + val subLayer = otherLayer.layers + .asSequence() + .filterIsInstance() + .find { it.name == layer.name } ?: return@forEachSetting + otherLayer = subLayer } + val otherSetting = otherLayer.layers + .asSequence() + .filterIsInstance>() + .find { it.name == single.name } + ?.setting ?: return@forEachSetting + if (single.setting.core::class != otherSetting.core::class) + throw IllegalStateException("Settings with the same name do not have the same type.") + @Suppress("UNCHECKED_CAST") + (single.setting as Setting).core = otherSetting.core as SettingCore } } backingAutomationConfig = value diff --git a/src/main/kotlin/com/lambda/config/UserAutomationConfig.kt b/src/main/kotlin/com/lambda/config/automation/UserAutomationConfig.kt similarity index 86% rename from src/main/kotlin/com/lambda/config/UserAutomationConfig.kt rename to src/main/kotlin/com/lambda/config/automation/UserAutomationConfig.kt index c1dabd000..e88bafc52 100644 --- a/src/main/kotlin/com/lambda/config/UserAutomationConfig.kt +++ b/src/main/kotlin/com/lambda/config/automation/UserAutomationConfig.kt @@ -15,16 +15,16 @@ * along with this program. If not, see . */ -package com.lambda.config +package com.lambda.config.automation -import com.lambda.config.configurations.UserAutomationConfigs +import com.lambda.config.categories.UserAutomationCategory import com.lambda.config.settings.collections.CollectionSetting.Companion.onDeselect import com.lambda.config.settings.collections.CollectionSetting.Companion.onSelect import com.lambda.module.Module import com.lambda.module.ModuleRegistry.moduleNameMap -class UserAutomationConfig(override val name: String) : AutomationConfig(name, UserAutomationConfigs) { - val linkedModules = setting("Linked Modules", emptySet(), moduleNameMap.filter { it.value.defaultAutomationConfig != Companion.DEFAULT }.keys) { false } +class UserAutomationConfig(name: String) : AutomationConfig(name, UserAutomationCategory) { + val linkedModules = setting("Linked Modules", emptySet(), moduleNameMap.filter { it.value.defaultAutomationConfig != Default }.keys) { false } .onSelect { name -> moduleNameMap[name]?.let { it.removeLink() diff --git a/src/main/kotlin/com/lambda/config/configurations/LambdaConfig.kt b/src/main/kotlin/com/lambda/config/categories/AutomationCategory.kt similarity index 70% rename from src/main/kotlin/com/lambda/config/configurations/LambdaConfig.kt rename to src/main/kotlin/com/lambda/config/categories/AutomationCategory.kt index 1b1f50299..6deb59062 100644 --- a/src/main/kotlin/com/lambda/config/configurations/LambdaConfig.kt +++ b/src/main/kotlin/com/lambda/config/categories/AutomationCategory.kt @@ -15,13 +15,13 @@ * along with this program. If not, see . */ -package com.lambda.config.configurations +package com.lambda.config.categories -import com.lambda.config.Configuration -import com.lambda.util.FolderRegister +import com.lambda.config.ConfigCategory +import com.lambda.util.FolderRegistry import java.io.File -object LambdaConfig : Configuration() { - override val configName get() = "lambda" - override val primary: File = FolderRegister.config.resolve("$configName.json").toFile() -} +object AutomationCategory : ConfigCategory() { + override val name = "automation" + override val primaryFile: File = FolderRegistry.config.resolve("$name.json").toFile() +} \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/config/configurations/FontConfig.kt b/src/main/kotlin/com/lambda/config/categories/FontCategory.kt similarity index 71% rename from src/main/kotlin/com/lambda/config/configurations/FontConfig.kt rename to src/main/kotlin/com/lambda/config/categories/FontCategory.kt index 10ff2d6f1..234609277 100644 --- a/src/main/kotlin/com/lambda/config/configurations/FontConfig.kt +++ b/src/main/kotlin/com/lambda/config/categories/FontCategory.kt @@ -15,14 +15,13 @@ * along with this program. If not, see . */ -package com.lambda.config.configurations +package com.lambda.config.categories -import com.lambda.config.Configuration -import com.lambda.util.FolderRegister +import com.lambda.config.ConfigCategory +import com.lambda.util.FolderRegistry import java.io.File - -object FontConfig : Configuration() { - override val configName = "font" - override val primary: File = FolderRegister.config.resolve("${configName}.json").toFile() +object FontCategory : ConfigCategory() { + override val name get() = "font" + override val primaryFile: File = FolderRegistry.config.resolve("$name.json").toFile() } \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/config/configurations/GuiConfig.kt b/src/main/kotlin/com/lambda/config/categories/FriendCategory.kt similarity index 70% rename from src/main/kotlin/com/lambda/config/configurations/GuiConfig.kt rename to src/main/kotlin/com/lambda/config/categories/FriendCategory.kt index afea31040..ff5b62483 100644 --- a/src/main/kotlin/com/lambda/config/configurations/GuiConfig.kt +++ b/src/main/kotlin/com/lambda/config/categories/FriendCategory.kt @@ -15,13 +15,13 @@ * along with this program. If not, see . */ -package com.lambda.config.configurations +package com.lambda.config.categories -import com.lambda.config.Configuration -import com.lambda.util.FolderRegister +import com.lambda.config.ConfigCategory +import com.lambda.util.FolderRegistry import java.io.File -object GuiConfig : Configuration() { - override val configName get() = "gui" - override val primary: File = FolderRegister.config.resolve("$configName.json").toFile() +object FriendCategory : ConfigCategory() { + override val name get() = "friends" + override val primaryFile: File = FolderRegistry.config.resolve("$name.json").toFile() } diff --git a/src/main/kotlin/com/lambda/config/configurations/HudConfig.kt b/src/main/kotlin/com/lambda/config/categories/GuiCategory.kt similarity index 70% rename from src/main/kotlin/com/lambda/config/configurations/HudConfig.kt rename to src/main/kotlin/com/lambda/config/categories/GuiCategory.kt index 17d6ce58e..2851a3799 100644 --- a/src/main/kotlin/com/lambda/config/configurations/HudConfig.kt +++ b/src/main/kotlin/com/lambda/config/categories/GuiCategory.kt @@ -15,13 +15,13 @@ * along with this program. If not, see . */ -package com.lambda.config.configurations +package com.lambda.config.categories -import com.lambda.config.Configuration -import com.lambda.util.FolderRegister +import com.lambda.config.ConfigCategory +import com.lambda.util.FolderRegistry import java.io.File -object HudConfig : Configuration() { - override val configName get() = "hud" - override val primary: File = FolderRegister.config.resolve("$configName.json").toFile() +object GuiCategory : ConfigCategory() { + override val name get() = "gui" + override val primaryFile: File = FolderRegistry.config.resolve("$name.json").toFile() } diff --git a/src/main/kotlin/com/lambda/config/categories/HudCategory.kt b/src/main/kotlin/com/lambda/config/categories/HudCategory.kt new file mode 100644 index 000000000..5a0046250 --- /dev/null +++ b/src/main/kotlin/com/lambda/config/categories/HudCategory.kt @@ -0,0 +1,27 @@ +/* + * Copyright 2026 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.categories + +import com.lambda.config.ConfigCategory +import com.lambda.util.FolderRegistry +import java.io.File + +object HudCategory : ConfigCategory() { + override val name get() = "hud" + override val primaryFile: File = FolderRegistry.config.resolve("$name.json").toFile() +} \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/config/categories/LambdaCategory.kt b/src/main/kotlin/com/lambda/config/categories/LambdaCategory.kt new file mode 100644 index 000000000..8851a4c7f --- /dev/null +++ b/src/main/kotlin/com/lambda/config/categories/LambdaCategory.kt @@ -0,0 +1,27 @@ +/* + * Copyright 2026 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.categories + +import com.lambda.config.ConfigCategory +import com.lambda.util.FolderRegistry +import java.io.File + +object LambdaCategory : ConfigCategory() { + override val name get() = "lambda" + override val primaryFile: File = FolderRegistry.config.resolve("$name.json").toFile() +} \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/config/configurations/ModuleConfigs.kt b/src/main/kotlin/com/lambda/config/categories/ModuleCategory.kt similarity index 60% rename from src/main/kotlin/com/lambda/config/configurations/ModuleConfigs.kt rename to src/main/kotlin/com/lambda/config/categories/ModuleCategory.kt index 5f141f170..75eb37f5a 100644 --- a/src/main/kotlin/com/lambda/config/configurations/ModuleConfigs.kt +++ b/src/main/kotlin/com/lambda/config/categories/ModuleCategory.kt @@ -15,24 +15,22 @@ * along with this program. If not, see . */ -package com.lambda.config.configurations +package com.lambda.config.categories -import com.lambda.config.Configuration -import com.lambda.config.configurations.ModuleConfigs.configName -import com.lambda.config.configurations.ModuleConfigs.primary -import com.lambda.util.FolderRegister +import com.lambda.config.ConfigCategory +import com.lambda.config.categories.ModuleCategory.name +import com.lambda.util.FolderRegistry import java.io.File - /** - * The [ModuleConfigs] object represents the configuration file for the [Module]s. + * The [ModuleCategory] object represents the configuration file for the [Module]s. * * This object is used to save and load the settings of all [Module]s in the system. * - * @property configName The name of the configuration. + * @property name The name of the configuration. * @property primary The primary file where the configuration is saved. */ -object ModuleConfigs : Configuration() { - override val configName get() = "modules" - override val primary: File = FolderRegister.config.resolve("$configName.json").toFile() -} +object ModuleCategory : ConfigCategory() { + override val name get() = "modules" + override val primaryFile: File = FolderRegistry.config.resolve("$name.json").toFile() +} \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/config/categories/SecretsCategory.kt b/src/main/kotlin/com/lambda/config/categories/SecretsCategory.kt new file mode 100644 index 000000000..acb6354a3 --- /dev/null +++ b/src/main/kotlin/com/lambda/config/categories/SecretsCategory.kt @@ -0,0 +1,27 @@ +/* + * Copyright 2026 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.categories + +import com.lambda.config.ConfigCategory +import com.lambda.util.FolderRegistry +import java.io.File + +object SecretsCategory : ConfigCategory() { + override val name get() = "secrets" + override val primaryFile: File = FolderRegistry.config.resolve("$name.json").toFile() +} \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/config/configurations/UserAutomationConfigs.kt b/src/main/kotlin/com/lambda/config/categories/UserAutomationCategory.kt similarity index 60% rename from src/main/kotlin/com/lambda/config/configurations/UserAutomationConfigs.kt rename to src/main/kotlin/com/lambda/config/categories/UserAutomationCategory.kt index 14cfb3784..fef2d103b 100644 --- a/src/main/kotlin/com/lambda/config/configurations/UserAutomationConfigs.kt +++ b/src/main/kotlin/com/lambda/config/categories/UserAutomationCategory.kt @@ -15,29 +15,33 @@ * along with this program. If not, see . */ -package com.lambda.config.configurations +package com.lambda.config.categories -import com.google.gson.JsonParser -import com.lambda.config.Configuration -import com.lambda.config.UserAutomationConfig +import com.lambda.Lambda.mapper +import com.lambda.config.ConfigCategory +import com.lambda.config.automation.UserAutomationConfig import com.lambda.module.ModuleRegistry.moduleNameMap import com.lambda.util.FileUtils.ifExists -import com.lambda.util.FolderRegister +import com.lambda.util.FolderRegistry import java.io.File -object UserAutomationConfigs : Configuration() { - override val configName = "custom-automation" - override val primary: File = FolderRegister.config.resolve("${configName}.json").toFile() +object UserAutomationCategory : ConfigCategory() { + override val name get() = "custom_automation" + override val primaryFile: File = FolderRegistry.config.resolve("$name.json").toFile() override fun internalTryLoad() { - primary.ifExists { - JsonParser.parseReader(it.reader()).asJsonObject.entrySet().forEach { (name, _) -> - if (configurables.any { config -> config.name == name }) return@forEach - UserAutomationConfig(name) - } + primaryFile.ifExists { + mapper.readTree(it) + .takeIf { it.isObject } + ?.asObject() + ?.propertyStream() + ?.forEach { (key, _) -> + if (configs.any { config -> config.name == key }) return@forEach + UserAutomationConfig(key) + } } super.internalTryLoad() - configurables.forEach { + configs.forEach { val config = it as? UserAutomationConfig ?: throw IllegalStateException("UserAutomationConfigs contains non-UserAutomationConfig") config.linkedModules.value.forEach { moduleName -> moduleNameMap[moduleName]?.automationConfig = config diff --git a/src/main/kotlin/com/lambda/config/configurations/FriendConfig.kt b/src/main/kotlin/com/lambda/config/configurations/FriendConfig.kt deleted file mode 100644 index f87030db0..000000000 --- a/src/main/kotlin/com/lambda/config/configurations/FriendConfig.kt +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2026 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.configurations - -import com.lambda.config.Configuration -import com.lambda.util.FolderRegister -import java.io.File - -object FriendConfig : Configuration() { - override val configName get() = "friends" - override val primary: File = FolderRegister.config.resolve("$configName.json").toFile() -} diff --git a/src/main/kotlin/com/lambda/config/configurations/SecretsConfig.kt b/src/main/kotlin/com/lambda/config/configurations/SecretsConfig.kt deleted file mode 100644 index 2e695e8d7..000000000 --- a/src/main/kotlin/com/lambda/config/configurations/SecretsConfig.kt +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2026 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.configurations - -import com.lambda.config.Configuration -import com.lambda.util.FolderRegister -import java.io.File - -object SecretsConfig : Configuration() { - override val configName get() = "secrets" - override val primary: File = FolderRegister.config.resolve("$configName.json").toFile() -} diff --git a/src/main/kotlin/com/lambda/config/groups/BreakSettings.kt b/src/main/kotlin/com/lambda/config/groups/BreakSettings.kt deleted file mode 100644 index 9c09ab9c1..000000000 --- a/src/main/kotlin/com/lambda/config/groups/BreakSettings.kt +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright 2026 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.groups - -import com.lambda.config.Configurable -import com.lambda.config.SettingGroup -import com.lambda.config.applyEdits -import com.lambda.event.events.TickEvent -import com.lambda.event.events.TickEvent.Companion.ALL_STAGES -import com.lambda.interaction.managers.breaking.BreakConfig -import com.lambda.interaction.managers.breaking.BreakConfig.AnimationMode -import com.lambda.interaction.managers.breaking.BreakConfig.BreakConfirmationMode -import com.lambda.interaction.managers.breaking.BreakConfig.BreakMode -import com.lambda.interaction.managers.breaking.BreakConfig.SwingMode -import com.lambda.interaction.managers.breaking.BreakConfig.WhitelistMode -import com.lambda.util.NamedEnum -import net.minecraft.registry.Registries -import java.awt.Color - -open class BreakSettings( - c: Configurable, - vararg baseGroup: NamedEnum, - prefix: String = "", - override val visibility: () -> Boolean = { true }, -) : SettingGroup(c), BreakConfig { - enum class Group(override val displayName: String) : NamedEnum { - General("General"), - Cosmetic("Cosmetic") - } - - // General - override val breakMode by c.setting("${prefix}Break Mode", BreakMode.Packet, visibility = visibility).group(*baseGroup, Group.General).index() - override val sorter by c.setting("${prefix}Break Sorter", ActionConfig.SortMode.Tool, "The order in which breaks are performed", visibility = visibility).group(*baseGroup, Group.General).index() - override val rebreak by c.setting("${prefix}Rebreak", true, "Re-breaks blocks after they've been broken once", visibility = visibility).group(*baseGroup, Group.General).index() - - // Double break - override val doubleBreak by c.setting("${prefix}Double Break", true, "Allows breaking two blocks at once", visibility = visibility).group(*baseGroup, Group.General).index() - override val unsafeCancels by c.setting("${prefix}Unsafe Cancels", true, "Allows cancelling block breaking even if the server might continue breaking sever side, potentially causing unexpected state changes") { visibility() && doubleBreak }.group(*baseGroup, Group.General).index() - - // Fixes / Delays - override val breakThreshold by c.setting("${prefix}Break Threshold", 0.70f, 0.1f..1.0f, 0.01f, "The break amount at which the block is considered broken", visibility = visibility).group(*baseGroup, Group.General).index() - override val fudgeFactor by c.setting("${prefix}Fudge Factor", 1, 0..5, 1, "The number of ticks to add to the break time, usually to account for server lag", visibility = visibility).group(*baseGroup, Group.General).index() - override val serverSwapTicks by c.setting("${prefix}Server Swap", 0, 0..5, 1, "The number of ticks to give the server time to recognize the player attributes on the swapped item", " tick(s)", visibility = visibility).group(*baseGroup, Group.General).index() - - // override val desyncFix by c.setting("Desync Fix", false, "Predicts if the players breaking will be slowed next tick as block break packets are processed using the players next position") { vis() && page == Page.General } - override val breakDelay by c.setting("${prefix}Break Delay", 0, 0..6, 1, "The delay between breaking blocks", " tick(s)", visibility = visibility).group(*baseGroup, Group.General).index() - - // Timing - override val tickStageMask by c.setting("${prefix}Break Stage Mask", setOf(TickEvent.Input.Post), ALL_STAGES.toSet(), "The sub-tick timing at which break actions can be performed", displayClassName = true, visibility = visibility).group(*baseGroup, Group.General).index() - - // Swap - override val swapMode by c.setting("${prefix}Break Swap Mode", BreakConfig.SwapMode.End, "Decides when to swap to the best suited tool when breaking a block", visibility = visibility).group(*baseGroup, Group.General).index() - - // Swing - override val swing by c.setting("${prefix}Swing Mode", SwingMode.Constant, "The times at which to swing the players hand", visibility = visibility).group(*baseGroup, Group.General).index() - override val swingType by c.setting("${prefix}Break Swing Type", BuildConfig.SwingType.Vanilla, "The style of swing") { visibility() && swing != SwingMode.None }.group(*baseGroup, Group.General).index() - - // Rotate - override val rotate by c.setting("${prefix}Rotate For Break", false, "Rotate towards block while breaking", visibility = visibility).group(*baseGroup, Group.General).index() - - // Pending / Post - override val breakConfirmation by c.setting("${prefix}Break Confirmation", BreakConfirmationMode.BreakThenAwait, "The style of confirmation used when breaking", visibility = visibility).group(*baseGroup, Group.General).index() - override val breaksPerTick by c.setting("${prefix}Breaks Per Tick", 30, 1..30, 1, "Maximum instant block breaks per tick", visibility = visibility).group(*baseGroup, Group.General).index() - - // Block - override val whitelistMode by c.setting("${prefix}Whitelist Mode", WhitelistMode.None, "The type of block selection used", visibility = visibility).group(*baseGroup, Group.General).index() - override val whitelist by c.setting("${prefix}Whitelist", mutableSetOf(), Registries.BLOCK.toMutableSet(), "Only these selected blocks are allowed to be broken") { visibility() && whitelistMode == WhitelistMode.Whitelist }.group(*baseGroup, Group.General).index() - override val blacklist by c.setting("${prefix}Blacklist", mutableSetOf(), Registries.BLOCK.toMutableSet(), "These selected blocks are not allowed to be broken") { visibility() && whitelistMode == WhitelistMode.Blacklist }.group(*baseGroup, Group.General).index() - override val avoidFluids by c.setting("${prefix}Avoid Fluids", true, "Avoids breaking blocks that would cause fluids to spill", visibility = visibility).group(*baseGroup, Group.General).index() - override val avoidSupporting by c.setting("${prefix}Avoid Supporting", true, "Avoids breaking the block supporting the player", visibility = visibility).group(*baseGroup, Group.General).index() - override val fillFluids by c.setting("Fill Fluids", true, "Fills fluids in order to break blocks that would initially spill them") { visibility() && avoidFluids }.group(*baseGroup, Group.General).index() - // Tool - override val efficientOnly by c.setting("${prefix}Efficient Tools Only", true, "Only use tools suitable for the given block (will get the item drop)") { visibility() && swapMode.isEnabled() }.group(*baseGroup, Group.General).index() - override val suitableToolsOnly by c.setting("${prefix}Suitable Tools Only", true, "Only use tools suitable for the given block (will get the item drop)") { visibility() && swapMode.isEnabled() }.group(*baseGroup, Group.General).index() - override val forceSilkTouch by c.setting("${prefix}Force Silk Touch", false, "Force silk touch when breaking blocks") { visibility() && swapMode.isEnabled() }.group(*baseGroup, Group.General).index() - override val forceFortunePickaxe by c.setting("${prefix}Force Fortune Pickaxe", false, "Force fortune pickaxe when breaking blocks") { visibility() && swapMode.isEnabled() }.group(*baseGroup, Group.General).index() - override val minFortuneLevel by c.setting("${prefix}Min Fortune Level", 1, 1..3, 1, "The minimum fortune level to use") { visibility() && swapMode.isEnabled() && forceFortunePickaxe }.group(*baseGroup, Group.General).index() - - // Cosmetics - override val sounds by c.setting("${prefix}Break Sounds", true, "Plays the breaking sounds", visibility = visibility).group(*baseGroup, Group.Cosmetic).index() - override val particles by c.setting("${prefix}Particles", true, "Renders the breaking particles", visibility = visibility).group(*baseGroup, Group.Cosmetic).index() - override val breakingTexture by c.setting("${prefix}Breaking Overlay", true, "Overlays the breaking texture at its different stages", visibility = visibility).group(*baseGroup, Group.Cosmetic).index() - - // Modes - override val renders by c.setting("${prefix}Renders", true, "Enables the render settings for breaking progress", visibility = visibility).group(*baseGroup, Group.Cosmetic).index() - override val animation by c.setting("${prefix}Animation", AnimationMode.Out, "The style of animation used for the box") { visibility() && renders }.group(*baseGroup, Group.Cosmetic).index() - - // Fill - override val fill by c.setting("${prefix}Fill", true, "Renders the sides of the box to display break progress") { visibility() && renders }.group(*baseGroup, Group.Cosmetic).index() - override val dynamicFillColor by c.setting("${prefix}Dynamic Colour", true, "Enables fill color interpolation from start to finish for fill when breaking a block") { visibility() && renders && fill }.group(*baseGroup, Group.Cosmetic).index() - override val staticFillColor by c.setting("${prefix}Fill Color", Color(255, 0, 0, 60).brighter(), "The color of the fill") { visibility() && renders && !dynamicFillColor && fill }.group(*baseGroup, Group.Cosmetic).index() - override val startFillColor by c.setting("${prefix}Start Fill Color", Color(255, 0, 0, 60).brighter(), "The color of the fill at the start of breaking") { visibility() && renders && dynamicFillColor && fill }.group(*baseGroup, Group.Cosmetic).index() - override val endFillColor by c.setting("${prefix}End Fill Color", Color(0, 255, 0, 60).brighter(), "The color of the fill at the end of breaking") { visibility() && renders && dynamicFillColor && fill }.group(*baseGroup, Group.Cosmetic).index() - - // Outline - override val outline by c.setting("${prefix}Outline", true, "Renders the lines of the box to display break progress") { visibility() && renders }.group(*baseGroup, Group.Cosmetic).index() - override val outlineConfig = WorldLineSettings(c, *baseGroup, Group.Cosmetic, prefix = "${prefix}Outline ") { visibility() && outline }.apply { - c.applyEdits { - hide(::startColor, ::endColor) - } - } - override val dynamicOutlineColor by c.setting("${prefix}Dynamic Outline Color", true, "Enables color interpolation from start to finish for the outline when breaking a block") { visibility() && renders && outline }.group(*baseGroup, Group.Cosmetic).index() - override val staticOutlineColor by c.setting("${prefix}Outline Color", Color.RED.brighter(), "The Color of the outline at the start of breaking") { visibility() && renders && !dynamicOutlineColor && outline }.group(*baseGroup, Group.Cosmetic).index() - override val startOutlineColor by c.setting("${prefix}Start Outline Color", Color.RED.brighter(), "The color of the outline at the start of breaking") { visibility() && renders && dynamicOutlineColor && outline }.group(*baseGroup, Group.Cosmetic).index() - override val endOutlineColor by c.setting("${prefix}End Outline Color", Color.GREEN.brighter(), "The color of the outline at the end of breaking") { visibility() && renders && dynamicOutlineColor && outline }.group(*baseGroup, Group.Cosmetic).index() -} diff --git a/src/main/kotlin/com/lambda/config/groups/BuildSettings.kt b/src/main/kotlin/com/lambda/config/groups/BuildSettings.kt deleted file mode 100644 index 3f3262f45..000000000 --- a/src/main/kotlin/com/lambda/config/groups/BuildSettings.kt +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright 2026 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.groups - -import com.lambda.config.Configurable -import com.lambda.config.SettingGroup -import com.lambda.interaction.managers.rotating.visibilty.PointSelection -import com.lambda.util.NamedEnum -import kotlin.math.max - -class BuildSettings( - c: Configurable, - vararg baseGroup: NamedEnum, - prefix: String = "", - override val visibility: () -> Boolean = { true }, -) : SettingGroup(c), BuildConfig { - enum class Group(override val displayName: String) : NamedEnum { - General("General"), - PacketLimits("Packet Limits"), - Reach("Reach"), - Scan("Scan") - } - - override val breakBlocks by c.setting("${prefix}Break", true, "Break blocks", visibility = visibility).group(*baseGroup, Group.General).index() - override val placeBlocks by c.setting("${prefix}Place", true, "Place blocks", visibility = visibility).group(*baseGroup, Group.General).index() - override val interactBlocks by c.setting("${prefix}Interact", true, "Interact blocks", visibility = visibility).group(*baseGroup, Group.General).index() - - override val pathing by c.setting("${prefix}Pathing", false, "Path to blocks", visibility = visibility).group(*baseGroup, Group.General).index() - override val stayInRange by c.setting("${prefix}Stay In Range", false, "Stay in range of blocks", visibility = visibility).group(*baseGroup, Group.General).index() - override val collectDrops by c.setting("${prefix}Collect All Drops", false, "Collect all drops when breaking blocks", visibility = visibility).group(*baseGroup, Group.General).index() - override val spleefEntities by c.setting("${prefix}Spleef Entities", false, "Breaks blocks beneath entities blocking placements to get them out of the way", visibility = visibility).group(*baseGroup, Group.General).index() - override val maxPendingActions by c.setting("${prefix}Max Pending Actions", 15, 1..30, 1, "The maximum count of pending interactions to allow before pausing future interactions", visibility = visibility).group(*baseGroup, Group.General).index() - override val actionTimeout by c.setting("${prefix}Action Timeout", 10, 1..30, 1, "Timeout for block breaks in ticks", unit = " ticks", visibility = visibility).group(*baseGroup, Group.General).index() - override val maxBuildDependencies by c.setting("${prefix}Max Sim Dependencies", 3, 0..10, 1, "Maximum dependency build results", visibility = visibility).group(*baseGroup, Group.General).index() - - override val limitTimeframe by c.setting("${prefix}Limit Timeframe", 310, 50..1500, 1, "The timeframe in which the limit is bound to", "ms", visibility = visibility).group(*baseGroup, Group.PacketLimits).index() - override val actionLimit by c.setting("${prefix}Action Limit", 59, 1..100, 1, "The maximum allowed action packets to be sent to the server per given timeframe", visibility = visibility).group(*baseGroup, Group.PacketLimits).index() - override val interactionLimit by c.setting("${prefix}Interaction Limit", 9, 1..20, 1, "The maximum allowed interaction packets to be sent to the server per given timeframe", visibility = visibility).group(*baseGroup, Group.PacketLimits).index() - override val inventoryLimit by c.setting("${prefix}Inventory Limit", 5, 1..100, 1, "The maximum allowed inventory packets to be sent to the server per given timeframe", visibility = visibility).group(*baseGroup, Group.PacketLimits).index() - - override var blockReach by c.setting("${prefix}Interact Reach", 4.5, 1.0..7.0, 0.01, "Maximum block interaction distance", visibility = visibility).group(*baseGroup, Group.Reach).index() - override var entityReach by c.setting("${prefix}Attack Reach", 3.0, 1.0..7.0, 0.01, "Maximum entity interaction distance", visibility = visibility).group(*baseGroup, Group.Reach).index() - override val scanReach: Double get() = max(entityReach, blockReach) - - override val checkSideVisibility by c.setting("${prefix}Visibility Check", false, "Whether to check if an AABB side is visible", visibility = visibility).group(*baseGroup, Group.Scan).index() - override val strictRayCast by c.setting("${prefix}Strict Raycast", false, "Whether to include the environment to the ray cast context", visibility = visibility).group(*baseGroup, Group.Scan).index() - override val resolution by c.setting("${prefix}Resolution", 5, 1..20, 1, "The amount of grid divisions per surface of the hit box", "") { visibility() && strictRayCast }.group(*baseGroup, Group.Scan).index() - override val pointSelection by c.setting("${prefix}Point Selection", PointSelection.Optimum, "The strategy to select the best hit point", visibility = visibility).group(*baseGroup, Group.Scan).index() -} diff --git a/src/main/kotlin/com/lambda/config/groups/EatSettings.kt b/src/main/kotlin/com/lambda/config/groups/EatSettings.kt deleted file mode 100644 index 58fbe341a..000000000 --- a/src/main/kotlin/com/lambda/config/groups/EatSettings.kt +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2026 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.groups - -import com.lambda.config.Configurable -import com.lambda.config.SettingGroup -import com.lambda.util.NamedEnum -import net.minecraft.item.Items - -class EatSettings( - c: Configurable, - vararg baseGroup: NamedEnum, - prefix: String = "", - override val visibility: () -> Boolean = { true }, -) : SettingGroup(c), EatConfig { - val nutritiousFoodDefaults = listOf(Items.APPLE, Items.BAKED_POTATO, Items.BEEF, Items.BEETROOT, Items.BEETROOT_SOUP, Items.BREAD, Items.CARROT, Items.CHICKEN, Items.CHORUS_FRUIT, Items.COD, Items.COOKED_BEEF, Items.COOKED_CHICKEN, Items.COOKED_COD, Items.COOKED_MUTTON, Items.COOKED_PORKCHOP, Items.COOKED_RABBIT, Items.COOKED_SALMON, Items.COOKIE, Items.DRIED_KELP, Items.ENCHANTED_GOLDEN_APPLE, Items.GOLDEN_APPLE, Items.GOLDEN_CARROT, Items.HONEY_BOTTLE, Items.MELON_SLICE, Items.MUSHROOM_STEW, Items.MUTTON, Items.POISONOUS_POTATO, Items.PORKCHOP, Items.POTATO, Items.PUFFERFISH, Items.PUMPKIN_PIE, Items.RABBIT, Items.RABBIT_STEW, Items.ROTTEN_FLESH, Items.SALMON, Items.SPIDER_EYE, Items.SUSPICIOUS_STEW, Items.SWEET_BERRIES, Items.GLOW_BERRIES, Items.TROPICAL_FISH) - val resistanceFoodDefaults = listOf(Items.ENCHANTED_GOLDEN_APPLE) - val regenerationFoodDefaults = listOf(Items.ENCHANTED_GOLDEN_APPLE, Items.GOLDEN_APPLE) - val negativeFoodDefaults = listOf(Items.CHICKEN, Items.POISONOUS_POTATO, Items.PUFFERFISH, Items.ROTTEN_FLESH, Items.SPIDER_EYE) - - override val eatOnHunger by c.setting("${prefix}Eat On Hunger", true, "Whether to eat when hungry", visibility = visibility).group(*baseGroup).index() - override val minFoodLevel by c.setting("${prefix}Minimum Food Level", 6, 0..20, 1, "The minimum food level to eat food", " food level") { visibility() && eatOnHunger }.group(*baseGroup).index() - override val saturated by c.setting("${prefix}Saturated", EatConfig.Saturation.EatSmart, "When to stop eating") { visibility() && eatOnHunger }.group(*baseGroup).index() - override val nutritiousFood by c.setting("${prefix}Nutritious Food", nutritiousFoodDefaults, nutritiousFoodDefaults, "Items that are be considered nutritious") { visibility() && eatOnHunger }.group(*baseGroup).index() - override val selectionPriority by c.setting("${prefix}Selection Priority", EatConfig.SelectionPriority.MostNutritious, "The priority for selecting food items") { visibility() && eatOnHunger }.group(*baseGroup).index() - override val eatOnFire by c.setting("${prefix}Eat On Fire", true, "Whether to eat when on fire", visibility = visibility).group(*baseGroup).index() - override val resistanceFood by c.setting("${prefix}Resistance Food", resistanceFoodDefaults, resistanceFoodDefaults, "Items that give Fire Resistance") { visibility() && eatOnFire }.group(*baseGroup).index() - override val eatOnDamage by c.setting("${prefix}Eat On Damage", true, "Whether to eat when damaged", visibility = visibility).group(*baseGroup).index() - override val minDamage by c.setting("${prefix}Minimum Damage", 10, 0..20, 1, "The minimum damage threshold to trigger eating") { visibility() && eatOnDamage }.group(*baseGroup).index() - override val regenerationFood by c.setting("${prefix}Regeneration Food", regenerationFoodDefaults, regenerationFoodDefaults, "Items that give Regeneration") { visibility() && eatOnDamage }.group(*baseGroup).index() - override val ignoreBadFood by c.setting("${prefix}Ignore Bad Food", true, "Whether to eat when the food is bad", visibility = visibility).group(*baseGroup).index() - override val badFood by c.setting("${prefix}Bad Food", negativeFoodDefaults, negativeFoodDefaults, "Items that are considered bad food") { visibility() && ignoreBadFood }.group(*baseGroup).index() -} \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/config/groups/EntityColorSettings.kt b/src/main/kotlin/com/lambda/config/groups/EntityColorSettings.kt deleted file mode 100644 index f6f7aed07..000000000 --- a/src/main/kotlin/com/lambda/config/groups/EntityColorSettings.kt +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright 2026 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.groups - -import com.lambda.config.Configurable -import com.lambda.config.SettingGroup -import com.lambda.context.SafeContext -import com.lambda.friend.FriendManager.isFriend -import com.lambda.util.EntityUtils -import com.lambda.util.EntityUtils.entityGroup -import com.lambda.util.NamedEnum -import com.lambda.util.extension.blockColor -import com.lambda.util.extension.entityColor -import com.lambda.util.math.dist -import com.lambda.util.math.lerp -import net.minecraft.block.entity.BlockEntity -import net.minecraft.client.network.OtherClientPlayerEntity -import net.minecraft.entity.Entity -import java.awt.Color - -class EntityColorSettings( - c: Configurable, - vararg baseGroup: NamedEnum, - prefix: String = "", - override val visibility: () -> Boolean = { true }, -) : EntityColorsConfig, SettingGroup(c) { - override val useNaturalColors by c.setting("${prefix}Use Natural Colors", false, "Uses an average color from the entities texture").group(*baseGroup).index() - override val playerColor by c.setting("${prefix}Player Color", Color(255, 50, 50)) { !useNaturalColors }.group(*baseGroup).index() - override val playerDistanceGradient by c.setting("${prefix}Player Distance Gradient", true).group(*baseGroup).index() - override val playerDistanceColorFar by c.setting("${prefix}Player Far Color", Color.GREEN) { playerDistanceGradient }.group(*baseGroup).index() - override val playerDistanceColorClose by c.setting("${prefix}Player Close Color", Color.RED) { playerDistanceGradient }.group(*baseGroup).index() - override val separateFriendColor by c.setting("${prefix}Separate Friend Color", true) { useNaturalColors }.group(*baseGroup).index() - override val friendColor by c.setting("${prefix}Friend Color", Color(0, 255, 255)) { !useNaturalColors || separateFriendColor }.group(*baseGroup).index() - override val mobColor by c.setting("${prefix}Mob Color", Color(255, 70, 50)) { !useNaturalColors }.group(*baseGroup).index() - override val passiveColor by c.setting("${prefix}Passive Color", Color(0, 255, 0)) { !useNaturalColors }.group(*baseGroup).index() - override val vehicleColor by c.setting("${prefix}Vehicle Color", Color(200, 150, 100)) { !useNaturalColors }.group(*baseGroup).index() - override val projectileColor by c.setting("${prefix}Projectile Color", Color(200, 200, 200)) { !useNaturalColors }.group(*baseGroup).index() - override val bossColor by c.setting("${prefix}Boss Color", Color(255, 100, 0)) { !useNaturalColors }.group(*baseGroup).index() - override val decorationColor by c.setting("${prefix}Decoration Color", Color(100, 100, 255)) { !useNaturalColors }.group(*baseGroup).index() - override val blockColor by c.setting("${prefix}Block Color", Color(200, 200, 200)) { !useNaturalColors }.group(*baseGroup).index() - override val miscColor by c.setting("${prefix}Misc Color", Color(255, 0, 255)) { !useNaturalColors }.group(*baseGroup).index() - - context(safeContext: SafeContext) - fun getColor(entity: Entity): Color { - val group = entity.entityGroup - return if (useNaturalColors && !hasSpecialCase(entity, group)) entityColor(entity) - else when (group) { - EntityUtils.EntityGroup.Player -> - when { - entity is OtherClientPlayerEntity && entity.isFriend && separateFriendColor -> friendColor - else -> - if (playerDistanceGradient) - lerp( - entity.dist(safeContext.player) / 60.0, - playerDistanceColorClose, - playerDistanceColorFar - ) - else playerColor - } - EntityUtils.EntityGroup.Mob -> mobColor - EntityUtils.EntityGroup.Passive -> passiveColor - EntityUtils.EntityGroup.Vehicle -> vehicleColor - EntityUtils.EntityGroup.Projectile -> projectileColor - EntityUtils.EntityGroup.Boss -> bossColor - EntityUtils.EntityGroup.Decoration -> decorationColor - else -> miscColor - } - } - - context(safeContext: SafeContext) - fun getColor(blockEntity: BlockEntity): Color = - if (useNaturalColors) safeContext.blockColor(blockEntity.cachedState, blockEntity.pos) - else blockColor - - private fun hasSpecialCase(entity: Entity, group: EntityUtils.EntityGroup) = - group == EntityUtils.EntityGroup.Player && - ((entity is OtherClientPlayerEntity && entity.isFriend && separateFriendColor) || playerDistanceGradient) -} \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/config/groups/EntitySelectionSettings.kt b/src/main/kotlin/com/lambda/config/groups/EntitySelectionSettings.kt deleted file mode 100644 index dbd293ff5..000000000 --- a/src/main/kotlin/com/lambda/config/groups/EntitySelectionSettings.kt +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright 2026 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.groups - -import com.lambda.Lambda.mc -import com.lambda.config.Configurable -import com.lambda.config.SettingGroup -import com.lambda.util.EntityUtils.blockEntityMap -import com.lambda.util.EntityUtils.bossEntityMap -import com.lambda.util.EntityUtils.decorationEntityMap -import com.lambda.util.EntityUtils.miscEntityMap -import com.lambda.util.EntityUtils.mobEntityMap -import com.lambda.util.EntityUtils.passiveEntityMap -import com.lambda.util.EntityUtils.playerEntityMap -import com.lambda.util.EntityUtils.projectileEntityMap -import com.lambda.util.EntityUtils.vehicleEntityMap -import com.lambda.util.NamedEnum -import net.minecraft.block.entity.BlockEntity -import net.minecraft.entity.Entity -import net.minecraft.entity.SpawnGroup - -class EntitySelectionSettings( - c: Configurable, - vararg baseGroup: NamedEnum, - prefix: String = "", - override val visibility: () -> Boolean = { true }, -) : EntitySelectionConfig, SettingGroup(c) { - override val self by c.setting("${prefix}Self", false, "Render own player in third person").group(*baseGroup).index() - override val enablePlayerEntities by c.setting("${prefix}Enable Player Entities", true).group(*baseGroup).index() - override val playerEntities by c.setting("${prefix}Player Entities", playerEntityMap.values.toSet(), playerEntityMap.values.toSet(), "Player entities to omit from rendering") { enablePlayerEntities }.group(*baseGroup).index() - override val enableMobEntities by c.setting("${prefix}Enable Mob Entities", true).group(*baseGroup).index() - override val mobEntities by c.setting("${prefix}Mob Entities", mobEntityMap.values.toSet(), mobEntityMap.values.toSet(), "Mob entities to omit from rendering") { enableMobEntities }.group(*baseGroup).index() - override val enablePassiveEntities by c.setting("${prefix}Enable Passive Entities", true).group(*baseGroup).index() - override val passiveEntities by c.setting("${prefix}Passive Entities", emptySet(), passiveEntityMap.values.toSet(), "Passive entities to omit from rendering") { enablePassiveEntities }.group(*baseGroup).index() - override val enableVehicleEntities by c.setting("${prefix}Enable Vehicle Entities", true).group(*baseGroup).index() - override val vehicleEntities by c.setting("${prefix}Vehicle Entities", emptySet(), vehicleEntityMap.values.toSet(), "Vehicle entities to omit from rendering") { enableVehicleEntities }.group(*baseGroup).index() - override val enableProjectileEntities by c.setting("${prefix}Enable Projectile Entities", true).group(*baseGroup).index() - override val projectileEntities by c.setting("${prefix}Projectile Entities", emptySet(), projectileEntityMap.values.toSet(), "Projectile entities to omit from rendering") { enableProjectileEntities }.group(*baseGroup).index() - override val enableBossEntities by c.setting("${prefix}Enable Boss Entities", true).group(*baseGroup).index() - override val bossEntities by c.setting("${prefix}Boss Entities", bossEntityMap.values.toSet(), bossEntityMap.values.toSet(), "Boss entities to omit from rendering") { enableBossEntities }.group(*baseGroup).index() - override val enableDecorationEntities by c.setting("${prefix}Enable Decoration Entities", true).group(*baseGroup).index() - override val decorationEntities by c.setting("${prefix}Decoration Entities", emptySet(), decorationEntityMap.values.toSet(), "Decoration entities to omit from rendering") { enableDecorationEntities }.group(*baseGroup).index() - override val enableBlockEntities by c.setting("${prefix}Enable Block Entities", true).group(*baseGroup).index() - override val blockEntities by c.setting("${prefix}Block Entities", emptySet(), blockEntityMap.values.toSet(), "Block entities to omit from rendering") { enableBlockEntities }.group(*baseGroup).index() - override val enableMiscEntities by c.setting("${prefix}Enable Misc Entities", true).group(*baseGroup).index() - override val miscEntities by c.setting("${prefix}Misc Entities", emptySet(), miscEntityMap.values.toSet(), "Miscellaneous entities to omit from rendering") { enableMiscEntities }.group(*baseGroup).index() - - fun isSelected(entity: Entity): Boolean { - val name = entity::class.simpleName - return if (entity == mc.player) self - else when (entity.type.spawnGroup) { - SpawnGroup.MISC -> - (enableMiscEntities && miscEntityMap[name] in miscEntities) || - (enablePlayerEntities && playerEntityMap[name] in playerEntities) || - (enableProjectileEntities && projectileEntityMap[name] in projectileEntities) || - (enableVehicleEntities && vehicleEntityMap[name] in vehicleEntities) || - (enableDecorationEntities && decorationEntityMap[name] in decorationEntities) || - (enablePassiveEntities && passiveEntityMap[name] in passiveEntities) || - (enableMobEntities && mobEntityMap[name] in mobEntities) || - (enableBossEntities && bossEntityMap[name] in bossEntities) - SpawnGroup.WATER_AMBIENT, - SpawnGroup.WATER_CREATURE, - SpawnGroup.AMBIENT, - SpawnGroup.AXOLOTLS, - SpawnGroup.CREATURE, - SpawnGroup.UNDERGROUND_WATER_CREATURE -> (enablePassiveEntities && passiveEntityMap[name] in passiveEntities) - SpawnGroup.MONSTER -> - (enableMobEntities && mobEntityMap[name] in mobEntities) || - (enableBossEntities && bossEntityMap[name] in bossEntities) - } - } - - fun isSelected(blockEntity: BlockEntity) = - (enableBlockEntities && blockEntityMap[blockEntity.javaClass.simpleName] in blockEntities) -} \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/config/groups/FormatterSettings.kt b/src/main/kotlin/com/lambda/config/groups/FormatterSettings.kt deleted file mode 100644 index 0f847073e..000000000 --- a/src/main/kotlin/com/lambda/config/groups/FormatterSettings.kt +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2026 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.groups - -import com.lambda.config.Configurable -import com.lambda.config.SettingGroup -import com.lambda.util.NamedEnum - -class FormatterSettings( - c: Configurable, - vararg baseGroup: NamedEnum, - prefix: String = "", - override val visibility: () -> Boolean = { true }, -) : FormatterConfig, SettingGroup(c) { - val localeEnum by c.setting("${prefix}Locale", FormatterConfig.Locales.US, "The regional formatting used for numbers", visibility = visibility).group(*baseGroup).index() - override val locale get() = localeEnum.locale - - val sep by c.setting("${prefix}Separator", FormatterConfig.TupleSeparator.Comma, "Separator for string serialization of tuple data structures", visibility = visibility).group(*baseGroup).index() - val customSep by c.setting("${prefix}Custom Separator", "") { visibility() && sep == FormatterConfig.TupleSeparator.Custom }.group(*baseGroup).index() - override val separator get() = if (sep == FormatterConfig.TupleSeparator.Custom) customSep else sep.separator - - val group by c.setting("${prefix}Tuple Prefix", FormatterConfig.TupleGrouping.Parentheses, visibility = visibility).group(*baseGroup).index() - override val prefix get() = group.prefix - override val postfix get() = group.postfix - - val floatingPrecision by c.setting("${prefix}Floating Precision", 3, 0..6, 1, "Precision for floating point numbers", visibility = visibility).group(*baseGroup).index() - override val precision get() = floatingPrecision - - val timeFormat by c.setting("${prefix}Time Format", FormatterConfig.Time.IsoDateTime, visibility = visibility).group(*baseGroup).index() - override val format get() = timeFormat.format -} \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/config/groups/HotbarSettings.kt b/src/main/kotlin/com/lambda/config/groups/HotbarSettings.kt deleted file mode 100644 index d424f79df..000000000 --- a/src/main/kotlin/com/lambda/config/groups/HotbarSettings.kt +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2026 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.groups - -import com.lambda.config.Configurable -import com.lambda.config.SettingGroup -import com.lambda.event.events.TickEvent -import com.lambda.event.events.TickEvent.Companion.ALL_STAGES -import com.lambda.interaction.managers.hotbar.HotbarConfig -import com.lambda.util.NamedEnum - -class HotbarSettings( - c: Configurable, - vararg baseGroup: NamedEnum, - prefix: String = "", - override val visibility: () -> Boolean = { true }, -) : SettingGroup(c), HotbarConfig { - override val swapMode by c.setting("${prefix}Swap Mode", HotbarConfig.SwapMode.Temporary, visibility = visibility).group(*baseGroup).index() - override val keepTicks by c.setting("${prefix}Keep Ticks", 1, 0..20, 1, "The number of ticks to keep the current hotbar selection active", " ticks") { visibility() && swapMode == HotbarConfig.SwapMode.Temporary }.group(*baseGroup).index() - override val swapDelay by c.setting("${prefix}Swap Delay", 0, 0..3, 1, "The number of ticks delay before allowing another hotbar selection swap", " ticks", visibility = visibility).group(*baseGroup).index() - override val swapsPerTick by c.setting("${prefix}Swaps Per Tick", 3, 1..10, 1, "The number of hotbar selection swaps that can take place each tick") { visibility() && swapDelay <= 0 }.group(*baseGroup).index() - override val swapPause by c.setting("${prefix}Swap Pause", 0, 0..20, 1, "The delay in ticks to pause actions after switching to the slot", " ticks", visibility = visibility).group(*baseGroup).index() - override val tickStageMask by c.setting("${prefix}Hotbar Stage Mask", setOf(TickEvent.Input.Post), ALL_STAGES.toSet(), "The sub-tick timing at which hotbar actions are performed", displayClassName = true, visibility = visibility).group(*baseGroup).index() -} \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/config/groups/InteractSettings.kt b/src/main/kotlin/com/lambda/config/groups/InteractSettings.kt deleted file mode 100644 index 5759cdbfe..000000000 --- a/src/main/kotlin/com/lambda/config/groups/InteractSettings.kt +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2026 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.groups - -import com.lambda.config.Configurable -import com.lambda.config.SettingGroup -import com.lambda.event.events.TickEvent -import com.lambda.event.events.TickEvent.Companion.ALL_STAGES -import com.lambda.interaction.managers.interacting.InteractConfig -import com.lambda.interaction.managers.interacting.InteractConfig.AirPlaceMode -import com.lambda.interaction.managers.interacting.InteractConfig.InteractConfirmationMode -import com.lambda.util.NamedEnum - -class InteractSettings( - c: Configurable, - vararg baseGroup: NamedEnum, - prefix: String = "", - override val visibility: () -> Boolean = { true }, -) : SettingGroup(c), InteractConfig { - override val rotate by c.setting("${prefix}Rotate For Interact", true, "Rotate towards block while placing", visibility = visibility).group(*baseGroup).index() - override val airPlace by c.setting("${prefix}Air Place", AirPlaceMode.Grim, "Allows for placing blocks without adjacent faces", visibility = visibility).group(*baseGroup).index() - override val axisRotateSetting by c.setting("${prefix}Axis Rotate", true, "Overrides the Rotate For Place setting and rotates the player on each axis to air place rotational blocks") { visibility() && airPlace.isEnabled }.group(*baseGroup).index() - override val sorter by c.setting("${prefix}Interaction Sorter", ActionConfig.SortMode.Tool, "The order in which placements are performed", visibility = visibility).group(*baseGroup).index() - override val tickStageMask by c.setting("${prefix}Interaction Stage Mask", setOf(TickEvent.Input.Post), ALL_STAGES.toSet(), "The sub-tick timing at which place actions are performed", displayClassName = true, visibility = visibility).group(*baseGroup).index() - override val interactConfirmationMode by c.setting("${prefix}Interact Confirmation", InteractConfirmationMode.PlaceThenAwait, "Wait for block placement confirmation", visibility = visibility).group(*baseGroup).index() - override val interactDelay by c.setting("${prefix}Interact Delay", 0, 0..3, 1, "Tick delay between interacting with another block", visibility = visibility).group(*baseGroup).index() - override val interactionsPerTick by c.setting("${prefix}Interactions Per Tick", 9, 1..30, 1, "Maximum instant block places per tick", visibility = visibility).group(*baseGroup).index() - override val swing by c.setting("${prefix}Swing On Interact", true, "Swings the players hand when placing", visibility = visibility).group(*baseGroup).index() - override val swingType by c.setting("${prefix}Interact Swing Type", BuildConfig.SwingType.Vanilla, "The style of swing") { visibility() && swing }.group(*baseGroup).index() - override val sounds by c.setting("${prefix}Place Sounds", true, "Plays the placing sounds", visibility = visibility).group(*baseGroup).index() -} \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/config/groups/InventorySettings.kt b/src/main/kotlin/com/lambda/config/groups/InventorySettings.kt deleted file mode 100644 index 6b4fac6c9..000000000 --- a/src/main/kotlin/com/lambda/config/groups/InventorySettings.kt +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2026 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.groups - -import com.lambda.config.Configurable -import com.lambda.config.SettingGroup -import com.lambda.event.events.TickEvent.Companion.ALL_STAGES -import com.lambda.interaction.managers.inventory.InventoryConfig -import com.lambda.util.NamedEnum -import com.lambda.util.item.ItemUtils - -class InventorySettings( - c: Configurable, - vararg baseGroup: NamedEnum, - prefix: String = "", - override val visibility: () -> Boolean = { true }, -) : SettingGroup(c), InventoryConfig { - enum class Group(override val displayName: String) : NamedEnum { - General("General"), - Container("Container"), - Access("Access") - } - - override val tickStageMask by c.setting("${prefix}Inventory Stage Mask", ALL_STAGES.toSet(), description = "The sub-tick timing at which inventory actions are performed", displayClassName = true, visibility = visibility).group(*baseGroup, Group.General).index() - override val disposables by c.setting("${prefix}Disposables", ItemUtils.defaultDisposables, description = "Items that will be ignored when checking for a free slot", visibility = visibility).group(*baseGroup, Group.Container).index() - override val swapWithDisposables by c.setting("${prefix}Swap With Disposables", true, "Swap items with disposable ones", visibility = visibility).group(*baseGroup, Group.Container).index() - override val providerPriority by c.setting("${prefix}Provider Priority", InventoryConfig.Priority.WithMinItems, "What container to prefer when retrieving the item from", visibility = visibility).group(*baseGroup, Group.Container).index() - override val storePriority by c.setting("${prefix}Store Priority", InventoryConfig.Priority.WithMinItems, "What container to prefer when storing the item to", visibility = visibility).group(*baseGroup, Group.Container).index() - - override val accessShulkerBoxes by c.setting("${prefix}Access Shulker Boxes", false, "Allow access to the player's shulker boxes", visibility = visibility).group(*baseGroup, Group.Access).index() - override val accessChests by c.setting("${prefix}Access Chests", false, "Allow access to the player's normal chests", visibility = visibility).group(*baseGroup, Group.Access).index() - override val accessEnderChest by c.setting("${prefix}Access Ender Chest", false, "Allow access to the player's ender chest", visibility = visibility).group(*baseGroup, Group.Access).index() - override val accessStashes by c.setting("${prefix}Access Stashes", false, "Allow access to the player's stashes", visibility = visibility).group(*baseGroup, Group.Access).index() -} \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/config/groups/OutlineSettings.kt b/src/main/kotlin/com/lambda/config/groups/OutlineSettings.kt deleted file mode 100644 index 8a21b7723..000000000 --- a/src/main/kotlin/com/lambda/config/groups/OutlineSettings.kt +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2026 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.groups - -import com.lambda.config.Configurable -import com.lambda.config.SettingGroup -import com.lambda.graphics.outline.OutlineStyle -import com.lambda.util.NamedEnum -import java.awt.Color - -class OutlineSettings( - c: Configurable, - vararg baseGroup: NamedEnum, - prefix: String = "", - override val visibility: () -> Boolean = { true }, -) : SettingGroup(c) { - val thicknessSetting by c.setting("${prefix}Line Width", 25, 1..100, 1, "The width of the outline", visibility = visibility).group(*baseGroup).index() - val thickness get() = thicknessSetting * 0.00005f - - val glowIntensitySetting by c.setting("${prefix}Glow Intensity", 50, 0..100, 1, "Intensity of the outline glow", visibility = visibility).group(*baseGroup).index() - val glowIntensity get() = glowIntensitySetting * 0.01f - - val glowRadiusSetting by c.setting("${prefix}Glow Radius", 20, 0..100, 1, "Radius of the outline glow", visibility = visibility).group(*baseGroup).index() - val glowRadius get() = glowRadiusSetting * 0.00005f - - val fill by c.setting("${prefix}Fill", true, "Fill the entity silhouette", visibility = visibility).group(*baseGroup).index() - - val fillOpacitySetting by c.setting("${prefix}Fill Opacity", 10, 0..100, 1, "Opacity of the fill") { visibility() && fill }.group(*baseGroup).index() - val fillOpacity get() = fillOpacitySetting * 0.01f - - fun toStyle(color: Color) = OutlineStyle( - color = color, - thickness = thickness, - glowIntensity = glowIntensity, - glowRadius = glowRadius, - fill = fill, - fillOpacity = fillOpacity - ) -} diff --git a/src/main/kotlin/com/lambda/config/groups/ReplaceConfig.kt b/src/main/kotlin/com/lambda/config/groups/ReplaceConfig.kt deleted file mode 100644 index e1aa35969..000000000 --- a/src/main/kotlin/com/lambda/config/groups/ReplaceConfig.kt +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2026 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.groups - -import com.lambda.util.Describable - -interface ReplaceConfig { - val action: ActionStrategy - val replace: ReplaceStrategy - - val enabled: Boolean get() = action != ActionStrategy.None - - enum class ActionStrategy(override val description: String) : Describable { - Hide("Hides the message. Will override other strategies."), - Delete("Deletes the matching part off the message."), - Replace("Replace the matching string in the message with one of the following replace strategy."), - None("Don't do anything."), - } - - enum class ReplaceStrategy(val block: (String) -> String) { - CensorAll({ it.replaceRange(0.. if (i % 2 == 0) acc + char else "$acc*" } }), - KeepFirst({ if (it.length <= 1) it else it.replaceRange(1, it.length, "*".repeat(it.length - 1)) }), - } -} \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/config/groups/ScreenLineSettings.kt b/src/main/kotlin/com/lambda/config/groups/ScreenLineSettings.kt deleted file mode 100644 index addfa317a..000000000 --- a/src/main/kotlin/com/lambda/config/groups/ScreenLineSettings.kt +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2026 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.groups - -import com.lambda.config.Configurable -import com.lambda.config.SettingGroup -import com.lambda.util.NamedEnum -import java.awt.Color - -class ScreenLineSettings( - c: Configurable, - vararg baseGroup: NamedEnum, - prefix: String = "", - override val visibility: () -> Boolean = { true }, -) : SettingGroup(c), LineConfig { - enum class Group(override val displayName: String) : NamedEnum { - Color("Color"), - Dash("Dash") - } - - val widthSetting by c.setting("${prefix}Width", 20, 1..100, 1, "The width of the line", visibility = visibility).group(*baseGroup).index() - override val width get() = widthSetting * 0.00005f - - override val startColor by c.setting("${prefix}Start Color", Color.WHITE, "The color at the start of the line", visibility = visibility).group(*baseGroup, Group.Color).index() - override val endColor by c.setting("${prefix}End Color", Color.WHITE, "The color at the end of the line", visibility = visibility).group(*baseGroup, Group.Color).index() - - override val dashEnabled by c.setting("${prefix}Dashed", false, "Enable dashed line pattern", visibility = visibility).group(*baseGroup, Group.Dash).index() - val dashLengthSetting by c.setting("${prefix}Dash Length", 30, 1..50, 1, "Length of each dash") { visibility() && dashEnabled }.group(*baseGroup, Group.Dash).index() - override val dashLength get() = dashLengthSetting * 0.001f - val gapLengthSetting by c.setting("${prefix}Gap Length", 15, 1..50, 1, "Length of gaps between dashes") { visibility() && dashEnabled }.group(*baseGroup, Group.Dash).index() - override val gapLength get() = gapLengthSetting * 0.001f - override val animated by c.setting("${prefix}Animated", true, "Animate the dash pattern") { visibility() && dashEnabled }.group(*baseGroup, Group.Dash).index() - val dashOffsetSetting by c.setting("${prefix}Dash Offset", 0, 0..100, 1, "Offset of the dash pattern") { visibility() && dashEnabled && !animated }.group(*baseGroup, Group.Dash).index() - override val dashOffset get() = dashOffsetSetting * 0.01f - val animationSpeedSetting by c.setting("${prefix}Animation Speed", 30, -100..100, 1, "Speed of dash animation (negative = reverse)") { visibility() && dashEnabled && animated }.group(*baseGroup, Group.Dash).index() - override val animationSpeed get() = animationSpeedSetting * 0.1f -} diff --git a/src/main/kotlin/com/lambda/config/groups/ScreenTextSettings.kt b/src/main/kotlin/com/lambda/config/groups/ScreenTextSettings.kt deleted file mode 100644 index 22ad3f926..000000000 --- a/src/main/kotlin/com/lambda/config/groups/ScreenTextSettings.kt +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2026 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.groups - -import com.lambda.config.Configurable -import com.lambda.config.SettingGroup -import com.lambda.util.NamedEnum -import java.awt.Color - -class ScreenTextSettings( - c: Configurable, - vararg baseGroup: NamedEnum, - prefix: String = "", - override val visibility: () -> Boolean = { true }, -) : SettingGroup(c), TextConfig { - enum class Group(override val displayName: String) : NamedEnum { - General("General"), - Outline("Outline"), - Glow("Glow"), - Shadow("Shadow") - } - - override val textColor by c.setting("${prefix}Text Color", Color.WHITE, "The main text color", visibility = visibility).group(*baseGroup, Group.General).index() - val sizeSetting by c.setting("${prefix}Text Size", 18, 1..50, 1, visibility = visibility).group(*baseGroup, Group.General).index() - override val size get() = sizeSetting * 0.001f - - override val outlineEnabled by c.setting("${prefix}Outline", false, "Enable text outline", visibility = visibility).group(*baseGroup, Group.Outline).index() - override val outlineColor by c.setting("${prefix}Outline Color", Color.BLACK, "Color of the outline") { visibility() && outlineEnabled }.group(*baseGroup, Group.Outline).index() - override val outlineWidth by c.setting("${prefix}Outline Width", 0.1f, 0f..0.4f, 0.005f, "Width of the outline") { visibility() && outlineEnabled }.group(*baseGroup, Group.Outline).index() - - override val glowEnabled by c.setting("${prefix}Glow", false, "Enable text glow effect", visibility = visibility).group(*baseGroup, Group.Glow).index() - override val glowColor by c.setting("${prefix}Glow Color", Color.WHITE, "Color of the glow") { visibility() && glowEnabled }.group(*baseGroup, Group.Glow).index() - override val glowRadius by c.setting("${prefix}Glow Radius", 0.2f, 0f..0.5f, 0.01f, "Radius of the glow effect") { visibility() && glowEnabled }.group(*baseGroup, Group.Glow).index() - - override val shadowEnabled by c.setting("${prefix}Shadow", true, "Enable text shadow", visibility = visibility).group(*baseGroup, Group.Shadow).index() - override val shadowColor by c.setting("${prefix}Shadow Color", Color(0, 0, 0, 180), "Color of the shadow") { visibility() && shadowEnabled }.group(*baseGroup, Group.Shadow).index() - override val shadowOffset by c.setting("${prefix}Shadow Offset", 0.05f, 0f..0.5f, 0.005f, "Distance of shadow from text") { visibility() && shadowEnabled }.group(*baseGroup, Group.Shadow).index() - override val shadowAngle by c.setting("${prefix}Shadow Angle", 135f, 0f..360f, 1f, "Angle of the shadow") { visibility() && shadowEnabled }.group(*baseGroup, Group.Shadow).index() - override val shadowSoftness by c.setting("${prefix}Shadow Softness", 0f, 0f..0.5f, 0.01f, "Softness of shadow edges") { visibility() && shadowEnabled }.group(*baseGroup, Group.Shadow).index() -} diff --git a/src/main/kotlin/com/lambda/config/groups/WorldLineSettings.kt b/src/main/kotlin/com/lambda/config/groups/WorldLineSettings.kt deleted file mode 100644 index 8e247befc..000000000 --- a/src/main/kotlin/com/lambda/config/groups/WorldLineSettings.kt +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2026 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.groups - -import com.lambda.config.Configurable -import com.lambda.config.SettingGroup -import com.lambda.util.NamedEnum -import java.awt.Color - -class WorldLineSettings( - c: Configurable, - vararg baseGroup: NamedEnum, - prefix: String = "", - override val visibility: () -> Boolean = { true }, -) : SettingGroup(c), LineConfig { - enum class Group(override val displayName: String) : NamedEnum { - General("General"), - Color("Color"), - Dash("Dash") - } - - val distanceScaling by c.setting("${prefix}Distance Scaling", true, "Line width stays constant on screen regardless of distance", visibility = visibility).group(*baseGroup, Group.General).index() - val worldWidthSetting by c.setting("${prefix}Width", 5, 1..50, 1) { visibility() && !distanceScaling }.group(*baseGroup, Group.General).index() - val screenWidthSetting by c.setting("${prefix}Screen Width", 20, 1..100, 1, "Line width in screen-space (stays constant size)") { visibility() && distanceScaling }.group(*baseGroup, Group.General).index() - - override val width: Float get() = - if (distanceScaling) -screenWidthSetting * 0.00005f - else worldWidthSetting * 0.001f - - override val startColor by c.setting("${prefix}Start Color", Color.WHITE, "The color at the start of the line", visibility = visibility).group(*baseGroup, Group.Color).index() - override val endColor by c.setting("${prefix}End Color", Color.WHITE, "The color at the end of the line", visibility = visibility).group(*baseGroup, Group.Color).index() - - override val dashEnabled by c.setting("${prefix}Dashed", false, "Enable dashed line pattern", visibility = visibility).group(*baseGroup, Group.Dash).index() - val dashLengthSetting by c.setting("${prefix}Dash Length", 50, 1..200, 1, "Length of each dash") { visibility() && dashEnabled }.group(*baseGroup, Group.Dash).index() - override val dashLength get() = dashLengthSetting * 0.01f - val gapLengthSetting by c.setting("${prefix}Gap Length", 25, 1..200, 1, "Length of gaps between dashes") { visibility() && dashEnabled }.group(*baseGroup, Group.Dash).index() - override val gapLength get() = gapLengthSetting * 0.01f - override val animated by c.setting("${prefix}Animated", true, "Animate the dash pattern") { visibility() && dashEnabled }.group(*baseGroup, Group.Dash).index() - val dashOffsetSetting by c.setting("${prefix}Dash Offset", 0, 0..100, 1, "Offset of the dash pattern") { visibility() && dashEnabled && !animated }.group(*baseGroup, Group.Dash).index() - override val dashOffset get() = dashOffsetSetting * 0.01f - val animationSpeedSetting by c.setting("${prefix}Animation Speed", 30, -100..100, 1, "Speed of dash animation (negative = reverse)") { visibility() && dashEnabled && animated }.group(*baseGroup, Group.Dash).index() - override val animationSpeed get() = animationSpeedSetting * 0.1f -} diff --git a/src/main/kotlin/com/lambda/config/groups/WorldTextSettings.kt b/src/main/kotlin/com/lambda/config/groups/WorldTextSettings.kt deleted file mode 100644 index 0fa62a65c..000000000 --- a/src/main/kotlin/com/lambda/config/groups/WorldTextSettings.kt +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2026 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.groups - -import com.lambda.config.Configurable -import com.lambda.config.SettingGroup -import com.lambda.util.NamedEnum -import java.awt.Color - -class WorldTextSettings( - c: Configurable, - vararg baseGroup: NamedEnum, - prefix: String = "", - override val visibility: () -> Boolean = { true }, -) : SettingGroup(c), TextConfig { - enum class Group(override val displayName: String) : NamedEnum { - General("General"), - Outline("Outline"), - Glow("Glow"), - Shadow("Shadow") - } - - override val textColor by c.setting("${prefix}Text Color", Color.WHITE, "The main text color", visibility = visibility).group(*baseGroup, Group.General).index() - val sizeSetting by c.setting("${prefix}Text Size", 5, 1..50, 1, visibility = visibility).group(*baseGroup, Group.General).index() - override val size get() = sizeSetting * 0.1f - - override val outlineEnabled by c.setting("${prefix}Outline", false, "Enable text outline", visibility = visibility).group(*baseGroup, Group.Outline).index() - override val outlineColor by c.setting("${prefix}Outline Color", Color.BLACK, "Color of the outline") { visibility() && outlineEnabled }.group(*baseGroup, Group.Outline).index() - override val outlineWidth by c.setting("${prefix}Outline Width", 0.1f, 0f..0.4f, 0.005f, "Width of the outline") { visibility() && outlineEnabled }.group(*baseGroup, Group.Outline).index() - - override val glowEnabled by c.setting("${prefix}Glow", false, "Enable text glow effect", visibility = visibility).group(*baseGroup, Group.Glow).index() - override val glowColor by c.setting("${prefix}Glow Color", Color.WHITE, "Color of the glow") { visibility() && glowEnabled }.group(*baseGroup, Group.Glow).index() - override val glowRadius by c.setting("${prefix}Glow Radius", 0.2f, 0f..0.5f, 0.01f, "Radius of the glow effect") { visibility() && glowEnabled }.group(*baseGroup, Group.Glow).index() - - override val shadowEnabled by c.setting("${prefix}Shadow", true, "Enable text shadow", visibility = visibility).group(*baseGroup, Group.Shadow).index() - override val shadowColor by c.setting("${prefix}Shadow Color", Color(0, 0, 0, 180), "Color of the shadow") { visibility() && shadowEnabled }.group(*baseGroup, Group.Shadow).index() - override val shadowOffset by c.setting("${prefix}Shadow Offset", 0.05f, 0f..0.5f, 0.005f, "Distance of shadow from text") { visibility() && shadowEnabled }.group(*baseGroup, Group.Shadow).index() - override val shadowAngle by c.setting("${prefix}Shadow Angle", 135f, 0f..360f, 1f, "Angle of the shadow") { visibility() && shadowEnabled }.group(*baseGroup, Group.Shadow).index() - override val shadowSoftness by c.setting("${prefix}Shadow Softness", 0f, 0f..0.5f, 0.01f, "Softness of shadow edges") { visibility() && shadowEnabled }.group(*baseGroup, Group.Shadow).index() -} diff --git a/src/main/kotlin/com/lambda/config/migration/MigrationUtils.kt b/src/main/kotlin/com/lambda/config/migration/MigrationUtils.kt new file mode 100644 index 000000000..269a4a59e --- /dev/null +++ b/src/main/kotlin/com/lambda/config/migration/MigrationUtils.kt @@ -0,0 +1,121 @@ +/* + * Copyright 2026 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.migration + +import com.lambda.config.Config +import com.lambda.config.ConfigCategory +import com.lambda.config.SettingLayer +import com.lambda.util.CommunicationUtils.logError +import tools.jackson.databind.JsonNode +import tools.jackson.databind.node.ObjectNode + +object MigrationUtils { + fun locateAndMoveMisplacedSettings(category: ConfigCategory, rootNode: ObjectNode): Int { + var settingsMoved = 0 + category.configs.forEach { config -> + val configNode = rootNode.get(config.name) ?: return@forEach + if (!configNode.isObject) return@forEach + settingsMoved += locateAndMoveMisplacedSettings(config, configNode.asObject()) + } + return settingsMoved + } + + private fun locateAndMoveMisplacedSettings(config: Config, rootNode: ObjectNode): Int { + var settingsMoved = 0 + fun walk(multiple: SettingLayer.Multiple, obj: ObjectNode) { + config.forEachSetting( + multiple, + false, + { _, childMultiple -> + val existing = obj.get(childMultiple.name) + val nestedObj: ObjectNode = when { + existing != null && existing.isObject -> existing.asObject() + existing == null || existing.isNull -> obj.putObject(childMultiple.name) + else -> return@forEachSetting + } + try { + walk(childMultiple, nestedObj) + } catch (e: Throwable) { + logError("Failed to relocate settings in ${childMultiple.multipleType.toString().lowercase()} '${childMultiple.name}' in '${config.name}'", e) + } + } + ) { path, single -> + if (obj.has(single.name)) return@forEachSetting + + val fallbackValue = locateAndRemove(single.name, path, rootNode) ?: return@forEachSetting + try { + obj.set(single.name, fallbackValue) + settingsMoved++ + } catch (e: Throwable) { + logError("Failed to relocate setting '${single.name}' in '${config.name}'", e) + } + } + } + + walk(config.settingLayers, rootNode) + return settingsMoved + } + + private fun locateAndRemove( + settingName: String, + parentLayers: List, + rootObj: ObjectNode + ): JsonNode? { + var bestMatch: JsonNode? = null + var bestMatchKey: String? = null + var bestMatchParent: ObjectNode? = null + var bestMatchScore = 0 + + fun search(currentObj: ObjectNode, jsonPath: List) { + currentObj.propertyStream().forEach { (key, element) -> + if (key.endsWith(settingName, ignoreCase = true)) { + var score = 0 + if (key.equals(settingName, ignoreCase = true)) { + score += 10 + } + + val fullPathString = (jsonPath + key).joinToString("") + parentLayers.forEach { layer -> + if (fullPathString.contains(layer.name, ignoreCase = true)) { + score += 5 + } + } + + if (score > bestMatchScore) { + bestMatchScore = score + bestMatch = element + bestMatchKey = key + bestMatchParent = currentObj + } + } + + if (element.isObject) { + search(element.asObject(), jsonPath + key) + } + } + } + + search(rootObj, emptyList()) + + if (bestMatch != null && bestMatchParent != null && bestMatchKey != null) { + bestMatchParent.remove(bestMatchKey) + } + + return bestMatch + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/config/migration/Migrations.kt b/src/main/kotlin/com/lambda/config/migration/Migrations.kt index e169794c6..e5cd0ca66 100644 --- a/src/main/kotlin/com/lambda/config/migration/Migrations.kt +++ b/src/main/kotlin/com/lambda/config/migration/Migrations.kt @@ -17,84 +17,51 @@ package com.lambda.config.migration -import com.google.gson.JsonArray -import com.google.gson.JsonElement -import com.google.gson.JsonObject -import com.lambda.Lambda.LOG +import com.lambda.Lambda.Log +import com.lambda.config.ConfigCategory import com.lambda.core.Loadable -import com.lambda.util.reflections.getInstances -import java.util.* +import com.lambda.util.ReflectionUtils.getInstances +import tools.jackson.databind.node.ArrayNode +import tools.jackson.databind.node.ObjectNode import kotlin.math.max -interface ConfigMigration { - val configName: String - val latestVersion: Int - val schemaVersionKey: String get() = ConfigMigrations.DEFAULT_SCHEMA_VERSION_KEY - fun applyStep(fromVersion: Int, root: JsonObject): StepResult? -} - -data class StepResult( - val toVersion: Int, - val changed: Boolean = true, -) - -data class MigrationResult( - val json: JsonObject, - val migrated: Boolean, -) - -abstract class StepConfigMigration : ConfigMigration { - private val steps = mutableMapOf Unit>>() - - protected fun step(fromVersion: Int, toVersion: Int, migrate: JsonObject.() -> Unit) { - steps[fromVersion] = toVersion to migrate - } - - final override fun applyStep(fromVersion: Int, root: JsonObject): StepResult? { - val step = steps[fromVersion] ?: return null - val (toVersion, block) = step - root.block() - return StepResult(toVersion = toVersion, changed = true) - } -} - -object ConfigMigrations : Loadable { - const val DEFAULT_SCHEMA_VERSION_KEY = "_schemaVersion" +object ConfigMigrationHandler : Loadable { + const val DefaultSchemaVersionKey = "_schemaVersion" override val priority: Int = 2 @Volatile private var initialized = false - private var byConfig = emptyMap() + private var byCategory = emptyMap() override fun load(): String { refreshRegistry() - return "Loaded ${byConfig.size} config migrations" + return "Loaded ${byCategory.size} config migrations" } - fun schemaVersionKey(configName: String): String? { + fun schemaVersionKey(category: ConfigCategory): String? { ensureInitialized() - return byConfig[configName]?.schemaVersionKey + return byCategory[category]?.schemaVersionKey } - fun latestVersion(configName: String): Int { + fun latestVersion(category: ConfigCategory): Int { ensureInitialized() - return byConfig[configName]?.latestVersion ?: 1 + return byCategory[category]?.latestVersion ?: 1 } - fun migrate(configName: String, original: JsonObject): MigrationResult { + fun migrate(category: ConfigCategory, original: ObjectNode): MigrationResult { ensureInitialized() - val migration = byConfig[configName] ?: return MigrationResult(original.deepCopy(), false) + val migration = byCategory[category] ?: return MigrationResult(original.deepCopy(), false) if (migration.latestVersion <= 1) return MigrationResult(original.deepCopy(), false) val json = original.deepCopy() var currentVersion = runCatching { - json.get(migration.schemaVersionKey)?.takeIf { it.isJsonPrimitive }?.asInt + json.get(migration.schemaVersionKey)?.takeIf { it.isNumber }?.asInt() }.getOrNull() ?: 1 var migrated = false if (currentVersion > migration.latestVersion) { - LOG.warn( - "Config ${configName.replaceFirstChar { it.uppercase() }} has schema version $currentVersion " + + Log.warn( + "Config category '${category.name}' has schema version $currentVersion " + "which is newer than supported ${migration.latestVersion}" ) return MigrationResult(json, false) @@ -105,8 +72,8 @@ object ConfigMigrations : Loadable { val fromVersion = currentVersion val stepResult = migration.applyStep(fromVersion, json) if (stepResult == null) { - LOG.warn( - "Missing migration step for ${configName.replaceFirstChar { it.uppercase() }} " + + Log.warn( + "Missing migration step for '${category.name}' config category " + "schema version $fromVersion -> ?. Expected latest schema version is ${migration.latestVersion}" ) break @@ -115,12 +82,12 @@ object ConfigMigrations : Loadable { currentVersion = stepResult.toVersion migrated = migrated || stepResult.changed if (currentVersion > 1) { - json.addProperty(migration.schemaVersionKey, currentVersion) + json.put(migration.schemaVersionKey, currentVersion) migrated = true } } catch (t: Throwable) { - LOG.error( - "Failed to migrate ${configName.replaceFirstChar { it.uppercase() }} config " + + Log.error( + "Failed to migrate ${category.name} config category " + "from v$currentVersion to next version", t ) @@ -130,9 +97,9 @@ object ConfigMigrations : Loadable { val normalizedVersion = max(1, currentVersion) if (normalizedVersion > 1) { - val existingVersion = runCatching { json.get(migration.schemaVersionKey)?.asInt }.getOrNull() + val existingVersion = runCatching { json.get(migration.schemaVersionKey)?.asInt() }.getOrNull() if (existingVersion != normalizedVersion) { - json.addProperty(migration.schemaVersionKey, normalizedVersion) + json.put(migration.schemaVersionKey, normalizedVersion) migrated = true } } else if (json.has(migration.schemaVersionKey)) { @@ -146,14 +113,14 @@ object ConfigMigrations : Loadable { @Synchronized private fun refreshRegistry() { val discovered = getInstances() - val duplicates = discovered.groupBy { it.configName }.filter { it.value.size > 1 } + val duplicates = discovered.groupBy { it.category }.filter { it.value.size > 1 } if (duplicates.isNotEmpty()) { duplicates.keys.forEach { key -> - LOG.warn("Multiple config migrations found for '$key'. Using the last discovered migration.") + Log.warn("Multiple config migrations found for '$key'. Using the last discovered migration.") } } - byConfig = discovered.associateBy { it.configName } + byCategory = discovered.associateBy { it.category } initialized = true } @@ -162,25 +129,41 @@ object ConfigMigrations : Loadable { } } -fun JsonObject.objectOrCreate(key: String): JsonObject = - getAsJsonObject(key) ?: JsonObject().also { add(key, it) } +abstract class StepConfigMigration : ConfigMigration { + private val steps = mutableMapOf Unit>>() -fun JsonObject.arrayOrCreate(key: String): JsonArray = - getAsJsonArray(key) ?: JsonArray().also { add(key, it) } + protected fun step(fromVersion: Int, toVersion: Int, migrate: (ObjectNode) -> Unit) { + steps[fromVersion] = toVersion to migrate + } -fun JsonElement.parseUuidOrNull(): UUID? { - val raw = when { - isJsonPrimitive -> asString - isJsonObject && asJsonObject.has("id") -> asJsonObject.get("id").asString - else -> return null + final override fun applyStep(fromVersion: Int, root: ObjectNode): StepResult? { + val step = steps[fromVersion] ?: return null + val (toVersion, block) = step + root.block() + return StepResult(toVersion = toVersion, changed = true) } - val normalized = - if (raw.length == 32) raw.replaceFirst( - "(\\w{8})(\\w{4})(\\w{4})(\\w{4})(\\w{12})".toRegex(), - "$1-$2-$3-$4-$5" - ) - else raw + fun ObjectNode.objectOrCreate(key: String): ObjectNode = + get(key) as? ObjectNode ?: putObject(key) - return runCatching { UUID.fromString(normalized) }.getOrNull() + fun ObjectNode.arrayOrCreate(key: String): ArrayNode = + get(key) as? ArrayNode ?: putArray(key) } + +interface ConfigMigration { + val category: ConfigCategory + val latestVersion: Int + val schemaVersionKey: String get() = ConfigMigrationHandler.DefaultSchemaVersionKey + fun applyStep(fromVersion: Int, root: ObjectNode): StepResult? +} + +data class StepResult( + val toVersion: Int, + val changed: Boolean = true, +) + +data class MigrationResult( + val json: ObjectNode, + val migrated: Boolean, +) + diff --git a/src/main/kotlin/com/lambda/config/migration/migrations/AutomationConfigMigration.kt b/src/main/kotlin/com/lambda/config/migration/migrations/AutomationConfigMigration.kt index cef85a53b..6ab5afd3f 100644 --- a/src/main/kotlin/com/lambda/config/migration/migrations/AutomationConfigMigration.kt +++ b/src/main/kotlin/com/lambda/config/migration/migrations/AutomationConfigMigration.kt @@ -17,28 +17,37 @@ package com.lambda.config.migration.migrations -import com.lambda.Lambda.LOG +import com.lambda.Lambda.Log +import com.lambda.config.categories.AutomationCategory +import com.lambda.config.migration.MigrationUtils import com.lambda.config.migration.StepConfigMigration +@Suppress("unused") object AutomationConfigMigration : StepConfigMigration() { - override val configName = "automation" - override val latestVersion = 2 + override val category = AutomationCategory + override val latestVersion = 3 init { - step(1, 2) { + step(1, 2) { root -> var updateCount = 0 - entrySet().forEach { configPair -> - getAsJsonObject(configPair.key)?.let { config -> + root.propertyStream().forEach { configPair -> + root.get(configPair.key).takeIf { it.isObject }?.asObject()?.let { config -> config.get("Limit Timeframe")?.let { limitTimeframe -> - if (limitTimeframe.asInt < 50) { - config.addProperty("Limit Timeframe", 310) + if (!limitTimeframe.isInt) return@forEach + if (limitTimeframe.asInt() < 50) { + config.put("Limit Timeframe", 310) updateCount++ } } } } - LOG.info("Migrated Automation config schema v1 -> v2: $updateCount settings updated") + Log.info("Migrated Automation config category schema v1 -> v2: $updateCount settings updated") + } + + step(2, 3) { root -> + val count = MigrationUtils.locateAndMoveMisplacedSettings(category, root) + Log.info("Migrated Automation config category schema v2 -> v3: $count settings moved") } } } \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/config/migration/migrations/FriendConfigMigration.kt b/src/main/kotlin/com/lambda/config/migration/migrations/FriendConfigMigration.kt index 4acf41076..8b517b428 100644 --- a/src/main/kotlin/com/lambda/config/migration/migrations/FriendConfigMigration.kt +++ b/src/main/kotlin/com/lambda/config/migration/migrations/FriendConfigMigration.kt @@ -17,23 +17,22 @@ package com.lambda.config.migration.migrations -import com.google.gson.JsonArray -import com.lambda.Lambda.LOG +import com.lambda.Lambda.Log +import com.lambda.config.categories.FriendCategory import com.lambda.config.migration.StepConfigMigration -import com.lambda.config.migration.arrayOrCreate -import com.lambda.config.migration.objectOrCreate -import com.lambda.config.migration.parseUuidOrNull +import tools.jackson.databind.JsonNode import java.util.* +@Suppress("unused") object FriendConfigMigration : StepConfigMigration() { - override val configName = "friends" + override val category = FriendCategory override val latestVersion = 2 init { - step(1, 2) { - val configurable = objectOrCreate("friends") - val rawFriends = configurable.arrayOrCreate("friends") - val migrated = JsonArray() + step(1, 2) { root -> + val config = root.objectOrCreate("friends") + val rawFriends = config.arrayOrCreate("friends") + val migrated = config.putArray("friends") val seen = mutableSetOf() var dropped = 0 @@ -45,8 +44,24 @@ object FriendConfigMigration : StepConfigMigration() { ?: run { dropped++ } } - configurable.add("friends", migrated) - LOG.info("Migrated Friend config schema v1 -> v2: ${migrated.size()} entries converted, $dropped entries dropped") + Log.info("Migrated Friend config category schema v1 -> v2: ${migrated.size()} entries converted, $dropped entries dropped") } } + + fun JsonNode.parseUuidOrNull(): UUID? { + val raw = when { + isString -> asString() + isObject && asObject().has("id") -> asObject().get("id").asString() + else -> return null + } + + val normalized = + if (raw.length == 32) raw.replaceFirst( + "(\\w{8})(\\w{4})(\\w{4})(\\w{4})(\\w{12})".toRegex(), + "$1-$2-$3-$4-$5" + ) + else raw + + return runCatching { UUID.fromString(normalized) }.getOrNull() + } } diff --git a/src/main/kotlin/com/lambda/config/SettingGroup.kt b/src/main/kotlin/com/lambda/config/migration/migrations/GuiConfigMigration.kt similarity index 55% rename from src/main/kotlin/com/lambda/config/SettingGroup.kt rename to src/main/kotlin/com/lambda/config/migration/migrations/GuiConfigMigration.kt index c5bc7711e..a111315a9 100644 --- a/src/main/kotlin/com/lambda/config/SettingGroup.kt +++ b/src/main/kotlin/com/lambda/config/migration/migrations/GuiConfigMigration.kt @@ -15,22 +15,22 @@ * along with this program. If not, see . */ -package com.lambda.config +package com.lambda.config.migration.migrations -interface ISettingGroup { - val settings: MutableList> - val visibility: () -> Boolean -} +import com.lambda.Lambda.Log +import com.lambda.config.categories.GuiCategory +import com.lambda.config.migration.MigrationUtils +import com.lambda.config.migration.StepConfigMigration -abstract class SettingGroup(c: Configurable) : ISettingGroup { - override val settings = mutableListOf>() +@Suppress("unused") +object GuiConfigMigration : StepConfigMigration() { + override val category = GuiCategory + override val latestVersion = 2 init { - c.settingGroups.add(this) + step(1, 2) { root -> + val count = MigrationUtils.locateAndMoveMisplacedSettings(category, root) + Log.info("Migrated Gui config category schema v1 -> v2: $count settings moved") + } } - - fun , R : Any> Setting.index(): Setting { - settings.add(this) - return this - } } \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/config/configurations/AutomationConfigs.kt b/src/main/kotlin/com/lambda/config/migration/migrations/ModuleConfigMigration.kt similarity index 54% rename from src/main/kotlin/com/lambda/config/configurations/AutomationConfigs.kt rename to src/main/kotlin/com/lambda/config/migration/migrations/ModuleConfigMigration.kt index 2290deafc..3576f4f75 100644 --- a/src/main/kotlin/com/lambda/config/configurations/AutomationConfigs.kt +++ b/src/main/kotlin/com/lambda/config/migration/migrations/ModuleConfigMigration.kt @@ -15,13 +15,22 @@ * along with this program. If not, see . */ -package com.lambda.config.configurations +package com.lambda.config.migration.migrations -import com.lambda.config.Configuration -import com.lambda.util.FolderRegister -import java.io.File +import com.lambda.Lambda.Log +import com.lambda.config.categories.ModuleCategory +import com.lambda.config.migration.MigrationUtils +import com.lambda.config.migration.StepConfigMigration -object AutomationConfigs : Configuration() { - override val configName = "automation" - override val primary: File = FolderRegister.config.resolve("${configName}.json").toFile() +@Suppress("unused") +object ModuleConfigMigration : StepConfigMigration() { + override val category = ModuleCategory + override val latestVersion = 2 + + init { + step(1, 2) { root -> + val count = MigrationUtils.locateAndMoveMisplacedSettings(category, root) + Log.info("Migrated Module config category schema v1 -> v2: $count settings moved") + } + } } \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/config/migration/migrations/UserAutomationConfigMigration.kt b/src/main/kotlin/com/lambda/config/migration/migrations/UserAutomationConfigMigration.kt new file mode 100644 index 000000000..e4dcf0bf6 --- /dev/null +++ b/src/main/kotlin/com/lambda/config/migration/migrations/UserAutomationConfigMigration.kt @@ -0,0 +1,36 @@ +/* + * Copyright 2026 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.migration.migrations + +import com.lambda.Lambda.Log +import com.lambda.config.categories.UserAutomationCategory +import com.lambda.config.migration.MigrationUtils +import com.lambda.config.migration.StepConfigMigration + +@Suppress("unused") +object UserAutomationConfigMigration : StepConfigMigration() { + override val category = UserAutomationCategory + override val latestVersion = 2 + + init { + step(1, 2) { root -> + val count = MigrationUtils.locateAndMoveMisplacedSettings(category, root) + Log.info("Migrated User Automation config category schema v1 -> v2: $count settings moved") + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/config/serializer/BindCodec.kt b/src/main/kotlin/com/lambda/config/serializer/BindCodec.kt deleted file mode 100644 index ba9de5608..000000000 --- a/src/main/kotlin/com/lambda/config/serializer/BindCodec.kt +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2026 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.JsonObject -import com.google.gson.JsonSerializationContext -import com.lambda.config.Codec -import com.lambda.config.settings.complex.Bind -import java.lang.reflect.Type - -object BindCodec : Codec { - override fun serialize(src: Bind, typeOfSrc: Type, context: JsonSerializationContext): JsonElement = - JsonObject().apply { - addProperty("key", src.key) - addProperty("modifiers", src.modifiers) - addProperty("mouse", src.mouse) - } - - override fun deserialize(json: JsonElement, typeOfT: Type, context: JsonDeserializationContext) = - json.asJsonObject.let { obj -> - Bind(obj.get("key").asInt, obj.get("modifiers").asInt, obj.get("mouse").asInt) - } -} \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/config/serializer/BlockPosCodec.kt b/src/main/kotlin/com/lambda/config/serializer/BlockPosCodec.kt deleted file mode 100644 index d120062e8..000000000 --- a/src/main/kotlin/com/lambda/config/serializer/BlockPosCodec.kt +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2026 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.JsonDeserializer -import com.google.gson.JsonElement -import com.google.gson.JsonSerializationContext -import com.google.gson.JsonSerializer -import com.lambda.config.Codec -import com.lambda.config.Stringifiable -import com.lambda.util.Formatting.format -import com.mojang.serialization.JsonOps -import net.minecraft.util.math.BlockPos -import java.lang.reflect.Type -import kotlin.jvm.optionals.getOrElse - -object BlockPosCodec : Codec, Stringifiable { - override fun serialize( - src: BlockPos, - typeOfSrc: Type, - context: JsonSerializationContext, - ): JsonElement = - BlockPos.CODEC.encodeStart(JsonOps.INSTANCE, src) - .orThrow - - override fun deserialize( - json: JsonElement?, - typeOfT: Type?, - context: JsonDeserializationContext?, - ): BlockPos = - BlockPos.CODEC.parse(JsonOps.INSTANCE, json) - .result() - .getOrElse { BlockPos.ORIGIN } - - override fun stringify(value: BlockPos) = value.format() -} diff --git a/src/main/kotlin/com/lambda/config/serializer/ColorSerializer.kt b/src/main/kotlin/com/lambda/config/serializer/ColorSerializer.kt deleted file mode 100644 index 134d59c3b..000000000 --- a/src/main/kotlin/com/lambda/config/serializer/ColorSerializer.kt +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2026 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.JsonParseException -import com.google.gson.JsonPrimitive -import com.google.gson.JsonSerializationContext -import com.lambda.config.Codec -import com.lambda.config.Stringifiable -import java.awt.Color -import java.lang.reflect.Type - -object ColorSerializer : Codec, Stringifiable { - override fun serialize( - src: Color, - typeOfSrc: Type, - context: JsonSerializationContext?, - ): JsonElement = - JsonPrimitive("${src.red},${src.green},${src.blue},${src.alpha}") - - override fun deserialize( - json: JsonElement, - typeOfT: Type, - context: JsonDeserializationContext?, - ): Color = - json.asString.split(",").let { - when (it.size) { - 3 -> Color(it[0].toInt(), it[1].toInt(), it[2].toInt()) - 4 -> Color(it[0].toInt(), it[1].toInt(), it[2].toInt(), it[3].toInt()) - else -> throw JsonParseException("Invalid color format") - } - } - - override fun stringify(value: Color) = "${value.red},${value.green},${value.blue},${value.alpha}" -} diff --git a/src/main/kotlin/com/lambda/config/serializer/GameProfileCodec.kt b/src/main/kotlin/com/lambda/config/serializer/GameProfileCodec.kt deleted file mode 100644 index bb0c2e4b4..000000000 --- a/src/main/kotlin/com/lambda/config/serializer/GameProfileCodec.kt +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2026 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.JsonDeserializer -import com.google.gson.JsonElement -import com.google.gson.JsonNull -import com.google.gson.JsonObject -import com.google.gson.JsonSerializationContext -import com.google.gson.JsonSerializer -import com.lambda.config.Codec -import com.lambda.config.Stringifiable -import com.mojang.authlib.GameProfile -import java.lang.reflect.Type -import java.util.* - -// Yeah yeah I know, there's already a serializer for GameProfile in the Minecraft codebase. -// But who cares, I'm doing it again. -// What you gon' do bout it, huh? -// That's what I thought. -object GameProfileCodec : Codec, Stringifiable { - override fun serialize( - src: GameProfile, - typeOfSrc: Type?, - context: JsonSerializationContext?, - ): JsonElement = - JsonObject().apply { - addProperty("name", src.name) - addProperty("id", src.id.toString()) - } - - override fun deserialize( - json: JsonElement, - typeOfT: Type?, - context: JsonDeserializationContext?, - ): GameProfile { - val name = json.asJsonObject.get("name").asString - val id = json.asJsonObject.get("id").asString - val parsedId = - if (id.length == 32) id.replaceFirst( - "(\\w{8})(\\w{4})(\\w{4})(\\w{4})(\\w{12})".toRegex(), - "$1-$2-$3-$4-$5" - ) - else id - - return GameProfile(UUID.fromString(parsedId), name) - } - - override fun stringify(value: GameProfile) = value.toString() -} diff --git a/src/main/kotlin/com/lambda/config/serializer/ItemStackCodec.kt b/src/main/kotlin/com/lambda/config/serializer/ItemStackCodec.kt deleted file mode 100644 index 68a3e4119..000000000 --- a/src/main/kotlin/com/lambda/config/serializer/ItemStackCodec.kt +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2026 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.lambda.config.Stringifiable -import com.mojang.serialization.JsonOps -import net.minecraft.item.ItemStack -import java.lang.reflect.Type -import kotlin.jvm.optionals.getOrElse - -object ItemStackCodec : Codec, Stringifiable { - override fun serialize( - stack: ItemStack, - typeOfSrc: Type, - context: JsonSerializationContext - ): JsonElement = - ItemStack.CODEC.encodeStart(JsonOps.INSTANCE, stack) - .orThrow - - override fun deserialize( - json: JsonElement, - typeOfT: Type, - context: JsonDeserializationContext - ): ItemStack = - ItemStack.CODEC.parse(JsonOps.INSTANCE, json) - .result() - .getOrElse { ItemStack.EMPTY } - - override fun stringify(value: ItemStack) = value.itemName.string.uppercase() -} diff --git a/src/main/kotlin/com/lambda/config/serializer/KeyCodeCodec.kt b/src/main/kotlin/com/lambda/config/serializer/KeyCodeCodec.kt deleted file mode 100644 index 1114ff293..000000000 --- a/src/main/kotlin/com/lambda/config/serializer/KeyCodeCodec.kt +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2026 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.JsonDeserializer -import com.google.gson.JsonElement -import com.google.gson.JsonNull -import com.google.gson.JsonParseException -import com.google.gson.JsonPrimitive -import com.google.gson.JsonSerializationContext -import com.google.gson.JsonSerializer -import com.lambda.config.Codec -import com.lambda.util.KeyCode -import java.lang.reflect.Type - -object KeyCodeCodec : Codec { - override fun serialize( - src: KeyCode?, - typeOfSrc: Type?, - context: JsonSerializationContext?, - ): JsonElement = - src?.let { - JsonPrimitive(it.name) - } ?: JsonNull.INSTANCE - - override fun deserialize( - json: JsonElement?, - typeOfT: Type?, - context: JsonDeserializationContext?, - ): KeyCode = - json?.asString?.let(KeyCode::fromKeyName) ?: throw JsonParseException("Invalid key code format") -} diff --git a/src/main/kotlin/com/lambda/config/serializer/OptionalCodec.kt b/src/main/kotlin/com/lambda/config/serializer/OptionalCodec.kt deleted file mode 100644 index 4e4c66ef8..000000000 --- a/src/main/kotlin/com/lambda/config/serializer/OptionalCodec.kt +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2026 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.JsonDeserializer -import com.google.gson.JsonElement -import com.google.gson.JsonNull -import com.google.gson.JsonSerializationContext -import com.google.gson.JsonSerializer -import com.lambda.config.Codec -import java.lang.reflect.Type -import java.util.* - -object OptionalCodec : Codec> { - override fun serialize(src: Optional?, typeOfSrc: Type?, context: JsonSerializationContext?): JsonElement = - src?.map { context?.serialize(it) }?.orElse(JsonNull.INSTANCE) ?: JsonNull.INSTANCE - - override fun deserialize( - json: JsonElement?, - typeOfT: Type?, - context: JsonDeserializationContext?, - ): Optional = - Optional.ofNullable(json?.let { context?.deserialize(it, typeOfT) ?: Optional.empty() }) -} diff --git a/src/main/kotlin/com/lambda/config/serializer/TextCodec.kt b/src/main/kotlin/com/lambda/config/serializer/TextCodec.kt deleted file mode 100644 index 5dc863ea3..000000000 --- a/src/main/kotlin/com/lambda/config/serializer/TextCodec.kt +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2026 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/config/serializer/UUIDCodec.kt b/src/main/kotlin/com/lambda/config/serializer/UUIDCodec.kt deleted file mode 100644 index 0b3169872..000000000 --- a/src/main/kotlin/com/lambda/config/serializer/UUIDCodec.kt +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2026 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.JsonParseException -import com.google.gson.JsonSerializationContext -import com.lambda.config.Codec -import com.lambda.config.Stringifiable -import java.lang.reflect.Type -import java.util.* - -object UUIDCodec : Codec, Stringifiable { - override fun serialize( - src: UUID, - typeOfSrc: Type?, - context: JsonSerializationContext?, - ): JsonElement = context?.serialize(src.toString()) ?: throw JsonParseException("No serialization context") - - override fun deserialize( - json: JsonElement, - typeOfT: Type?, - context: JsonDeserializationContext?, - ): UUID { - val rawId = when { - json.isJsonPrimitive -> json.asString - json.isJsonObject && json.asJsonObject.has("id") -> json.asJsonObject.get("id").asString - else -> throw JsonParseException("Cannot deserialize UUID from: $json") - } - - val parsedId = - if (rawId.length == 32) rawId.replaceFirst( - "(\\w{8})(\\w{4})(\\w{4})(\\w{4})(\\w{12})".toRegex(), - "$1-$2-$3-$4-$5" - ) - else rawId - - return UUID.fromString(parsedId) - } - - override fun stringify(value: UUID) = value.toString() -} diff --git a/src/main/kotlin/com/lambda/config/serializer/BlockCodec.kt b/src/main/kotlin/com/lambda/config/serializers/BlockSerializer.kt similarity index 51% rename from src/main/kotlin/com/lambda/config/serializer/BlockCodec.kt rename to src/main/kotlin/com/lambda/config/serializers/BlockSerializer.kt index a990d93c0..133e5937b 100644 --- a/src/main/kotlin/com/lambda/config/serializer/BlockCodec.kt +++ b/src/main/kotlin/com/lambda/config/serializers/BlockSerializer.kt @@ -15,34 +15,30 @@ * along with this program. If not, see . */ -package com.lambda.config.serializer +@file:Suppress("unused") -import com.google.gson.JsonDeserializationContext -import com.google.gson.JsonElement -import com.google.gson.JsonSerializationContext -import com.lambda.config.Codec +package com.lambda.config.serializers + +import com.lambda.config.Deserializer +import com.lambda.config.JsonOps +import com.lambda.config.Serializer import com.lambda.config.Stringifiable -import com.mojang.serialization.JsonOps import net.minecraft.block.Block import net.minecraft.registry.Registries -import java.lang.reflect.Type - -object BlockCodec : Codec, Stringifiable { - override fun serialize( - src: Block, - typeOfSrc: Type, - context: JsonSerializationContext, - ): JsonElement = - Registries.BLOCK.codec.encodeStart(JsonOps.INSTANCE, src) - .orThrow +import tools.jackson.core.JsonGenerator +import tools.jackson.core.JsonParser +import tools.jackson.databind.DeserializationContext +import tools.jackson.databind.SerializationContext - override fun deserialize( - json: JsonElement?, - typeOfT: Type?, - context: JsonDeserializationContext?, - ): Block = - Registries.BLOCK.codec.parse(JsonOps.INSTANCE, json) - .orThrow +object BlockSerializer : Serializer(Block::class.java), Stringifiable { + override fun serialize(block: Block, gen: JsonGenerator, ctxt: SerializationContext) { + gen.writeTree((Registries.BLOCK.codec.encodeStart(JsonOps.Uncompressed, block).orThrow)) + } override fun stringify(value: Block) = Registries.BLOCK.getId(value).path.replaceFirstChar { it.uppercase() } } + +object BlockDeserializer : Deserializer(Block::class.java) { + override fun deserialize(p: JsonParser, ctxt: DeserializationContext): Block = + Registries.BLOCK.codec.parse(JsonOps.Uncompressed, mapper.readTree(p)).orThrow +} \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/config/serializers/ClassCollectionSettingSerializer.kt b/src/main/kotlin/com/lambda/config/serializers/ClassCollectionSettingSerializer.kt new file mode 100644 index 000000000..cad9ca518 --- /dev/null +++ b/src/main/kotlin/com/lambda/config/serializers/ClassCollectionSettingSerializer.kt @@ -0,0 +1,62 @@ +/* + * Copyright 2026 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 . + */ + +@file:Suppress("unused") + +package com.lambda.config.serializers + +import com.lambda.config.Deserializer +import com.lambda.config.Serializer +import com.lambda.config.Setting +import com.lambda.config.settings.collections.ClassCollectionSetting +import com.lambda.util.ReflectionUtils.className +import tools.jackson.core.JsonGenerator +import tools.jackson.core.JsonParser +import tools.jackson.databind.DeserializationContext +import tools.jackson.databind.SerializationContext + +object ClassCollectionSettingSerializer : Serializer>(ClassCollectionSetting::class.java) { + override fun serialize(setting: ClassCollectionSetting<*>, gen: JsonGenerator, ctxt: SerializationContext) { + gen.writeStartArray() + setting.originalCore.value.forEach { element -> + gen.writeString(element.className) + } + gen.writeEndArray() + } +} + +object ClassCollectionSettingDeserializer : Deserializer>(ClassCollectionSetting::class.java) { + override fun deserialize(p: JsonParser, ctxt: DeserializationContext): ClassCollectionSetting<*> { + throw initFromJsonException("ClassCollectionSetting") + } + + override fun deserialize(p: JsonParser, ctxt: DeserializationContext, setting: ClassCollectionSetting<*>): ClassCollectionSetting<*> = + setting.apply { + val arrayNode = mapper.readTree(p) + if (!arrayNode.isArray) throw IllegalStateException("ClassCollectionSetting's serialized value is not an array.") + val classNames = mutableListOf() + arrayNode.forEach { node -> + if (!node.isString) throw IllegalStateException("ClassCollectionSetting's serialized array contains a non-string value.") + if (node.isString) classNames.add(node.stringValue()) + } + + @Suppress("unchecked_cast") + (setting as Setting).originalCore.value = classNames.mapNotNull { className -> + setting.immutableCollection.find { it.className == className } + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/config/serializers/CollectionSettingSerializer.kt b/src/main/kotlin/com/lambda/config/serializers/CollectionSettingSerializer.kt new file mode 100644 index 000000000..b87854d4f --- /dev/null +++ b/src/main/kotlin/com/lambda/config/serializers/CollectionSettingSerializer.kt @@ -0,0 +1,70 @@ +/* + * Copyright 2026 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 . + */ + +@file:Suppress("unused") + +package com.lambda.config.serializers + +import com.lambda.config.FallbackDeserializer +import com.lambda.config.FallbackSerializer +import com.lambda.config.settings.collections.CollectionSetting +import tools.jackson.core.JsonGenerator +import tools.jackson.core.JsonParser +import tools.jackson.databind.DeserializationContext +import tools.jackson.databind.SerializationContext + +object CollectionSettingSerializer : FallbackSerializer>(CollectionSetting::class.java) { + override fun serialize(setting: CollectionSetting<*>, gen: JsonGenerator, ctxt: SerializationContext) { + if (setting.serialize) mapper.writeValue(gen, setting.originalCore.value) + else { + gen.writeStartArray() + setting.originalCore.value.forEach { element -> + gen.writeString(element.toString()) + } + gen.writeEndArray() + } + } +} + +object CollectionSettingDeserializer : FallbackDeserializer>(CollectionSetting::class.java) { + override fun deserialize(p: JsonParser, ctxt: DeserializationContext): CollectionSetting<*> { + throw initFromJsonException("CollectionSetting") + } + + override fun deserialize(p: JsonParser, ctxt: DeserializationContext, settingCore: CollectionSetting<*>): CollectionSetting<*> = + settingCore.apply { + val newValue = mutableListOf() + + if (serialize) { + val tree = mapper.readTree(p) + val deserialized = mapper.treeToValue>(tree, type) + newValue.addAll(deserialized) + } else { + val node = mapper.readTree(p) + if (!node.isArray) throw IllegalStateException("CollectionSetting's serialized value is not an array.") + node.forEach { element -> + if (!element.isString) throw IllegalStateException("CollectionSetting's serialized array contains a non-string value. A CollectionSetting's JSON array must only contain strings if CollectionSetting.serialize is false.") + val str = element.stringValue() + val matched = immutableCollection.find { it.toString() == str } + if (matched != null) newValue.add(matched) + } + } + + @Suppress("unchecked_cast") + (this as CollectionSetting).originalCore.value = newValue + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/config/serializers/ColorSerializer.kt b/src/main/kotlin/com/lambda/config/serializers/ColorSerializer.kt new file mode 100644 index 000000000..10f69ce95 --- /dev/null +++ b/src/main/kotlin/com/lambda/config/serializers/ColorSerializer.kt @@ -0,0 +1,48 @@ +/* + * Copyright 2026 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 . + */ + +@file:Suppress("unused") + +package com.lambda.config.serializers + +import com.lambda.config.Deserializer +import com.lambda.config.Serializer +import com.lambda.config.Stringifiable +import tools.jackson.core.JsonGenerator +import tools.jackson.core.JsonParser +import tools.jackson.databind.DeserializationContext +import tools.jackson.databind.SerializationContext +import java.awt.Color + +object ColorSerializer : Serializer(Color::class.java), Stringifiable { + override fun serialize(color: Color, gen: JsonGenerator, ctxt: SerializationContext) { + gen.writeString("${color.red},${color.green},${color.blue},${color.alpha}") + } + + override fun stringify(value: Color) = "${value.red},${value.green},${value.blue},${value.alpha}" +} + +object ColorDeserializer : Deserializer(Color::class.java) { + override fun deserialize(p: JsonParser, ctxt: DeserializationContext): Color { + val color = p.valueAsString.split(",") + return when (color.size) { + 3 -> Color(color[0].toInt(), color[1].toInt(), color[2].toInt()) + 4 -> Color(color[0].toInt(), color[1].toInt(), color[2].toInt(), color[3].toInt()) + else -> throw IllegalStateException("Invalid color format") + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/config/serializers/ConfigCategoryFallbackSerializer.kt b/src/main/kotlin/com/lambda/config/serializers/ConfigCategoryFallbackSerializer.kt new file mode 100644 index 000000000..bee75cfdc --- /dev/null +++ b/src/main/kotlin/com/lambda/config/serializers/ConfigCategoryFallbackSerializer.kt @@ -0,0 +1,217 @@ +/* + * Copyright 2026 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 . + */ + +@file:Suppress("unused") + +package com.lambda.config.serializers + +import com.lambda.Lambda.Log +import com.lambda.config.Config +import com.lambda.config.ConfigCategory +import com.lambda.config.Deserializer +import com.lambda.config.FallbackDeserializer +import com.lambda.config.FallbackSerializer +import com.lambda.config.Property +import com.lambda.config.PropertyLayer +import com.lambda.config.Serializer +import com.lambda.config.Setting +import com.lambda.config.SettingLayer +import com.lambda.config.migration.ConfigMigrationHandler +import tools.jackson.core.JsonGenerator +import tools.jackson.core.JsonParser +import tools.jackson.databind.DeserializationContext +import tools.jackson.databind.JsonNode +import tools.jackson.databind.SerializationContext + +object ConfigCategoryFallbackSerializer : FallbackSerializer(ConfigCategory::class.java) { + override fun serialize(category: ConfigCategory, gen: JsonGenerator, ctxt: SerializationContext) { + gen.writeStartObject() + val latestSchemaVersion = ConfigMigrationHandler.latestVersion(category) + if (latestSchemaVersion > 1) { + gen.writeNumberProperty( + ConfigMigrationHandler.schemaVersionKey(category) ?: ConfigMigrationHandler.DefaultSchemaVersionKey, + latestSchemaVersion + ) + } + category.configs.forEach { config -> + val serialized = mapper.valueToTree(config) + if (serialized.isEmpty) return@forEach + gen.writePOJOProperty(config.name, serialized) + } + gen.writeEndObject() + } +} + +object ConfigCategoryFallbackDeserializer : FallbackDeserializer(ConfigCategory::class.java) { + override fun deserialize(p: JsonParser, ctxt: DeserializationContext): ConfigCategory { + throw initFromJsonException("ConfigCategory") + } + + override fun deserialize(p: JsonParser, ctxt: DeserializationContext, category: ConfigCategory): ConfigCategory = + category.apply { + val categoryJson = mapper.readTree(p) + configs.forEach { config -> + val configJson = categoryJson.get(config.name) ?: return@forEach + mapper.updateValue(config, configJson) + } + } +} + +object ConfigFallbackSerializer : FallbackSerializer(Config::class.java) { + override fun serialize(config: Config, gen: JsonGenerator, ctxt: SerializationContext) { + gen.writeObjectPropertyStart(config.name) + val serializedSettings = mapper.valueToTree(config.settingLayers) + if (!serializedSettings.isEmpty) { + gen.writeName(config.settingLayers.name) + gen.writeTree(serializedSettings) + } + if (config.propertyLayers.layers.isNotEmpty()) { + gen.writePOJO(config.propertyLayers) + } + gen.writeEndObject() + } +} + +object ConfigFallbackDeserializer : FallbackDeserializer(Config::class.java) { + override fun deserialize(p: JsonParser, ctxt: DeserializationContext): Config { + throw initFromJsonException("Config") + } + + override fun deserialize(p: JsonParser, ctxt: DeserializationContext, config: Config): Config = + config.apply { + val configJson = mapper.readTree(p) + val settingsJson = configJson.get(settingLayers.name) + if (settingsJson != null && settingsJson.isObject) mapper.updateValue(settingLayers, settingsJson) + val propertiesJson = configJson.get(propertyLayers.name) + if (propertiesJson != null && propertiesJson.isObject) mapper.updateValue(propertyLayers, propertiesJson) + } +} + +object MultipleSerializers { + object SettingLayerMultipleFallbackSerializer : FallbackSerializer(SettingLayer.Multiple::class.java) { + override fun serialize(multiple: SettingLayer.Multiple, gen: JsonGenerator, ctxt: SerializationContext) { + gen.writeStartObject() + multiple.layers.forEach { layer -> + if (layer is SettingLayer.Single<*, *> && !layer.setting.isModified) return@forEach + val serialized = mapper.valueToTree(layer) + if (serialized.isObject && serialized.isEmpty) return@forEach + gen.writePOJOProperty(layer.name, serialized) + } + gen.writeEndObject() + } + } + + object SettingLayerMultipleFallbackDeserializer : FallbackDeserializer(SettingLayer.Multiple::class.java) { + override fun deserialize(p: JsonParser, ctxt: DeserializationContext): SettingLayer.Multiple { + throw initFromJsonException("SettingLayer.Multiple") + } + + override fun deserialize(p: JsonParser, ctxt: DeserializationContext, multiple: SettingLayer.Multiple): SettingLayer.Multiple = + multiple.apply { + val multipleJson = mapper.readTree(p) + layers.forEach { layer -> + val layerJson = multipleJson.get(layer.name) ?: return@forEach + mapper.updateValue(layer, layerJson) + } + } + } + + object PropertyLayerMultipleFallbackSerializer : FallbackSerializer(PropertyLayer.Multiple::class.java) { + override fun serialize(multiple: PropertyLayer.Multiple, gen: JsonGenerator, ctxt: SerializationContext) { + if (multiple.layers.isEmpty()) return + gen.writeObjectPropertyStart(multiple.name) + multiple.layers.forEach { layer -> + gen.writePOJOProperty(layer.name, layer) + } + gen.writeEndObject() + } + } + + object PropertyLayerMultipleFallbackDeserializer : FallbackDeserializer(PropertyLayer.Multiple::class.java) { + override fun deserialize(p: JsonParser, ctxt: DeserializationContext): PropertyLayer.Multiple { + throw initFromJsonException("PropertyLayer.Multiple") + } + + override fun deserialize(p: JsonParser, ctxt: DeserializationContext, multiple: PropertyLayer.Multiple) = + multiple.apply { + val multipleJson = mapper.readTree(p) + layers.forEach { layer -> + val layerJson = multipleJson.get(layer.name) ?: return@forEach + mapper.updateValue(layer, layerJson) + } + } + } +} + +object SingleSerializers { + object SettingLayerSingleFallbackSerializer : FallbackSerializer>(SettingLayer.Single::class.java) { + override fun serialize(single: SettingLayer.Single<*, *>, gen: JsonGenerator, ctxt: SerializationContext) { + gen.writePOJOProperty(single.name, single.setting) + } + } + + object SettingLayerSingleFallbackDeserializer : FallbackDeserializer>(SettingLayer.Single::class.java) { + override fun deserialize(p: JsonParser, ctxt: DeserializationContext): SettingLayer.Single<*, *> { + throw initFromJsonException("SettingLayer.Single") + } + + override fun deserialize(p: JsonParser, ctxt: DeserializationContext, single: SettingLayer.Single<*, *>): SettingLayer.Single<*, *> = + single.apply { + try { + mapper.updateValue(setting, mapper.readTree(p)) + } catch (e: Throwable) { + Log.error("Failed to deserialize setting '${name}'", e) + } + } + } + + object PropertyLayerSingleSerializer : Serializer(PropertyLayer.Single::class.java) { + override fun serialize(single: PropertyLayer.Single, gen: JsonGenerator, ctxt: SerializationContext?) { + gen.writePOJOProperty(single.name, single.property.value) + } + } + + object PropertyLayerSingleDeserializer : Deserializer(PropertyLayer.Single::class.java) { + override fun deserialize(p: JsonParser, ctxt: DeserializationContext): PropertyLayer.Single { + throw initFromJsonException("PropertyLayer.Single") + } + + override fun deserialize(p: JsonParser, ctxt: DeserializationContext, single: PropertyLayer.Single) = + single.apply { + @Suppress("unchecked_cast") + (property as Property).value = ctxt.readValue(p, property.value.javaClass) + } + } +} + +object SettingFallbackSerializer : FallbackSerializer>(Setting::class.java) { + override fun serialize(setting: Setting<*>, gen: JsonGenerator, ctxt: SerializationContext) { + gen.writePOJO(setting.originalCore.value) + } +} + +object SettingFallbackDeserializer : FallbackDeserializer>(Setting::class.java) { + override fun deserialize(p: JsonParser, ctxt: DeserializationContext): Setting<*> { + throw initFromJsonException("Setting") + } + + override fun deserialize(p: JsonParser, ctxt: DeserializationContext, setting: Setting<*>) = + setting.apply { + @Suppress("unchecked_cast") + (this as Setting).originalCore.value = ctxt.readValue(p, originalCore.value.javaClass) + } +} diff --git a/src/main/kotlin/com/lambda/config/serializers/FunctionSettingSerializer.kt b/src/main/kotlin/com/lambda/config/serializers/FunctionSettingSerializer.kt new file mode 100644 index 000000000..61a03e092 --- /dev/null +++ b/src/main/kotlin/com/lambda/config/serializers/FunctionSettingSerializer.kt @@ -0,0 +1,42 @@ +/* + * Copyright 2026 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 . + */ + +@file:Suppress("unused") + +package com.lambda.config.serializers + +import com.lambda.config.Deserializer +import com.lambda.config.Serializer +import com.lambda.config.settings.FunctionSetting +import tools.jackson.core.JsonGenerator +import tools.jackson.core.JsonParser +import tools.jackson.databind.DeserializationContext +import tools.jackson.databind.SerializationContext + +object FunctionSettingSerializer : Serializer>(FunctionSetting::class.java) { + override fun serialize(functionSetting: FunctionSetting<*, *>, gen: JsonGenerator, ctxt: SerializationContext) { + gen.writeNull() + } +} + +object FunctionSettingDeserializer : Deserializer>(FunctionSetting::class.java) { + override fun deserialize(p: JsonParser, ctxt: DeserializationContext): FunctionSetting<*, *> { + throw initFromJsonException("FunctionSetting") + } + + override fun deserialize(p: JsonParser, ctxt: DeserializationContext, functionSetting: FunctionSetting<*, *>): FunctionSetting<*, *> = functionSetting +} \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/config/serializer/ItemCodec.kt b/src/main/kotlin/com/lambda/config/serializers/ItemSerializer.kt similarity index 55% rename from src/main/kotlin/com/lambda/config/serializer/ItemCodec.kt rename to src/main/kotlin/com/lambda/config/serializers/ItemSerializer.kt index 1e7324dac..b6c401253 100644 --- a/src/main/kotlin/com/lambda/config/serializer/ItemCodec.kt +++ b/src/main/kotlin/com/lambda/config/serializers/ItemSerializer.kt @@ -15,32 +15,31 @@ * along with this program. If not, see . */ -package com.lambda.config.serializer +@file:Suppress("unused") -import com.google.gson.JsonDeserializationContext -import com.google.gson.JsonElement -import com.google.gson.JsonPrimitive -import com.google.gson.JsonSerializationContext -import com.lambda.config.Codec +package com.lambda.config.serializers + +import com.lambda.config.Deserializer +import com.lambda.config.Serializer import com.lambda.config.Stringifiable import net.minecraft.item.Item import net.minecraft.registry.Registries import net.minecraft.util.Identifier -import java.lang.reflect.Type - -object ItemCodec : Codec, Stringifiable { - override fun serialize( - item: Item, - typeOfSrc: Type, - context: JsonSerializationContext - ): JsonElement = JsonPrimitive(item.toString()) +import tools.jackson.core.JsonGenerator +import tools.jackson.core.JsonParser +import tools.jackson.databind.DeserializationContext +import tools.jackson.databind.SerializationContext - override fun deserialize( - json: JsonElement, - typeOfT: Type, - context: JsonDeserializationContext - ): Item = - Registries.ITEM.get(Identifier.of(json.asString)) // Watch out!! Errors are silently catched by gson!! +object ItemSerializer : Serializer(Item::class.java), Stringifiable { + override fun serialize(item: Item, gen: JsonGenerator, ctxt: SerializationContext) { + gen.writeString(item.toString()) + } override fun stringify(value: Item) = value.name.string.replaceFirstChar { it.uppercase() } +} + +object ItemDeserializer : Deserializer(Item::class.java) { + override fun deserialize(p: JsonParser, ctxt: DeserializationContext): Item { + return Registries.ITEM.get(Identifier.of(p.valueAsString)) + } } \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/config/serializers/ItemStackSerializer.kt b/src/main/kotlin/com/lambda/config/serializers/ItemStackSerializer.kt new file mode 100644 index 000000000..3d213039e --- /dev/null +++ b/src/main/kotlin/com/lambda/config/serializers/ItemStackSerializer.kt @@ -0,0 +1,43 @@ +/* + * Copyright 2026 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 . + */ + +@file:Suppress("unused") + +package com.lambda.config.serializers + +import com.lambda.config.Deserializer +import com.lambda.config.JsonOps +import com.lambda.config.Serializer +import com.lambda.config.Stringifiable +import net.minecraft.item.ItemStack +import tools.jackson.core.JsonGenerator +import tools.jackson.core.JsonParser +import tools.jackson.databind.DeserializationContext +import tools.jackson.databind.SerializationContext + +object ItemStackSerializer : Serializer(ItemStack::class.java), Stringifiable { + override fun serialize(itemStack: ItemStack, gen: JsonGenerator, ctxt: SerializationContext) { + gen.writeTree(ItemStack.CODEC.encodeStart(JsonOps.Uncompressed, itemStack).orThrow) + } + + override fun stringify(value: ItemStack) = value.itemName.string.uppercase() +} + +object ItemStackDeserializer : Deserializer(ItemStack::class.java) { + override fun deserialize(p: JsonParser, ctxt: DeserializationContext): ItemStack = + ItemStack.CODEC.parse(JsonOps.Uncompressed, mapper.readTree(p)).orThrow +} \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/config/serializers/KeyCodeSerializer.kt b/src/main/kotlin/com/lambda/config/serializers/KeyCodeSerializer.kt new file mode 100644 index 000000000..cba41b9a4 --- /dev/null +++ b/src/main/kotlin/com/lambda/config/serializers/KeyCodeSerializer.kt @@ -0,0 +1,39 @@ +/* + * Copyright 2026 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 . + */ + +@file:Suppress("unused") + +package com.lambda.config.serializers + +import com.lambda.config.Deserializer +import com.lambda.config.Serializer +import com.lambda.util.KeyCode +import tools.jackson.core.JsonGenerator +import tools.jackson.core.JsonParser +import tools.jackson.databind.DeserializationContext +import tools.jackson.databind.SerializationContext + +object KeyCodeSerializer : Serializer(KeyCode::class.java) { + override fun serialize(keyCode: KeyCode, gen: JsonGenerator, ctxt: SerializationContext) { + gen.writeString(keyCode.name) + } +} + +object KeyCodeDeserializer : Deserializer(KeyCode::class.java) { + override fun deserialize(p: JsonParser, ctxt: DeserializationContext): KeyCode = + KeyCode.fromKeyName(p.string) +} \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/config/serializers/TextSerializer.kt b/src/main/kotlin/com/lambda/config/serializers/TextSerializer.kt new file mode 100644 index 000000000..415ddb266 --- /dev/null +++ b/src/main/kotlin/com/lambda/config/serializers/TextSerializer.kt @@ -0,0 +1,41 @@ +/* + * Copyright 2026 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 . + */ + +@file:Suppress("unused") + +package com.lambda.config.serializers + +import com.lambda.config.Deserializer +import com.lambda.config.JsonOps +import com.lambda.config.Serializer +import net.minecraft.text.Text +import net.minecraft.text.TextCodecs +import tools.jackson.core.JsonGenerator +import tools.jackson.core.JsonParser +import tools.jackson.databind.DeserializationContext +import tools.jackson.databind.SerializationContext + +object TextSerializer : Serializer(Text::class.java) { + override fun serialize(text: Text, gen: JsonGenerator, ctxt: SerializationContext) { + gen.writeTree(TextCodecs.CODEC.encodeStart(JsonOps.Uncompressed, text).orThrow) + } +} + +object TextDeserializer : Deserializer(Text::class.java) { + override fun deserialize(p: JsonParser, ctxt: DeserializationContext): Text = + TextCodecs.CODEC.parse(JsonOps.Uncompressed, mapper.readTree(p)).orThrow +} \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/config/serializers/UuidSerializer.kt b/src/main/kotlin/com/lambda/config/serializers/UuidSerializer.kt new file mode 100644 index 000000000..2d570821e --- /dev/null +++ b/src/main/kotlin/com/lambda/config/serializers/UuidSerializer.kt @@ -0,0 +1,55 @@ +/* + * Copyright 2026 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 . + */ + +@file:Suppress("unused") + +package com.lambda.config.serializers + +import com.lambda.config.Deserializer +import com.lambda.config.Serializer +import com.lambda.config.Stringifiable +import tools.jackson.core.JsonGenerator +import tools.jackson.core.JsonParser +import tools.jackson.databind.DeserializationContext +import tools.jackson.databind.SerializationContext +import java.util.* + +object UuidSerializer : Serializer(UUID::class.java), Stringifiable { + override fun serialize(uuid: UUID, gen: JsonGenerator, ctxt: SerializationContext) { + gen.writeString(uuid.toString()) + } + + override fun stringify(value: UUID) = value.toString() +} + +object UuidDeserializer : Deserializer(UUID::class.java) { + override fun deserialize(p: JsonParser, ctxt: DeserializationContext): UUID { + val jsonNode = mapper.readTree(p) + + val rawId = when { + jsonNode.isString -> jsonNode.stringValue() + jsonNode.isObject && jsonNode.has("id") -> jsonNode.get("id").stringValue() + else -> throw IllegalStateException("Cannot deserialize UUID from: $jsonNode") + } + + val parsedId = if (rawId.length == 32) + rawId.replace(Regex("(\\w{8})(\\w{4})(\\w{4})(\\w{4})(\\w{12})"), "$1-$2-$3-$4-$5") + else rawId + + return UUID.fromString(parsedId) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/config/settings/CharSetting.kt b/src/main/kotlin/com/lambda/config/settings/CharSetting.kt index 7c13a8043..ddaa37003 100644 --- a/src/main/kotlin/com/lambda/config/settings/CharSetting.kt +++ b/src/main/kotlin/com/lambda/config/settings/CharSetting.kt @@ -17,37 +17,40 @@ package com.lambda.config.settings -import com.google.gson.reflect.TypeToken import com.lambda.brigadier.CommandResult.Companion.failure import com.lambda.brigadier.CommandResult.Companion.success import com.lambda.brigadier.argument.value import com.lambda.brigadier.argument.word import com.lambda.brigadier.executeWithResult import com.lambda.brigadier.required +import com.lambda.config.Config import com.lambda.config.Setting import com.lambda.config.SettingCore +import com.lambda.config.SettingLayer import com.lambda.gui.dsl.ImGuiBuilder import com.lambda.util.extension.CommandBuilder import net.minecraft.command.CommandRegistryAccess /** - * @see [com.lambda.config.Configurable] + * @see [com.lambda.config.Config] */ -class CharSetting(defaultValue: Char) : SettingCore( - defaultValue, - TypeToken.get(Char::class.java).type -) { - context(setting: Setting<*, Char>) +class CharSetting( + name: String, + description: String, + config: Config, + layer: SettingLayer.Single<*, Char>, + defaultValue: Char, + visibility: () -> Boolean +) : Setting(name, description, SettingCore(defaultValue), config, layer, visibility) { override fun ImGuiBuilder.buildLayout() {} - context(setting: Setting<*, Char>) - override fun CommandBuilder.buildCommand(registry: CommandRegistryAccess) { - required(word(setting.name)) { parameter -> - executeWithResult { - val char = parameter().value().firstOrNull() ?: return@executeWithResult failure("Cant parse char type") - setting.trySetValue(char) - return@executeWithResult success() - } - } - } -} + override fun CommandBuilder.buildCommand(registry: CommandRegistryAccess) { + required(word(name)) { parameter -> + executeWithResult { + val char = parameter().value().firstOrNull() ?: return@executeWithResult failure("Can't parse char type") + trySetValue(char) + return@executeWithResult success() + } + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/config/settings/FunctionSetting.kt b/src/main/kotlin/com/lambda/config/settings/FunctionSetting.kt index 96eabb9cd..b4ca58e33 100644 --- a/src/main/kotlin/com/lambda/config/settings/FunctionSetting.kt +++ b/src/main/kotlin/com/lambda/config/settings/FunctionSetting.kt @@ -17,25 +17,22 @@ package com.lambda.config.settings -import com.google.gson.JsonElement -import com.google.gson.JsonNull -import com.google.gson.reflect.TypeToken +import com.lambda.config.Config import com.lambda.config.Setting import com.lambda.config.SettingCore +import com.lambda.config.SettingLayer import com.lambda.gui.dsl.ImGuiBuilder -open class FunctionSetting(defaultValue: () -> T) : SettingCore<() -> T>( - defaultValue, - TypeToken.get(defaultValue::class.java).type -) { - context(setting: Setting<*, () -> T>) +class FunctionSetting R, R>( + name: String, + description: String, + defaultValue: T, + config: Config, + layer: SettingLayer.Single, T>, + visibility: () -> Boolean +) : Setting(name, description, SettingCore(defaultValue), config, layer, visibility) { override fun ImGuiBuilder.buildLayout() { - button(setting.name) { value() } - lambdaTooltip(setting.description) + button(name) { value() } + lambdaTooltip(description) } - - context(setting: Setting<*, () -> T>) - override fun toJson(): JsonElement = JsonNull.INSTANCE - context(setting: Setting<*, () -> T>) - override fun loadFromJson(serialized: JsonElement) { value = defaultValue } } diff --git a/src/main/kotlin/com/lambda/config/settings/NumericSetting.kt b/src/main/kotlin/com/lambda/config/settings/NumericSetting.kt index 526b556c7..46a8ccbe8 100644 --- a/src/main/kotlin/com/lambda/config/settings/NumericSetting.kt +++ b/src/main/kotlin/com/lambda/config/settings/NumericSetting.kt @@ -17,11 +17,12 @@ package com.lambda.config.settings -import com.google.gson.reflect.TypeToken +import com.lambda.config.Config +import com.lambda.config.SettingEditor import com.lambda.config.Setting import com.lambda.config.SettingCore import com.lambda.config.SettingEditorDsl -import com.lambda.config.SettingGroupEditor +import com.lambda.config.SettingLayer import com.lambda.gui.dsl.ImGuiBuilder import com.lambda.imgui.ImGui import com.lambda.imgui.ImGui.calcTextSize @@ -31,87 +32,85 @@ import java.text.NumberFormat import java.util.* /** - * @see [com.lambda.config.Configurable] + * @see [com.lambda.config.Config] */ abstract class NumericSetting( + name: String, + description: String, + config: Config, + layer: SettingLayer.Single<*, T>, defaultValue: T, + visibility: () -> Boolean, open var range: ClosedRange, open var step: T, var unit: String -) : SettingCore( - defaultValue, - TypeToken.get(defaultValue::class.java).type -) where T : Number, T : Comparable { +) : Setting(name, description, SettingCore(defaultValue), config, layer, visibility) where T : Number, T : Comparable { override var value: T get() = super.value set(newVal) { super.value = newVal.coerceIn(range) } - private val formatter = NumberFormat.getNumberInstance(Locale.getDefault()) + private val formatter = NumberFormat.getNumberInstance(Locale.getDefault()) - override fun toString() = "${formatter.format(value)}$unit" + override fun toString() = "${formatter.format(value)}$unit" - /** - * Subclasses must implement this to provide their specific slider widget. - */ - context(setting: Setting<*, T>) - protected abstract fun ImGuiBuilder.buildSlider() + /** + * Subclasses must implement this to provide their specific slider widget. + */ + protected abstract fun ImGuiBuilder.buildSlider() - context(setting: Setting<*, T>) - override fun ImGuiBuilder.buildLayout() { - val showReset = setting.isModified - val resetButtonText = "R" - val valueString = this@NumericSetting.toString() + override fun ImGuiBuilder.buildLayout() { + val showReset = isModified + val resetButtonText = "R" + val valueString = this@NumericSetting.toString() - buildSlider() - lambdaTooltip(setting.description) + buildSlider() + lambdaTooltip(description) - val itemRectMin = ImGui.getItemRectMin() - val itemRectMax = ImGui.getItemRectMax() - val textHeight = ImGui.getTextLineHeight() - val textY = itemRectMin.y + (itemRectMax.y - itemRectMin.y - textHeight) / 2.0f - val labelWidth = calcTextSize(setting.name).x - val valueWidth = calcTextSize(valueString).x + val itemRectMin = ImGui.getItemRectMin() + val itemRectMax = ImGui.getItemRectMax() + val textHeight = ImGui.getTextLineHeight() + val textY = itemRectMin.y + (itemRectMax.y - itemRectMin.y - textHeight) / 2.0f + val labelWidth = calcTextSize(name).x + val valueWidth = calcTextSize(valueString).x - val labelEndPosX = itemRectMin.x + style.framePadding.x * 2 + labelWidth - val valueStartPosX = itemRectMax.x - style.framePadding.x * 2 - valueWidth + val labelEndPosX = itemRectMin.x + style.framePadding.x * 2 + labelWidth + val valueStartPosX = itemRectMax.x - style.framePadding.x * 2 - valueWidth - windowDrawList.addText(itemRectMin.x + style.framePadding.x * 2, textY, ImGui.getColorU32(ImGuiCol.Text), setting.name) - if (labelEndPosX < valueStartPosX) { - windowDrawList.addText(valueStartPosX, textY, ImGui.getColorU32(ImGuiCol.Text), valueString) - } + windowDrawList.addText(itemRectMin.x + style.framePadding.x * 2, textY, ImGui.getColorU32(ImGuiCol.Text), name) + if (labelEndPosX < valueStartPosX) { + windowDrawList.addText(valueStartPosX, textY, ImGui.getColorU32(ImGuiCol.Text), valueString) + } - sameLine(0.0f, style.itemSpacing.x) - if (showReset) { - button("$resetButtonText##${setting.name}") { - setting.reset() - } - onItemHover { - tooltip { text("Reset to default") } - } - } else { - dummy(calcTextSize(resetButtonText).x + style.framePadding.x * 2.0f, ImGui.getFrameHeight()) - } - } + sameLine(0.0f, style.itemSpacing.x) + if (showReset) { + button("$resetButtonText##$name") { + reset() + } + onItemHover { + tooltip { text("Reset to default") } + } + } else { + dummy(calcTextSize(resetButtonText).x + style.framePadding.x * 2.0f, ImGui.getFrameHeight()) + } + } - companion object { - @SettingEditorDsl - @Suppress("unchecked_cast") - fun SettingGroupEditor.TypedEditBuilder.range(range: ClosedRange) where T : Number, T : Comparable { - (settings as Collection>).forEach { it.range = range } - } + @Suppress("unchecked_cast", "unused") + companion object { + @SettingEditorDsl + fun SettingEditor.TypedEditBuilder.range(range: ClosedRange) where T : Number, T : Comparable { + (settings as Collection>).forEach { it.range = range } + } - @SettingEditorDsl - @Suppress("unchecked_cast") - fun SettingGroupEditor.TypedEditBuilder.step(step: T) where T : Number, T : Comparable { - (settings as Collection>).forEach { it.step = step } - } + @SettingEditorDsl + fun SettingEditor.TypedEditBuilder.step(step: T) where T : Number, T : Comparable { + (settings as Collection>).forEach { it.step = step } + } - @SettingEditorDsl - @Suppress("unchecked_cast") - fun SettingGroupEditor.TypedEditBuilder.unit(unit: String) where T : Number, T : Comparable { - (settings as Collection>).forEach { it.unit = unit} - } - } + @SettingEditorDsl + fun SettingEditor.TypedEditBuilder.unit(unit: String) where T : Number, T : Comparable { + (settings as Collection>).forEach { it.unit = unit } + } + } } diff --git a/src/main/kotlin/com/lambda/config/settings/StringSetting.kt b/src/main/kotlin/com/lambda/config/settings/StringSetting.kt index d313dff90..5f160f9f6 100644 --- a/src/main/kotlin/com/lambda/config/settings/StringSetting.kt +++ b/src/main/kotlin/com/lambda/config/settings/StringSetting.kt @@ -17,61 +17,62 @@ package com.lambda.config.settings -import com.google.gson.reflect.TypeToken import com.lambda.brigadier.argument.greedyString import com.lambda.brigadier.argument.value import com.lambda.brigadier.execute import com.lambda.brigadier.required +import com.lambda.config.Config +import com.lambda.config.SettingEditor import com.lambda.config.Setting import com.lambda.config.SettingCore import com.lambda.config.SettingEditorDsl -import com.lambda.config.SettingGroupEditor +import com.lambda.config.SettingLayer import com.lambda.gui.dsl.ImGuiBuilder -import com.lambda.util.extension.CommandBuilder import com.lambda.imgui.flag.ImGuiInputTextFlags +import com.lambda.util.extension.CommandBuilder import net.minecraft.command.CommandRegistryAccess /** - * @see [com.lambda.config.Configurable] + * @see [com.lambda.config.Config] */ class StringSetting( + name: String, + description: String, + config: Config, + layer: SettingLayer.Single<*, String>, defaultValue: String, + visibility: () -> Boolean, var multiline: Boolean = false, var flags: Int = ImGuiInputTextFlags.None, -) : SettingCore( - defaultValue, - TypeToken.get(String::class.java).type -) { - context(setting: Setting<*, String>) +) : Setting(name, description, SettingCore(defaultValue), config, layer, visibility) { + override fun ImGuiBuilder.buildLayout() { if (multiline) { - inputTextMultiline(setting.name, ::value, flags = flags) + inputTextMultiline(name, ::value, flags = flags) } else { - inputText(setting.name, ::value, flags) + inputText(name, ::value, flags) } - lambdaTooltip(setting.description) + lambdaTooltip(description) } - context(setting: Setting<*, String>) override fun CommandBuilder.buildCommand(registry: CommandRegistryAccess) { - required(greedyString(setting.name)) { parameter -> + required(greedyString(name)) { parameter -> execute { - setting.trySetValue(parameter().value()) + trySetValue(parameter().value()) } } } + @Suppress("unused", "unchecked_cast") companion object { @SettingEditorDsl - @Suppress("unchecked_cast") - fun SettingGroupEditor.TypedEditBuilder.multiline(multiline: Boolean) { + fun SettingEditor.TypedEditBuilder.multiline(multiline: Boolean) { (settings as Collection).forEach { it.multiline = multiline } } @SettingEditorDsl - @Suppress("unchecked_cast") - fun SettingGroupEditor.TypedEditBuilder.flags(flags: Int) { + fun SettingEditor.TypedEditBuilder.flags(flags: Int) { (settings as Collection).forEach { it.flags = flags } } } -} +} \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/config/groups/ActionConfig.kt b/src/main/kotlin/com/lambda/config/settings/blocks/ActionConfig.kt similarity index 97% rename from src/main/kotlin/com/lambda/config/groups/ActionConfig.kt rename to src/main/kotlin/com/lambda/config/settings/blocks/ActionConfig.kt index 561a72ca1..f1ff60dd3 100644 --- a/src/main/kotlin/com/lambda/config/groups/ActionConfig.kt +++ b/src/main/kotlin/com/lambda/config/settings/blocks/ActionConfig.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package com.lambda.config.groups +package com.lambda.config.settings.blocks import com.lambda.event.events.TickEvent import com.lambda.util.Describable diff --git a/src/main/kotlin/com/lambda/interaction/managers/breaking/BreakConfig.kt b/src/main/kotlin/com/lambda/config/settings/blocks/BreakConfig.kt similarity index 94% rename from src/main/kotlin/com/lambda/interaction/managers/breaking/BreakConfig.kt rename to src/main/kotlin/com/lambda/config/settings/blocks/BreakConfig.kt index 7f93f567b..6c4d44764 100644 --- a/src/main/kotlin/com/lambda/interaction/managers/breaking/BreakConfig.kt +++ b/src/main/kotlin/com/lambda/config/settings/blocks/BreakConfig.kt @@ -15,18 +15,15 @@ * along with this program. If not, see . */ -package com.lambda.interaction.managers.breaking +package com.lambda.config.settings.blocks -import com.lambda.config.ISettingGroup -import com.lambda.config.groups.ActionConfig -import com.lambda.config.groups.BuildConfig -import com.lambda.config.groups.LineConfig import com.lambda.util.Describable import com.lambda.util.NamedEnum import net.minecraft.block.Block import java.awt.Color -interface BreakConfig : ActionConfig, ISettingGroup { +@Suppress("unused") +interface BreakConfig : ActionConfig { val breakMode: BreakMode val rebreak: Boolean @@ -145,4 +142,4 @@ interface BreakConfig : ActionConfig, ISettingGroup { Blacklist("Blacklist", "Only break blocks not in the blacklist"), None("None", "Breaks all blocks") } -} +} \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/config/settings/blocks/BreakSettings.kt b/src/main/kotlin/com/lambda/config/settings/blocks/BreakSettings.kt new file mode 100644 index 000000000..f00813cec --- /dev/null +++ b/src/main/kotlin/com/lambda/config/settings/blocks/BreakSettings.kt @@ -0,0 +1,99 @@ +/* + * Copyright 2026 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.settings.blocks + +import com.lambda.config.Config +import com.lambda.config.SettingEditor.hide +import com.lambda.config.Group +import com.lambda.config.ConfigBlock +import com.lambda.config.settings.blocks.BreakConfig.AnimationMode +import com.lambda.config.settings.blocks.BreakConfig.BreakConfirmationMode +import com.lambda.config.settings.blocks.BreakConfig.BreakMode +import com.lambda.config.settings.blocks.BreakConfig.SwingMode +import com.lambda.config.settings.blocks.BreakConfig.WhitelistMode +import com.lambda.config.withEdits +import com.lambda.event.events.TickEvent +import com.lambda.event.events.TickEvent.Companion.ALL_STAGES +import net.minecraft.registry.Registries +import java.awt.Color + +class BreakSettings(override val c: Config) : BreakConfig, ConfigBlock { + companion object { + const val CosmeticGroup = "Cosmetic" + } + + // General + override val breakMode by c.setting("Break Mode", BreakMode.Packet) + override val sorter by c.setting("Break Sorter", ActionConfig.SortMode.Tool, "The order in which breaks are performed") + override val rebreak by c.setting("Rebreak", true, "Re-breaks blocks after they've been broken once") + // Double break + override val doubleBreak by c.setting("Double Break", true, "Allows breaking two blocks at once") + override val unsafeCancels by c.setting("Unsafe Cancels", true, "Allows cancelling block breaking even if the server might continue breaking sever side, potentially causing unexpected state changes") { doubleBreak } + // Fixes / Delays + override val breakThreshold by c.setting("Break Threshold", 0.70f, 0.1f..1.0f, 0.01f, "The break amount at which the block is considered broken") + override val fudgeFactor by c.setting("Fudge Factor", 1, 0..5, 1, "The number of ticks to add to the break time, usually to account for server lag") + override val serverSwapTicks by c.setting("Server Swap", 0, 0..5, 1, "The number of ticks to give the server time to recognize the player attributes on the swapped item", " tick(s)") +// @Group(GeneralGroup) override val desyncFix by c.setting("Desync Fix", false, "Predicts if the players breaking will be slowed next tick as block break packets are processed using the players next position") { page == Page.General } + override val breakDelay by c.setting("Break Delay", 0, 0..6, 1, "The delay between breaking blocks", " tick(s)") + // Timing + override val tickStageMask by c.setting("Break Stage Mask", setOf(TickEvent.Input.Post), ALL_STAGES.toSet(), "The sub-tick timing at which break actions can be performed", displayClassName = true) + override val swapMode by c.setting("Break Swap Mode", BreakConfig.SwapMode.End, "Decides when to swap to the best suited tool when breaking a block") + override val swing by c.setting("Swing Mode", SwingMode.Constant, "The times at which to swing the players hand") + override val swingType by c.setting("Break Swing Type", BuildConfig.SwingType.Vanilla, "The style of swing") { swing != SwingMode.None } + // Rotate + override val rotate by c.setting("Rotate For Break", false, "Rotate towards block while breaking") + // Pending / Post + override val breakConfirmation by c.setting("Break Confirmation", BreakConfirmationMode.BreakThenAwait, "The style of confirmation used when breaking") + override val breaksPerTick by c.setting("Breaks Per Tick", 30, 1..30, 1, "Maximum instant block breaks per tick") + override val whitelistMode by c.setting("Whitelist Mode", WhitelistMode.None, "The type of block selection used") + override val whitelist by c.setting("Whitelist", mutableSetOf(), Registries.BLOCK.toSet(), "Only these selected blocks are allowed to be broken") { whitelistMode == WhitelistMode.Whitelist } + override val blacklist by c.setting("Blacklist", mutableSetOf(), Registries.BLOCK.toSet(), "These selected blocks are not allowed to be broken") { whitelistMode == WhitelistMode.Blacklist } + override val avoidFluids by c.setting("Avoid Fluids", true, "Avoids breaking blocks that would cause fluids to spill") + override val avoidSupporting by c.setting("Avoid Supporting", true, "Avoids breaking the block supporting the player") + override val fillFluids by c.setting("Fill Fluids", true, "Fills fluids in order to break blocks that would initially spill them") { avoidFluids } + // Tool + override val efficientOnly by c.setting("Efficient Tools Only", true, "Only use tools suitable for the given block (will get the item drop)") { swapMode.isEnabled() } + override val suitableToolsOnly by c.setting("Suitable Tools Only", true, "Only use tools suitable for the given block (will get the item drop)") { swapMode.isEnabled() } + override val forceSilkTouch by c.setting("Force Silk Touch", false, "Force silk touch when breaking blocks") { swapMode.isEnabled() } + override val forceFortunePickaxe by c.setting("Force Fortune Pickaxe", false, "Force fortune pickaxe when breaking blocks") { swapMode.isEnabled() } + override val minFortuneLevel by c.setting("Min Fortune Level", 1, 1..3, 1, "The minimum fortune level to use") { swapMode.isEnabled() && forceFortunePickaxe } + + // Cosmetics + @Group(CosmeticGroup) override val sounds by c.setting("Break Sounds", true, "Plays the breaking sounds") + @Group(CosmeticGroup) override val particles by c.setting("Particles", true, "Renders the breaking particles") + @Group(CosmeticGroup) override val breakingTexture by c.setting("Breaking Overlay", true, "Overlays the breaking texture at its different stages") + // Modes + @Group(CosmeticGroup) override val renders by c.setting("Renders", true, "Enables the render settings for breaking progress") + @Group(CosmeticGroup) override val animation by c.setting("Animation", AnimationMode.Out, "The style of animation used for the box") { renders } + // Fill + @Group(CosmeticGroup) override val fill by c.setting("Fill", true, "Renders the sides of the box to display break progress") { renders } + @Group(CosmeticGroup) override val dynamicFillColor by c.setting("Dynamic Colour", true, "Enables fill color interpolation from start to finish for fill when breaking a block") { renders && fill } + @Group(CosmeticGroup) override val staticFillColor by c.setting("Fill Color", Color(255, 0, 0, 60), "The color of the fill") { renders && !dynamicFillColor && fill } + @Group(CosmeticGroup) override val startFillColor by c.setting("Start Fill Color", Color(255, 0, 0, 60), "The color of the fill at the start of breaking") { renders && dynamicFillColor && fill } + @Group(CosmeticGroup) override val endFillColor by c.setting("End Fill Color", Color(0, 255, 0, 60), "The color of the fill at the end of breaking") { renders && dynamicFillColor && fill } + // Outline + @Group(CosmeticGroup) override val outline by c.setting("Outline", true, "Renders the lines of the box to display break progress") { renders } + @Group(CosmeticGroup) override val outlineConfig by c.configBlock(WorldLineSettings(c)) + .withEdits(c) { + hide(::startColor, ::endColor) + } + @Group(CosmeticGroup) override val dynamicOutlineColor by c.setting("Dynamic Outline Color", true, "Enables color interpolation from start to finish for the outline when breaking a block") { renders && outline } + @Group(CosmeticGroup) override val staticOutlineColor by c.setting("Outline Color", Color.RED, "The Color of the outline at the start of breaking") { renders && !dynamicOutlineColor && outline } + @Group(CosmeticGroup) override val startOutlineColor by c.setting("Start Outline Color", Color.RED, "The color of the outline at the start of breaking") { renders && dynamicOutlineColor && outline } + @Group(CosmeticGroup) override val endOutlineColor by c.setting("End Outline Color", Color.GREEN, "The color of the outline at the end of breaking") { renders && dynamicOutlineColor && outline } +} diff --git a/src/main/kotlin/com/lambda/config/groups/BuildConfig.kt b/src/main/kotlin/com/lambda/config/settings/blocks/BuildConfig.kt similarity index 57% rename from src/main/kotlin/com/lambda/config/groups/BuildConfig.kt rename to src/main/kotlin/com/lambda/config/settings/blocks/BuildConfig.kt index 8752d08c9..a1d2518a3 100644 --- a/src/main/kotlin/com/lambda/config/groups/BuildConfig.kt +++ b/src/main/kotlin/com/lambda/config/settings/blocks/BuildConfig.kt @@ -15,14 +15,17 @@ * along with this program. If not, see . */ -package com.lambda.config.groups +package com.lambda.config.settings.blocks -import com.lambda.config.ISettingGroup -import com.lambda.interaction.managers.rotating.visibilty.PointSelection +import com.lambda.interaction.managers.rotating.Rotation.Companion.dist +import com.lambda.interaction.managers.rotating.RotationManager import com.lambda.util.Describable import com.lambda.util.NamedEnum +import com.lambda.util.math.distSq +import com.lambda.util.math.times +import com.lambda.util.player.CheckedHit -interface BuildConfig : ISettingGroup { +interface BuildConfig { val breakBlocks: Boolean val placeBlocks: Boolean val interactBlocks: Boolean @@ -57,4 +60,33 @@ interface BuildConfig : ISettingGroup { Server("Server", "Only notify the server to swing; local animation may not play unless the server echoes it."), Client("Client", "Only play the local swing animation; does not notify the server (purely visual).") } + + @Suppress("unused") + enum class PointSelection( + override val displayName: String, + override val description: String, + val select: (Collection) -> CheckedHit? + ) : NamedEnum, Describable { + ByRotation( + "By Rotation", + "Choose the point that needs the least rotation from your current view (minimal camera turn).", + select = { hits -> + hits.minByOrNull { RotationManager.activeRotation dist it.rotation } + } + ), + Optimum( + "Optimum", + "Choose the point closest to the average of all candidates (balanced and stable aim).", + select = { hits -> + val optimum = hits + .mapNotNull { it.hit.pos } + .reduceOrNull { acc, pos -> acc.add(pos) } + ?.times(1 / hits.size.toDouble()) + + optimum?.let { center -> + hits.minByOrNull { it.hit.pos?.distSq(center) ?: 0.0 } + } + } + ) + } } diff --git a/src/main/kotlin/com/lambda/config/settings/blocks/BuildSettings.kt b/src/main/kotlin/com/lambda/config/settings/blocks/BuildSettings.kt new file mode 100644 index 000000000..7f2bf9760 --- /dev/null +++ b/src/main/kotlin/com/lambda/config/settings/blocks/BuildSettings.kt @@ -0,0 +1,58 @@ +/* + * Copyright 2026 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.settings.blocks + +import com.lambda.config.Config +import com.lambda.config.Group +import com.lambda.config.ConfigBlock +import kotlin.math.max + +class BuildSettings(override val c: Config) : BuildConfig, ConfigBlock { + companion object { + private const val GeneralGroup = "General" + private const val PacketLimitsGroup = "Packet Limits" + private const val ReachGroup = "Reach" + private const val ScanGroup = "Scan" + } + + @Group(GeneralGroup) override val breakBlocks by c.setting("Break", true, "Break blocks") + @Group(GeneralGroup) override val placeBlocks by c.setting("Place", true, "Place blocks") + @Group(GeneralGroup) override val interactBlocks by c.setting("Interact", true, "Interact blocks") + + @Group(GeneralGroup) override val pathing by c.setting("Pathing", false, "Path to blocks") + @Group(GeneralGroup) override val stayInRange by c.setting("Stay In Range", false, "Stay in range of blocks") + @Group(GeneralGroup) override val collectDrops by c.setting("Collect All Drops", false, "Collect all drops when breaking blocks") + @Group(GeneralGroup) override val spleefEntities by c.setting("Spleef Entities", false, "Breaks blocks beneath entities blocking placements to get them out of the way") + @Group(GeneralGroup) override val maxPendingActions by c.setting("Max Pending Actions", 15, 1..30, 1, "The maximum count of pending interactions to allow before pausing future interactions") + @Group(GeneralGroup) override val actionTimeout by c.setting("Action Timeout", 10, 1..30, 1, "Timeout for block breaks in ticks", unit = " ticks") + @Group(GeneralGroup) override val maxBuildDependencies by c.setting("Max Sim Dependencies", 3, 0..10, 1, "Maximum dependency build results") + + @Group(PacketLimitsGroup) override val limitTimeframe by c.setting("Limit Timeframe", 310, 50..1500, 1, "The timeframe in which the limit is bound to", "ms") + @Group(PacketLimitsGroup) override val actionLimit by c.setting("Action Limit", 59, 1..100, 1, "The maximum allowed action packets to be sent to the server per given timeframe") + @Group(PacketLimitsGroup) override val interactionLimit by c.setting("Interaction Limit", 9, 1..20, 1, "The maximum allowed interaction packets to be sent to the server per given timeframe") + @Group(PacketLimitsGroup) override val inventoryLimit by c.setting("Inventory Limit", 5, 1..100, 1, "The maximum allowed inventory packets to be sent to the server per given timeframe") + + @Group(ReachGroup) override var blockReach by c.setting("Interact Reach", 4.5, 1.0..7.0, 0.01, "Maximum block interaction distance") + @Group(ReachGroup) override var entityReach by c.setting("Attack Reach", 3.0, 1.0..7.0, 0.01, "Maximum entity interaction distance") + override val scanReach: Double get() = max(entityReach, blockReach) + + @Group(ScanGroup) override val checkSideVisibility by c.setting("Visibility Check", false, "Whether to check if an AABB side is visible") + @Group(ScanGroup) override val strictRayCast by c.setting("Strict Raycast", false, "Whether to include the environment to the ray cast context") + @Group(ScanGroup) override val resolution by c.setting("Resolution", 5, 1..20, 1, "The amount of grid divisions per surface of the hit box", "") { strictRayCast } + @Group(ScanGroup) override val pointSelection by c.setting("Point Selection", BuildConfig.PointSelection.Optimum, "The strategy to select the best hit point") +} diff --git a/src/main/kotlin/com/lambda/config/groups/EatConfig.kt b/src/main/kotlin/com/lambda/config/settings/blocks/EatConfig.kt similarity index 97% rename from src/main/kotlin/com/lambda/config/groups/EatConfig.kt rename to src/main/kotlin/com/lambda/config/settings/blocks/EatConfig.kt index 31e4ba5b0..6975c721f 100644 --- a/src/main/kotlin/com/lambda/config/groups/EatConfig.kt +++ b/src/main/kotlin/com/lambda/config/settings/blocks/EatConfig.kt @@ -15,9 +15,8 @@ * along with this program. If not, see . */ -package com.lambda.config.groups +package com.lambda.config.settings.blocks -import com.lambda.config.ISettingGroup import com.lambda.context.Automated import com.lambda.context.AutomatedSafeContext import com.lambda.interaction.material.StackSelection.Companion.selectStack @@ -29,7 +28,7 @@ import net.minecraft.entity.effect.StatusEffects import net.minecraft.item.Item import net.minecraft.item.ItemStack -interface EatConfig : ISettingGroup { +interface EatConfig { val eatOnHunger: Boolean val minFoodLevel: Int val nutritiousFood: Collection @@ -54,6 +53,7 @@ interface EatConfig : ISettingGroup { EatUntilFull("Eat Until Full", "Eats food until the hunger bar is completely full. May waste some food."), } + @Suppress("unused") enum class SelectionPriority( val comparator: Comparator, override val displayName: String, diff --git a/src/main/kotlin/com/lambda/config/settings/blocks/EatSettings.kt b/src/main/kotlin/com/lambda/config/settings/blocks/EatSettings.kt new file mode 100644 index 000000000..0b4daa0a2 --- /dev/null +++ b/src/main/kotlin/com/lambda/config/settings/blocks/EatSettings.kt @@ -0,0 +1,42 @@ +/* + * Copyright 2026 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.settings.blocks + +import com.lambda.config.Config +import com.lambda.config.ConfigBlock +import net.minecraft.item.Items + +class EatSettings(override val c: Config) : EatConfig, ConfigBlock { + val nutritiousFoodDefaults = listOf(Items.APPLE, Items.BAKED_POTATO, Items.BEEF, Items.BEETROOT, Items.BEETROOT_SOUP, Items.BREAD, Items.CARROT, Items.CHICKEN, Items.CHORUS_FRUIT, Items.COD, Items.COOKED_BEEF, Items.COOKED_CHICKEN, Items.COOKED_COD, Items.COOKED_MUTTON, Items.COOKED_PORKCHOP, Items.COOKED_RABBIT, Items.COOKED_SALMON, Items.COOKIE, Items.DRIED_KELP, Items.ENCHANTED_GOLDEN_APPLE, Items.GOLDEN_APPLE, Items.GOLDEN_CARROT, Items.HONEY_BOTTLE, Items.MELON_SLICE, Items.MUSHROOM_STEW, Items.MUTTON, Items.POISONOUS_POTATO, Items.PORKCHOP, Items.POTATO, Items.PUFFERFISH, Items.PUMPKIN_PIE, Items.RABBIT, Items.RABBIT_STEW, Items.ROTTEN_FLESH, Items.SALMON, Items.SPIDER_EYE, Items.SUSPICIOUS_STEW, Items.SWEET_BERRIES, Items.GLOW_BERRIES, Items.TROPICAL_FISH) + val resistanceFoodDefaults = listOf(Items.ENCHANTED_GOLDEN_APPLE) + val regenerationFoodDefaults = listOf(Items.ENCHANTED_GOLDEN_APPLE, Items.GOLDEN_APPLE) + val negativeFoodDefaults = listOf(Items.CHICKEN, Items.POISONOUS_POTATO, Items.PUFFERFISH, Items.ROTTEN_FLESH, Items.SPIDER_EYE) + + override val eatOnHunger by c.setting("Eat On Hunger", true, "Whether to eat when hungry") + override val minFoodLevel by c.setting("Minimum Food Level", 6, 0..20, 1, "The minimum food level to eat food", " food level") { eatOnHunger } + override val saturated by c.setting("Saturated", EatConfig.Saturation.EatSmart, "When to stop eating") { eatOnHunger } + override val nutritiousFood by c.setting("Nutritious Food", nutritiousFoodDefaults, nutritiousFoodDefaults, "Items that are be considered nutritious") { eatOnHunger } + override val selectionPriority by c.setting("Selection Priority", EatConfig.SelectionPriority.MostNutritious, "The priority for selecting food items") { eatOnHunger } + override val eatOnFire by c.setting("Eat On Fire", true, "Whether to eat when on fire") + override val resistanceFood by c.setting("Resistance Food", resistanceFoodDefaults, resistanceFoodDefaults, "Items that give Fire Resistance") { eatOnFire } + override val eatOnDamage by c.setting("Eat On Damage", true, "Whether to eat when damaged") + override val minDamage by c.setting("Minimum Damage", 10, 0..20, 1, "The minimum damage threshold to trigger eating") { eatOnDamage } + override val regenerationFood by c.setting("Regeneration Food", regenerationFoodDefaults, regenerationFoodDefaults, "Items that give Regeneration") { eatOnDamage } + override val ignoreBadFood by c.setting("Ignore Bad Food", true, "Whether to eat when the food is bad") + override val badFood by c.setting("Bad Food", negativeFoodDefaults, negativeFoodDefaults, "Items that are considered bad food") { ignoreBadFood } +} diff --git a/src/main/kotlin/com/lambda/config/settings/blocks/EntityColorSettings.kt b/src/main/kotlin/com/lambda/config/settings/blocks/EntityColorSettings.kt new file mode 100644 index 000000000..f941377fe --- /dev/null +++ b/src/main/kotlin/com/lambda/config/settings/blocks/EntityColorSettings.kt @@ -0,0 +1,88 @@ +/* + * Copyright 2026 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.settings.blocks + +import com.lambda.config.Config +import com.lambda.config.ConfigBlock +import com.lambda.context.SafeContext +import com.lambda.friend.FriendHandler.isFriend +import com.lambda.util.EntityUtils.EntityGroup +import com.lambda.util.EntityUtils.entityGroup +import com.lambda.util.extension.blockColor +import com.lambda.util.extension.entityColor +import com.lambda.util.math.dist +import com.lambda.util.math.lerp +import net.minecraft.block.entity.BlockEntity +import net.minecraft.client.network.OtherClientPlayerEntity +import net.minecraft.entity.Entity +import net.minecraft.entity.player.PlayerEntity +import java.awt.Color + +class EntityColorSettings(override val c: Config) : ConfigBlock, EntityColorsConfig { + override val useNaturalColors by c.setting("Use Natural Colors", false, "Uses an average color from the entities texture") + override val playerColor by c.setting("Player Color", Color(255, 50, 50)) { !useNaturalColors } + override val playerDistanceGradient by c.setting("Player Distance Gradient", true) + override val playerDistanceColorFar by c.setting("Player Far Color", Color.GREEN) { playerDistanceGradient } + override val playerDistanceColorClose by c.setting("Player Close Color", Color.RED) { playerDistanceGradient } + override val separateFriendColor by c.setting("Separate Friend Color", true) { useNaturalColors } + override val friendColor by c.setting("Friend Color", Color(0, 255, 255)) { !useNaturalColors || separateFriendColor } + override val mobColor by c.setting("Mob Color", Color(255, 70, 50)) { !useNaturalColors } + override val passiveColor by c.setting("Passive Color", Color(0, 255, 0)) { !useNaturalColors } + override val vehicleColor by c.setting("Vehicle Color", Color(200, 150, 100)) { !useNaturalColors } + override val projectileColor by c.setting("Projectile Color", Color(200, 200, 200)) { !useNaturalColors } + override val bossColor by c.setting("Boss Color", Color(255, 100, 0)) { !useNaturalColors } + override val decorationColor by c.setting("Decoration Color", Color(100, 100, 255)) { !useNaturalColors } + override val blockColor by c.setting("Block Color", Color(200, 200, 200)) { !useNaturalColors } + override val miscColor by c.setting("Misc Color", Color(255, 0, 255)) { !useNaturalColors } + + context(safeContext: SafeContext) + fun getColor(entity: Entity): Color { + val group = entity.entityGroup + return if (useNaturalColors && !hasSpecialCase(entity, group)) entityColor(entity) + else when (group) { + EntityGroup.Player -> + when { + entity is PlayerEntity && entity.isFriend && separateFriendColor -> friendColor + else -> + if (playerDistanceGradient) + lerp( + entity.dist(safeContext.player) / 60.0, + playerDistanceColorClose, + playerDistanceColorFar + ) + else playerColor + } + EntityGroup.Mob -> mobColor + EntityGroup.Passive -> passiveColor + EntityGroup.Vehicle -> vehicleColor + EntityGroup.Projectile -> projectileColor + EntityGroup.Boss -> bossColor + EntityGroup.Decoration -> decorationColor + else -> miscColor + } + } + + context(safeContext: SafeContext) + fun getColor(blockEntity: BlockEntity): Color = + if (useNaturalColors) safeContext.blockColor(blockEntity.cachedState, blockEntity.pos) + else blockColor + + private fun hasSpecialCase(entity: Entity, group: EntityGroup) = + group == EntityGroup.Player && + ((entity is OtherClientPlayerEntity && entity.isFriend && separateFriendColor) || playerDistanceGradient) +} \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/config/groups/EntityColorsConfig.kt b/src/main/kotlin/com/lambda/config/settings/blocks/EntityColorsConfig.kt similarity index 96% rename from src/main/kotlin/com/lambda/config/groups/EntityColorsConfig.kt rename to src/main/kotlin/com/lambda/config/settings/blocks/EntityColorsConfig.kt index 02f2a9117..ef6ac4aec 100644 --- a/src/main/kotlin/com/lambda/config/groups/EntityColorsConfig.kt +++ b/src/main/kotlin/com/lambda/config/settings/blocks/EntityColorsConfig.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package com.lambda.config.groups +package com.lambda.config.settings.blocks import java.awt.Color diff --git a/src/main/kotlin/com/lambda/config/groups/EntitySelectionConfig.kt b/src/main/kotlin/com/lambda/config/settings/blocks/EntitySelectionConfig.kt similarity index 97% rename from src/main/kotlin/com/lambda/config/groups/EntitySelectionConfig.kt rename to src/main/kotlin/com/lambda/config/settings/blocks/EntitySelectionConfig.kt index 44b3d6182..0916f5108 100644 --- a/src/main/kotlin/com/lambda/config/groups/EntitySelectionConfig.kt +++ b/src/main/kotlin/com/lambda/config/settings/blocks/EntitySelectionConfig.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package com.lambda.config.groups +package com.lambda.config.settings.blocks interface EntitySelectionConfig { val self: Boolean diff --git a/src/main/kotlin/com/lambda/config/settings/blocks/EntitySelectionSettings.kt b/src/main/kotlin/com/lambda/config/settings/blocks/EntitySelectionSettings.kt new file mode 100644 index 000000000..5c4065bd8 --- /dev/null +++ b/src/main/kotlin/com/lambda/config/settings/blocks/EntitySelectionSettings.kt @@ -0,0 +1,84 @@ +/* + * Copyright 2026 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.settings.blocks + +import com.lambda.Lambda.mc +import com.lambda.config.Config +import com.lambda.config.ConfigBlock +import com.lambda.util.EntityUtils.blockEntityMap +import com.lambda.util.EntityUtils.bossEntityMap +import com.lambda.util.EntityUtils.decorationEntityMap +import com.lambda.util.EntityUtils.miscEntityMap +import com.lambda.util.EntityUtils.mobEntityMap +import com.lambda.util.EntityUtils.passiveEntityMap +import com.lambda.util.EntityUtils.playerEntityMap +import com.lambda.util.EntityUtils.projectileEntityMap +import com.lambda.util.EntityUtils.vehicleEntityMap +import net.minecraft.block.entity.BlockEntity +import net.minecraft.entity.Entity +import net.minecraft.entity.SpawnGroup + +class EntitySelectionSettings(override val c: Config) : ConfigBlock, EntitySelectionConfig { + override val self by c.setting("Self", false, "Render own player in third person") + override val enablePlayerEntities by c.setting("Enable Player Entities", true) + override val playerEntities by c.setting("Player Entities", playerEntityMap.values.toSet(), playerEntityMap.values.toSet(), "Player entities to omit from rendering") { enablePlayerEntities } + override val enableMobEntities by c.setting("Enable Mob Entities", true) + override val mobEntities by c.setting("Mob Entities", mobEntityMap.values.toSet(), mobEntityMap.values.toSet(), "Mob entities to omit from rendering") { enableMobEntities } + override val enablePassiveEntities by c.setting("Enable Passive Entities", true) + override val passiveEntities by c.setting("Passive Entities", emptySet(), passiveEntityMap.values.toSet(), "Passive entities to omit from rendering") { enablePassiveEntities } + override val enableVehicleEntities by c.setting("Enable Vehicle Entities", true) + override val vehicleEntities by c.setting("Vehicle Entities", emptySet(), vehicleEntityMap.values.toSet(), "Vehicle entities to omit from rendering") { enableVehicleEntities } + override val enableProjectileEntities by c.setting("Enable Projectile Entities", true) + override val projectileEntities by c.setting("Projectile Entities", emptySet(), projectileEntityMap.values.toSet(), "Projectile entities to omit from rendering") { enableProjectileEntities } + override val enableBossEntities by c.setting("Enable Boss Entities", true) + override val bossEntities by c.setting("Boss Entities", bossEntityMap.values.toSet(), bossEntityMap.values.toSet(), "Boss entities to omit from rendering") { enableBossEntities } + override val enableDecorationEntities by c.setting("Enable Decoration Entities", true) + override val decorationEntities by c.setting("Decoration Entities", emptySet(), decorationEntityMap.values.toSet(), "Decoration entities to omit from rendering") { enableDecorationEntities } + override val enableBlockEntities by c.setting("Enable Block Entities", true) + override val blockEntities by c.setting("Block Entities", emptySet(), blockEntityMap.values.toSet(), "Block entities to omit from rendering") { enableBlockEntities } + override val enableMiscEntities by c.setting("Enable Misc Entities", true) + override val miscEntities by c.setting("Misc Entities", emptySet(), miscEntityMap.values.toSet(), "Miscellaneous entities to omit from rendering") { enableMiscEntities } + + fun isSelected(entity: Entity): Boolean { + val name = entity::class.simpleName + return if (entity == mc.player) self + else when (entity.type.spawnGroup) { + SpawnGroup.MISC -> + (enableMiscEntities && miscEntityMap[name] in miscEntities) || + (enablePlayerEntities && playerEntityMap[name] in playerEntities) || + (enableProjectileEntities && projectileEntityMap[name] in projectileEntities) || + (enableVehicleEntities && vehicleEntityMap[name] in vehicleEntities) || + (enableDecorationEntities && decorationEntityMap[name] in decorationEntities) || + (enablePassiveEntities && passiveEntityMap[name] in passiveEntities) || + (enableMobEntities && mobEntityMap[name] in mobEntities) || + (enableBossEntities && bossEntityMap[name] in bossEntities) + SpawnGroup.WATER_AMBIENT, + SpawnGroup.WATER_CREATURE, + SpawnGroup.AMBIENT, + SpawnGroup.AXOLOTLS, + SpawnGroup.CREATURE, + SpawnGroup.UNDERGROUND_WATER_CREATURE -> (enablePassiveEntities && passiveEntityMap[name] in passiveEntities) + SpawnGroup.MONSTER -> + (enableMobEntities && mobEntityMap[name] in mobEntities) || + (enableBossEntities && bossEntityMap[name] in bossEntities) + } + } + + fun isSelected(blockEntity: BlockEntity) = + (enableBlockEntities && blockEntityMap[blockEntity.javaClass.simpleName] in blockEntities) +} \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/config/groups/FormatterConfig.kt b/src/main/kotlin/com/lambda/config/settings/blocks/FormatterConfig.kt similarity index 98% rename from src/main/kotlin/com/lambda/config/groups/FormatterConfig.kt rename to src/main/kotlin/com/lambda/config/settings/blocks/FormatterConfig.kt index 28b093309..232c2ce1e 100644 --- a/src/main/kotlin/com/lambda/config/groups/FormatterConfig.kt +++ b/src/main/kotlin/com/lambda/config/settings/blocks/FormatterConfig.kt @@ -15,15 +15,15 @@ * along with this program. If not, see . */ -package com.lambda.config.groups +package com.lambda.config.settings.blocks -import com.lambda.config.ISettingGroup import com.lambda.util.Describable import com.lambda.util.NamedEnum import java.time.format.DateTimeFormatter import java.util.* -interface FormatterConfig : ISettingGroup { +@Suppress("unused") +interface FormatterConfig { val locale: Locale val separator: String val prefix: String diff --git a/src/main/kotlin/com/lambda/config/settings/blocks/FormatterSettings.kt b/src/main/kotlin/com/lambda/config/settings/blocks/FormatterSettings.kt new file mode 100644 index 000000000..580a1b3a1 --- /dev/null +++ b/src/main/kotlin/com/lambda/config/settings/blocks/FormatterSettings.kt @@ -0,0 +1,40 @@ +/* + * Copyright 2026 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.settings.blocks + +import com.lambda.config.Config +import com.lambda.config.ConfigBlock + +class FormatterSettings(override val c: Config) : FormatterConfig, ConfigBlock { + val localeEnum by c.setting("Locale", FormatterConfig.Locales.US, "The regional formatting used for numbers") + override val locale get() = localeEnum.locale + + val sep by c.setting("Separator", FormatterConfig.TupleSeparator.Comma, "Separator for string serialization of tuple data structures") + val customSep by c.setting("Custom Separator", "") { sep == FormatterConfig.TupleSeparator.Custom } + override val separator get() = if (sep == FormatterConfig.TupleSeparator.Custom) customSep else sep.separator + + val tupleGroup by c.setting("Tuple Prefix", FormatterConfig.TupleGrouping.Parentheses) + override val prefix get() = tupleGroup.prefix + override val postfix get() = tupleGroup.postfix + + val floatingPrecision by c.setting("Floating Precision", 3, 0..6, 1, "Precision for floating point numbers") + override val precision get() = floatingPrecision + + val timeFormat by c.setting("Time Format", FormatterConfig.Time.IsoDateTime) + override val format get() = timeFormat.format +} \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/interaction/managers/hotbar/HotbarConfig.kt b/src/main/kotlin/com/lambda/config/settings/blocks/HotbarConfig.kt similarity index 92% rename from src/main/kotlin/com/lambda/interaction/managers/hotbar/HotbarConfig.kt rename to src/main/kotlin/com/lambda/config/settings/blocks/HotbarConfig.kt index eac80f7ee..63f075e02 100644 --- a/src/main/kotlin/com/lambda/interaction/managers/hotbar/HotbarConfig.kt +++ b/src/main/kotlin/com/lambda/config/settings/blocks/HotbarConfig.kt @@ -15,9 +15,8 @@ * along with this program. If not, see . */ -package com.lambda.interaction.managers.hotbar +package com.lambda.config.settings.blocks -import com.lambda.config.ISettingGroup import com.lambda.event.events.TickEvent /** @@ -25,7 +24,7 @@ import com.lambda.event.events.TickEvent * * @param priority The priority of this configuration. */ -interface HotbarConfig : ISettingGroup { +interface HotbarConfig { val swapMode: SwapMode /** * The number of ticks to keep the current hotbar selection active. diff --git a/src/main/kotlin/com/lambda/config/settings/blocks/HotbarSettings.kt b/src/main/kotlin/com/lambda/config/settings/blocks/HotbarSettings.kt new file mode 100644 index 000000000..e340a0309 --- /dev/null +++ b/src/main/kotlin/com/lambda/config/settings/blocks/HotbarSettings.kt @@ -0,0 +1,32 @@ +/* + * Copyright 2026 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.settings.blocks + +import com.lambda.config.Config +import com.lambda.config.ConfigBlock +import com.lambda.event.events.TickEvent +import com.lambda.event.events.TickEvent.Companion.ALL_STAGES + +class HotbarSettings(override val c: Config) : HotbarConfig, ConfigBlock { + override val swapMode by c.setting("Swap Mode", HotbarConfig.SwapMode.Temporary) + override val keepTicks by c.setting("Keep Ticks", 1, 0..20, 1, "The number of ticks to keep the current hotbar selection active", " ticks") { swapMode == HotbarConfig.SwapMode.Temporary } + override val swapDelay by c.setting("Swap Delay", 0, 0..3, 1, "The number of ticks delay before allowing another hotbar selection swap", " ticks") + override val swapsPerTick by c.setting("Swaps Per Tick", 3, 1..10, 1, "The number of hotbar selection swaps that can take place each tick") { swapDelay <= 0 } + override val swapPause by c.setting("Swap Pause", 0, 0..20, 1, "The delay in ticks to pause actions after switching to the slot", " ticks") + override val tickStageMask by c.setting("Hotbar Stage Mask", setOf(TickEvent.Input.Post), ALL_STAGES.toSet(), "The sub-tick timing at which hotbar actions are performed", displayClassName = true) +} \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/interaction/managers/interacting/InteractConfig.kt b/src/main/kotlin/com/lambda/config/settings/blocks/InteractConfig.kt similarity index 86% rename from src/main/kotlin/com/lambda/interaction/managers/interacting/InteractConfig.kt rename to src/main/kotlin/com/lambda/config/settings/blocks/InteractConfig.kt index 077acf610..128f9a219 100644 --- a/src/main/kotlin/com/lambda/interaction/managers/interacting/InteractConfig.kt +++ b/src/main/kotlin/com/lambda/config/settings/blocks/InteractConfig.kt @@ -15,15 +15,12 @@ * along with this program. If not, see . */ -package com.lambda.interaction.managers.interacting +package com.lambda.config.settings.blocks -import com.lambda.config.ISettingGroup -import com.lambda.config.groups.ActionConfig -import com.lambda.config.groups.BuildConfig import com.lambda.util.Describable import com.lambda.util.NamedEnum -interface InteractConfig : ActionConfig, ISettingGroup { +interface InteractConfig : ActionConfig { val rotate: Boolean val airPlace: AirPlaceMode val axisRotateSetting: Boolean @@ -35,14 +32,14 @@ interface InteractConfig : ActionConfig, ISettingGroup { val swingType: BuildConfig.SwingType val sounds: Boolean + @Suppress("unused") enum class AirPlaceMode( override val displayName: String, override val description: String ) : NamedEnum, Describable { None("None", "Do not attempt air placements; only place against valid supports."), Standard("Standard", "Try common air-place techniques for convenience; moderate compatibility."), - Grim("Grim", "Use grim specific air placing.") - ; + Grim("Grim", "Use grim specific air placing."); val isEnabled get() = this != None } @@ -55,4 +52,4 @@ interface InteractConfig : ActionConfig, ISettingGroup { PlaceThenAwait("Interact now, confirm later", "Interact immediately, then wait for server confirmation to verify."), AwaitThenPlace("Confirm first, then Interact", "Wait for server response before interacting; safest, adds a short delay.") } -} +} \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/config/settings/blocks/InteractSettings.kt b/src/main/kotlin/com/lambda/config/settings/blocks/InteractSettings.kt new file mode 100644 index 000000000..16fc17a01 --- /dev/null +++ b/src/main/kotlin/com/lambda/config/settings/blocks/InteractSettings.kt @@ -0,0 +1,37 @@ +/* + * Copyright 2026 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.settings.blocks + +import com.lambda.config.Config +import com.lambda.config.ConfigBlock +import com.lambda.event.events.TickEvent +import com.lambda.event.events.TickEvent.Companion.ALL_STAGES + +class InteractSettings(override val c: Config) : InteractConfig, ConfigBlock { + override val rotate by c.setting("Rotate For Interact", true, "Rotate towards block while placing") + override val airPlace by c.setting("Air Place", InteractConfig.AirPlaceMode.Grim, "Allows for placing blocks without adjacent faces") + override val axisRotateSetting by c.setting("Axis Rotate", true, "Overrides the Rotate For Place setting and rotates the player on each axis to air place rotational blocks") { airPlace.isEnabled } + override val sorter by c.setting("Interaction Sorter", ActionConfig.SortMode.Tool, "The order in which placements are performed") + override val tickStageMask by c.setting("Interaction Stage Mask", setOf(TickEvent.Input.Post), ALL_STAGES.toSet(), "The sub-tick timing at which place actions are performed", displayClassName = true) + override val interactConfirmationMode by c.setting("Interact Confirmation", InteractConfig.InteractConfirmationMode.PlaceThenAwait, "Wait for block placement confirmation") + override val interactDelay by c.setting("Interact Delay", 0, 0..3, 1, "Tick delay between interacting with another block") + override val interactionsPerTick by c.setting("Interactions Per Tick", 9, 1..30, 1, "Maximum instant block places per tick") + override val swing by c.setting("Swing On Interact", true, "Swings the players hand when placing") + override val swingType by c.setting("Interact Swing Type", BuildConfig.SwingType.Vanilla, "The style of swing") { swing } + override val sounds by c.setting("Place Sounds", true, "Plays the placing sounds") +} \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/interaction/managers/inventory/InventoryConfig.kt b/src/main/kotlin/com/lambda/config/settings/blocks/InventoryConfig.kt similarity index 95% rename from src/main/kotlin/com/lambda/interaction/managers/inventory/InventoryConfig.kt rename to src/main/kotlin/com/lambda/config/settings/blocks/InventoryConfig.kt index d62b02de1..cfc66af3f 100644 --- a/src/main/kotlin/com/lambda/interaction/managers/inventory/InventoryConfig.kt +++ b/src/main/kotlin/com/lambda/config/settings/blocks/InventoryConfig.kt @@ -15,9 +15,8 @@ * along with this program. If not, see . */ -package com.lambda.interaction.managers.inventory +package com.lambda.config.settings.blocks -import com.lambda.config.ISettingGroup import com.lambda.context.SafeContext import com.lambda.event.events.TickEvent import com.lambda.interaction.material.ContainerSelection @@ -27,7 +26,7 @@ import com.lambda.util.Describable import com.lambda.util.NamedEnum import net.minecraft.item.Item -interface InventoryConfig : ISettingGroup { +interface InventoryConfig { val tickStageMask: Collection val disposables: Collection val swapWithDisposables: Boolean @@ -82,4 +81,4 @@ interface InventoryConfig : ISettingGroup { .thenBy { it.name } } } -} +} \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/config/settings/blocks/InventorySettings.kt b/src/main/kotlin/com/lambda/config/settings/blocks/InventorySettings.kt new file mode 100644 index 000000000..a937670a7 --- /dev/null +++ b/src/main/kotlin/com/lambda/config/settings/blocks/InventorySettings.kt @@ -0,0 +1,42 @@ +/* + * Copyright 2026 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.settings.blocks + +import com.lambda.config.Config +import com.lambda.config.Group +import com.lambda.config.ConfigBlock +import com.lambda.event.events.TickEvent.Companion.ALL_STAGES +import com.lambda.util.item.ItemUtils + +class InventorySettings(override val c: Config) : InventoryConfig, ConfigBlock { + companion object { + private const val ContainerGroup = "Container" + private const val AccessGroup = "Access" + } + + override val tickStageMask by c.setting("Inventory Stage Mask", ALL_STAGES.toSet(), description = "The sub-tick timing at which inventory actions are performed", displayClassName = true) + @Group(ContainerGroup) override val disposables by c.setting("Disposables", ItemUtils.defaultDisposables, description = "Items that will be ignored when checking for a free slot") + @Group(ContainerGroup) override val swapWithDisposables by c.setting("Swap With Disposables", true, "Swap items with disposable ones") + @Group(ContainerGroup) override val providerPriority by c.setting("Provider Priority", InventoryConfig.Priority.WithMinItems, "What container to prefer when retrieving the item from") + @Group(ContainerGroup) override val storePriority by c.setting("Store Priority", InventoryConfig.Priority.WithMinItems, "What container to prefer when storing the item to") + + @Group(AccessGroup) override val accessShulkerBoxes by c.setting("Access Shulker Boxes", false, "Allow access to the player's shulker boxes") + @Group(AccessGroup) override val accessChests by c.setting("Access Chests", false, "Allow access to the player's normal chests") + @Group(AccessGroup) override val accessEnderChest by c.setting("Access Ender Chest", false, "Allow access to the player's ender chest") + @Group(AccessGroup) override val accessStashes by c.setting("Access Stashes", false, "Allow access to the player's stashes") +} \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/config/groups/LineConfig.kt b/src/main/kotlin/com/lambda/config/settings/blocks/LineConfig.kt similarity index 96% rename from src/main/kotlin/com/lambda/config/groups/LineConfig.kt rename to src/main/kotlin/com/lambda/config/settings/blocks/LineConfig.kt index 30f87205a..e7c516156 100644 --- a/src/main/kotlin/com/lambda/config/groups/LineConfig.kt +++ b/src/main/kotlin/com/lambda/config/settings/blocks/LineConfig.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package com.lambda.config.groups +package com.lambda.config.settings.blocks import com.lambda.graphics.mc.LineDashStyle import java.awt.Color diff --git a/src/main/kotlin/com/lambda/config/settings/blocks/OutlineConfig.kt b/src/main/kotlin/com/lambda/config/settings/blocks/OutlineConfig.kt new file mode 100644 index 000000000..881690211 --- /dev/null +++ b/src/main/kotlin/com/lambda/config/settings/blocks/OutlineConfig.kt @@ -0,0 +1,26 @@ +/* + * Copyright 2026 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.settings.blocks + +interface OutlineConfig { + val thickness: Float + val glowIntensity: Float + val glowRadius: Float + val fill: Boolean + val fillOpacity: Float +} \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/config/settings/blocks/OutlineSettings.kt b/src/main/kotlin/com/lambda/config/settings/blocks/OutlineSettings.kt new file mode 100644 index 000000000..c15d6609d --- /dev/null +++ b/src/main/kotlin/com/lambda/config/settings/blocks/OutlineSettings.kt @@ -0,0 +1,49 @@ +/* + * Copyright 2026 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.settings.blocks + +import com.lambda.config.Config +import com.lambda.config.ConfigBlock +import com.lambda.graphics.outline.OutlineStyle +import java.awt.Color + +class OutlineSettings(override val c: Config) : OutlineConfig, ConfigBlock { + val thicknessSetting by c.setting("Line Width", 25, 1..100, 1, "The width of the outline") + override val thickness get() = thicknessSetting * 0.00005f + + val glowIntensitySetting by c.setting("Glow Intensity", 50, 0..100, 1, "Intensity of the outline glow") + override val glowIntensity get() = glowIntensitySetting * 0.01f + + val glowRadiusSetting by c.setting("Glow Radius", 20, 0..100, 1, "Radius of the outline glow") + override val glowRadius get() = glowRadiusSetting * 0.00005f + + override val fill by c.setting("Fill", true, "Fill the entity silhouette") + + val fillOpacitySetting by c.setting("Fill Opacity", 10, 0..100, 1, "Opacity of the fill") { fill } + override val fillOpacity get() = fillOpacitySetting * 0.01f + + fun toStyle(color: Color) = + OutlineStyle( + color = color, + thickness = thickness, + glowIntensity = glowIntensity, + glowRadius = glowRadius, + fill = fill, + fillOpacity = fillOpacity + ) +} diff --git a/src/main/kotlin/com/lambda/interaction/managers/rotating/RotationConfig.kt b/src/main/kotlin/com/lambda/config/settings/blocks/RotationConfig.kt similarity index 82% rename from src/main/kotlin/com/lambda/interaction/managers/rotating/RotationConfig.kt rename to src/main/kotlin/com/lambda/config/settings/blocks/RotationConfig.kt index 17eea26d4..8ef5b4dc0 100644 --- a/src/main/kotlin/com/lambda/interaction/managers/rotating/RotationConfig.kt +++ b/src/main/kotlin/com/lambda/config/settings/blocks/RotationConfig.kt @@ -15,13 +15,13 @@ * along with this program. If not, see . */ -package com.lambda.interaction.managers.rotating +package com.lambda.config.settings.blocks -import com.lambda.config.ISettingGroup -import com.lambda.config.Setting import com.lambda.event.events.TickEvent +import com.lambda.interaction.managers.rotating.RotationManager +import com.lambda.interaction.managers.rotating.RotationMode -interface RotationConfig : ISettingGroup { +interface RotationConfig { /** * - [RotationMode.Silent] Spoofing server-side rotation. * - [RotationMode.Sync] Spoofing server-side rotation and adjusting client-side movement based on reported rotation (for Grim). @@ -46,12 +46,11 @@ interface RotationConfig : ISettingGroup { val tickStageMask: Set - open class Instant(mode: RotationMode, override val visibility: () -> Boolean = { true }) : RotationConfig { - override val settings = mutableListOf>() + open class Instant(mode: RotationMode) : RotationConfig { override val rotationMode = mode override val keepTicks = 1 override val decayTicks = 1 override val turnSpeed = 180.0 override val tickStageMask = RotationManager.openStages.toSet() } -} +} \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/config/groups/RotationSettings.kt b/src/main/kotlin/com/lambda/config/settings/blocks/RotationSettings.kt similarity index 60% rename from src/main/kotlin/com/lambda/config/groups/RotationSettings.kt rename to src/main/kotlin/com/lambda/config/settings/blocks/RotationSettings.kt index ae44bc781..20ff8f6ec 100644 --- a/src/main/kotlin/com/lambda/config/groups/RotationSettings.kt +++ b/src/main/kotlin/com/lambda/config/settings/blocks/RotationSettings.kt @@ -15,15 +15,13 @@ * along with this program. If not, see . */ -package com.lambda.config.groups +package com.lambda.config.settings.blocks -import com.lambda.config.Configurable -import com.lambda.config.SettingGroup +import com.lambda.config.Config +import com.lambda.config.ConfigBlock import com.lambda.event.events.TickEvent import com.lambda.event.events.TickEvent.Companion.ALL_STAGES -import com.lambda.interaction.managers.rotating.RotationConfig import com.lambda.interaction.managers.rotating.RotationMode -import com.lambda.util.NamedEnum import kotlin.math.PI import kotlin.math.abs import kotlin.math.cos @@ -31,36 +29,31 @@ import kotlin.math.ln import kotlin.math.sqrt import kotlin.random.Random -class RotationSettings( - c: Configurable, - vararg baseGroup: NamedEnum, - prefix: String = "", - override val visibility: () -> Boolean = { true }, -) : SettingGroup(c), RotationConfig { - override var rotationMode by c.setting("${prefix}Mode", RotationMode.Sync, "How the player is being rotated on interaction", visibility = visibility).group(*baseGroup).index() +class RotationSettings(override val c: Config) : RotationConfig, ConfigBlock { + override var rotationMode by c.setting("Mode", RotationMode.Sync, "How the player is being rotated on interaction") /** How many ticks to keep the rotation before resetting */ - override val keepTicks by c.setting("${prefix}Keep Rotation", 1, 1..10, 1, "Ticks to keep rotation", " ticks", visibility = visibility).group(*baseGroup).index() + override val keepTicks by c.setting("Keep Rotation", 1, 1..10, 1, "Ticks to keep rotation", " ticks") /** How many ticks to wait before resetting the rotation */ - override val decayTicks by c.setting("${prefix}Reset Rotation", 1, 1..10, 1, "Ticks before rotation is reset", " ticks", visibility = visibility).group(*baseGroup).index() + override val decayTicks by c.setting("Reset Rotation", 1, 1..10, 1, "Ticks before rotation is reset", " ticks") override val tickStageMask = ALL_STAGES.subList(0, ALL_STAGES.indexOf(TickEvent.Player.Post)).toSet() /** Whether the rotation is instant */ - var instant by c.setting("${prefix}Instant Rotation", true, "Instantly rotate", visibility = visibility).group(*baseGroup).index() + var instant by c.setting("Instant Rotation", true, "Instantly rotate") /** * The mean (average/base) value used to calculate rotation speed. * This value represents the center of the distribution. */ - var mean by c.setting("${prefix}Mean", 40.0, 1.0..120.0, 0.1, "Average rotation speed", unit = "°") { visibility() && !instant }.group(*baseGroup).index() + var mean by c.setting("Mean", 40.0, 1.0..120.0, 0.1, "Average rotation speed", unit = "°") { !instant } /** * The standard deviation for the Gaussian distribution used to calculate rotation speed. * This value represents the spread of rotation speed. */ - var spread by c.setting("${prefix}Spread", 10.0, 0.0..60.0, 0.1, "Spread of rotation speeds", unit = "°") { visibility() && !instant }.group(*baseGroup).index() + var spread by c.setting("Spread", 10.0, 0.0..60.0, 0.1, "Spread of rotation speeds", unit = "°") { !instant } /** * We must always provide turn speed to the interpolator because the player's yaw might exceed the -180 to 180 range. diff --git a/src/main/kotlin/com/lambda/config/settings/blocks/ScreenLineSettings.kt b/src/main/kotlin/com/lambda/config/settings/blocks/ScreenLineSettings.kt new file mode 100644 index 000000000..7b6606ec5 --- /dev/null +++ b/src/main/kotlin/com/lambda/config/settings/blocks/ScreenLineSettings.kt @@ -0,0 +1,47 @@ +/* + * Copyright 2026 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.settings.blocks + +import com.lambda.config.Config +import com.lambda.config.Group +import com.lambda.config.ConfigBlock +import java.awt.Color + +class ScreenLineSettings(override val c: Config) : LineConfig, ConfigBlock { + companion object { + private const val ColorGroup = "Color" + private const val DashGroup = "Dash" + } + + val widthSetting by c.setting("Width", 20, 1..100, 1, "The width of the line") + override val width get() = widthSetting * 0.00005f + + @Group(ColorGroup) override val startColor by c.setting("Start Color", Color.WHITE, "The color at the start of the line") + @Group(ColorGroup) override val endColor by c.setting("End Color", Color.WHITE, "The color at the end of the line") + + @Group(DashGroup) override val dashEnabled by c.setting("Dashed", false, "Enable dashed line pattern") + @Group(DashGroup) val dashLengthSetting by c.setting("Dash Length", 30, 1..50, 1, "Length of each dash") { dashEnabled } + override val dashLength get() = dashLengthSetting * 0.001f + @Group(DashGroup) val gapLengthSetting by c.setting("Gap Length", 15, 1..50, 1, "Length of gaps between dashes") { dashEnabled } + override val gapLength get() = gapLengthSetting * 0.001f + @Group(DashGroup) override val animated by c.setting("Animated", true, "Animate the dash pattern") { dashEnabled } + @Group(DashGroup) val dashOffsetSetting by c.setting("Dash Offset", 0, 0..100, 1, "Offset of the dash pattern") { dashEnabled && !animated } + override val dashOffset get() = dashOffsetSetting * 0.01f + @Group(DashGroup) val animationSpeedSetting by c.setting("Animation Speed", 30, -100..100, 1, "Speed of dash animation (negative = reverse)") { dashEnabled && animated } + override val animationSpeed get() = animationSpeedSetting * 0.1f +} diff --git a/src/main/kotlin/com/lambda/config/settings/blocks/ScreenTextSettings.kt b/src/main/kotlin/com/lambda/config/settings/blocks/ScreenTextSettings.kt new file mode 100644 index 000000000..207af7935 --- /dev/null +++ b/src/main/kotlin/com/lambda/config/settings/blocks/ScreenTextSettings.kt @@ -0,0 +1,49 @@ +/* + * Copyright 2026 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.settings.blocks + +import com.lambda.config.Config +import com.lambda.config.Group +import com.lambda.config.ConfigBlock +import java.awt.Color + +class ScreenTextSettings(override val c: Config) : TextConfig, ConfigBlock { + companion object { + private const val OutlineGroup = "Outline" + private const val GlowGroup = "Glow" + private const val ShadowGroup = "Shadow" + } + + override val textColor by c.setting("Text Color", Color.WHITE, "The main text color") + val sizeSetting by c.setting("Text Size", 18, 1..50, 1) + override val size get() = sizeSetting * 0.001f + + @Group(OutlineGroup) override val outlineEnabled by c.setting("Outline", false, "Enable text outline") + @Group(OutlineGroup) override val outlineColor by c.setting("Outline Color", Color.BLACK, "Color of the outline") { outlineEnabled } + @Group(OutlineGroup) override val outlineWidth by c.setting("Outline Width", 0.1f, 0f..0.4f, 0.005f, "Width of the outline") { outlineEnabled } + + @Group(GlowGroup) override val glowEnabled by c.setting("Glow", false, "Enable text glow effect") + @Group(GlowGroup) override val glowColor by c.setting("Glow Color", Color.WHITE, "Color of the glow") { glowEnabled } + @Group(GlowGroup) override val glowRadius by c.setting("Glow Radius", 0.2f, 0f..0.5f, 0.01f, "Radius of the glow effect") { glowEnabled } + + @Group(ShadowGroup) override val shadowEnabled by c.setting("Shadow", true, "Enable text shadow") + @Group(ShadowGroup) override val shadowColor by c.setting("Shadow Color", Color(0, 0, 0, 180), "Color of the shadow") { shadowEnabled } + @Group(ShadowGroup) override val shadowOffset by c.setting("Shadow Offset", 0.05f, 0f..0.5f, 0.005f, "Distance of shadow from text") { shadowEnabled } + @Group(ShadowGroup) override val shadowAngle by c.setting("Shadow Angle", 135f, 0f..360f, 1f, "Angle of the shadow") { shadowEnabled } + @Group(ShadowGroup) override val shadowSoftness by c.setting("Shadow Softness", 0f, 0f..0.5f, 0.01f, "Softness of shadow edges") { shadowEnabled } +} diff --git a/src/main/kotlin/com/lambda/config/groups/TargetingConfig.kt b/src/main/kotlin/com/lambda/config/settings/blocks/TargetingConfig.kt similarity index 94% rename from src/main/kotlin/com/lambda/config/groups/TargetingConfig.kt rename to src/main/kotlin/com/lambda/config/settings/blocks/TargetingConfig.kt index 929f86401..4a5fd0147 100644 --- a/src/main/kotlin/com/lambda/config/groups/TargetingConfig.kt +++ b/src/main/kotlin/com/lambda/config/settings/blocks/TargetingConfig.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package com.lambda.config.groups +package com.lambda.config.settings.blocks interface TargetingConfig { val targetingRange: Double diff --git a/src/main/kotlin/com/lambda/config/groups/Targeting.kt b/src/main/kotlin/com/lambda/config/settings/blocks/TargetingSettings.kt similarity index 76% rename from src/main/kotlin/com/lambda/config/groups/Targeting.kt rename to src/main/kotlin/com/lambda/config/settings/blocks/TargetingSettings.kt index 8c385e117..f5da522a2 100644 --- a/src/main/kotlin/com/lambda/config/groups/Targeting.kt +++ b/src/main/kotlin/com/lambda/config/settings/blocks/TargetingSettings.kt @@ -15,18 +15,18 @@ * along with this program. If not, see . */ -package com.lambda.config.groups +package com.lambda.config.settings.blocks -import com.lambda.config.Configurable -import com.lambda.config.SettingGroup -import com.lambda.config.applyEdits +import com.lambda.config.Config +import com.lambda.config.SettingEditor.hide +import com.lambda.config.ConfigBlock +import com.lambda.config.withEdits import com.lambda.context.SafeContext -import com.lambda.friend.FriendManager.isFriend +import com.lambda.friend.FriendHandler.isFriend import com.lambda.interaction.managers.rotating.Rotation.Companion.dist import com.lambda.interaction.managers.rotating.Rotation.Companion.rotation import com.lambda.interaction.managers.rotating.Rotation.Companion.rotationTo import com.lambda.threading.runSafe -import com.lambda.util.NamedEnum import com.lambda.util.extension.fullHealth import com.lambda.util.math.distSq import com.lambda.util.world.fastEntitySearch @@ -45,29 +45,22 @@ import java.util.* * based on player settings and entity characteristics. It allows for specifying which types of entities * are targetable, the range of targeting, and various other conditions for targeting. * - * @param c The [Configurable] instance used to get and set configuration options for targeting. - * @param visibility The predicate used to determine whether the targeting settings are visible and active. + * @param c The [Config] instance used to get and set configuration options for targeting. * @param defaultRange The default range within which entities can be targeted. * @param maxRange The maximum range within which entities can be targeted. */ -abstract class Targeting( - c: Configurable, - vararg baseGroup: NamedEnum, +abstract class TargetingSettings( + override val c: Config, defaultRange: Double, maxRange: Double, - prefix: String = "", - visibility: () -> Boolean = { true }, -) : SettingGroup(c), TargetingConfig { +) : TargetingConfig, ConfigBlock { /** - * The range within which entities can be targeted. This value is configurable and constrained + * The range within which entities can be targeted. This value is config and constrained * between 1.0 and [maxRange]. */ - override val targetingRange by c.setting("${prefix}Targeting Range", defaultRange, 1.0..maxRange, 0.05, visibility = visibility).group(*baseGroup).index() - override val targets = EntitySelectionSettings(c = c, baseGroup = baseGroup).apply { - c.applyEdits { - hide(::self, ::blockEntities) - } - } + override val targetingRange by c.setting("Targeting Range", defaultRange, 1.0..maxRange, 0.05) + override val targets by c.configBlock(EntitySelectionSettings(c)) + .withEdits(c) { hide(::self, ::enableBlockEntities, ::blockEntities) } /** * Validates whether a given entity is targetable by the player based on current settings. @@ -85,33 +78,30 @@ abstract class Targeting( * @property fov The field of view limit within which entities are considered for targeting. Configurable. * @property priority The priority used to determine which entity is targeted when multiple candidates are available. */ - class Combat( - c: Configurable, - vararg baseGroup: NamedEnum, + class CombatSettings( + c: Config, defaultRange: Double = 5.0, maxRange: Double = 16.0, - prefix: String = "", - override val visibility: () -> Boolean = { true }, - ) : Targeting(c, *baseGroup, defaultRange = defaultRange, maxRange = maxRange, prefix = prefix, visibility = visibility) { + ) : TargetingSettings(c, defaultRange, maxRange) { /** * The field of view limit for targeting entities. Configurable between 5 and 180 degrees. */ - val fov by c.setting("${prefix}FOV Limit", 180, 5..180, 1) { visibility() && priority == Priority.Fov }.group(*baseGroup).index() + val fov by c.setting("FOV Limit", 180, 5..180, 1) { priority == Priority.Fov } /** * The priority used to determine which entity is targeted. Configurable with default set to [Priority.Distance]. */ - val priority by c.setting("${prefix}Priority", Priority.Distance, visibility = visibility).group(*baseGroup).index() + val priority by c.setting("Priority", Priority.Distance) /** * Whether to target named entities that are not players. */ - val targetNamed by c.setting("${prefix}Target Named Entities", false, visibility = visibility).group(*baseGroup).index() + val targetNamed by c.setting("Target Named Entities", false) /** * Whether to target tamed entities. */ - val targetTamed by c.setting("${prefix}Target Tamed Entities", false, visibility = visibility).group(*baseGroup).index() - val owned by c.setting("${prefix}Owned", false) { visibility() && targetTamed }.group(*baseGroup).index() + val targetTamed by c.setting("Target Tamed Entities", false) + val owned by c.setting("Owned", false) { targetTamed } /** * Validates whether a given entity is targetable for combat based on the field of view limit and other settings. diff --git a/src/main/kotlin/com/lambda/config/groups/TextConfig.kt b/src/main/kotlin/com/lambda/config/settings/blocks/TextConfig.kt similarity index 97% rename from src/main/kotlin/com/lambda/config/groups/TextConfig.kt rename to src/main/kotlin/com/lambda/config/settings/blocks/TextConfig.kt index 7d33c2c39..b1dc6c242 100644 --- a/src/main/kotlin/com/lambda/config/groups/TextConfig.kt +++ b/src/main/kotlin/com/lambda/config/settings/blocks/TextConfig.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package com.lambda.config.groups +package com.lambda.config.settings.blocks import com.lambda.graphics.mc.RenderBuilder import java.awt.Color diff --git a/src/main/kotlin/com/lambda/config/settings/blocks/WorldLineSettings.kt b/src/main/kotlin/com/lambda/config/settings/blocks/WorldLineSettings.kt new file mode 100644 index 000000000..02b6ae075 --- /dev/null +++ b/src/main/kotlin/com/lambda/config/settings/blocks/WorldLineSettings.kt @@ -0,0 +1,52 @@ +/* + * Copyright 2026 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.settings.blocks + +import com.lambda.config.Config +import com.lambda.config.Group +import com.lambda.config.ConfigBlock +import java.awt.Color + +class WorldLineSettings(override val c: Config) : LineConfig, ConfigBlock { + companion object { + private const val ColorGroup = "Color" + private const val DashGroup = "Dash" + } + + val distanceScaling by c.setting("Distance Scaling", true, "Line width stays constant on screen regardless of distance") + val worldWidthSetting by c.setting("Width", 5, 1..50, 1) { !distanceScaling } + val screenWidthSetting by c.setting("Screen Width", 20, 1..100, 1, "Line width in screen-space (stays constant size)") { distanceScaling } + + override val width: Float get() = + if (distanceScaling) -screenWidthSetting * 0.00005f + else worldWidthSetting * 0.001f + + @Group(ColorGroup) override val startColor by c.setting("Start Color", Color.WHITE, "The color at the start of the line") + @Group(ColorGroup) override val endColor by c.setting("End Color", Color.WHITE, "The color at the end of the line") + + @Group(DashGroup) override val dashEnabled by c.setting("Dashed", false, "Enable dashed line pattern") + @Group(DashGroup) val dashLengthSetting by c.setting("Dash Length", 50, 1..200, 1, "Length of each dash") { dashEnabled } + override val dashLength get() = dashLengthSetting * 0.01f + @Group(DashGroup) val gapLengthSetting by c.setting("Gap Length", 25, 1..200, 1, "Length of gaps between dashes") { dashEnabled } + override val gapLength get() = gapLengthSetting * 0.01f + @Group(DashGroup) override val animated by c.setting("Animated", true, "Animate the dash pattern") { dashEnabled } + @Group(DashGroup) val dashOffsetSetting by c.setting("Dash Offset", 0, 0..100, 1, "Offset of the dash pattern") { dashEnabled && !animated } + override val dashOffset get() = dashOffsetSetting * 0.01f + @Group(DashGroup) val animationSpeedSetting by c.setting("Animation Speed", 30, -100..100, 1, "Speed of dash animation (negative = reverse)") { dashEnabled && animated } + override val animationSpeed get() = animationSpeedSetting * 0.1f +} diff --git a/src/main/kotlin/com/lambda/config/settings/blocks/WorldTextSettings.kt b/src/main/kotlin/com/lambda/config/settings/blocks/WorldTextSettings.kt new file mode 100644 index 000000000..d0324387f --- /dev/null +++ b/src/main/kotlin/com/lambda/config/settings/blocks/WorldTextSettings.kt @@ -0,0 +1,49 @@ +/* + * Copyright 2026 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.settings.blocks + +import com.lambda.config.Config +import com.lambda.config.Group +import com.lambda.config.ConfigBlock +import java.awt.Color + +class WorldTextSettings(override val c: Config) : TextConfig, ConfigBlock { + companion object { + private const val OutlineGroup = "Outline" + private const val GlowGroup = "Glow" + private const val ShadowGroup = "Shadow" + } + + override val textColor by c.setting("Text Color", Color.WHITE, "The main text color") + val sizeSetting by c.setting("Text Size", 5, 1..50, 1) + override val size get() = sizeSetting * 0.1f + + @Group(OutlineGroup) override val outlineEnabled by c.setting("Outline", false, "Enable text outline") + @Group(OutlineGroup) override val outlineColor by c.setting("Outline Color", Color.BLACK, "Color of the outline") { outlineEnabled } + @Group(OutlineGroup) override val outlineWidth by c.setting("Outline Width", 0.1f, 0f..0.4f, 0.005f, "Width of the outline") { outlineEnabled } + + @Group(GlowGroup) override val glowEnabled by c.setting("Glow", false, "Enable text glow effect") + @Group(GlowGroup) override val glowColor by c.setting("Glow Color", Color.WHITE, "Color of the glow") { glowEnabled } + @Group(GlowGroup) override val glowRadius by c.setting("Glow Radius", 0.2f, 0f..0.5f, 0.01f, "Radius of the glow effect") { glowEnabled } + + @Group(ShadowGroup) override val shadowEnabled by c.setting("Shadow", true, "Enable text shadow") + @Group(ShadowGroup) override val shadowColor by c.setting("Shadow Color", Color(0, 0, 0, 180), "Color of the shadow") { shadowEnabled } + @Group(ShadowGroup) override val shadowOffset by c.setting("Shadow Offset", 0.05f, 0f..0.5f, 0.005f, "Distance of shadow from text") { shadowEnabled } + @Group(ShadowGroup) override val shadowAngle by c.setting("Shadow Angle", 135f, 0f..360f, 1f, "Angle of the shadow") { shadowEnabled } + @Group(ShadowGroup) override val shadowSoftness by c.setting("Shadow Softness", 0f, 0f..0.5f, 0.01f, "Softness of shadow edges") { shadowEnabled } +} diff --git a/src/main/kotlin/com/lambda/config/settings/collections/BlockCollectionSetting.kt b/src/main/kotlin/com/lambda/config/settings/collections/BlockCollectionSetting.kt index 62452f9f3..5e37799f1 100644 --- a/src/main/kotlin/com/lambda/config/settings/collections/BlockCollectionSetting.kt +++ b/src/main/kotlin/com/lambda/config/settings/collections/BlockCollectionSetting.kt @@ -17,21 +17,31 @@ package com.lambda.config.settings.collections -import com.google.gson.reflect.TypeToken -import com.lambda.config.Setting -import com.lambda.config.serializer.BlockCodec +import com.lambda.Lambda.typeFactory +import com.lambda.config.Config +import com.lambda.config.SettingLayer +import com.lambda.config.serializers.BlockSerializer import com.lambda.gui.dsl.ImGuiBuilder import net.minecraft.block.Block class BlockCollectionSetting( + name: String, + description: String, + config: Config, + layer: SettingLayer.Single<*, MutableCollection>, + visibility: () -> Boolean, immutableCollection: Collection, defaultValue: MutableCollection, ) : CollectionSetting( + name, + description, + config, + layer, + visibility, defaultValue, immutableCollection, - TypeToken.getParameterized(Collection::class.java, Block::class.java).type, + typeFactory.constructCollectionType(MutableCollection::class.java, Block::class.java), serialize = true, ) { - context(setting: Setting<*, MutableCollection>) - override fun ImGuiBuilder.buildLayout() = buildDualPane("block") { BlockCodec.stringify(it) } + override fun ImGuiBuilder.buildLayout() = buildDualPane("block") { BlockSerializer.stringify(it) } } \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/config/settings/collections/ClassCollectionSetting.kt b/src/main/kotlin/com/lambda/config/settings/collections/ClassCollectionSetting.kt index f40ef8ff3..25d55c368 100644 --- a/src/main/kotlin/com/lambda/config/settings/collections/ClassCollectionSetting.kt +++ b/src/main/kotlin/com/lambda/config/settings/collections/ClassCollectionSetting.kt @@ -17,41 +17,34 @@ package com.lambda.config.settings.collections -import com.google.gson.JsonElement -import com.google.gson.reflect.TypeToken -import com.lambda.Lambda.gson -import com.lambda.config.Setting +import com.lambda.Lambda.typeFactory +import com.lambda.config.Config +import com.lambda.config.SettingLayer import com.lambda.gui.dsl.ImGuiBuilder -import com.lambda.util.reflections.className +import com.lambda.util.ReflectionUtils.className /** - * @see [com.lambda.config.settings.collections.CollectionSetting] - * @see [com.lambda.config.Configurable] + * @see [CollectionSetting] + * @see [com.lambda.config.Config] */ class ClassCollectionSetting( - private val immutableCollection: Collection, + name: String, + description: String, + config: Config, + layer: SettingLayer.Single<*, MutableCollection>, + visibility: () -> Boolean, + immutableCollection: Collection, defaultValue: MutableCollection ) : CollectionSetting( + name, + description, + config, + layer, + visibility, defaultValue, immutableCollection, - TypeToken.getParameterized(Collection::class.java, Any::class.java).type, + typeFactory.constructCollectionType(Collection::class.java, Any::class.java), serialize = false, ) { - context(setting: Setting<*, MutableCollection>) override fun ImGuiBuilder.buildLayout() = buildDualPane("item") { it.className } - - // When serializing the list to json we do not want to serialize the elements' classes, but their stringified representation. - // If we do serialize the classes we'll run into missing type adapters errors by Gson. - // This is intended behaviour. If you wish your collection settings to display something else then you must extend this class. - context(setting: Setting<*, MutableCollection>) - override fun toJson(): JsonElement = gson.toJsonTree(value.map { it.className }) - - context(setting: Setting<*, MutableCollection>) - override fun loadFromJson(serialized: JsonElement) { - val strList = gson.fromJson>(serialized, type) - .mapNotNull { str -> immutableCollection.find { it.className == str } } - .toMutableList() - - value = strList - } } \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/config/settings/collections/CollectionSetting.kt b/src/main/kotlin/com/lambda/config/settings/collections/CollectionSetting.kt index b8d1a310a..544e6aa5d 100644 --- a/src/main/kotlin/com/lambda/config/settings/collections/CollectionSetting.kt +++ b/src/main/kotlin/com/lambda/config/settings/collections/CollectionSetting.kt @@ -17,24 +17,24 @@ package com.lambda.config.settings.collections -import com.google.gson.JsonElement -import com.google.gson.reflect.TypeToken -import com.lambda.Lambda.gson +import com.lambda.config.Config +import com.lambda.config.SettingEditor import com.lambda.config.Setting import com.lambda.config.SettingCore +import com.lambda.config.ConfigEntryD5l import com.lambda.config.SettingEditorDsl -import com.lambda.config.SettingGroupEditor +import com.lambda.config.SettingLayer import com.lambda.context.SafeContext import com.lambda.gui.dsl.ImGuiBuilder import com.lambda.imgui.ImGui import com.lambda.imgui.ImGui.getContentRegionAvail -import com.lambda.threading.runSafe import com.lambda.imgui.ImGuiListClipper import com.lambda.imgui.callback.ImListClipperCallback import com.lambda.imgui.flag.ImGuiChildFlags import com.lambda.imgui.flag.ImGuiPopupFlags import com.lambda.imgui.flag.ImGuiSelectableFlags.DontClosePopups -import java.lang.reflect.Type +import com.lambda.threading.runSafe +import tools.jackson.databind.JavaType /** * This generic collection settings handles all [Comparable] values (i.e., not classes) and serialize @@ -44,45 +44,48 @@ import java.lang.reflect.Type * If you wish to use a different codec or simply display values differently, you must create your own * collection setting. * - * @see [com.lambda.config.Configurable] + * @see [com.lambda.config.Config] */ open class CollectionSetting( + name: String, + description: String, + config: Config, + layer: SettingLayer.Single<*, MutableCollection>, + visibility: () -> Boolean, defaultValue: MutableCollection, - private var immutableCollection: Collection, - type: Type, - private val serialize: Boolean, -) : SettingCore>( - defaultValue, - type -) { - override var value + var immutableCollection: Collection, + val type: JavaType, + val serialize: Boolean, +) : Setting>(name, description, SettingCore(defaultValue, defaultValue.toMutableList()), config, layer, visibility) { + override var value: MutableCollection get() = super.value set(newVal) { super.value = newVal.toMutableList() } - private var searchFilter = "" - private val strListType = - TypeToken.getParameterized(Collection::class.java, String::class.java).type + private var searchFilter = "" + + val selectListeners = mutableListOf Unit>() + val deselectListeners = mutableListOf Unit>() - val selectListeners = mutableListOf Unit>() - val deselectListeners = mutableListOf Unit>() + override val isModified: Boolean + get() = with(originalCore) { + value.size != defaultValue.size || defaultValue.any { !value.contains(it) } + } - context(setting: Setting<*, MutableCollection>) - override fun ImGuiBuilder.buildLayout() = buildDualPane("item") { it.toString() } + override fun ImGuiBuilder.buildLayout() = buildDualPane("item") { it.toString() } - context(setting: Setting<*, MutableCollection>) fun ImGuiBuilder.buildDualPane(itemName: String, toString: (R) -> String) { val text = if (value.size == 1) itemName else "${itemName}s" - val popupId = "##${setting.name}-collection-popup" + val popupId = "##$name-collection-popup" - button("${setting.name}: ${value.size} $text") { + button("$name: ${value.size} $text") { ImGui.openPopup(popupId) } ImGui.setNextWindowSizeConstraints(500f, 0f, Float.MAX_VALUE, io.displaySize.y * 0.5f) popupContextItem(popupId, ImGuiPopupFlags.None) { - inputText("##${setting.name}-SearchBox", ::searchFilter) + inputText("##$name-SearchBox", ::searchFilter) val q = searchFilter.trim() val filteredDeselected = immutableCollection @@ -98,7 +101,7 @@ open class CollectionSetting( group { textDisabled("Deselected (${filteredDeselected.size})") child( - strId = "##${setting.name}-Deselected", + strId = "##$name-Deselected", width = paneWidth, height = paneHeight, childFlags = ImGuiChildFlags.Border or ImGuiChildFlags.ResizeX or ImGuiChildFlags.ResizeY, @@ -144,7 +147,7 @@ open class CollectionSetting( group { textDisabled("Selected (${filteredSelected.size})") child( - strId = "##${setting.name}-Selected", + strId = "##$name-Selected", width = paneWidth, height = paneHeight, childFlags = ImGuiChildFlags.Border or ImGuiChildFlags.ResizeX or ImGuiChildFlags.ResizeY, @@ -167,34 +170,20 @@ open class CollectionSetting( } } - context(setting: Setting<*, MutableCollection>) - override fun toJson(): JsonElement = - gson.toJsonTree(value, type) - - context(setting: Setting<*, MutableCollection>) - override fun loadFromJson(serialized: JsonElement) { - val strList = - if (serialize) gson.fromJson(serialized, type) - else gson.fromJson>(serialized, strListType) - .mapNotNull { str -> immutableCollection.find { it.toString() == str } } - .toMutableList() - - value = strList - } - + @Suppress("unused") companion object { - fun , R : Any> Setting>.onSelect(block: SafeContext.(R) -> Unit) = apply { - core.selectListeners.add(block) - } - - fun , R : Any> Setting>.onDeselect(block: SafeContext.(R) -> Unit) = apply { - core.deselectListeners.add(block) + @ConfigEntryD5l + fun , R : Any> T.onSelect(block: SafeContext.(R) -> Unit) = + apply { selectListeners.add(block) } + + @ConfigEntryD5l + fun , R : Any> T.onDeselect(block: SafeContext.(R) -> Unit) = + apply { deselectListeners.add(block) } + + @Suppress("unchecked_cast") + @SettingEditorDsl + fun SettingEditor.TypedEditBuilder>.immutableCollection(collection: Collection) { + (settings as Collection>).forEach { it.immutableCollection = collection } } - - @SettingEditorDsl - @Suppress("unchecked_cast") - fun SettingGroupEditor.TypedEditBuilder>.immutableCollection(collection: Collection) { - (settings as Collection>).forEach { it.immutableCollection = collection } - } - } -} + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/config/settings/collections/ItemCollectionSetting.kt b/src/main/kotlin/com/lambda/config/settings/collections/ItemCollectionSetting.kt index 8a045ed29..f90581def 100644 --- a/src/main/kotlin/com/lambda/config/settings/collections/ItemCollectionSetting.kt +++ b/src/main/kotlin/com/lambda/config/settings/collections/ItemCollectionSetting.kt @@ -17,21 +17,27 @@ package com.lambda.config.settings.collections -import com.google.gson.reflect.TypeToken -import com.lambda.config.Setting -import com.lambda.config.serializer.ItemCodec +import com.lambda.Lambda.typeFactory +import com.lambda.config.Config +import com.lambda.config.SettingLayer +import com.lambda.config.serializers.ItemSerializer import com.lambda.gui.dsl.ImGuiBuilder import net.minecraft.item.Item class ItemCollectionSetting( + name: String, + description: String, + config: Config, + layer: SettingLayer.Single<*, MutableCollection>, + visibility: () -> Boolean, immutableCollection: Collection, defaultValue: MutableCollection ) : CollectionSetting( + name, description, config, layer, visibility, defaultValue, immutableCollection, - TypeToken.getParameterized(Collection::class.java, Item::class.java).type, + typeFactory.constructCollectionType(Collection::class.java, Item::class.java), serialize = true, ) { - context(setting: Setting<*, MutableCollection>) - override fun ImGuiBuilder.buildLayout() = buildDualPane("item") { ItemCodec.stringify(it) } + override fun ImGuiBuilder.buildLayout() = buildDualPane("item") { ItemSerializer.stringify(it) } } \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/config/settings/collections/MapSetting.kt b/src/main/kotlin/com/lambda/config/settings/collections/MapSetting.kt index db0e45b51..fdb3ce0b6 100644 --- a/src/main/kotlin/com/lambda/config/settings/collections/MapSetting.kt +++ b/src/main/kotlin/com/lambda/config/settings/collections/MapSetting.kt @@ -17,21 +17,21 @@ package com.lambda.config.settings.collections +import com.lambda.config.Config import com.lambda.config.Setting import com.lambda.config.SettingCore +import com.lambda.config.SettingLayer import com.lambda.gui.dsl.ImGuiBuilder -import java.lang.reflect.Type +import tools.jackson.databind.JavaType -/** - * @see [com.lambda.config.Configurable] - */ class MapSetting( + name: String, + description: String, + config: Config, + layer: SettingLayer.Single<*, MutableMap>, + visibility: () -> Boolean, defaultValue: MutableMap, - type: Type -) : SettingCore>( - defaultValue, - type -) { - context(setting: Setting<*, MutableMap>) + val type: JavaType +) : Setting>(name, description, SettingCore(defaultValue), config, layer, visibility) { override fun ImGuiBuilder.buildLayout() {} -} +} \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/config/settings/comparable/BooleanSetting.kt b/src/main/kotlin/com/lambda/config/settings/comparable/BooleanSetting.kt index f316e0b2f..56efe8996 100644 --- a/src/main/kotlin/com/lambda/config/settings/comparable/BooleanSetting.kt +++ b/src/main/kotlin/com/lambda/config/settings/comparable/BooleanSetting.kt @@ -17,36 +17,36 @@ package com.lambda.config.settings.comparable -import com.google.gson.reflect.TypeToken import com.lambda.brigadier.argument.boolean import com.lambda.brigadier.argument.value import com.lambda.brigadier.execute import com.lambda.brigadier.required +import com.lambda.config.Config import com.lambda.config.Setting import com.lambda.config.SettingCore +import com.lambda.config.SettingLayer import com.lambda.gui.dsl.ImGuiBuilder import com.lambda.util.extension.CommandBuilder import net.minecraft.command.CommandRegistryAccess -/** - * @see [com.lambda.config.Configurable] - */ -class BooleanSetting(defaultValue: Boolean) : SettingCore( - defaultValue, - TypeToken.get(Boolean::class.java).type -) { - context(setting: Setting<*, Boolean>) +class BooleanSetting( + name: String, + description: String, + config: Config, + layer: SettingLayer.Single<*, Boolean>, + visibility: () -> Boolean, + defaultValue: Boolean +) : Setting(name, description, SettingCore(defaultValue), config, layer, visibility) { override fun ImGuiBuilder.buildLayout() { - checkbox(setting.name, ::value) - lambdaTooltip(setting.description) - } + checkbox(name, ::value) + lambdaTooltip(description) + } - context(setting: Setting<*, Boolean>) - override fun CommandBuilder.buildCommand(registry: CommandRegistryAccess) { - required(boolean(setting.name)) { parameter -> - execute { - setting.trySetValue(parameter().value()) - } - } - } -} + override fun CommandBuilder.buildCommand(registry: CommandRegistryAccess) { + required(boolean(name)) { parameter -> + execute { + trySetValue(parameter().value()) + } + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/config/settings/comparable/EnumSetting.kt b/src/main/kotlin/com/lambda/config/settings/comparable/EnumSetting.kt index 67ecd6225..3bc9506c9 100644 --- a/src/main/kotlin/com/lambda/config/settings/comparable/EnumSetting.kt +++ b/src/main/kotlin/com/lambda/config/settings/comparable/EnumSetting.kt @@ -17,64 +17,53 @@ package com.lambda.config.settings.comparable -import com.google.gson.JsonElement -import com.google.gson.reflect.TypeToken import com.lambda.brigadier.CommandResult.Companion.failure import com.lambda.brigadier.CommandResult.Companion.success import com.lambda.brigadier.argument.value import com.lambda.brigadier.argument.word import com.lambda.brigadier.executeWithResult import com.lambda.brigadier.required +import com.lambda.config.Config import com.lambda.config.Setting import com.lambda.config.SettingCore +import com.lambda.config.SettingLayer import com.lambda.gui.dsl.ImGuiBuilder import com.lambda.util.Describable import com.lambda.util.StringUtils.capitalize import com.lambda.util.extension.CommandBuilder import com.lambda.util.extension.displayValue import net.minecraft.command.CommandRegistryAccess -import kotlin.properties.Delegates -/** - * @see [com.lambda.config.Configurable] - */ -class EnumSetting>(defaultValue: T) : SettingCore( - defaultValue, - TypeToken.get(defaultValue.declaringJavaClass).type -) { - var index by Delegates.observable(value.ordinal) { _, _, to -> - value = value.enumValues[to % value.enumValues.size] - } - - context(setting: Setting<*, T>) - override fun loadFromJson(serialized: JsonElement) { - super.loadFromJson(serialized) - index = value.ordinal // super bug fix for imgui - } - - context(setting: Setting<*, T>) +class EnumSetting>( + name: String, + description: String, + config: Config, + layer: SettingLayer.Single<*, T>, + visibility: () -> Boolean, + defaultValue: T +) : Setting(name, description, SettingCore(defaultValue), config, layer, visibility) { override fun ImGuiBuilder.buildLayout() { val values = value.enumValues val currentDisplay = value.displayValue + val currentIndex = value.ordinal - combo("##${setting.name}", preview = "${setting.name}: $currentDisplay") { + combo("##$name", preview = "$name: $currentDisplay") { values.forEachIndexed { idx, v -> - val isSelected = idx == index + val isSelected = idx == currentIndex selectable(v.displayValue, isSelected) { - if (!isSelected) index = idx + if (!isSelected) value = values[idx % values.size] } (v as? Describable)?.let { lambdaTooltip(it.description) } } } - lambdaTooltip(setting.description) + lambdaTooltip(description) } - context(setting: Setting<*, T>) override fun CommandBuilder.buildCommand(registry: CommandRegistryAccess) { - required(word(setting.name)) { parameter -> + required(word(name)) { parameter -> suggests { _, builder -> value.enumValues.forEach { builder.suggest(it.name.capitalize()) } builder.buildFuture() @@ -82,7 +71,7 @@ class EnumSetting>(defaultValue: T) : SettingCore( executeWithResult { val newValue = value.enumValues.find { it.name.equals(parameter().value(), true) } ?: return@executeWithResult failure("Invalid value") - setting.trySetValue(newValue) + trySetValue(newValue) return@executeWithResult success() } } @@ -92,4 +81,4 @@ class EnumSetting>(defaultValue: T) : SettingCore( val > T.enumValues: Array get() = declaringJavaClass.enumConstants } -} +} \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/config/settings/complex/BlockPosSetting.kt b/src/main/kotlin/com/lambda/config/settings/complex/BlockPosSetting.kt index b9fb525f4..98cd82134 100644 --- a/src/main/kotlin/com/lambda/config/settings/complex/BlockPosSetting.kt +++ b/src/main/kotlin/com/lambda/config/settings/complex/BlockPosSetting.kt @@ -17,54 +17,54 @@ package com.lambda.config.settings.complex -import com.google.gson.reflect.TypeToken import com.lambda.Lambda.mc import com.lambda.brigadier.argument.integer import com.lambda.brigadier.argument.value import com.lambda.brigadier.execute import com.lambda.brigadier.required +import com.lambda.config.Config import com.lambda.config.Setting import com.lambda.config.SettingCore +import com.lambda.config.SettingLayer import com.lambda.gui.dsl.ImGuiBuilder import com.lambda.util.BlockUtils.blockPos -import com.lambda.util.Communication.info +import com.lambda.util.CommunicationUtils.info import com.lambda.util.extension.CommandBuilder import com.lambda.util.world.raycast.RayCastUtils.blockResult import net.minecraft.command.CommandRegistryAccess import net.minecraft.util.math.BlockPos -/** - * @see [com.lambda.config.Configurable] - */ -class BlockPosSetting(defaultValue: BlockPos) : SettingCore( - defaultValue, - TypeToken.get(BlockPos::class.java).type -) { - context(setting: Setting<*, BlockPos>) +class BlockPosSetting( + name: String, + description: String, + config: Config, + layer: SettingLayer.Single<*, BlockPos>, + visibility: () -> Boolean, + defaultValue: BlockPos +) : Setting(name, description, SettingCore(defaultValue), config, layer, visibility) { override fun ImGuiBuilder.buildLayout() { - button("Set##${setting.name}") { + button("Set##$name") { mc.crosshairTarget?.blockResult?.blockPos?.let { value = it } ?: info("No block under crosshair") } lambdaTooltip("Set the coordinates to the block you are currently looking at") sameLine() - treeNode(setting.name, id = setting.name) { - inputVec3i("##${setting.name}", value) { value = it.blockPos } + treeNode(name, id = name) { + inputVec3i("##$name", value) { value = it.blockPos } } - lambdaTooltip(setting.description) + lambdaTooltip(description) } - context(setting: Setting<*, BlockPos>) - override fun CommandBuilder.buildCommand(registry: CommandRegistryAccess) { - required(integer("X", -30000000, 30000000)) { x -> - required(integer("Y", -64, 319)) { y -> - required(integer("Z", -30000000, 30000000)) { z -> - execute { - setting.trySetValue(BlockPos(x().value(), y().value(), z().value())) - } - } - } - } - } -} + override fun CommandBuilder.buildCommand(registry: CommandRegistryAccess) { + required(integer("X", -30000000, 30000000)) { x -> + required(integer("Y", -64, 319)) { y -> + required(integer("Z", -30000000, 30000000)) { z -> + execute { + trySetValue(BlockPos(x().value(), y().value(), z().value())) + } + } + } + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/config/settings/complex/BlockSetting.kt b/src/main/kotlin/com/lambda/config/settings/complex/BlockSetting.kt index 7dbe8bf33..161338255 100644 --- a/src/main/kotlin/com/lambda/config/settings/complex/BlockSetting.kt +++ b/src/main/kotlin/com/lambda/config/settings/complex/BlockSetting.kt @@ -17,34 +17,34 @@ package com.lambda.config.settings.complex -import com.google.gson.reflect.TypeToken import com.lambda.brigadier.argument.blockState import com.lambda.brigadier.argument.value import com.lambda.brigadier.execute import com.lambda.brigadier.required +import com.lambda.config.Config import com.lambda.config.Setting import com.lambda.config.SettingCore +import com.lambda.config.SettingLayer import com.lambda.gui.dsl.ImGuiBuilder import com.lambda.util.extension.CommandBuilder import net.minecraft.block.Block import net.minecraft.command.CommandRegistryAccess -/** - * @see [com.lambda.config.Configurable] - */ -class BlockSetting(defaultValue: Block) : SettingCore( - defaultValue, - TypeToken.get(Block::class.java).type -) { - context(setting: Setting<*, Block>) - override fun ImGuiBuilder.buildLayout() {} +class BlockSetting( + name: String, + description: String, + config: Config, + layer: SettingLayer.Single<*, Block>, + visibility: () -> Boolean, + defaultValue: Block +) : Setting(name, description, SettingCore(defaultValue), config, layer, visibility) { + override fun ImGuiBuilder.buildLayout() {} - context(setting: Setting<*, Block>) - override fun CommandBuilder.buildCommand(registry: CommandRegistryAccess) { - required(blockState(setting.name, registry)) { argument -> - execute { - setting.trySetValue(argument().value().blockState.block) - } - } - } -} + override fun CommandBuilder.buildCommand(registry: CommandRegistryAccess) { + required(blockState(name, registry)) { argument -> + execute { + trySetValue(argument().value().blockState.block) + } + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/config/settings/complex/ColorSetting.kt b/src/main/kotlin/com/lambda/config/settings/complex/ColorSetting.kt index 88913b3f1..4af718f98 100644 --- a/src/main/kotlin/com/lambda/config/settings/complex/ColorSetting.kt +++ b/src/main/kotlin/com/lambda/config/settings/complex/ColorSetting.kt @@ -17,33 +17,33 @@ package com.lambda.config.settings.complex -import com.google.gson.reflect.TypeToken import com.lambda.brigadier.argument.integer import com.lambda.brigadier.argument.value import com.lambda.brigadier.execute import com.lambda.brigadier.optional import com.lambda.brigadier.required +import com.lambda.config.Config import com.lambda.config.Setting import com.lambda.config.SettingCore +import com.lambda.config.SettingLayer import com.lambda.gui.dsl.ImGuiBuilder import com.lambda.util.extension.CommandBuilder import net.minecraft.command.CommandRegistryAccess import java.awt.Color -/** - * @see [com.lambda.config.Configurable] - */ -class ColorSetting(defaultValue: Color) : SettingCore( - defaultValue, - TypeToken.get(Color::class.java).type -) { - context(setting: Setting<*, Color>) - override fun ImGuiBuilder.buildLayout() { - colorEdit(setting.name, ::value) - lambdaTooltip(setting.description) +class ColorSetting( + name: String, + description: String, + config: Config, + layer: SettingLayer.Single<*, Color>, + visibility: () -> Boolean, + defaultValue: Color +) : Setting(name, description, SettingCore(defaultValue), config, layer, visibility) { + override fun ImGuiBuilder.buildLayout() { + colorEdit(name, ::value) + lambdaTooltip(description) } - context(setting: Setting<*, Color>) override fun CommandBuilder.buildCommand(registry: CommandRegistryAccess) { required(integer("Red", 0, 255)) { red -> required(integer("Green", 0, 255)) { green -> @@ -51,11 +51,11 @@ class ColorSetting(defaultValue: Color) : SettingCore( optional(integer("Alpha", 0, 255)) { alpha -> execute { val alphaValue = alpha?.let { it().value() } ?: 255 - setting.trySetValue(Color(red().value(), green().value(), blue().value(), alphaValue)) + trySetValue(Color(red().value(), green().value(), blue().value(), alphaValue)) } } } } } } -} +} \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/config/settings/complex/KeybindSetting.kt b/src/main/kotlin/com/lambda/config/settings/complex/KeybindSetting.kt index 8acc12ca4..7160114f1 100644 --- a/src/main/kotlin/com/lambda/config/settings/complex/KeybindSetting.kt +++ b/src/main/kotlin/com/lambda/config/settings/complex/KeybindSetting.kt @@ -17,7 +17,7 @@ package com.lambda.config.settings.complex -import com.google.gson.reflect.TypeToken +import com.fasterxml.jackson.annotation.JsonIncludeProperties import com.lambda.brigadier.CommandResult.Companion.failure import com.lambda.brigadier.CommandResult.Companion.success import com.lambda.brigadier.argument.boolean @@ -26,22 +26,25 @@ import com.lambda.brigadier.argument.word import com.lambda.brigadier.executeWithResult import com.lambda.brigadier.optional import com.lambda.brigadier.required +import com.lambda.config.Config import com.lambda.config.Setting import com.lambda.config.SettingCore +import com.lambda.config.ConfigEntryD5l +import com.lambda.config.SettingLayer import com.lambda.context.SafeContext import com.lambda.event.Muteable import com.lambda.event.events.ButtonEvent import com.lambda.event.listener.SafeListener.Companion.listen import com.lambda.gui.dsl.ImGuiBuilder +import com.lambda.imgui.ImGui.isMouseClicked +import com.lambda.imgui.flag.ImGuiCol +import com.lambda.imgui.flag.ImGuiHoveredFlags +import com.lambda.imgui.flag.ImGuiMouseButton import com.lambda.util.InputUtils import com.lambda.util.KeyCode import com.lambda.util.Mouse import com.lambda.util.StringUtils.capitalize import com.lambda.util.extension.CommandBuilder -import com.lambda.imgui.ImGui.isMouseClicked -import com.lambda.imgui.flag.ImGuiCol -import com.lambda.imgui.flag.ImGuiHoveredFlags -import com.lambda.imgui.flag.ImGuiMouseButton import net.minecraft.command.CommandRegistryAccess import org.lwjgl.glfw.GLFW.GLFW_KEY_LEFT_SHIFT import org.lwjgl.glfw.GLFW.GLFW_KEY_RIGHT_SUPER @@ -53,16 +56,27 @@ import org.lwjgl.glfw.GLFW.GLFW_MOD_SHIFT import org.lwjgl.glfw.GLFW.GLFW_MOD_SUPER class KeybindSetting( + name: String, + description: String, + config: Config, + layer: SettingLayer.Single<*, Bind>, + visibility: () -> Boolean, defaultValue: Bind, private val muteable: Muteable?, private val alwaysListening: Boolean, private val screenCheck: Boolean -) : SettingCore( - defaultValue, - TypeToken.get(Bind::class.java).type -), Muteable { - constructor(defaultValue: KeyCode, muteable: Muteable?, alwaysListen: Boolean, screenCheck: Boolean) - : this(Bind(defaultValue.code, 0, -1), muteable, alwaysListen, screenCheck) +) : Setting(name, description, SettingCore(defaultValue), config, layer, visibility), Muteable { + constructor( + name: String, + description: String, + config: Config, + layer: SettingLayer.Single<*, Bind>, + visibility: () -> Boolean, + defaultValue: KeyCode, + muteable: Muteable?, + alwaysListen: Boolean, + screenCheck: Boolean + ) : this(name, description, config, layer, visibility, Bind(defaultValue.code, 0, -1), muteable, alwaysListen, screenCheck) private val pressListeners = mutableListOf Unit>() private val repeatListeners = mutableListOf Unit>() @@ -89,9 +103,8 @@ class KeybindSetting( } else if (event.isReleased) releaseListeners.forEach { it(event) } } - context(setting: Setting<*, Bind>) override fun ImGuiBuilder.buildLayout() { - text(setting.name) + text(name) sameLine() val bind = value @@ -114,7 +127,7 @@ class KeybindSetting( } lambdaTooltip { - if (!listening) setting.description.ifBlank { "Click to set. Esc cancels. Backspace/Delete unbinds." } + if (!listening) description.ifBlank { "Click to set. Esc cancels. Backspace/Delete unbinds." } else "Listening… Press a key to bind. Esc to cancel. Backspace/Delete to unbind." } @@ -125,7 +138,7 @@ class KeybindSetting( sameLine() withId("##Unbind-${this@KeybindSetting.hashCode()}") { smallButton("Unbind") { - value = Bind.EMPTY + value = Bind.Empty listening = false } } @@ -149,7 +162,7 @@ class KeybindSetting( if ((it.isPressed && !isModKey) || (it.isReleased && isModKey)) { when (it.translated) { KeyCode.Escape -> {} - KeyCode.Backspace, KeyCode.Delete -> value = Bind.EMPTY + KeyCode.Backspace, KeyCode.Delete -> value = Bind.Empty else -> value = Bind(it.translated.code, it.modifiers, -1) } @@ -161,55 +174,54 @@ class KeybindSetting( } } - context(setting: Setting<*, Bind>) override fun CommandBuilder.buildCommand(registry: CommandRegistryAccess) { - required(word(setting.name)) { name -> + required(word(name)) { nameArg -> suggests { _, builder -> KeyCode.entries.forEach { builder.suggest(it.name.capitalize()) } - (1..10).forEach { builder.suggest(it) } + (1..10).forEach { builder.suggest(it.toString()) } builder.buildFuture() } optional(boolean("mouse button")) { isMouseButton -> executeWithResult { val isMouse = if (isMouseButton != null) isMouseButton().value() else false - var bind = Bind.EMPTY + var bind = Bind.Empty if (isMouse) { val num = try { - name().value().toInt() - } catch(_: NumberFormatException) { - return@executeWithResult failure("${name().value()} doesn't match with a mouse button") + nameArg().value().toInt() + } catch (_: NumberFormatException) { + return@executeWithResult failure("${nameArg().value()} doesn't match with a mouse button") } bind = Bind(0, 0, mouse = num) } else { bind = try { - Bind(KeyCode.valueOf(name().value()).code, 0) - } catch(_: IllegalArgumentException) { - return@executeWithResult failure("${name().value()} doesn't match with a bind") + Bind(KeyCode.valueOf(nameArg().value()).code, 0) + } catch (_: IllegalArgumentException) { + return@executeWithResult failure("${nameArg().value()} doesn't match with a bind") } } - setting.trySetValue(bind) + trySetValue(bind) return@executeWithResult success() } } } } + @Suppress("unused") companion object { - fun Setting.onPress(block: SafeContext.(ButtonEvent) -> Unit) = apply { - core.pressListeners.add(block) - } + @ConfigEntryD5l + fun KeybindSetting.onPress(block: SafeContext.(ButtonEvent) -> Unit) = apply { pressListeners.add(block) } - fun Setting.onRepeat(block: SafeContext.(ButtonEvent) -> Unit) = apply { - core.repeatListeners.add(block) - } + @ConfigEntryD5l + fun KeybindSetting.onRepeat(block: SafeContext.(ButtonEvent) -> Unit) = apply { repeatListeners.add(block) } - fun Setting.onRelease(block: SafeContext.(ButtonEvent) -> Unit) = apply { - core.releaseListeners.add(block) - } + @ConfigEntryD5l + fun KeybindSetting.onRelease(block: SafeContext.(ButtonEvent) -> Unit) = apply { releaseListeners.add(block) } } } +@Suppress("unused") +@JsonIncludeProperties("key", "modifiers", "mouse") data class Bind( val key: Int, val modifiers: Int, @@ -247,6 +259,6 @@ data class Bind( "Key Code: $key, Modifiers: ${trueMods.joinToString(separator = "+") { it.name }}, Mouse Button: ${Mouse.entries.getOrNull(mouse) ?: "None"}" companion object { - val EMPTY = Bind(0, 0, -1) + val Empty = Bind(0, 0, -1) } } diff --git a/src/main/kotlin/com/lambda/config/settings/complex/Vec3dSetting.kt b/src/main/kotlin/com/lambda/config/settings/complex/Vec3dSetting.kt index 17aa606f8..4909fe47c 100644 --- a/src/main/kotlin/com/lambda/config/settings/complex/Vec3dSetting.kt +++ b/src/main/kotlin/com/lambda/config/settings/complex/Vec3dSetting.kt @@ -17,38 +17,41 @@ package com.lambda.config.settings.complex -import com.google.gson.reflect.TypeToken import com.lambda.brigadier.argument.double import com.lambda.brigadier.argument.value import com.lambda.brigadier.execute import com.lambda.brigadier.required +import com.lambda.config.Config import com.lambda.config.Setting import com.lambda.config.SettingCore +import com.lambda.config.SettingLayer import com.lambda.gui.dsl.ImGuiBuilder import com.lambda.util.extension.CommandBuilder import net.minecraft.command.CommandRegistryAccess import net.minecraft.util.math.Vec3d -class Vec3dSetting(defaultValue: Vec3d) : SettingCore( - defaultValue, - TypeToken.get(Vec3d::class.java).type -) { - context(setting: Setting<*, Vec3d>) - override fun ImGuiBuilder.buildLayout() { - inputVec3d(setting.name, ::value as Vec3d) // FixMe: what the fuck - lambdaTooltip(setting.description) +class Vec3dSetting( + name: String, + description: String, + config: Config, + layer: SettingLayer.Single<*, Vec3d>, + visibility: () -> Boolean, + defaultValue: Vec3d +) : Setting(name, description, SettingCore(defaultValue), config, layer, visibility) { + override fun ImGuiBuilder.buildLayout() { + inputVec3d(name, ::value as Vec3d) // FixMe: what the fuck + lambdaTooltip(description) } - context(setting: Setting<*, Vec3d>) override fun CommandBuilder.buildCommand(registry: CommandRegistryAccess) { required(double("X", -30000000.0, 30000000.0)) { x -> required(double("Y", -64.0, 255.0)) { y -> required(double("Z", -30000000.0, 30000000.0)) { z -> execute { - setting.trySetValue(Vec3d(x().value(), y().value(), z().value())) + trySetValue(Vec3d(x().value(), y().value(), z().value())) } } } } } -} +} \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/config/settings/numeric/DoubleSetting.kt b/src/main/kotlin/com/lambda/config/settings/numeric/DoubleSetting.kt index d5efa138b..02b1ba111 100644 --- a/src/main/kotlin/com/lambda/config/settings/numeric/DoubleSetting.kt +++ b/src/main/kotlin/com/lambda/config/settings/numeric/DoubleSetting.kt @@ -22,48 +22,46 @@ import com.lambda.brigadier.argument.double import com.lambda.brigadier.argument.value import com.lambda.brigadier.execute import com.lambda.brigadier.required -import com.lambda.config.Setting +import com.lambda.config.Config +import com.lambda.config.SettingLayer import com.lambda.config.settings.NumericSetting import com.lambda.gui.dsl.ImGuiBuilder +import com.lambda.imgui.type.ImInt import com.lambda.util.extension.CommandBuilder import com.lambda.util.math.MathUtils.roundToStep import net.minecraft.command.CommandRegistryAccess import kotlin.math.roundToInt /** - * @see [com.lambda.config.Configurable] + * @see [com.lambda.config.Config] */ class DoubleSetting( - defaultValue: Double, - override var range: ClosedRange, - override var step: Double, + name: String, + description: String, + config: Config, + layer: SettingLayer.Single<*, Double>, + visibility: () -> Boolean, + defaultValue: Double, + override var range: ClosedRange, + override var step: Double, unit: String -) : NumericSetting( - defaultValue, - range, - step, - unit -) { - private var valueIndex: Int - get() = ((value - range.start) / step).roundToInt() - set(index) { - value = (range.start + index * step) - .roundToStep(step) - .coerceIn(range) - } +) : NumericSetting(name, description, config, layer, defaultValue, visibility, range, step, unit) { + override fun ImGuiBuilder.buildSlider() { + val maxIndex = ((range.endInclusive - range.start) / step).toInt() + val currentIndex = ((value - range.start) / step).roundToInt() + val imInt = ImInt(currentIndex) + slider("##$name", imInt, 0, maxIndex, "") { + value = (range.start + imInt.get() * step) + .roundToStep(step) + .coerceIn(range) + } + } - context(setting: Setting<*, Double>) - override fun ImGuiBuilder.buildSlider() { - val maxIndex = ((range.endInclusive - range.start) / step).toInt() - slider("##${setting.name}", ::valueIndex, 0, maxIndex, "") - } - - context(setting: Setting<*, Double>) - override fun CommandBuilder.buildCommand(registry: CommandRegistryAccess) { - required(double(setting.name, range.start, range.endInclusive)) { parameter -> - execute { - setting.trySetValue(parameter().value()) - } - } - } -} + override fun CommandBuilder.buildCommand(registry: CommandRegistryAccess) { + required(double(name, range.start, range.endInclusive)) { parameter -> + execute { + trySetValue(parameter().value()) + } + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/config/settings/numeric/FloatSetting.kt b/src/main/kotlin/com/lambda/config/settings/numeric/FloatSetting.kt index a82509a09..beeeba7a1 100644 --- a/src/main/kotlin/com/lambda/config/settings/numeric/FloatSetting.kt +++ b/src/main/kotlin/com/lambda/config/settings/numeric/FloatSetting.kt @@ -21,48 +21,46 @@ import com.lambda.brigadier.argument.float import com.lambda.brigadier.argument.value import com.lambda.brigadier.execute import com.lambda.brigadier.required -import com.lambda.config.Setting +import com.lambda.config.Config +import com.lambda.config.SettingLayer import com.lambda.config.settings.NumericSetting import com.lambda.gui.dsl.ImGuiBuilder +import com.lambda.imgui.type.ImInt import com.lambda.util.extension.CommandBuilder import com.lambda.util.math.MathUtils.roundToStep import net.minecraft.command.CommandRegistryAccess import kotlin.math.roundToInt /** - * @see [com.lambda.config.Configurable] + * @see [com.lambda.config.Config] */ class FloatSetting( - defaultValue: Float, - override var range: ClosedRange, - override var step: Float = 1f, - unit: String, -) : NumericSetting( - defaultValue, - range, - step, - unit -) { - private var valueIndex: Int - get() = ((value - range.start) / step).roundToInt() - set(index) { - value = (range.start + index * step) - .roundToStep(step) - .coerceIn(range) - } + name: String, + description: String, + config: Config, + layer: SettingLayer.Single<*, Float>, + visibility: () -> Boolean, + defaultValue: Float, + override var range: ClosedRange, + override var step: Float = 1f, + unit: String, +) : NumericSetting(name, description, config, layer, defaultValue, visibility, range, step, unit) { + override fun ImGuiBuilder.buildSlider() { + val maxIndex = ((range.endInclusive - range.start) / step).toInt() + val currentIndex = ((value - range.start) / step).roundToInt() + val imInt = ImInt(currentIndex) + slider("##$name", imInt, 0, maxIndex, "") { + value = (range.start + imInt.get() * step) + .roundToStep(step) + .coerceIn(range) + } + } - context(setting: Setting<*, Float>) - override fun ImGuiBuilder.buildSlider() { - val maxIndex = ((range.endInclusive - range.start) / step).toInt() - slider("##${setting.name}", ::valueIndex, 0, maxIndex, "") - } - - context(setting: Setting<*, Float>) - override fun CommandBuilder.buildCommand(registry: CommandRegistryAccess) { - required(float(setting.name, range.start, range.endInclusive)) { parameter -> - execute { - setting.trySetValue(parameter().value()) - } - } - } -} + override fun CommandBuilder.buildCommand(registry: CommandRegistryAccess) { + required(float(name, range.start, range.endInclusive)) { parameter -> + execute { + trySetValue(parameter().value()) + } + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/config/settings/numeric/IntegerSetting.kt b/src/main/kotlin/com/lambda/config/settings/numeric/IntegerSetting.kt index 07a1849dc..3998c5c99 100644 --- a/src/main/kotlin/com/lambda/config/settings/numeric/IntegerSetting.kt +++ b/src/main/kotlin/com/lambda/config/settings/numeric/IntegerSetting.kt @@ -21,37 +21,36 @@ import com.lambda.brigadier.argument.integer import com.lambda.brigadier.argument.value import com.lambda.brigadier.execute import com.lambda.brigadier.required -import com.lambda.config.Setting +import com.lambda.config.Config +import com.lambda.config.SettingLayer import com.lambda.config.settings.NumericSetting import com.lambda.gui.dsl.ImGuiBuilder import com.lambda.util.extension.CommandBuilder import net.minecraft.command.CommandRegistryAccess /** - * @see [com.lambda.config.Configurable] + * @see [com.lambda.config.Config] */ class IntegerSetting( + name: String, + description: String, + config: Config, + layer: SettingLayer.Single<*, Int>, + visibility: () -> Boolean, defaultValue: Int, override var range: ClosedRange, override var step: Int = 1, unit: String -) : NumericSetting( - defaultValue, - range, - step, - unit -) { - context(setting: Setting<*, Int>) +) : NumericSetting(name, description, config, layer, defaultValue, visibility, range, step, unit) { override fun ImGuiBuilder.buildSlider() { - slider("##${setting.name}", ::value, range.start, range.endInclusive, "") + slider("##$name", ::value, range.start, range.endInclusive, "") } - context(setting: Setting<*, Int>) override fun CommandBuilder.buildCommand(registry: CommandRegistryAccess) { - required(integer(setting.name, range.start, range.endInclusive)) { parameter -> + required(integer(name, range.start, range.endInclusive)) { parameter -> execute { - setting.trySetValue(parameter().value()) + trySetValue(parameter().value()) } } } -} +} \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/config/settings/numeric/LongSetting.kt b/src/main/kotlin/com/lambda/config/settings/numeric/LongSetting.kt index c71a2a838..46a92b0c1 100644 --- a/src/main/kotlin/com/lambda/config/settings/numeric/LongSetting.kt +++ b/src/main/kotlin/com/lambda/config/settings/numeric/LongSetting.kt @@ -21,45 +21,43 @@ import com.lambda.brigadier.argument.long import com.lambda.brigadier.argument.value import com.lambda.brigadier.execute import com.lambda.brigadier.required -import com.lambda.config.Setting +import com.lambda.config.Config +import com.lambda.config.SettingLayer import com.lambda.config.settings.NumericSetting import com.lambda.gui.dsl.ImGuiBuilder +import com.lambda.imgui.type.ImInt import com.lambda.util.extension.CommandBuilder import net.minecraft.command.CommandRegistryAccess /** - * @see [com.lambda.config.Configurable] + * @see [com.lambda.config.Config] */ class LongSetting( + name: String, + description: String, + config: Config, + layer: SettingLayer.Single<*, Long>, + visibility: () -> Boolean, defaultValue: Long, override var range: ClosedRange, override var step: Long = 1, unit: String -) : NumericSetting( - defaultValue, - range, - step, - unit -) { - // ToDo: No worky for super large numbers - private var valueIndex: Int - get() = ((value - range.start) / step).toInt() - set(index) { - value = (range.start + index * step).coerceIn(range) - } - - context(setting: Setting<*, Long>) +) : NumericSetting(name, description, config, layer, defaultValue, visibility, range, step, unit) { override fun ImGuiBuilder.buildSlider() { + // FixMe: No worky for super large numbers val maxIndex = ((range.endInclusive - range.start) / step).toInt() - slider("##${setting.name}", ::valueIndex, 0, maxIndex, "") + val currentIndex = ((value - range.start) / step).toInt() + val imInt = ImInt(currentIndex) + slider("##$name", imInt, 0, maxIndex, "") { + value = (range.start + imInt.get() * step).coerceIn(range) + } } - context(setting: Setting<*, Long>) override fun CommandBuilder.buildCommand(registry: CommandRegistryAccess) { - required(long(setting.name, range.start, range.endInclusive)) { parameter -> + required(long(name, range.start, range.endInclusive)) { parameter -> execute { - setting.trySetValue(parameter().value()) + trySetValue(parameter().value()) } } } -} +} \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/context/Automated.kt b/src/main/kotlin/com/lambda/context/Automated.kt index 46d4cb23d..681f3e310 100644 --- a/src/main/kotlin/com/lambda/context/Automated.kt +++ b/src/main/kotlin/com/lambda/context/Automated.kt @@ -17,13 +17,13 @@ package com.lambda.context -import com.lambda.config.groups.BuildConfig -import com.lambda.config.groups.EatConfig -import com.lambda.interaction.managers.breaking.BreakConfig -import com.lambda.interaction.managers.hotbar.HotbarConfig -import com.lambda.interaction.managers.interacting.InteractConfig -import com.lambda.interaction.managers.inventory.InventoryConfig -import com.lambda.interaction.managers.rotating.RotationConfig +import com.lambda.config.settings.blocks.BreakConfig +import com.lambda.config.settings.blocks.BuildConfig +import com.lambda.config.settings.blocks.EatConfig +import com.lambda.config.settings.blocks.HotbarConfig +import com.lambda.config.settings.blocks.InteractConfig +import com.lambda.config.settings.blocks.InventoryConfig +import com.lambda.config.settings.blocks.RotationConfig interface Automated { val buildConfig: BuildConfig diff --git a/src/main/kotlin/com/lambda/core/Loader.kt b/src/main/kotlin/com/lambda/core/Loader.kt index 564f6fa81..d629acc28 100644 --- a/src/main/kotlin/com/lambda/core/Loader.kt +++ b/src/main/kotlin/com/lambda/core/Loader.kt @@ -18,9 +18,9 @@ package com.lambda.core import com.lambda.Lambda -import com.lambda.Lambda.LOG -import com.lambda.util.Communication.ascii -import com.lambda.util.reflections.getInstances +import com.lambda.Lambda.Log +import com.lambda.util.CommunicationUtils.ascii +import com.lambda.util.ReflectionUtils.getInstances import kotlin.system.measureTimeMillis import kotlin.time.Duration.Companion.milliseconds @@ -33,14 +33,14 @@ object Loader { private val loadables = getInstances() fun initialize(): Long { - ascii.split("\n").forEach { LOG.info(it) } - LOG.info("Initializing ${Lambda.MOD_NAME} ${Lambda.VERSION} (${loadables.size} loaders)...") + ascii.split("\n").forEach { Log.info(it) } + Log.info("Initializing ${Lambda.ModName} ${Lambda.Version} (${loadables.size} loaders)...") val initTime = measureTimeMillis { loadables.sortedByDescending { it.priority }.forEach { var response: String val time = measureTimeMillis { response = it.load() } - if (response.isNotBlank()) LOG.info("$response ($time ms)") + if (response.isNotBlank()) Log.info("$response ($time ms)") } } diff --git a/src/main/kotlin/com/lambda/core/PingManager.kt b/src/main/kotlin/com/lambda/core/PingHandler.kt similarity index 92% rename from src/main/kotlin/com/lambda/core/PingManager.kt rename to src/main/kotlin/com/lambda/core/PingHandler.kt index 788445e70..8adaf819a 100644 --- a/src/main/kotlin/com/lambda/core/PingManager.kt +++ b/src/main/kotlin/com/lambda/core/PingHandler.kt @@ -25,24 +25,23 @@ import net.minecraft.network.packet.c2s.query.QueryPingC2SPacket import net.minecraft.network.packet.s2c.query.PingResultS2CPacket import net.minecraft.util.Util -object PingManager : Loadable { +@Suppress("unused") +object PingHandler : Loadable { private val pings: LimitedOrderedSet = LimitedOrderedSet(100) - private const val INTERVAL = 1 - override fun load() = "Loaded Ping Manager" - - val lastPing: Long - get() = pings.lastOrNull() ?: 0 - - init { + override fun load(): String { listen { connection.sendPacket(QueryPingC2SPacket(Util.getMeasuringTimeMs())) } listen { event -> if (event.packet !is PingResultS2CPacket) return@listen - pings.add(Util.getMeasuringTimeMs() - event.packet.startTime) } + + return "Loaded Ping Manager" } + + val lastPing: Long + get() = pings.lastOrNull() ?: 0 } diff --git a/src/main/kotlin/com/lambda/core/TimerManager.kt b/src/main/kotlin/com/lambda/core/TimerHandler.kt similarity index 92% rename from src/main/kotlin/com/lambda/core/TimerManager.kt rename to src/main/kotlin/com/lambda/core/TimerHandler.kt index 69f385029..786f56784 100644 --- a/src/main/kotlin/com/lambda/core/TimerManager.kt +++ b/src/main/kotlin/com/lambda/core/TimerHandler.kt @@ -22,15 +22,15 @@ import com.lambda.event.events.ClientEvent import kotlin.concurrent.fixedRateTimer import kotlin.time.Duration.Companion.milliseconds -object TimerManager : Loadable { - const val DEFAULT_LENGTH = 50.0 +object TimerHandler : Loadable { + const val DefaultLength = 50.0 var lastTickLength = 50.0 override fun load() = "Loaded Timer Manager" val length: Double get() { - var length = DEFAULT_LENGTH + var length = DefaultLength ClientEvent.TimerUpdate(1.0).post { length /= speed diff --git a/src/main/kotlin/com/lambda/event/events/ModuleEvent.kt b/src/main/kotlin/com/lambda/event/events/ModuleEvent.kt index 5eba52e79..531cee463 100644 --- a/src/main/kotlin/com/lambda/event/events/ModuleEvent.kt +++ b/src/main/kotlin/com/lambda/event/events/ModuleEvent.kt @@ -18,8 +18,6 @@ package com.lambda.event.events import com.lambda.event.Event -import com.lambda.event.callback.Cancellable -import com.lambda.event.callback.ICancellable import com.lambda.module.Module /** diff --git a/src/main/kotlin/com/lambda/event/listener/Listener.kt b/src/main/kotlin/com/lambda/event/listener/Listener.kt index e45dc9c0e..8a59ba1ea 100644 --- a/src/main/kotlin/com/lambda/event/listener/Listener.kt +++ b/src/main/kotlin/com/lambda/event/listener/Listener.kt @@ -73,3 +73,6 @@ abstract class Listener : Comparable> { get() = (this as? OwnerPriority)?.let { { ownerPriority } } ?: { 0 } } } + +@DslMarker +annotation class ListenMarker diff --git a/src/main/kotlin/com/lambda/event/listener/SafeListener.kt b/src/main/kotlin/com/lambda/event/listener/SafeListener.kt index f29dd6811..4071fba71 100644 --- a/src/main/kotlin/com/lambda/event/listener/SafeListener.kt +++ b/src/main/kotlin/com/lambda/event/listener/SafeListener.kt @@ -119,6 +119,7 @@ class SafeListener( * @param function The function to be executed when the event is posted. This function should take a SafeContext and an event of type T as parameters. * @return The newly created and registered [SafeListener]. */ + @ListenMarker inline fun Any.listen( noinline priority: () -> Int = ownerPriorityOr0Getter, alwaysListen: Boolean = false, @@ -161,6 +162,7 @@ class SafeListener( * @param function The function to be executed when the event is posted. This function should take a SafeContext and an event of type T as parameters. * @return The newly created and registered [SafeListener]. */ + @ListenMarker fun Any.listen( kClass: KClass, priority: () -> Int = ownerPriorityOr0Getter, @@ -202,6 +204,7 @@ class SafeListener( * @param alwaysListen If true, the listener will be executed even if it is muted. The Default value is false. * @return The newly created and registered [SafeListener]. */ + @ListenMarker inline fun Any.listenOnce( noinline priority: () -> Int = ownerPriorityOr0Getter, alwaysListen: Boolean = false, @@ -250,6 +253,7 @@ class SafeListener( * @param function The function to be executed when the event is posted. This function should take a SafeContext and an event of type T as parameters. * @return The newly created and registered [SafeListener]. */ + @ListenMarker inline fun Any.listenConcurrently( noinline priority: () -> Int = ownerPriorityOr0Getter, alwaysListen: Boolean = false, diff --git a/src/main/kotlin/com/lambda/event/listener/UnsafeListener.kt b/src/main/kotlin/com/lambda/event/listener/UnsafeListener.kt index 58347660d..c6c126daf 100644 --- a/src/main/kotlin/com/lambda/event/listener/UnsafeListener.kt +++ b/src/main/kotlin/com/lambda/event/listener/UnsafeListener.kt @@ -111,6 +111,7 @@ class UnsafeListener( * @param function The function to be executed when the event is posted. This function should take an event of type T as a parameter. * @return The newly created and registered [UnsafeListener]. */ + @ListenMarker inline fun Any.listenUnsafe( noinline priority: () -> Int = ownerPriorityOr0Getter, alwaysListen: Boolean = false, @@ -149,6 +150,7 @@ class UnsafeListener( * @param function The function to be executed when the event is posted. This function should take an event of type T as a parameter. * @return The newly created and registered [UnsafeListener]. */ + @ListenMarker fun Any.listenUnsafe( kClass: KClass, priority: () -> Int = ownerPriorityOr0Getter, @@ -185,6 +187,7 @@ class UnsafeListener( * @param alwaysListen If true, the listener will be executed even if it is muted. * @return The newly created and registered [UnsafeListener]. */ + @ListenMarker inline fun Any.listenOnceUnsafe( noinline priority: () -> Int = ownerPriorityOr0Getter, alwaysListen: Boolean = false, @@ -234,6 +237,7 @@ class UnsafeListener( * @param function The function to be executed when the event is posted. This function should take a SafeContext and an event of type T as parameters. * @return The newly created and registered [UnsafeListener]. */ + @ListenMarker inline fun Any.listenConcurrentlyUnsafe( noinline priority: () -> Int = ownerPriorityOr0Getter, alwaysListen: Boolean = false, diff --git a/src/main/kotlin/com/lambda/friend/FriendManager.kt b/src/main/kotlin/com/lambda/friend/FriendHandler.kt similarity index 90% rename from src/main/kotlin/com/lambda/friend/FriendManager.kt rename to src/main/kotlin/com/lambda/friend/FriendHandler.kt index 240bda5de..3edf6c20a 100644 --- a/src/main/kotlin/com/lambda/friend/FriendManager.kt +++ b/src/main/kotlin/com/lambda/friend/FriendHandler.kt @@ -18,8 +18,10 @@ package com.lambda.friend import com.lambda.Lambda.mc -import com.lambda.config.Configurable -import com.lambda.config.configurations.FriendConfig +import com.lambda.command.CommandRegistry.prefix +import com.lambda.command.commands.FriendCommand +import com.lambda.config.Config +import com.lambda.config.categories.FriendCategory import com.lambda.core.Loadable import com.lambda.network.mojang.getProfile import com.lambda.util.text.ClickEvents @@ -34,8 +36,10 @@ import net.minecraft.text.Text import java.awt.Color import java.util.* -object FriendManager : Configurable(FriendConfig), Loadable { - override val name = "friends" +object FriendHandler : Config( + "friends", + FriendCategory +), Loadable { val friends by setting("friends", emptySet(), serialize = true) private val cachedProfiles = mutableMapOf() @@ -112,7 +116,7 @@ object FriendManager : Configurable(FriendConfig), Loadable { literal(Color.GREEN, "Added ") text(name) literal(" to your friend list ") - clickEvent(ClickEvents.suggestCommand(";friends remove ${name.string}")) { + clickEvent(ClickEvents.suggestCommand("${prefix}${FriendCommand.name} remove ${name.string}")) { styled(underlined = true, color = Color.LIGHT_GRAY) { literal("[Undo]") } @@ -124,7 +128,7 @@ object FriendManager : Configurable(FriendConfig), Loadable { literal(Color.RED, "Removed ") text(name) literal(" from your friend list ") - clickEvent(ClickEvents.suggestCommand(";friends add ${name.string}")) { + clickEvent(ClickEvents.suggestCommand("${prefix}${FriendCommand.name} add ${name.string}")) { styled(underlined = true, color = Color.LIGHT_GRAY) { literal("[Undo]") } diff --git a/src/main/kotlin/com/lambda/graphics/RenderMain.kt b/src/main/kotlin/com/lambda/graphics/RenderMain.kt index 3f251ae27..d14023f1a 100644 --- a/src/main/kotlin/com/lambda/graphics/RenderMain.kt +++ b/src/main/kotlin/com/lambda/graphics/RenderMain.kt @@ -20,8 +20,8 @@ package com.lambda.graphics import com.lambda.event.EventFlow.post import com.lambda.event.events.RenderEvent import com.lambda.graphics.mc.renderer.RendererUtils +import com.lambda.graphics.outline.OutlineHandler import com.lambda.graphics.outline.OutlineIdBuffer -import com.lambda.graphics.outline.OutlineManager import com.lambda.graphics.outline.OutlineRenderer import com.lambda.graphics.outline.VertexCapture import org.joml.Matrix4f @@ -36,7 +36,7 @@ object RenderMain { @JvmStatic fun preRender() { - OutlineManager.clear() + OutlineHandler.clear() VertexCapture.clear() OutlineIdBuffer.beginFrame() } diff --git a/src/main/kotlin/com/lambda/graphics/mc/BoxBuilder.kt b/src/main/kotlin/com/lambda/graphics/mc/BoxBuilder.kt index acd76c20f..7ceeed706 100644 --- a/src/main/kotlin/com/lambda/graphics/mc/BoxBuilder.kt +++ b/src/main/kotlin/com/lambda/graphics/mc/BoxBuilder.kt @@ -17,14 +17,14 @@ package com.lambda.graphics.mc -import com.lambda.config.groups.LineConfig +import com.lambda.config.settings.blocks.LineConfig import com.lambda.graphics.util.DirectionMask import net.minecraft.util.math.Direction import java.awt.Color class BoxBuilder(lineConfig: LineConfig?) { - var outlineSides: Int = DirectionMask.ALL - var fillSides: Int = DirectionMask.ALL + var outlineSides: Int = DirectionMask.All + var fillSides: Int = DirectionMask.All var outlineMode: DirectionMask.OutlineMode = DirectionMask.OutlineMode.And var lineWidth = lineConfig?.width ?: -0.0005f @@ -213,24 +213,24 @@ class BoxBuilder(lineConfig: LineConfig?) { @RenderDsl fun hideOutline() { - outlineSides = DirectionMask.NONE + outlineSides = DirectionMask.None } @RenderDsl fun hideFill() { - fillSides = DirectionMask.NONE + fillSides = DirectionMask.None } @RenderDsl fun outlineOnly() { - outlineSides = DirectionMask.ALL - fillSides = DirectionMask.NONE + outlineSides = DirectionMask.All + fillSides = DirectionMask.None } @RenderDsl fun fillOnly() { - outlineSides = DirectionMask.NONE - fillSides = DirectionMask.ALL + outlineSides = DirectionMask.None + fillSides = DirectionMask.All } @RenderDsl diff --git a/src/main/kotlin/com/lambda/graphics/mc/RegionRenderer.kt b/src/main/kotlin/com/lambda/graphics/mc/RegionRenderer.kt index b71010199..09ad03afa 100644 --- a/src/main/kotlin/com/lambda/graphics/mc/RegionRenderer.kt +++ b/src/main/kotlin/com/lambda/graphics/mc/RegionRenderer.kt @@ -18,9 +18,9 @@ package com.lambda.graphics.mc import com.lambda.Lambda.mc -import com.lambda.graphics.outline.OutlineStyle import com.lambda.graphics.mc.renderer.RendererUtils import com.lambda.graphics.mc.renderer.upload +import com.lambda.graphics.outline.OutlineStyle import com.mojang.blaze3d.buffers.GpuBuffer import com.mojang.blaze3d.systems.RenderPass import com.mojang.blaze3d.systems.RenderSystem @@ -409,8 +409,6 @@ class RegionRenderer { fun hasData(): Boolean = hasWorldData companion object { - fun createRenderPass(label: String): RenderPass? = createRenderPass(label, useMcDepth = true) - fun createRenderPass(label: String, useMcDepth: Boolean): RenderPass? { val framebuffer = mc.framebuffer ?: return null diff --git a/src/main/kotlin/com/lambda/graphics/mc/RenderBuilder.kt b/src/main/kotlin/com/lambda/graphics/mc/RenderBuilder.kt index ece277047..f0e4f7220 100644 --- a/src/main/kotlin/com/lambda/graphics/mc/RenderBuilder.kt +++ b/src/main/kotlin/com/lambda/graphics/mc/RenderBuilder.kt @@ -18,9 +18,9 @@ package com.lambda.graphics.mc import com.lambda.Lambda.mc -import com.lambda.config.groups.LineConfig +import com.lambda.config.settings.blocks.LineConfig import com.lambda.context.SafeContext -import com.lambda.graphics.outline.OutlineManager +import com.lambda.graphics.outline.OutlineHandler import com.lambda.graphics.outline.OutlineStyle import com.lambda.graphics.text.FontHandler import com.lambda.graphics.text.SDFFontAtlas @@ -32,12 +32,12 @@ import com.mojang.blaze3d.textures.GpuTextureView import net.minecraft.block.BlockState import net.minecraft.client.font.TextRenderer import net.minecraft.client.render.OverlayTexture -import net.minecraft.client.render.item.ItemRenderState -import net.minecraft.client.render.command.OrderedRenderCommandQueue -import net.minecraft.client.render.VertexConsumer import net.minecraft.client.render.RenderLayer +import net.minecraft.client.render.VertexConsumer import net.minecraft.client.render.command.ModelCommandRenderer +import net.minecraft.client.render.command.OrderedRenderCommandQueue import net.minecraft.client.render.entity.state.EntityRenderState +import net.minecraft.client.render.item.ItemRenderState import net.minecraft.client.render.model.BakedQuad import net.minecraft.client.render.model.BlockModelPart import net.minecraft.client.render.model.BlockStateModel @@ -45,14 +45,14 @@ import net.minecraft.client.render.state.CameraRenderState import net.minecraft.client.texture.Sprite import net.minecraft.client.util.math.MatrixStack import net.minecraft.entity.Entity -import net.minecraft.util.Identifier -import net.minecraft.util.math.BlockPos -import net.minecraft.util.math.Box -import net.minecraft.util.math.Vec3d import net.minecraft.item.ItemDisplayContext import net.minecraft.item.ItemStack import net.minecraft.text.OrderedText import net.minecraft.text.Text +import net.minecraft.util.Identifier +import net.minecraft.util.math.BlockPos +import net.minecraft.util.math.Box +import net.minecraft.util.math.Vec3d import net.minecraft.util.math.random.Random import org.joml.Matrix4f import org.joml.Quaternionf @@ -102,8 +102,8 @@ class RenderBuilder(private val cameraPos: Vec3d, var depthTest: Boolean = false builder: (BoxBuilder.() -> Unit)? = null ) { val boxBuilder = BoxBuilder(lineConfig).apply { builder?.invoke(this) } - if (boxBuilder.fillSides != DirectionMask.NONE) boxBuilder.boxFaces(box) - if (boxBuilder.outlineSides != DirectionMask.NONE) boxBuilder.boxOutline(box) + if (boxBuilder.fillSides != DirectionMask.None) boxBuilder.boxFaces(box) + if (boxBuilder.outlineSides != DirectionMask.None) boxBuilder.boxOutline(box) } context(safeContext: SafeContext) @@ -116,8 +116,8 @@ class RenderBuilder(private val cameraPos: Vec3d, var depthTest: Boolean = false val boxes = state.getOutlineShape(world, pos).boundingBoxes.map { it.offset(pos) } val boxBuilder = BoxBuilder(lineConfig).apply { builder?.invoke(this) } boxes.forEach { box -> - if (boxBuilder.fillSides != DirectionMask.NONE) boxBuilder.boxFaces(box) - if (boxBuilder.outlineSides != DirectionMask.NONE) boxBuilder.boxOutline(box) + if (boxBuilder.fillSides != DirectionMask.None) boxBuilder.boxFaces(box) + if (boxBuilder.outlineSides != DirectionMask.None) boxBuilder.boxOutline(box) } } @@ -277,28 +277,28 @@ class RenderBuilder(private val cameraPos: Vec3d, var depthTest: Boolean = false fun worldOutline( entity: Entity, style: OutlineStyle - ) = OutlineManager.setEntityOutline(entity.id, style, depthTest = depthTest) + ) = OutlineHandler.setEntityOutline(entity.id, style, depthTest = depthTest) @JvmName("worldOutlines1") fun worldOutlines( entities: Iterable, style: OutlineStyle ) = entities.forEach { - OutlineManager.setEntityOutline(it.id, style, depthTest = depthTest) + OutlineHandler.setEntityOutline(it.id, style, depthTest = depthTest) } @JvmName("worldOutline2") fun worldOutline( pos: BlockPos, style: OutlineStyle - ) = OutlineManager.setBlockOutline(pos, style, depthTest = depthTest) + ) = OutlineHandler.setBlockOutline(pos, style, depthTest = depthTest) @JvmName("worldOutlines2") fun worldOutlines( positions: Iterable, style: OutlineStyle ) = positions.forEach { - OutlineManager.setBlockOutline(it, style, depthTest = depthTest) + OutlineHandler.setBlockOutline(it, style, depthTest = depthTest) } fun withOutline(style: OutlineStyle, block: RenderBuilder.() -> Unit) { @@ -1306,7 +1306,7 @@ class RenderBuilder(private val cameraPos: Vec3d, var depthTest: Boolean = false } private fun BoxBuilder.boxFaces(box: Box) { - if (fillSides.hasDirection(DirectionMask.EAST)) { + if (fillSides.hasDirection(DirectionMask.East)) { filledQuadGradient( box.maxX, box.minY, box.minZ, fillBottomNorthEast, box.maxX, box.maxY, box.minZ, fillTopNorthEast, @@ -1314,7 +1314,7 @@ class RenderBuilder(private val cameraPos: Vec3d, var depthTest: Boolean = false box.maxX, box.minY, box.maxZ, fillBottomSouthEast ) } - if (fillSides.hasDirection(DirectionMask.WEST)) { + if (fillSides.hasDirection(DirectionMask.West)) { filledQuadGradient( box.minX, box.minY, box.minZ, fillBottomNorthWest, box.minX, box.minY, box.maxZ, fillBottomSouthWest, @@ -1322,7 +1322,7 @@ class RenderBuilder(private val cameraPos: Vec3d, var depthTest: Boolean = false box.minX, box.maxY, box.minZ, fillTopNorthWest ) } - if (fillSides.hasDirection(DirectionMask.UP)) { + if (fillSides.hasDirection(DirectionMask.Up)) { filledQuadGradient( box.minX, box.maxY, box.minZ, fillTopNorthWest, box.minX, box.maxY, box.maxZ, fillTopSouthWest, @@ -1330,7 +1330,7 @@ class RenderBuilder(private val cameraPos: Vec3d, var depthTest: Boolean = false box.maxX, box.maxY, box.minZ, fillTopNorthEast ) } - if (fillSides.hasDirection(DirectionMask.DOWN)) { + if (fillSides.hasDirection(DirectionMask.Down)) { filledQuadGradient( box.minX, box.minY, box.minZ, fillBottomNorthWest, box.maxX, box.minY, box.minZ, fillBottomNorthEast, @@ -1338,7 +1338,7 @@ class RenderBuilder(private val cameraPos: Vec3d, var depthTest: Boolean = false box.minX, box.minY, box.maxZ, fillBottomSouthWest ) } - if (fillSides.hasDirection(DirectionMask.SOUTH)) { + if (fillSides.hasDirection(DirectionMask.South)) { filledQuadGradient( box.minX, box.minY, box.maxZ, fillBottomSouthWest, box.maxX, box.minY, box.maxZ, fillBottomSouthEast, @@ -1346,7 +1346,7 @@ class RenderBuilder(private val cameraPos: Vec3d, var depthTest: Boolean = false box.minX, box.maxY, box.maxZ, fillTopSouthWest ) } - if (fillSides.hasDirection(DirectionMask.NORTH)) { + if (fillSides.hasDirection(DirectionMask.North)) { filledQuadGradient( box.minX, box.minY, box.minZ, fillBottomNorthWest, box.minX, box.maxY, box.minZ, fillTopNorthWest, @@ -1357,12 +1357,12 @@ class RenderBuilder(private val cameraPos: Vec3d, var depthTest: Boolean = false } private fun BoxBuilder.boxOutline(box: Box) { - val hasEast = outlineSides.hasDirection(DirectionMask.EAST) - val hasWest = outlineSides.hasDirection(DirectionMask.WEST) - val hasUp = outlineSides.hasDirection(DirectionMask.UP) - val hasDown = outlineSides.hasDirection(DirectionMask.DOWN) - val hasSouth = outlineSides.hasDirection(DirectionMask.SOUTH) - val hasNorth = outlineSides.hasDirection(DirectionMask.NORTH) + val hasEast = outlineSides.hasDirection(DirectionMask.East) + val hasWest = outlineSides.hasDirection(DirectionMask.West) + val hasUp = outlineSides.hasDirection(DirectionMask.Up) + val hasDown = outlineSides.hasDirection(DirectionMask.Down) + val hasSouth = outlineSides.hasDirection(DirectionMask.South) + val hasNorth = outlineSides.hasDirection(DirectionMask.North) if (outlineMode.check(hasUp, hasNorth)) { lineGradient( @@ -1477,6 +1477,7 @@ class RenderBuilder(private val cameraPos: Vec3d, var depthTest: Boolean = false collector.addEdgeVertex(rx2, ry2, rz2, color2, dx, dy, dz, width, dashStyle, activeOutlineId) } + @Suppress("SameParameterValue") private fun transformPoint(matrix: Matrix4f, x: Float, y: Float, z: Float): Vector3f { val result = Vector4f(x, y, z, 1f) matrix.transform(result) diff --git a/src/main/kotlin/com/lambda/graphics/mc/renderer/AbstractRenderer.kt b/src/main/kotlin/com/lambda/graphics/mc/renderer/AbstractRenderer.kt index 237c1c608..e64ce365d 100644 --- a/src/main/kotlin/com/lambda/graphics/mc/renderer/AbstractRenderer.kt +++ b/src/main/kotlin/com/lambda/graphics/mc/renderer/AbstractRenderer.kt @@ -25,7 +25,6 @@ import com.mojang.blaze3d.buffers.GpuBufferSlice import com.mojang.blaze3d.systems.RenderPass import com.mojang.blaze3d.systems.RenderSystem import com.mojang.blaze3d.textures.FilterMode -import kotlin.collections.isNotEmpty abstract class AbstractRenderer(val name: String, var depthTest: () -> Boolean) { protected abstract fun getRendererTransforms(): List> diff --git a/src/main/kotlin/com/lambda/graphics/mc/renderer/ChunkedRenderer.kt b/src/main/kotlin/com/lambda/graphics/mc/renderer/ChunkedRenderer.kt index 3118f91be..d7aebfca2 100644 --- a/src/main/kotlin/com/lambda/graphics/mc/renderer/ChunkedRenderer.kt +++ b/src/main/kotlin/com/lambda/graphics/mc/renderer/ChunkedRenderer.kt @@ -27,8 +27,9 @@ import com.lambda.event.listener.UnsafeListener.Companion.listenUnsafe import com.lambda.graphics.RenderMain import com.lambda.graphics.mc.RegionRenderer import com.lambda.graphics.mc.RenderBuilder +import com.lambda.graphics.mc.RenderDsl import com.lambda.module.Module -import com.lambda.module.modules.client.StyleEditor +import com.lambda.module.modules.client.Client import com.lambda.util.world.FastVector import com.lambda.util.world.fastVectorOf import com.mojang.blaze3d.buffers.GpuBufferSlice @@ -83,13 +84,13 @@ class ChunkedRenderer( owner.listenConcurrentlyUnsafe { if (pauseUpdates()) return@listenConcurrentlyUnsafe val queueSize = rebuildQueue.size - val polls = minOf(StyleEditor.rebuildsPerTick, queueSize) + val polls = minOf(Client.chunkRebuildsPerTick, queueSize) val depth = depthTest() repeat(polls) { rebuildQueue.poll()?.rebuild(depth) } } owner.listenUnsafe { - val polls = minOf(StyleEditor.uploadsPerTick, uploadQueue.size) + val polls = minOf(Client.chunkUploadsPerTick, uploadQueue.size) repeat(polls) { uploadQueue.poll()?.invoke() } } @@ -189,6 +190,7 @@ class ChunkedRenderer( } companion object { + @RenderDsl fun Any.chunkedRenderer( name: String, preChunkBuild: (ChunkPos) -> Unit = {}, diff --git a/src/main/kotlin/com/lambda/graphics/mc/renderer/ImmediateRenderer.kt b/src/main/kotlin/com/lambda/graphics/mc/renderer/ImmediateRenderer.kt index 8feddcfdc..ab45fcf90 100644 --- a/src/main/kotlin/com/lambda/graphics/mc/renderer/ImmediateRenderer.kt +++ b/src/main/kotlin/com/lambda/graphics/mc/renderer/ImmediateRenderer.kt @@ -18,13 +18,12 @@ package com.lambda.graphics.mc.renderer import com.lambda.Lambda.mc -import com.lambda.context.SafeContext import com.lambda.event.events.RenderEvent -import com.lambda.event.listener.SafeListener.Companion.listen import com.lambda.event.listener.UnsafeListener.Companion.listenUnsafe import com.lambda.graphics.RenderMain import com.lambda.graphics.mc.RegionRenderer import com.lambda.graphics.mc.RenderBuilder +import com.lambda.graphics.mc.RenderDsl import com.mojang.blaze3d.buffers.GpuBufferSlice import com.mojang.blaze3d.systems.RenderSystem import org.joml.Vector3f @@ -72,6 +71,7 @@ class ImmediateRenderer( override fun getScreenRenderers() = if (renderer.hasScreenData()) listOf(renderer) else emptyList() companion object { + @RenderDsl fun Any.immediateRenderer( name: String, depthTest: () -> Boolean = { false }, diff --git a/src/main/kotlin/com/lambda/graphics/mc/renderer/TickedRenderer.kt b/src/main/kotlin/com/lambda/graphics/mc/renderer/TickedRenderer.kt index 198d3fdb3..cd0734dc6 100644 --- a/src/main/kotlin/com/lambda/graphics/mc/renderer/TickedRenderer.kt +++ b/src/main/kotlin/com/lambda/graphics/mc/renderer/TickedRenderer.kt @@ -18,14 +18,13 @@ package com.lambda.graphics.mc.renderer import com.lambda.Lambda.mc -import com.lambda.context.SafeContext import com.lambda.event.events.RenderEvent import com.lambda.event.events.TickEvent -import com.lambda.event.listener.SafeListener.Companion.listen import com.lambda.event.listener.UnsafeListener.Companion.listenUnsafe import com.lambda.graphics.RenderMain import com.lambda.graphics.mc.RegionRenderer import com.lambda.graphics.mc.RenderBuilder +import com.lambda.graphics.mc.RenderDsl import com.mojang.blaze3d.buffers.GpuBufferSlice import com.mojang.blaze3d.systems.RenderSystem import net.minecraft.util.math.Vec3d @@ -87,6 +86,7 @@ class TickedRenderer( override fun getScreenRenderers() = if (renderer.hasScreenData()) listOf(renderer) else emptyList() companion object { + @RenderDsl fun Any.tickedRenderer( name: String, depthTest: () -> Boolean = { false }, diff --git a/src/main/kotlin/com/lambda/graphics/outline/OutlineCapturingQueue.kt b/src/main/kotlin/com/lambda/graphics/outline/OutlineCapturingQueue.kt index 2e88efcc6..3ee79d4f9 100644 --- a/src/main/kotlin/com/lambda/graphics/outline/OutlineCapturingQueue.kt +++ b/src/main/kotlin/com/lambda/graphics/outline/OutlineCapturingQueue.kt @@ -19,39 +19,39 @@ package com.lambda.graphics.outline import com.lambda.Lambda.mc import com.lambda.graphics.RenderMain -import net.minecraft.client.model.Model -import net.minecraft.client.model.ModelPart -import net.minecraft.client.render.RenderLayer -import net.minecraft.client.render.VertexConsumer -import net.minecraft.client.render.model.BakedQuad -import net.minecraft.client.render.state.CameraRenderState -import net.minecraft.client.texture.Sprite -import net.minecraft.client.util.math.MatrixStack -import net.minecraft.item.ItemDisplayContext -import net.minecraft.util.math.Vec3d -import org.joml.Matrix4f -import org.joml.Vector3f -import org.joml.Vector4f import com.mojang.blaze3d.textures.GpuTextureView import net.minecraft.block.BlockState import net.minecraft.client.font.TextRenderer +import net.minecraft.client.model.Model +import net.minecraft.client.model.ModelPart +import net.minecraft.client.render.RenderLayer import net.minecraft.client.render.SpriteTexturedVertexConsumer +import net.minecraft.client.render.VertexConsumer import net.minecraft.client.render.block.BlockModelRenderer import net.minecraft.client.render.block.MovingBlockRenderState import net.minecraft.client.render.command.BatchingRenderCommandQueue import net.minecraft.client.render.command.CustomCommandRenderer import net.minecraft.client.render.command.LabelCommandRenderer -import net.minecraft.client.render.command.OrderedRenderCommandQueue -import net.minecraft.client.render.command.OrderedRenderCommandQueueImpl import net.minecraft.client.render.command.ModelCommandRenderer import net.minecraft.client.render.command.ModelPartCommandRenderer +import net.minecraft.client.render.command.OrderedRenderCommandQueue +import net.minecraft.client.render.command.OrderedRenderCommandQueueImpl import net.minecraft.client.render.entity.state.EntityRenderState import net.minecraft.client.render.item.ItemRenderState +import net.minecraft.client.render.model.BakedQuad import net.minecraft.client.render.model.BlockStateModel +import net.minecraft.client.render.state.CameraRenderState +import net.minecraft.client.texture.Sprite +import net.minecraft.client.util.math.MatrixStack +import net.minecraft.item.ItemDisplayContext import net.minecraft.text.OrderedText import net.minecraft.text.Text +import net.minecraft.util.math.Vec3d +import org.joml.Matrix4f import org.joml.Matrix4fStack import org.joml.Quaternionf +import org.joml.Vector3f +import org.joml.Vector4f class OutlineCapturingQueue @JvmOverloads constructor( private val delegate: OrderedRenderCommandQueueImpl, diff --git a/src/main/kotlin/com/lambda/graphics/outline/OutlineManager.kt b/src/main/kotlin/com/lambda/graphics/outline/OutlineHandler.kt similarity index 98% rename from src/main/kotlin/com/lambda/graphics/outline/OutlineManager.kt rename to src/main/kotlin/com/lambda/graphics/outline/OutlineHandler.kt index 6bd602c67..aaeced3f6 100644 --- a/src/main/kotlin/com/lambda/graphics/outline/OutlineManager.kt +++ b/src/main/kotlin/com/lambda/graphics/outline/OutlineHandler.kt @@ -19,7 +19,8 @@ package com.lambda.graphics.outline import net.minecraft.util.math.BlockPos -object OutlineManager { +@Suppress("unused") +object OutlineHandler { private val depthTestedEntityOutlines = mutableMapOf() private val xrayEntityOutlines = mutableMapOf() diff --git a/src/main/kotlin/com/lambda/graphics/outline/OutlineIdBuffer.kt b/src/main/kotlin/com/lambda/graphics/outline/OutlineIdBuffer.kt index 592f6969b..d888dabd9 100644 --- a/src/main/kotlin/com/lambda/graphics/outline/OutlineIdBuffer.kt +++ b/src/main/kotlin/com/lambda/graphics/outline/OutlineIdBuffer.kt @@ -22,8 +22,7 @@ import com.mojang.blaze3d.systems.RenderSystem import com.mojang.blaze3d.textures.GpuTexture import com.mojang.blaze3d.textures.GpuTextureView import com.mojang.blaze3d.textures.TextureFormat -import java.util.OptionalDouble -import java.util.OptionalInt +import java.util.* object OutlineIdBuffer { private var idTexture: GpuTexture? = null @@ -101,10 +100,7 @@ object OutlineIdBuffer { fun getSilhouetteDepthView(): GpuTextureView? = depthTextureView fun getTextureView(): GpuTextureView? = idTextureView - - fun getWidth(): Int = bufferWidth - fun getHeight(): Int = bufferHeight - + fun cleanup() { idTextureView?.close() idTexture?.close() diff --git a/src/main/kotlin/com/lambda/graphics/outline/OutlineIdPassRenderer.kt b/src/main/kotlin/com/lambda/graphics/outline/OutlineIdPassRenderer.kt index bf1d35e87..4fd408900 100644 --- a/src/main/kotlin/com/lambda/graphics/outline/OutlineIdPassRenderer.kt +++ b/src/main/kotlin/com/lambda/graphics/outline/OutlineIdPassRenderer.kt @@ -24,20 +24,19 @@ import com.lambda.graphics.mc.renderer.upload import com.mojang.blaze3d.buffers.GpuBuffer import com.mojang.blaze3d.systems.RenderSystem import com.mojang.blaze3d.textures.GpuTextureView -import net.minecraft.util.Identifier import net.minecraft.client.render.model.BakedQuad import net.minecraft.client.render.model.BlockModelPart import net.minecraft.client.util.math.Vector2f +import net.minecraft.util.Identifier +import net.minecraft.util.math.BlockPos import net.minecraft.util.math.Direction import net.minecraft.util.math.random.Random -import net.minecraft.util.math.BlockPos import org.joml.Matrix4f import org.joml.Vector3f import org.joml.Vector4f import org.lwjgl.system.MemoryUtil import java.nio.ByteOrder -import java.util.OptionalDouble -import java.util.OptionalInt +import java.util.* object OutlineIdPassRenderer { private val vertexSize = 28 @@ -61,7 +60,7 @@ object OutlineIdPassRenderer { val colorView = OutlineIdBuffer.getTextureView() ?: return - val outlines = if (useMcDepth) OutlineManager.getDepthTestedEntityStyles() else OutlineManager.getXrayEntityStyles() + val outlines = if (useMcDepth) OutlineHandler.getDepthTestedEntityStyles() else OutlineHandler.getXrayEntityStyles() val filteredOutlines = outlines.filter { (id, _) -> id in entityIds } if (filteredOutlines.isNotEmpty()) { diff --git a/src/main/kotlin/com/lambda/graphics/outline/OutlineRenderer.kt b/src/main/kotlin/com/lambda/graphics/outline/OutlineRenderer.kt index f7b012fa2..90ff102f7 100644 --- a/src/main/kotlin/com/lambda/graphics/outline/OutlineRenderer.kt +++ b/src/main/kotlin/com/lambda/graphics/outline/OutlineRenderer.kt @@ -30,8 +30,7 @@ import org.joml.Matrix4f import org.joml.Vector3f import org.joml.Vector4f import org.lwjgl.system.MemoryUtil -import java.util.OptionalDouble -import java.util.OptionalInt +import java.util.* object OutlineRenderer { private var silhouetteTexture: GpuTexture? = null @@ -185,11 +184,11 @@ object OutlineRenderer { private fun OutlineStyle.toKey() = StyleKey(color, thickness, glowIntensity, glowRadius, fill, fillOpacity) fun renderAllIDPasses() { - val depthTestedEntityStyles = OutlineManager.getDepthTestedEntityStyles() - val xrayEntityStyles = OutlineManager.getXrayEntityStyles() + val depthTestedEntityStyles = OutlineHandler.getDepthTestedEntityStyles() + val xrayEntityStyles = OutlineHandler.getXrayEntityStyles() - val depthTestedBlockStyles = OutlineManager.getDepthTestedBlockStyles() - val xrayBlockStyles = OutlineManager.getXrayBlockStyles() + val depthTestedBlockStyles = OutlineHandler.getDepthTestedBlockStyles() + val xrayBlockStyles = OutlineHandler.getXrayBlockStyles() val depthTestedEntityGroups = depthTestedEntityStyles.entries.groupBy({ it.value.toKey() }, { it.key }) val xrayEntityGroups = xrayEntityStyles.entries.groupBy({ it.value.toKey() }, { it.key }) @@ -225,8 +224,8 @@ object OutlineRenderer { if (OutlineIdBuffer.hasData) { val representativeStyle = when { - !depthTestedIds.isNullOrEmpty() -> OutlineManager.getEntityOutlineStyle(depthTestedIds.first()) - !xrayIds.isNullOrEmpty() -> OutlineManager.getEntityOutlineStyle(xrayIds.first()) + !depthTestedIds.isNullOrEmpty() -> OutlineHandler.getEntityOutlineStyle(depthTestedIds.first()) + !xrayIds.isNullOrEmpty() -> OutlineHandler.getEntityOutlineStyle(xrayIds.first()) !depthTestedBlocks.isNullOrEmpty() -> depthTestedBlocks.first().second !xrayBlocks.isNullOrEmpty() -> xrayBlocks.first().second else -> null @@ -238,7 +237,7 @@ object OutlineRenderer { private fun applyEdgeDetection(style: OutlineStyle = OutlineStyle.DEFAULT) { val idBufferView = OutlineIdBuffer.getTextureView() ?: return - applySobel(idBufferView, "Lambda Global Outline Sobel Pass", style) + applySobel(idBufferView, style) } private fun buildStyleMatrix(style: OutlineStyle): Matrix4f { @@ -250,7 +249,7 @@ object OutlineRenderer { return mat } - private fun applySobel(textureView: GpuTextureView, label: String, style: OutlineStyle = OutlineStyle.DEFAULT) { + private fun applySobel(textureView: GpuTextureView, style: OutlineStyle = OutlineStyle.DEFAULT) { val framebuffer = mc.framebuffer ?: return ensureFullscreenQuad() @@ -264,7 +263,7 @@ object OutlineRenderer { RenderSystem.getDevice() .createCommandEncoder() .createRenderPass( - { label }, + { "Lambda Outline Sobel Pass" }, framebuffer.colorAttachmentView, OptionalInt.empty(), null, diff --git a/src/main/kotlin/com/lambda/graphics/outline/VertexCapture.kt b/src/main/kotlin/com/lambda/graphics/outline/VertexCapture.kt index d1ed2d195..e467a4535 100644 --- a/src/main/kotlin/com/lambda/graphics/outline/VertexCapture.kt +++ b/src/main/kotlin/com/lambda/graphics/outline/VertexCapture.kt @@ -18,8 +18,8 @@ package com.lambda.graphics.outline import com.mojang.blaze3d.textures.GpuTextureView -import kotlin.collections.find +@Suppress("unused") object VertexCapture { private val entityGeometries = mutableMapOf>() diff --git a/src/main/kotlin/com/lambda/graphics/text/FontHandler.kt b/src/main/kotlin/com/lambda/graphics/text/FontHandler.kt index bad50be5e..133848156 100644 --- a/src/main/kotlin/com/lambda/graphics/text/FontHandler.kt +++ b/src/main/kotlin/com/lambda/graphics/text/FontHandler.kt @@ -17,13 +17,13 @@ package com.lambda.graphics.text -import com.lambda.Lambda.LOG -import com.lambda.config.Configurable -import com.lambda.config.configurations.FontConfig +import com.lambda.Lambda.Log +import com.lambda.config.Config +import com.lambda.config.categories.FontCategory import com.lambda.core.Loadable import com.lambda.event.events.ClientEvent import com.lambda.event.listener.SafeListener.Companion.listen -import com.lambda.util.FolderRegister +import com.lambda.util.FolderRegistry import java.util.concurrent.ConcurrentHashMap import kotlin.io.path.notExists @@ -33,8 +33,11 @@ import kotlin.io.path.notExists * Manages SDF font atlases with automatic caching by path and size. * Fonts are discovered at startup but only loaded when actually used. */ -object FontHandler : Loadable, Configurable(FontConfig) { - override val name = "Font" +@Suppress("unused") +object FontHandler : Loadable, Config( + "Font", + FontCategory +) { override val priority = -1 private val loadedAtlases = ConcurrentHashMap() @@ -74,7 +77,7 @@ object FontHandler : Loadable, Configurable(FontConfig) { fun discoverFonts() { discoveredFonts.clear() - val fontsFolder = FolderRegister.fonts + val fontsFolder = FolderRegistry.fonts if (fontsFolder.notExists()) { fontsFolder.toFile().mkdirs() @@ -106,7 +109,7 @@ object FontHandler : Loadable, Configurable(FontConfig) { discoveredFonts.sortBy { it.displayName } - LOG.info("[FontHandler] Discovered ${discoveredFonts.size} fonts") + Log.info("[FontHandler] Discovered ${discoveredFonts.size} fonts") } /** @@ -126,10 +129,10 @@ object FontHandler : Loadable, Configurable(FontConfig) { return loadedAtlases.getOrPut(key) { try { - LOG.info("[FontHandler] Loading SDF atlas for: ${fontInfo.displayName}") + Log.info("[FontHandler] Loading SDF atlas for: ${fontInfo.displayName}") SDFFontAtlas(fontInfo.path, fontInfo.userFont, fontInfo.size).apply { upload() } } catch (e: Exception) { - LOG.error("[FontHandler] Failed to load font: ${fontInfo.path} - ${e.message}") + Log.error("[FontHandler] Failed to load font: ${fontInfo.path} - ${e.message}") return null } } diff --git a/src/main/kotlin/com/lambda/graphics/text/SDFFontAtlas.kt b/src/main/kotlin/com/lambda/graphics/text/SDFFontAtlas.kt index 79948ce22..f8aa51997 100644 --- a/src/main/kotlin/com/lambda/graphics/text/SDFFontAtlas.kt +++ b/src/main/kotlin/com/lambda/graphics/text/SDFFontAtlas.kt @@ -24,6 +24,9 @@ import com.mojang.blaze3d.textures.FilterMode import com.mojang.blaze3d.textures.GpuTexture import com.mojang.blaze3d.textures.GpuTextureView import com.mojang.blaze3d.textures.TextureFormat +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking import net.minecraft.client.gl.GpuSampler import net.minecraft.client.texture.NativeImage import org.lwjgl.stb.STBTTFontinfo @@ -43,12 +46,9 @@ import org.lwjgl.stb.STBTruetype.stbtt_ScaleForPixelHeight import org.lwjgl.system.MemoryStack import org.lwjgl.system.MemoryUtil import java.nio.ByteBuffer -import kotlin.math.sqrt -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch -import kotlinx.coroutines.runBlocking import java.nio.file.Path import kotlin.io.path.readBytes +import kotlin.math.sqrt class SDFFontAtlas( fontPath: String, @@ -94,14 +94,9 @@ class SDFFontAtlas( val descent: Float val scale: Float - val sdfPixelRange: Float get() = (sdfSpread * 2).toFloat() - val textureView: GpuTextureView? get() = glTextureView - val sampler: GpuSampler? get() = gpuSampler - val isUploaded: Boolean get() = glTexture != null - init { val fontBytes = if (userFont) Path.of(fontPath).readBytes() diff --git a/src/main/kotlin/com/lambda/graphics/util/DirectionMask.kt b/src/main/kotlin/com/lambda/graphics/util/DirectionMask.kt index 2966954c1..9c55031d1 100644 --- a/src/main/kotlin/com/lambda/graphics/util/DirectionMask.kt +++ b/src/main/kotlin/com/lambda/graphics/util/DirectionMask.kt @@ -25,17 +25,17 @@ import net.minecraft.util.math.BlockPos import net.minecraft.util.math.Direction object DirectionMask { - const val EAST = 1 // X + - const val WEST = 2 // X - + const val East = 1 // X + + const val West = 2 // X - - const val UP = 4 // Y + - const val DOWN = 8 // Y - + const val Up = 4 // Y + + const val Down = 8 // Y - - const val SOUTH = 16 // Z + - const val NORTH = 32 // Z - + const val South = 16 // Z + + const val North = 32 // Z - - const val ALL = EAST or WEST or UP or DOWN or SOUTH or NORTH - const val NONE = 0 + const val All = East or West or Up or Down or South or North + const val None = 0 fun Int.include(dir: Int) = this or dir fun Int.include(direction: Direction) = include(direction.mask) @@ -47,7 +47,7 @@ object DirectionMask { buildSideMesh(position.toFastVec()) { filter(it.toBlockPos()) } fun buildSideMesh(position: FastVector, filter: (FastVector) -> Boolean): Int { - var sides = ALL + var sides = All Direction.entries .filter { filter(position.offset(it)) } @@ -58,12 +58,12 @@ object DirectionMask { val Direction.mask get() = when (this) { - Direction.DOWN -> DOWN - Direction.UP -> UP - Direction.NORTH -> NORTH - Direction.SOUTH -> SOUTH - Direction.WEST -> WEST - Direction.EAST -> EAST + Direction.DOWN -> Down + Direction.UP -> Up + Direction.NORTH -> North + Direction.SOUTH -> South + Direction.WEST -> West + Direction.EAST -> East } enum class OutlineMode(val check: (Boolean, Boolean) -> Boolean) { diff --git a/src/main/kotlin/com/lambda/gui/DearImGui.kt b/src/main/kotlin/com/lambda/gui/DearImGui.kt index 32d71dcbd..13e8bd106 100644 --- a/src/main/kotlin/com/lambda/gui/DearImGui.kt +++ b/src/main/kotlin/com/lambda/gui/DearImGui.kt @@ -22,9 +22,6 @@ import com.lambda.core.Loadable import com.lambda.event.EventFlow.post import com.lambda.event.events.GuiEvent import com.lambda.gui.components.ClickGuiLayout -import com.lambda.util.stream -import com.mojang.blaze3d.opengl.GlStateManager -import com.mojang.blaze3d.systems.RenderSystem import com.lambda.imgui.ImFontConfig import com.lambda.imgui.ImFontGlyphRangesBuilder import com.lambda.imgui.ImGui @@ -33,6 +30,9 @@ import com.lambda.imgui.extension.implot.ImPlot import com.lambda.imgui.flag.ImGuiConfigFlags import com.lambda.imgui.gl3.ImGuiImplGl3 import com.lambda.imgui.glfw.ImGuiImplGlfw +import com.lambda.util.stream +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 org.lwjgl.opengl.GL30.GL_FRAMEBUFFER @@ -42,12 +42,12 @@ object DearImGui : Loadable { val implGlfw = ImGuiImplGlfw() val implGl3 = ImGuiImplGl3() - const val EXTERNAL_LINK = '↗' - const val BREADCRUMB_SEPARATOR = '»' - const val BASE_FONT_SCALE = 13f + const val ExternalLink = '↗' + const val BreadCrumbSeparator = '»' + const val BaseFontScale = 13f val io: ImGuiIO get() = ImGui.getIO() - const val DEFAULT_FLAGS = ImGuiConfigFlags.NavEnableKeyboard or // Enable Keyboard Controls + const val DefaultFlags = ImGuiConfigFlags.NavEnableKeyboard or // Enable Keyboard Controls ImGuiConfigFlags.NavEnableSetMousePos or // Move the cursor using the keyboard ImGuiConfigFlags.DockingEnable @@ -60,11 +60,11 @@ object DearImGui : Loadable { val glyphRanges = ImFontGlyphRangesBuilder().apply { addRanges(io.fonts.glyphRangesDefault) addRanges(io.fonts.glyphRangesGreek) - addChar(EXTERNAL_LINK) - addChar(BREADCRUMB_SEPARATOR) + addChar(ExternalLink) + addChar(BreadCrumbSeparator) }.buildRanges() val fontConfig = ImFontConfig() - val size = BASE_FONT_SCALE * scale + val size = BaseFontScale * scale with(io.fonts) { clear() addFontFromMemoryTTF("fonts/FiraSans-Regular.ttf".stream.readAllBytes(), size, fontConfig, glyphRanges) @@ -78,7 +78,7 @@ object DearImGui : Loadable { fun render() { val userPercent = ClickGuiLayout.scaleSetting / 100.0 val dpi = ClickGuiLayout.deviceScaleMultiplier() - val base = ClickGuiLayout.BASE_SCALE_MULTI * dpi + val base = ClickGuiLayout.BaseScaleMulti * dpi val fontScaleSetting = ClickGuiLayout.fontScale val scale = (base * userPercent * fontScaleSetting).toFloat() @@ -136,7 +136,7 @@ object DearImGui : Loadable { ImGui.createContext() ImPlot.createContext() - io.configFlags = DEFAULT_FLAGS + io.configFlags = DefaultFlags io.iniFilename = "lambda.ini" implGlfw.init(mc.window.handle, true) diff --git a/src/main/kotlin/com/lambda/gui/MenuBar.kt b/src/main/kotlin/com/lambda/gui/MenuBar.kt index 2ff59a143..b54ab77f1 100644 --- a/src/main/kotlin/com/lambda/gui/MenuBar.kt +++ b/src/main/kotlin/com/lambda/gui/MenuBar.kt @@ -18,39 +18,39 @@ package com.lambda.gui import com.lambda.Lambda -import com.lambda.Lambda.REPO_URL +import com.lambda.Lambda.RepoUrl import com.lambda.Lambda.mc import com.lambda.command.CommandRegistry -import com.lambda.config.AutomationConfig -import com.lambda.config.Configuration -import com.lambda.config.Configuration.Companion.configurables -import com.lambda.config.UserAutomationConfig -import com.lambda.config.configurations.UserAutomationConfigs +import com.lambda.config.ConfigLoader +import com.lambda.config.ConfigLoader.configs +import com.lambda.config.automation.AutomationConfig +import com.lambda.config.automation.UserAutomationConfig +import com.lambda.config.categories.UserAutomationCategory import com.lambda.core.Loader import com.lambda.event.EventFlow import com.lambda.graphics.texture.TextureOwner.upload -import com.lambda.gui.DearImGui.EXTERNAL_LINK +import com.lambda.gui.DearImGui.ExternalLink import com.lambda.gui.components.ClickGuiLayout import com.lambda.gui.components.HudGuiLayout import com.lambda.gui.components.QuickSearch import com.lambda.gui.components.SettingsWidget.buildConfigSettingsContext import com.lambda.gui.dsl.ImGuiBuilder -import com.lambda.interaction.BaritoneManager +import com.lambda.imgui.ImGui +import com.lambda.imgui.ImGui.closeCurrentPopup +import com.lambda.imgui.flag.ImGuiCol +import com.lambda.imgui.flag.ImGuiStyleVar +import com.lambda.imgui.flag.ImGuiWindowFlags +import com.lambda.interaction.BaritoneHandler import com.lambda.module.ModuleRegistry import com.lambda.module.ModuleRegistry.moduleNameMap import com.lambda.module.tag.ModuleTag import com.lambda.network.LambdaAPI import com.lambda.threading.runSafe -import com.lambda.util.Communication.info +import com.lambda.util.CommunicationUtils.info import com.lambda.util.Diagnostics.gatherDiagnostics -import com.lambda.util.FolderRegister -import com.lambda.util.FolderRegister.minecraft +import com.lambda.util.FolderRegistry +import com.lambda.util.FolderRegistry.minecraft import com.mojang.blaze3d.platform.TextureUtil -import com.lambda.imgui.ImGui -import com.lambda.imgui.ImGui.closeCurrentPopup -import com.lambda.imgui.flag.ImGuiCol -import com.lambda.imgui.flag.ImGuiStyleVar -import com.lambda.imgui.flag.ImGuiWindowFlags import net.fabricmc.loader.api.FabricLoader import net.minecraft.client.gui.screen.DebugOptionsScreen import net.minecraft.network.packet.c2s.play.ChangeGameModeC2SPacket @@ -118,25 +118,25 @@ object MenuBar { private fun ImGuiBuilder.buildLambdaMenu() { menu("Save Config...") { menuItem("Save All Configs") { - Configuration.configurations.forEach { it.trySave(true) } - info("Saved ${Configuration.configurations.size} configuration files.") + ConfigLoader.configCategories.forEach { it.trySaveToFile(true) } + info("Saved ${ConfigLoader.configCategories.size} configuration files.") } - Configuration.configurations.forEach { config -> - menuItem("Save ${config.configName}") { - config.trySave(true) - info("Saved ${config.configName}") + ConfigLoader.configCategories.forEach { config -> + menuItem("Save ${config.name}") { + config.trySaveToFile(true) + info("Saved ${config.name}") } } } menu("Load Config...") { menuItem("Load All Configs") { - Configuration.configurations.forEach { it.tryLoad() } - info("Loaded ${Configuration.configurations.size} configuration files.") + ConfigLoader.configCategories.forEach { it.tryLoadFromFile() } + info("Loaded ${ConfigLoader.configCategories.size} configuration files.") } - Configuration.configurations.forEach { config -> - menuItem("Load ${config.configName}") { - config.tryLoad() - info("Loaded ${config.configName}") + ConfigLoader.configCategories.forEach { config -> + menuItem("Load ${config.name}") { + config.tryLoadFromFile() + info("Loaded ${config.name}") } } } @@ -152,34 +152,34 @@ object MenuBar { buildConfigSettingsContext(LambdaAPI) } menu("Baritone Settings") { - buildConfigSettingsContext(BaritoneManager) + buildConfigSettingsContext(BaritoneHandler) } } separator() menu("Open Folder") { menuItem("Open Lambda Folder") { - Util.getOperatingSystem().open(FolderRegister.lambda) + Util.getOperatingSystem().open(FolderRegistry.lambda) } menuItem("Open Config Folder") { - Util.getOperatingSystem().open(FolderRegister.config) + Util.getOperatingSystem().open(FolderRegistry.config) } menuItem("Open Packet Logs Folder") { - Util.getOperatingSystem().open(FolderRegister.packetLogs) + Util.getOperatingSystem().open(FolderRegistry.packetLogs) } menuItem("Open Replay Folder") { - Util.getOperatingSystem().open(FolderRegister.replay) + Util.getOperatingSystem().open(FolderRegistry.replay) } menuItem("Open Cache Folder") { - Util.getOperatingSystem().open(FolderRegister.cache) + Util.getOperatingSystem().open(FolderRegistry.cache) } menuItem("Open Capes Folder") { - Util.getOperatingSystem().open(FolderRegister.capes) + Util.getOperatingSystem().open(FolderRegistry.capes) } menuItem("Open Structures Folder") { - Util.getOperatingSystem().open(FolderRegister.structure) + Util.getOperatingSystem().open(FolderRegistry.structure) } menuItem("Open Maps Folder") { - Util.getOperatingSystem().open(FolderRegister.maps) + Util.getOperatingSystem().open(FolderRegistry.maps) } } separator() @@ -290,7 +290,7 @@ object MenuBar { popupContextWindow("##new-config") { inputText("Name", ::newConfigName) button("Create") { - if (newConfigName.isEmpty() && configurables.none { it.name == newConfigName }) return@button + if (newConfigName.isEmpty() && configs.none { it.name == newConfigName }) return@button UserAutomationConfig(newConfigName) newConfigName = "" closeCurrentPopup() @@ -303,11 +303,11 @@ object MenuBar { } } - UserAutomationConfigs.configurables.forEach { config -> - if (config !is UserAutomationConfig) throw java.lang.IllegalStateException("All configurables within UserAutomationConfigs must be UserAutomationConfigs!") + UserAutomationCategory.configs.forEach { config -> + if (config !is UserAutomationConfig) throw IllegalStateException("All configs within UserAutomationConfigs must be UserAutomationConfigs!") buildAutomationConfigSelectable(config) } - buildAutomationConfigSelectable(AutomationConfig.Companion.DEFAULT) + buildAutomationConfigSelectable(AutomationConfig.Default) } private fun ImGuiBuilder.buildAutomationConfigSelectable(config: AutomationConfig) { @@ -321,7 +321,7 @@ object MenuBar { module.automationConfig = module.defaultAutomationConfig } } - UserAutomationConfigs.configurables.remove(config) + UserAutomationCategory.configs.remove(config) } separator() } @@ -444,19 +444,19 @@ object MenuBar { menuItem("Quick Search...", "Shift+Shift") { QuickSearch.open() } - menuItem("Documentation $EXTERNAL_LINK") { - Util.getOperatingSystem().open("$REPO_URL/wiki") + menuItem("Documentation $ExternalLink") { + Util.getOperatingSystem().open("$RepoUrl/wiki") } - menuItem("Report Issue $EXTERNAL_LINK") { + menuItem("Report Issue $ExternalLink") { mc.keyboard.clipboard = gatherDiagnostics() info("Copied diagnostics to clipboard. Please paste it in a new issue on GitHub and click “Submit new issue”. Thank you!") - Util.getOperatingSystem().open("$REPO_URL/issues") + Util.getOperatingSystem().open("$RepoUrl/issues") } - menuItem("Check for Updates $EXTERNAL_LINK") { + menuItem("Check for Updates $ExternalLink") { // ToDo: // - Check for a newer version, show availability & changelog, and allow opening release page. // - Needs UpdateManager - Util.getOperatingSystem().open("$REPO_URL/releases") + Util.getOperatingSystem().open("$RepoUrl/releases") } } @@ -464,13 +464,17 @@ object MenuBar { popupModal("About Lambda", ImGuiWindowFlags.AlwaysAutoResize or ImGuiWindowFlags.NoTitleBar) { imageHorizontallyCentered(headerLogo.id.toLong(), 553f, 200f) group { - text("Version: ${Lambda.VERSION}") + text("Version: ${Lambda.Version}") if (Lambda.isDebug) text("Development Environment") text("Runtime: ${Loader.runtime}") text("Modules: ${ModuleRegistry.modules.size}") text("Commands: ${CommandRegistry.commands.size}") - val totalSettings = Configuration.configurations.sumOf { cfg -> - cfg.configurables.sumOf { it.settings.size } + val totalSettings = ConfigLoader.configCategories.sumOf { cfg -> + cfg.configs.sumOf { + var count = 0 + it.forEachSetting { _, _ -> count++ } + count + } } text("Settings: $totalSettings") text("Synchronous listeners: ${EventFlow.syncListeners.size}") @@ -496,8 +500,8 @@ object MenuBar { ImGui.setClipboardText(gatherDiagnostics()) } sameLine() - button("View License $EXTERNAL_LINK") { - Util.getOperatingSystem().open("$REPO_URL/blob/master/LICENSE.md") + button("View License $ExternalLink") { + Util.getOperatingSystem().open("$RepoUrl/blob/master/LICENSE.md") } sameLine() button("Close") { @@ -521,9 +525,9 @@ object MenuBar { withStyleColor(ImGuiCol.ButtonHovered, 0x22FFFFFF) { withStyleColor(ImGuiCol.ButtonActive, 0x44FFFFFF) { val clicked = ImGui.imageButton("##github", githubLogo.id.toLong(), iconSize, iconSize) - lambdaTooltip("Open GitHub Repository $EXTERNAL_LINK") + lambdaTooltip("Open GitHub Repository $ExternalLink") if (clicked) { - Util.getOperatingSystem().open(REPO_URL) + Util.getOperatingSystem().open(RepoUrl) } } } diff --git a/src/main/kotlin/com/lambda/gui/components/ClickGuiLayout.kt b/src/main/kotlin/com/lambda/gui/components/ClickGuiLayout.kt index 342f5c58b..33831aae8 100644 --- a/src/main/kotlin/com/lambda/gui/components/ClickGuiLayout.kt +++ b/src/main/kotlin/com/lambda/gui/components/ClickGuiLayout.kt @@ -18,8 +18,9 @@ package com.lambda.gui.components import com.lambda.Lambda.mc -import com.lambda.config.Configurable -import com.lambda.config.configurations.GuiConfig +import com.lambda.config.Config +import com.lambda.config.Tab +import com.lambda.config.categories.GuiCategory import com.lambda.config.settings.complex.KeybindSetting.Companion.onPress import com.lambda.core.Loadable import com.lambda.event.events.GuiEvent @@ -31,26 +32,26 @@ import com.lambda.gui.MenuBar.buildMenuBar import com.lambda.gui.components.QuickSearch.renderQuickSearch import com.lambda.gui.dsl.ImGuiBuilder.buildLayout import com.lambda.gui.snap.RectF -import com.lambda.gui.snap.SnapManager -import com.lambda.gui.snap.SnapManager.drawDragGrid -import com.lambda.gui.snap.SnapManager.drawSnapLines -import com.lambda.gui.snap.SnapManager.updateDragAndSnapping +import com.lambda.gui.snap.SnapHandler +import com.lambda.gui.snap.SnapHandler.drawDragGrid +import com.lambda.gui.snap.SnapHandler.drawSnapLines +import com.lambda.gui.snap.SnapHandler.updateDragAndSnapping +import com.lambda.imgui.ImGui +import com.lambda.imgui.extension.implot.ImPlot +import com.lambda.imgui.flag.ImGuiCol +import com.lambda.imgui.flag.ImGuiCond +import com.lambda.imgui.flag.ImGuiHoveredFlags +import com.lambda.imgui.flag.ImGuiWindowFlags import com.lambda.module.ModuleRegistry import com.lambda.module.modules.client.Client import com.lambda.module.tag.ModuleTag import com.lambda.module.tag.ModuleTag.Companion.shownTags import com.lambda.sound.LambdaSound -import com.lambda.sound.SoundManager.play +import com.lambda.sound.SoundHandler.play import com.lambda.util.Describable import com.lambda.util.KeyCode import com.lambda.util.NamedEnum import com.lambda.util.WindowUtils.setLambdaWindowIcon -import com.lambda.imgui.ImGui -import com.lambda.imgui.extension.implot.ImPlot -import com.lambda.imgui.flag.ImGuiCol -import com.lambda.imgui.flag.ImGuiCond -import com.lambda.imgui.flag.ImGuiHoveredFlags -import com.lambda.imgui.flag.ImGuiWindowFlags import net.minecraft.SharedConstants import net.minecraft.client.gui.screen.ChatScreen import net.minecraft.client.gui.screen.Screen @@ -60,8 +61,11 @@ import net.minecraft.client.gui.screen.ingame.SignEditScreen import net.minecraft.client.util.Icons import java.awt.Color -object ClickGuiLayout : Loadable, Configurable(GuiConfig) { - override val name = "GUI" +@Suppress("unused") +object ClickGuiLayout : Loadable, Config( + "GUI", + GuiCategory +) { var open = false var developerMode = false val keybind by setting("Keybind", KeyCode.Y, screenCheck = false) @@ -79,16 +83,14 @@ object ClickGuiLayout : Loadable, Configurable(GuiConfig) { private var dragOffsetY = 0f private val lastBounds = mutableMapOf() private val pendingPositions = mutableMapOf>() - private val snapOverlays = mutableMapOf() - - private enum class Group(override val displayName: String) : NamedEnum { - General("General"), - Snapping("Snapping"), - Sizing("Sizing"), - Rounding("Rounding"), - Colors("Colors"), - Font("Font") - } + private val snapOverlays = mutableMapOf() + + private const val GeneralTab = "General" + private const val SnappingTab = "Snapping" + private const val SizingTab = "Sizing" + private const val RoundingTab = "Rounding" + private const val ColorsTab = "Colors" + private const val FontTab = "Font" @Suppress("unused") enum class TooltipType( @@ -102,8 +104,8 @@ object ClickGuiLayout : Loadable, Configurable(GuiConfig) { LongDelay("Long Delay", "Show tooltip after a longer delay (~0.40s), and only after the mouse has been still briefly on the item.", ImGuiHoveredFlags.DelayNormal) } - const val BASE_SCALE = 100 - const val BASE_SCALE_MULTI = 1.8 + const val BaseScale = 100 + const val BaseScaleMulti = 1.8 fun deviceScaleMultiplier() = try { val monitorWidth = mc.window.monitor!!.currentVideoMode!!.width.toDouble() @@ -113,11 +115,11 @@ object ClickGuiLayout : Loadable, Configurable(GuiConfig) { } // General - internal val scaleSetting by setting("Scale", BASE_SCALE, 50..300, 1, unit = "%").group(Group.General) - val alpha by setting("Alpha", 1.0f, 0.0f..1.0f, 0.01f).group(Group.General) - val disabledAlpha by setting("Disabled Alpha", 0.6f, 0.0f..1.0f, 0.01f).group(Group.General) - val tooltipType by setting("Tooltip Type", TooltipType.Stationary, description = "When to show the tooltip.").group(Group.General) - val setLambdaWindowIcon by setting("Set Lambda Window Icon", true).group(Group.General).onValueChange { _, to -> + @Tab(GeneralTab) internal val scaleSetting by setting("Scale", BaseScale, 50..300, 1, unit = "%") + @Tab(GeneralTab) val alpha by setting("Alpha", 1.0f, 0.0f..1.0f, 0.01f) + @Tab(GeneralTab) val disabledAlpha by setting("Disabled Alpha", 0.6f, 0.0f..1.0f, 0.01f) + @Tab(GeneralTab) val tooltipType by setting("Tooltip Type", TooltipType.Stationary, description = "When to show the tooltip.") + @Tab(GeneralTab) val setLambdaWindowIcon by setting("Set Lambda Window Icon", true).onValueChange { _, to -> if (to) { setLambdaWindowIcon() } else { @@ -126,122 +128,121 @@ object ClickGuiLayout : Loadable, Configurable(GuiConfig) { } } @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) + @Tab(GeneralTab) val setLambdaWindowTitle by setting("Set Lambda Window Title", true).onValueChange { _, _ -> mc.updateWindowTitle() } + @Tab(GeneralTab) val lambdaTitleAppendixName by setting("Append Username", true) { setLambdaWindowTitle }.onValueChange { _, _ -> mc.updateWindowTitle() } + @Tab(GeneralTab) val backgroundBlur by setting("Background Blur", true) + @Tab(GeneralTab) val backgroundDarkening by setting("Background Darkening", true) // Snapping - val snapEnabled by setting("Enable Snapping", true, "Master toggle for GUI/HUD snapping").group(Group.Snapping) - val gridSize by setting("Grid Size", 25f, 2f..128f, 1f, "Grid step in pixels") { snapEnabled }.group(Group.Snapping) - val snapToEdges by setting("Snap To Element Edges", true) { snapEnabled }.group(Group.Snapping) - val snapToCenters by setting("Snap To Element Centers", true) { snapEnabled }.group(Group.Snapping) - val snapToScreenCenter by setting("Snap To Screen Center", true) { snapEnabled }.group(Group.Snapping) - val snapToGrid by setting("Snap To Grid", true) { snapEnabled }.group(Group.Snapping) - val snapDistanceElement by setting("Snap Distance (Elements)", 20f, 1f..48f, 1f, "Distance threshold in px") { snapEnabled }.group(Group.Snapping) - val snapDistanceScreen by setting("Snap Distance (Screen Center)", 14f, 1f..48f, 1f) { snapEnabled }.group(Group.Snapping) - val snapDistanceGrid by setting("Snap Distance (Grid)", 12f, 1f..48f, 1f) { snapEnabled }.group(Group.Snapping) - val snapLineColor by setting("Snap Line Color", Color(255, 160, 0, 220)) { snapEnabled }.group(Group.Snapping) + @Tab(SnappingTab) val snapEnabled by setting("Enable Snapping", true, "Master toggle for GUI/HUD snapping") + @Tab(SnappingTab) val gridSize by setting("Grid Size", 25f, 2f..128f, 1f, "Grid step in pixels") { snapEnabled } + @Tab(SnappingTab) val snapToEdges by setting("Snap To Element Edges", true) { snapEnabled } + @Tab(SnappingTab) val snapToCenters by setting("Snap To Element Centers", true) { snapEnabled } + @Tab(SnappingTab) val snapToScreenCenter by setting("Snap To Screen Center", true) { snapEnabled } + @Tab(SnappingTab) val snapToGrid by setting("Snap To Grid", true) { snapEnabled } + @Tab(SnappingTab) val snapDistanceElement by setting("Snap Distance (Elements)", 20f, 1f..48f, 1f, "Distance threshold in px") { snapEnabled } + @Tab(SnappingTab) val snapDistanceScreen by setting("Snap Distance (Screen Center)", 14f, 1f..48f, 1f) { snapEnabled } + @Tab(SnappingTab) val snapDistanceGrid by setting("Snap Distance (Grid)", 12f, 1f..48f, 1f) { snapEnabled } + @Tab(SnappingTab) val snapLineColor by setting("Snap Line Color", Color(255, 160, 0, 220)) { snapEnabled } // Sizing - val windowPaddingX by setting("Window Padding X", 8.0f, 0.0f..20.0f, 0.1f).group(Group.Sizing) - val windowPaddingY by setting("Window Padding Y", 8.0f, 0.0f..20.0f, 0.1f).group(Group.Sizing) - val windowMinSizeX by setting("Window Min Size X", 32.0f, 0.0f..100.0f, 1.0f).group(Group.Sizing) - val windowMinSizeY by setting("Window Min Size Y", 32.0f, 0.0f..100.0f, 1.0f).group(Group.Sizing) - val windowTitleAlignX by setting("Window Title Align X", 0.0f, 0.0f..1.0f, 0.01f).group(Group.Sizing) - val windowTitleAlignY by setting("Window Title Align Y", 0.5f, 0.0f..1.0f, 0.01f).group(Group.Sizing) - val framePaddingX by setting("Frame Padding X", 4.0f, 0.0f..20.0f, 0.1f).group(Group.Sizing) - val framePaddingY by setting("Frame Padding Y", 3.0f, 0.0f..20.0f, 0.1f).group(Group.Sizing) - val itemSpacingX by setting("Item Spacing X", 8.0f, 0.0f..20.0f, 0.1f).group(Group.Sizing) - val itemSpacingY by setting("Item Spacing Y", 4.0f, 0.0f..20.0f, 0.1f).group(Group.Sizing) - val itemInnerSpacingX by setting("Item Inner Spacing X", 4.0f, 0.0f..20.0f, 0.1f).group(Group.Sizing) - val itemInnerSpacingY by setting("Item Inner Spacing Y", 4.0f, 0.0f..20.0f, 0.1f).group(Group.Sizing) - val indentSpacing by setting("Indent Spacing", 21.0f, 0.0f..50.0f, 0.1f).group(Group.Sizing) - val scrollbarSize by setting("Scrollbar Size", 8.4f, 0.0f..30.0f, 0.1f).group(Group.Sizing) - val grabMinSize by setting("Grab Min Size", 10.0f, 0.0f..30.0f, 0.1f).group(Group.Sizing) - val windowBorderSize by setting("Window Border Size", 1.0f, 0.0f..5.0f, 0.1f).group(Group.Sizing) - val childBorderSize by setting("Child Border Size", 1.0f, 0.0f..5.0f, 0.1f).group(Group.Sizing) - val popupBorderSize by setting("Popup Border Size", 1.0f, 0.0f..5.0f, 0.1f).group(Group.Sizing) - val frameBorderSize by setting("Frame Border Size", 0.0f, 0.0f..5.0f, 0.1f).group(Group.Sizing) - val tabBorderSize by setting("Tab Border Size", 0.0f, 0.0f..5.0f, 0.1f).group(Group.Sizing) + @Tab(SizingTab) val windowPaddingX by setting("Window Padding X", 8.0f, 0.0f..20.0f, 0.1f) + @Tab(SizingTab) val windowPaddingY by setting("Window Padding Y", 8.0f, 0.0f..20.0f, 0.1f) + @Tab(SizingTab) val windowMinSizeX by setting("Window Min Size X", 32.0f, 0.0f..100.0f, 1.0f) + @Tab(SizingTab) val windowMinSizeY by setting("Window Min Size Y", 32.0f, 0.0f..100.0f, 1.0f) + @Tab(SizingTab) val windowTitleAlignX by setting("Window Title Align X", 0.0f, 0.0f..1.0f, 0.01f) + @Tab(SizingTab) val windowTitleAlignY by setting("Window Title Align Y", 0.5f, 0.0f..1.0f, 0.01f) + @Tab(SizingTab) val framePaddingX by setting("Frame Padding X", 4.0f, 0.0f..20.0f, 0.1f) + @Tab(SizingTab) val framePaddingY by setting("Frame Padding Y", 3.0f, 0.0f..20.0f, 0.1f) + @Tab(SizingTab) val itemSpacingX by setting("Item Spacing X", 8.0f, 0.0f..20.0f, 0.1f) + @Tab(SizingTab) val itemSpacingY by setting("Item Spacing Y", 4.0f, 0.0f..20.0f, 0.1f) + @Tab(SizingTab) val itemInnerSpacingX by setting("Item Inner Spacing X", 4.0f, 0.0f..20.0f, 0.1f) + @Tab(SizingTab) val itemInnerSpacingY by setting("Item Inner Spacing Y", 4.0f, 0.0f..20.0f, 0.1f) + @Tab(SizingTab) val indentSpacing by setting("Indent Spacing", 21.0f, 0.0f..50.0f, 0.1f) + @Tab(SizingTab) val scrollbarSize by setting("Scrollbar Size", 8.4f, 0.0f..30.0f, 0.1f) + @Tab(SizingTab) val grabMinSize by setting("Grab Min Size", 10.0f, 0.0f..30.0f, 0.1f) + @Tab(SizingTab) val windowBorderSize by setting("Window Border Size", 1.0f, 0.0f..5.0f, 0.1f) + @Tab(SizingTab) val childBorderSize by setting("Child Border Size", 1.0f, 0.0f..5.0f, 0.1f) + @Tab(SizingTab) val popupBorderSize by setting("Popup Border Size", 1.0f, 0.0f..5.0f, 0.1f) + @Tab(SizingTab) val frameBorderSize by setting("Frame Border Size", 0.0f, 0.0f..5.0f, 0.1f) + @Tab(SizingTab) val tabBorderSize by setting("Tab Border Size", 0.0f, 0.0f..5.0f, 0.1f) // Rounding - val windowRounding by setting("Window Rounding", 4.6f, 0.0f..12.0f, 0.1f).group(Group.Rounding) - val childRounding by setting("Child Rounding", 0.0f, 0.0f..12.0f, 0.1f).group(Group.Rounding) - val frameRounding by setting("Frame Rounding", 4.6f, 0.0f..12.0f, 0.1f).group(Group.Rounding) - val popupRounding by setting("Popup Rounding", 4.6f, 0.0f..12.0f, 0.1f).group(Group.Rounding) - val scrollbarRounding by setting("Scrollbar Rounding", 9.0f, 0.0f..12.0f, 0.1f).group(Group.Rounding) - val grabRounding by setting("Grab Rounding", 4.6f, 0.0f..12.0f, 0.1f).group(Group.Rounding) - val tabRounding by setting("Tab Rounding", 4.6f, 0.0f..12.0f, 0.1f).group(Group.Rounding) - val curveTessellationTol by setting("Curve Tessellation Tol", 1.25f, 0.1f..10.0f, 0.05f).group(Group.Rounding) + @Tab(RoundingTab) val windowRounding by setting("Window Rounding", 4.6f, 0.0f..12.0f, 0.1f) + @Tab(RoundingTab) val childRounding by setting("Child Rounding", 0.0f, 0.0f..12.0f, 0.1f) + @Tab(RoundingTab) val frameRounding by setting("Frame Rounding", 4.6f, 0.0f..12.0f, 0.1f) + @Tab(RoundingTab) val popupRounding by setting("Popup Rounding", 4.6f, 0.0f..12.0f, 0.1f) + @Tab(RoundingTab) val scrollbarRounding by setting("Scrollbar Rounding", 9.0f, 0.0f..12.0f, 0.1f) + @Tab(RoundingTab) val grabRounding by setting("Grab Rounding", 4.6f, 0.0f..12.0f, 0.1f) + @Tab(RoundingTab) val tabRounding by setting("Tab Rounding", 4.6f, 0.0f..12.0f, 0.1f) + @Tab(RoundingTab) val curveTessellationTol by setting("Curve Tessellation Tol", 1.25f, 0.1f..10.0f, 0.05f) // Font - val fontScale by setting("Font Scale", 1.0, 0.5..2.0, 0.1).group(Group.Font) + @Tab(FontTab) val fontScale by setting("Font Scale", 1.0, 0.5..2.0, 0.1) // Colors - val primaryColor by setting("Primary Color", Color(130, 200, 255)).group(Group.Colors) - val secondaryColor by setting("Secondary Color", Color(225, 130, 225)).group(Group.Colors) - - @Suppress("unused") - val shade by setting("Shade", true).group(Group.Colors) - val colorWidth by setting("Shade Width", 200.0, 10.0..1000.0, 10.0).group(Group.Colors) - val colorHeight by setting("Shade Height", 200.0, 10.0..1000.0, 10.0).group(Group.Colors) - val colorSpeed by setting("Color Speed", 1.0, 0.1..5.0, 0.1).group(Group.Colors) - val text by setting("Text", Color(255, 255, 255, 255)).group(Group.Colors) - val textDisabled by setting("Text Disabled", Color(128, 128, 128, 255)).group(Group.Colors) - val windowBg by setting("Window Background", Color(35, 0, 14, 240)).group(Group.Colors) - val childBg by setting("Child Background", Color(35, 0, 14, 240)).group(Group.Colors) - val popupBg by setting("Popup Background", Color(35, 0, 14, 240)).group(Group.Colors) - val border by setting("Border", Color(130, 12, 60, 240)).group(Group.Colors) - val borderShadow by setting("Border Shadow", Color(51, 0, 21, 240)).group(Group.Colors) - val frameBg by setting("Frame Background", Color(171, 32, 93, 102)).group(Group.Colors) - val frameBgHovered by setting("Frame Background Hovered", Color(214, 45, 119, 102)).group(Group.Colors) - val frameBgActive by setting("Frame Background Active", Color(255, 50, 140, 102)).group(Group.Colors) - val titleBg by setting("Title Background", Color(125, 0, 50, 240)).group(Group.Colors) - val titleBgActive by setting("Title Background Active", Color(162, 0, 68, 240)).group(Group.Colors) - val titleBgCollapsed by setting("Title Background Collapsed", Color(35, 0, 14, 240)).group(Group.Colors) - val menuBarBg by setting("MenuBar Background", Color(35, 0, 14, 240)).group(Group.Colors) - val scrollbarBg by setting("Scrollbar Background", Color(35, 0, 14, 240)).group(Group.Colors) - val scrollbarGrab by setting("Scrollbar Grab", Color(159, 30, 83, 240)).group(Group.Colors) - val scrollbarGrabHovered by setting("Scrollbar Grab Hovered", Color(198, 40, 105, 240)).group(Group.Colors) - val scrollbarGrabActive by setting("Scrollbar Grab Active", Color(235, 49, 126, 240)).group(Group.Colors) - val checkMark by setting("Check Mark", Color(255, 64, 148, 220)).group(Group.Colors) - val sliderGrab by setting("Slider Grab", Color(207, 46, 117, 200)).group(Group.Colors) - val sliderGrabActive by setting("Slider Grab Active", Color(241, 67, 143, 200)).group(Group.Colors) - val button by setting("Button", Color(171, 32, 93, 102)).group(Group.Colors) - val buttonHovered by setting("Button Hovered", Color(214, 45, 119, 102)).group(Group.Colors) - val buttonActive by setting("Button Active", Color(255, 50, 140, 102)).group(Group.Colors) - val header by setting("Header", Color(192, 30, 94, 115)).group(Group.Colors) - val headerHovered by setting("Header Hovered", Color(255, 59, 136, 115)).group(Group.Colors) - val headerActive by setting("Header Active", Color(202, 36, 101, 115)).group(Group.Colors) - val separator by setting("Separator", Color(107, 0, 47, 128)).group(Group.Colors) - val separatorHovered by setting("Separator Hovered", Color(146, 0, 64, 128)).group(Group.Colors) - val separatorActive by setting("Separator Active", Color(186, 0, 82, 128)).group(Group.Colors) - val resizeGrip by setting("Resize Grip", Color(214, 45, 119, 102)).group(Group.Colors) - val resizeGripHovered by setting("Resize Grip Hovered", Color(214, 45, 119, 102)).group(Group.Colors) - val resizeGripActive by setting("Resize Grip Active", Color(214, 45, 119, 102)).group(Group.Colors) - val tab by setting("Tab", Color(121, 21, 65, 140)).group(Group.Colors) - val tabHovered by setting("Tab Hovered", Color(169, 34, 94, 140)).group(Group.Colors) - val tabActive by setting("Tab Active", Color(209, 34, 112, 140)).group(Group.Colors) - val tabUnfocused by setting("Tab Unfocused", Color(121, 21, 65, 120)).group(Group.Colors) - val tabUnfocusedActive by setting("Tab Unfocused Active", Color(196, 36, 107, 120)).group(Group.Colors) - val dockingPreview by setting("Docking Preview", Color(208, 47, 117, 102)).group(Group.Colors) - val dockingEmptyBg by setting("Docking Empty Background", Color(35, 0, 14, 240)).group(Group.Colors) - val plotLines by setting("Plot Lines", Color(178, 36, 95, 240)).group(Group.Colors) - val plotLinesHovered by setting("Plot Lines Hovered", Color(209, 40, 110, 240)).group(Group.Colors) - val plotHistogram by setting("Plot Histogram", Color(192, 32, 91, 255)).group(Group.Colors) - val plotHistogramHovered by setting("Plot Histogram Hovered", Color(226, 38, 108, 255)).group(Group.Colors) - val tableHeaderBg by setting("Table Header Background", Color(75, 0, 31, 240)).group(Group.Colors) - val tableBorderStrong by setting("Table Border Strong", Color(88, 0, 36, 240)).group(Group.Colors) - val tableBorderLight by setting("Table Border Light", Color(67, 0, 28, 240)).group(Group.Colors) - val tableRowBg by setting("Table Row Background", Color(35, 0, 14, 240)).group(Group.Colors) - val tableRowBgAlt by setting("Table Row Background Alt", Color(242, 140, 182, 240)).group(Group.Colors) - val textSelectedBg by setting("Text Selected Background", Color(218, 54, 121, 240)).group(Group.Colors) - val dragDropTarget by setting("Drag Drop Target", Color(218, 54, 121, 240)).group(Group.Colors) - val navHighlight by setting("Nav Highlight", Color(218, 54, 121, 240)).group(Group.Colors) - val navWindowingHighlight by setting("Nav Windowing Highlight", Color(242, 140, 182, 240)).group(Group.Colors) - val navWindowingDimBg by setting("Nav Windowing Dim Background", Color(242, 140, 182, 240)).group(Group.Colors) - val modalWindowDimBg by setting("Modal Window Dim Background", Color(35, 0, 14, 90)).group(Group.Colors) + @Tab(ColorsTab) val primaryColor by setting("Primary Color", Color(130, 200, 255)) + @Tab(ColorsTab) val secondaryColor by setting("Secondary Color", Color(225, 130, 225)) + + @Tab(ColorsTab) val shade by setting("Shade", true) + @Tab(ColorsTab) val colorWidth by setting("Shade Width", 200.0, 10.0..1000.0, 10.0) + @Tab(ColorsTab) val colorHeight by setting("Shade Height", 200.0, 10.0..1000.0, 10.0) + @Tab(ColorsTab) val colorSpeed by setting("Color Speed", 1.0, 0.1..5.0, 0.1) + @Tab(ColorsTab) val text by setting("Text", Color(255, 255, 255, 255)) + @Tab(ColorsTab) val textDisabled by setting("Text Disabled", Color(128, 128, 128, 255)) + @Tab(ColorsTab) val windowBg by setting("Window Background", Color(35, 0, 14, 240)) + @Tab(ColorsTab) val childBg by setting("Child Background", Color(35, 0, 14, 240)) + @Tab(ColorsTab) val popupBg by setting("Popup Background", Color(35, 0, 14, 240)) + @Tab(ColorsTab) val border by setting("Border", Color(130, 12, 60, 240)) + @Tab(ColorsTab) val borderShadow by setting("Border Shadow", Color(51, 0, 21, 240)) + @Tab(ColorsTab) val frameBg by setting("Frame Background", Color(171, 32, 93, 102)) + @Tab(ColorsTab) val frameBgHovered by setting("Frame Background Hovered", Color(214, 45, 119, 102)) + @Tab(ColorsTab) val frameBgActive by setting("Frame Background Active", Color(255, 50, 140, 102)) + @Tab(ColorsTab) val titleBg by setting("Title Background", Color(125, 0, 50, 240)) + @Tab(ColorsTab) val titleBgActive by setting("Title Background Active", Color(162, 0, 68, 240)) + @Tab(ColorsTab) val titleBgCollapsed by setting("Title Background Collapsed", Color(35, 0, 14, 240)) + @Tab(ColorsTab) val menuBarBg by setting("MenuBar Background", Color(35, 0, 14, 240)) + @Tab(ColorsTab) val scrollbarBg by setting("Scrollbar Background", Color(35, 0, 14, 240)) + @Tab(ColorsTab) val scrollbarGrab by setting("Scrollbar Grab", Color(159, 30, 83, 240)) + @Tab(ColorsTab) val scrollbarGrabHovered by setting("Scrollbar Grab Hovered", Color(198, 40, 105, 240)) + @Tab(ColorsTab) val scrollbarGrabActive by setting("Scrollbar Grab Active", Color(235, 49, 126, 240)) + @Tab(ColorsTab) val checkMark by setting("Check Mark", Color(255, 64, 148, 220)) + @Tab(ColorsTab) val sliderGrab by setting("Slider Grab", Color(207, 46, 117, 200)) + @Tab(ColorsTab) val sliderGrabActive by setting("Slider Grab Active", Color(241, 67, 143, 200)) + @Tab(ColorsTab) val button by setting("Button", Color(171, 32, 93, 102)) + @Tab(ColorsTab) val buttonHovered by setting("Button Hovered", Color(214, 45, 119, 102)) + @Tab(ColorsTab) val buttonActive by setting("Button Active", Color(255, 50, 140, 102)) + @Tab(ColorsTab) val header by setting("Header", Color(192, 30, 94, 115)) + @Tab(ColorsTab) val headerHovered by setting("Header Hovered", Color(255, 59, 136, 115)) + @Tab(ColorsTab) val headerActive by setting("Header Active", Color(202, 36, 101, 115)) + @Tab(ColorsTab) val separator by setting("Separator", Color(107, 0, 47, 128)) + @Tab(ColorsTab) val separatorHovered by setting("Separator Hovered", Color(146, 0, 64, 128)) + @Tab(ColorsTab) val separatorActive by setting("Separator Active", Color(186, 0, 82, 128)) + @Tab(ColorsTab) val resizeGrip by setting("Resize Grip", Color(214, 45, 119, 102)) + @Tab(ColorsTab) val resizeGripHovered by setting("Resize Grip Hovered", Color(214, 45, 119, 102)) + @Tab(ColorsTab) val resizeGripActive by setting("Resize Grip Active", Color(214, 45, 119, 102)) + @Tab(ColorsTab) val tab by setting("Tab", Color(121, 21, 65, 140)) + @Tab(ColorsTab) val tabHovered by setting("Tab Hovered", Color(169, 34, 94, 140)) + @Tab(ColorsTab) val tabActive by setting("Tab Active", Color(209, 34, 112, 140)) + @Tab(ColorsTab) val tabUnfocused by setting("Tab Unfocused", Color(121, 21, 65, 120)) + @Tab(ColorsTab) val tabUnfocusedActive by setting("Tab Unfocused Active", Color(196, 36, 107, 120)) + @Tab(ColorsTab) val dockingPreview by setting("Docking Preview", Color(208, 47, 117, 102)) + @Tab(ColorsTab) val dockingEmptyBg by setting("Docking Empty Background", Color(35, 0, 14, 240)) + @Tab(ColorsTab) val plotLines by setting("Plot Lines", Color(178, 36, 95, 240)) + @Tab(ColorsTab) val plotLinesHovered by setting("Plot Lines Hovered", Color(209, 40, 110, 240)) + @Tab(ColorsTab) val plotHistogram by setting("Plot Histogram", Color(192, 32, 91, 255)) + @Tab(ColorsTab) val plotHistogramHovered by setting("Plot Histogram Hovered", Color(226, 38, 108, 255)) + @Tab(ColorsTab) val tableHeaderBg by setting("Table Header Background", Color(75, 0, 31, 240)) + @Tab(ColorsTab) val tableBorderStrong by setting("Table Border Strong", Color(88, 0, 36, 240)) + @Tab(ColorsTab) val tableBorderLight by setting("Table Border Light", Color(67, 0, 28, 240)) + @Tab(ColorsTab) val tableRowBg by setting("Table Row Background", Color(35, 0, 14, 240)) + @Tab(ColorsTab) val tableRowBgAlt by setting("Table Row Background Alt", Color(242, 140, 182, 240)) + @Tab(ColorsTab) val textSelectedBg by setting("Text Selected Background", Color(218, 54, 121, 240)) + @Tab(ColorsTab) val dragDropTarget by setting("Drag Drop Target", Color(218, 54, 121, 240)) + @Tab(ColorsTab) val navHighlight by setting("Nav Highlight", Color(218, 54, 121, 240)) + @Tab(ColorsTab) val navWindowingHighlight by setting("Nav Windowing Highlight", Color(242, 140, 182, 240)) + @Tab(ColorsTab) val navWindowingDimBg by setting("Nav Windowing Dim Background", Color(242, 140, 182, 240)) + @Tab(ColorsTab) val modalWindowDimBg by setting("Modal Window Dim Background", Color(35, 0, 14, 90)) init { listen { @@ -250,7 +251,7 @@ object ClickGuiLayout : Loadable, Configurable(GuiConfig) { buildLayout { buildMenuBar() val vp = ImGui.getMainViewport() - SnapManager.beginFrame(vp.sizeX, vp.sizeY, io.fontGlobalScale) + SnapHandler.beginFrame(vp.sizeX, vp.sizeY, io.fontGlobalScale) val mouseDown = io.mouseDown[0] val mousePressedThisFrame = mouseDown && !mouseWasDown @@ -280,7 +281,7 @@ object ClickGuiLayout : Loadable, Configurable(GuiConfig) { } } - val tags = if (developerMode) shownTags + ModuleTag.DEBUG else shownTags + val tags = if (developerMode) shownTags + ModuleTag.Debug else shownTags if (tags.isEmpty()) return@buildLayout var nextX = 20f @@ -330,7 +331,7 @@ object ClickGuiLayout : Loadable, Configurable(GuiConfig) { } val rect = RectF(windowPos.x, windowPos.y, windowSize.x, windowSize.y) - SnapManager.registerElement(tag.name, rect) + SnapHandler.registerElement(tag.name, rect) lastBounds[tag.name] = rect nextX += ImGui.getWindowWidth() + 20f diff --git a/src/main/kotlin/com/lambda/gui/components/HudGuiLayout.kt b/src/main/kotlin/com/lambda/gui/components/HudGuiLayout.kt index c192edb3c..257053243 100644 --- a/src/main/kotlin/com/lambda/gui/components/HudGuiLayout.kt +++ b/src/main/kotlin/com/lambda/gui/components/HudGuiLayout.kt @@ -17,8 +17,8 @@ package com.lambda.gui.components -import com.lambda.config.Configurable -import com.lambda.config.configurations.HudConfig +import com.lambda.config.Config +import com.lambda.config.categories.HudCategory import com.lambda.core.Loadable import com.lambda.event.events.GuiEvent import com.lambda.event.listener.SafeListener.Companion.listen @@ -26,13 +26,10 @@ import com.lambda.gui.components.SettingsWidget.buildConfigSettingsContext import com.lambda.gui.dsl.ImGuiBuilder import com.lambda.gui.dsl.ImGuiBuilder.buildLayout import com.lambda.gui.snap.RectF -import com.lambda.gui.snap.SnapManager -import com.lambda.gui.snap.SnapManager.drawDragGrid -import com.lambda.gui.snap.SnapManager.drawSnapLines -import com.lambda.gui.snap.SnapManager.updateDragAndSnapping -import com.lambda.module.HudModule -import com.lambda.module.ModuleRegistry -import com.lambda.util.NamedEnum +import com.lambda.gui.snap.SnapHandler +import com.lambda.gui.snap.SnapHandler.drawDragGrid +import com.lambda.gui.snap.SnapHandler.drawSnapLines +import com.lambda.gui.snap.SnapHandler.updateDragAndSnapping import com.lambda.imgui.ImColor import com.lambda.imgui.ImDrawList import com.lambda.imgui.ImGui @@ -40,25 +37,24 @@ import com.lambda.imgui.flag.ImDrawListFlags import com.lambda.imgui.flag.ImGuiCol import com.lambda.imgui.flag.ImGuiStyleVar import com.lambda.imgui.flag.ImGuiWindowFlags +import com.lambda.module.HudModule +import com.lambda.module.ModuleRegistry import java.awt.Color import kotlin.math.PI -object HudGuiLayout : Loadable, Configurable(HudConfig) { - override val name = "HUD" - - enum class Group(override val displayName: String) : NamedEnum { - HudOutline("HUD Outline") - } - +object HudGuiLayout : Loadable, Config( + "HUD", + HudCategory +) { // HUD Outline - val hudOutlineCornerRadius by setting("HUD Corner Radius", 6.0f, 0.5f..24.0f, 0.5f).group(Group.HudOutline) - val hudOutlineHaloColor by setting("HUD Corner Halo Color", Color(140, 140, 140, 90)).group(Group.HudOutline) - val hudOutlineBorderColor by setting("HUD Corner Border Color", Color(190, 190, 190, 200)).group(Group.HudOutline) - val hudOutlineHaloThickness by setting("HUD Corner Halo Thickness", 3.0f, 1.0f..6.0f, 0.5f).group(Group.HudOutline) - val hudOutlineBorderThickness by setting("HUD Corner Border Thickness", 1.5f, 1.0f..4.0f, 0.5f).group(Group.HudOutline) - val hudOutlineCornerInflate by setting("HUD Corner Inflate", 1.0f, 0.0f..4.0f, 0.5f, "Extra radius for the halo arc").group(Group.HudOutline) - - const val DEFAULT_HUD_FLAGS = + val hudOutlineCornerRadius by setting("HUD Corner Radius", 6.0f, 0.5f..24.0f, 0.5f) + val hudOutlineHaloColor by setting("HUD Corner Halo Color", Color(140, 140, 140, 90)) + val hudOutlineBorderColor by setting("HUD Corner Border Color", Color(190, 190, 190, 200)) + val hudOutlineHaloThickness by setting("HUD Corner Halo Thickness", 3.0f, 1.0f..6.0f, 0.5f) + val hudOutlineBorderThickness by setting("HUD Corner Border Thickness", 1.5f, 1.0f..4.0f, 0.5f) + val hudOutlineCornerInflate by setting("HUD Corner Inflate", 1.0f, 0.0f..4.0f, 0.5f, "Extra radius for the halo arc") + + const val DefaultHudFlags = ImGuiWindowFlags.NoDecoration or ImGuiWindowFlags.NoBackground or ImGuiWindowFlags.AlwaysAutoResize or @@ -69,16 +65,16 @@ object HudGuiLayout : Loadable, Configurable(HudConfig) { private var dragOffsetY = 0f private val lastBounds = mutableMapOf() private val pendingPositions = mutableMapOf>() - private val snapOverlays = mutableMapOf() + private val snapOverlays = mutableMapOf() private var mousePressedThisFrameGlobal = false var isShownInGUI = true var isLocked = false - private const val PI_F = PI.toFloat() - private const val HALF_PI_F = (0.5f * PI).toFloat() - private const val THREE_HALVES_PI_F = (1.5f * PI).toFloat() - private const val TWO_PI_F = (2f * PI).toFloat() + private const val PiF = PI.toFloat() + private const val HalfPiF = (0.5f * PI).toFloat() + private const val ThreeHalvesPiF = (1.5f * PI).toFloat() + private const val TwoPiF = (2f * PI).toFloat() init { listen { @@ -117,7 +113,7 @@ object HudGuiLayout : Loadable, Configurable(HudConfig) { val (huds, notShown) = ModuleRegistry.modules .filterIsInstance() .partition { it.isEnabled } - notShown.forEach { SnapManager.unregisterElement(it.name) } + notShown.forEach { SnapHandler.unregisterElement(it.name) } if (ClickGuiLayout.open) { registerContextMenu(notShown) @@ -148,8 +144,8 @@ object HudGuiLayout : Loadable, Configurable(HudConfig) { val bg = hud.backgroundColor.value val hasBg = bg.alpha > 0 val baseFlags = if (hasBg) { - DEFAULT_HUD_FLAGS and ImGuiWindowFlags.NoBackground.inv() - } else DEFAULT_HUD_FLAGS + DefaultHudFlags and ImGuiWindowFlags.NoBackground.inv() + } else DefaultHudFlags var hudFlags = if (!ClickGuiLayout.open || isLocked) { baseFlags or ImGuiWindowFlags.NoMove } else baseFlags @@ -180,7 +176,7 @@ object HudGuiLayout : Loadable, Configurable(HudConfig) { popupContextWindow("##ctx-${hud.name}") { menuItem("Remove HUD Element") { hud.disable() - SnapManager.unregisterElement(hud.name) + SnapHandler.unregisterElement(hud.name) } separator() buildConfigSettingsContext(hud) @@ -189,7 +185,7 @@ object HudGuiLayout : Loadable, Configurable(HudConfig) { if (!isLocked) drawHudCornerArcs(windowDrawList, windowPos.x, windowPos.y, windowSize.x, windowSize.y) } val rect = RectF(windowPos.x, windowPos.y, windowSize.x, windowSize.y) - SnapManager.registerElement(hud.name, rect) + SnapHandler.registerElement(hud.name, rect) lastBounds[hud.name] = rect } } @@ -286,12 +282,12 @@ object HudGuiLayout : Loadable, Configurable(HudConfig) { } // TL: pi -> 1.5pi - strokeArc(tlCx, tlCy, PI_F, THREE_HALVES_PI_F) + strokeArc(tlCx, tlCy, PiF, ThreeHalvesPiF) // TR: 1.5pi -> 2pi - strokeArc(trCx, trCy, THREE_HALVES_PI_F, TWO_PI_F) + strokeArc(trCx, trCy, ThreeHalvesPiF, TwoPiF) // BR: 0 -> 0.5pi - strokeArc(brCx, brCy, 0f, HALF_PI_F) + strokeArc(brCx, brCy, 0f, HalfPiF) // BL: 0.5pi -> pi - strokeArc(blCx, blCy, HALF_PI_F, PI_F) + strokeArc(blCx, blCy, HalfPiF, PiF) } } \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/gui/components/ModuleEntry.kt b/src/main/kotlin/com/lambda/gui/components/ModuleEntry.kt index 8a8b2cac0..44f715906 100644 --- a/src/main/kotlin/com/lambda/gui/components/ModuleEntry.kt +++ b/src/main/kotlin/com/lambda/gui/components/ModuleEntry.kt @@ -20,8 +20,8 @@ package com.lambda.gui.components import com.lambda.gui.Layout import com.lambda.gui.components.SettingsWidget.buildConfigSettingsContext import com.lambda.gui.dsl.ImGuiBuilder -import com.lambda.module.Module import com.lambda.imgui.ImGui +import com.lambda.module.Module class ModuleEntry(val module: Module): Layout { override fun ImGuiBuilder.buildLayout() { diff --git a/src/main/kotlin/com/lambda/gui/components/QuickSearch.kt b/src/main/kotlin/com/lambda/gui/components/QuickSearch.kt index 6c2175de4..f4167b193 100644 --- a/src/main/kotlin/com/lambda/gui/components/QuickSearch.kt +++ b/src/main/kotlin/com/lambda/gui/components/QuickSearch.kt @@ -20,14 +20,19 @@ package com.lambda.gui.components import com.lambda.Lambda.mc import com.lambda.command.CommandRegistry import com.lambda.command.LambdaCommand -import com.lambda.config.Configurable -import com.lambda.config.Configuration +import com.lambda.config.Config +import com.lambda.config.ConfigLoader import com.lambda.config.Setting import com.lambda.event.events.ButtonEvent import com.lambda.event.listener.UnsafeListener.Companion.listenUnsafe import com.lambda.gui.LambdaScreen import com.lambda.gui.Layout import com.lambda.gui.dsl.ImGuiBuilder +import com.lambda.imgui.ImGui +import com.lambda.imgui.flag.ImGuiInputTextFlags +import com.lambda.imgui.flag.ImGuiStyleVar +import com.lambda.imgui.flag.ImGuiWindowFlags +import com.lambda.imgui.type.ImString import com.lambda.module.HudModule import com.lambda.module.Module import com.lambda.module.ModuleRegistry @@ -35,15 +40,11 @@ import com.lambda.module.modules.client.AutoUpdater import com.lambda.util.KeyCode import com.lambda.util.StringUtils.capitalize import com.lambda.util.StringUtils.levenshteinDistance -import com.lambda.imgui.ImGui -import com.lambda.imgui.flag.ImGuiInputTextFlags -import com.lambda.imgui.flag.ImGuiStyleVar -import com.lambda.imgui.flag.ImGuiWindowFlags -import com.lambda.imgui.type.ImString import net.minecraft.client.gui.screen.ChatScreen import kotlin.math.max // ToDo: Add support for searching of menu bar entries +@Suppress("unused") object QuickSearch { private val searchInput = ImString(256) var isOpen = false @@ -53,9 +54,9 @@ object QuickSearch { private var lastShiftPressTime = 0L private var lastShiftKeyCode = -1 - private const val DOUBLE_SHIFT_WINDOW_MS = 500L - private const val MAX_RESULTS = 50 - const val WINDOW_FLAGS = + private const val DoubleShiftWindowMs = 500L + private const val MaxResults = 50 + const val WindowFlags = ImGuiWindowFlags.AlwaysAutoResize or ImGuiWindowFlags.NoTitleBar or ImGuiWindowFlags.NoMove or @@ -101,8 +102,8 @@ object QuickSearch { } } - private class SettingResult(val setting: Setting<*, *>, val configurable: Configurable) : SearchResult { - override val breadcrumb: String by lazy { buildSettingBreadcrumb(configurable.name, setting) } + private class SettingResult(val setting: Setting<*>, val config: Config) : SearchResult { + override val breadcrumb: String by lazy { buildSettingBreadcrumb(config.name, setting) } override fun ImGuiBuilder.buildLayout() { with(setting) { @@ -145,7 +146,7 @@ object QuickSearch { ImGui.setNextWindowSize(maxW, 0f) ImGui.setNextWindowSizeConstraints(0f, 0f, maxW, maxH) - popupModal("QuickSearch", WINDOW_FLAGS) { + popupModal("QuickSearch", WindowFlags) { if (shouldFocus) { ImGui.setKeyboardFocusHere() shouldFocus = false @@ -194,9 +195,9 @@ object QuickSearch { private object SearchService { private data class RankedSearchResult(val result: SearchResult, val score: Int) - private const val MODULE_PRIORITY_BONUS = 300 - private const val HUD_MODULE_PRIORITY_BONUS = 270 - private const val COMMAND_PRIORITY_BONUS = 200 + private const val ModulePriorityBonus = 300 + private const val HudModulePriorityBonus = 270 + private const val CommandPriorityBonus = 200 /** * Calculates a relevance score for a query against a target string. @@ -244,8 +245,8 @@ object QuickSearch { if (bestScore > 0) { when(module) { - is HudModule -> RankedSearchResult(ModuleResult(module), bestScore + HUD_MODULE_PRIORITY_BONUS) - else -> RankedSearchResult(ModuleResult(module), bestScore + MODULE_PRIORITY_BONUS) + is HudModule -> RankedSearchResult(ModuleResult(module), bestScore + HudModulePriorityBonus) + else -> RankedSearchResult(ModuleResult(module), bestScore + ModulePriorityBonus) } } else null } @@ -256,18 +257,21 @@ object QuickSearch { val bestScore = max(nameScore, aliasScore) if (bestScore > 0) { - RankedSearchResult(CommandResult(command), bestScore + COMMAND_PRIORITY_BONUS) + RankedSearchResult(CommandResult(command), bestScore + CommandPriorityBonus) } else null } - val settingResults = Configuration.configurations.flatMap { - it.configurables.flatMap { configurable -> - configurable.settings - .filter { setting -> setting.visibility() } - .mapNotNull { setting -> - val score = calculateScore(lowerCaseQuery, setting.name.lowercase(), lenient) - if (score > 0) RankedSearchResult(SettingResult(setting, configurable), score) else null + val settingResults = buildList { + ConfigLoader.configCategories.forEach { category -> + category.configs.forEach { config -> + config.forEachSetting { _, single -> + val setting = single.setting + if (setting.visibility()) { + val score = calculateScore(lowerCaseQuery, setting.name.lowercase(), lenient) + if (score > 0) add(RankedSearchResult(SettingResult(setting, config), score)) + } } + } } } @@ -285,23 +289,21 @@ object QuickSearch { return strictResults .sortedByDescending { it.score } .map { it.result } - .take(MAX_RESULTS) + .take(MaxResults) } // Second pass: if nothing was found, perform a more generous fuzzy search. return searchInternal(query, lenient = true) .sortedByDescending { it.score } .map { it.result } - .take(MAX_RESULTS) + .take(MaxResults) } } - private fun buildSettingBreadcrumb(configurableName: String, setting: Setting<*, *>): String { - val group = setting.groups - .minByOrNull { it.size } - ?.joinToString(" » ") { it.displayName } - ?: return configurableName - return "$configurableName » $group" + private fun buildSettingBreadcrumb(configName: String, setting: Setting<*>): String { + val path = setting.getConfigCommandPath() + return if (path.isEmpty()) configName + else "$configName » ${path.joinToString(" » ")}" } private fun handleKeyPress(event: ButtonEvent.Keyboard.Press) { @@ -311,7 +313,7 @@ object QuickSearch { val currentTime = System.currentTimeMillis() if (lastShiftKeyCode == event.keyCode && - currentTime - lastShiftPressTime <= DOUBLE_SHIFT_WINDOW_MS + currentTime - lastShiftPressTime <= DoubleShiftWindowMs ) { open() lastShiftPressTime = 0L diff --git a/src/main/kotlin/com/lambda/gui/components/SettingsWidget.kt b/src/main/kotlin/com/lambda/gui/components/SettingsWidget.kt index 1dc397721..da4c1f749 100644 --- a/src/main/kotlin/com/lambda/gui/components/SettingsWidget.kt +++ b/src/main/kotlin/com/lambda/gui/components/SettingsWidget.kt @@ -17,26 +17,26 @@ package com.lambda.gui.components -import com.lambda.config.AutomationConfig -import com.lambda.config.Configurable -import com.lambda.config.IMutableAutomationConfig +import com.lambda.config.Config import com.lambda.config.Setting -import com.lambda.config.UserAutomationConfig -import com.lambda.config.configurations.UserAutomationConfigs +import com.lambda.config.SettingLayer +import com.lambda.config.automation.AutomationConfig +import com.lambda.config.automation.IMutableAutomationConfig +import com.lambda.config.automation.UserAutomationConfig +import com.lambda.config.categories.UserAutomationCategory import com.lambda.gui.dsl.ImGuiBuilder -import com.lambda.module.HudModule -import com.lambda.module.Module -import com.lambda.module.modules.client.AutoUpdater -import com.lambda.util.NamedEnum import com.lambda.imgui.ImGui import com.lambda.imgui.flag.ImGuiPopupFlags import com.lambda.imgui.flag.ImGuiTabBarFlags +import com.lambda.module.HudModule +import com.lambda.module.Module +import com.lambda.module.modules.client.AutoUpdater object SettingsWidget { /** - * Builds the settings context popup content for the given configurable. + * Builds the settings context popup content for the given config. */ - fun ImGuiBuilder.buildConfigSettingsContext(config: Configurable) { + fun ImGuiBuilder.buildConfigSettingsContext(config: Config) { group { if (config is Module && config != AutoUpdater) { button("Module Settings") { @@ -52,12 +52,12 @@ object SettingsWidget { with(config.backgroundColor) { buildLayout() } } smallButton("Reset") { - config.settings.forEach { it.reset(silent = true) } + config.reset() } } } lambdaTooltip("Resets all settings for this module to their default values") - if (config is IMutableAutomationConfig && config.automationConfig !== AutomationConfig.Companion.DEFAULT) { + if (config is IMutableAutomationConfig && config.automationConfig !== AutomationConfig.Default) { button("Automation Config") { ImGui.openPopup("##automation-config-popup-${config.name}") } @@ -68,7 +68,7 @@ object SettingsWidget { ImGui.setNextWindowSizeConstraints(0f, 0f, Float.MAX_VALUE, io.displaySize.y * 0.5f) popupContextItem("##automation-config-popup-${config.name}", ImGuiPopupFlags.None) { combo("##LinkedConfig", preview = "Linked Config: ${config.backingAutomationConfig.name}") { - val addItem: (Configurable) -> Unit = { item -> + val addItem: (Config) -> Unit = { item -> val selected = item === config.backingAutomationConfig selectable(item.name, selected) { @@ -80,62 +80,65 @@ object SettingsWidget { } } addItem(config.defaultAutomationConfig) - UserAutomationConfigs.configurables.forEach { addItem(it) } + UserAutomationCategory.configs.forEach { addItem(it) } } buildConfigSettingsContext(config.automationConfig) } } } - val visibleSettings = config.settings.filter { it.visibility() } - if (visibleSettings.isEmpty()) return - else separator() - val (grouped, ungrouped) = visibleSettings.partition { it.groups.isNotEmpty() } - ungrouped.forEach { - it.withDisabled { buildLayout() } - } - renderGroup(grouped, emptyList(), config) + if (!hasVisibleSettings(config.settingLayers)) return + separator() + drawLayers(config.settingLayers, config.name) } - private fun Setting<*, *>.withDisabled(block: Setting<*, *>.() -> Unit) { - if (disabled()) ImGui.beginDisabled() - block() - if (disabled()) ImGui.endDisabled() - } + private fun ImGuiBuilder.drawLayers(root: SettingLayer.Multiple, idPrefix: String) { + var tabsDrawn = false - private fun ImGuiBuilder.renderGroup( - settings: List>, - parentPath: List, - config: Configurable - ) { - settings.filter { it.groups.contains(parentPath) }.forEach { - it.withDisabled { buildLayout() } - } - - val subGroupSettings = settings.filter { s -> - s.groups.any { it.size > parentPath.size && it.subList(0, parentPath.size) == parentPath } - } - val subTabs = subGroupSettings - .flatMap { s -> - s.groups.mapNotNull { path -> - if (path.size > parentPath.size && path.subList(0, parentPath.size) == parentPath) - path[parentPath.size] else null - } - }.distinct() + root.layers.forEach { layer -> + when (layer) { + is SettingLayer.Single<*, *> -> drawSetting(layer.setting) + is SettingLayer.Group -> { + if (hasVisibleSettings(layer)) { + treeNode("${layer.name}##$idPrefix-group-${layer.name}") { + drawLayers(layer, "$idPrefix-${layer.name}") + } + } + } + is SettingLayer.Tab -> { + if (!tabsDrawn) { + tabsDrawn = true + val allTabs = root.layers + .filterIsInstance() + .filter { hasVisibleSettings(it) } + if (allTabs.isNotEmpty()) { + tabBar("##$idPrefix-tabs", ImGuiTabBarFlags.FittingPolicyResizeDown) { + allTabs.forEach { tab -> + tabItem(tab.name) { + drawLayers(tab, "$idPrefix-${tab.name}") + } + } + } + } + } + } + else -> {} + } + } + } - if (subTabs.isNotEmpty()) { - val id = "##${config.name}-tabs-${parentPath.joinToString("-") { it.displayName }}" - tabBar(id, ImGuiTabBarFlags.FittingPolicyResizeDown) { - subTabs.forEach { tab -> - tabItem(tab.displayName) { - val newParentPath = parentPath + tab - val settingsForSubGroup = subGroupSettings.filter { s -> - s.groups.any { it.size >= newParentPath.size && it.subList(0, newParentPath.size) == newParentPath } - } - renderGroup(settingsForSubGroup, newParentPath, config) - } - } - } - } + private fun ImGuiBuilder.drawSetting(setting: Setting<*>) { + if (!setting.visibility()) return + if (setting.disabled()) ImGui.beginDisabled() + with(setting) { buildLayout() } + if (setting.disabled()) ImGui.endDisabled() } + + private fun hasVisibleSettings(layer: SettingLayer.Multiple): Boolean = + layer.layers.any { layer -> + when (layer) { + is SettingLayer.Single<*, *> -> layer.setting.visibility() + is SettingLayer.Multiple -> hasVisibleSettings(layer) + } + } } \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/gui/dsl/ImGuiBuilder.kt b/src/main/kotlin/com/lambda/gui/dsl/ImGuiBuilder.kt index 865688cab..e57d4d6a2 100644 --- a/src/main/kotlin/com/lambda/gui/dsl/ImGuiBuilder.kt +++ b/src/main/kotlin/com/lambda/gui/dsl/ImGuiBuilder.kt @@ -17,28 +17,11 @@ @file:Suppress("unused") -/* - * 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.gui.dsl import com.lambda.gui.components.ClickGuiLayout +import com.lambda.gui.dsl.ImGuiBuilder.openPopup import com.lambda.gui.dsl.ImGuiBuilder.text -import com.lambda.util.math.Vec2d import com.lambda.imgui.ImDrawList import com.lambda.imgui.ImFont import com.lambda.imgui.ImGui @@ -130,6 +113,7 @@ import com.lambda.imgui.ImGui.isWindowAppearing import com.lambda.imgui.ImGui.isWindowCollapsed import com.lambda.imgui.ImGui.isWindowHovered import com.lambda.imgui.ImGui.plotHistogram +import com.lambda.imgui.ImGui.plotLines import com.lambda.imgui.ImGui.popFont import com.lambda.imgui.ImGui.popID import com.lambda.imgui.ImGui.popItemWidth @@ -157,6 +141,7 @@ import com.lambda.imgui.ImGuiTextFilter import com.lambda.imgui.ImGuiViewport import com.lambda.imgui.ImVec2 import com.lambda.imgui.flag.ImDrawListFlags +import com.lambda.imgui.flag.ImGuiChildFlags import com.lambda.imgui.flag.ImGuiCol import com.lambda.imgui.flag.ImGuiColorEditFlags import com.lambda.imgui.flag.ImGuiComboFlags @@ -174,13 +159,12 @@ import com.lambda.imgui.type.ImDouble import com.lambda.imgui.type.ImFloat import com.lambda.imgui.type.ImInt import com.lambda.imgui.type.ImString +import com.lambda.util.math.Vec2d import net.minecraft.util.math.Vec2f import net.minecraft.util.math.Vec3d import net.minecraft.util.math.Vec3i import java.awt.Color import kotlin.reflect.KMutableProperty0 -import com.lambda.imgui.ImGui.plotLines -import com.lambda.imgui.flag.ImGuiChildFlags typealias ProcedureBlock = ImGuiBuilder.() -> Unit typealias WrappedBlock = ImGuiBuilder.(In) -> Out @@ -1964,7 +1948,7 @@ object ImGuiBuilder { * @param value Float value * @param block Content of the scope * - * @see imgui.flag.ImGuiStyleVar + * @see com.lambda.imgui.flag.ImGuiStyleVar */ @ImGuiDsl inline fun withStyleVar(styleVar: Int, value: Float, block: ProcedureBlock) { diff --git a/src/main/kotlin/com/lambda/gui/snap/SnapManager.kt b/src/main/kotlin/com/lambda/gui/snap/SnapHandler.kt similarity index 99% rename from src/main/kotlin/com/lambda/gui/snap/SnapManager.kt rename to src/main/kotlin/com/lambda/gui/snap/SnapHandler.kt index 10115bdd9..77dbae460 100644 --- a/src/main/kotlin/com/lambda/gui/snap/SnapManager.kt +++ b/src/main/kotlin/com/lambda/gui/snap/SnapHandler.kt @@ -33,11 +33,10 @@ import com.lambda.gui.components.ClickGuiLayout.snapToScreenCenter import com.lambda.gui.dsl.ImGuiBuilder import com.lambda.imgui.ImColor import com.lambda.imgui.ImGui -import kotlin.collections.set import kotlin.math.abs import kotlin.math.max -object SnapManager : Loadable { +object SnapHandler : Loadable { private data class SnapGuide(val guide: Guide, val sourceId: String?) private val frameGuides = ArrayList(512) private val elementRects = LinkedHashMap() diff --git a/src/main/kotlin/com/lambda/interaction/BaritoneHandler.kt b/src/main/kotlin/com/lambda/interaction/BaritoneHandler.kt new file mode 100644 index 000000000..45e8b7a53 --- /dev/null +++ b/src/main/kotlin/com/lambda/interaction/BaritoneHandler.kt @@ -0,0 +1,368 @@ +/* + * Copyright 2026 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.interaction + +import baritone.api.BaritoneAPI +import baritone.api.IBaritone +import baritone.api.Settings +import baritone.api.pathing.goals.Goal +import com.lambda.config.Config +import com.lambda.config.Group +import com.lambda.config.ConfigBlock +import com.lambda.config.Tab +import com.lambda.config.automation.AutomationConfig +import com.lambda.config.categories.LambdaCategory +import com.lambda.config.settings.blocks.RotationSettings +import com.lambda.context.Automated +import com.lambda.util.BlockUtils.blockPos +import net.fabricmc.loader.api.FabricLoader +import net.minecraft.util.BlockMirror +import net.minecraft.util.BlockRotation + +@Suppress("unused") +object BaritoneHandler : Config( + "baritone", + LambdaCategory +), Automated by AutomationConfig.Default { + val isBaritoneLoaded = FabricLoader.getInstance().isModLoaded("baritone") + + private val baritone = if (isBaritoneLoaded) BaritoneAPI.getProvider() else null + val baritoneSettings: Settings? = if (isBaritoneLoaded) BaritoneAPI.getSettings() else null + +// val settings by baritoneSettings?.let { settingBlock(BaritoneConfigSettings(this, it)) } + private const val RotationTab = "Rotation" + @Tab(RotationTab) override val rotationConfig by configBlock(RotationSettings(this)) + + @JvmStatic + val primary: IBaritone? = baritone?.primaryBaritone + + /** + * Whether Baritone is currently pathing + */ + val isPathing: Boolean + get() = isBaritoneLoaded && primary?.pathingBehavior?.isPathing == true + + /** + * Whether Baritone is active (pathing, calculating goal, etc.) + */ + val isActive: Boolean + get() = isBaritoneLoaded && + (primary?.customGoalProcess?.isActive == true || + primary?.pathingBehavior?.isPathing == true || + primary?.pathingControlManager?.mostRecentInControl()?.orElse(null)?.isActive == true || + primary?.elytraProcess?.isActive == true) + + /** + * Sets the current Baritone goal and starts pathing + */ + fun setGoalAndPath(goal: Goal) { + if (!isBaritoneLoaded) return + primary?.customGoalProcess?.setGoalAndPath(goal) + } + + /** + * Sets the current Baritone goal without starting pathing + */ + fun setGoal(goal: Goal) { + if (!isBaritoneLoaded || primary?.elytraProcess?.isLoaded != true) return + primary.customGoalProcess?.goal = goal + } + + fun setGoalAndElytraPath(goal: Goal) { + if (!isBaritoneLoaded || primary?.elytraProcess?.isLoaded != true) return + primary.elytraProcess?.pathTo(goal) + } + + /** + * Force cancel Baritone + */ + fun cancel() { + if (!isBaritoneLoaded) return + primary?.pathingBehavior?.cancelEverything() + primary?.elytraProcess?.resetState() + } + + class BaritoneConfigSettings( + override val c: Config, + private val bSettings: Settings + ) : ConfigBlock { + companion object { + private const val GeneralTab = "General" + private const val PathingTab = "Pathing" + private const val BehaviorTab = "Behavior" + private const val BuildingTab = "Building" + private const val RenderingTab = "Rendering" + private const val ElytraTab = "Elytra" + + private const val ChatAndControlGroup = "Chat & Control" + private const val WaypointsGroup = "Waypoints" + private const val AssumptionsGroup = "Assumptions" + private const val MovementGroup = "Movement" + private const val BlockRulesGroup = "Block Rules" + private const val MiningAndFarmingGroup = "Mining & Farming" + private const val InteractionGroup = "Interaction" + private const val PenaltiesGroup = "Penalties" + private const val ExplorationGroup = "Exploration" + private const val MiscGroup = "Misc" + private const val RenderingGroup = "Rendering" + private const val RenderingColorsGroup = "Rendering Colors" + private const val RenderingSelectionGroup = "Rendering Selection" + private const val PathingPerformanceGroup = "Pathing Performance" + private const val PathingCoreGroup = "Pathing Core" + private const val FollowGroup = "Follow" + private const val SchematicGroup = "Schematic" + } + + @Tab(GeneralTab) @Group(ChatAndControlGroup) val logAsToast by c.setting("Log As Toast", bSettings.logAsToast.value).onValueChange { _, it -> bSettings.logAsToast.value = it } + @Tab(GeneralTab) @Group(ChatAndControlGroup) val chatDebug by c.setting("Chat Debug", bSettings.chatDebug.value).onValueChange { _, it -> bSettings.chatDebug.value = it } + @Tab(GeneralTab) @Group(ChatAndControlGroup) val chatControl by c.setting("Chat Control", bSettings.chatControl.value).onValueChange { _, it -> bSettings.chatControl.value = it } + @Tab(GeneralTab) @Group(ChatAndControlGroup) val chatControlAnyway by c.setting("Chat Control Anyway", bSettings.chatControlAnyway.value).onValueChange { _, it -> bSettings.chatControlAnyway.value = it } + @Tab(GeneralTab) @Group(ChatAndControlGroup) val prefixControl by c.setting("Prefix Control", bSettings.prefixControl.value).onValueChange { _, it -> bSettings.prefixControl.value = it } + @Tab(GeneralTab) @Group(ChatAndControlGroup) val prefix by c.setting("Prefix", bSettings.prefix.value).onValueChange { _, it -> bSettings.prefix.value = it } + @Tab(GeneralTab) @Group(ChatAndControlGroup) val shortBaritonePrefix by c.setting("Short Baritone Prefix", bSettings.shortBaritonePrefix.value).onValueChange { _, it -> bSettings.shortBaritonePrefix.value = it } + @Tab(GeneralTab) @Group(ChatAndControlGroup) val useMessageTag by c.setting("Use Message Tag", bSettings.useMessageTag.value).onValueChange { _, it -> bSettings.useMessageTag.value = it } + @Tab(GeneralTab) @Group(ChatAndControlGroup) val echoCommands by c.setting("Echo Commands", bSettings.echoCommands.value).onValueChange { _, it -> bSettings.echoCommands.value = it } + @Tab(GeneralTab) @Group(ChatAndControlGroup) val censorCoordinates by c.setting("Censor Coordinates", bSettings.censorCoordinates.value).onValueChange { _, it -> bSettings.censorCoordinates.value = it } + @Tab(GeneralTab) @Group(ChatAndControlGroup) val censorRanCommands by c.setting("Censor Ran Commands", bSettings.censorRanCommands.value).onValueChange { _, it -> bSettings.censorRanCommands.value = it } + @Tab(GeneralTab) @Group(ChatAndControlGroup) val desktopNotifications by c.setting("Desktop Notifications", bSettings.desktopNotifications.value).onValueChange { _, it -> bSettings.desktopNotifications.value = it } + @Tab(GeneralTab) @Group(ChatAndControlGroup) val notificationOnPathComplete by c.setting("Notification On Path Complete", bSettings.notificationOnPathComplete.value).onValueChange { _, it -> bSettings.notificationOnPathComplete.value = it } + @Tab(GeneralTab) @Group(ChatAndControlGroup) val notificationOnFarmFail by c.setting("Notification On Farm Fail", bSettings.notificationOnFarmFail.value).onValueChange { _, it -> bSettings.notificationOnFarmFail.value = it } + @Tab(GeneralTab) @Group(ChatAndControlGroup) val notificationOnBuildFinished by c.setting("Notification On Build Finished", bSettings.notificationOnBuildFinished.value).onValueChange { _, it -> bSettings.notificationOnBuildFinished.value = it } + @Tab(GeneralTab) @Group(ChatAndControlGroup) val notificationOnExploreFinished by c.setting("Notification On Explore Finished", bSettings.notificationOnExploreFinished.value).onValueChange { _, it -> bSettings.notificationOnExploreFinished.value = it } + @Tab(GeneralTab) @Group(ChatAndControlGroup) val notificationOnMineFail by c.setting("Notification On Mine Fail", bSettings.notificationOnMineFail.value).onValueChange { _, it -> bSettings.notificationOnMineFail.value = it } + @Tab(GeneralTab) @Group(ChatAndControlGroup) val verboseCommandExceptions by c.setting("Verbose Command Exceptions", bSettings.verboseCommandExceptions.value).onValueChange { _, it -> bSettings.verboseCommandExceptions.value = it } + @Tab(GeneralTab) @Group(WaypointsGroup) val doBedWaypoints by c.setting("Do Bed Waypoints", bSettings.doBedWaypoints.value).onValueChange { _, it -> bSettings.doBedWaypoints.value = it } + @Tab(GeneralTab) @Group(WaypointsGroup) val doDeathWaypoints by c.setting("Do Death Waypoints", bSettings.doDeathWaypoints.value).onValueChange { _, it -> bSettings.doDeathWaypoints.value = it } + @Tab(GeneralTab) @Group(MiscGroup) val antiCheatCompatibility by c.setting("Anti Cheat Compatibility", bSettings.antiCheatCompatibility.value).onValueChange { _, it -> bSettings.antiCheatCompatibility.value = it } + @Tab(PathingTab) @Group(PathingCoreGroup) val pathingMaxChunkBorderFetch by c.setting("Pathing Max Chunk Border Fetch", bSettings.pathingMaxChunkBorderFetch.value, 0..64).onValueChange { _, it -> bSettings.pathingMaxChunkBorderFetch.value = it } + @Tab(PathingTab) @Group(PathingCoreGroup) val pathingMapDefaultSize by c.setting("Pathing Map Default Size", bSettings.pathingMapDefaultSize.value, 0..2048).onValueChange { _, it -> bSettings.pathingMapDefaultSize.value = it } + @Tab(PathingTab) @Group(PathingCoreGroup) val pathingMapLoadFactor by c.setting("Pathing Map Load Factor", bSettings.pathingMapLoadFactor.value, 0f..1f, 0.05f).onValueChange { _, it -> bSettings.pathingMapLoadFactor.value = it } + @Tab(PathingTab) @Group(PathingCoreGroup) val distanceTrim by c.setting("Distance Trim", bSettings.distanceTrim.value).onValueChange { _, it -> bSettings.distanceTrim.value = it } + @Tab(PathingTab) @Group(PathingCoreGroup) val simplifyUnloadedYCoord by c.setting("Simplify Unloaded Y Coord", bSettings.simplifyUnloadedYCoord.value).onValueChange { _, it -> bSettings.simplifyUnloadedYCoord.value = it } + @Tab(PathingTab) @Group(PathingCoreGroup) val repackOnAnyBlockChange by c.setting("Repack On Any Block Change", bSettings.repackOnAnyBlockChange.value).onValueChange { _, it -> bSettings.repackOnAnyBlockChange.value = it } + @Tab(PathingTab) @Group(PathingCoreGroup) val avoidance by c.setting("Avoidance", bSettings.avoidance.value).onValueChange { _, it -> bSettings.avoidance.value = it } + @Tab(PathingTab) @Group(PathingCoreGroup) val pruneRegionsFromRAM by c.setting("Prune Regions From RAM", bSettings.pruneRegionsFromRAM.value).onValueChange { _, it -> bSettings.pruneRegionsFromRAM.value = it } + @Tab(PathingTab) @Group(PathingCoreGroup) val backfill by c.setting("Backfill", bSettings.backfill.value).onValueChange { _, it -> bSettings.backfill.value = it } + @Tab(PathingTab) @Group(PathingCoreGroup) val maxFallHeightNoWater by c.setting("Max Fall Height No Water", bSettings.maxFallHeightNoWater.value, 0..256).onValueChange { _, it -> bSettings.maxFallHeightNoWater.value = it } + @Tab(PathingTab) @Group(PathingCoreGroup) val maxFallHeightBucket by c.setting("Max Fall Height Bucket", bSettings.maxFallHeightBucket.value, 0..256).onValueChange { _, it -> bSettings.maxFallHeightBucket.value = it } + @Tab(PathingTab) @Group(PathingCoreGroup) val axisHeight by c.setting("Axis Height", bSettings.axisHeight.value, 0..256).onValueChange { _, it -> bSettings.axisHeight.value = it } + @Tab(PathingTab) @Group(PathingCoreGroup) val disconnectOnArrival by c.setting("Disconnect On Arrival", bSettings.disconnectOnArrival.value).onValueChange { _, it -> bSettings.disconnectOnArrival.value = it } + @Tab(PathingTab) @Group(PathingCoreGroup) val splicePath by c.setting("Splice Path", bSettings.splicePath.value).onValueChange { _, it -> bSettings.splicePath.value = it } + @Tab(PathingTab) @Group(PathingCoreGroup) val maxPathHistoryLength by c.setting("Max Path History Length", bSettings.maxPathHistoryLength.value, 0..10000).onValueChange { _, it -> bSettings.maxPathHistoryLength.value = it } + @Tab(PathingTab) @Group(PathingCoreGroup) val pathHistoryCutoffAmount by c.setting("Path History Cutoff Amount", bSettings.pathHistoryCutoffAmount.value, 0..10000).onValueChange { _, it -> bSettings.pathHistoryCutoffAmount.value = it } + @Tab(PathingTab) @Group(PathingCoreGroup) val mineGoalUpdateInterval by c.setting("Mine Goal Update Interval", bSettings.mineGoalUpdateInterval.value, 0..10000).onValueChange { _, it -> bSettings.mineGoalUpdateInterval.value = it } + @Tab(PathingTab) @Group(PathingCoreGroup) val maxCachedWorldScanCount by c.setting("Max Cached World Scan Count", bSettings.maxCachedWorldScanCount.value, 0..100000).onValueChange { _, it -> bSettings.maxCachedWorldScanCount.value = it } + @Tab(PathingTab) @Group(PathingCoreGroup) val mineMaxOreLocationsCount by c.setting("Mine Max Ore Locations Count", bSettings.mineMaxOreLocationsCount.value, 0..100000).onValueChange { _, it -> bSettings.mineMaxOreLocationsCount.value = it } + @Tab(PathingTab) @Group(PathingCoreGroup) val cachedChunksExpirySeconds by c.setting("Cached Chunks Expiry Seconds", bSettings.cachedChunksExpirySeconds.value, -1L..86400L).onValueChange { _, it -> bSettings.cachedChunksExpirySeconds.value = it } + @Tab(PathingTab) @Group(PathingCoreGroup) val yLevelBoxSize by c.setting("Y Level Box Size", bSettings.yLevelBoxSize.value, 0.0..256.0).onValueChange { _, it -> bSettings.yLevelBoxSize.value = it } + @Tab(PathingTab) @Group(PathingCoreGroup) val extendCacheOnThreshold by c.setting("Extend Cache On Threshold", bSettings.extendCacheOnThreshold.value).onValueChange { _, it -> bSettings.extendCacheOnThreshold.value = it } + @Tab(PathingTab) @Group(PathingCoreGroup) val cancelOnGoalInvalidation by c.setting("Cancel On Goal Invalidation", bSettings.cancelOnGoalInvalidation.value).onValueChange { _, it -> bSettings.cancelOnGoalInvalidation.value = it } + @Tab(PathingTab) @Group(PathingCoreGroup) val chunkCaching by c.setting("Chunk Caching", bSettings.chunkCaching.value).onValueChange { _, it -> bSettings.chunkCaching.value = it } + @Tab(PathingTab) @Group(PathingCoreGroup) val chunkPackerQueueMaxSize by c.setting("Chunk Packer Queue Max Size", bSettings.chunkPackerQueueMaxSize.value, 0..10000).onValueChange { _, it -> bSettings.chunkPackerQueueMaxSize.value = it } + @Tab(PathingTab) @Group(PathingCoreGroup) val pathThroughCachedOnly by c.setting("Path Through Cached Only", bSettings.pathThroughCachedOnly.value).onValueChange { _, it -> bSettings.pathThroughCachedOnly.value = it } + @Tab(PathingTab) @Group(PathingCoreGroup) val blacklistClosestOnFailure by c.setting("Blacklist Closest On Failure", bSettings.blacklistClosestOnFailure.value).onValueChange { _, it -> bSettings.blacklistClosestOnFailure.value = it } + @Tab(PathingTab) @Group(PathingCoreGroup) val pathCutoffMinimumLength by c.setting("Path Cutoff Minimum Length", bSettings.pathCutoffMinimumLength.value, 0..1000).onValueChange { _, it -> bSettings.pathCutoffMinimumLength.value = it } + @Tab(PathingTab) @Group(PathingCoreGroup) val cutoffAtLoadBoundary by c.setting("Cutoff At Load Boundary", bSettings.cutoffAtLoadBoundary.value).onValueChange { _, it -> bSettings.cutoffAtLoadBoundary.value = it } + @Tab(PathingTab) @Group(PathingCoreGroup) val minimumImprovementRepropagation by c.setting("Minimum Improvement Repropagation", bSettings.minimumImprovementRepropagation.value).onValueChange { _, it -> bSettings.minimumImprovementRepropagation.value = it } + @Tab(PathingTab) @Group(PathingCoreGroup) val costVerificationLookahead by c.setting("Cost Verification Lookahead", bSettings.costVerificationLookahead.value, 0..1000).onValueChange { _, it -> bSettings.costVerificationLookahead.value = it } + @Tab(PathingTab) @Group(PathingPerformanceGroup) val primaryTimeoutMS by c.setting("Primary Timeout", bSettings.primaryTimeoutMS.value, 0L..600000L, unit = " ms").onValueChange { _, it -> bSettings.primaryTimeoutMS.value = it } + @Tab(PathingTab) @Group(PathingPerformanceGroup) val failureTimeoutMS by c.setting("Failure Timeout", bSettings.failureTimeoutMS.value, 0L..600000L, unit = " ms").onValueChange { _, it -> bSettings.failureTimeoutMS.value = it } + @Tab(PathingTab) @Group(PathingPerformanceGroup) val planAheadPrimaryTimeoutMS by c.setting("Plan Ahead Primary Timeout", bSettings.planAheadPrimaryTimeoutMS.value, 0L..600000L, unit = " ms").onValueChange { _, it -> bSettings.planAheadPrimaryTimeoutMS.value = it } + @Tab(PathingTab) @Group(PathingPerformanceGroup) val planAheadFailureTimeoutMS by c.setting("Plan Ahead Failure Timeout", bSettings.planAheadFailureTimeoutMS.value, 0L..600000L, unit = " ms").onValueChange { _, it -> bSettings.planAheadFailureTimeoutMS.value = it } + @Tab(PathingTab) @Group(PathingPerformanceGroup) val slowPath by c.setting("Slow Path", bSettings.slowPath.value).onValueChange { _, it -> bSettings.slowPath.value = it } + @Tab(PathingTab) @Group(PathingPerformanceGroup) val slowPathTimeDelayMS by c.setting("Slow Path Time Delay", bSettings.slowPathTimeDelayMS.value, 0L..600000L, unit = " ms").onValueChange { _, it -> bSettings.slowPathTimeDelayMS.value = it } + @Tab(PathingTab) @Group(PathingPerformanceGroup) val slowPathTimeoutMS by c.setting("Slow Path Timeout", bSettings.slowPathTimeoutMS.value, 0L..600000L, unit = " ms").onValueChange { _, it -> bSettings.slowPathTimeoutMS.value = it } + @Tab(PathingTab) @Group(PathingPerformanceGroup) val planningTickLookahead by c.setting("Planning Tick Lookahead", bSettings.planningTickLookahead.value, 0..200).onValueChange { _, it -> bSettings.planningTickLookahead.value = it } + @Tab(PathingTab) @Group(PathingPerformanceGroup) val movementTimeoutTicks by c.setting("Movement Timeout Ticks", bSettings.movementTimeoutTicks.value, 0..2000).onValueChange { _, it -> bSettings.movementTimeoutTicks.value = it } + @Tab(PathingTab) @Group(FollowGroup) val followOffsetDistance by c.setting("Follow Offset Distance", bSettings.followOffsetDistance.value, 0.0..256.0).onValueChange { _, it -> bSettings.followOffsetDistance.value = it } + @Tab(PathingTab) @Group(FollowGroup) val followOffsetDirection by c.setting("Follow Offset Direction", bSettings.followOffsetDirection.value, -180f..180f, 1f).onValueChange { _, it -> bSettings.followOffsetDirection.value = it } + @Tab(PathingTab) @Group(FollowGroup) val followRadius by c.setting("Follow Radius", bSettings.followRadius.value, 0..1000).onValueChange { _, it -> bSettings.followRadius.value = it } + @Tab(PathingTab) @Group(FollowGroup) val followTargetMaxDistance by c.setting("Follow Target Max Distance", bSettings.followTargetMaxDistance.value, 0..10000).onValueChange { _, it -> bSettings.followTargetMaxDistance.value = it } + @Tab(PathingTab) @Group(FollowGroup) val disableCompletionCheck by c.setting("Disable Completion Check", bSettings.disableCompletionCheck.value).onValueChange { _, it -> bSettings.disableCompletionCheck.value = it } + @Tab(BehaviorTab) @Group(AssumptionsGroup) val strictLiquidCheck by c.setting("Strict Liquid Check", bSettings.strictLiquidCheck.value).onValueChange { _, it -> bSettings.strictLiquidCheck.value = it } + @Tab(BehaviorTab) @Group(AssumptionsGroup) val assumeWalkOnWater by c.setting("Assume Walk On Water", bSettings.assumeWalkOnWater.value).onValueChange { _, it -> bSettings.assumeWalkOnWater.value = it } + @Tab(BehaviorTab) @Group(AssumptionsGroup) val assumeWalkOnLava by c.setting("Assume Walk On Lava", bSettings.assumeWalkOnLava.value).onValueChange { _, it -> bSettings.assumeWalkOnLava.value = it } + @Tab(BehaviorTab) @Group(AssumptionsGroup) val assumeStep by c.setting("Assume Step", bSettings.assumeStep.value).onValueChange { _, it -> bSettings.assumeStep.value = it } + @Tab(BehaviorTab) @Group(AssumptionsGroup) val assumeSafeWalk by c.setting("Assume Safe Walk", bSettings.assumeSafeWalk.value).onValueChange { _, it -> bSettings.assumeSafeWalk.value = it } + @Tab(BehaviorTab) @Group(AssumptionsGroup) val assumeExternalAutoTool by c.setting("Assume External Auto Tool", bSettings.assumeExternalAutoTool.value).onValueChange { _, it -> bSettings.assumeExternalAutoTool.value = it } + @Tab(BehaviorTab) @Group(MovementGroup) val allowParkourAscend by c.setting("Allow Parkour Ascend", bSettings.allowParkourAscend.value).onValueChange { _, it -> bSettings.allowParkourAscend.value = it } + @Tab(BehaviorTab) @Group(MovementGroup) val allowDiagonalDescend by c.setting("Allow Diagonal Descend", bSettings.allowDiagonalDescend.value).onValueChange { _, it -> bSettings.allowDiagonalDescend.value = it } + @Tab(BehaviorTab) @Group(MovementGroup) val allowDiagonalAscend by c.setting("Allow Diagonal Ascend", bSettings.allowDiagonalAscend.value).onValueChange { _, it -> bSettings.allowDiagonalAscend.value = it } + @Tab(BehaviorTab) @Group(MovementGroup) val allowDownward by c.setting("Allow Downward", bSettings.allowDownward.value).onValueChange { _, it -> bSettings.allowDownward.value = it } + @Tab(BehaviorTab) @Group(MovementGroup) val allowVines by c.setting("Allow Vines", bSettings.allowVines.value).onValueChange { _, it -> bSettings.allowVines.value = it } + @Tab(BehaviorTab) @Group(MovementGroup) val allowWalkOnBottomSlab by c.setting("Allow Walk On Bottom Slab", bSettings.allowWalkOnBottomSlab.value).onValueChange { _, it -> bSettings.allowWalkOnBottomSlab.value = it } + @Tab(BehaviorTab) @Group(MovementGroup) val allowParkour by c.setting("Allow Parkour", bSettings.allowParkour.value).onValueChange { _, it -> bSettings.allowParkour.value = it } + @Tab(BehaviorTab) @Group(MovementGroup) val allowParkourPlace by c.setting("Allow Parkour Place", bSettings.allowParkourPlace.value).onValueChange { _, it -> bSettings.allowParkourPlace.value = it } + @Tab(BehaviorTab) @Group(MovementGroup) val sprintAscends by c.setting("Sprint Ascends", bSettings.sprintAscends.value).onValueChange { _, it -> bSettings.sprintAscends.value = it } + @Tab(BehaviorTab) @Group(MovementGroup) val overshootTraverse by c.setting("Overshoot Traverse", bSettings.overshootTraverse.value).onValueChange { _, it -> bSettings.overshootTraverse.value = it } + @Tab(BehaviorTab) @Group(MovementGroup) val pauseMiningForFallingBlocks by c.setting("Pause Mining For Falling Blocks", bSettings.pauseMiningForFallingBlocks.value).onValueChange { _, it -> bSettings.pauseMiningForFallingBlocks.value = it } + @Tab(BehaviorTab) @Group(MovementGroup) val allowOvershootDiagonalDescend by c.setting("Allow Overshoot Diagonal Descend", bSettings.allowOvershootDiagonalDescend.value).onValueChange { _, it -> bSettings.allowOvershootDiagonalDescend.value = it } + @Tab(BehaviorTab) @Group(MovementGroup) val sprintInWater by c.setting("Sprint In Water", bSettings.sprintInWater.value).onValueChange { _, it -> bSettings.sprintInWater.value = it } + @Tab(BehaviorTab) @Group(InteractionGroup) val allowBreak by c.setting("Allow Break", bSettings.allowBreak.value).onValueChange { _, it -> bSettings.allowBreak.value = it } + @Tab(BehaviorTab) @Group(InteractionGroup) val allowBreakAnyway by c.setting("Allow Break Anyway", bSettings.allowBreakAnyway.value).onValueChange { _, it -> bSettings.allowBreakAnyway.value = it.toList() } + @Tab(BehaviorTab) @Group(InteractionGroup) val allowSprint by c.setting("Allow Sprint", bSettings.allowSprint.value).onValueChange { _, it -> bSettings.allowSprint.value = it } + @Tab(BehaviorTab) @Group(InteractionGroup) val allowPlace by c.setting("Allow Place", bSettings.allowPlace.value).onValueChange { _, it -> bSettings.allowPlace.value = it } + @Tab(BehaviorTab) @Group(InteractionGroup) val allowPlaceInFluidsSource by c.setting("Allow Place In Fluids Source", bSettings.allowPlaceInFluidsSource.value).onValueChange { _, it -> bSettings.allowPlaceInFluidsSource.value = it } + @Tab(BehaviorTab) @Group(InteractionGroup) val allowPlaceInFluidsFlow by c.setting("Allow Place In Fluids Flow", bSettings.allowPlaceInFluidsFlow.value).onValueChange { _, it -> bSettings.allowPlaceInFluidsFlow.value = it } + @Tab(BehaviorTab) @Group(InteractionGroup) val allowInventory by c.setting("Allow Inventory", bSettings.allowInventory.value).onValueChange { _, it -> bSettings.allowInventory.value = it } + @Tab(BehaviorTab) @Group(InteractionGroup) val ticksBetweenInventoryMoves by c.setting("Ticks Between Inventory Moves", bSettings.ticksBetweenInventoryMoves.value, 0..20).onValueChange { _, it -> bSettings.ticksBetweenInventoryMoves.value = it } + @Tab(BehaviorTab) @Group(InteractionGroup) val inventoryMoveOnlyIfStationary by c.setting("Inventory Move Only If Stationary", bSettings.inventoryMoveOnlyIfStationary.value).onValueChange { _, it -> bSettings.inventoryMoveOnlyIfStationary.value = it } + @Tab(BehaviorTab) @Group(InteractionGroup) val autoTool by c.setting("Auto Tool", bSettings.autoTool.value).onValueChange { _, it -> bSettings.autoTool.value = it } + @Tab(BehaviorTab) @Group(InteractionGroup) val allowWaterBucketFall by c.setting("Allow Water Bucket Fall", bSettings.allowWaterBucketFall.value).onValueChange { _, it -> bSettings.allowWaterBucketFall.value = it } + @Tab(BehaviorTab) @Group(InteractionGroup) val allowJumpAtBuildLimit by c.setting("Allow Jump At Build Limit", bSettings.allowJumpAtBuildLimit.value).onValueChange { _, it -> bSettings.allowJumpAtBuildLimit.value = it } + @Tab(BehaviorTab) @Group(InteractionGroup) val rightClickContainerOnArrival by c.setting("Right Click Container On Arrival", bSettings.rightClickContainerOnArrival.value).onValueChange { _, it -> bSettings.rightClickContainerOnArrival.value = it } + @Tab(BehaviorTab) @Group(InteractionGroup) val enterPortal by c.setting("Enter Portal", bSettings.enterPortal.value).onValueChange { _, it -> bSettings.enterPortal.value = it } + @Tab(BehaviorTab) @Group(InteractionGroup) val walkWhileBreaking by c.setting("Walk While Breaking", bSettings.walkWhileBreaking.value).onValueChange { _, it -> bSettings.walkWhileBreaking.value = it } + @Tab(BehaviorTab) @Group(InteractionGroup) val useSwordToMine by c.setting("Use Sword To Mine", bSettings.useSwordToMine.value).onValueChange { _, it -> bSettings.useSwordToMine.value = it } + @Tab(BehaviorTab) @Group(InteractionGroup) val rightClickSpeed by c.setting("Right Click Speed", bSettings.rightClickSpeed.value, 0..10).onValueChange { _, it -> bSettings.rightClickSpeed.value = it } + @Tab(BehaviorTab) @Group(InteractionGroup) val blockReachDistance by c.setting("Block Reach Distance", bSettings.blockReachDistance.value, 0f..10f, 0.1f).onValueChange { _, it -> bSettings.blockReachDistance.value = it } + @Tab(BehaviorTab) @Group(InteractionGroup) val blockBreakSpeed by c.setting("Block Break Speed", bSettings.blockBreakSpeed.value, 0..10).onValueChange { _, it -> bSettings.blockBreakSpeed.value = it } + @Tab(BehaviorTab) @Group(InteractionGroup) val randomLooking113 by c.setting("Random Looking 1.13", bSettings.randomLooking113.value, 0.0..5.0, 0.01).onValueChange { _, it -> bSettings.randomLooking113.value = it } + @Tab(BehaviorTab) @Group(InteractionGroup) val randomLooking by c.setting("Random Looking", bSettings.randomLooking.value, 0.0..1.0, 0.01).onValueChange { _, it -> bSettings.randomLooking.value = it } + @Tab(BehaviorTab) @Group(InteractionGroup) val freeLook by c.setting("Free Look", bSettings.freeLook.value).onValueChange { _, it -> bSettings.freeLook.value = it } + @Tab(BehaviorTab) @Group(InteractionGroup) val blockFreeLook by c.setting("Block Free Look", bSettings.blockFreeLook.value).onValueChange { _, it -> bSettings.blockFreeLook.value = it } + @Tab(BehaviorTab) @Group(InteractionGroup) val elytraFreeLook by c.setting("Elytra Free Look", bSettings.elytraFreeLook.value).onValueChange { _, it -> bSettings.elytraFreeLook.value = it } + @Tab(BehaviorTab) @Group(InteractionGroup) val smoothLook by c.setting("Smooth Look", bSettings.smoothLook.value).onValueChange { _, it -> bSettings.smoothLook.value = it } + @Tab(BehaviorTab) @Group(InteractionGroup) val elytraSmoothLook by c.setting("Elytra Smooth Look", bSettings.elytraSmoothLook.value).onValueChange { _, it -> bSettings.elytraSmoothLook.value = it } + @Tab(BehaviorTab) @Group(InteractionGroup) val smoothLookTicks by c.setting("Smooth Look Ticks", bSettings.smoothLookTicks.value, 0..200).onValueChange { _, it -> bSettings.smoothLookTicks.value = it } + @Tab(BehaviorTab) @Group(InteractionGroup) val remainWithExistingLookDirection by c.setting("Remain With Existing Look Direction", bSettings.remainWithExistingLookDirection.value).onValueChange { _, it -> bSettings.remainWithExistingLookDirection.value = it } + @Tab(BehaviorTab) @Group(PenaltiesGroup) val blockPlacementPenalty by c.setting("Block Placement Penalty", bSettings.blockPlacementPenalty.value, 0.0..100.0, 0.1).onValueChange { _, it -> bSettings.blockPlacementPenalty.value = it } + @Tab(BehaviorTab) @Group(PenaltiesGroup) val blockBreakAdditionalPenalty by c.setting("Block Break Additional Penalty", bSettings.blockBreakAdditionalPenalty.value, 0.0..100.0, 0.1).onValueChange { _, it -> bSettings.blockBreakAdditionalPenalty.value = it } + @Tab(BehaviorTab) @Group(PenaltiesGroup) val jumpPenalty by c.setting("Jump Penalty", bSettings.jumpPenalty.value, 0.0..100.0, 0.1).onValueChange { _, it -> bSettings.jumpPenalty.value = it } + @Tab(BehaviorTab) @Group(PenaltiesGroup) val walkOnWaterOnePenalty by c.setting("Walk On Water One Penalty", bSettings.walkOnWaterOnePenalty.value, 0.0..100.0, 0.1).onValueChange { _, it -> bSettings.walkOnWaterOnePenalty.value = it } + @Tab(BehaviorTab) @Group(PenaltiesGroup) val avoidBreakingMultiplier by c.setting("Avoid Breaking Multiplier", bSettings.avoidBreakingMultiplier.value, 0.0..100.0, 0.1).onValueChange { _, it -> bSettings.avoidBreakingMultiplier.value = it } + @Tab(BehaviorTab) @Group(PenaltiesGroup) val maxCostIncrease by c.setting("Max Cost Increase", bSettings.maxCostIncrease.value, 0.0..100.0).onValueChange { _, it -> bSettings.maxCostIncrease.value = it } + @Tab(BehaviorTab) @Group(PenaltiesGroup) val backtrackCostFavoringCoefficient by c.setting("Backtrack Cost Favoring Coefficient", bSettings.backtrackCostFavoringCoefficient.value, 0.0..100.0, 0.1).onValueChange { _, it -> bSettings.backtrackCostFavoringCoefficient.value = it } + @Tab(BehaviorTab) @Group(PenaltiesGroup) val mobSpawnerAvoidanceCoefficient by c.setting("Mob Spawner Avoidance Coefficient", bSettings.mobSpawnerAvoidanceCoefficient.value, 0.0..100.0, 0.1).onValueChange { _, it -> bSettings.mobSpawnerAvoidanceCoefficient.value = it } + @Tab(BehaviorTab) @Group(PenaltiesGroup) val mobSpawnerAvoidanceRadius by c.setting("Mob Spawner Avoidance Radius", bSettings.mobSpawnerAvoidanceRadius.value, 0..1000).onValueChange { _, it -> bSettings.mobSpawnerAvoidanceRadius.value = it } + @Tab(BehaviorTab) @Group(PenaltiesGroup) val mobAvoidanceCoefficient by c.setting("Mob Avoidance Coefficient", bSettings.mobAvoidanceCoefficient.value, 0.0..100.0, 0.1).onValueChange { _, it -> bSettings.mobAvoidanceCoefficient.value = it } + @Tab(BehaviorTab) @Group(PenaltiesGroup) val mobAvoidanceRadius by c.setting("Mob Avoidance Radius", bSettings.mobAvoidanceRadius.value, 0..1000).onValueChange { _, it -> bSettings.mobAvoidanceRadius.value = it } + @Tab(BehaviorTab) @Group(PenaltiesGroup) val pathCutoffFactor by c.setting("Path Cutoff Factor", bSettings.pathCutoffFactor.value, 0.0..100.0, 0.1).onValueChange { _, it -> bSettings.pathCutoffFactor.value = it } + @Tab(BehaviorTab) @Group(PenaltiesGroup) val breakCorrectBlockPenaltyMultiplier by c.setting("Break Correct Block Penalty Multiplier", bSettings.breakCorrectBlockPenaltyMultiplier.value, 0.0..100.0, 0.1).onValueChange { _, it -> bSettings.breakCorrectBlockPenaltyMultiplier.value = it } + @Tab(BehaviorTab) @Group(PenaltiesGroup) val placeIncorrectBlockPenaltyMultiplier by c.setting("Place Incorrect Block Penalty Multiplier", bSettings.placeIncorrectBlockPenaltyMultiplier.value, 0.0..100.0, 0.1).onValueChange { _, it -> bSettings.placeIncorrectBlockPenaltyMultiplier.value = it } + @Tab(BehaviorTab) @Group(PenaltiesGroup) val costHeuristic by c.setting("Cost Heuristic", bSettings.costHeuristic.value, 0.0..10.0, 0.001).onValueChange { _, it -> bSettings.costHeuristic.value = it } + @Tab(BehaviorTab) @Group(MiningAndFarmingGroup) val itemSaver by c.setting("Item Saver", bSettings.itemSaver.value).onValueChange { _, it -> bSettings.itemSaver.value = it } + @Tab(BehaviorTab) @Group(MiningAndFarmingGroup) val itemSaverThreshold by c.setting("Item Saver Threshold", bSettings.itemSaverThreshold.value, 0..100).onValueChange { _, it -> bSettings.itemSaverThreshold.value = it } + @Tab(BehaviorTab) @Group(MiningAndFarmingGroup) val preferSilkTouch by c.setting("Prefer Silk Touch", bSettings.preferSilkTouch.value).onValueChange { _, it -> bSettings.preferSilkTouch.value = it } + @Tab(BehaviorTab) @Group(MiningAndFarmingGroup) val mineScanDroppedItems by c.setting("Mine Scan Dropped Items", bSettings.mineScanDroppedItems.value).onValueChange { _, it -> bSettings.mineScanDroppedItems.value = it } + @Tab(BehaviorTab) @Group(MiningAndFarmingGroup) val mineDropLoiterDurationMSThanksLouca by c.setting("Mine Drop Loiter Duration", bSettings.mineDropLoiterDurationMSThanksLouca.value, 0L..600000L, unit = " ms").onValueChange { _, it -> bSettings.mineDropLoiterDurationMSThanksLouca.value = it } + @Tab(BehaviorTab) @Group(MiningAndFarmingGroup) val legitMine by c.setting("Legit Mine", bSettings.legitMine.value).onValueChange { _, it -> bSettings.legitMine.value = it } + @Tab(BehaviorTab) @Group(MiningAndFarmingGroup) val legitMineYLevel by c.setting("Legit Mine Y Level", bSettings.legitMineYLevel.value, 0..256).onValueChange { _, it -> bSettings.legitMineYLevel.value = it } + @Tab(BehaviorTab) @Group(MiningAndFarmingGroup) val legitMineIncludeDiagonals by c.setting("Legit Mine Include Diagonals", bSettings.legitMineIncludeDiagonals.value).onValueChange { _, it -> bSettings.legitMineIncludeDiagonals.value = it } + @Tab(BehaviorTab) @Group(MiningAndFarmingGroup) val forceInternalMining by c.setting("Force Internal Mining", bSettings.forceInternalMining.value).onValueChange { _, it -> bSettings.forceInternalMining.value = it } + @Tab(BehaviorTab) @Group(MiningAndFarmingGroup) val internalMiningAirException by c.setting("Internal Mining Air Exception", bSettings.internalMiningAirException.value).onValueChange { _, it -> bSettings.internalMiningAirException.value = it } + @Tab(BehaviorTab) @Group(MiningAndFarmingGroup) val minYLevelWhileMining by c.setting("Min Y Level While Mining", bSettings.minYLevelWhileMining.value, 0..2048).onValueChange { _, it -> bSettings.minYLevelWhileMining.value = it } + @Tab(BehaviorTab) @Group(MiningAndFarmingGroup) val maxYLevelWhileMining by c.setting("Max Y Level While Mining", bSettings.maxYLevelWhileMining.value, 0..2048).onValueChange { _, it -> bSettings.maxYLevelWhileMining.value = it } + @Tab(BehaviorTab) @Group(MiningAndFarmingGroup) val allowOnlyExposedOres by c.setting("Allow Only Exposed Ores", bSettings.allowOnlyExposedOres.value).onValueChange { _, it -> bSettings.allowOnlyExposedOres.value = it } + @Tab(BehaviorTab) @Group(MiningAndFarmingGroup) val allowOnlyExposedOresDistance by c.setting("Allow Only Exposed Ores Distance", bSettings.allowOnlyExposedOresDistance.value, 0..16).onValueChange { _, it -> bSettings.allowOnlyExposedOresDistance.value = it } + @Tab(BehaviorTab) @Group(MiningAndFarmingGroup) val replantCrops by c.setting("Replant Crops", bSettings.replantCrops.value).onValueChange { _, it -> bSettings.replantCrops.value = it } + @Tab(BehaviorTab) @Group(MiningAndFarmingGroup) val replantNetherWart by c.setting("Replant Nether Wart", bSettings.replantNetherWart.value).onValueChange { _, it -> bSettings.replantNetherWart.value = it } + @Tab(BehaviorTab) @Group(MiningAndFarmingGroup) val farmMaxScanSize by c.setting("Farm Max Scan Size", bSettings.farmMaxScanSize.value, 0..1024).onValueChange { _, it -> bSettings.farmMaxScanSize.value = it } + @Tab(BehaviorTab) @Group(MiningAndFarmingGroup) val considerPotionEffects by c.setting("Consider Potion Effects", bSettings.considerPotionEffects.value).onValueChange { _, it -> bSettings.considerPotionEffects.value = it } + @Tab(BehaviorTab) @Group(ExplorationGroup) val exploreForBlocks by c.setting("Explore For Blocks", bSettings.exploreForBlocks.value).onValueChange { _, it -> bSettings.exploreForBlocks.value = it } + @Tab(BehaviorTab) @Group(ExplorationGroup) val worldExploringChunkOffset by c.setting("World Exploring Chunk Offset", bSettings.worldExploringChunkOffset.value, 0..32).onValueChange { _, it -> bSettings.worldExploringChunkOffset.value = it } + @Tab(BehaviorTab) @Group(ExplorationGroup) val exploreChunkSetMinimumSize by c.setting("Explore Chunk Set Minimum Size", bSettings.exploreChunkSetMinimumSize.value, 0..10000).onValueChange { _, it -> bSettings.exploreChunkSetMinimumSize.value = it } + @Tab(BehaviorTab) @Group(ExplorationGroup) val exploreMaintainY by c.setting("Explore Maintain Y", bSettings.exploreMaintainY.value, 0..256).onValueChange { _, it -> bSettings.exploreMaintainY.value = it } + @Tab(BuildingTab) @Group(SchematicGroup) val buildInLayers by c.setting("Build In Layers", bSettings.buildInLayers.value).onValueChange { _, it -> bSettings.buildInLayers.value = it } + @Tab(BuildingTab) @Group(SchematicGroup) val layerOrder by c.setting("Layer Order", bSettings.layerOrder.value).onValueChange { _, it -> bSettings.layerOrder.value = it } + @Tab(BuildingTab) @Group(SchematicGroup) val layerHeight by c.setting("Layer Height", bSettings.layerHeight.value, 0..256).onValueChange { _, it -> bSettings.layerHeight.value = it } + @Tab(BuildingTab) @Group(SchematicGroup) val startAtLayer by c.setting("Start At Layer", bSettings.startAtLayer.value, 0..256).onValueChange { _, it -> bSettings.startAtLayer.value = it } + @Tab(BuildingTab) @Group(SchematicGroup) val skipFailedLayers by c.setting("Skip Failed Layers", bSettings.skipFailedLayers.value).onValueChange { _, it -> bSettings.skipFailedLayers.value = it } + @Tab(BuildingTab) @Group(SchematicGroup) val buildOnlySelection by c.setting("Build Only Selection", bSettings.buildOnlySelection.value).onValueChange { _, it -> bSettings.buildOnlySelection.value = it } + @Tab(BuildingTab) @Group(SchematicGroup) val buildRepeat by c.setting("Build Repeat", bSettings.buildRepeat.value.blockPos).onValueChange { _, it -> bSettings.buildRepeat.value = it } + @Tab(BuildingTab) @Group(SchematicGroup) val buildRepeatCount by c.setting("Build Repeat Count", bSettings.buildRepeatCount.value, 0..1000).onValueChange { _, it -> bSettings.buildRepeatCount.value = it } + @Tab(BuildingTab) @Group(SchematicGroup) val buildRepeatSneaky by c.setting("Build Repeat Sneaky", bSettings.buildRepeatSneaky.value).onValueChange { _, it -> bSettings.buildRepeatSneaky.value = it } + @Tab(BuildingTab) @Group(SchematicGroup) val breakFromAbove by c.setting("Break From Above", bSettings.breakFromAbove.value).onValueChange { _, it -> bSettings.breakFromAbove.value = it } + @Tab(BuildingTab) @Group(SchematicGroup) val goalBreakFromAbove by c.setting("Goal Break From Above", bSettings.goalBreakFromAbove.value).onValueChange { _, it -> bSettings.goalBreakFromAbove.value = it } + @Tab(BuildingTab) @Group(SchematicGroup) val mapArtMode by c.setting("Map Art Mode", bSettings.mapArtMode.value).onValueChange { _, it -> bSettings.mapArtMode.value = it } + @Tab(BuildingTab) @Group(SchematicGroup) val okIfWater by c.setting("Ok If Water", bSettings.okIfWater.value).onValueChange { _, it -> bSettings.okIfWater.value = it } + @Tab(BuildingTab) @Group(SchematicGroup) val incorrectSize by c.setting("Incorrect Size", bSettings.incorrectSize.value, 0..1000).onValueChange { _, it -> bSettings.incorrectSize.value = it } + @Tab(BuildingTab) @Group(SchematicGroup) val schematicOrientationX by c.setting("Schematic Orientation X", bSettings.schematicOrientationX.value).onValueChange { _, it -> bSettings.schematicOrientationX.value = it } + @Tab(BuildingTab) @Group(SchematicGroup) val schematicOrientationY by c.setting("Schematic Orientation Y", bSettings.schematicOrientationY.value).onValueChange { _, it -> bSettings.schematicOrientationY.value = it } + @Tab(BuildingTab) @Group(SchematicGroup) val schematicOrientationZ by c.setting("Schematic Orientation Z", bSettings.schematicOrientationZ.value).onValueChange { _, it -> bSettings.schematicOrientationZ.value = it } + @Tab(BuildingTab) @Group(SchematicGroup) val buildSchematicRotation: BlockRotation by c.setting("Build Schematic Rotation", bSettings.buildSchematicRotation.value).onValueChange { _, it -> bSettings.buildSchematicRotation.value = it } + @Tab(BuildingTab) @Group(SchematicGroup) val buildSchematicMirror: BlockMirror by c.setting("Build Schematic Mirror", bSettings.buildSchematicMirror.value).onValueChange { _, it -> bSettings.buildSchematicMirror.value = it } + @Tab(BuildingTab) @Group(SchematicGroup) val schematicFallbackExtension by c.setting("Schematic Fallback Extension", bSettings.schematicFallbackExtension.value).onValueChange { _, it -> bSettings.schematicFallbackExtension.value = it } + @Tab(BuildingTab) @Group(SchematicGroup) val builderTickScanRadius by c.setting("Builder Tick Scan Radius", bSettings.builderTickScanRadius.value, 0..64).onValueChange { _, it -> bSettings.builderTickScanRadius.value = it } + @Tab(BuildingTab) @Group(BlockRulesGroup) val acceptableThrowawayItems by c.setting("Acceptable Throwaway Items", bSettings.acceptableThrowawayItems.value).onValueChange { _, it -> bSettings.acceptableThrowawayItems.value = it.toList() } + @Tab(BuildingTab) @Group(BlockRulesGroup) val blocksToAvoid by c.setting("Blocks To Avoid", bSettings.blocksToAvoid.value).onValueChange { _, it -> bSettings.blocksToAvoid.value = it.toList() } + @Tab(BuildingTab) @Group(BlockRulesGroup) val blocksToDisallowBreaking by c.setting("Blocks To Disallow Breaking", bSettings.blocksToDisallowBreaking.value).onValueChange { _, it -> bSettings.blocksToDisallowBreaking.value = it.toList() } + @Tab(BuildingTab) @Group(BlockRulesGroup) val blocksToAvoidBreaking by c.setting("Blocks To Avoid Breaking", bSettings.blocksToAvoidBreaking.value).onValueChange { _, it -> bSettings.blocksToAvoidBreaking.value = it.toList() } + @Tab(BuildingTab) @Group(BlockRulesGroup) val buildIgnoreBlocks by c.setting("Build Ignore Blocks", bSettings.buildIgnoreBlocks.value).onValueChange { _, it -> bSettings.buildIgnoreBlocks.value = it.toList() } + @Tab(BuildingTab) @Group(BlockRulesGroup) val buildSkipBlocks by c.setting("Build Skip Blocks", bSettings.buildSkipBlocks.value).onValueChange { _, it -> bSettings.buildSkipBlocks.value = it.toList() } + @Tab(BuildingTab) @Group(BlockRulesGroup) val buildValidSubstitutes by c.setting("Build Valid Substitutes", bSettings.buildValidSubstitutes.value).onValueChange { _, it -> bSettings.buildValidSubstitutes.value = it.mapValues { (_, v) -> v.toList() } } + @Tab(BuildingTab) @Group(BlockRulesGroup) val buildSubstitutes by c.setting("Build Substitutes", bSettings.buildSubstitutes.value).onValueChange { _, it -> bSettings.buildSubstitutes.value = it.mapValues { (_, v) -> v.toList() } } + @Tab(BuildingTab) @Group(BlockRulesGroup) val okIfAir by c.setting("Ok If Air", bSettings.okIfAir.value).onValueChange { _, it -> bSettings.okIfAir.value = it.toList() } + @Tab(BuildingTab) @Group(BlockRulesGroup) val buildIgnoreExisting by c.setting("Build Ignore Existing", bSettings.buildIgnoreExisting.value).onValueChange { _, it -> bSettings.buildIgnoreExisting.value = it } + @Tab(BuildingTab) @Group(BlockRulesGroup) val buildIgnoreDirection by c.setting("Build Ignore Direction", bSettings.buildIgnoreDirection.value).onValueChange { _, it -> bSettings.buildIgnoreDirection.value = it } + @Tab(BuildingTab) @Group(BlockRulesGroup) val buildIgnoreProperties by c.setting("Build Ignore Properties", bSettings.buildIgnoreProperties.value).onValueChange { _, it -> bSettings.buildIgnoreProperties.value = it.toList() } + @Tab(BuildingTab) @Group(BlockRulesGroup) val avoidUpdatingFallingBlocks by c.setting("Avoid Updating Falling Blocks", bSettings.avoidUpdatingFallingBlocks.value).onValueChange { _, it -> bSettings.avoidUpdatingFallingBlocks.value = it } + @Tab(RenderingTab) @Group(RenderingGroup) val renderPath by c.setting("Render Path", bSettings.renderPath.value).onValueChange { _, it -> bSettings.renderPath.value = it } + @Tab(RenderingTab) @Group(RenderingGroup) val renderPathAsLine by c.setting("Render Path As Line", bSettings.renderPathAsLine.value).onValueChange { _, it -> bSettings.renderPathAsLine.value = it } + @Tab(RenderingTab) @Group(RenderingGroup) val renderGoal by c.setting("Render Goal", bSettings.renderGoal.value).onValueChange { _, it -> bSettings.renderGoal.value = it } + @Tab(RenderingTab) @Group(RenderingGroup) val renderGoalAnimated by c.setting("Render Goal Animated", bSettings.renderGoalAnimated.value).onValueChange { _, it -> bSettings.renderGoalAnimated.value = it } + @Tab(RenderingTab) @Group(RenderingGroup) val renderGoalIgnoreDepth by c.setting("Render Goal Ignore Depth", bSettings.renderGoalIgnoreDepth.value).onValueChange { _, it -> bSettings.renderGoalIgnoreDepth.value = it } + @Tab(RenderingTab) @Group(RenderingGroup) val renderGoalXZBeacon by c.setting("Render Goal XZ Beacon", bSettings.renderGoalXZBeacon.value).onValueChange { _, it -> bSettings.renderGoalXZBeacon.value = it } + @Tab(RenderingTab) @Group(RenderingGroup) val pathRenderLineWidthPixels by c.setting("Path Render Line Width Pixels", bSettings.pathRenderLineWidthPixels.value, 0f..10f, 0.1f).onValueChange { _, it -> bSettings.pathRenderLineWidthPixels.value = it } + @Tab(RenderingTab) @Group(RenderingGroup) val goalRenderLineWidthPixels by c.setting("Goal Render Line Width Pixels", bSettings.goalRenderLineWidthPixels.value, 0f..10f, 0.1f).onValueChange { _, it -> bSettings.goalRenderLineWidthPixels.value = it } + @Tab(RenderingTab) @Group(RenderingGroup) val fadePath by c.setting("Fade Path", bSettings.fadePath.value).onValueChange { _, it -> bSettings.fadePath.value = it } + @Tab(RenderingTab) @Group(RenderingGroup) val renderCachedChunks by c.setting("Render Cached Chunks", bSettings.renderCachedChunks.value).onValueChange { _, it -> bSettings.renderCachedChunks.value = it } + @Tab(RenderingTab) @Group(RenderingGroup) val cachedChunksOpacity by c.setting("Cached Chunks Opacity", bSettings.cachedChunksOpacity.value, 0f..1f, 0.05f).onValueChange { _, it -> bSettings.cachedChunksOpacity.value = it } + @Tab(RenderingTab) @Group(RenderingGroup) val renderPathIgnoreDepth by c.setting("Render Path Ignore Depth", bSettings.renderPathIgnoreDepth.value).onValueChange { _, it -> bSettings.renderPathIgnoreDepth.value = it } + @Tab(RenderingTab) @Group(RenderingGroup) val renderSelectionBoxes by c.setting("Render Selection Boxes", bSettings.renderSelectionBoxes.value).onValueChange { _, it -> bSettings.renderSelectionBoxes.value = it } + @Tab(RenderingTab) @Group(RenderingColorsGroup) val colorCurrentPath by c.setting("Color Current Path", bSettings.colorCurrentPath.value).onValueChange { _, it -> bSettings.colorCurrentPath.value = it } + @Tab(RenderingTab) @Group(RenderingColorsGroup) val colorNextPath by c.setting("Color Next Path", bSettings.colorNextPath.value).onValueChange { _, it -> bSettings.colorNextPath.value = it } + @Tab(RenderingTab) @Group(RenderingColorsGroup) val colorBlocksToBreak by c.setting("Color Blocks To Break", bSettings.colorBlocksToBreak.value).onValueChange { _, it -> bSettings.colorBlocksToBreak.value = it } + @Tab(RenderingTab) @Group(RenderingColorsGroup) val colorBlocksToPlace by c.setting("Color Blocks To Place", bSettings.colorBlocksToPlace.value).onValueChange { _, it -> bSettings.colorBlocksToPlace.value = it } + @Tab(RenderingTab) @Group(RenderingColorsGroup) val colorBlocksToWalkInto by c.setting("Color Blocks To Walk Into", bSettings.colorBlocksToWalkInto.value).onValueChange { _, it -> bSettings.colorBlocksToWalkInto.value = it } + @Tab(RenderingTab) @Group(RenderingColorsGroup) val colorBestPathSoFar by c.setting("Color Best Path So Far", bSettings.colorBestPathSoFar.value).onValueChange { _, it -> bSettings.colorBestPathSoFar.value = it } + @Tab(RenderingTab) @Group(RenderingColorsGroup) val colorMostRecentConsidered by c.setting("Color Most Recent Considered", bSettings.colorMostRecentConsidered.value).onValueChange { _, it -> bSettings.colorMostRecentConsidered.value = it } + @Tab(RenderingTab) @Group(RenderingColorsGroup) val colorGoalBox by c.setting("Color Goal Box", bSettings.colorGoalBox.value).onValueChange { _, it -> bSettings.colorGoalBox.value = it } + @Tab(RenderingTab) @Group(RenderingColorsGroup) val colorInvertedGoalBox by c.setting("Color Inverted Goal Box", bSettings.colorInvertedGoalBox.value).onValueChange { _, it -> bSettings.colorInvertedGoalBox.value = it } + @Tab(RenderingTab) @Group(RenderingSelectionGroup) val renderSelection by c.setting("Render Selection", bSettings.renderSelection.value).onValueChange { _, it -> bSettings.renderSelection.value = it } + @Tab(RenderingTab) @Group(RenderingSelectionGroup) val colorSelection by c.setting("Color Selection", bSettings.colorSelection.value).onValueChange { _, it -> bSettings.colorSelection.value = it } + @Tab(RenderingTab) @Group(RenderingSelectionGroup) val colorSelectionPos1 by c.setting("Color Selection Pos1", bSettings.colorSelectionPos1.value).onValueChange { _, it -> bSettings.colorSelectionPos1.value = it } + @Tab(RenderingTab) @Group(RenderingSelectionGroup) val colorSelectionPos2 by c.setting("Color Selection Pos2", bSettings.colorSelectionPos2.value).onValueChange { _, it -> bSettings.colorSelectionPos2.value = it } + @Tab(RenderingTab) @Group(RenderingSelectionGroup) val selectionOpacity by c.setting("Selection Opacity", bSettings.selectionOpacity.value, 0f..1f, 0.05f).onValueChange { _, it -> bSettings.selectionOpacity.value = it } + @Tab(RenderingTab) @Group(RenderingSelectionGroup) val selectionLineWidth by c.setting("Selection Line Width", bSettings.selectionLineWidth.value, 0f..10f, 0.1f).onValueChange { _, it -> bSettings.selectionLineWidth.value = it } + @Tab(RenderingTab) @Group(RenderingSelectionGroup) val renderSelectionIgnoreDepth by c.setting("Render Selection Ignore Depth", bSettings.renderSelectionIgnoreDepth.value).onValueChange { _, it -> bSettings.renderSelectionIgnoreDepth.value = it } + @Tab(RenderingTab) @Group(RenderingSelectionGroup) val renderSelectionCorners by c.setting("Render Selection Corners", bSettings.renderSelectionCorners.value).onValueChange { _, it -> bSettings.renderSelectionCorners.value = it } + @Tab(RenderingTab) @Group(RenderingSelectionGroup) val renderSelectionBoxesIgnoreDepth by c.setting("Render Selection Boxes Ignore Depth", bSettings.renderSelectionBoxesIgnoreDepth.value).onValueChange { _, it -> bSettings.renderSelectionBoxesIgnoreDepth.value = it } + @Tab(ElytraTab) val elytraSimulationTicks by c.setting("Simulation Ticks", bSettings.elytraSimulationTicks.value, 0..200).onValueChange { _, it -> bSettings.elytraSimulationTicks.value = it } + @Tab(ElytraTab) val elytraPitchRange by c.setting("Pitch Range", bSettings.elytraPitchRange.value, 0..90).onValueChange { _, it -> bSettings.elytraPitchRange.value = it } + @Tab(ElytraTab) val elytraFireworkSpeed by c.setting("Firework Speed", bSettings.elytraFireworkSpeed.value, 0.0..3.0, 0.1).onValueChange { _, it -> bSettings.elytraFireworkSpeed.value = it } + @Tab(ElytraTab) val elytraFireworkSetbackUseDelay by c.setting("Firework Setback Use Delay", bSettings.elytraFireworkSetbackUseDelay.value, 0..600).onValueChange { _, it -> bSettings.elytraFireworkSetbackUseDelay.value = it } + @Tab(ElytraTab) val elytraMinimumAvoidance by c.setting("Minimum Avoidance", bSettings.elytraMinimumAvoidance.value, 0.0..10.0, 0.1).onValueChange { _, it -> bSettings.elytraMinimumAvoidance.value = it } + @Tab(ElytraTab) val elytraConserveFireworks by c.setting("Conserve Fireworks", bSettings.elytraConserveFireworks.value).onValueChange { _, it -> bSettings.elytraConserveFireworks.value = it } + @Tab(ElytraTab) val elytraRenderRaytraces by c.setting("Render Raytraces", bSettings.elytraRenderRaytraces.value).onValueChange { _, it -> bSettings.elytraRenderRaytraces.value = it } + @Tab(ElytraTab) val elytraRenderHitboxRaytraces by c.setting("Render Hitbox Raytraces", bSettings.elytraRenderHitboxRaytraces.value).onValueChange { _, it -> bSettings.elytraRenderHitboxRaytraces.value = it } + @Tab(ElytraTab) val elytraRenderSimulation by c.setting("Render Simulation", bSettings.elytraRenderSimulation.value).onValueChange { _, it -> bSettings.elytraRenderSimulation.value = it } + @Tab(ElytraTab) val elytraAutoJump by c.setting("Auto Jump", bSettings.elytraAutoJump.value).onValueChange { _, it -> bSettings.elytraAutoJump.value = it } + @Tab(ElytraTab) val elytraNetherSeed by c.setting("Nether Seed", bSettings.elytraNetherSeed.value, Long.MIN_VALUE..Long.MAX_VALUE).onValueChange { _, it -> bSettings.elytraNetherSeed.value = it } + @Tab(ElytraTab) val elytraPredictTerrain by c.setting("Predict Terrain", bSettings.elytraPredictTerrain.value).onValueChange { _, it -> bSettings.elytraPredictTerrain.value = it } + @Tab(ElytraTab) val elytraAutoSwap by c.setting("Auto Swap", bSettings.elytraAutoSwap.value).onValueChange { _, it -> bSettings.elytraAutoSwap.value = it } + @Tab(ElytraTab) val elytraMinimumDurability by c.setting("Minimum Durability", bSettings.elytraMinimumDurability.value, 0..432).onValueChange { _, it -> bSettings.elytraMinimumDurability.value = it } + @Tab(ElytraTab) val elytraMinFireworksBeforeLanding by c.setting("Min Fireworks Before Landing", bSettings.elytraMinFireworksBeforeLanding.value, 0..64).onValueChange { _, it -> bSettings.elytraMinFireworksBeforeLanding.value = it } + @Tab(ElytraTab) val elytraAllowEmergencyLand by c.setting("Allow Emergency Land", bSettings.elytraAllowEmergencyLand.value).onValueChange { _, it -> bSettings.elytraAllowEmergencyLand.value = it } + @Tab(ElytraTab) val elytraTimeBetweenCacheCullSecs by c.setting("Time Between Cache Cull Secs", bSettings.elytraTimeBetweenCacheCullSecs.value, 0L..86400L).onValueChange { _, it -> bSettings.elytraTimeBetweenCacheCullSecs.value = it } + @Tab(ElytraTab) val elytraCacheCullDistance by c.setting("Cache Cull Distance", bSettings.elytraCacheCullDistance.value, 0..100000).onValueChange { _, it -> bSettings.elytraCacheCullDistance.value = it } + @Tab(ElytraTab) val elytraAllowLandOnNetherFortress by c.setting("Allow Land On Nether Fortress", bSettings.elytraAllowLandOnNetherFortress.value).onValueChange { _, it -> bSettings.elytraAllowLandOnNetherFortress.value = it } + @Tab(ElytraTab) val elytraTermsAccepted by c.setting("Terms Accepted", bSettings.elytraTermsAccepted.value).onValueChange { _, it -> bSettings.elytraTermsAccepted.value = it } + @Tab(ElytraTab) val elytraChatSpam by c.setting("Chat Spam", bSettings.elytraChatSpam.value).onValueChange { _, it -> bSettings.elytraChatSpam.value = it } + } +} diff --git a/src/main/kotlin/com/lambda/interaction/BaritoneManager.kt b/src/main/kotlin/com/lambda/interaction/BaritoneManager.kt deleted file mode 100644 index e478ce96d..000000000 --- a/src/main/kotlin/com/lambda/interaction/BaritoneManager.kt +++ /dev/null @@ -1,389 +0,0 @@ -/* - * Copyright 2026 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.interaction - -import baritone.api.BaritoneAPI -import baritone.api.IBaritone -import baritone.api.Settings -import baritone.api.pathing.goals.Goal -import com.lambda.config.AutomationConfig -import com.lambda.config.Configurable -import com.lambda.config.configurations.LambdaConfig -import com.lambda.config.groups.RotationSettings -import com.lambda.context.Automated -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" - - 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 - - private enum class Group(override val displayName: String) : NamedEnum { - General("General"), - Rotation("Rotation"), - Pathing("Pathing"), - Behavior("Behavior"), - Building("Building"), - Rendering("Rendering"), - Elytra("Elytra") - } - - private enum class SubGroup(override val displayName: String) : NamedEnum { - ChatAndControl("Chat & Control"), - Waypoints("Waypoints"), - Assumptions("Assumptions"), - Movement("Movement"), - BlockRules("Block Rules"), - MiningAndFarming("Mining & Farming"), - Interaction("Interaction"), - Penalties("Penalties"), - Exploration("Exploration"), - Misc("Misc"), - Rendering("Rendering"), - RenderingColors("Rendering Colors"), - RenderingSelection("Rendering Selection"), - PathingPerformance("Pathing Performance"), - PathingCore("Pathing Core"), - Follow("Follow"), - Schematic("Schematic") - } - - override val rotationConfig = RotationSettings(this, Group.Rotation) - - init { - // ToDo: Dont actually save the settings as its duplicate data - if (isBaritoneLoaded) { - with(baritoneSettings!!) { - // GENERAL - setting("Log As Toast", logAsToast.value).group(Group.General, SubGroup.ChatAndControl).onValueChange { _, it -> logAsToast.value = it } - setting("Chat Debug", chatDebug.value).group(Group.General, SubGroup.ChatAndControl).onValueChange { _, it -> chatDebug.value = it } - setting("Chat Control", chatControl.value).group(Group.General, SubGroup.ChatAndControl).onValueChange { _, it -> chatControl.value = it } - setting("Chat Control Anyway", chatControlAnyway.value).group(Group.General, SubGroup.ChatAndControl).onValueChange { _, it -> chatControlAnyway.value = it } - setting("Prefix Control", prefixControl.value).group(Group.General, SubGroup.ChatAndControl).onValueChange { _, it -> prefixControl.value = it } - setting("Prefix", prefix.value).group(Group.General, SubGroup.ChatAndControl).onValueChange { _, it -> prefix.value = it } - setting("Short Baritone Prefix", shortBaritonePrefix.value).group(Group.General, SubGroup.ChatAndControl).onValueChange { _, it -> shortBaritonePrefix.value = it } - setting("Use Message Tag", useMessageTag.value).group(Group.General, SubGroup.ChatAndControl).onValueChange { _, it -> useMessageTag.value = it } - setting("Echo Commands", echoCommands.value).group(Group.General, SubGroup.ChatAndControl).onValueChange { _, it -> echoCommands.value = it } - setting("Censor Coordinates", censorCoordinates.value).group(Group.General, SubGroup.ChatAndControl).onValueChange { _, it -> censorCoordinates.value = it } - setting("Censor Ran Commands", censorRanCommands.value).group(Group.General, SubGroup.ChatAndControl).onValueChange { _, it -> censorRanCommands.value = it } - setting("Desktop Notifications", desktopNotifications.value).group(Group.General, SubGroup.ChatAndControl).onValueChange { _, it -> desktopNotifications.value = it } - setting("Notification On Path Complete", notificationOnPathComplete.value).group(Group.General, SubGroup.ChatAndControl).onValueChange { _, it -> notificationOnPathComplete.value = it } - setting("Notification On Farm Fail", notificationOnFarmFail.value).group(Group.General, SubGroup.ChatAndControl).onValueChange { _, it -> notificationOnFarmFail.value = it } - setting("Notification On Build Finished", notificationOnBuildFinished.value).group(Group.General, SubGroup.ChatAndControl).onValueChange { _, it -> notificationOnBuildFinished.value = it } - setting("Notification On Explore Finished", notificationOnExploreFinished.value).group(Group.General, SubGroup.ChatAndControl).onValueChange { _, it -> notificationOnExploreFinished.value = it } - setting("Notification On Mine Fail", notificationOnMineFail.value).group(Group.General, SubGroup.ChatAndControl).onValueChange { _, it -> notificationOnMineFail.value = it } - setting("Verbose Command Exceptions", verboseCommandExceptions.value).group(Group.General, SubGroup.ChatAndControl).onValueChange { _, it -> verboseCommandExceptions.value = it } - - setting("Do Bed Waypoints", doBedWaypoints.value).group(Group.General, SubGroup.Waypoints).onValueChange { _, it -> doBedWaypoints.value = it } - setting("Do Death Waypoints", doDeathWaypoints.value).group(Group.General, SubGroup.Waypoints).onValueChange { _, it -> doDeathWaypoints.value = it } - - setting("Anti Cheat Compatibility", antiCheatCompatibility.value).group(Group.General, SubGroup.Misc).onValueChange { _, it -> antiCheatCompatibility.value = it } - - // PATHING - setting("Pathing Max Chunk Border Fetch", pathingMaxChunkBorderFetch.value, 0..64).group(Group.Pathing, SubGroup.PathingCore).onValueChange { _, it -> pathingMaxChunkBorderFetch.value = it } - setting("Pathing Map Default Size", pathingMapDefaultSize.value, 0..2048).group(Group.Pathing, SubGroup.PathingCore).onValueChange { _, it -> pathingMapDefaultSize.value = it } - setting("Pathing Map Load Factor", pathingMapLoadFactor.value, 0f..1f, 0.05f).group(Group.Pathing, SubGroup.PathingCore).onValueChange { _, it -> pathingMapLoadFactor.value = it } - setting("Distance Trim", distanceTrim.value).group(Group.Pathing, SubGroup.PathingCore).onValueChange { _, it -> distanceTrim.value = it } - setting("Simplify Unloaded Y Coord", simplifyUnloadedYCoord.value).group(Group.Pathing, SubGroup.PathingCore).onValueChange { _, it -> simplifyUnloadedYCoord.value = it } - setting("Repack On Any Block Change", repackOnAnyBlockChange.value).group(Group.Pathing, SubGroup.PathingCore).onValueChange { _, it -> repackOnAnyBlockChange.value = it } - setting("Avoidance", avoidance.value).group(Group.Pathing, SubGroup.PathingCore).onValueChange { _, it -> avoidance.value = it } - setting("Prune Regions From RAM", pruneRegionsFromRAM.value).group(Group.Pathing, SubGroup.PathingCore).onValueChange { _, it -> pruneRegionsFromRAM.value = it } - setting("Backfill", backfill.value).group(Group.Pathing, SubGroup.PathingCore).onValueChange { _, it -> backfill.value = it } - setting("Max Fall Height No Water", maxFallHeightNoWater.value, 0..256).group(Group.Pathing, SubGroup.PathingCore).onValueChange { _, it -> maxFallHeightNoWater.value = it } - setting("Max Fall Height Bucket", maxFallHeightBucket.value, 0..256).group(Group.Pathing, SubGroup.PathingCore).onValueChange { _, it -> maxFallHeightBucket.value = it } - setting("Axis Height", axisHeight.value, 0..256).group(Group.Pathing, SubGroup.PathingCore).onValueChange { _, it -> axisHeight.value = it } - setting("Disconnect On Arrival", disconnectOnArrival.value).group(Group.Pathing, SubGroup.PathingCore).onValueChange { _, it -> disconnectOnArrival.value = it } - setting("Splice Path", splicePath.value).group(Group.Pathing, SubGroup.PathingCore).onValueChange { _, it -> splicePath.value = it } - setting("Max Path History Length", maxPathHistoryLength.value, 0..10000).group(Group.Pathing, SubGroup.PathingCore).onValueChange { _, it -> maxPathHistoryLength.value = it } - setting("Path History Cutoff Amount", pathHistoryCutoffAmount.value, 0..10000).group(Group.Pathing, SubGroup.PathingCore).onValueChange { _, it -> pathHistoryCutoffAmount.value = it } - setting("Mine Goal Update Interval", mineGoalUpdateInterval.value, 0..10000).group(Group.Pathing, SubGroup.PathingCore).onValueChange { _, it -> mineGoalUpdateInterval.value = it } - setting("Max Cached World Scan Count", maxCachedWorldScanCount.value, 0..100000).group(Group.Pathing, SubGroup.PathingCore).onValueChange { _, it -> maxCachedWorldScanCount.value = it } - setting("Mine Max Ore Locations Count", mineMaxOreLocationsCount.value, 0..100000).group(Group.Pathing, SubGroup.PathingCore).onValueChange { _, it -> mineMaxOreLocationsCount.value = it } - setting("Cached Chunks Expiry Seconds", cachedChunksExpirySeconds.value, -1L..86400L).group(Group.Pathing, SubGroup.PathingCore).onValueChange { _, it -> cachedChunksExpirySeconds.value = it } - setting("Y Level Box Size", yLevelBoxSize.value, 0.0..256.0).group(Group.Pathing, SubGroup.PathingCore).onValueChange { _, it -> yLevelBoxSize.value = it } - setting("Extend Cache On Threshold", extendCacheOnThreshold.value).group(Group.Pathing, SubGroup.PathingCore).onValueChange { _, it -> extendCacheOnThreshold.value = it } - setting("Cancel On Goal Invalidation", cancelOnGoalInvalidation.value).group(Group.Pathing, SubGroup.PathingCore).onValueChange { _, it -> cancelOnGoalInvalidation.value = it } - setting("Chunk Caching", chunkCaching.value).group(Group.Pathing, SubGroup.PathingCore).onValueChange { _, it -> chunkCaching.value = it } - setting("Chunk Packer Queue Max Size", chunkPackerQueueMaxSize.value, 0..10000).group(Group.Pathing, SubGroup.PathingCore).onValueChange { _, it -> chunkPackerQueueMaxSize.value = it } - setting("Path Through Cached Only", pathThroughCachedOnly.value).group(Group.Pathing, SubGroup.PathingCore).onValueChange { _, it -> pathThroughCachedOnly.value = it } - setting("Blacklist Closest On Failure", blacklistClosestOnFailure.value).group(Group.Pathing, SubGroup.PathingCore).onValueChange { _, it -> blacklistClosestOnFailure.value = it } - setting("Path Cutoff Minimum Length", pathCutoffMinimumLength.value, 0..1000).group(Group.Pathing, SubGroup.PathingCore).onValueChange { _, it -> pathCutoffMinimumLength.value = it } - setting("Cutoff At Load Boundary", cutoffAtLoadBoundary.value).group(Group.Pathing, SubGroup.PathingCore).onValueChange { _, it -> cutoffAtLoadBoundary.value = it } - setting("Minimum Improvement Repropagation", minimumImprovementRepropagation.value).group(Group.Pathing, SubGroup.PathingCore).onValueChange { _, it -> minimumImprovementRepropagation.value = it } - setting("Cost Verification Lookahead", costVerificationLookahead.value, 0..1000).group(Group.Pathing, SubGroup.PathingCore).onValueChange { _, it -> costVerificationLookahead.value = it } - - setting("Primary Timeout", primaryTimeoutMS.value, 0L..600000L, unit = " ms").group(Group.Pathing, SubGroup.PathingPerformance).onValueChange { _, it -> primaryTimeoutMS.value = it } - setting("Failure Timeout", failureTimeoutMS.value, 0L..600000L, unit = " ms").group(Group.Pathing, SubGroup.PathingPerformance).onValueChange { _, it -> failureTimeoutMS.value = it } - setting("Plan Ahead Primary Timeout", planAheadPrimaryTimeoutMS.value, 0L..600000L, unit = " ms").group(Group.Pathing, SubGroup.PathingPerformance).onValueChange { _, it -> planAheadPrimaryTimeoutMS.value = it } - setting("Plan Ahead Failure Timeout", planAheadFailureTimeoutMS.value, 0L..600000L, unit = " ms").group(Group.Pathing, SubGroup.PathingPerformance).onValueChange { _, it -> planAheadFailureTimeoutMS.value = it } - setting("Slow Path", slowPath.value).group(Group.Pathing, SubGroup.PathingPerformance).onValueChange { _, it -> slowPath.value = it } - setting("Slow Path Time Delay", slowPathTimeDelayMS.value, 0L..600000L, unit = " ms").group(Group.Pathing, SubGroup.PathingPerformance).onValueChange { _, it -> slowPathTimeDelayMS.value = it } - setting("Slow Path Timeout", slowPathTimeoutMS.value, 0L..600000L, unit = " ms").group(Group.Pathing, SubGroup.PathingPerformance).onValueChange { _, it -> slowPathTimeoutMS.value = it } - setting("Planning Tick Lookahead", planningTickLookahead.value, 0..200).group(Group.Pathing, SubGroup.PathingPerformance).onValueChange { _, it -> planningTickLookahead.value = it } - setting("Movement Timeout Ticks", movementTimeoutTicks.value, 0..2000).group(Group.Pathing, SubGroup.PathingPerformance).onValueChange { _, it -> movementTimeoutTicks.value = it } - - setting("Follow Offset Distance", followOffsetDistance.value, 0.0..256.0).group(Group.Pathing, SubGroup.Follow).onValueChange { _, it -> followOffsetDistance.value = it } - setting("Follow Offset Direction", followOffsetDirection.value, -180f..180f, 1f).group(Group.Pathing, SubGroup.Follow).onValueChange { _, it -> followOffsetDirection.value = it } - setting("Follow Radius", followRadius.value, 0..1000).group(Group.Pathing, SubGroup.Follow).onValueChange { _, it -> followRadius.value = it } - setting("Follow Target Max Distance", followTargetMaxDistance.value, 0..10000).group(Group.Pathing, SubGroup.Follow).onValueChange { _, it -> followTargetMaxDistance.value = it } - setting("Disable Completion Check", disableCompletionCheck.value).group(Group.Pathing, SubGroup.Follow).onValueChange { _, it -> disableCompletionCheck.value = it } - - // BEHAVIOR - setting("Strict Liquid Check", strictLiquidCheck.value).group(Group.Behavior, SubGroup.Assumptions).onValueChange { _, it -> strictLiquidCheck.value = it } - setting("Assume Walk On Water", assumeWalkOnWater.value).group(Group.Behavior, SubGroup.Assumptions).onValueChange { _, it -> assumeWalkOnWater.value = it } - setting("Assume Walk On Lava", assumeWalkOnLava.value).group(Group.Behavior, SubGroup.Assumptions).onValueChange { _, it -> assumeWalkOnLava.value = it } - setting("Assume Step", assumeStep.value).group(Group.Behavior, SubGroup.Assumptions).onValueChange { _, it -> assumeStep.value = it } - setting("Assume Safe Walk", assumeSafeWalk.value).group(Group.Behavior, SubGroup.Assumptions).onValueChange { _, it -> assumeSafeWalk.value = it } - setting("Assume External Auto Tool", assumeExternalAutoTool.value).group(Group.Behavior, SubGroup.Assumptions).onValueChange { _, it -> assumeExternalAutoTool.value = it } - - setting("Allow Parkour Ascend", allowParkourAscend.value).group(Group.Behavior, SubGroup.Movement).onValueChange { _, it -> allowParkourAscend.value = it } - setting("Allow Diagonal Descend", allowDiagonalDescend.value).group(Group.Behavior, SubGroup.Movement).onValueChange { _, it -> allowDiagonalDescend.value = it } - setting("Allow Diagonal Ascend", allowDiagonalAscend.value).group(Group.Behavior, SubGroup.Movement).onValueChange { _, it -> allowDiagonalAscend.value = it } - setting("Allow Downward", allowDownward.value).group(Group.Behavior, SubGroup.Movement).onValueChange { _, it -> allowDownward.value = it } - setting("Allow Vines", allowVines.value).group(Group.Behavior, SubGroup.Movement).onValueChange { _, it -> allowVines.value = it } - setting("Allow Walk On Bottom Slab", allowWalkOnBottomSlab.value).group(Group.Behavior, SubGroup.Movement).onValueChange { _, it -> allowWalkOnBottomSlab.value = it } - setting("Allow Parkour", allowParkour.value).group(Group.Behavior, SubGroup.Movement).onValueChange { _, it -> allowParkour.value = it } - setting("Allow Parkour Place", allowParkourPlace.value).group(Group.Behavior, SubGroup.Movement).onValueChange { _, it -> allowParkourPlace.value = it } - setting("Sprint Ascends", sprintAscends.value).group(Group.Behavior, SubGroup.Movement).onValueChange { _, it -> sprintAscends.value = it } - setting("Overshoot Traverse", overshootTraverse.value).group(Group.Behavior, SubGroup.Movement).onValueChange { _, it -> overshootTraverse.value = it } - setting("Pause Mining For Falling Blocks", pauseMiningForFallingBlocks.value).group(Group.Behavior, SubGroup.Movement).onValueChange { _, it -> pauseMiningForFallingBlocks.value = it } - setting("Allow Overshoot Diagonal Descend", allowOvershootDiagonalDescend.value).group(Group.Behavior, SubGroup.Movement).onValueChange { _, it -> allowOvershootDiagonalDescend.value = it } - setting("Sprint In Water", sprintInWater.value).group(Group.Behavior, SubGroup.Movement).onValueChange { _, it -> sprintInWater.value = it } - - setting("Allow Break", allowBreak.value).group(Group.Behavior, SubGroup.Interaction).onValueChange { _, it -> allowBreak.value = it } - setting("Allow Break Anyway", allowBreakAnyway.value).group(Group.Behavior, SubGroup.Interaction).onValueChange { _, it -> allowBreakAnyway.value = it.toList() } - setting("Allow Sprint", allowSprint.value).group(Group.Behavior, SubGroup.Interaction).onValueChange { _, it -> allowSprint.value = it } - setting("Allow Place", allowPlace.value).group(Group.Behavior, SubGroup.Interaction).onValueChange { _, it -> allowPlace.value = it } - setting("Allow Place In Fluids Source", allowPlaceInFluidsSource.value).group(Group.Behavior, SubGroup.Interaction).onValueChange { _, it -> allowPlaceInFluidsSource.value = it } - setting("Allow Place In Fluids Flow", allowPlaceInFluidsFlow.value).group(Group.Behavior, SubGroup.Interaction).onValueChange { _, it -> allowPlaceInFluidsFlow.value = it } - setting("Allow Inventory", allowInventory.value).group(Group.Behavior, SubGroup.Interaction).onValueChange { _, it -> allowInventory.value = it } - setting("Ticks Between Inventory Moves", ticksBetweenInventoryMoves.value, 0..20).group(Group.Behavior, SubGroup.Interaction).onValueChange { _, it -> ticksBetweenInventoryMoves.value = it } - setting("Inventory Move Only If Stationary", inventoryMoveOnlyIfStationary.value).group(Group.Behavior, SubGroup.Interaction).onValueChange { _, it -> inventoryMoveOnlyIfStationary.value = it } - setting("Auto Tool", autoTool.value).group(Group.Behavior, SubGroup.Interaction).onValueChange { _, it -> autoTool.value = it } - setting("Allow Water Bucket Fall", allowWaterBucketFall.value).group(Group.Behavior, SubGroup.Interaction).onValueChange { _, it -> allowWaterBucketFall.value = it } - setting("Allow Jump At Build Limit", allowJumpAtBuildLimit.value).group(Group.Behavior, SubGroup.Interaction).onValueChange { _, it -> allowJumpAtBuildLimit.value = it } - setting("Right Click Container On Arrival", rightClickContainerOnArrival.value).group(Group.Behavior, SubGroup.Interaction).onValueChange { _, it -> rightClickContainerOnArrival.value = it } - setting("Enter Portal", enterPortal.value).group(Group.Behavior, SubGroup.Interaction).onValueChange { _, it -> enterPortal.value = it } - setting("Walk While Breaking", walkWhileBreaking.value).group(Group.Behavior, SubGroup.Interaction).onValueChange { _, it -> walkWhileBreaking.value = it } - setting("Use Sword To Mine", useSwordToMine.value).group(Group.Behavior, SubGroup.Interaction).onValueChange { _, it -> useSwordToMine.value = it } - setting("Right Click Speed", rightClickSpeed.value, 0..10).group(Group.Behavior, SubGroup.Interaction).onValueChange { _, it -> rightClickSpeed.value = it } - setting("Block Reach Distance", blockReachDistance.value, 0f..10f, 0.1f).group(Group.Behavior, SubGroup.Interaction).onValueChange { _, it -> blockReachDistance.value = it } - setting("Block Break Speed", blockBreakSpeed.value, 0..10).group(Group.Behavior, SubGroup.Interaction).onValueChange { _, it -> blockBreakSpeed.value = it } - setting("Random Looking 1.13", randomLooking113.value, 0.0..5.0, 0.01).group(Group.Behavior, SubGroup.Interaction).onValueChange { _, it -> randomLooking113.value = it } - setting("Random Looking", randomLooking.value, 0.0..1.0, 0.01).group(Group.Behavior, SubGroup.Interaction).onValueChange { _, it -> randomLooking.value = it } - setting("Free Look", freeLook.value).group(Group.Behavior, SubGroup.Interaction).onValueChange { _, it -> freeLook.value = it } - setting("Block Free Look", blockFreeLook.value).group(Group.Behavior, SubGroup.Interaction).onValueChange { _, it -> blockFreeLook.value = it } - setting("Elytra Free Look", elytraFreeLook.value).group(Group.Behavior, SubGroup.Interaction).onValueChange { _, it -> elytraFreeLook.value = it } - setting("Smooth Look", smoothLook.value).group(Group.Behavior, SubGroup.Interaction).onValueChange { _, it -> smoothLook.value = it } - setting("Elytra Smooth Look", elytraSmoothLook.value).group(Group.Behavior, SubGroup.Interaction).onValueChange { _, it -> elytraSmoothLook.value = it } - setting("Smooth Look Ticks", smoothLookTicks.value, 0..200).group(Group.Behavior, SubGroup.Interaction).onValueChange { _, it -> smoothLookTicks.value = it } - setting("Remain With Existing Look Direction", remainWithExistingLookDirection.value).group(Group.Behavior, SubGroup.Interaction).onValueChange { _, it -> remainWithExistingLookDirection.value = it } - - setting("Block Placement Penalty", blockPlacementPenalty.value, 0.0..100.0, 0.1).group(Group.Behavior, SubGroup.Penalties).onValueChange { _, it -> blockPlacementPenalty.value = it } - setting("Block Break Additional Penalty", blockBreakAdditionalPenalty.value, 0.0..100.0, 0.1).group(Group.Behavior, SubGroup.Penalties).onValueChange { _, it -> blockBreakAdditionalPenalty.value = it } - setting("Jump Penalty", jumpPenalty.value, 0.0..100.0, 0.1).group(Group.Behavior, SubGroup.Penalties).onValueChange { _, it -> jumpPenalty.value = it } - setting("Walk On Water One Penalty", walkOnWaterOnePenalty.value, 0.0..100.0, 0.1).group(Group.Behavior, SubGroup.Penalties).onValueChange { _, it -> walkOnWaterOnePenalty.value = it } - setting("Avoid Breaking Multiplier", avoidBreakingMultiplier.value, 0.0..100.0, 0.1).group(Group.Behavior, SubGroup.Penalties).onValueChange { _, it -> avoidBreakingMultiplier.value = it } - setting("Max Cost Increase", maxCostIncrease.value, 0.0..100.0).group(Group.Behavior, SubGroup.Penalties).onValueChange { _, it -> maxCostIncrease.value = it } - setting("Backtrack Cost Favoring Coefficient", backtrackCostFavoringCoefficient.value, 0.0..100.0, 0.1).group(Group.Behavior, SubGroup.Penalties).onValueChange { _, it -> backtrackCostFavoringCoefficient.value = it } - setting("Mob Spawner Avoidance Coefficient", mobSpawnerAvoidanceCoefficient.value, 0.0..100.0, 0.1).group(Group.Behavior, SubGroup.Penalties).onValueChange { _, it -> mobSpawnerAvoidanceCoefficient.value = it } - setting("Mob Spawner Avoidance Radius", mobSpawnerAvoidanceRadius.value, 0..1000).group(Group.Behavior, SubGroup.Penalties).onValueChange { _, it -> mobSpawnerAvoidanceRadius.value = it } - setting("Mob Avoidance Coefficient", mobAvoidanceCoefficient.value, 0.0..100.0, 0.1).group(Group.Behavior, SubGroup.Penalties).onValueChange { _, it -> mobAvoidanceCoefficient.value = it } - setting("Mob Avoidance Radius", mobAvoidanceRadius.value, 0..1000).group(Group.Behavior, SubGroup.Penalties).onValueChange { _, it -> mobAvoidanceRadius.value = it } - setting("Path Cutoff Factor", pathCutoffFactor.value, 0.0..100.0, 0.1).group(Group.Behavior, SubGroup.Penalties).onValueChange { _, it -> pathCutoffFactor.value = it } - setting("Break Correct Block Penalty Multiplier", breakCorrectBlockPenaltyMultiplier.value, 0.0..100.0, 0.1).group(Group.Behavior, SubGroup.Penalties).onValueChange { _, it -> breakCorrectBlockPenaltyMultiplier.value = it } - setting("Place Incorrect Block Penalty Multiplier", placeIncorrectBlockPenaltyMultiplier.value, 0.0..100.0, 0.1).group(Group.Behavior, SubGroup.Penalties).onValueChange { _, it -> placeIncorrectBlockPenaltyMultiplier.value = it } - setting("Cost Heuristic", costHeuristic.value, 0.0..10.0, 0.001).group(Group.Behavior, SubGroup.Penalties).onValueChange { _, it -> costHeuristic.value = it } - - setting("Item Saver", itemSaver.value).group(Group.Behavior, SubGroup.MiningAndFarming).onValueChange { _, it -> itemSaver.value = it } - setting("Item Saver Threshold", itemSaverThreshold.value, 0..100).group(Group.Behavior, SubGroup.MiningAndFarming).onValueChange { _, it -> itemSaverThreshold.value = it } - setting("Prefer Silk Touch", preferSilkTouch.value).group(Group.Behavior, SubGroup.MiningAndFarming).onValueChange { _, it -> preferSilkTouch.value = it } - setting("Mine Scan Dropped Items", mineScanDroppedItems.value).group(Group.Behavior, SubGroup.MiningAndFarming).onValueChange { _, it -> mineScanDroppedItems.value = it } - setting("Mine Drop Loiter Duration", mineDropLoiterDurationMSThanksLouca.value, 0L..600000L, unit = " ms").group(Group.Behavior, SubGroup.MiningAndFarming).onValueChange { _, it -> mineDropLoiterDurationMSThanksLouca.value = it } - setting("Legit Mine", legitMine.value).group(Group.Behavior, SubGroup.MiningAndFarming).onValueChange { _, it -> legitMine.value = it } - setting("Legit Mine Y Level", legitMineYLevel.value, 0..256).group(Group.Behavior, SubGroup.MiningAndFarming).onValueChange { _, it -> legitMineYLevel.value = it } - setting("Legit Mine Include Diagonals", legitMineIncludeDiagonals.value).group(Group.Behavior, SubGroup.MiningAndFarming).onValueChange { _, it -> legitMineIncludeDiagonals.value = it } - setting("Force Internal Mining", forceInternalMining.value).group(Group.Behavior, SubGroup.MiningAndFarming).onValueChange { _, it -> forceInternalMining.value = it } - setting("Internal Mining Air Exception", internalMiningAirException.value).group(Group.Behavior, SubGroup.MiningAndFarming).onValueChange { _, it -> internalMiningAirException.value = it } - setting("Min Y Level While Mining", minYLevelWhileMining.value, 0..2048).group(Group.Behavior, SubGroup.MiningAndFarming).onValueChange { _, it -> minYLevelWhileMining.value = it } - setting("Max Y Level While Mining", maxYLevelWhileMining.value, 0..2048).group(Group.Behavior, SubGroup.MiningAndFarming).onValueChange { _, it -> maxYLevelWhileMining.value = it } - setting("Allow Only Exposed Ores", allowOnlyExposedOres.value).group(Group.Behavior, SubGroup.MiningAndFarming).onValueChange { _, it -> allowOnlyExposedOres.value = it } - setting("Allow Only Exposed Ores Distance", allowOnlyExposedOresDistance.value, 0..16).group(Group.Behavior, SubGroup.MiningAndFarming).onValueChange { _, it -> allowOnlyExposedOresDistance.value = it } - setting("Replant Crops", replantCrops.value).group(Group.Behavior, SubGroup.MiningAndFarming).onValueChange { _, it -> replantCrops.value = it } - setting("Replant Nether Wart", replantNetherWart.value).group(Group.Behavior, SubGroup.MiningAndFarming).onValueChange { _, it -> replantNetherWart.value = it } - setting("Farm Max Scan Size", farmMaxScanSize.value, 0..1024).group(Group.Behavior, SubGroup.MiningAndFarming).onValueChange { _, it -> farmMaxScanSize.value = it } - setting("Consider Potion Effects", considerPotionEffects.value).group(Group.Behavior, SubGroup.MiningAndFarming).onValueChange { _, it -> considerPotionEffects.value = it } - - setting("Explore For Blocks", exploreForBlocks.value).group(Group.Behavior, SubGroup.Exploration).onValueChange { _, it -> exploreForBlocks.value = it } - setting("World Exploring Chunk Offset", worldExploringChunkOffset.value, 0..32).group(Group.Behavior, SubGroup.Exploration).onValueChange { _, it -> worldExploringChunkOffset.value = it } - setting("Explore Chunk Set Minimum Size", exploreChunkSetMinimumSize.value, 0..10000).group(Group.Behavior, SubGroup.Exploration).onValueChange { _, it -> exploreChunkSetMinimumSize.value = it } - setting("Explore Maintain Y", exploreMaintainY.value, 0..256).group(Group.Behavior, SubGroup.Exploration).onValueChange { _, it -> exploreMaintainY.value = it } - - // BUILDING - setting("Build In Layers", buildInLayers.value).group(Group.Building, SubGroup.Schematic).onValueChange { _, it -> buildInLayers.value = it } - setting("Layer Order", layerOrder.value).group(Group.Building, SubGroup.Schematic).onValueChange { _, it -> layerOrder.value = it } - setting("Layer Height", layerHeight.value, 0..256).group(Group.Building, SubGroup.Schematic).onValueChange { _, it -> layerHeight.value = it } - setting("Start At Layer", startAtLayer.value, 0..256).group(Group.Building, SubGroup.Schematic).onValueChange { _, it -> startAtLayer.value = it } - setting("Skip Failed Layers", skipFailedLayers.value).group(Group.Building, SubGroup.Schematic).onValueChange { _, it -> skipFailedLayers.value = it } - setting("Build Only Selection", buildOnlySelection.value).group(Group.Building, SubGroup.Schematic).onValueChange { _, it -> buildOnlySelection.value = it } - setting("Build Repeat", buildRepeat.value.blockPos).group(Group.Building, SubGroup.Schematic).onValueChange { _, it -> buildRepeat.value = it } - setting("Build Repeat Count", buildRepeatCount.value, 0..1000).group(Group.Building, SubGroup.Schematic).onValueChange { _, it -> buildRepeatCount.value = it } - setting("Build Repeat Sneaky", buildRepeatSneaky.value).group(Group.Building, SubGroup.Schematic).onValueChange { _, it -> buildRepeatSneaky.value = it } - setting("Break From Above", breakFromAbove.value).group(Group.Building, SubGroup.Schematic).onValueChange { _, it -> breakFromAbove.value = it } - setting("Goal Break From Above", goalBreakFromAbove.value).group(Group.Building, SubGroup.Schematic).onValueChange { _, it -> goalBreakFromAbove.value = it } - setting("Map Art Mode", mapArtMode.value).group(Group.Building, SubGroup.Schematic).onValueChange { _, it -> mapArtMode.value = it } - setting("Ok If Water", okIfWater.value).group(Group.Building, SubGroup.Schematic).onValueChange { _, it -> okIfWater.value = it } - setting("Incorrect Size", incorrectSize.value, 0..1000).group(Group.Building, SubGroup.Schematic).onValueChange { _, it -> incorrectSize.value = it } - setting("Schematic Orientation X", schematicOrientationX.value).group(Group.Building, SubGroup.Schematic).onValueChange { _, it -> schematicOrientationX.value = it } - setting("Schematic Orientation Y", schematicOrientationY.value).group(Group.Building, SubGroup.Schematic).onValueChange { _, it -> schematicOrientationY.value = it } - setting("Schematic Orientation Z", schematicOrientationZ.value).group(Group.Building, SubGroup.Schematic).onValueChange { _, it -> schematicOrientationZ.value = it } - setting("Build Schematic Rotation", buildSchematicRotation.value).group(Group.Building, SubGroup.Schematic).onValueChange { _, it -> buildSchematicRotation.value = it } - setting("Build Schematic Mirror", buildSchematicMirror.value).group(Group.Building, SubGroup.Schematic).onValueChange { _, it -> buildSchematicMirror.value = it } - setting("Schematic Fallback Extension", schematicFallbackExtension.value).group(Group.Building, SubGroup.Schematic).onValueChange { _, it -> schematicFallbackExtension.value = it } - setting("Builder Tick Scan Radius", builderTickScanRadius.value, 0..64).group(Group.Building, SubGroup.Schematic).onValueChange { _, it -> builderTickScanRadius.value = it } - - setting("Acceptable Throwaway Items", acceptableThrowawayItems.value).group(Group.Building, SubGroup.BlockRules).onValueChange { _, it -> acceptableThrowawayItems.value = it.toList() } - setting("Blocks To Avoid", blocksToAvoid.value).group(Group.Building, SubGroup.BlockRules).onValueChange { _, it -> blocksToAvoid.value = it.toList() } - setting("Blocks To Disallow Breaking", blocksToDisallowBreaking.value).group(Group.Building, SubGroup.BlockRules).onValueChange { _, it -> blocksToDisallowBreaking.value = it.toList() } - setting("Blocks To Avoid Breaking", blocksToAvoidBreaking.value).group(Group.Building, SubGroup.BlockRules).onValueChange { _, it -> blocksToAvoidBreaking.value = it.toList() } - setting("Build Ignore Blocks", buildIgnoreBlocks.value).group(Group.Building, SubGroup.BlockRules).onValueChange { _, it -> buildIgnoreBlocks.value = it.toList() } - setting("Build Skip Blocks", buildSkipBlocks.value).group(Group.Building, SubGroup.BlockRules).onValueChange { _, it -> buildSkipBlocks.value = it.toList() } - // FixMe: lmao fuck this im so done - //setting("Build Valid Substitutes", buildValidSubstitutes.value.flatMap { it.value }).group(Group.Building, SubGroup.BlockRules).onValueChange { _, it -> buildValidSubstitutes.value = it.mapValues { (_, v) -> v.toList() } } - //setting("Build Substitutes", buildSubstitutes.value.flatMap { it.value }).group(Group.Building, SubGroup.BlockRules).onValueChange { _, it -> buildSubstitutes.value = it.mapValues { (_, v) -> v.toList() } } - setting("Ok If Air", okIfAir.value).group(Group.Building, SubGroup.BlockRules).onValueChange { _, it -> okIfAir.value = it.toList() } - setting("Build Ignore Existing", buildIgnoreExisting.value).group(Group.Building, SubGroup.BlockRules).onValueChange { _, it -> buildIgnoreExisting.value = it } - setting("Build Ignore Direction", buildIgnoreDirection.value).group(Group.Building, SubGroup.BlockRules).onValueChange { _, it -> buildIgnoreDirection.value = it } - setting("Build Ignore Properties", buildIgnoreProperties.value).group(Group.Building, SubGroup.BlockRules).onValueChange { _, it -> buildIgnoreProperties.value = it.toList() } - setting("Avoid Updating Falling Blocks", avoidUpdatingFallingBlocks.value).group(Group.Building, SubGroup.BlockRules).onValueChange { _, it -> avoidUpdatingFallingBlocks.value = it } - - // RENDERING - setting("Render Path", renderPath.value).group(Group.Rendering, SubGroup.Rendering).onValueChange { _, it -> renderPath.value = it } - setting("Render Path As Line", renderPathAsLine.value).group(Group.Rendering, SubGroup.Rendering).onValueChange { _, it -> renderPathAsLine.value = it } - setting("Render Goal", renderGoal.value).group(Group.Rendering, SubGroup.Rendering).onValueChange { _, it -> renderGoal.value = it } - setting("Render Goal Animated", renderGoalAnimated.value).group(Group.Rendering, SubGroup.Rendering).onValueChange { _, it -> renderGoalAnimated.value = it } - setting("Render Goal Ignore Depth", renderGoalIgnoreDepth.value).group(Group.Rendering, SubGroup.Rendering).onValueChange { _, it -> renderGoalIgnoreDepth.value = it } - setting("Render Goal XZ Beacon", renderGoalXZBeacon.value).group(Group.Rendering, SubGroup.Rendering).onValueChange { _, it -> renderGoalXZBeacon.value = it } - setting("Path Render Line Width Pixels", pathRenderLineWidthPixels.value, 0f..10f, 0.1f).group(Group.Rendering, SubGroup.Rendering).onValueChange { _, it -> pathRenderLineWidthPixels.value = it } - setting("Goal Render Line Width Pixels", goalRenderLineWidthPixels.value, 0f..10f, 0.1f).group(Group.Rendering, SubGroup.Rendering).onValueChange { _, it -> goalRenderLineWidthPixels.value = it } - setting("Fade Path", fadePath.value).group(Group.Rendering, SubGroup.Rendering).onValueChange { _, it -> fadePath.value = it } - setting("Render Cached Chunks", renderCachedChunks.value).group(Group.Rendering, SubGroup.Rendering).onValueChange { _, it -> renderCachedChunks.value = it } - setting("Cached Chunks Opacity", cachedChunksOpacity.value, 0f..1f, 0.05f).group(Group.Rendering, SubGroup.Rendering).onValueChange { _, it -> cachedChunksOpacity.value = it } - setting("Render Path Ignore Depth", renderPathIgnoreDepth.value).group(Group.Rendering, SubGroup.Rendering).onValueChange { _, it -> renderPathIgnoreDepth.value = it } - setting("Render Selection Boxes", renderSelectionBoxes.value).group(Group.Rendering, SubGroup.Rendering).onValueChange { _, it -> renderSelectionBoxes.value = it } - - setting("Color Current Path", colorCurrentPath.value).group(Group.Rendering, SubGroup.RenderingColors).onValueChange { _, it -> colorCurrentPath.value = it } - setting("Color Next Path", colorNextPath.value).group(Group.Rendering, SubGroup.RenderingColors).onValueChange { _, it -> colorNextPath.value = it } - setting("Color Blocks To Break", colorBlocksToBreak.value).group(Group.Rendering, SubGroup.RenderingColors).onValueChange { _, it -> colorBlocksToBreak.value = it } - setting("Color Blocks To Place", colorBlocksToPlace.value).group(Group.Rendering, SubGroup.RenderingColors).onValueChange { _, it -> colorBlocksToPlace.value = it } - setting("Color Blocks To Walk Into", colorBlocksToWalkInto.value).group(Group.Rendering, SubGroup.RenderingColors).onValueChange { _, it -> colorBlocksToWalkInto.value = it } - setting("Color Best Path So Far", colorBestPathSoFar.value).group(Group.Rendering, SubGroup.RenderingColors).onValueChange { _, it -> colorBestPathSoFar.value = it } - setting("Color Most Recent Considered", colorMostRecentConsidered.value).group(Group.Rendering, SubGroup.RenderingColors).onValueChange { _, it -> colorMostRecentConsidered.value = it } - setting("Color Goal Box", colorGoalBox.value).group(Group.Rendering, SubGroup.RenderingColors).onValueChange { _, it -> colorGoalBox.value = it } - setting("Color Inverted Goal Box", colorInvertedGoalBox.value).group(Group.Rendering, SubGroup.RenderingColors).onValueChange { _, it -> colorInvertedGoalBox.value = it } - - setting("Render Selection", renderSelection.value).group(Group.Rendering, SubGroup.RenderingSelection).onValueChange { _, it -> renderSelection.value = it } - setting("Color Selection", colorSelection.value).group(Group.Rendering, SubGroup.RenderingSelection).onValueChange { _, it -> colorSelection.value = it } - setting("Color Selection Pos1", colorSelectionPos1.value).group(Group.Rendering, SubGroup.RenderingSelection).onValueChange { _, it -> colorSelectionPos1.value = it } - setting("Color Selection Pos2", colorSelectionPos2.value).group(Group.Rendering, SubGroup.RenderingSelection).onValueChange { _, it -> colorSelectionPos2.value = it } - setting("Selection Opacity", selectionOpacity.value, 0f..1f, 0.05f).group(Group.Rendering, SubGroup.RenderingSelection).onValueChange { _, it -> selectionOpacity.value = it } - setting("Selection Line Width", selectionLineWidth.value, 0f..10f, 0.1f).group(Group.Rendering, SubGroup.RenderingSelection).onValueChange { _, it -> selectionLineWidth.value = it } - setting("Render Selection Ignore Depth", renderSelectionIgnoreDepth.value).group(Group.Rendering, SubGroup.RenderingSelection).onValueChange { _, it -> renderSelectionIgnoreDepth.value = it } - setting("Render Selection Corners", renderSelectionCorners.value).group(Group.Rendering, SubGroup.RenderingSelection).onValueChange { _, it -> renderSelectionCorners.value = it } - setting("Render Selection Boxes Ignore Depth", renderSelectionBoxesIgnoreDepth.value).group(Group.Rendering, SubGroup.RenderingSelection).onValueChange { _, it -> renderSelectionBoxesIgnoreDepth.value = it } - - // ELYTRA - setting("Simulation Ticks", elytraSimulationTicks.value, 0..200).group(Group.Elytra).onValueChange { _, it -> elytraSimulationTicks.value = it } - setting("Pitch Range", elytraPitchRange.value, 0..90).group(Group.Elytra).onValueChange { _, it -> elytraPitchRange.value = it } - setting("Firework Speed", elytraFireworkSpeed.value, 0.0..3.0, 0.1).group(Group.Elytra).onValueChange { _, it -> elytraFireworkSpeed.value = it } - setting("Firework Setback Use Delay", elytraFireworkSetbackUseDelay.value, 0..600).group(Group.Elytra).onValueChange { _, it -> elytraFireworkSetbackUseDelay.value = it } - setting("Minimum Avoidance", elytraMinimumAvoidance.value, 0.0..10.0, 0.1).group(Group.Elytra).onValueChange { _, it -> elytraMinimumAvoidance.value = it } - setting("Conserve Fireworks", elytraConserveFireworks.value).group(Group.Elytra).onValueChange { _, it -> elytraConserveFireworks.value = it } - setting("Render Raytraces", elytraRenderRaytraces.value).group(Group.Elytra).onValueChange { _, it -> elytraRenderRaytraces.value = it } - setting("Render Hitbox Raytraces", elytraRenderHitboxRaytraces.value).group(Group.Elytra).onValueChange { _, it -> elytraRenderHitboxRaytraces.value = it } - setting("Render Simulation", elytraRenderSimulation.value).group(Group.Elytra).onValueChange { _, it -> elytraRenderSimulation.value = it } - setting("Auto Jump", elytraAutoJump.value).group(Group.Elytra).onValueChange { _, it -> elytraAutoJump.value = it } - setting("Nether Seed", elytraNetherSeed.value, Long.MIN_VALUE..Long.MAX_VALUE).group(Group.Elytra).onValueChange { _, it -> elytraNetherSeed.value = it } - setting("Predict Terrain", elytraPredictTerrain.value).group(Group.Elytra).onValueChange { _, it -> elytraPredictTerrain.value = it } - setting("Auto Swap", elytraAutoSwap.value).group(Group.Elytra).onValueChange { _, it -> elytraAutoSwap.value = it } - setting("Minimum Durability", elytraMinimumDurability.value, 0..432).group(Group.Elytra).onValueChange { _, it -> elytraMinimumDurability.value = it } - setting("Min Fireworks Before Landing", elytraMinFireworksBeforeLanding.value, 0..64).group(Group.Elytra).onValueChange { _, it -> elytraMinFireworksBeforeLanding.value = it } - setting("Allow Emergency Land", elytraAllowEmergencyLand.value).group(Group.Elytra).onValueChange { _, it -> elytraAllowEmergencyLand.value = it } - setting("Time Between Cache Cull Secs", elytraTimeBetweenCacheCullSecs.value, 0L..86400L).group(Group.Elytra).onValueChange { _, it -> elytraTimeBetweenCacheCullSecs.value = it } - setting("Cache Cull Distance", elytraCacheCullDistance.value, 0..100000).group(Group.Elytra).onValueChange { _, it -> elytraCacheCullDistance.value = it } - 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 } - } - } - } - - /** - * Whether Baritone is currently pathing - */ - val isPathing: Boolean - get() = isBaritoneLoaded && primary?.pathingBehavior?.isPathing == true - - /** - * Whether Baritone is active (pathing, calculating goal, etc.) - */ - val isActive: Boolean - get() = isBaritoneLoaded && - (primary?.customGoalProcess?.isActive == true || - primary?.pathingBehavior?.isPathing == true || - primary?.pathingControlManager?.mostRecentInControl()?.orElse(null)?.isActive == true || - primary?.elytraProcess?.isActive == true) - - /** - * Sets the current Baritone goal and starts pathing - */ - fun setGoalAndPath(goal: Goal) { - if (!isBaritoneLoaded) return - primary?.customGoalProcess?.setGoalAndPath(goal) - } - - /** - * Sets the current Baritone goal without starting pathing - */ - fun setGoal(goal: Goal) { - if (!isBaritoneLoaded || primary?.elytraProcess?.isLoaded != true) return - primary.customGoalProcess?.goal = goal - } - - fun setGoalAndElytraPath(goal: Goal) { - if (!isBaritoneLoaded || primary?.elytraProcess?.isLoaded != true) return - primary.elytraProcess?.pathTo(goal) - } - - /** - * Force cancel Baritone - */ - fun cancel() { - if (!isBaritoneLoaded) return - primary?.pathingBehavior?.cancelEverything() - primary?.elytraProcess?.resetState() - } -} diff --git a/src/main/kotlin/com/lambda/interaction/construction/StructureRegistry.kt b/src/main/kotlin/com/lambda/interaction/construction/StructureRegistry.kt index fb8cea819..7a76210cf 100644 --- a/src/main/kotlin/com/lambda/interaction/construction/StructureRegistry.kt +++ b/src/main/kotlin/com/lambda/interaction/construction/StructureRegistry.kt @@ -17,10 +17,10 @@ package com.lambda.interaction.construction -import com.lambda.Lambda.LOG +import com.lambda.Lambda.Log import com.lambda.core.Loadable -import com.lambda.util.FolderRegister -import com.lambda.util.FolderRegister.structure +import com.lambda.util.FolderRegistry +import com.lambda.util.FolderRegistry.structure import com.lambda.util.extension.readLitematica import com.lambda.util.extension.readSchematic import com.lambda.util.extension.readSponge @@ -164,7 +164,7 @@ object StructureRegistry : ConcurrentHashMap(), Loada * @param structure The [StructureTemplate] to save. */ private fun saveStructure(relativePath: String, structure: StructureTemplate) { - val path = FolderRegister.structure.resolve("$relativePath.nbt") + val path = FolderRegistry.structure.resolve("$relativePath.nbt") val compound = structure.writeNbt(NbtCompound()) Files.createDirectories(path.parent) @@ -189,7 +189,7 @@ object StructureRegistry : ConcurrentHashMap(), Loada .distinctBy { it.nameWithoutExtension } // Pick the first structure in the priority list nbt > litematica > schematica .forEach { struct -> runCatching { loadStructureByRelativePath(structure.relativize(struct)) } - .onFailure { LOG.warn("Unable to load the structure $struct: ${it.message}") } + .onFailure { Log.warn("Unable to load the structure $struct: ${it.message}") } } return "Loaded $size structure templates" diff --git a/src/main/kotlin/com/lambda/interaction/construction/simulation/BuildSimulator.kt b/src/main/kotlin/com/lambda/interaction/construction/simulation/BuildSimulator.kt index 8babe3199..4f68fb872 100644 --- a/src/main/kotlin/com/lambda/interaction/construction/simulation/BuildSimulator.kt +++ b/src/main/kotlin/com/lambda/interaction/construction/simulation/BuildSimulator.kt @@ -18,11 +18,11 @@ package com.lambda.interaction.construction.simulation import com.lambda.context.AutomatedSafeContext -import com.lambda.interaction.construction.simulation.result.BuildResult -import com.lambda.interaction.construction.simulation.result.results.PostSimResult import com.lambda.interaction.construction.simulation.SimInfo.Companion.sim import com.lambda.interaction.construction.simulation.checks.BreakSim.Companion.simBreak import com.lambda.interaction.construction.simulation.checks.InteractSim.Companion.simInteraction +import com.lambda.interaction.construction.simulation.result.BuildResult +import com.lambda.interaction.construction.simulation.result.results.PostSimResult import com.lambda.util.BlockUtils.blockState import com.lambda.util.extension.Structure import io.ktor.util.collections.* diff --git a/src/main/kotlin/com/lambda/interaction/construction/simulation/Sim.kt b/src/main/kotlin/com/lambda/interaction/construction/simulation/Sim.kt index dd165d7c0..5c9532b84 100644 --- a/src/main/kotlin/com/lambda/interaction/construction/simulation/Sim.kt +++ b/src/main/kotlin/com/lambda/interaction/construction/simulation/Sim.kt @@ -21,11 +21,11 @@ import com.lambda.interaction.construction.simulation.processing.PreProcessingDa import com.lambda.interaction.construction.simulation.result.BuildResult import com.lambda.interaction.construction.simulation.result.results.GenericResult import com.lambda.interaction.managers.rotating.Rotation.Companion.rotationTo -import com.lambda.interaction.managers.rotating.visibilty.VisibilityChecker.CheckedHit -import com.lambda.interaction.managers.rotating.visibilty.VisibilityChecker.scanClosestPoints -import com.lambda.interaction.managers.rotating.visibilty.VisibilityChecker.scanSurfaces import com.lambda.util.math.distSq import com.lambda.util.math.vec3d +import com.lambda.util.player.CheckedHit +import com.lambda.util.player.RotationUtils.scanClosestPoints +import com.lambda.util.player.RotationUtils.scanSurfaces import com.lambda.util.world.raycast.RayCastUtils.blockResult import io.ktor.util.collections.* import kotlinx.coroutines.launch 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 20cf9fdd8..817de2a3c 100644 --- a/src/main/kotlin/com/lambda/interaction/construction/simulation/Simulation.kt +++ b/src/main/kotlin/com/lambda/interaction/construction/simulation/Simulation.kt @@ -20,7 +20,6 @@ package com.lambda.interaction.construction.simulation import com.lambda.context.Automated import com.lambda.context.SafeContext import com.lambda.graphics.mc.RenderBuilder -import com.lambda.graphics.mc.renderer.TickedRenderer import com.lambda.interaction.construction.blueprint.Blueprint import com.lambda.interaction.construction.simulation.BuildSimulator.simulate import com.lambda.interaction.construction.simulation.result.BuildResult @@ -37,6 +36,7 @@ import net.minecraft.util.math.Direction import net.minecraft.util.math.Vec3d import java.awt.Color +@Suppress("unused") data class Simulation( val blueprint: Blueprint, private val automated: Automated diff --git a/src/main/kotlin/com/lambda/interaction/construction/simulation/checks/BasicChecker.kt b/src/main/kotlin/com/lambda/interaction/construction/simulation/checks/BasicChecker.kt index 8d588b317..8c4c996af 100644 --- a/src/main/kotlin/com/lambda/interaction/construction/simulation/checks/BasicChecker.kt +++ b/src/main/kotlin/com/lambda/interaction/construction/simulation/checks/BasicChecker.kt @@ -17,6 +17,7 @@ package com.lambda.interaction.construction.simulation.checks +import com.lambda.config.settings.blocks.BreakConfig.WhitelistMode import com.lambda.context.AutomatedSafeContext import com.lambda.interaction.construction.simulation.BreakSimInfo import com.lambda.interaction.construction.simulation.Results @@ -24,7 +25,6 @@ import com.lambda.interaction.construction.simulation.SimDsl import com.lambda.interaction.construction.simulation.SimInfo import com.lambda.interaction.construction.simulation.result.results.GenericResult import com.lambda.interaction.construction.simulation.result.results.PreSimResult -import com.lambda.interaction.managers.breaking.BreakConfig.WhitelistMode import com.lambda.util.player.gamemode import com.lambda.util.world.WorldUtils.isLoaded import net.minecraft.block.OperatorBlock diff --git a/src/main/kotlin/com/lambda/interaction/construction/simulation/checks/BreakSim.kt b/src/main/kotlin/com/lambda/interaction/construction/simulation/checks/BreakSim.kt index c4b747f10..cf6048e21 100644 --- a/src/main/kotlin/com/lambda/interaction/construction/simulation/checks/BreakSim.kt +++ b/src/main/kotlin/com/lambda/interaction/construction/simulation/checks/BreakSim.kt @@ -31,18 +31,18 @@ import com.lambda.interaction.construction.verify.TargetState import com.lambda.interaction.managers.hotbar.HotbarManager import com.lambda.interaction.managers.rotating.IRotationRequest.Companion.rotationRequest import com.lambda.interaction.managers.rotating.RotationManager -import com.lambda.interaction.managers.rotating.visibilty.lookAtBlock import com.lambda.interaction.material.ContainerSelection.Companion.selectContainer import com.lambda.interaction.material.StackSelection -import com.lambda.interaction.material.StackSelection.Companion.EVERYTHING +import com.lambda.interaction.material.StackSelection.Companion.Everything import com.lambda.interaction.material.StackSelection.Companion.selectStack -import com.lambda.interaction.material.container.ContainerManager.findContainersWithMaterial +import com.lambda.interaction.material.container.ContainerHandler.findContainersWithMaterial import com.lambda.interaction.material.container.MaterialContainer import com.lambda.util.BlockUtils.blockState import com.lambda.util.BlockUtils.calcItemBlockBreakingDelta import com.lambda.util.BlockUtils.instantBreakable import com.lambda.util.item.ItemStackUtils.inventoryIndex import com.lambda.util.item.ItemStackUtils.inventoryIndexOrSelected +import com.lambda.util.player.RotationUtils.lookAtBlock import com.lambda.util.world.raycast.RayCastUtils.blockResult import net.minecraft.block.BlockState import net.minecraft.block.FallingBlock @@ -53,12 +53,6 @@ import net.minecraft.fluid.FlowableFluid import net.minecraft.fluid.LavaFluid import net.minecraft.fluid.WaterFluid import net.minecraft.item.ItemStack -import net.minecraft.registry.tag.ItemTags.DIAMOND_TOOL_MATERIALS -import net.minecraft.registry.tag.ItemTags.GOLD_TOOL_MATERIALS -import net.minecraft.registry.tag.ItemTags.IRON_TOOL_MATERIALS -import net.minecraft.registry.tag.ItemTags.NETHERITE_TOOL_MATERIALS -import net.minecraft.registry.tag.ItemTags.STONE_TOOL_MATERIALS -import net.minecraft.registry.tag.ItemTags.WOODEN_TOOL_MATERIALS import net.minecraft.util.math.BlockPos import net.minecraft.util.math.Direction import kotlin.jvm.optionals.getOrNull @@ -161,7 +155,7 @@ class BreakSim private constructor(simInfo: SimInfo) it.inventoryIndex == HotbarManager.serverSlot } ) { - EVERYTHING + Everything .andIf(breakConfig.efficientOnly) { isEfficientForBreaking(state) }.andIf(breakConfig.suitableToolsOnly) { diff --git a/src/main/kotlin/com/lambda/interaction/construction/simulation/checks/InteractSim.kt b/src/main/kotlin/com/lambda/interaction/construction/simulation/checks/InteractSim.kt index 171461348..4cfac537d 100644 --- a/src/main/kotlin/com/lambda/interaction/construction/simulation/checks/InteractSim.kt +++ b/src/main/kotlin/com/lambda/interaction/construction/simulation/checks/InteractSim.kt @@ -31,22 +31,22 @@ import com.lambda.interaction.managers.rotating.IRotationRequest.Companion.rotat import com.lambda.interaction.managers.rotating.Rotation import com.lambda.interaction.managers.rotating.Rotation.Companion.rotation import com.lambda.interaction.managers.rotating.RotationManager -import com.lambda.interaction.managers.rotating.visibilty.PlaceDirection -import com.lambda.interaction.managers.rotating.visibilty.VisibilityChecker.CheckedHit -import com.lambda.interaction.managers.rotating.visibilty.lookInDirection import com.lambda.interaction.material.ContainerSelection.Companion.selectContainer import com.lambda.interaction.material.StackSelection import com.lambda.interaction.material.StackSelection.Companion.select -import com.lambda.interaction.material.container.ContainerManager.findContainersWithMaterial +import com.lambda.interaction.material.container.ContainerHandler.findContainersWithMaterial import com.lambda.interaction.material.container.MaterialContainer import com.lambda.util.BlockUtils import com.lambda.util.BlockUtils.blockState import com.lambda.util.EntityUtils.getPositionsWithinHitboxXZ +import com.lambda.util.PlaceDirection import com.lambda.util.item.ItemStackUtils.inventoryIndex import com.lambda.util.item.ItemUtils.blockItem import com.lambda.util.math.MathUtils.floorToInt import com.lambda.util.math.minus +import com.lambda.util.player.CheckedHit import com.lambda.util.player.MovementUtils.sneaking +import com.lambda.util.player.RotationUtils.lookInDirection import com.lambda.util.player.copyPlayer import com.lambda.util.world.raycast.RayCastUtils.blockResult import kotlinx.coroutines.CoroutineScope diff --git a/src/main/kotlin/com/lambda/interaction/construction/simulation/context/BuildContext.kt b/src/main/kotlin/com/lambda/interaction/construction/simulation/context/BuildContext.kt index 30b26d55a..572b730ee 100644 --- a/src/main/kotlin/com/lambda/interaction/construction/simulation/context/BuildContext.kt +++ b/src/main/kotlin/com/lambda/interaction/construction/simulation/context/BuildContext.kt @@ -17,7 +17,7 @@ package com.lambda.interaction.construction.simulation.context -import com.lambda.config.groups.ActionConfig +import com.lambda.config.settings.blocks.ActionConfig import com.lambda.context.Automated import com.lambda.interaction.construction.simulation.result.Drawable import com.lambda.interaction.managers.rotating.RotationRequest diff --git a/src/main/kotlin/com/lambda/interaction/construction/simulation/processing/ProcessorRegistry.kt b/src/main/kotlin/com/lambda/interaction/construction/simulation/processing/ProcessorRegistry.kt index 7e6de74ad..3ec075142 100644 --- a/src/main/kotlin/com/lambda/interaction/construction/simulation/processing/ProcessorRegistry.kt +++ b/src/main/kotlin/com/lambda/interaction/construction/simulation/processing/ProcessorRegistry.kt @@ -23,7 +23,7 @@ import com.lambda.core.Loadable import com.lambda.interaction.construction.simulation.SimDsl import com.lambda.interaction.construction.verify.TargetState import com.lambda.util.BlockUtils.matches -import com.lambda.util.reflections.getInstances +import com.lambda.util.ReflectionUtils.getInstances import net.minecraft.block.BlockState import net.minecraft.item.ItemStack import net.minecraft.state.property.Properties diff --git a/src/main/kotlin/com/lambda/interaction/construction/simulation/processing/preprocessors/property/placement/post/ChestPostProcessor.kt b/src/main/kotlin/com/lambda/interaction/construction/simulation/processing/preprocessors/property/placement/post/ChestPostProcessor.kt index 8da78566f..6973a2521 100644 --- a/src/main/kotlin/com/lambda/interaction/construction/simulation/processing/preprocessors/property/placement/post/ChestPostProcessor.kt +++ b/src/main/kotlin/com/lambda/interaction/construction/simulation/processing/preprocessors/property/placement/post/ChestPostProcessor.kt @@ -27,7 +27,6 @@ import net.minecraft.block.enums.ChestType import net.minecraft.state.property.Properties import net.minecraft.util.math.BlockPos -// Collected using reflections and then accessed from a collection in ProcessorRegistry @Suppress("unused") object ChestPostProcessor : PropertyPostProcessor { override fun acceptsState(state: BlockState, targetState: BlockState) = diff --git a/src/main/kotlin/com/lambda/interaction/construction/simulation/processing/preprocessors/property/placement/post/PoweredPostProcessor.kt b/src/main/kotlin/com/lambda/interaction/construction/simulation/processing/preprocessors/property/placement/post/PoweredPostProcessor.kt index 69e9048c8..18a532cd6 100644 --- a/src/main/kotlin/com/lambda/interaction/construction/simulation/processing/preprocessors/property/placement/post/PoweredPostProcessor.kt +++ b/src/main/kotlin/com/lambda/interaction/construction/simulation/processing/preprocessors/property/placement/post/PoweredPostProcessor.kt @@ -26,7 +26,6 @@ import net.minecraft.block.LeverBlock import net.minecraft.state.property.Properties import net.minecraft.util.math.BlockPos -// Collected using reflections and then accessed from a collection in ProcessorRegistry @Suppress("unused") object PoweredPostProcessor : PropertyPostProcessor { override fun acceptsState(state: BlockState, targetState: BlockState) = diff --git a/src/main/kotlin/com/lambda/interaction/construction/simulation/processing/preprocessors/property/placement/post/SlabPostProcessor.kt b/src/main/kotlin/com/lambda/interaction/construction/simulation/processing/preprocessors/property/placement/post/SlabPostProcessor.kt index 59655f073..986e99b4a 100644 --- a/src/main/kotlin/com/lambda/interaction/construction/simulation/processing/preprocessors/property/placement/post/SlabPostProcessor.kt +++ b/src/main/kotlin/com/lambda/interaction/construction/simulation/processing/preprocessors/property/placement/post/SlabPostProcessor.kt @@ -26,7 +26,6 @@ import net.minecraft.block.enums.SlabType import net.minecraft.state.property.Properties import net.minecraft.util.math.BlockPos -// Collected using reflections and then accessed from a collection in ProcessorRegistry @Suppress("unused") object SlabPostProcessor : PropertyPostProcessor { override fun acceptsState(state: BlockState, targetState: BlockState) = diff --git a/src/main/kotlin/com/lambda/interaction/construction/simulation/processing/preprocessors/property/placement/post/StandardInteractPostProcessor.kt b/src/main/kotlin/com/lambda/interaction/construction/simulation/processing/preprocessors/property/placement/post/StandardInteractPostProcessor.kt index 2f0b5011e..8ea4f4863 100644 --- a/src/main/kotlin/com/lambda/interaction/construction/simulation/processing/preprocessors/property/placement/post/StandardInteractPostProcessor.kt +++ b/src/main/kotlin/com/lambda/interaction/construction/simulation/processing/preprocessors/property/placement/post/StandardInteractPostProcessor.kt @@ -22,12 +22,10 @@ import com.lambda.interaction.construction.simulation.processing.PreProcessingIn import com.lambda.interaction.construction.simulation.processing.ProcessorRegistry.standardInteractProperties import com.lambda.interaction.construction.simulation.processing.PropertyPostProcessor import net.minecraft.block.BlockState -import net.minecraft.block.Blocks import net.minecraft.block.DoorBlock import net.minecraft.block.TrapdoorBlock import net.minecraft.util.math.BlockPos -// Collected using reflections and then accessed from a collection in ProcessorRegistry @Suppress("unused") object StandardInteractPostProcessor : PropertyPostProcessor { override fun acceptsState(state: BlockState, targetState: BlockState) = diff --git a/src/main/kotlin/com/lambda/interaction/construction/simulation/processing/preprocessors/property/placement/pre/AttachmentPreProcessor.kt b/src/main/kotlin/com/lambda/interaction/construction/simulation/processing/preprocessors/property/placement/pre/AttachmentPreProcessor.kt index 9d4ee6122..a37876bfa 100644 --- a/src/main/kotlin/com/lambda/interaction/construction/simulation/processing/preprocessors/property/placement/pre/AttachmentPreProcessor.kt +++ b/src/main/kotlin/com/lambda/interaction/construction/simulation/processing/preprocessors/property/placement/pre/AttachmentPreProcessor.kt @@ -26,7 +26,6 @@ import net.minecraft.state.property.Properties import net.minecraft.util.math.BlockPos import net.minecraft.util.math.Direction -// Collected using reflections and then accessed from a collection in ProcessorRegistry @Suppress("unused") object AttachmentPreProcessor : PropertyPreProcessor { override fun acceptsState(state: BlockState, targetState: BlockState) = diff --git a/src/main/kotlin/com/lambda/interaction/construction/simulation/processing/preprocessors/property/placement/pre/AxisPreProcessor.kt b/src/main/kotlin/com/lambda/interaction/construction/simulation/processing/preprocessors/property/placement/pre/AxisPreProcessor.kt index 317a6a6e9..0877bdac5 100644 --- a/src/main/kotlin/com/lambda/interaction/construction/simulation/processing/preprocessors/property/placement/pre/AxisPreProcessor.kt +++ b/src/main/kotlin/com/lambda/interaction/construction/simulation/processing/preprocessors/property/placement/pre/AxisPreProcessor.kt @@ -24,7 +24,6 @@ import net.minecraft.block.BlockState import net.minecraft.state.property.Properties import net.minecraft.util.math.BlockPos -// Collected using reflections and then accessed from a collection in ProcessorRegistry @Suppress("unused") object AxisPreProcessor : PropertyPreProcessor { override fun acceptsState(state: BlockState, targetState: BlockState) = diff --git a/src/main/kotlin/com/lambda/interaction/construction/simulation/processing/preprocessors/property/placement/pre/BlockFacePreProcessor.kt b/src/main/kotlin/com/lambda/interaction/construction/simulation/processing/preprocessors/property/placement/pre/BlockFacePreProcessor.kt index 9c6c7fb81..d61b184a6 100644 --- a/src/main/kotlin/com/lambda/interaction/construction/simulation/processing/preprocessors/property/placement/pre/BlockFacePreProcessor.kt +++ b/src/main/kotlin/com/lambda/interaction/construction/simulation/processing/preprocessors/property/placement/pre/BlockFacePreProcessor.kt @@ -26,7 +26,6 @@ import net.minecraft.state.property.Properties import net.minecraft.util.math.BlockPos import net.minecraft.util.math.Direction -// Collected using reflections and then accessed from a collection in ProcessorRegistry @Suppress("unused") object BlockFacePreProcessor : PropertyPreProcessor { override fun acceptsState(state: BlockState, targetState: BlockState) = diff --git a/src/main/kotlin/com/lambda/interaction/construction/simulation/processing/preprocessors/property/placement/pre/BlockHalfPreProcessor.kt b/src/main/kotlin/com/lambda/interaction/construction/simulation/processing/preprocessors/property/placement/pre/BlockHalfPreProcessor.kt index 0ea978439..47af759f2 100644 --- a/src/main/kotlin/com/lambda/interaction/construction/simulation/processing/preprocessors/property/placement/pre/BlockHalfPreProcessor.kt +++ b/src/main/kotlin/com/lambda/interaction/construction/simulation/processing/preprocessors/property/placement/pre/BlockHalfPreProcessor.kt @@ -28,7 +28,6 @@ import net.minecraft.state.property.Properties import net.minecraft.util.math.BlockPos import net.minecraft.util.math.Direction -// Collected using reflections and then accessed from a collection in ProcessorRegistry @Suppress("unused") object BlockHalfPreProcessor : PropertyPreProcessor { override fun acceptsState(state: BlockState, targetState: BlockState) = diff --git a/src/main/kotlin/com/lambda/interaction/construction/simulation/processing/preprocessors/property/placement/pre/ChestPreProcessor.kt b/src/main/kotlin/com/lambda/interaction/construction/simulation/processing/preprocessors/property/placement/pre/ChestPreProcessor.kt index e82691361..d0a70d09b 100644 --- a/src/main/kotlin/com/lambda/interaction/construction/simulation/processing/preprocessors/property/placement/pre/ChestPreProcessor.kt +++ b/src/main/kotlin/com/lambda/interaction/construction/simulation/processing/preprocessors/property/placement/pre/ChestPreProcessor.kt @@ -26,7 +26,6 @@ import net.minecraft.block.enums.ChestType import net.minecraft.state.property.Properties import net.minecraft.util.math.BlockPos -// Collected using reflections and then accessed from a collection in ProcessorRegistry @Suppress("unused") object ChestPreProcessor : PropertyPreProcessor { override fun acceptsState(state: BlockState, targetState: BlockState) = diff --git a/src/main/kotlin/com/lambda/interaction/construction/simulation/processing/preprocessors/property/placement/pre/DoorHingePreProcessor.kt b/src/main/kotlin/com/lambda/interaction/construction/simulation/processing/preprocessors/property/placement/pre/DoorHingePreProcessor.kt index 1602cba7c..3fc96466e 100644 --- a/src/main/kotlin/com/lambda/interaction/construction/simulation/processing/preprocessors/property/placement/pre/DoorHingePreProcessor.kt +++ b/src/main/kotlin/com/lambda/interaction/construction/simulation/processing/preprocessors/property/placement/pre/DoorHingePreProcessor.kt @@ -28,7 +28,6 @@ import net.minecraft.state.property.Properties import net.minecraft.util.math.BlockPos import net.minecraft.util.math.Direction -// Collected using reflections and then accessed from a collection in ProcessorRegistry @Suppress("unused") object DoorHingePreProcessor : PropertyPreProcessor { override fun acceptsState(state: BlockState, targetState: BlockState) = diff --git a/src/main/kotlin/com/lambda/interaction/construction/simulation/processing/preprocessors/property/placement/pre/HopperFacingPreProcessor.kt b/src/main/kotlin/com/lambda/interaction/construction/simulation/processing/preprocessors/property/placement/pre/HopperFacingPreProcessor.kt index 25d733f6a..9cc3415ce 100644 --- a/src/main/kotlin/com/lambda/interaction/construction/simulation/processing/preprocessors/property/placement/pre/HopperFacingPreProcessor.kt +++ b/src/main/kotlin/com/lambda/interaction/construction/simulation/processing/preprocessors/property/placement/pre/HopperFacingPreProcessor.kt @@ -25,7 +25,6 @@ import net.minecraft.state.property.Properties import net.minecraft.util.math.BlockPos import net.minecraft.util.math.Direction -// Collected using reflections and then accessed from a collection in ProcessorRegistry @Suppress("unused") object HopperFacingPreProcessor : PropertyPreProcessor { override fun acceptsState(state: BlockState, targetState: BlockState) = diff --git a/src/main/kotlin/com/lambda/interaction/construction/simulation/processing/preprocessors/property/placement/pre/SlabPreProcessor.kt b/src/main/kotlin/com/lambda/interaction/construction/simulation/processing/preprocessors/property/placement/pre/SlabPreProcessor.kt index 4cdef28ed..3a3605604 100644 --- a/src/main/kotlin/com/lambda/interaction/construction/simulation/processing/preprocessors/property/placement/pre/SlabPreProcessor.kt +++ b/src/main/kotlin/com/lambda/interaction/construction/simulation/processing/preprocessors/property/placement/pre/SlabPreProcessor.kt @@ -29,7 +29,6 @@ import net.minecraft.state.property.Properties import net.minecraft.util.math.BlockPos import net.minecraft.util.math.Direction -// Collected using reflections and then accessed from a collection in ProcessorRegistry @Suppress("unused") object SlabPreProcessor : PropertyPreProcessor { override fun acceptsState(state: BlockState, targetState: BlockState) = targetState.block is SlabBlock diff --git a/src/main/kotlin/com/lambda/interaction/construction/simulation/processing/preprocessors/state/BambooStateProcessor.kt b/src/main/kotlin/com/lambda/interaction/construction/simulation/processing/preprocessors/state/BambooStateProcessor.kt index 22a158f71..6f3ed7302 100644 --- a/src/main/kotlin/com/lambda/interaction/construction/simulation/processing/preprocessors/state/BambooStateProcessor.kt +++ b/src/main/kotlin/com/lambda/interaction/construction/simulation/processing/preprocessors/state/BambooStateProcessor.kt @@ -27,7 +27,6 @@ import net.minecraft.block.Blocks import net.minecraft.item.Items import net.minecraft.util.math.BlockPos -// Collected using reflections and then accessed from a collection in ProcessorRegistry @Suppress("unused") object BambooStateProcessor : StateProcessor { override fun acceptsState(state: BlockState, targetState: BlockState) = diff --git a/src/main/kotlin/com/lambda/interaction/construction/simulation/processing/preprocessors/state/FireStateProcessor.kt b/src/main/kotlin/com/lambda/interaction/construction/simulation/processing/preprocessors/state/FireStateProcessor.kt index 078e09ae4..f2123d2cb 100644 --- a/src/main/kotlin/com/lambda/interaction/construction/simulation/processing/preprocessors/state/FireStateProcessor.kt +++ b/src/main/kotlin/com/lambda/interaction/construction/simulation/processing/preprocessors/state/FireStateProcessor.kt @@ -25,7 +25,6 @@ import net.minecraft.block.Blocks import net.minecraft.item.Items import net.minecraft.util.math.BlockPos -// Collected using reflections and then accessed from a collection in ProcessorRegistry @Suppress("unused") object FireStateProcessor : StateProcessor { override fun acceptsState(state: BlockState, targetState: BlockState) = diff --git a/src/main/kotlin/com/lambda/interaction/construction/simulation/processing/preprocessors/state/FlowerPotStateProcessor.kt b/src/main/kotlin/com/lambda/interaction/construction/simulation/processing/preprocessors/state/FlowerPotStateProcessor.kt index 981a41b33..c6a649fc6 100644 --- a/src/main/kotlin/com/lambda/interaction/construction/simulation/processing/preprocessors/state/FlowerPotStateProcessor.kt +++ b/src/main/kotlin/com/lambda/interaction/construction/simulation/processing/preprocessors/state/FlowerPotStateProcessor.kt @@ -26,7 +26,6 @@ import net.minecraft.block.FlowerPotBlock import net.minecraft.item.Items import net.minecraft.util.math.BlockPos -// Collected using reflections and then accessed from a collection in ProcessorRegistry @Suppress("unused") object FlowerPotStateProcessor : StateProcessor { override fun acceptsState(state: BlockState, targetState: BlockState) = diff --git a/src/main/kotlin/com/lambda/interaction/construction/simulation/result/Contextual.kt b/src/main/kotlin/com/lambda/interaction/construction/simulation/result/Contextual.kt index 4d98d6292..f996a87a0 100644 --- a/src/main/kotlin/com/lambda/interaction/construction/simulation/result/Contextual.kt +++ b/src/main/kotlin/com/lambda/interaction/construction/simulation/result/Contextual.kt @@ -17,7 +17,7 @@ package com.lambda.interaction.construction.simulation.result -import com.lambda.config.groups.ActionConfig +import com.lambda.config.settings.blocks.ActionConfig import com.lambda.interaction.construction.simulation.context.BreakContext import com.lambda.interaction.construction.simulation.context.BuildContext import com.lambda.interaction.construction.simulation.context.InteractContext diff --git a/src/main/kotlin/com/lambda/interaction/construction/simulation/result/Drawable.kt b/src/main/kotlin/com/lambda/interaction/construction/simulation/result/Drawable.kt index 517a29518..57fdae135 100644 --- a/src/main/kotlin/com/lambda/interaction/construction/simulation/result/Drawable.kt +++ b/src/main/kotlin/com/lambda/interaction/construction/simulation/result/Drawable.kt @@ -18,7 +18,6 @@ package com.lambda.interaction.construction.simulation.result import com.lambda.graphics.mc.RenderBuilder -import com.lambda.graphics.mc.renderer.TickedRenderer /** * Represents a [BuildResult] that can be rendered in-game. diff --git a/src/main/kotlin/com/lambda/interaction/construction/simulation/result/Navigable.kt b/src/main/kotlin/com/lambda/interaction/construction/simulation/result/Navigable.kt index 47611f36d..dcbd702da 100644 --- a/src/main/kotlin/com/lambda/interaction/construction/simulation/result/Navigable.kt +++ b/src/main/kotlin/com/lambda/interaction/construction/simulation/result/Navigable.kt @@ -23,5 +23,5 @@ import baritone.api.pathing.goals.Goal * Represents a [BuildResult] with a pathing goal. */ interface Navigable { - val goal: Goal + val goal: Goal? } diff --git a/src/main/kotlin/com/lambda/interaction/construction/simulation/result/results/BreakResult.kt b/src/main/kotlin/com/lambda/interaction/construction/simulation/result/results/BreakResult.kt index 28005dab2..54cb085e1 100644 --- a/src/main/kotlin/com/lambda/interaction/construction/simulation/result/results/BreakResult.kt +++ b/src/main/kotlin/com/lambda/interaction/construction/simulation/result/results/BreakResult.kt @@ -22,6 +22,7 @@ import baritone.api.pathing.goals.GoalInverted import com.lambda.context.AutomatedSafeContext import com.lambda.graphics.mc.RenderBuilder import com.lambda.graphics.util.DirectionMask.mask +import com.lambda.interaction.BaritoneHandler import com.lambda.interaction.construction.simulation.context.BreakContext import com.lambda.interaction.construction.simulation.result.BuildResult import com.lambda.interaction.construction.simulation.result.ComparableResult @@ -32,7 +33,7 @@ import com.lambda.interaction.construction.simulation.result.Navigable import com.lambda.interaction.construction.simulation.result.Rank import com.lambda.interaction.construction.simulation.result.Resolvable import com.lambda.interaction.material.StackSelection.Companion.selectStack -import com.lambda.interaction.material.container.ContainerManager.transferByTask +import com.lambda.interaction.material.container.ContainerHandler.transferByTask import com.lambda.interaction.material.container.containers.HotbarContainer import com.lambda.task.Task import net.minecraft.block.BlockState @@ -181,7 +182,7 @@ sealed class BreakResult : BuildResult() { override val rank = Rank.BreakPlayerOnTop private val color = Color(252, 3, 207, 100) - override val goal = GoalInverted(GoalBlock(pos)) + override val goal = if (BaritoneHandler.isBaritoneLoaded) GoalInverted(GoalBlock(pos)) else null override fun RenderBuilder.render() { box(pos) { diff --git a/src/main/kotlin/com/lambda/interaction/construction/simulation/result/results/GenericResult.kt b/src/main/kotlin/com/lambda/interaction/construction/simulation/result/results/GenericResult.kt index 31c5ced68..404f61963 100644 --- a/src/main/kotlin/com/lambda/interaction/construction/simulation/result/results/GenericResult.kt +++ b/src/main/kotlin/com/lambda/interaction/construction/simulation/result/results/GenericResult.kt @@ -20,6 +20,7 @@ package com.lambda.interaction.construction.simulation.result.results import baritone.api.pathing.goals.GoalNear import com.lambda.context.AutomatedSafeContext import com.lambda.graphics.mc.RenderBuilder +import com.lambda.interaction.BaritoneHandler import com.lambda.interaction.construction.simulation.result.BuildResult import com.lambda.interaction.construction.simulation.result.ComparableResult import com.lambda.interaction.construction.simulation.result.Drawable @@ -27,7 +28,7 @@ import com.lambda.interaction.construction.simulation.result.Navigable import com.lambda.interaction.construction.simulation.result.Rank import com.lambda.interaction.construction.simulation.result.Resolvable import com.lambda.interaction.material.StackSelection -import com.lambda.interaction.material.container.ContainerManager.transferByTask +import com.lambda.interaction.material.container.ContainerHandler.transferByTask import com.lambda.interaction.material.container.containers.HotbarContainer import com.lambda.task.Task import net.minecraft.client.data.TextureMap.side @@ -133,7 +134,7 @@ sealed class GenericResult : BuildResult() { misses.minOfOrNull { pov.distanceTo(it.first) } ?: 0.0 } - override val goal = GoalNear(pos, 3) + override val goal = if (BaritoneHandler.isBaritoneLoaded) GoalNear(pos, 3) else null override fun RenderBuilder.render() { val center = pos.toCenterPos() diff --git a/src/main/kotlin/com/lambda/interaction/construction/simulation/result/results/InteractResult.kt b/src/main/kotlin/com/lambda/interaction/construction/simulation/result/results/InteractResult.kt index 817c96658..86c7fe4fd 100644 --- a/src/main/kotlin/com/lambda/interaction/construction/simulation/result/results/InteractResult.kt +++ b/src/main/kotlin/com/lambda/interaction/construction/simulation/result/results/InteractResult.kt @@ -20,7 +20,7 @@ package com.lambda.interaction.construction.simulation.result.results import baritone.api.pathing.goals.GoalBlock import baritone.api.pathing.goals.GoalInverted import com.lambda.graphics.mc.RenderBuilder -import com.lambda.graphics.mc.renderer.TickedRenderer +import com.lambda.interaction.BaritoneHandler import com.lambda.interaction.construction.simulation.context.InteractContext import com.lambda.interaction.construction.simulation.result.BuildResult import com.lambda.interaction.construction.simulation.result.Contextual @@ -105,7 +105,7 @@ sealed class InteractResult : BuildResult() { override val pos: BlockPos ) : Navigable, InteractResult() { override val rank = Rank.PlaceBlockedByPlayer - override val goal = GoalInverted(GoalBlock(pos)) + override val goal = if (BaritoneHandler.isBaritoneLoaded) GoalInverted(GoalBlock(pos)) else null } /** diff --git a/src/main/kotlin/com/lambda/interaction/construction/simulation/result/results/PreSimResult.kt b/src/main/kotlin/com/lambda/interaction/construction/simulation/result/results/PreSimResult.kt index 496552fc0..8369a0b27 100644 --- a/src/main/kotlin/com/lambda/interaction/construction/simulation/result/results/PreSimResult.kt +++ b/src/main/kotlin/com/lambda/interaction/construction/simulation/result/results/PreSimResult.kt @@ -19,6 +19,7 @@ package com.lambda.interaction.construction.simulation.result.results import baritone.api.pathing.goals.GoalBlock import com.lambda.graphics.mc.RenderBuilder +import com.lambda.interaction.BaritoneHandler import com.lambda.interaction.construction.simulation.result.BuildResult import com.lambda.interaction.construction.simulation.result.ComparableResult import com.lambda.interaction.construction.simulation.result.Drawable @@ -53,7 +54,7 @@ sealed class PreSimResult : BuildResult() { override val rank = Rank.ChunkNotLoaded private val color = Color(252, 165, 3, 100) - override val goal = GoalBlock(pos) + override val goal = if (BaritoneHandler.isBaritoneLoaded) GoalBlock(pos) else null override fun RenderBuilder.render() { box(pos) { diff --git a/src/main/kotlin/com/lambda/interaction/construction/verify/TargetState.kt b/src/main/kotlin/com/lambda/interaction/construction/verify/TargetState.kt index e7f41c57f..167040608 100644 --- a/src/main/kotlin/com/lambda/interaction/construction/verify/TargetState.kt +++ b/src/main/kotlin/com/lambda/interaction/construction/verify/TargetState.kt @@ -19,7 +19,7 @@ package com.lambda.interaction.construction.verify import com.lambda.context.AutomatedSafeContext import com.lambda.context.SafeContext -import com.lambda.interaction.material.container.ContainerManager.findDisposable +import com.lambda.interaction.material.container.ContainerHandler.findDisposable import com.lambda.util.BlockUtils.blockState import com.lambda.util.BlockUtils.emptyState import com.lambda.util.BlockUtils.isEmpty diff --git a/src/main/kotlin/com/lambda/interaction/managers/ManagerUtils.kt b/src/main/kotlin/com/lambda/interaction/managers/ManagerUtils.kt index 491eb623c..9a5f193bd 100644 --- a/src/main/kotlin/com/lambda/interaction/managers/ManagerUtils.kt +++ b/src/main/kotlin/com/lambda/interaction/managers/ManagerUtils.kt @@ -17,7 +17,7 @@ package com.lambda.interaction.managers -import com.lambda.util.reflections.getInstances +import com.lambda.util.ReflectionUtils.getInstances import net.minecraft.util.math.BlockPos object ManagerUtils { diff --git a/src/main/kotlin/com/lambda/interaction/managers/PacketLimitHandler.kt b/src/main/kotlin/com/lambda/interaction/managers/PacketLimitHandler.kt index bd0407a22..d9d4ba6bb 100644 --- a/src/main/kotlin/com/lambda/interaction/managers/PacketLimitHandler.kt +++ b/src/main/kotlin/com/lambda/interaction/managers/PacketLimitHandler.kt @@ -17,13 +17,13 @@ package com.lambda.interaction.managers -import com.lambda.config.groups.BuildConfig +import com.lambda.config.settings.blocks.BuildConfig import com.lambda.context.Automated import com.lambda.event.events.TickEvent import com.lambda.event.listener.SafeListener.Companion.listen +import kotlin.time.ComparableTimeMark import kotlin.time.Duration import kotlin.time.Duration.Companion.milliseconds -import kotlin.time.ComparableTimeMark import kotlin.time.TimeSource object PacketLimitHandler { diff --git a/src/main/kotlin/com/lambda/interaction/managers/breaking/BreakInfo.kt b/src/main/kotlin/com/lambda/interaction/managers/breaking/BreakInfo.kt index 0d0873dee..e36ce31f5 100644 --- a/src/main/kotlin/com/lambda/interaction/managers/breaking/BreakInfo.kt +++ b/src/main/kotlin/com/lambda/interaction/managers/breaking/BreakInfo.kt @@ -17,6 +17,7 @@ package com.lambda.interaction.managers.breaking +import com.lambda.config.settings.blocks.BreakConfig import com.lambda.context.SafeContext import com.lambda.interaction.construction.simulation.context.BreakContext import com.lambda.interaction.managers.ActionInfo 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 1b3d06fe0..65d001379 100644 --- a/src/main/kotlin/com/lambda/interaction/managers/breaking/BreakManager.kt +++ b/src/main/kotlin/com/lambda/interaction/managers/breaking/BreakManager.kt @@ -17,6 +17,9 @@ package com.lambda.interaction.managers.breaking +import com.lambda.config.settings.blocks.BreakConfig +import com.lambda.config.settings.blocks.BreakConfig.BreakConfirmationMode +import com.lambda.config.settings.blocks.BreakConfig.BreakMode import com.lambda.context.AutomatedSafeContext import com.lambda.context.SafeContext import com.lambda.event.events.ConnectionEvent @@ -36,8 +39,6 @@ import com.lambda.interaction.managers.ManagerUtils.isPosBlocked import com.lambda.interaction.managers.PacketLimitHandler import com.lambda.interaction.managers.PacketType import com.lambda.interaction.managers.PositionBlocking -import com.lambda.interaction.managers.breaking.BreakConfig.BreakConfirmationMode -import com.lambda.interaction.managers.breaking.BreakConfig.BreakMode import com.lambda.interaction.managers.breaking.BreakInfo.BreakType.Primary import com.lambda.interaction.managers.breaking.BreakInfo.BreakType.Rebreak import com.lambda.interaction.managers.breaking.BreakInfo.BreakType.RedundantSecondary @@ -137,7 +138,7 @@ object BreakManager : Manager( .lastOrNull { it.breakConfig.doubleBreak || it.type == Secondary }?.context?.itemSelection - ?: StackSelection.EVERYTHING.select() + ?: StackSelection.Everything.select() override val blockedPositions get() = activeInfos.map { it.context.blockPos } + pendingActions.map { it.context.blockPos } diff --git a/src/main/kotlin/com/lambda/interaction/managers/breaking/BrokenBlockHandler.kt b/src/main/kotlin/com/lambda/interaction/managers/breaking/BrokenBlockHandler.kt index fdd3db098..5bc31bf11 100644 --- a/src/main/kotlin/com/lambda/interaction/managers/breaking/BrokenBlockHandler.kt +++ b/src/main/kotlin/com/lambda/interaction/managers/breaking/BrokenBlockHandler.kt @@ -17,26 +17,26 @@ package com.lambda.interaction.managers.breaking -import com.lambda.config.AutomationConfig.Companion.DEFAULT -import com.lambda.module.modules.client.Client -import com.lambda.module.modules.client.Client.verboseDebug +import com.lambda.config.automation.AutomationConfig.Companion.Default +import com.lambda.config.settings.blocks.BreakConfig.BreakConfirmationMode import com.lambda.context.SafeContext import com.lambda.event.events.EntityEvent import com.lambda.event.events.WorldEvent import com.lambda.event.listener.SafeListener.Companion.listen import com.lambda.interaction.construction.simulation.processing.ProcessorRegistry import com.lambda.interaction.managers.PostActionHandler -import com.lambda.interaction.managers.breaking.BreakConfig.BreakConfirmationMode import com.lambda.interaction.managers.breaking.BreakManager.lastPosStarted import com.lambda.interaction.managers.breaking.BreakManager.matchesBlockItem import com.lambda.interaction.managers.breaking.RebreakHandler.rebreak +import com.lambda.module.modules.client.Client +import com.lambda.module.modules.client.Client.verboseDebug import com.lambda.threading.runSafe import com.lambda.util.BlockUtils.emptyState import com.lambda.util.BlockUtils.fluidState import com.lambda.util.BlockUtils.isEmpty import com.lambda.util.BlockUtils.isNotBroken import com.lambda.util.BlockUtils.matches -import com.lambda.util.Communication.warn +import com.lambda.util.CommunicationUtils.warn import com.lambda.util.collections.LimitedDecayQueue import com.lambda.util.player.gamemode import net.minecraft.block.OperatorBlock @@ -51,7 +51,7 @@ import net.minecraft.util.math.ChunkSectionPos */ object BrokenBlockHandler : PostActionHandler() { override val pendingActions = LimitedDecayQueue( - DEFAULT.buildConfig.maxPendingActions, DEFAULT.buildConfig.actionTimeout * 50L + Default.buildConfig.maxPendingActions, Default.buildConfig.actionTimeout * 50L ) { info -> runSafe { val pos = info.context.blockPos diff --git a/src/main/kotlin/com/lambda/interaction/managers/breaking/RebreakHandler.kt b/src/main/kotlin/com/lambda/interaction/managers/breaking/RebreakHandler.kt index e504e5603..e80fba20b 100644 --- a/src/main/kotlin/com/lambda/interaction/managers/breaking/RebreakHandler.kt +++ b/src/main/kotlin/com/lambda/interaction/managers/breaking/RebreakHandler.kt @@ -17,6 +17,7 @@ package com.lambda.interaction.managers.breaking +import com.lambda.config.settings.blocks.BreakConfig import com.lambda.context.SafeContext import com.lambda.event.events.ConnectionEvent import com.lambda.event.events.TickEvent diff --git a/src/main/kotlin/com/lambda/interaction/managers/breaking/SwapInfo.kt b/src/main/kotlin/com/lambda/interaction/managers/breaking/SwapInfo.kt index 2e79dd828..39850164a 100644 --- a/src/main/kotlin/com/lambda/interaction/managers/breaking/SwapInfo.kt +++ b/src/main/kotlin/com/lambda/interaction/managers/breaking/SwapInfo.kt @@ -17,7 +17,8 @@ package com.lambda.interaction.managers.breaking -import com.lambda.config.AutomationConfig.Companion.DEFAULT +import com.lambda.config.automation.AutomationConfig.Companion.Default +import com.lambda.config.settings.blocks.BreakConfig import com.lambda.context.Automated import com.lambda.context.SafeContext import com.lambda.interaction.managers.breaking.BreakInfo.BreakType.Primary @@ -30,7 +31,7 @@ import com.lambda.threading.runSafeAutomated */ data class SwapInfo( private val type: BreakInfo.BreakType, - private val automated: Automated = DEFAULT, + private val automated: Automated = Default, val swap: Boolean = false, val longSwap: Boolean = false ) : Automated by automated { diff --git a/src/main/kotlin/com/lambda/interaction/managers/hotbar/HotbarManager.kt b/src/main/kotlin/com/lambda/interaction/managers/hotbar/HotbarManager.kt index 4bc8bcca9..a4b19c48c 100644 --- a/src/main/kotlin/com/lambda/interaction/managers/hotbar/HotbarManager.kt +++ b/src/main/kotlin/com/lambda/interaction/managers/hotbar/HotbarManager.kt @@ -17,12 +17,12 @@ package com.lambda.interaction.managers.hotbar +import com.lambda.config.settings.blocks.HotbarConfig.SwapMode import com.lambda.context.AutomatedSafeContext import com.lambda.context.SafeContext import com.lambda.event.events.TickEvent import com.lambda.event.listener.SafeListener.Companion.listen import com.lambda.interaction.managers.Manager -import com.lambda.interaction.managers.hotbar.HotbarConfig.SwapMode import com.lambda.interaction.managers.hotbar.HotbarManager.activeRequest import com.lambda.interaction.managers.hotbar.HotbarManager.activeSlot import com.lambda.interaction.managers.hotbar.HotbarManager.checkResetSwap @@ -142,7 +142,7 @@ object HotbarManager : Manager( /** * Called after every [tickStage] closes. This method checks if the current [activeRequest] should be stopped. * This action is counted as another swap, so the conditions for a regular swap must be met. If the requests - * [HotbarConfig.tickStageMask] does not contain the current tick stage, no actions can be performed. + * [com.lambda.config.blocks.HotbarConfig.tickStageMask] does not contain the current tick stage, no actions can be performed. * * @see net.minecraft.client.network.ClientPlayerInteractionManager.syncSelectedSlot */ diff --git a/src/main/kotlin/com/lambda/interaction/managers/interacting/InteractInfo.kt b/src/main/kotlin/com/lambda/interaction/managers/interacting/InteractInfo.kt index febea9365..7fbfe671b 100644 --- a/src/main/kotlin/com/lambda/interaction/managers/interacting/InteractInfo.kt +++ b/src/main/kotlin/com/lambda/interaction/managers/interacting/InteractInfo.kt @@ -17,6 +17,7 @@ package com.lambda.interaction.managers.interacting +import com.lambda.config.settings.blocks.InteractConfig import com.lambda.context.SafeContext import com.lambda.interaction.construction.simulation.context.BuildContext import com.lambda.interaction.construction.simulation.context.InteractContext diff --git a/src/main/kotlin/com/lambda/interaction/managers/interacting/InteractManager.kt b/src/main/kotlin/com/lambda/interaction/managers/interacting/InteractManager.kt index fb0a23952..c98fee685 100644 --- a/src/main/kotlin/com/lambda/interaction/managers/interacting/InteractManager.kt +++ b/src/main/kotlin/com/lambda/interaction/managers/interacting/InteractManager.kt @@ -17,6 +17,8 @@ package com.lambda.interaction.managers.interacting +import com.lambda.config.settings.blocks.InteractConfig +import com.lambda.config.settings.blocks.InteractConfig.AirPlaceMode import com.lambda.context.Automated import com.lambda.context.AutomatedSafeContext import com.lambda.context.SafeContext @@ -34,9 +36,10 @@ import com.lambda.interaction.managers.PacketType import com.lambda.interaction.managers.PositionBlocking import com.lambda.interaction.managers.breaking.BreakManager import com.lambda.interaction.managers.hotbar.HotbarRequest -import com.lambda.interaction.managers.interacting.InteractConfig.AirPlaceMode import com.lambda.interaction.managers.interacting.InteractManager.activeRequest +import com.lambda.interaction.managers.interacting.InteractManager.maxInteractionsThisTick import com.lambda.interaction.managers.interacting.InteractManager.populateFrom +import com.lambda.interaction.managers.interacting.InteractManager.potentialInteractions import com.lambda.interaction.managers.interacting.InteractManager.processRequest import com.lambda.interaction.managers.interacting.InteractedBlockHandler.pendingActions import com.lambda.interaction.managers.interacting.InteractedBlockHandler.setPendingConfigs @@ -47,6 +50,7 @@ import com.lambda.threading.runConcurrent import com.lambda.threading.runSafeAutomated import com.lambda.threading.runSafeGameScheduled import com.lambda.util.BlockUtils.blockState +import com.lambda.util.PacketUtils.sendPacket import com.lambda.util.item.ItemUtils.blockItem import com.lambda.util.player.MovementUtils.sneaking import com.lambda.util.player.gamemode @@ -215,9 +219,9 @@ object InteractManager : Manager( runConcurrent { delay(signWriteDelay) runSafeGameScheduled { - connection.sendPacket( + connection.sendPacket { UpdateSignC2SPacket(ctx.blockPos, true, "", "", "", "") - ) + } } } } diff --git a/src/main/kotlin/com/lambda/interaction/managers/interacting/InteractedBlockHandler.kt b/src/main/kotlin/com/lambda/interaction/managers/interacting/InteractedBlockHandler.kt index 031267e9d..c456b02ed 100644 --- a/src/main/kotlin/com/lambda/interaction/managers/interacting/InteractedBlockHandler.kt +++ b/src/main/kotlin/com/lambda/interaction/managers/interacting/InteractedBlockHandler.kt @@ -17,21 +17,22 @@ package com.lambda.interaction.managers.interacting -import com.lambda.config.AutomationConfig.Companion.DEFAULT -import com.lambda.module.modules.client.Client.verboseDebug +import com.lambda.config.automation.AutomationConfig.Companion.Default +import com.lambda.config.settings.blocks.InteractConfig import com.lambda.event.events.WorldEvent import com.lambda.event.listener.SafeListener.Companion.listen import com.lambda.interaction.managers.PostActionHandler import com.lambda.interaction.managers.interacting.InteractManager.placeSound +import com.lambda.module.modules.client.Client.verboseDebug import com.lambda.threading.runSafe import com.lambda.util.BlockUtils.matches -import com.lambda.util.Communication.warn +import com.lambda.util.CommunicationUtils.warn import com.lambda.util.collections.LimitedDecayQueue object InteractedBlockHandler : PostActionHandler() { override val pendingActions = LimitedDecayQueue( - DEFAULT.buildConfig.maxPendingActions, - DEFAULT.buildConfig.actionTimeout * 50L + Default.buildConfig.maxPendingActions, + Default.buildConfig.actionTimeout * 50L ) { if (verboseDebug) warn("${it::class.simpleName} at ${it.context.blockPos.toShortString()} timed out") if (it.interactConfig.interactConfirmationMode != InteractConfig.InteractConfirmationMode.AwaitThenPlace) { diff --git a/src/main/kotlin/com/lambda/interaction/managers/inventory/InventoryRequest.kt b/src/main/kotlin/com/lambda/interaction/managers/inventory/InventoryRequest.kt index db42c1484..91431edab 100644 --- a/src/main/kotlin/com/lambda/interaction/managers/inventory/InventoryRequest.kt +++ b/src/main/kotlin/com/lambda/interaction/managers/inventory/InventoryRequest.kt @@ -101,13 +101,13 @@ class InventoryRequest private constructor( val offhandStack = player.getStackInHand(Hand.OFF_HAND) player.setStackInHand(Hand.OFF_HAND, player.getStackInHand(Hand.MAIN_HAND)) player.setStackInHand(Hand.MAIN_HAND, offhandStack) - connection.sendPacket( + connection.sendPacket { PlayerActionC2SPacket( PlayerActionC2SPacket.Action.SWAP_ITEM_WITH_OFFHAND, BlockPos.ORIGIN, Direction.DOWN ) - ) + } }.addToActions() } diff --git a/src/main/kotlin/com/lambda/interaction/managers/rotating/Rotation.kt b/src/main/kotlin/com/lambda/interaction/managers/rotating/Rotation.kt index 18f85a196..3da702a11 100644 --- a/src/main/kotlin/com/lambda/interaction/managers/rotating/Rotation.kt +++ b/src/main/kotlin/com/lambda/interaction/managers/rotating/Rotation.kt @@ -88,9 +88,9 @@ data class Rotation(val yaw: Double, val pitch: Double) { else -> 0.0f } - val ZERO = Rotation(0.0, 0.0) - val DOWN = Rotation(0.0, 90.0) - val UP = Rotation(0.0, -90.0) + val Zero = Rotation(0.0, 0.0) + val Down = Rotation(0.0, 90.0) + val Up = Rotation(0.0, -90.0) val Direction.rotation get() = Rotation(yaw.toDouble(), 0.0) var Entity.rotation get() = Rotation(yaw, pitch) diff --git a/src/main/kotlin/com/lambda/interaction/managers/rotating/RotationManager.kt b/src/main/kotlin/com/lambda/interaction/managers/rotating/RotationManager.kt index ddb15812f..343a95a8d 100644 --- a/src/main/kotlin/com/lambda/interaction/managers/rotating/RotationManager.kt +++ b/src/main/kotlin/com/lambda/interaction/managers/rotating/RotationManager.kt @@ -28,7 +28,7 @@ import com.lambda.event.events.TickEvent import com.lambda.event.events.TickEvent.Companion.ALL_STAGES import com.lambda.event.listener.SafeListener.Companion.listen import com.lambda.event.listener.UnsafeListener.Companion.listenUnsafe -import com.lambda.interaction.BaritoneManager +import com.lambda.interaction.BaritoneHandler import com.lambda.interaction.managers.Manager import com.lambda.interaction.managers.rotating.Rotation.Companion.slerpPitch import com.lambda.interaction.managers.rotating.Rotation.Companion.slerpYaw @@ -55,6 +55,7 @@ import kotlin.math.sin /** * Manager designed to rotate the player and adjust movement input to match the camera's direction. */ +@Suppress("unused") object RotationManager : Manager( 1, *(ALL_STAGES.subList(ALL_STAGES.indexOf(TickEvent.Player.Post), ALL_STAGES.size - 1).toTypedArray()), @@ -68,9 +69,9 @@ object RotationManager : Manager( @JvmStatic val requests = mutableListOf(null, null) private var usingBaritoneRotation = false - @JvmStatic var activeRotation = Rotation.ZERO - @JvmStatic var serverRotation = Rotation.ZERO - @JvmStatic var prevServerRotation = Rotation.ZERO + @JvmStatic var activeRotation = Rotation.Zero + @JvmStatic var serverRotation = Rotation.Zero + @JvmStatic var prevServerRotation = Rotation.Zero private var changedThisTick = false @@ -119,7 +120,7 @@ object RotationManager : Manager( } listenUnsafe({ Int.MIN_VALUE }) { - reset(Rotation.ZERO) + reset(Rotation.Zero) } // Override user interactions with max priority @@ -206,7 +207,7 @@ object RotationManager : Manager( fun handleBaritoneRotation(yaw: Double, pitch: Double) { runSafe { usingBaritoneRotation = true - val request = IRotationRequest.Full(BaritoneManager) { Rotation(yaw, pitch) } + val request = IRotationRequest.Full(BaritoneHandler) { Rotation(yaw, pitch) } yawRequest = request pitchRequest = request updateActiveRotation() diff --git a/src/main/kotlin/com/lambda/interaction/managers/rotating/visibilty/PointSelection.kt b/src/main/kotlin/com/lambda/interaction/managers/rotating/visibilty/PointSelection.kt deleted file mode 100644 index 69df13106..000000000 --- a/src/main/kotlin/com/lambda/interaction/managers/rotating/visibilty/PointSelection.kt +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2026 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.interaction.managers.rotating.visibilty - -import com.lambda.interaction.managers.rotating.Rotation.Companion.dist -import com.lambda.interaction.managers.rotating.RotationManager -import com.lambda.util.Describable -import com.lambda.util.NamedEnum -import com.lambda.util.math.distSq -import com.lambda.util.math.times - -enum class PointSelection( - override val displayName: String, - override val description: String, - val select: (Collection) -> VisibilityChecker.CheckedHit? -) : NamedEnum, Describable { - ByRotation( - "By Rotation", - "Choose the point that needs the least rotation from your current view (minimal camera turn).", - select = { hits -> - hits.minByOrNull { RotationManager.activeRotation dist it.rotation } - } - ), - Optimum( - "Optimum", - "Choose the point closest to the average of all candidates (balanced and stable aim).", - select = { hits -> - val optimum = hits - .mapNotNull { it.hit.pos } - .reduceOrNull { acc, pos -> acc.add(pos) } - ?.times(1 / hits.size.toDouble()) - - optimum?.let { center -> - hits.minByOrNull { it.hit.pos?.distSq(center) ?: 0.0 } - } - } - ) -} diff --git a/src/main/kotlin/com/lambda/interaction/managers/rotating/visibilty/RotationTargets.kt b/src/main/kotlin/com/lambda/interaction/managers/rotating/visibilty/RotationTargets.kt deleted file mode 100644 index ffa91a59c..000000000 --- a/src/main/kotlin/com/lambda/interaction/managers/rotating/visibilty/RotationTargets.kt +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2026 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.interaction.managers.rotating.visibilty - -import com.lambda.context.AutomatedSafeContext -import com.lambda.context.SafeContext -import com.lambda.interaction.managers.rotating.Rotation -import com.lambda.interaction.managers.rotating.RotationManager -import com.lambda.interaction.managers.rotating.visibilty.VisibilityChecker.ALL_SIDES -import com.lambda.interaction.managers.rotating.visibilty.VisibilityChecker.findRotation -import com.lambda.util.extension.rotation -import net.minecraft.entity.Entity -import net.minecraft.util.hit.BlockHitResult -import net.minecraft.util.hit.EntityHitResult -import net.minecraft.util.hit.HitResult -import net.minecraft.util.math.BlockPos -import net.minecraft.util.math.Direction -import net.minecraft.util.math.Vec3d -import kotlin.math.atan2 -import kotlin.math.hypot - -@DslMarker -annotation class RotationDsl - -@RotationDsl -fun SafeContext.lookAt(pos: Vec3d): Rotation { - val direction = pos.subtract(player.eyePos).normalize() - val yaw = Math.toDegrees(atan2(direction.z, direction.x)) - 90.0 - val pitch = -Math.toDegrees(atan2(direction.y, hypot(direction.x, direction.z))) - return Rotation(yaw, pitch) -} - -@RotationDsl -fun SafeContext.lookInDirection(direction: PlaceDirection) = - if (!direction.isInArea(player.rotation)) direction.snapToArea(RotationManager.activeRotation) - else player.rotation - -@RotationDsl -fun AutomatedSafeContext.lookAtHit(hit: HitResult) = - when (hit) { - is BlockHitResult -> lookAtBlock(hit.blockPos, setOf(hit.side)) - is EntityHitResult -> lookAtEntity(hit.entity) - else -> null - } - -@RotationDsl -fun AutomatedSafeContext.lookAtEntity(entity: Entity, sides: Set = ALL_SIDES) = - entity.findRotation(buildConfig.entityReach, player.eyePos, sides) - -@RotationDsl -fun AutomatedSafeContext.lookAtBlock(pos: BlockPos, sides: Set = ALL_SIDES) = - pos.findRotation(buildConfig.blockReach, player.eyePos, sides) \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/interaction/material/StackSelection.kt b/src/main/kotlin/com/lambda/interaction/material/StackSelection.kt index bea27eca3..ca6a0b044 100644 --- a/src/main/kotlin/com/lambda/interaction/material/StackSelection.kt +++ b/src/main/kotlin/com/lambda/interaction/material/StackSelection.kt @@ -38,11 +38,12 @@ import kotlin.reflect.KClass /** * [StackSelection] is a class that holds a predicate for matching [ItemStack]s. */ +@Suppress("unused") @StackSelectionDsl class StackSelection { - var selector: (ItemStack) -> Boolean = EVERYTHING - var comparator: Comparator = NO_COMPARE - var count: Int = DEFAULT_AMOUNT + var selector: (ItemStack) -> Boolean = Everything + var comparator: Comparator = NoCompare + var count: Int = DefaultAmount var inShulkerBox: Boolean = false var item: Item? = null @@ -83,12 +84,12 @@ class StackSelection { } fun > thenBy(selector: (ItemStack) -> R?): StackSelection = apply { - check(comparator != NO_COMPARE) { "No comparator specified" } + check(comparator != NoCompare) { "No comparator specified" } comparator = comparator.thenBy(selector) } fun > thenByDescending(selector: (ItemStack) -> R?): StackSelection = apply { - check(comparator != NO_COMPARE) { "No comparator specified" } + check(comparator != NoCompare) { "No comparator specified" } comparator = comparator.thenByDescending(selector) } @@ -129,8 +130,8 @@ class StackSelection { } } - fun any() = EVERYTHING - fun none() = NOTHING + fun any() = Everything + fun none() = Nothing /** * [isItem] returns a predicate that matches a specific [Item]. @@ -264,25 +265,25 @@ class StackSelection { itemStack?.let { append(it.name.string) } damage?.let { append(" with damage $it") } when (selector) { - EVERYTHING -> append(" everything") - NOTHING -> append(" nothing") + Everything -> append(" everything") + Nothing -> append(" nothing") else -> append(" custom predicate") } if (inShulkerBox) append(" in shulker box") - if (comparator != NO_COMPARE) append(" sorted by custom comparator") + if (comparator != NoCompare) append(" sorted by custom comparator") } companion object { @DslMarker annotation class StackSelectionDsl - const val DEFAULT_AMOUNT = 1 + const val DefaultAmount = 1 - val FULL_SHULKERS: (ItemStack) -> Boolean = { stack -> stack.shulkerBoxContents.none { it.isEmpty } } - val EMPTY_SHULKERS: (ItemStack) -> Boolean = { stack -> stack.shulkerBoxContents.all { it.isEmpty } } - val EVERYTHING: (ItemStack) -> Boolean = { true } - val NOTHING: (ItemStack) -> Boolean = { false } - val NO_COMPARE: Comparator = Comparator { _, _ -> 0 } + val FullShulkers: (ItemStack) -> Boolean = { stack -> stack.shulkerBoxContents.none { it.isEmpty } } + val EmptyShulkers: (ItemStack) -> Boolean = { stack -> stack.shulkerBoxContents.all { it.isEmpty } } + val Everything: (ItemStack) -> Boolean = { true } + val Nothing: (ItemStack) -> Boolean = { false } + val NoCompare: Comparator = Comparator { _, _ -> 0 } val efficientToolCache: MutableMap = Collections.synchronizedMap(mutableMapOf()) @@ -305,10 +306,10 @@ class StackSelection { @StackSelectionDsl fun selectStack( - count: Int = DEFAULT_AMOUNT, + count: Int = DefaultAmount, inShulkerBox: Boolean = false, - sorter: Comparator = NO_COMPARE, - block: StackSelection.() -> (ItemStack) -> Boolean = { EVERYTHING }, + sorter: Comparator = NoCompare, + block: StackSelection.() -> (ItemStack) -> Boolean = { Everything }, ) = StackSelection().apply { selector = block() comparator = sorter diff --git a/src/main/kotlin/com/lambda/interaction/material/container/ContainerManager.kt b/src/main/kotlin/com/lambda/interaction/material/container/ContainerHandler.kt similarity index 98% rename from src/main/kotlin/com/lambda/interaction/material/container/ContainerManager.kt rename to src/main/kotlin/com/lambda/interaction/material/container/ContainerHandler.kt index d5e60cc91..fe48cdb86 100644 --- a/src/main/kotlin/com/lambda/interaction/material/container/ContainerManager.kt +++ b/src/main/kotlin/com/lambda/interaction/material/container/ContainerHandler.kt @@ -29,8 +29,8 @@ import com.lambda.interaction.material.StackSelection.Companion.select import com.lambda.interaction.material.container.containers.ChestContainer import com.lambda.interaction.material.container.containers.EnderChestContainer import com.lambda.util.BlockUtils.blockEntity +import com.lambda.util.ReflectionUtils.getInstances import com.lambda.util.extension.containerStacks -import com.lambda.util.reflections.getInstances import net.minecraft.block.entity.BlockEntity import net.minecraft.block.entity.ChestBlockEntity import net.minecraft.block.entity.EnderChestBlockEntity @@ -39,7 +39,8 @@ import net.minecraft.screen.ScreenHandlerType import net.minecraft.screen.slot.Slot // ToDo: Make this a Configurable to save container caches. Should use a cached region based storage system. -object ContainerManager : Loadable { +@Suppress("unused") +object ContainerHandler : Loadable { private val containers: List get() = compileContainers + runtimeContainers diff --git a/src/main/kotlin/com/lambda/interaction/material/container/containers/ChestContainer.kt b/src/main/kotlin/com/lambda/interaction/material/container/containers/ChestContainer.kt index 18cc96534..20014a240 100644 --- a/src/main/kotlin/com/lambda/interaction/material/container/containers/ChestContainer.kt +++ b/src/main/kotlin/com/lambda/interaction/material/container/containers/ChestContainer.kt @@ -19,7 +19,7 @@ package com.lambda.interaction.material.container.containers import com.lambda.context.AutomatedSafeContext import com.lambda.context.SafeContext -import com.lambda.interaction.material.container.ContainerManager +import com.lambda.interaction.material.container.ContainerHandler import com.lambda.interaction.material.container.ExternalContainer import com.lambda.interaction.material.container.MaterialContainer import com.lambda.task.Task @@ -42,7 +42,7 @@ data class ChestContainer( context(safeContext: SafeContext) override val slots get(): List = - if (ContainerManager.lastInteractedBlockEntity is ChestBlockEntity) + if (ContainerHandler.lastInteractedBlockEntity is ChestBlockEntity) safeContext.player.currentScreenHandler.containerSlots else emptyList() diff --git a/src/main/kotlin/com/lambda/interaction/material/container/containers/EnderChestContainer.kt b/src/main/kotlin/com/lambda/interaction/material/container/containers/EnderChestContainer.kt index ea70d15d0..2ee7da2de 100644 --- a/src/main/kotlin/com/lambda/interaction/material/container/containers/EnderChestContainer.kt +++ b/src/main/kotlin/com/lambda/interaction/material/container/containers/EnderChestContainer.kt @@ -20,8 +20,8 @@ package com.lambda.interaction.material.container.containers import com.lambda.context.AutomatedSafeContext import com.lambda.context.SafeContext import com.lambda.interaction.material.StackSelection.Companion.select -import com.lambda.interaction.material.container.ContainerManager -import com.lambda.interaction.material.container.ContainerManager.findSlotsWithMaterial +import com.lambda.interaction.material.container.ContainerHandler +import com.lambda.interaction.material.container.ContainerHandler.findSlotsWithMaterial import com.lambda.interaction.material.container.ExternalContainer import com.lambda.interaction.material.container.MaterialContainer import com.lambda.task.TaskGenerator @@ -34,21 +34,18 @@ import com.lambda.util.text.literal import net.minecraft.block.entity.EnderChestBlockEntity import net.minecraft.item.ItemStack import net.minecraft.item.Items -import net.minecraft.util.math.BlockPos object EnderChestContainer : MaterialContainer(Rank.EnderChest), ExternalContainer { context(safeContext: SafeContext) override val slots get() = - if (ContainerManager.lastInteractedBlockEntity is EnderChestBlockEntity) + if (ContainerHandler.lastInteractedBlockEntity is EnderChestBlockEntity) safeContext.player.currentScreenHandler.containerSlots else emptyList() override var stacks = emptyList() override val description = buildText { literal("Ender Chest") } - private var placePos = BlockPos.ORIGIN - context(automatedSafeContext: AutomatedSafeContext) override fun accessThen(exitAfter: Boolean, taskGenerator: TaskGenerator) = Items.ENDER_CHEST @@ -56,10 +53,9 @@ object EnderChestContainer : MaterialContainer(Rank.EnderChest), ExternalContain .findSlotsWithMaterial() .firstOrNull()?.let { slot -> PlaceContainerTask(slot, automatedSafeContext).then { pos -> - placePos = pos OpenContainerTask(pos, automatedSafeContext).then { taskGenerator.invoke(automatedSafeContext, Unit).thenOrNull { - if (exitAfter) automatedSafeContext.breakAndCollectBlock(placePos, lifeMaintenance = false) + if (exitAfter) automatedSafeContext.breakAndCollectBlock(pos, lifeMaintenance = false) else null } } diff --git a/src/main/kotlin/com/lambda/interaction/material/container/containers/ShulkerBoxContainer.kt b/src/main/kotlin/com/lambda/interaction/material/container/containers/ShulkerBoxContainer.kt index 78b2717bb..37b268635 100644 --- a/src/main/kotlin/com/lambda/interaction/material/container/containers/ShulkerBoxContainer.kt +++ b/src/main/kotlin/com/lambda/interaction/material/container/containers/ShulkerBoxContainer.kt @@ -19,7 +19,7 @@ package com.lambda.interaction.material.container.containers import com.lambda.context.AutomatedSafeContext import com.lambda.context.SafeContext -import com.lambda.interaction.material.container.ContainerManager +import com.lambda.interaction.material.container.ContainerHandler import com.lambda.interaction.material.container.ExternalContainer import com.lambda.interaction.material.container.MaterialContainer import com.lambda.task.TaskGenerator @@ -44,7 +44,7 @@ data class ShulkerBoxContainer( context(safeContext: SafeContext) override val slots get(): List = - if (ContainerManager.lastInteractedBlockEntity is ShulkerBoxBlockEntity) + if (ContainerHandler.lastInteractedBlockEntity is ShulkerBoxBlockEntity) safeContext.player.currentScreenHandler.containerSlots else emptyList() diff --git a/src/main/kotlin/com/lambda/module/HudModule.kt b/src/main/kotlin/com/lambda/module/HudModule.kt index e084165f1..83443d5cf 100644 --- a/src/main/kotlin/com/lambda/module/HudModule.kt +++ b/src/main/kotlin/com/lambda/module/HudModule.kt @@ -28,7 +28,7 @@ abstract class HudModule( tag: ModuleTag, alwaysListening: Boolean = false, enabledByDefault: Boolean = false, - defaultKeybind: Bind = Bind.EMPTY, -) : Module(name, description, tag, alwaysListening, enabledByDefault, defaultKeybind), Layout { + defaultKeybind: Bind = Bind.Empty, +) : Module(name, description, tag, alwaysListening, enabledByDefault, defaultKeybind = defaultKeybind), Layout { val backgroundColor = setting("Background Color", Color(0, 0, 0, 0)) } diff --git a/src/main/kotlin/com/lambda/module/Module.kt b/src/main/kotlin/com/lambda/module/Module.kt index 8e4dfb45d..116286b24 100644 --- a/src/main/kotlin/com/lambda/module/Module.kt +++ b/src/main/kotlin/com/lambda/module/Module.kt @@ -18,12 +18,12 @@ package com.lambda.module import com.lambda.command.LambdaCommand -import com.lambda.config.Configurable -import com.lambda.config.Configuration -import com.lambda.config.IMutableAutomationConfig -import com.lambda.config.MutableAutomationConfig +import com.lambda.config.Config +import com.lambda.config.ConfigCategory import com.lambda.config.SettingCore -import com.lambda.config.configurations.ModuleConfigs +import com.lambda.config.automation.IMutableAutomationConfig +import com.lambda.config.automation.MutableAutomationConfig +import com.lambda.config.categories.ModuleCategory import com.lambda.config.settings.complex.Bind import com.lambda.config.settings.complex.KeybindSetting.Companion.onPress import com.lambda.config.settings.complex.KeybindSetting.Companion.onRelease @@ -42,13 +42,13 @@ import com.lambda.event.listener.UnsafeListener import com.lambda.module.modules.client.Client import com.lambda.module.tag.ModuleTag import com.lambda.sound.LambdaSound -import com.lambda.sound.SoundManager.play +import com.lambda.sound.SoundHandler.play import com.lambda.util.KeyCode import com.lambda.util.Nameable /** * A [Module] is a feature or tool for the utility mod. - * It represents a [Configurable] component of the mod, + * It represents a [Config] component of the mod, * with its own set of behaviors and properties. * * Each [Module] has a [name], which is displayed in-game. @@ -63,7 +63,7 @@ import com.lambda.util.Nameable * If a module does not need to be activated by a key (like [ClickGui]), * the default [keybind] should not be set (using [KeyCode.Unbound]). * - * [Module]s are [Configurable]s with [settings] (see [SettingCore] for all setting types). + * [Module]s are [Config]s with [settingLayers] (see [SettingCore] for all setting types). * Example: * ``` * private val foo by setting("Foo", true) @@ -71,7 +71,7 @@ import com.lambda.util.Nameable * ``` * * These settings are persisted in the `lambda/config/modules.json` config file. - * See [ModuleConfigs.primary] and [Configuration] for more details. + * See [ModuleCategory.primary] and [ConfigCategory] for more details. * * In the `init` block, you can add hooks like [onEnable], [onDisable], [onToggle] and add listeners. * @@ -118,21 +118,23 @@ import com.lambda.util.Nameable * * See [SafeListener] and [UnsafeListener] for more details. */ +@Suppress("unused") abstract class Module( - override val name: String, + name: String, val description: String = "", val tag: ModuleTag, private val alwaysListening: Boolean = false, enabledByDefault: Boolean = false, - defaultKeybind: Bind = Bind.EMPTY, + modulePriority: Int = 0, + defaultKeybind: Bind = Bind.Empty, autoDisable: Boolean = false -) : Nameable, Muteable, OwnerPriority, Configurable(ModuleConfigs), +) : Nameable, Muteable, OwnerPriority, Config(name, ModuleCategory), IMutableAutomationConfig by MutableAutomationConfig() { private val isEnabledSetting = setting("Enabled", enabledByDefault) { false } - val prioritySetting = setting("Module Priority", 0, -100..100, 1, "Priority over other modules") { false } + val prioritySetting = setting("Module Priority", modulePriority, -100..100, 1, "Priority over other modules") { false } .onValueChangeUnsafe { _, to -> ownerPriority = to } - override var ownerPriority = 0 + override var ownerPriority = modulePriority set(value) { val oldVal = field field = value @@ -145,6 +147,7 @@ abstract class Module( val drawSetting = setting("Draw", true, "Draws the module in the module list hud element") { false } var isEnabled by isEnabledSetting + private set val isDisabled get() = !isEnabled val keybind by keybindSetting @@ -163,59 +166,66 @@ abstract class Module( listen { if (autoDisable) disable() } } + @DslMarker + private annotation class ModuleDsl + + @ModuleDsl fun enable() { ModuleEvent.Enabled(this@Module).post() isEnabled = true } + @ModuleDsl fun disable() { ModuleEvent.Disabled(this@Module).post() isEnabled = false } + @ModuleDsl fun toggle() { ModuleEvent.Toggle(this@Module, !isEnabled).post() if (isEnabled) disable() else enable() } + @ModuleDsl fun onEnable(block: SafeContext.() -> Unit) { isEnabledSetting.onValueChange { from, to -> if (!from && to) block() } } + @ModuleDsl fun onDisable(block: SafeContext.() -> Unit) { isEnabledSetting.onValueChange { from, to -> if (from && !to) block() } } + @ModuleDsl fun onToggle(block: SafeContext.(to: Boolean) -> Unit) { isEnabledSetting.onValueChange { from, to -> if (from != to) block(to) } } + @ModuleDsl fun onEnableUnsafe(block: () -> Unit) { isEnabledSetting.onValueChangeUnsafe { from, to -> if (!from && to) block() } } + @ModuleDsl fun onDisableUnsafe(block: () -> Unit) { isEnabledSetting.onValueChangeUnsafe { from, to -> if (from && !to) block() } } + @ModuleDsl fun onToggleUnsafe(block: (to: Boolean) -> Unit) { isEnabledSetting.onValueChangeUnsafe { from, to -> if (from != to) block(to) } } - - protected fun setModulePriority(priority: Int) { - prioritySetting.value = priority - prioritySetting.core.defaultValue = priority - } } diff --git a/src/main/kotlin/com/lambda/module/ModuleRegistry.kt b/src/main/kotlin/com/lambda/module/ModuleRegistry.kt index 9c9f52dbe..a8dc8cda7 100644 --- a/src/main/kotlin/com/lambda/module/ModuleRegistry.kt +++ b/src/main/kotlin/com/lambda/module/ModuleRegistry.kt @@ -18,7 +18,7 @@ package com.lambda.module import com.lambda.core.Loadable -import com.lambda.util.reflections.getInstances +import com.lambda.util.ReflectionUtils.getInstances object ModuleRegistry : Loadable { override val priority = 1 @@ -28,6 +28,11 @@ object ModuleRegistry : Loadable { val moduleNameMap = modules.associateBy { it.name } - override fun load() = - "Loaded ${modules.size} modules with ${modules.sumOf { it.settings.size }} settings" + override fun load(): String { + var settingCount = 0 + modules.forEach { module -> + module.forEachSetting { _, _ -> settingCount++ } + } + return "Loaded ${modules.size} modules with $settingCount settings" + } } diff --git a/src/main/kotlin/com/lambda/module/hud/AccountName.kt b/src/main/kotlin/com/lambda/module/hud/AccountName.kt index 50bdb26a2..8b6e70830 100644 --- a/src/main/kotlin/com/lambda/module/hud/AccountName.kt +++ b/src/main/kotlin/com/lambda/module/hud/AccountName.kt @@ -22,10 +22,11 @@ import com.lambda.module.HudModule import com.lambda.module.tag.ModuleTag import com.lambda.threading.runSafe +@Suppress("unused") object AccountName : HudModule( name = "AccountName", description = "Displays the current accounts name", - tag = ModuleTag.HUD + tag = ModuleTag.Hud ) { override fun ImGuiBuilder.buildLayout() { runSafe { text(player.name.string) } diff --git a/src/main/kotlin/com/lambda/module/hud/Baritone.kt b/src/main/kotlin/com/lambda/module/hud/Baritone.kt index 581b6b1ad..4935b5579 100644 --- a/src/main/kotlin/com/lambda/module/hud/Baritone.kt +++ b/src/main/kotlin/com/lambda/module/hud/Baritone.kt @@ -18,23 +18,24 @@ package com.lambda.module.hud import com.lambda.gui.dsl.ImGuiBuilder -import com.lambda.interaction.BaritoneManager +import com.lambda.interaction.BaritoneHandler import com.lambda.interaction.construction.simulation.BuildGoal import com.lambda.module.HudModule import com.lambda.module.tag.ModuleTag +@Suppress("unused") object Baritone : HudModule( name = "Baritone", description = "Look inside of Baritones head", - tag = ModuleTag.HUD, + tag = ModuleTag.Hud, ) { override fun ImGuiBuilder.buildLayout() { - if (!BaritoneManager.isBaritoneLoaded) { + if (!BaritoneHandler.isBaritoneLoaded) { text("Baritone is not loaded") return } - BaritoneManager.primary?.customGoalProcess?.goal?.let { + BaritoneHandler.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/hud/Coordinates.kt b/src/main/kotlin/com/lambda/module/hud/Coordinates.kt index dcc9b7360..1daadd6b1 100644 --- a/src/main/kotlin/com/lambda/module/hud/Coordinates.kt +++ b/src/main/kotlin/com/lambda/module/hud/Coordinates.kt @@ -17,39 +17,35 @@ package com.lambda.module.hud -import com.lambda.config.applyEdits -import com.lambda.config.groups.FormatterSettings +import com.lambda.config.SettingEditor.edit +import com.lambda.config.Tab +import com.lambda.config.settings.blocks.FormatterSettings +import com.lambda.config.withEdits import com.lambda.gui.dsl.ImGuiBuilder import com.lambda.module.HudModule import com.lambda.module.tag.ModuleTag import com.lambda.threading.runSafe -import com.lambda.util.Formatting.format -import com.lambda.util.NamedEnum +import com.lambda.util.FormattingUtils.format import com.lambda.util.extension.dimensionName import com.lambda.util.extension.isNether import com.lambda.util.math.Vec2d import com.lambda.util.math.netherCoord import com.lambda.util.math.overworldCoord +@Suppress("unused") object Coordinates : HudModule( name = "Coordinates", description = "Show your coordinates", - tag = ModuleTag.HUD, + tag = ModuleTag.Hud, ) { - enum class Group(override val displayName: String) : NamedEnum { - CurrentDimension("Current Dimension"), - OtherDimension("Other Dimension"), - } - private val showDimension by setting("Show Dimension Name", true) private val showBiome by setting("Show Biome Name", true) private val showCurrentDimensionOnly by setting("Show Current Dimension Only", true) - private val formatter = FormatterSettings(c = this, baseGroup = arrayOf(Group.CurrentDimension)).apply { - applyEdits { - ::timeFormat.edit { hide() } - } - } + private const val CurrentDimensionTab = "Current Dimension" + @Tab(CurrentDimensionTab) private val formatter by configBlock(FormatterSettings(this)) + .withEdits { ::timeFormat.edit { hide() } } + // private val otherFormatter = FormatterSettings(this, Page.OtherDimension).apply { // ::timeFormat.edit { hide() } // ::group.edit { defaultValue(FormatterConfig.TupleGrouping.SquareBrackets) } diff --git a/src/main/kotlin/com/lambda/module/hud/FPS.kt b/src/main/kotlin/com/lambda/module/hud/FPS.kt index e8846fa96..075d5d735 100644 --- a/src/main/kotlin/com/lambda/module/hud/FPS.kt +++ b/src/main/kotlin/com/lambda/module/hud/FPS.kt @@ -25,10 +25,11 @@ import com.lambda.module.tag.ModuleTag import com.lambda.util.collections.LimitedDecayQueue import kotlin.time.Duration.Companion.seconds +@Suppress("unused") object FPS : HudModule( name = "FPS", description = "Displays your games frames per second", - tag = ModuleTag.HUD + tag = ModuleTag.Hud ) { val average by setting("Average", true) val updateDelay by setting("Update Delay", 50, 0..1000, 1, "Time between updating the fps value") diff --git a/src/main/kotlin/com/lambda/module/hud/ModuleList.kt b/src/main/kotlin/com/lambda/module/hud/ModuleList.kt index c676874a8..381ab2ab6 100644 --- a/src/main/kotlin/com/lambda/module/hud/ModuleList.kt +++ b/src/main/kotlin/com/lambda/module/hud/ModuleList.kt @@ -18,15 +18,16 @@ package com.lambda.module.hud import com.lambda.gui.dsl.ImGuiBuilder +import com.lambda.imgui.flag.ImGuiCol import com.lambda.module.HudModule import com.lambda.module.ModuleRegistry import com.lambda.module.tag.ModuleTag -import com.lambda.imgui.flag.ImGuiCol import java.awt.Color +@Suppress("unused") object ModuleList : HudModule( name = "ModuleList", - tag = ModuleTag.HUD, + tag = ModuleTag.Hud, ) { val onlyBound by setting("Only Bound", false, "Only displays modules with a keybind") val showKeybind by setting("Show Keybind", true, "Display keybind next to a module") @@ -41,7 +42,7 @@ object ModuleList : HudModule( enabled.forEach { val bound = it.keybind.key != 0 || it.keybind.mouse != -1 if (onlyBound && !bound) return@forEach - text(it.name); + text(it.name) if (showKeybind) { val color = if (!bound) Color.RED else Color.GREEN diff --git a/src/main/kotlin/com/lambda/module/hud/Rotation.kt b/src/main/kotlin/com/lambda/module/hud/Rotation.kt index c79ff7b0e..45d6bff61 100644 --- a/src/main/kotlin/com/lambda/module/hud/Rotation.kt +++ b/src/main/kotlin/com/lambda/module/hud/Rotation.kt @@ -17,24 +17,25 @@ package com.lambda.module.hud -import com.lambda.config.applyEdits -import com.lambda.config.groups.FormatterSettings +import com.lambda.config.SettingEditor.edit +import com.lambda.config.settings.blocks.FormatterSettings +import com.lambda.config.withEdits import com.lambda.gui.dsl.ImGuiBuilder import com.lambda.module.HudModule import com.lambda.module.tag.ModuleTag import com.lambda.threading.runSafe -import com.lambda.util.Formatting.format +import com.lambda.util.FormattingUtils.format +@Suppress("unused") object Rotation : HudModule( name = "Rotation", description = "Show your rotation", - tag = ModuleTag.HUD, + tag = ModuleTag.Hud, ) { - private val formatter = FormatterSettings(c = this,).apply { - applyEdits { + private val formatter by configBlock(FormatterSettings(this)) + .withEdits { ::timeFormat.edit { hide() } } - } override fun ImGuiBuilder.buildLayout() { runSafe { diff --git a/src/main/kotlin/com/lambda/module/hud/Speedometer.kt b/src/main/kotlin/com/lambda/module/hud/Speedometer.kt index c120a834d..9eeb8fe0d 100644 --- a/src/main/kotlin/com/lambda/module/hud/Speedometer.kt +++ b/src/main/kotlin/com/lambda/module/hud/Speedometer.kt @@ -23,14 +23,13 @@ import com.lambda.event.listener.SafeListener.Companion.listen import com.lambda.gui.dsl.ImGuiBuilder import com.lambda.module.HudModule import com.lambda.module.tag.ModuleTag -import com.lambda.threading.runSafe import com.lambda.util.SpeedUnit import net.minecraft.util.math.Vec3d object Speedometer : HudModule( name = "Speedometer", description = "Displays player speed", - tag = ModuleTag.HUD + tag = ModuleTag.Hud ) { var speedUnit by setting("Speed Unit", SpeedUnit.MetersPerSecond) var onlyHorizontal by setting("Horizontal Speed", false, description = "Only consider horizontal movement for speed calculation") @@ -68,8 +67,6 @@ object Speedometer : HudModule( } override fun ImGuiBuilder.buildLayout() { - runSafe { - text("Speed: %.2f %s".format(speed, speedUnit.unitName)) - } + text("Speed: %.2f %s".format(speed, speedUnit.unitName)) } } \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/module/hud/TPS.kt b/src/main/kotlin/com/lambda/module/hud/TPS.kt index 1f7992ab6..371cac486 100644 --- a/src/main/kotlin/com/lambda/module/hud/TPS.kt +++ b/src/main/kotlin/com/lambda/module/hud/TPS.kt @@ -18,19 +18,20 @@ package com.lambda.module.hud import com.lambda.gui.dsl.ImGuiBuilder +import com.lambda.imgui.ImVec2 import com.lambda.module.HudModule import com.lambda.module.tag.ModuleTag -import com.lambda.util.Formatting.format -import com.lambda.util.ServerTPS -import com.lambda.util.ServerTPS.recentData -import com.lambda.imgui.ImVec2 +import com.lambda.util.FormattingUtils.format +import com.lambda.util.ServerTPSUtils +import com.lambda.util.ServerTPSUtils.recentData +@Suppress("unused") object TPS : HudModule( name = "TPS", description = "Display the server's tick rate", - tag = ModuleTag.HUD, + tag = ModuleTag.Hud, ) { - private val format by setting("Tick format", ServerTPS.TickFormat.Tps) + private val format by setting("Tick format", ServerTPSUtils.TickFormat.Tps) private val showGraph by setting("Show TPS Graph", false) private val graphHeight by setting("Graph Height", 40f, 10f..200f, 1f) private val graphWidth by setting("Graph Width", 200f, 10f..500f, 1f) diff --git a/src/main/kotlin/com/lambda/module/hud/TaskFlowHUD.kt b/src/main/kotlin/com/lambda/module/hud/TaskFlowHUD.kt index a9577b1c2..35ca07d03 100644 --- a/src/main/kotlin/com/lambda/module/hud/TaskFlowHUD.kt +++ b/src/main/kotlin/com/lambda/module/hud/TaskFlowHUD.kt @@ -22,9 +22,10 @@ import com.lambda.module.HudModule import com.lambda.module.tag.ModuleTag import com.lambda.task.RootTask +@Suppress("unused") object TaskFlowHUD : HudModule( name = "TaskFlowHud", - tag = ModuleTag.HUD, + tag = ModuleTag.Hud, ) { override fun ImGuiBuilder.buildLayout() { text(RootTask.toString()) diff --git a/src/main/kotlin/com/lambda/module/hud/Watermark.kt b/src/main/kotlin/com/lambda/module/hud/Watermark.kt index 3de4c0f41..f58ca99b7 100644 --- a/src/main/kotlin/com/lambda/module/hud/Watermark.kt +++ b/src/main/kotlin/com/lambda/module/hud/Watermark.kt @@ -19,13 +19,14 @@ package com.lambda.module.hud import com.lambda.graphics.texture.TextureOwner.upload import com.lambda.gui.dsl.ImGuiBuilder +import com.lambda.imgui.ImGui import com.lambda.module.HudModule import com.lambda.module.tag.ModuleTag -import com.lambda.imgui.ImGui +@Suppress("unused") object Watermark : HudModule( name = "Watermark", - tag = ModuleTag.HUD, + tag = ModuleTag.Hud, enabledByDefault = true, ) { private val texture = upload("textures/lambda.png") diff --git a/src/main/kotlin/com/lambda/module/modules/chat/AntiSpam.kt b/src/main/kotlin/com/lambda/module/modules/chat/AntiSpam.kt index 7d78cac8c..adf12879e 100644 --- a/src/main/kotlin/com/lambda/module/modules/chat/AntiSpam.kt +++ b/src/main/kotlin/com/lambda/module/modules/chat/AntiSpam.kt @@ -17,13 +17,12 @@ package com.lambda.module.modules.chat -import com.lambda.config.Configurable -import com.lambda.config.SettingGroup -import com.lambda.config.applyEdits -import com.lambda.config.groups.ReplaceConfig +import com.lambda.config.Config +import com.lambda.config.Group +import com.lambda.config.ConfigBlock import com.lambda.event.events.ChatEvent import com.lambda.event.listener.SafeListener.Companion.listen -import com.lambda.friend.FriendManager +import com.lambda.friend.FriendHandler import com.lambda.module.Module import com.lambda.module.tag.ModuleTag import com.lambda.util.ChatUtils.addresses @@ -34,16 +33,18 @@ import com.lambda.util.ChatUtils.sexual import com.lambda.util.ChatUtils.slurs import com.lambda.util.ChatUtils.swears import com.lambda.util.ChatUtils.toAscii -import com.lambda.util.NamedEnum +import com.lambda.util.Describable import com.lambda.util.text.DirectMessage import com.lambda.util.text.MessageParser import com.lambda.util.text.MessageType import net.minecraft.text.Text +@Suppress("unused") object AntiSpam : Module( name = "AntiSpam", description = "Keeps your chat clean", - tag = ModuleTag.CHAT, + tag = ModuleTag.Chat, + modulePriority = 100 ) { private val fancyChats by setting("Replace Fancy Chat", false) @@ -55,39 +56,22 @@ object AntiSpam : Module( private val ignoreSystem by setting("Ignore System", false) private val ignoreDms by setting("Ignore DMs", false) - private val detectSlurs = ReplaceSettings("Slurs", this, Group.Slurs) - private val detectSwears = ReplaceSettings("Swears", this, Group.Swears) - private val detectSexual = ReplaceSettings("Sexual", this, Group.Sexual) - private val detectDiscord = ReplaceSettings("Discord", this, Group.Discord) - .apply { applyEdits { ::action.edit { defaultValue(ReplaceConfig.ActionStrategy.Hide) } } } - private val detectAddresses = ReplaceSettings("Addresses", this, Group.Addresses) - .apply { applyEdits { ::action.edit { defaultValue(ReplaceConfig.ActionStrategy.Hide) } } } - private val detectHexBypass = ReplaceSettings("Hex", this, Group.Hex) - .apply { applyEdits { ::action.edit { defaultValue(ReplaceConfig.ActionStrategy.Hide) } } } - private val detectColors = ReplaceSettings("Colors", this, Group.Colors) - .apply { applyEdits { ::action.edit { defaultValue(ReplaceConfig.ActionStrategy.None) } } } - - enum class Group(override val displayName: String) : NamedEnum { - General("General"), - Slurs("Slurs"), - Swears("Swears"), - Sexual("Sexual"), - Discord("Discord Invites"), - Addresses("IPs and Addresses"), - Hex("Hex Bypass"), - Colors("Color Prefixes") - } + @Group("Slurs") private val detectSlurs by configBlock(ReplaceSettings("Slurs", this)) + @Group("Swears") private val detectSwears by configBlock(ReplaceSettings("Swears", this)) + @Group("Sexual") private val detectSexual by configBlock(ReplaceSettings("Sexual", this)) + @Group("Discord") private val detectDiscord by configBlock(ReplaceSettings("Discord", this, ActionStrategy.Hide)) + @Group("Addresses") private val detectAddresses by configBlock(ReplaceSettings("Addresses", this, ActionStrategy.Hide)) + @Group("Hex") private val detectHexBypass by configBlock(ReplaceSettings("Hex", this, ActionStrategy.Hide)) + @Group("Colors") private val detectColors by configBlock(ReplaceSettings("Colors", this, ActionStrategy.None)) init { - setModulePriority(100) listen { event -> var raw = event.message.string val author = MessageParser.playerName(raw) - if ( - ignoreSystem && !MessageType.Both.matches(raw) && !DirectMessage.Both.matches(raw) || - ignoreDms && DirectMessage.Receive.matches(raw) - ) return@listen + if ((ignoreSystem && !MessageType.Both.matches(raw) && !DirectMessage.Both.matches(raw)) || + (ignoreDms && DirectMessage.Receive.matches(raw)) + ) return@listen val slurMatches = slurs.takeIf { detectSlurs.enabled }.orEmpty().flatMap { it.findAll(raw).toList().reversed() } val swearMatches = swears.takeIf { detectSwears.enabled }.orEmpty().flatMap { it.findAll(raw).toList().reversed() } @@ -100,22 +84,21 @@ object AntiSpam : Module( var cancelled = false var hasMatches = false - fun doMatch(replace: ReplaceConfig, matches: Sequence) { - if ( - cancelled || - filterSystem && !MessageType.Both.matches(raw) && !DirectMessage.Both.matches(raw) || - filterDms && DirectMessage.Receive.matches(raw) || - filterFriends && author?.let { FriendManager.isFriend(it) } == true || - filterSelf && MessageType.Self.matches(raw) - ) return + fun doMatch(replace: ReplaceSettings, matches: Sequence) { + if (cancelled || + (filterSystem && !MessageType.Both.matches(raw) && !DirectMessage.Both.matches(raw)) || + (filterDms && DirectMessage.Receive.matches(raw)) || + (filterFriends && author?.let { FriendHandler.isFriend(it) } == true) || + (filterSelf && MessageType.Self.matches(raw)) + ) return when (replace.action) { - ReplaceConfig.ActionStrategy.Hide -> matches.firstOrNull()?.let { event.cancel(); cancelled = true } // If there's one detection, nuke the whole damn thang - ReplaceConfig.ActionStrategy.Delete -> matches + ActionStrategy.Hide -> matches.firstOrNull()?.let { event.cancel(); cancelled = true } // If there's one detection, nuke the whole damn thang + ActionStrategy.Delete -> matches .forEach { raw = raw.replaceRange(it.range, ""); hasMatches = true } - ReplaceConfig.ActionStrategy.Replace -> matches + ActionStrategy.Replace -> matches .forEach { raw = raw.replaceRange(it.range, replace.replace.block(it.value)); hasMatches = true } - ReplaceConfig.ActionStrategy.None -> {} + ActionStrategy.None -> {} } } @@ -129,18 +112,32 @@ object AntiSpam : Module( if (cancelled) return@listen event.cancel() - if (hasMatches) - event.message = Text.of(if (fancyChats) raw.toAscii else raw) + if (hasMatches) event.message = Text.of(if (fancyChats) raw.toAscii else raw) } } class ReplaceSettings( - name: String, - c: Configurable, - baseGroup: NamedEnum, - override val visibility: () -> Boolean = { true }, - ) : ReplaceConfig, SettingGroup(c) { - override val action by setting("$name Action Strategy", ReplaceConfig.ActionStrategy.Replace, visibility = visibility).group(baseGroup) - override val replace by setting("$name Replace Strategy", ReplaceConfig.ReplaceStrategy.CensorAll) { visibility() && action == ReplaceConfig.ActionStrategy.Replace }.group(baseGroup) + val name: String, + override val c: Config, + actionStrategy: ActionStrategy = ActionStrategy.Replace + ) : ConfigBlock { + val action by c.setting("$name Action Strategy", actionStrategy) + val replace by c.setting("$name Replace Strategy", ReplaceStrategy.CensorAll) { action == ActionStrategy.Replace } + + val enabled: Boolean get() = action != ActionStrategy.None + } + + enum class ActionStrategy(override val description: String) : Describable { + Hide("Hides the message. Will override other strategies."), + Delete("Deletes the matching part off the message."), + Replace("Replace the matching string in the message with one of the following replace strategy."), + None("Don't do anything."), + } + + @Suppress("unused") + enum class ReplaceStrategy(val block: (String) -> String) { + CensorAll({ it.replaceRange(0.. if (i % 2 == 0) acc + char else "$acc*" } }), + KeepFirst({ if (it.length <= 1) it else it.replaceRange(1, it.length, "*".repeat(it.length - 1)) }), } } \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/module/modules/chat/ChatTimestamp.kt b/src/main/kotlin/com/lambda/module/modules/chat/ChatTimestamp.kt index 43d1803be..06220ae4d 100644 --- a/src/main/kotlin/com/lambda/module/modules/chat/ChatTimestamp.kt +++ b/src/main/kotlin/com/lambda/module/modules/chat/ChatTimestamp.kt @@ -17,14 +17,16 @@ package com.lambda.module.modules.chat -import com.lambda.config.applyEdits -import com.lambda.config.groups.FormatterConfig -import com.lambda.config.groups.FormatterSettings +import com.lambda.config.SettingEditor.editTyped +import com.lambda.config.SettingEditor.hide +import com.lambda.config.settings.blocks.FormatterConfig +import com.lambda.config.settings.blocks.FormatterSettings +import com.lambda.config.withEdits import com.lambda.event.events.ChatEvent import com.lambda.event.listener.SafeListener.Companion.listen import com.lambda.module.Module import com.lambda.module.tag.ModuleTag -import com.lambda.util.Formatting.format +import com.lambda.util.FormattingUtils.format import com.lambda.util.text.buildText import com.lambda.util.text.literal import com.lambda.util.text.styled @@ -36,17 +38,21 @@ import java.time.ZoneId import java.time.ZonedDateTime import java.time.temporal.ChronoUnit +@Suppress("unused") object ChatTimestamp : Module( name = "ChatTimestamp", description = "Displays the time a message was sent next to it", - tag = ModuleTag.CHAT, + tag = ModuleTag.Chat, ) { - var color: Formatting by setting("Color", Formatting.GRAY) + private var color: Formatting by setting("Color", Formatting.GRAY) .onValueChange { from, to -> if (to.colorIndex !in 0..15) color = from } + private val javaColor: Color get() = Color(color.colorValue!! and 16777215) - val javaColor: Color get() = Color(color.colorValue!! and 16777215) - - val formatter = FormatterSettings(c = this,).apply { applyEdits { hide(::localeEnum, ::sep, ::customSep, ::group, ::floatingPrecision); editTyped(::timeFormat) { defaultValue(FormatterConfig.Time.IsoLocalTime) } } } + val formatter by configBlock(FormatterSettings(this)) + .withEdits { + hide(::localeEnum, ::sep, ::customSep, ::floatingPrecision) + editTyped(::timeFormat) { defaultValue(FormatterConfig.Time.IsoLocalTime) } + } private val currentTime get() = ZonedDateTime.of(LocalDateTime.now(), ZoneId.systemDefault()) diff --git a/src/main/kotlin/com/lambda/module/modules/chat/CustomChat.kt b/src/main/kotlin/com/lambda/module/modules/chat/CustomChat.kt index 321e6ea45..454c8d60b 100644 --- a/src/main/kotlin/com/lambda/module/modules/chat/CustomChat.kt +++ b/src/main/kotlin/com/lambda/module/modules/chat/CustomChat.kt @@ -21,24 +21,24 @@ import com.google.common.collect.Comparators.min import com.lambda.command.CommandRegistry.prefix import com.lambda.event.events.ChatEvent import com.lambda.event.listener.SafeListener.Companion.listen -import com.lambda.interaction.BaritoneManager +import com.lambda.interaction.BaritoneHandler import com.lambda.module.Module import com.lambda.module.tag.ModuleTag import com.lambda.util.NamedEnum +@Suppress("unused") object CustomChat : Module( name = "CustomChat", description = "Adds a custom ending to your message", - tag = ModuleTag.CHAT, + tag = ModuleTag.Chat, ) { private val decoration by setting("Decoration", Decoration.Separator) private val text by setting("Text", Text.Lambda) - private val customText by setting("Custom Text", "") { text == Text.Custom } init { listen { - val isBaritone = BaritoneManager.baritoneSettings?.prefix?.value + val isBaritone = BaritoneHandler.baritoneSettings?.prefix?.value ?.let { setting -> it.message.startsWith(setting)} ?: false diff --git a/src/main/kotlin/com/lambda/module/modules/chat/FancyChat.kt b/src/main/kotlin/com/lambda/module/modules/chat/FancyChat.kt index b9ff4f25f..25dc0dda5 100644 --- a/src/main/kotlin/com/lambda/module/modules/chat/FancyChat.kt +++ b/src/main/kotlin/com/lambda/module/modules/chat/FancyChat.kt @@ -20,7 +20,7 @@ package com.lambda.module.modules.chat import com.lambda.command.CommandRegistry.prefix import com.lambda.event.events.ChatEvent import com.lambda.event.listener.SafeListener.Companion.listen -import com.lambda.interaction.BaritoneManager +import com.lambda.interaction.BaritoneHandler import com.lambda.module.Module import com.lambda.module.tag.ModuleTag import com.lambda.util.ChatUtils.toBlue @@ -28,19 +28,20 @@ import com.lambda.util.ChatUtils.toGreen import com.lambda.util.ChatUtils.toLeet import com.lambda.util.ChatUtils.toUwu +@Suppress("unused") object FancyChat : Module( name = "FancyChat", description = "Makes messages you send - fancy", - tag = ModuleTag.CHAT, + tag = ModuleTag.Chat, ) { - private val uwu by setting("uwu", true) + private val uwu by setting("uwu", false) private val leet by setting("1337", false) - private val green by setting(">", false) + private val green by setting(">", true) private val blue by setting("`", false) init { listen { - val isBaritone = BaritoneManager.baritoneSettings?.prefix?.value + val isBaritone = BaritoneHandler.baritoneSettings?.prefix?.value ?.let { setting -> it.message.startsWith(setting)} ?: false diff --git a/src/main/kotlin/com/lambda/module/modules/chat/FriendHighlight.kt b/src/main/kotlin/com/lambda/module/modules/chat/FriendHighlight.kt index 6f624da47..748a84c1f 100644 --- a/src/main/kotlin/com/lambda/module/modules/chat/FriendHighlight.kt +++ b/src/main/kotlin/com/lambda/module/modules/chat/FriendHighlight.kt @@ -19,11 +19,11 @@ package com.lambda.module.modules.chat import com.lambda.event.events.ChatEvent import com.lambda.event.listener.SafeListener.Companion.listen -import com.lambda.friend.FriendManager +import com.lambda.friend.FriendHandler import com.lambda.module.Module import com.lambda.module.tag.ModuleTag -import com.lambda.sound.SoundManager.playSound -import com.lambda.util.Communication.logError +import com.lambda.sound.SoundHandler.playSound +import com.lambda.util.CommunicationUtils.logError import com.lambda.util.text.MessageType import com.lambda.util.text.buildText import com.lambda.util.text.literal @@ -32,26 +32,26 @@ import net.minecraft.sound.SoundEvents import net.minecraft.util.Formatting import java.awt.Color +@Suppress("unused") object FriendHighlight : Module( name = "FriendHighlight", description = "Highlights your friends names in chat", - tag = ModuleTag.CHAT, + tag = ModuleTag.Chat, ) { - var color: Formatting by setting("Color", Formatting.GREEN) + private var color: Formatting by setting("Color", Formatting.GREEN) .onValueChange { from, to -> if (to.colorIndex !in 0..15) color = from } + private val javaColor: Color get() = Color(color.colorValue!! and 16777215) - val javaColor: Color get() = Color(color.colorValue!! and 16777215) + private val bold by setting("Bold", true) + private val italic by setting("Italic", false) + private val underlined by setting("Underlined", false) + private val strikethrough by setting("Strikethrough", false) - val bold by setting("Bold", true) - val italic by setting("Italic", false) - val underlined by setting("Underlined", false) - val strikethrough by setting("Strikethrough", false) - - val ping by setting("Ping On Message", true) + private val ping by setting("Ping On Message", true) init { onEnable { - if (FriendManager.friends.isEmpty()) + if (FriendHandler.friends.isEmpty()) logError("You don't have any friends added, silly! Go add some friends before using the module") } @@ -60,7 +60,7 @@ object FriendHighlight : Module( val author = MessageType.Others.playerName(raw) ?: return@listen val content = MessageType.Others.removedOrNull(raw) ?: return@listen - if (!FriendManager.isFriend(author)) return@listen + if (!FriendHandler.isFriend(author)) return@listen if (ping) playSound(SoundEvents.ENTITY_EXPERIENCE_ORB_PICKUP) diff --git a/src/main/kotlin/com/lambda/module/modules/client/AutoUpdater.kt b/src/main/kotlin/com/lambda/module/modules/client/AutoUpdater.kt index e31076fc3..ed465c5ab 100644 --- a/src/main/kotlin/com/lambda/module/modules/client/AutoUpdater.kt +++ b/src/main/kotlin/com/lambda/module/modules/client/AutoUpdater.kt @@ -23,14 +23,14 @@ import com.lambda.event.listener.SafeListener.Companion.listen import com.lambda.gui.LambdaScreen import com.lambda.gui.dsl.ImGuiBuilder import com.lambda.gui.dsl.ImGuiBuilder.popupModal +import com.lambda.imgui.ImGui +import com.lambda.imgui.flag.ImGuiWindowFlags import com.lambda.module.Module import com.lambda.module.tag.ModuleTag import com.lambda.threading.runIO -import com.lambda.util.Communication.debug -import com.lambda.util.Communication.logError -import com.lambda.util.Communication.warn -import com.lambda.imgui.ImGui -import com.lambda.imgui.flag.ImGuiWindowFlags +import com.lambda.util.CommunicationUtils.debug +import com.lambda.util.CommunicationUtils.logError +import com.lambda.util.CommunicationUtils.warn import net.fabricmc.loader.api.FabricLoader import net.minecraft.SharedConstants import java.net.URI @@ -40,11 +40,12 @@ import javax.xml.parsers.DocumentBuilderFactory object AutoUpdater : Module( name = "AutoUpdater", description = "Installs / uninstalls Lambda loader", - tag = ModuleTag.CLIENT, + tag = ModuleTag.Client, ) { private val debug by setting("Debug", false, "Enable debug logging") private val loaderBranch by setting("Loader Branch", Branch.Stable, "Select loader update branch") private val clientBranch by setting("Client Branch", Branch.Snapshot, "Select client update branch") + //ToDo: Saving arbitrary data to configs without weird setting display workarounds private var loaderPromptHandled by setting("Loader Prompt Handled", false) { false } @JvmStatic var showFirstLaunchModal = false @@ -52,18 +53,18 @@ object AutoUpdater : Module( @JvmStatic var showUninstallModal = false private var firstLaunchStateInitialized = false - private const val MAVEN_URL = "https://maven.lambda-client.org" - private const val LOADER_RELEASES_META = "$MAVEN_URL/releases/com/lambda/lambda-loader/maven-metadata.xml" - private const val LOADER_SNAPSHOTS_META = "$MAVEN_URL/snapshots/com/lambda/lambda-loader/maven-metadata.xml" - private const val CLIENT_RELEASES_META = "$MAVEN_URL/releases/com/lambda/lambda/maven-metadata.xml" - private const val CLIENT_SNAPSHOTS_META = "$MAVEN_URL/snapshots/com/lambda/lambda/maven-metadata.xml" + private const val MavenUrl = "https://maven.lambda-client.org" + private const val LoaderReleasesMeta = "$MavenUrl/releases/com/lambda/lambda-loader/maven-metadata.xml" + private const val LoaderSnapshotsMeta = "$MavenUrl/snapshots/com/lambda/lambda-loader/maven-metadata.xml" + private const val ClientReleasesMeta = "$MavenUrl/releases/com/lambda/lambda/maven-metadata.xml" + private const val ClientSnapshotsMeta = "$MavenUrl/snapshots/com/lambda/lambda/maven-metadata.xml" private enum class Branch { Stable, Snapshot } - const val WINDOW_FLAGS = + const val WindowFlags = ImGuiWindowFlags.AlwaysAutoResize or ImGuiWindowFlags.NoMove or ImGuiWindowFlags.NoResize or @@ -90,7 +91,7 @@ object AutoUpdater : Module( if (mc.currentScreen !is LambdaScreen) return@listen ImGui.openPopup("Loader Installation Wizard") - popupModal("Loader Installation Wizard", WINDOW_FLAGS) { + popupModal("Loader Installation Wizard", WindowFlags) { renderLoaderInstallExplanation() val buttonWidth = (ImGui.getContentRegionAvailX() - ImGui.getStyle().itemSpacing.x) / 2f @@ -115,7 +116,7 @@ object AutoUpdater : Module( if (showInstallModal) { ImGui.openPopup("Loader Installation Wizard") - popupModal("Loader Installation Wizard", WINDOW_FLAGS) { + popupModal("Loader Installation Wizard", WindowFlags) { renderLoaderInstallExplanation() val buttonWidth = (ImGui.getContentRegionAvailX() - ImGui.getStyle().itemSpacing.x) / 2f @@ -138,7 +139,7 @@ object AutoUpdater : Module( if (showUninstallModal) { ImGui.openPopup("Uninstall Loader") - popupModal("Uninstall Loader", WINDOW_FLAGS) { + popupModal("Uninstall Loader", WindowFlags) { text("Do you want to uninstall Lambda Loader?") separator() text("This will close the client automatically once the uninstall is finished.") @@ -228,22 +229,22 @@ object AutoUpdater : Module( when (branch) { Branch.Stable -> { - val xml = URI(LOADER_RELEASES_META).toURL().readText() + val xml = URI(LoaderReleasesMeta).toURL().readText() version = parseLatestVersion(xml, null) - baseUrl = "$MAVEN_URL/releases" + baseUrl = "$MavenUrl/releases" } Branch.Snapshot -> { - val xml = URI(LOADER_SNAPSHOTS_META).toURL().readText() + val xml = URI(LoaderSnapshotsMeta).toURL().readText() version = parseLatestVersion(xml, null) - baseUrl = "$MAVEN_URL/snapshots" + baseUrl = "$MavenUrl/snapshots" } } if (version == null && branch == Branch.Stable) { warn("No stable loader found, falling back to snapshot") - val xml = URI(LOADER_SNAPSHOTS_META).toURL().readText() + val xml = URI(LoaderSnapshotsMeta).toURL().readText() version = parseLatestVersion(xml, null) - baseUrl = "$MAVEN_URL/snapshots" + baseUrl = "$MavenUrl/snapshots" } if (version == null) { @@ -280,22 +281,22 @@ object AutoUpdater : Module( when (branch) { Branch.Stable -> { - val xml = URI(CLIENT_RELEASES_META).toURL().readText() + val xml = URI(ClientReleasesMeta).toURL().readText() version = parseLatestVersion(xml, mcVersion) - baseUrl = "$MAVEN_URL/releases" + baseUrl = "$MavenUrl/releases" } Branch.Snapshot -> { - val xml = URI(CLIENT_SNAPSHOTS_META).toURL().readText() + val xml = URI(ClientSnapshotsMeta).toURL().readText() version = parseLatestVersion(xml, mcVersion) - baseUrl = "$MAVEN_URL/snapshots" + baseUrl = "$MavenUrl/snapshots" } } if (version == null && branch == Branch.Stable) { warn("No stable client found for MC $mcVersion, falling back to snapshot") - val xml = URI(CLIENT_SNAPSHOTS_META).toURL().readText() + val xml = URI(ClientSnapshotsMeta).toURL().readText() version = parseLatestVersion(xml, mcVersion) - baseUrl = "$MAVEN_URL/snapshots" + baseUrl = "$MavenUrl/snapshots" } if (version == null) { diff --git a/src/main/kotlin/com/lambda/module/modules/client/Capes.kt b/src/main/kotlin/com/lambda/module/modules/client/Capes.kt index e1e42039f..7cc11902f 100644 --- a/src/main/kotlin/com/lambda/module/modules/client/Capes.kt +++ b/src/main/kotlin/com/lambda/module/modules/client/Capes.kt @@ -23,6 +23,6 @@ import com.lambda.module.tag.ModuleTag object Capes : Module( name = "Capes", description = "Display custom capes", - tag = ModuleTag.CLIENT, + tag = ModuleTag.Client, enabledByDefault = true, ) diff --git a/src/main/kotlin/com/lambda/module/modules/client/Client.kt b/src/main/kotlin/com/lambda/module/modules/client/Client.kt index 9c99d71b0..c8adb6102 100644 --- a/src/main/kotlin/com/lambda/module/modules/client/Client.kt +++ b/src/main/kotlin/com/lambda/module/modules/client/Client.kt @@ -17,31 +17,37 @@ package com.lambda.module.modules.client +import com.lambda.config.Group +import com.lambda.config.Tab import com.lambda.graphics.mc.renderer.TickedRenderer.Companion.tickedRenderer import com.lambda.interaction.construction.simulation.result.Drawable import com.lambda.module.Module import com.lambda.module.tag.ModuleTag -import com.lambda.util.NamedEnum +import java.awt.Color object Client : Module( name = "Client", description = "Global settings for Lambda", - tag = ModuleTag.CLIENT, + tag = ModuleTag.Client, enabledByDefault = true ) { - private enum class Group(override val displayName: String) : NamedEnum { - General("General"), - Debug("Debug") - } + private const val GeneralTab = "General" + private const val DebugTab = "Debug" + + private const val RenderingGroup = "Rendering" + + @Tab(GeneralTab) val clientSounds by setting("Client Sounds", true, "Plays sounds when certain actions are performed with lambda. Toggling modules, for example") + @Tab(GeneralTab) val buildTaskRenders by setting("Build Task Renders", false, "Displays renders from some build sim results generated from the build task") + @Tab(GeneralTab) val avoidInventoryDesync by setting("Avoid Inventory Desync", true, "Cancels incoming inventory update packets if they match previous actions") + @Tab(GeneralTab) val desyncTimeout by setting("Desync Timeout", 30, 1..30, 1, unit = " ticks", description = "Time to store previous inventory actions before dropping the cache") { avoidInventoryDesync } + @Tab(GeneralTab) val scanShrinkFactor by setting("Scan Shrink Factor", 0.001, 0.0..1.0, 0.001, "How much to shrink block scans from the edges to avoid flagging anticheats") + @Tab(GeneralTab) @Group(RenderingGroup) val chunkUploadsPerTick by setting("Chunk Uploads", 16, 1..256, 1, unit = " chunks/tick") + @Tab(GeneralTab) @Group(RenderingGroup) val chunkRebuildsPerTick by setting("Chunk Rebuilds", 64, 1..256, 1, unit = " chunks/tick") + @Tab(GeneralTab) val highlightColor by setting("Text Highlight Color", Color(214, 55, 87), "Base text highlight color") - val clientSounds by setting("Client Sounds", true, "Plays sounds when certain actions are performed with lambda. Toggling modules, for example").group(Group.General) - val buildTaskRenders by setting("Build Task Renders", false, "Displays renders from some build sim results generated from the build task").group(Group.General) - val avoidInventoryDesync by setting("Avoid Inventory Desync", true, "Cancels incoming inventory update packets if they match previous actions").group(Group.General) - val desyncTimeout by setting("Desync Timeout", 30, 1..30, 1, unit = " ticks", description = "Time to store previous inventory actions before dropping the cache") { avoidInventoryDesync }.group(Group.General) - val scanShrinkFactor by setting("Scan Shrink Factor", 0.001, 0.0..1.0, 0.001).group(Group.General) - val showAllEntries by setting("Show All Entries", false, "Show all entries in the task tree").group(Group.Debug) - val ignoreItemDropWarnings by setting("Ignore Drop Warnings", false, "Hides the item drop warnings from the break manager").group(Group.Debug) - val verboseDebug by setting("Verbose Debug", false, "Prints more, and more detailed, debug logs").group(Group.Debug) + @Tab(DebugTab) val showAllEntries by setting("Show All Entries", false, "Show all entries in the task tree") + @Tab(DebugTab) val ignoreItemDropWarnings by setting("Ignore Drop Warnings", false, "Hides the item drop warnings from the break manager") + @Tab(DebugTab) val verboseDebug by setting("Verbose Debug", false, "Prints more, and more detailed, debug logs") @Volatile var drawables = listOf() diff --git a/src/main/kotlin/com/lambda/module/modules/client/Discord.kt b/src/main/kotlin/com/lambda/module/modules/client/Discord.kt index 87d33fc51..fb74da1e4 100644 --- a/src/main/kotlin/com/lambda/module/modules/client/Discord.kt +++ b/src/main/kotlin/com/lambda/module/modules/client/Discord.kt @@ -18,17 +18,17 @@ package com.lambda.module.modules.client import com.lambda.Lambda -import com.lambda.Lambda.LOG +import com.lambda.Lambda.Log import com.lambda.context.SafeContext import com.lambda.event.EventFlow import com.lambda.event.events.TickEvent import com.lambda.event.listener.SafeListener.Companion.listenOnce import com.lambda.module.Module import com.lambda.module.tag.ModuleTag -import com.lambda.network.NetworkManager.updateToken +import com.lambda.network.NetworkHandler.updateToken import com.lambda.network.api.v1.endpoints.linkDiscord import com.lambda.threading.runConcurrent -import com.lambda.util.Communication.warn +import com.lambda.util.CommunicationUtils.warn import com.lambda.util.Nameable import com.lambda.util.extension.dimensionName import com.lambda.util.extension.fullHealth @@ -41,10 +41,11 @@ import dev.cbyrne.kdiscordipc.data.activity.timestamps import kotlinx.coroutines.delay import java.util.concurrent.atomic.AtomicBoolean +@Suppress("unused") object Discord : Module( name = "Discord", description = "Discord Rich Presence configuration", - tag = ModuleTag.CLIENT, + tag = ModuleTag.Client, enabledByDefault = true, ) { private val delay by setting("Update Delay", 5000L, 5000L..30000L, 100L, unit = "ms") @@ -55,7 +56,7 @@ object Discord : Module( private val line2Right by setting("Line 2 Right", LineInfo.Fps) val rpc by lazy { - KDiscordIPC(Lambda.APP_ID, scope = EventFlow.lambdaScope) + KDiscordIPC(Lambda.AppId, scope = EventFlow.lambdaScope) } var connecting = AtomicBoolean(false) @@ -94,7 +95,7 @@ object Discord : Module( discordAuth = auth } .onFailure { - LOG.error(it) + Log.error(it) warn("Failed to link your discord account") } return true @@ -117,7 +118,7 @@ object Discord : Module( details = "${line1Left.value(this@update)} | ${line1Right.value(this@update)}".take(128) state = "${line2Left.value(this@update)} | ${line2Right.value(this@update)}".take(128) - largeImage("lambda", Lambda.VERSION) + largeImage("lambda", Lambda.Version) smallImage("https://mc-heads.net/avatar/${mc.gameProfile.id}/nohelm", mc.gameProfile.name) //button("Download", "https://github.com/lambda-client/lambda") @@ -126,7 +127,7 @@ object Discord : Module( } private enum class LineInfo(val value: SafeContext.() -> String) : Nameable { - Version({ Lambda.VERSION }), + Version({ Lambda.Version }), World({ worldName }), Username({ mc.session.username }), Health({ "${player.fullHealth} HP" }), diff --git a/src/main/kotlin/com/lambda/module/modules/client/ModuleNotifier.kt b/src/main/kotlin/com/lambda/module/modules/client/ModuleNotifier.kt index 46f635b64..7b5b7ad1c 100644 --- a/src/main/kotlin/com/lambda/module/modules/client/ModuleNotifier.kt +++ b/src/main/kotlin/com/lambda/module/modules/client/ModuleNotifier.kt @@ -21,7 +21,7 @@ import com.lambda.event.events.ModuleEvent import com.lambda.event.listener.SafeListener.Companion.listen import com.lambda.module.Module import com.lambda.module.tag.ModuleTag -import com.lambda.util.Communication.log +import com.lambda.util.CommunicationUtils.log import com.lambda.util.Describable import com.lambda.util.NamedEnum import com.lambda.util.text.TextBuilder @@ -31,10 +31,11 @@ import com.lambda.util.text.literal import net.minecraft.util.Colors import java.awt.Color +@Suppress("unused") object ModuleNotifier : Module( name = "ModuleNotifier", description = "Notifies you when a module is enabled or disabled", - tag = ModuleTag.CLIENT, + tag = ModuleTag.Client, enabledByDefault = true ) { var notifyTarget by setting("Notify Target", setOf(NotifyTarget.ActionBar), NotifyTarget.entries.toSet(), description = "Where to send notifications when modules are toggled") diff --git a/src/main/kotlin/com/lambda/module/modules/client/StyleEditor.kt b/src/main/kotlin/com/lambda/module/modules/client/StyleEditor.kt deleted file mode 100644 index b4d60b800..000000000 --- a/src/main/kotlin/com/lambda/module/modules/client/StyleEditor.kt +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2026 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.module.modules.client - -import com.lambda.module.Module -import com.lambda.module.tag.ModuleTag -import com.lambda.util.NamedEnum -import java.awt.Color - -object StyleEditor : Module( - name = "StyleEditor", - description = "Modify the style of the GUI", - tag = ModuleTag.CLIENT, -) { - val alpha by setting("Alpha", 1.0, 0.2..1.0, 0.005, "Global alpha applies to everything in Dear ImGui") - val disabledAlpha by setting("Disabled Alpha", 0.6, 0.0..1.0, 0.005, "Additional alpha multiplier applied by BeginDisabled(). Multiply over current value of Alpha") - //val windowPaddingH by setting("Horizontal Window Padding", 8, 0) - val itemSpacing by setting("Item Spacing", 21.0, 0.0..30.0, 1.0, "Horizontal spacing when e.g. entering a tree node") // Generally == (FontSize + FramePadding.x*2) - val scrollbarSize by setting("Scrollbar Size", 14.0, 1.0..20.0, 1.0) - - // General - val useMemoryMapping by setting("Use Memory Mapping", true).group(Group.General) - - // Font - val shadow by setting("Shadow", true).group(Group.Font) - val shadowBrightness by setting("Shadow Brightness", 0.35, 0.0..0.5, 0.01) { shadow }.group(Group.Font) - val shadowShift by setting("Shadow Shift", 1.0, 0.0..2.0, 0.05) { shadow }.group(Group.Font) - val gap by setting("Gap", 1.5, -10.0..10.0, 0.5).group(Group.Font) - val baselineOffset by setting("Vertical Offset", 0.0, -10.0..10.0, 0.5).group(Group.Font) - val highlightColor by setting("Text Highlight Color", Color(214, 55, 87)).group(Group.Font) - val sdfMin by setting("SDF Min", 0.4, 0.0..1.0, 0.01).group(Group.Font) - val sdfMax by setting("SDF Max", 1.0, 0.0..1.0, 0.01).group(Group.Font) - - // ESP - val uploadsPerTick by setting("Uploads", 16, 1..256, 1, unit = " chunks/tick").group(Group.ESP) - val rebuildsPerTick by setting("Rebuilds", 64, 1..256, 1, unit = " chunks/tick").group(Group.ESP) - val updateFrequency by setting("Update Frequency", 2, 1..10, 1, "Frequency of block updates", unit = " ticks").group(Group.ESP) - val outlineWidth by setting("Outline Width", 1.0, 0.1..5.0, 0.1, "Width of block outlines", unit = "px").group(Group.ESP) - - private enum class Group(override val displayName: String): NamedEnum { - General("General"), - Font("Font"), - ESP("ESP"), - } -} diff --git a/src/main/kotlin/com/lambda/module/modules/combat/AutoArmor.kt b/src/main/kotlin/com/lambda/module/modules/combat/AutoArmor.kt index c80126edf..ec45fc94e 100644 --- a/src/main/kotlin/com/lambda/module/modules/combat/AutoArmor.kt +++ b/src/main/kotlin/com/lambda/module/modules/combat/AutoArmor.kt @@ -17,10 +17,11 @@ package com.lambda.module.modules.combat -import com.lambda.config.AutomationConfig.Companion.setDefaultAutomationConfig -import com.lambda.config.applyEdits +import com.lambda.config.SettingEditor.hideAllBlocksExcept +import com.lambda.config.automation.AutomationConfig.Companion.setDefaultAutomationConfig import com.lambda.config.settings.complex.Bind import com.lambda.config.settings.complex.KeybindSetting.Companion.onPress +import com.lambda.config.withEdits import com.lambda.context.SafeContext import com.lambda.event.events.TickEvent import com.lambda.event.listener.SafeListener.Companion.listen @@ -40,13 +41,14 @@ import net.minecraft.registry.RegistryKey import net.minecraft.registry.tag.ItemTags import net.minecraft.screen.slot.Slot +@Suppress("unused") object AutoArmor : Module( name = "AutoArmor", description = "Automatically equips armor", - tag = ModuleTag.Companion.COMBAT + tag = ModuleTag.Combat ) { private var elytraPriority by setting("Elytra Priority", true, "Prioritizes elytra's over other armor pieces in the chest slot") - private val toggleElytraPriority by setting("Toggle Elytra Priority", Bind.Companion.EMPTY) + private val toggleElytraPriority by setting("Toggle Elytra Priority", Bind.Empty) .onPress { elytraPriority = !elytraPriority } private val minDurabilityPercentage by setting("Min Durability", 5, 0..100, 1, "Minimum durability percentage before being swapped for a new piece", "%") private val headProtection by setting("Preferred Head Protection", Protection.Protection) @@ -94,11 +96,10 @@ object AutoArmor : Module( } init { - setDefaultAutomationConfig { - applyEdits { - hideAllGroupsExcept(inventoryConfig) + setDefaultAutomationConfig() + .withEdits { + hideAllBlocksExcept(::inventoryConfig) } - } listen { val armorSlots = player.armorSlots diff --git a/src/main/kotlin/com/lambda/module/modules/combat/AutoDisconnect.kt b/src/main/kotlin/com/lambda/module/modules/combat/AutoDisconnect.kt index ef5ab52c1..34ebc152f 100644 --- a/src/main/kotlin/com/lambda/module/modules/combat/AutoDisconnect.kt +++ b/src/main/kotlin/com/lambda/module/modules/combat/AutoDisconnect.kt @@ -21,13 +21,13 @@ import com.lambda.context.SafeContext import com.lambda.event.events.PlayerEvent import com.lambda.event.events.TickEvent import com.lambda.event.listener.SafeListener.Companion.listen -import com.lambda.friend.FriendManager +import com.lambda.friend.FriendHandler import com.lambda.module.Module import com.lambda.module.tag.ModuleTag -import com.lambda.sound.SoundManager.playSound -import com.lambda.util.Communication -import com.lambda.util.Communication.prefix -import com.lambda.util.Formatting.format +import com.lambda.sound.SoundHandler.playSound +import com.lambda.util.CommunicationUtils +import com.lambda.util.CommunicationUtils.prefix +import com.lambda.util.FormattingUtils.format import com.lambda.util.combat.CombatUtils.hasDeadlyCrystal import com.lambda.util.combat.DamageUtils.isFallDeadly import com.lambda.util.extension.fullHealth @@ -50,10 +50,12 @@ import net.minecraft.text.Text import net.minecraft.world.GameMode import java.awt.Color +@Suppress("unused") object AutoDisconnect : Module( name = "AutoDisconnect", description = "Automatically disconnects when in danger or on low health", - tag = ModuleTag.COMBAT, + tag = ModuleTag.Combat, + modulePriority = -100 ) { private val health by setting("Health", true, "Disconnect from the server when health is below the set limit.") private val minimumHealth by setting("Min Health", 10, 1..36, 1, "Set the minimum health threshold for disconnection.", unit = " half-hearts") { health } @@ -86,7 +88,6 @@ object AutoDisconnect : Module( private val trident by setting("Trident", false, "Disconnect from the server when you get trident damage.") { onDamage } init { - setModulePriority(-100) listen { Reason.entries.filter { it.check() @@ -160,13 +161,13 @@ object AutoDisconnect : Module( } private fun SafeContext.generateInfo(text: Text) = buildText { - text(prefix(Communication.LogLevel.Warn.logoColor)) + text(prefix(CommunicationUtils.LogLevel.Warn.logoColor)) text(text) literal("\n\n") literal("Disconnected at ") highlighted(player.pos.format()) literal(" on ") - highlighted(Communication.currentTime()) + highlighted(CommunicationUtils.currentTime()) literal(" with ") highlighted(player.fullHealth.format()) literal(" health.") @@ -245,7 +246,7 @@ object AutoDisconnect : Module( fastEntitySearch(minPlayerDistance.toDouble()).find { otherPlayer -> otherPlayer != player && player.distanceTo(otherPlayer) <= minPlayerDistance - && (!friends || !FriendManager.isFriend(otherPlayer.uuid)) + && (!friends || !FriendHandler.isFriend(otherPlayer.uuid)) }?.let { otherPlayer -> buildText { literal("The player ") diff --git a/src/main/kotlin/com/lambda/module/modules/combat/AutoTotem.kt b/src/main/kotlin/com/lambda/module/modules/combat/AutoTotem.kt index 5b4de1bce..3b23ff02f 100644 --- a/src/main/kotlin/com/lambda/module/modules/combat/AutoTotem.kt +++ b/src/main/kotlin/com/lambda/module/modules/combat/AutoTotem.kt @@ -17,17 +17,17 @@ package com.lambda.module.modules.combat -import com.lambda.config.AutomationConfig.Companion.setDefaultAutomationConfig -import com.lambda.config.applyEdits +import com.lambda.config.SettingEditor.hideAllBlocksExcept +import com.lambda.config.automation.AutomationConfig.Companion.setDefaultAutomationConfig +import com.lambda.config.withEdits import com.lambda.context.SafeContext import com.lambda.event.events.TickEvent import com.lambda.event.listener.SafeListener.Companion.listen -import com.lambda.friend.FriendManager +import com.lambda.friend.FriendHandler import com.lambda.interaction.managers.inventory.InventoryRequest.Companion.inventoryRequest import com.lambda.interaction.material.StackSelection.Companion.select import com.lambda.module.Module import com.lambda.module.tag.ModuleTag -import com.lambda.util.NamedEnum import com.lambda.util.combat.CombatUtils.hasDeadlyCrystal import com.lambda.util.combat.DamageUtils.isFallDeadly import com.lambda.util.extension.fullHealth @@ -37,29 +37,29 @@ import net.minecraft.entity.mob.CreeperEntity import net.minecraft.entity.player.PlayerEntity import net.minecraft.item.Items +@Suppress("unused") object AutoTotem : Module( name = "AutoTotem", description = "Swaps the your off-hand item to a totem", - tag = ModuleTag.COMBAT, + tag = ModuleTag.Combat, + modulePriority = 100 ) { - private val always by setting("Always", true, "Always attempt to keep a totem in offhand").group(Group.General) - private val ignoreWhenHolding by setting("Ignore When Holding", false, "Ignore swapping to offhand when already holding a totem").group(Group.General) - private val minimumHealth by setting("Min Health", 10, 6..36, 1, "Set the minimum health threshold to swap", unit = " half-hearts") { !always }.group(Group.General) - private val falls by setting("Falls", true, "Swap if the player will die of fall damage") { !always }.group(Group.General) - private val fallDistance by setting("Falls Time", 10, 0..30, 1, "Number of blocks fallen before swapping", unit = " blocks") { !always && falls }.group(Group.General) - private val crystals by setting("Crystals", true, "Swap if an End Crystal explosion would be lethal") { !always }.group(Group.General) - private val creeper by setting("Creepers", true, "Swap when an ignited Creeper is nearby") { !always }.group(Group.General) - private val players by setting("Players", false, "Swap if a nearby player is detected within the set distance") { !always }.group(Group.General) - private val minPlayerDistance by setting("Player Distance", 64, 32..128, 4, "Set the distance to detect players to swap") { !always && players }.group(Group.General) - private val friends by setting("Friends", false, "Exclude friends from triggering player-based swaps") { !always && players }.group(Group.General) + private val always by setting("Always", true, "Always attempt to keep a totem in offhand") + private val ignoreWhenHolding by setting("Ignore When Holding", false, "Ignore swapping to offhand when already holding a totem") + private val minimumHealth by setting("Min Health", 10, 6..36, 1, "Set the minimum health threshold to swap", unit = " half-hearts") { !always } + private val falls by setting("Falls", true, "Swap if the player will die of fall damage") { !always } + private val fallDistance by setting("Falls Time", 10, 0..30, 1, "Number of blocks fallen before swapping", unit = " blocks") { !always && falls } + private val crystals by setting("Crystals", true, "Swap if an End Crystal explosion would be lethal") { !always } + private val creeper by setting("Creepers", true, "Swap when an ignited Creeper is nearby") { !always } + private val players by setting("Players", false, "Swap if a nearby player is detected within the set distance") { !always } + private val minPlayerDistance by setting("Player Distance", 64, 32..128, 4, "Set the distance to detect players to swap") { !always && players } + private val friends by setting("Friends", false, "Exclude friends from triggering player-based swaps") { !always && players } init { - setModulePriority(100) - setDefaultAutomationConfig { - applyEdits { - hideAllGroupsExcept(inventoryConfig) + setDefaultAutomationConfig() + .withEdits { + hideAllBlocksExcept(::inventoryConfig) } - } listen { if (!always && Reason.entries.none { it.check(this) }) return@listen @@ -91,14 +91,9 @@ object AutoTotem : Module( Player({ players && fastEntitySearch(minPlayerDistance.toDouble()).any { otherPlayer -> otherPlayer != player && player.distanceTo(otherPlayer) <= minPlayerDistance - && (!friends || !FriendManager.isFriend(otherPlayer.uuid)) + && (!friends || !FriendHandler.isFriend(otherPlayer.uuid)) } }), EndCrystal({ crystals && hasDeadlyCrystal() }), FallDamage({ falls && isFallDeadly() && player.fallDistance > fallDistance }) } - - enum class Group(override val displayName: String): NamedEnum { - General("General"), - Inventory("Inventory"), - } } diff --git a/src/main/kotlin/com/lambda/module/modules/combat/Criticals.kt b/src/main/kotlin/com/lambda/module/modules/combat/Criticals.kt index ad0c69fcc..ef42742c2 100644 --- a/src/main/kotlin/com/lambda/module/modules/combat/Criticals.kt +++ b/src/main/kotlin/com/lambda/module/modules/combat/Criticals.kt @@ -24,6 +24,7 @@ import com.lambda.interaction.managers.rotating.Rotation import com.lambda.interaction.managers.rotating.Rotation.Companion.rotationTo import com.lambda.module.Module import com.lambda.module.tag.ModuleTag +import com.lambda.util.PacketUtils.sendPacket import com.lambda.util.extension.rotation import com.lambda.util.math.component1 import com.lambda.util.math.component2 @@ -35,17 +36,18 @@ import net.minecraft.util.Hand import net.minecraft.util.math.BlockPos import net.minecraft.util.math.Direction +@Suppress("unused") object Criticals : Module( name = "Criticals", description = "Forces your hits to be critical", - tag = ModuleTag.COMBAT, + tag = ModuleTag.Combat, ) { - private val mode by setting("Mode", Mode.Grim) - enum class Mode { Grim } + private val mode by setting("Mode", Mode.Grim) + init { listen { when (mode) { @@ -54,13 +56,13 @@ object Criticals : Module( posPacket(-0.000000001, rotation = player.eyePos.rotationTo(it.entity.boundingBox.center)) connection.sendPacket(PlayerInteractItemC2SPacket(Hand.OFF_HAND, 0, player.yaw, player.pitch)) // TODO: This is wrong, fix it - connection.sendPacket( + connection.sendPacket { PlayerActionC2SPacket( PlayerActionC2SPacket.Action.RELEASE_USE_ITEM, BlockPos.ORIGIN, Direction.DOWN ) - ) + } } } } diff --git a/src/main/kotlin/com/lambda/module/modules/combat/CrystalAura.kt b/src/main/kotlin/com/lambda/module/modules/combat/CrystalAura.kt index 9e0fb1a3b..25ea7483b 100644 --- a/src/main/kotlin/com/lambda/module/modules/combat/CrystalAura.kt +++ b/src/main/kotlin/com/lambda/module/modules/combat/CrystalAura.kt @@ -17,9 +17,12 @@ package com.lambda.module.modules.combat -import com.lambda.config.AutomationConfig.Companion.setDefaultAutomationConfig -import com.lambda.config.applyEdits -import com.lambda.config.groups.Targeting +import com.lambda.config.SettingEditor.hide +import com.lambda.config.SettingEditor.hideAllBlocksExcept +import com.lambda.config.Tab +import com.lambda.config.automation.AutomationConfig.Companion.setDefaultAutomationConfig +import com.lambda.config.settings.blocks.TargetingSettings +import com.lambda.config.withEdits import com.lambda.context.SafeContext import com.lambda.event.events.EntityEvent import com.lambda.event.events.TickEvent @@ -28,9 +31,8 @@ import com.lambda.interaction.managers.hotbar.HotbarRequest import com.lambda.interaction.managers.rotating.IRotationRequest.Companion.rotationRequest import com.lambda.interaction.managers.rotating.Rotation.Companion.rotationTo import com.lambda.interaction.managers.rotating.RotationManager -import com.lambda.interaction.managers.rotating.visibilty.VisibilityChecker.getVisibleSurfaces import com.lambda.interaction.material.StackSelection.Companion.selectStack -import com.lambda.interaction.material.container.ContainerManager.transfer +import com.lambda.interaction.material.container.ContainerHandler.transfer import com.lambda.interaction.material.container.containers.HotbarContainer import com.lambda.interaction.material.container.containers.OffHandContainer import com.lambda.module.Module @@ -39,8 +41,7 @@ import com.lambda.threading.runSafe import com.lambda.threading.runSafeAutomated import com.lambda.threading.runSafeGameScheduled import com.lambda.util.BlockUtils.blockState -import com.lambda.util.Communication.info -import com.lambda.util.NamedEnum +import com.lambda.util.CommunicationUtils.info import com.lambda.util.PacketUtils.sendPacket import com.lambda.util.Timer import com.lambda.util.collections.LimitedDecayQueue @@ -53,6 +54,7 @@ import com.lambda.util.math.flooredBlockPos import com.lambda.util.math.getHitVec import com.lambda.util.math.minus import com.lambda.util.math.plus +import com.lambda.util.player.RotationUtils.getVisibleSurfaces import com.lambda.util.player.SlotUtils.hotbarStacks import com.lambda.util.world.fastEntitySearch import net.minecraft.block.Blocks @@ -72,45 +74,47 @@ import kotlin.concurrent.fixedRateTimer import kotlin.math.max import kotlin.time.Duration.Companion.milliseconds +@Suppress("unused") object CrystalAura : Module( name = "CrystalAura", description = "Automatically attacks entities with crystals", - tag = ModuleTag.COMBAT, + tag = ModuleTag.Combat, ) { - /* General */ - private val rotate by setting("Rotate", true).group(Group.General) - private val updateMode by setting("Update Mode", UpdateMode.Async).group(Group.General) - private val updateDelaySetting by setting("Update Delay", 25L, 5L..200L, 5L, unit = " ms") { updateMode == UpdateMode.Async }.group(Group.General) - private val maxUpdatesPerFrame by setting("Max Updates Per Frame", 5, 1..20, 1) { updateMode == UpdateMode.Async }.group(Group.General) - private val updateDelay get() = if (updateMode == UpdateMode.Async) updateDelaySetting else 0L - private val debug by setting("Debug", false).group(Group.General) - - /* Placement */ - private val placeRange by setting("Place Range", 4.6, 1.0..7.0, 0.1, "Range to place crystals", " blocks").group(Group.Placement) - private val placeDelay by setting("Place Delay", 50L, 0L..1000L, 1L, "Delay between placement attempts", " ms").group(Group.Placement) - private val swap by setting("Swap", true, "Swaps to crystals").group(Group.Placement) - private val swapHand by setting("Swap Hand", Hand.MAIN_HAND, "Which hand to swap the crystal to") { swap }.group(Group.Placement) - private val priorityMode by setting("Crystal Priority", Priority.Damage).group(Group.Placement) - private val minDamageAdvantage by setting("Min Damage Advantage", 4.0, 1.0..10.0, 0.5) { priorityMode == Priority.Advantage }.group(Group.Placement) - private val minTargetDamage by setting("Min Target Damage", 8.0, 0.0..20.0, 0.5, "Minimum target damage to use crystals").group(Group.Placement) - private val maxSelfDamage by setting("Max Self Damage", 8.0, 0.0..36.0, 0.5, "Maximum self damage to use crystals").group(Group.Placement) - private val minPlaceHealth by setting("Min Place Health", 5.0, 0.0..36.0, 0.5, "Minimum player health to place crystals").group(Group.Placement) - private val preventDeath by setting("Prevent Death", true, "Prevent death by crystal").group(Group.Placement) - private val oldPlace by setting("1.12 Placement", false).group(Group.Placement) - - /* Exploding */ - private val explodeRange by setting("Explode Range", 3.0, 1.0..7.0, 0.1, "Range to explode crystals", " blocks").group(Group.Exploding) - private val explodeDelay by setting("Explode Delay", 10L, 0L..1000L, 1L, "Delay between explosion attempts", " ms").group(Group.Exploding) - - /* Prediction */ - private val prediction by setting("Prediction", PredictionMode.None).group(Group.Prediction) - private val packetPredictions by setting("Packet Predictions", 1, 0..20, 1) { prediction.onPacket }.group(Group.Prediction) - private val placePostPause by setting("Place Post Pause", true) { prediction.onPacket }.group(Group.Prediction) - private val placePredictions by setting("Place Predictions", 4, 1..20, 1) { prediction.onPlace }.group(Group.Prediction) - private val packetLifetime by setting("Packet Lifetime", 500L, 50L..1000L) { prediction.onPlace }.group(Group.Prediction) - - /* Targeting */ - private val targeting = Targeting.Combat(c = this, Group.Targeting, defaultRange = 10.0) + private const val GeneralTab = "General" + private const val PlacementTab = "Placement" + private const val ExplodingTab = "Exploding" + private const val PredictionTab = "Prediction" + private const val TargetingTab = "Targeting" + + @Tab(GeneralTab) private val rotate by setting("Rotate", true) + @Tab(GeneralTab) private val updateMode by setting("Update Mode", UpdateMode.Async) + @Tab(GeneralTab) private val updateDelaySetting by setting("Update Delay", 25L, 5L..200L, 5L, unit = " ms") { updateMode == UpdateMode.Async } + @Tab(GeneralTab) private val maxUpdatesPerFrame by setting("Max Updates Per Frame", 5, 1..20, 1) { updateMode == UpdateMode.Async } + @Tab(GeneralTab) private val updateDelay get() = if (updateMode == UpdateMode.Async) updateDelaySetting else 0L + @Tab(GeneralTab) private val debug by setting("Debug", false) + + @Tab(PlacementTab) private val placeRange by setting("Place Range", 4.6, 1.0..7.0, 0.1, "Range to place crystals", " blocks") + @Tab(PlacementTab) private val placeDelay by setting("Place Delay", 50L, 0L..1000L, 1L, "Delay between placement attempts", " ms") + @Tab(PlacementTab) private val swap by setting("Swap", true, "Swaps to crystals") + @Tab(PlacementTab) private val swapHand by setting("Swap Hand", Hand.MAIN_HAND, "Which hand to swap the crystal to") { swap } + @Tab(PlacementTab) private val priorityMode by setting("Crystal Priority", Priority.Damage) + @Tab(PlacementTab) private val minDamageAdvantage by setting("Min Damage Advantage", 4.0, 1.0..10.0, 0.5) { priorityMode == Priority.Advantage } + @Tab(PlacementTab) private val minTargetDamage by setting("Min Target Damage", 8.0, 0.0..20.0, 0.5, "Minimum target damage to use crystals") + @Tab(PlacementTab) private val maxSelfDamage by setting("Max Self Damage", 8.0, 0.0..36.0, 0.5, "Maximum self damage to use crystals") + @Tab(PlacementTab) private val minPlaceHealth by setting("Min Place Health", 5.0, 0.0..36.0, 0.5, "Minimum player health to place crystals") + @Tab(PlacementTab) private val preventDeath by setting("Prevent Death", true, "Prevent death by crystal") + @Tab(PlacementTab) private val oldPlace by setting("1.12 Placement", false) + + @Tab(ExplodingTab) private val explodeRange by setting("Explode Range", 3.0, 1.0..7.0, 0.1, "Range to explode crystals", " blocks") + @Tab(ExplodingTab) private val explodeDelay by setting("Explode Delay", 10L, 0L..1000L, 1L, "Delay between explosion attempts", " ms") + + @Tab(PredictionTab) private val prediction by setting("Prediction", PredictionMode.None) + @Tab(PredictionTab) private val packetPredictions by setting("Packet Predictions", 1, 0..20, 1) { prediction.onPacket } + @Tab(PredictionTab) private val placePostPause by setting("Place Post Pause", true) { prediction.onPacket } + @Tab(PredictionTab) private val placePredictions by setting("Place Predictions", 4, 1..20, 1) { prediction.onPlace } + @Tab(PredictionTab) private val packetLifetime by setting("Packet Lifetime", 500L, 50L..1000L) { prediction.onPlace } + + @Tab(PredictionTab) private val targetingSettings by configBlock(TargetingSettings.CombatSettings(this, 10.0)) private val blueprint = mutableMapOf() private var activeOpportunity: Opportunity? = null @@ -142,17 +146,16 @@ object CrystalAura : Module( } init { - setDefaultAutomationConfig { - applyEdits { - hideAllGroupsExcept(buildConfig, rotationConfig, hotbarConfig, inventoryConfig) - buildConfig.apply { - hide( - ::pathing, ::stayInRange, ::collectDrops, ::spleefEntities, - ::maxPendingActions, ::actionTimeout, ::maxBuildDependencies, ::breakBlocks, ::interactBlocks, ::placeBlocks - ) - } - } - } + setDefaultAutomationConfig() + .withEdits { + hideAllBlocksExcept(::buildConfig, ::rotationConfig, ::hotbarConfig, ::inventoryConfig) + buildConfig.apply { + hide( + ::pathing, ::stayInRange, ::collectDrops, ::spleefEntities, + ::maxPendingActions, ::actionTimeout, ::maxBuildDependencies, ::breakBlocks, ::interactBlocks, ::placeBlocks + ) + } + } // Async ticking fixedRateTimer( @@ -245,7 +248,7 @@ object CrystalAura : Module( private fun SafeContext.tick() { // Update the target - currentTarget = targeting.target() + currentTarget = targetingSettings.target() // Update the blueprint currentTarget?.let { @@ -551,15 +554,6 @@ object CrystalAura : Module( ) } - private enum class Group(override val displayName: String): NamedEnum { - General("General"), - Placement("Placement"), - Exploding("Exploding"), - Prediction("Prediction"), - Targeting("Targeting"), - Rotation("Rotation") - } - private enum class UpdateMode { Async, Ticked 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 bbc7152be..fe88ac343 100644 --- a/src/main/kotlin/com/lambda/module/modules/combat/FakePlayer.kt +++ b/src/main/kotlin/com/lambda/module/modules/combat/FakePlayer.kt @@ -37,10 +37,11 @@ import java.util.* import kotlin.jvm.optionals.getOrNull import kotlin.time.Duration.Companion.seconds +@Suppress("unused") object FakePlayer : Module( name = "FakePlayer", description = "Spawns a fake player", - tag = ModuleTag.COMBAT, + tag = ModuleTag.Combat, ) { private val playerName by setting("Name", "Steve") 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 04feeb894..48a136a28 100644 --- a/src/main/kotlin/com/lambda/module/modules/combat/KillAura.kt +++ b/src/main/kotlin/com/lambda/module/modules/combat/KillAura.kt @@ -17,16 +17,19 @@ package com.lambda.module.modules.combat -import com.lambda.config.AutomationConfig.Companion.setDefaultAutomationConfig -import com.lambda.config.applyEdits -import com.lambda.config.groups.Targeting +import com.lambda.config.SettingEditor.edit +import com.lambda.config.SettingEditor.hide +import com.lambda.config.SettingEditor.hideAllBlocksExcept +import com.lambda.config.Tab +import com.lambda.config.automation.AutomationConfig.Companion.setDefaultAutomationConfig +import com.lambda.config.settings.blocks.TargetingSettings +import com.lambda.config.withEdits import com.lambda.context.SafeContext import com.lambda.event.events.InventoryEvent import com.lambda.event.events.TickEvent import com.lambda.event.listener.SafeListener.Companion.listen import com.lambda.interaction.managers.hotbar.HotbarRequest import com.lambda.interaction.managers.rotating.IRotationRequest.Companion.rotationRequest -import com.lambda.interaction.managers.rotating.visibilty.lookAtEntity import com.lambda.interaction.material.StackSelection.Companion.selectStack import com.lambda.module.Module import com.lambda.module.tag.ModuleTag @@ -35,6 +38,7 @@ import com.lambda.util.NamedEnum import com.lambda.util.item.ItemStackUtils.attackDamage import com.lambda.util.item.ItemStackUtils.attackSpeed import com.lambda.util.math.random +import com.lambda.util.player.RotationUtils.lookAtEntity import com.lambda.util.player.SlotUtils.hotbarStacks import net.minecraft.entity.Entity import net.minecraft.item.ItemStack @@ -45,23 +49,25 @@ import net.minecraft.world.GameMode object KillAura : Module( name = "KillAura", description = "Attacks entities", - tag = ModuleTag.COMBAT, + tag = ModuleTag.Combat, + modulePriority = 90 ) { - // Interact - private val rotate by setting("Rotate", true).group(Group.General) - private val swap by setting("Swap", true, "Swap to the item with the highest damage").group(Group.General) - private val disableWhileGliding by setting("Disable While Gliding", false, "Disables when gliding with an elytra").group(Group.General) - private val damageMode by setting("Damage Mode", DamageMode.DPS).group(Group.General) - private val attackMode by setting("Attack Mode", AttackMode.Cooldown).group(Group.General) - private val cooldownShrink by setting("Cooldown Offset", 0, 0..5, 1) { attackMode == AttackMode.Cooldown }.group(Group.General) - private val hitDelay1 by setting("Hit Delay 1", 2.0, 0.0..20.0, 1.0) { attackMode == AttackMode.Delay }.group(Group.General) - private val hitDelay2 by setting("Hit Delay 2", 6.0, 0.0..20.0, 1.0) { attackMode == AttackMode.Delay }.group(Group.General) - - // Targeting - private val targeting = Targeting.Combat(c = this, Group.Targeting) + private const val GeneralTab = "General" + private const val TargetingTab = "Targeting" + + @Tab(GeneralTab) private val rotate by setting("Rotate", true) + @Tab(GeneralTab) private val swap by setting("Swap", true, "Swap to the item with the highest damage") + @Tab(GeneralTab) private val disableWhileGliding by setting("Disable While Gliding", false, "Disables when gliding with an elytra") + @Tab(GeneralTab) private val damageMode by setting("Damage Mode", DamageMode.DPS) + @Tab(GeneralTab) private val attackMode by setting("Attack Mode", AttackMode.Cooldown) + @Tab(GeneralTab) private val cooldownShrink by setting("Cooldown Offset", 0, 0..5, 1) { attackMode == AttackMode.Cooldown } + @Tab(GeneralTab) private val hitDelay1 by setting("Hit Delay 1", 2.0, 0.0..20.0, 1.0) { attackMode == AttackMode.Delay } + @Tab(GeneralTab) private val hitDelay2 by setting("Hit Delay 2", 6.0, 0.0..20.0, 1.0) { attackMode == AttackMode.Delay } + + @Tab(TargetingTab) private val targetingSettings by configBlock(TargetingSettings.CombatSettings(this)) val target: Entity? - get() = targeting.target() + get() = targetingSettings.target() private var prevEntity = target private var validServerRot = false @@ -70,11 +76,6 @@ object KillAura : Module( private var hitDelay = 100.0 private var cooldownFromSwap = false - enum class Group(override val displayName: String) : NamedEnum { - General("General"), - Targeting("Targeting"), - } - enum class AttackMode { Cooldown, Delay @@ -87,10 +88,9 @@ object KillAura : Module( } init { - setModulePriority(90) - setDefaultAutomationConfig { - applyEdits { - hideAllGroupsExcept(buildConfig, hotbarConfig, rotationConfig) + setDefaultAutomationConfig() + .withEdits { + hideAllBlocksExcept(::buildConfig, ::hotbarConfig, ::rotationConfig) buildConfig.apply { hide( ::pathing, ::stayInRange, ::collectDrops, @@ -102,7 +102,6 @@ object KillAura : Module( ::tickStageMask.edit { defaultValue(mutableSetOf(TickEvent.Pre)) } } } - } listen { cooldownFromSwap = true } diff --git a/src/main/kotlin/com/lambda/module/modules/combat/PlayerTrap.kt b/src/main/kotlin/com/lambda/module/modules/combat/PlayerTrap.kt index 67339b858..d52a378ac 100644 --- a/src/main/kotlin/com/lambda/module/modules/combat/PlayerTrap.kt +++ b/src/main/kotlin/com/lambda/module/modules/combat/PlayerTrap.kt @@ -17,13 +17,14 @@ package com.lambda.module.modules.combat -import com.lambda.config.AutomationConfig.Companion.setDefaultAutomationConfig -import com.lambda.config.applyEdits +import com.lambda.config.SettingEditor.editTyped +import com.lambda.config.SettingEditor.hideBlock +import com.lambda.config.automation.AutomationConfig.Companion.setDefaultAutomationConfig +import com.lambda.config.withEdits import com.lambda.context.SafeContext -import com.lambda.friend.FriendManager.isFriend +import com.lambda.friend.FriendHandler.isFriend import com.lambda.interaction.construction.blueprint.TickingBlueprint.Companion.tickingBlueprint import com.lambda.interaction.construction.verify.TargetState -import com.lambda.interaction.managers.interacting.InteractConfig import com.lambda.module.Module import com.lambda.module.tag.ModuleTag import com.lambda.task.RootTask.run @@ -45,7 +46,7 @@ import kotlin.jvm.optionals.getOrNull object PlayerTrap : Module( name = "PlayerTrap", description = "Surrounds players with any given block", - tag = ModuleTag.COMBAT + tag = ModuleTag.Combat ) { private val blocks by setting("Blocks", setOf(Blocks.OBSIDIAN, Blocks.ENDER_CHEST, Blocks.CRYING_OBSIDIAN)) private val friends by setting("Friends", false) @@ -54,8 +55,8 @@ object PlayerTrap : Module( private var task: Task<*>? = null init { - setDefaultAutomationConfig { - applyEdits { + setDefaultAutomationConfig() + .withEdits { buildConfig.apply { editTyped( ::pathing, @@ -64,9 +65,8 @@ object PlayerTrap : Module( ::collectDrops ) { defaultValue(false); hide() } } - hideGroup(eatConfig) + hideBlock(::eatConfig) } - } onEnable { task = tickingBlueprint { diff --git a/src/main/kotlin/com/lambda/module/modules/combat/Surround.kt b/src/main/kotlin/com/lambda/module/modules/combat/Surround.kt index 146eb87b4..d1a6c7e2d 100644 --- a/src/main/kotlin/com/lambda/module/modules/combat/Surround.kt +++ b/src/main/kotlin/com/lambda/module/modules/combat/Surround.kt @@ -17,11 +17,12 @@ package com.lambda.module.modules.combat -import com.lambda.config.AutomationConfig.Companion.setDefaultAutomationConfig -import com.lambda.config.applyEdits +import com.lambda.config.SettingEditor.editTyped +import com.lambda.config.SettingEditor.hideBlock +import com.lambda.config.automation.AutomationConfig.Companion.setDefaultAutomationConfig +import com.lambda.config.withEdits import com.lambda.interaction.construction.blueprint.TickingBlueprint.Companion.tickingBlueprint import com.lambda.interaction.construction.verify.TargetState -import com.lambda.interaction.managers.interacting.InteractConfig import com.lambda.module.Module import com.lambda.module.modules.combat.PlayerTrap.getTrapPositions import com.lambda.module.tag.ModuleTag @@ -33,18 +34,19 @@ import com.lambda.util.player.SlotUtils.hotbarAndInventoryStacks import net.minecraft.block.Blocks import net.minecraft.item.BlockItem +@Suppress("unused") object Surround : Module( name = "Surround", description = "Surrounds your players feet with any given block", - tag = ModuleTag.COMBAT + tag = ModuleTag.Combat ) { private val blocks by setting("Blocks", setOf(Blocks.OBSIDIAN, Blocks.ENDER_CHEST, Blocks.CRYING_OBSIDIAN)) private var task: Task<*>? = null init { - setDefaultAutomationConfig { - applyEdits { + setDefaultAutomationConfig() + .withEdits { buildConfig.apply { editTyped( ::pathing, @@ -53,9 +55,8 @@ object Surround : Module( ::collectDrops ) { defaultValue(false); hide() } } - hideGroup(eatConfig) + hideBlock(::eatConfig) } - } onEnable { task = tickingBlueprint { diff --git a/src/main/kotlin/com/lambda/module/modules/debug/BaritoneTest.kt b/src/main/kotlin/com/lambda/module/modules/debug/BaritoneTest.kt index 9d1cc7500..7237eb029 100644 --- a/src/main/kotlin/com/lambda/module/modules/debug/BaritoneTest.kt +++ b/src/main/kotlin/com/lambda/module/modules/debug/BaritoneTest.kt @@ -20,22 +20,23 @@ package com.lambda.module.modules.debug import baritone.api.pathing.goals.GoalXZ import com.lambda.event.events.TickEvent import com.lambda.event.listener.SafeListener.Companion.listen -import com.lambda.interaction.BaritoneManager +import com.lambda.interaction.BaritoneHandler import com.lambda.module.Module import com.lambda.module.tag.ModuleTag +@Suppress("unused") object BaritoneTest : Module( name = "BaritoneTest", description = "Test Baritone", - tag = ModuleTag.DEBUG, + tag = ModuleTag.Debug, ) { init { listen { - BaritoneManager.setGoalAndPath(GoalXZ(0, 0)) + BaritoneHandler.setGoalAndPath(GoalXZ(0, 0)) } onDisable { - BaritoneManager.cancel() + BaritoneHandler.cancel() } } } diff --git a/src/main/kotlin/com/lambda/module/modules/debug/BlockTest.kt b/src/main/kotlin/com/lambda/module/modules/debug/BlockTest.kt index 6f78877d9..083473926 100644 --- a/src/main/kotlin/com/lambda/module/modules/debug/BlockTest.kt +++ b/src/main/kotlin/com/lambda/module/modules/debug/BlockTest.kt @@ -21,16 +21,16 @@ import com.lambda.graphics.mc.renderer.TickedRenderer.Companion.tickedRenderer import com.lambda.module.Module import com.lambda.module.tag.ModuleTag import com.lambda.threading.runSafe -import com.lambda.util.ChatUtils.colors import com.lambda.util.world.blockSearch import net.minecraft.block.Blocks import net.minecraft.util.math.Vec3i import java.awt.Color +@Suppress("unused") object BlockTest : Module( name = "BlockTest", description = "BlockTest", - tag = ModuleTag.DEBUG, + tag = ModuleTag.Debug, ) { private val rangeX by setting("Range X", 5, 1..7, 1, "Range X") private val rangeY by setting("Range Y", 5, 1..7, 1, "Range Y") diff --git a/src/main/kotlin/com/lambda/module/modules/debug/ContainerTest.kt b/src/main/kotlin/com/lambda/module/modules/debug/ContainerTest.kt index 3b452015e..d5e2e7b1a 100644 --- a/src/main/kotlin/com/lambda/module/modules/debug/ContainerTest.kt +++ b/src/main/kotlin/com/lambda/module/modules/debug/ContainerTest.kt @@ -26,10 +26,11 @@ import com.lambda.task.RootTask.run import com.lambda.task.tasks.AcquireMaterialTask.Companion.acquire import net.minecraft.item.Items +@Suppress("unused") object ContainerTest : Module( name = "ContainerTest", description = "Test container", - tag = ModuleTag.DEBUG, + tag = ModuleTag.Debug, ) { init { listen { 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 73bc7f569..c96db2cd4 100644 --- a/src/main/kotlin/com/lambda/module/modules/debug/DebugRendererModule.kt +++ b/src/main/kotlin/com/lambda/module/modules/debug/DebugRendererModule.kt @@ -17,17 +17,14 @@ package com.lambda.module.modules.debug -import com.lambda.Lambda.mc import com.lambda.module.Module import com.lambda.module.tag.ModuleTag -import net.minecraft.client.render.VertexConsumerProvider -import net.minecraft.client.render.debug.DebugRenderer -import net.minecraft.client.util.math.MatrixStack +@Suppress("unused") object DebugRendererModule: Module( name = "Debug Renderer", description = "Renders debug information of minecraft internals", - tag = ModuleTag.DEBUG, + tag = ModuleTag.Debug, ) { private val waterDebugRenderer by setting("Water Debug Renderer", false) private val chunkBorderDebugRenderer by setting("Chunk Border Debug Renderer", false) diff --git a/src/main/kotlin/com/lambda/module/modules/debug/FallTest.kt b/src/main/kotlin/com/lambda/module/modules/debug/FallTest.kt index 7a5bf4de2..446803891 100644 --- a/src/main/kotlin/com/lambda/module/modules/debug/FallTest.kt +++ b/src/main/kotlin/com/lambda/module/modules/debug/FallTest.kt @@ -21,13 +21,14 @@ import com.lambda.event.events.TickEvent import com.lambda.event.listener.SafeListener.Companion.listen import com.lambda.module.Module import com.lambda.module.tag.ModuleTag -import com.lambda.util.Communication.info +import com.lambda.util.CommunicationUtils.info import com.lambda.util.combat.DamageUtils.fallDamage import com.lambda.util.combat.DamageUtils.isFallDeadly +@Suppress("unused") object FallTest : Module( name = "FallTest", - tag = ModuleTag.DEBUG, + tag = ModuleTag.Debug, ) { init { listen { diff --git a/src/main/kotlin/com/lambda/module/modules/debug/InventoryDebug.kt b/src/main/kotlin/com/lambda/module/modules/debug/InventoryDebug.kt index ccf7bed30..da058e09e 100644 --- a/src/main/kotlin/com/lambda/module/modules/debug/InventoryDebug.kt +++ b/src/main/kotlin/com/lambda/module/modules/debug/InventoryDebug.kt @@ -17,13 +17,13 @@ package com.lambda.module.modules.debug -import com.lambda.Lambda.LOG +import com.lambda.Lambda.Log import com.lambda.event.events.InventoryEvent import com.lambda.event.events.PacketEvent import com.lambda.event.listener.SafeListener.Companion.listen import com.lambda.module.Module import com.lambda.module.tag.ModuleTag -import com.lambda.util.Communication.info +import com.lambda.util.CommunicationUtils.info import com.lambda.util.DynamicReflectionSerializer.dynamicString import net.minecraft.network.packet.c2s.play.ClickSlotC2SPacket import net.minecraft.network.packet.c2s.play.CloseHandledScreenC2SPacket @@ -34,16 +34,17 @@ import net.minecraft.network.packet.c2s.play.UpdateSelectedSlotC2SPacket import net.minecraft.network.packet.s2c.play.InventoryS2CPacket import net.minecraft.network.packet.s2c.play.UpdateSelectedSlotS2CPacket +@Suppress("unused") object InventoryDebug : Module( name = "InventoryDebug", description = "Debugs the inventory", - tag = ModuleTag.DEBUG, + tag = ModuleTag.Debug, ) { init { listen { event -> info("Opened screen handler: ${event.screenHandler::class.simpleName}") - LOG.info("\n" + event.screenHandler.slots.joinToString("\n") { + Log.info("\n" + event.screenHandler.slots.joinToString("\n") { "${it.inventory::class.simpleName} ${it.index} ${it.x} ${it.y}" }) } @@ -61,7 +62,7 @@ object InventoryDebug : Module( is UpdateSelectedSlotS2CPacket, is InventoryS2CPacket, -> { - LOG.info(it.packet.dynamicString()) + Log.info(it.packet.dynamicString()) } } when (val packet = it.packet) { @@ -79,7 +80,7 @@ object InventoryDebug : Module( is CraftRequestC2SPacket, is CreativeInventoryActionC2SPacket, is UpdateSelectedSlotC2SPacket, - -> LOG.info(System.currentTimeMillis().toString() + " " + it.packet.dynamicString()) + -> Log.info(System.currentTimeMillis().toString() + " " + it.packet.dynamicString()) } } } diff --git a/src/main/kotlin/com/lambda/module/modules/debug/PropertyPrinter.kt b/src/main/kotlin/com/lambda/module/modules/debug/PropertyPrinter.kt index c470aec00..fb45830d7 100644 --- a/src/main/kotlin/com/lambda/module/modules/debug/PropertyPrinter.kt +++ b/src/main/kotlin/com/lambda/module/modules/debug/PropertyPrinter.kt @@ -19,19 +19,20 @@ package com.lambda.module.modules.debug import com.lambda.module.Module import com.lambda.module.tag.ModuleTag -import com.lambda.util.FolderRegister +import com.lambda.util.FolderRegistry import com.lambda.util.extension.resolveFile import net.minecraft.block.Block import net.minecraft.block.Blocks +@Suppress("unused") object PropertyPrinter : Module( name = "PropertyPrinter", description = "Prints all properties coupled with all the states that use them into a text file", - tag = ModuleTag.DEBUG, + tag = ModuleTag.Debug, ) { init { onEnable { - val file = FolderRegister.lambda.resolve("property-print").resolveFile("property-print.txt") + val file = FolderRegistry.lambda.resolve("property-print").resolveFile("property-print.txt") file.parentFile.mkdirs() file.writeText("") StateInfo.propertyFields.forEach properties@{ property -> diff --git a/src/main/kotlin/com/lambda/module/modules/debug/RenderTest.kt b/src/main/kotlin/com/lambda/module/modules/debug/RenderTest.kt index 7b3193008..cdf3f1681 100644 --- a/src/main/kotlin/com/lambda/module/modules/debug/RenderTest.kt +++ b/src/main/kotlin/com/lambda/module/modules/debug/RenderTest.kt @@ -23,7 +23,6 @@ import com.lambda.graphics.util.DynamicAABB.Companion.dynamicBox import com.lambda.module.Module import com.lambda.module.tag.ModuleTag import com.lambda.threading.runSafe -import com.lambda.util.ChatUtils.colors import com.lambda.util.extension.tickDelta import com.lambda.util.math.setAlpha import com.lambda.util.world.entitySearch @@ -31,10 +30,11 @@ import net.minecraft.entity.LivingEntity import net.minecraft.util.math.Box import java.awt.Color +@Suppress("unused") object RenderTest : Module( name = "Render:shrimp:Test:canned_food:", description = "RenderTest", - tag = ModuleTag.DEBUG, + tag = ModuleTag.Debug, ) { private val test1 by setting("Toggle visibility", true) private val test21 by setting("Hallo 1", true, visibility = ::test1) diff --git a/src/main/kotlin/com/lambda/module/modules/debug/RendererTestModule.kt b/src/main/kotlin/com/lambda/module/modules/debug/RendererTestModule.kt index 6e88b541a..c4e600a64 100644 --- a/src/main/kotlin/com/lambda/module/modules/debug/RendererTestModule.kt +++ b/src/main/kotlin/com/lambda/module/modules/debug/RendererTestModule.kt @@ -30,9 +30,7 @@ import com.lambda.graphics.mc.RenderBuilder.SDFStyle import com.lambda.graphics.mc.renderer.ChunkedRenderer.Companion.chunkedRenderer import com.lambda.graphics.mc.renderer.ImmediateRenderer.Companion.immediateRenderer import com.lambda.graphics.mc.renderer.TickedRenderer.Companion.tickedRenderer -import com.lambda.graphics.outline.OutlineManager import com.lambda.graphics.outline.OutlineStyle -import com.lambda.graphics.outline.VertexCapture import com.lambda.module.Module import com.lambda.module.tag.ModuleTag import com.lambda.threading.runSafe @@ -40,9 +38,6 @@ import com.lambda.util.extension.prevPos import com.lambda.util.extension.tickDelta import com.lambda.util.math.lerp import com.lambda.util.world.toBlockPos -import net.minecraft.entity.mob.HostileEntity -import net.minecraft.entity.passive.PassiveEntity -import net.minecraft.entity.player.PlayerEntity import net.minecraft.item.ItemStack import net.minecraft.item.Items import net.minecraft.util.Identifier @@ -54,10 +49,11 @@ import net.minecraft.util.math.random.Random import org.joml.Quaternionf import java.awt.Color +@Suppress("unused") object ChunkedRendererTest : Module( name = "ChunkedRendererTest", description = "Test module for ChunkedRenderer", - tag = ModuleTag.DEBUG, + tag = ModuleTag.Debug, ) { var updated = false @@ -168,10 +164,11 @@ object ChunkedRendererTest : Module( } } +@Suppress("unused") object TickedRendererTest : Module( name = "TickedRendererTest", description = "Test module for TickedRenderer", - tag = ModuleTag.DEBUG, + tag = ModuleTag.Debug, ) { private val throughWalls by setting("Through Walls", true) @@ -274,10 +271,11 @@ object TickedRendererTest : Module( } } +@Suppress("unused") object ImmediateRendererTest : Module( name = "ImmediateRendererTest", description = "Test module for ImmediateRenderer", - tag = ModuleTag.DEBUG, + tag = ModuleTag.Debug, ) { private val throughWalls by setting("Through Walls", true) diff --git a/src/main/kotlin/com/lambda/module/modules/debug/RotationTest.kt b/src/main/kotlin/com/lambda/module/modules/debug/RotationTest.kt index 20375406d..c2ceafb9c 100644 --- a/src/main/kotlin/com/lambda/module/modules/debug/RotationTest.kt +++ b/src/main/kotlin/com/lambda/module/modules/debug/RotationTest.kt @@ -17,21 +17,19 @@ package com.lambda.module.modules.debug -import com.lambda.config.AutomationConfig -import com.lambda.config.groups.RotationSettings import com.lambda.event.events.TickEvent import com.lambda.event.listener.SafeListener.Companion.listen import com.lambda.interaction.managers.rotating.IRotationRequest.Companion.rotationRequest -import com.lambda.interaction.managers.rotating.visibilty.lookAt import com.lambda.module.Module import com.lambda.module.tag.ModuleTag +import com.lambda.util.player.RotationUtils.lookAt import net.minecraft.util.hit.HitResult +@Suppress("unused") object RotationTest : Module( name = "RotationTest", - tag = ModuleTag.DEBUG, + tag = ModuleTag.Debug, ) { - override val rotationConfig = RotationSettings(this, AutomationConfig.Group.Rotation) var hitPos: HitResult? = null init { diff --git a/src/main/kotlin/com/lambda/module/modules/debug/SettingsTestModule.kt b/src/main/kotlin/com/lambda/module/modules/debug/SettingsTestModule.kt index 4b24ae97c..45218ec98 100644 --- a/src/main/kotlin/com/lambda/module/modules/debug/SettingsTestModule.kt +++ b/src/main/kotlin/com/lambda/module/modules/debug/SettingsTestModule.kt @@ -17,77 +17,40 @@ package com.lambda.module.modules.debug -import com.lambda.config.groups.ScreenLineSettings -import com.lambda.config.groups.WorldLineSettings -import com.lambda.config.groups.ScreenTextSettings -import com.lambda.config.groups.WorldTextSettings +import com.lambda.config.Config +import com.lambda.config.ConfigBlock +import com.lambda.config.Group +import com.lambda.config.Tab +import com.lambda.config.settings.blocks.ScreenLineSettings +import com.lambda.config.settings.blocks.ScreenTextSettings +import com.lambda.config.settings.blocks.WorldLineSettings +import com.lambda.config.settings.blocks.WorldTextSettings import com.lambda.module.Module import com.lambda.module.tag.ModuleTag +@Suppress("unused") object SettingsTestModule : Module( name = "SettingsTestModule", description = "Test module for Line and Text Config Settings", - tag = ModuleTag.DEBUG + tag = ModuleTag.Debug ) { - private enum class Page(override val displayName: String) : com.lambda.util.NamedEnum { - WorldLine("World Line"), - ScreenLine("Screen Line"), - WorldText("World Text"), - ScreenText("Screen Text") - } - - private val worldLineConfig = WorldLineSettings( - this, - Page.WorldLine, - prefix = "World Line " - ) - - private val screenLineConfig = ScreenLineSettings( - this, - Page.ScreenLine, - prefix = "Screen Line " - ) - - private val worldTextConfig = WorldTextSettings( - this, - Page.WorldText, - prefix = "World Text " - ) - - private val textConfig = ScreenTextSettings( - this, - Page.ScreenText, - prefix = "Screen Text " - ) - -// private val renderer = ImmediateRenderer("SettingsTestRenderer") + private const val WorldLineTab = "World Line" + private const val ScreenLineTab = "Screen Line" + private const val WorldTextTab = "World Text" + private const val ScreenTextTab = "Screen Text" + + private const val TestConfigBlockTab = "Test Config Block Tab" + private const val TestConfigBlockGroup = "Test Config Block Group" + @Tab(TestConfigBlockTab) @Group(TestConfigBlockGroup) private val testConfigBlock by configBlock(TestConfigBlock(this)) + @Tab(TestConfigBlockTab) private val testValue1 by property(1) + + @Tab(WorldLineTab) private val worldLineConfig by configBlock(WorldLineSettings(this)) + @Tab(ScreenLineTab) private val screenLineConfig by configBlock(ScreenLineSettings(this)) + @Tab(WorldTextTab) private val worldTextConfig by configBlock(WorldTextSettings(this)) + @Tab(ScreenTextTab) private val textConfig by configBlock(ScreenTextSettings(this)) +} -// init { -// listen { -// renderer.tick() -// renderer.shapes { -// val startPos = lerp(mc.tickDelta, player.prevPos, player.pos).offset(Direction.NORTH, 3.0) -// -// // Render line using config -// lineGradient( -// startPos, -// lineConfig.startColor, -// startPos.offset(Direction.EAST, 3.0), -// lineConfig.endColor, -// lineConfig.lineWidth, -// lineConfig.getDashStyle() -// ) -// -// // Render text using config -// worldText( -// "Configured Text", -// startPos.add(0.0, 1.0, 0.0), -// style = textConfig.getSDFStyle() -// ) -// } -// renderer.render() -// } -// -// onDisable { renderer.close() } -// } +class TestConfigBlock(override val c: Config) : ConfigBlock { + var testValue2 by c.property(2) + val testValue3 by c.property { 3 } } diff --git a/src/main/kotlin/com/lambda/module/modules/debug/SilentSwap.kt b/src/main/kotlin/com/lambda/module/modules/debug/SilentSwap.kt index 3e194fc37..b1201be3d 100644 --- a/src/main/kotlin/com/lambda/module/modules/debug/SilentSwap.kt +++ b/src/main/kotlin/com/lambda/module/modules/debug/SilentSwap.kt @@ -17,27 +17,27 @@ package com.lambda.module.modules.debug -import com.lambda.config.groups.HotbarSettings +import com.lambda.config.SettingEditor.hideAllBlocksExcept +import com.lambda.config.automation.AutomationConfig.Companion.setDefaultAutomationConfig +import com.lambda.config.withEdits import com.lambda.event.events.PlayerEvent import com.lambda.event.listener.SafeListener.Companion.listen import com.lambda.interaction.managers.hotbar.HotbarRequest import com.lambda.module.Module import com.lambda.module.tag.ModuleTag -import com.lambda.util.Communication.info -import com.lambda.util.NamedEnum +import com.lambda.util.CommunicationUtils.info object SilentSwap : Module( name = "SilentSwap", description = "SilentSwap", - tag = ModuleTag.DEBUG, + tag = ModuleTag.Debug, ) { - private enum class Group(override val displayName: String) : NamedEnum { - Hotbar("Hotbar") - } - - override val hotbarConfig = HotbarSettings(this, Group.Hotbar) - init { + setDefaultAutomationConfig() + .withEdits { + hideAllBlocksExcept(::hotbarConfig) + } + listen { if (!HotbarRequest(0, this@SilentSwap).submit().done) { it.cancel() diff --git a/src/main/kotlin/com/lambda/module/modules/debug/StateInfo.kt b/src/main/kotlin/com/lambda/module/modules/debug/StateInfo.kt index beb055cbc..f073d8c08 100644 --- a/src/main/kotlin/com/lambda/module/modules/debug/StateInfo.kt +++ b/src/main/kotlin/com/lambda/module/modules/debug/StateInfo.kt @@ -21,7 +21,7 @@ import com.lambda.config.settings.complex.KeybindSetting.Companion.onPress import com.lambda.module.Module import com.lambda.module.tag.ModuleTag import com.lambda.util.BlockUtils.blockState -import com.lambda.util.Communication.info +import com.lambda.util.CommunicationUtils.info import com.lambda.util.KeyCode import net.minecraft.block.BlockState import net.minecraft.state.property.Properties @@ -31,8 +31,9 @@ import net.minecraft.util.hit.BlockHitResult object StateInfo : Module( name = "StateInfo", description = "Prints the target block's state into chat", - tag = ModuleTag.DEBUG, + tag = ModuleTag.Debug, ) { + @Suppress("unused") private val printBind by setting("Print", KeyCode.Unbound, "The bind used to print the info to chat") .onPress { val crosshair = mc.crosshairTarget ?: return@onPress diff --git a/src/main/kotlin/com/lambda/module/modules/debug/TimerTest.kt b/src/main/kotlin/com/lambda/module/modules/debug/TimerTest.kt index c38ca4ffc..4a6fb21bb 100644 --- a/src/main/kotlin/com/lambda/module/modules/debug/TimerTest.kt +++ b/src/main/kotlin/com/lambda/module/modules/debug/TimerTest.kt @@ -22,11 +22,12 @@ 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.tag.ModuleTag -import com.lambda.util.Communication.info +import com.lambda.util.CommunicationUtils.info +@Suppress("unused") object TimerTest : Module( name = "TimerTest", - tag = ModuleTag.DEBUG, + tag = ModuleTag.Debug, ) { private var last = 0L diff --git a/src/main/kotlin/com/lambda/module/modules/movement/AutoSpiral.kt b/src/main/kotlin/com/lambda/module/modules/movement/AutoSpiral.kt index f68c0a0da..8994e8d9b 100644 --- a/src/main/kotlin/com/lambda/module/modules/movement/AutoSpiral.kt +++ b/src/main/kotlin/com/lambda/module/modules/movement/AutoSpiral.kt @@ -21,14 +21,13 @@ import baritone.api.pathing.goals.GoalXZ import com.lambda.context.SafeContext import com.lambda.event.events.TickEvent import com.lambda.event.listener.SafeListener.Companion.listen -import com.lambda.interaction.BaritoneManager +import com.lambda.interaction.BaritoneHandler import com.lambda.interaction.managers.rotating.IRotationRequest.Companion.rotationRequest -import com.lambda.interaction.managers.rotating.visibilty.lookAt import com.lambda.module.Module import com.lambda.module.tag.ModuleTag -import com.lambda.threading.runSafe import com.lambda.util.BlockPosIterators import com.lambda.util.extension.isNether +import com.lambda.util.player.RotationUtils.lookAt import net.minecraft.util.math.BlockPos import kotlin.math.sqrt @@ -36,7 +35,7 @@ import kotlin.math.sqrt object AutoSpiral : Module( name = "AutoSpiral", description = "Automatically flies in a spiral pattern. Uses Baritone elytra pathing in the Nether.", - tag = ModuleTag.MOVEMENT, + tag = ModuleTag.Movement, ) { var iterator: BlockPosIterators.SpiralIterator2d? = null var currentWaypoint: BlockPos? = null @@ -61,7 +60,7 @@ object AutoSpiral : Module( onDisable { iterator = null currentWaypoint = null - BaritoneManager.cancel() + BaritoneHandler.cancel() } listen { @@ -97,9 +96,9 @@ object AutoSpiral : Module( val scaled = pos.multiply(spiralSpacing) val w = scaled.add(center) if (world.isNether) { - BaritoneManager.setGoalAndElytraPath(GoalXZ(w.x, w.z)) + BaritoneHandler.setGoalAndElytraPath(GoalXZ(w.x, w.z)) } else { - if (setBaritoneGoal) BaritoneManager.setGoal(GoalXZ(w.x, w.z)) + if (setBaritoneGoal) BaritoneHandler.setGoal(GoalXZ(w.x, w.z)) } currentWaypoint = w } diff --git a/src/main/kotlin/com/lambda/module/modules/movement/AutoWalk.kt b/src/main/kotlin/com/lambda/module/modules/movement/AutoWalk.kt index 711644a73..d53903e96 100644 --- a/src/main/kotlin/com/lambda/module/modules/movement/AutoWalk.kt +++ b/src/main/kotlin/com/lambda/module/modules/movement/AutoWalk.kt @@ -18,22 +18,19 @@ package com.lambda.module.modules.movement import com.lambda.event.events.MovementEvent -import com.lambda.event.events.TickEvent import com.lambda.event.listener.SafeListener.Companion.listen import com.lambda.module.Module import com.lambda.module.tag.ModuleTag -import com.lambda.util.Timer import com.lambda.util.player.MovementUtils.forward import com.lambda.util.player.MovementUtils.strafe import com.lambda.util.player.MovementUtils.update import net.minecraft.util.math.Vec2f -import kotlin.time.DurationUnit -import kotlin.time.toDuration +@Suppress("unused") object AutoWalk : Module( name = "AutoWalk", description = "Automatically makes your character walk forward", - tag = ModuleTag.MOVEMENT, + tag = ModuleTag.Movement, ) { val limitSpeed by setting("Limit Speed", false) val speed by setting("Speed", 0.5, 0.1..1.0, 0.05) { limitSpeed } diff --git a/src/main/kotlin/com/lambda/module/modules/movement/BackTrack.kt b/src/main/kotlin/com/lambda/module/modules/movement/BackTrack.kt index 70b0e687a..81062956d 100644 --- a/src/main/kotlin/com/lambda/module/modules/movement/BackTrack.kt +++ b/src/main/kotlin/com/lambda/module/modules/movement/BackTrack.kt @@ -54,10 +54,11 @@ import net.minecraft.util.math.Vec3d import java.awt.Color import java.util.concurrent.ConcurrentLinkedDeque +@Suppress("unused") object BackTrack : Module( name = "BackTrack", description = "Gives reach advantage by delaying your packets", - tag = ModuleTag.MOVEMENT, + tag = ModuleTag.Movement, ) { private val outbound by setting("Outbound", true) private val mode by setting("Mode", Mode.Fixed) @@ -70,7 +71,7 @@ object BackTrack : Module( private val box = DynamicAABB() - private const val POSITION_PACKET_SCALE = 1 / 4096.0 + private const val PositionPacketScale = 1 / 4096.0 private val currentTime get() = System.currentTimeMillis() private val sendPool = ConcurrentLinkedDeque>() @@ -128,9 +129,9 @@ object BackTrack : Module( if (target.id == packet.id) { targetPos = targetPos?.plus( Vec3d( - packet.deltaX * POSITION_PACKET_SCALE, - packet.deltaY * POSITION_PACKET_SCALE, - packet.deltaZ * POSITION_PACKET_SCALE + packet.deltaX * PositionPacketScale, + packet.deltaY * PositionPacketScale, + packet.deltaZ * PositionPacketScale ) ) } diff --git a/src/main/kotlin/com/lambda/module/modules/movement/BetterFirework.kt b/src/main/kotlin/com/lambda/module/modules/movement/BetterFirework.kt index 5426400fa..17c8556df 100644 --- a/src/main/kotlin/com/lambda/module/modules/movement/BetterFirework.kt +++ b/src/main/kotlin/com/lambda/module/modules/movement/BetterFirework.kt @@ -19,10 +19,12 @@ package com.lambda.module.modules.movement import com.lambda.Lambda import com.lambda.Lambda.mc -import com.lambda.config.AutomationConfig.Companion.setDefaultAutomationConfig -import com.lambda.config.applyEdits +import com.lambda.config.SettingEditor.edit +import com.lambda.config.SettingEditor.hideAllBlocksExcept +import com.lambda.config.automation.AutomationConfig.Companion.setDefaultAutomationConfig import com.lambda.config.settings.complex.Bind import com.lambda.config.settings.complex.KeybindSetting.Companion.onPress +import com.lambda.config.withEdits import com.lambda.context.SafeContext import com.lambda.event.events.TickEvent import com.lambda.event.listener.SafeListener.Companion.listen @@ -32,7 +34,7 @@ import com.lambda.interaction.material.StackSelection.Companion.selectStack import com.lambda.module.Module import com.lambda.module.tag.ModuleTag import com.lambda.threading.runSafe -import com.lambda.util.Communication.warn +import com.lambda.util.CommunicationUtils.warn import com.lambda.util.KeyCode import com.lambda.util.Mouse import com.lambda.util.player.SlotUtils.hotbarAndInventoryStacks @@ -49,7 +51,8 @@ import net.minecraft.util.hit.HitResult object BetterFirework : Module( name = "BetterFirework", description = "Automatic takeoff with fireworks", - tag = ModuleTag.MOVEMENT, + tag = ModuleTag.Movement, + modulePriority = 1 ) { private var activateButton: Bind by setting("Activate Key", Bind(0, 0, Mouse.Middle.ordinal), "Button to activate Firework") .onPress { @@ -71,7 +74,8 @@ object BetterFirework : Module( if (player.canOpenElytra || player.isGliding) takeoffState = TakeoffState.StartFlying else if (player.canTakeoff) takeoffState = TakeoffState.Jumping } - private var midFlightActivationKey by setting("Mid-Flight Activation Key", Bind.EMPTY, "Firework use key for mid flight activation") + @Suppress("unused") + private var midFlightActivationKey by setting("Mid-Flight Activation Key", Bind.Empty, "Firework use key for mid flight activation") .onPress { if (player.isGliding) takeoffState = TakeoffState.StartFlying } private var middleClickCancel by setting("Middle Click Cancel", false, description = "Cancel pick block action on middle mouse click") { activateButton.key != KeyCode.Unbound.code } private var fireworkInteract by setting("Right Click Fly", true, "Automatically start flying when right clicking fireworks") @@ -97,14 +101,12 @@ object BetterFirework : Module( get() = !abilities.flying && !isClimbing && !isGliding && !isTouchingWater && !isOnGround && !hasVehicle() && !hasStatusEffect(StatusEffects.LEVITATION) init { - setModulePriority(1) - setDefaultAutomationConfig { - applyEdits { - hideAllGroupsExcept(hotbarConfig, inventoryConfig) + setDefaultAutomationConfig() + .withEdits { + hideAllBlocksExcept(::hotbarConfig, ::inventoryConfig) hotbarConfig::tickStageMask.edit { defaultValue(mutableSetOf(TickEvent.Pre)) } inventoryConfig::tickStageMask.edit { defaultValue(mutableSetOf(TickEvent.Pre)) } } - } listen { when (takeoffState) { diff --git a/src/main/kotlin/com/lambda/module/modules/movement/Blink.kt b/src/main/kotlin/com/lambda/module/modules/movement/Blink.kt index 444006b51..b27dc107e 100644 --- a/src/main/kotlin/com/lambda/module/modules/movement/Blink.kt +++ b/src/main/kotlin/com/lambda/module/modules/movement/Blink.kt @@ -45,7 +45,7 @@ import java.util.concurrent.ConcurrentLinkedDeque object Blink : Module( name = "Blink", description = "Holds packets", - tag = ModuleTag.MOVEMENT, + tag = ModuleTag.Movement, ) { private var delay by setting("Delay", 500, 50..10000, 10) private val shiftVelocity by setting("Shift velocity", true) diff --git a/src/main/kotlin/com/lambda/module/modules/movement/ElytraAltitudeControl.kt b/src/main/kotlin/com/lambda/module/modules/movement/ElytraAltitudeControl.kt index 5852c0515..19e5317b9 100644 --- a/src/main/kotlin/com/lambda/module/modules/movement/ElytraAltitudeControl.kt +++ b/src/main/kotlin/com/lambda/module/modules/movement/ElytraAltitudeControl.kt @@ -17,8 +17,10 @@ package com.lambda.module.modules.movement -import com.lambda.config.AutomationConfig.Companion.setDefaultAutomationConfig -import com.lambda.config.applyEdits +import com.lambda.config.SettingEditor.hideAllBlocksExcept +import com.lambda.config.Tab +import com.lambda.config.automation.AutomationConfig.Companion.setDefaultAutomationConfig +import com.lambda.config.withEdits import com.lambda.event.events.TickEvent import com.lambda.event.listener.SafeListener.Companion.listen import com.lambda.interaction.managers.rotating.IRotationRequest.Companion.rotationRequest @@ -26,8 +28,7 @@ import com.lambda.module.Module import com.lambda.module.modules.movement.BetterFirework.startFirework import com.lambda.module.tag.ModuleTag import com.lambda.threading.runSafe -import com.lambda.util.Communication.info -import com.lambda.util.NamedEnum +import com.lambda.util.CommunicationUtils.info import com.lambda.util.SpeedUnit import com.lambda.util.Timer import com.lambda.util.player.hasFirework @@ -37,48 +38,60 @@ import net.minecraft.util.math.Vec3d import kotlin.time.Duration.Companion.seconds import kotlin.time.TimeSource +@Suppress("unused") object ElytraAltitudeControl : Module( - name = "ElytraAttitudeControl", + name = "ElytraAltitudeControl", description = "Automatically control attitude or speed while elytra flying", - tag = ModuleTag.MOVEMENT, + tag = ModuleTag.Movement, ) { - val controlValue by setting("Control Value", Mode.Altitude) - - val maxPitchAngle by setting("Max Pitch Angle", 45.0, 0.0..90.0, 1.0, unit = "°", description = "Maximum pitch angle") - val disableOnFirework by setting("Disable On Firework", false, description = "Disables the module when a firework is used") + enum class Mode { + Speed, + Altitude + } + val controlValue by setting("Control Value", Mode.Altitude) val targetAltitude by setting("Target Altitude", 120, 0..256, 10, unit = " blocks", description = "Adjusts pitch to control altitude") { controlValue == Mode.Altitude } - val altitudeControllerP by setting("Altitude Control P", 1.2, 0.0..2.0, 0.05).group(Group.AltitudeControl) - val altitudeControllerD by setting("Altitude Control D", 0.85, 0.0..1.0, 0.05).group(Group.AltitudeControl) - val altitudeControllerI by setting("Altitude Control I", 0.04, 0.0..1.0, 0.05).group(Group.AltitudeControl) - val altitudeControllerConst by setting("Altitude Control Const", 0.0, 0.0..10.0, 0.1).group(Group.AltitudeControl) - val targetSpeed by setting("Target Speed", 20.0, 0.1..50.0, 0.1, unit = " m/s", description = "Adjusts pitch to control speed") { controlValue == Mode.Speed } + val horizontalSpeed by setting("Horizontal Speed", false, description = "Uses horizontal speed instead of total speed for speed control") { controlValue == Mode.Speed } - val speedControllerP by setting("Speed Control P", 6.75, 0.0..10.0, 0.05).group(Group.SpeedControl) - val speedControllerD by setting("Speed Control D", 4.5, 0.0..5.0, 0.05).group(Group.SpeedControl) - val speedControllerI by setting("Speed Control I", 0.3, 0.0..1.0, 0.05).group(Group.SpeedControl) + + val maxPitchAngle by setting("Max Pitch Angle", 45.0, 0.0..90.0, 1.0, unit = "°", description = "Maximum pitch angle") + val disableOnFirework by setting("Disable On Firework", false, description = "Disables the module when a firework is used") val useFireworkOnHeight by setting("Use Firework On Height", false, "Use fireworks when below a certain height") - val minHeight by setting("Min Height", 50, 0..256, 10, unit = " blocks", description = "Minimum height to use firework") { useFireworkOnHeight } + val minHeight by setting("Min Height", 150, 0..256, 10, unit = " blocks", description = "Minimum height to use firework") { useFireworkOnHeight } val useFireworkOnSpeed by setting("Use Firework On Speed", false, "Use fireworks based on speed") val minSpeed by setting("Min Speed", 20.0, 0.1..50.0, 0.1, unit = " m/s", description = "Minimum speed to use fireworks") { useFireworkOnSpeed } + val usePitch40OnHeight by setting("Use Pitch 40 On Height", false, "Use Pitch 40 to gain height and speed") + + private const val AltitudeControlGroup = "Altitude Control" + private const val SpeedControlGroup = "Speed Control" + private const val Pitch40ControlGroup = "Pitch 40 Control" + + @Tab(AltitudeControlGroup) val altitudeControllerP by setting("PID P", 1.2, 0.0..2.0, 0.05) + @Tab(AltitudeControlGroup) val altitudeControllerD by setting("PID D", 0.85, 0.0..1.0, 0.05) + @Tab(AltitudeControlGroup) val altitudeControllerI by setting("PID I", 0.04, 0.0..1.0, 0.05) + @Tab(AltitudeControlGroup) val altitudeControllerConst by setting("PID const", 0.0, 0.0..10.0, 0.1) + + @Tab(SpeedControlGroup) val speedControllerP by setting("PID P", 6.75, 0.0..10.0, 0.05) + @Tab(SpeedControlGroup) val speedControllerD by setting("PID D", 4.5, 0.0..5.0, 0.05) + @Tab(SpeedControlGroup) val speedControllerI by setting("PID I", 0.3, 0.0..1.0, 0.05) + + @Tab(Pitch40ControlGroup) val logHeightGain by setting("Log Height Gain", false, "Logs the height gained each cycle to the chat") { usePitch40OnHeight } + @Tab(Pitch40ControlGroup) val minHeightForPitch40 by setting("Min Height For Pitch 40", 120, 0..256, 10, unit = " blocks", description = "Minimum height to use Pitch 40") { usePitch40OnHeight } + @Tab(Pitch40ControlGroup) val pitch40ExitHeight by setting("Exit height", 190, 0..256, 10, unit = " blocks", description = "Height to exit Pitch 40 mode") { usePitch40OnHeight } + @Tab(Pitch40ControlGroup) val pitch40UpStartAngle by setting("Up Start Angle", -49f, -90f..0f, .5f, description = "Start angle when going back up. negative pitch = looking up") { usePitch40OnHeight } + @Tab(Pitch40ControlGroup) val pitch40DownAngle by setting("Down Angle", 33f, 0f..90f, .5f, description = "Angle to dive down at to gain speed") { usePitch40OnHeight } + @Tab(Pitch40ControlGroup) val pitch40AngleChangeRate by setting("Angle Change Rate", 0.5f, 0.1f..5f, 0.01f, description = "Rate at which to increase pitch while in the fly up curve") { usePitch40OnHeight } + @Tab(Pitch40ControlGroup) val pitch40SpeedThreshold by setting("Speed Threshold", 41f, 10f..100f, .5f, description = "Speed at which to start pitching up") { usePitch40OnHeight } + @Tab(Pitch40ControlGroup) val pitch40UseFireworkOnUpTrajectory by setting("Use Firework On Up Trajectory", false, "Use fireworks when converting speed to altitude in the Pitch 40 maneuver") { usePitch40OnHeight } + var lastPos: Vec3d = Vec3d.ZERO val speedController: PIController = PIController({ speedControllerP }, { speedControllerD }, { speedControllerI }, { 0.0 }) val altitudeController: PIController = PIController({ altitudeControllerP }, { altitudeControllerD }, { altitudeControllerI }, { altitudeControllerConst }) - val usePitch40OnHeight by setting("Use Pitch 40 On Height", false, "Use Pitch 40 to gain height and speed") - val logHeightGain by setting("Log Height Gain", false, "Logs the height gained each cycle to the chat") { usePitch40OnHeight }.group(Group.Pitch40Control) - val minHeightForPitch40 by setting("Min Height For Pitch 40", 120, 0..256, 10, unit = " blocks", description = "Minimum height to use Pitch 40") { usePitch40OnHeight }.group(Group.Pitch40Control) - val pitch40ExitHeight by setting("Exit height", 190, 0..256, 10, unit = " blocks", description = "Height to exit Pitch 40 mode") { usePitch40OnHeight }.group(Group.Pitch40Control) - val pitch40UpStartAngle by setting("Up Start Angle", -49f, -90f..0f, .5f, description = "Start angle when going back up. negative pitch = looking up") { usePitch40OnHeight }.group(Group.Pitch40Control) - val pitch40DownAngle by setting("Down Angle", 33f, 0f..90f, .5f, description = "Angle to dive down at to gain speed") { usePitch40OnHeight }.group(Group.Pitch40Control) - val pitch40AngleChangeRate by setting("Angle Change Rate", 0.5f, 0.1f..5f, 0.01f, description = "Rate at which to increase pitch while in the fly up curve") { usePitch40OnHeight }.group(Group.Pitch40Control) - val pitch40SpeedThreshold by setting("Speed Threshold", 41f, 10f..100f, .5f, description = "Speed at which to start pitching up") { usePitch40OnHeight }.group(Group.Pitch40Control) - val pitch40UseFireworkOnUpTrajectory by setting("Use Firework On Up Trajectory", false, "Use fireworks when converting speed to altitude in the Pitch 40 maneuver") { usePitch40OnHeight }.group(Group.Pitch40Control) - var controlState = ControlState.AttitudeControl var state = Pitch40State.GainSpeed var lastAngle = pitch40UpStartAngle @@ -88,11 +101,10 @@ object ElytraAltitudeControl : Module( val usageDelay = Timer() init { - setDefaultAutomationConfig { - applyEdits { - hideAllGroupsExcept(rotationConfig) + setDefaultAutomationConfig() + .withEdits { + hideAllBlocksExcept(::rotationConfig) } - } listen { if (!player.isGliding) return@listen @@ -220,23 +232,11 @@ object ElytraAltitudeControl : Module( return SpeedUnit.MetersPerSecond.convertFromMinecraft(delta.length()).toFloat() } - enum class Mode { - Speed, - Altitude; - } - enum class ControlState { AttitudeControl, Pitch40Fly } - enum class Group(override val displayName: String) : NamedEnum { - SpeedControl("Speed Control"), - AltitudeControl("Altitude Control"), - Pitch40Control("Pitch 40 Control"), - Rotation("Rotation") - } - enum class Pitch40State { GainSpeed, PitchUp, diff --git a/src/main/kotlin/com/lambda/module/modules/movement/ElytraFly.kt b/src/main/kotlin/com/lambda/module/modules/movement/ElytraFly.kt index 9644f7ff5..d1906f882 100644 --- a/src/main/kotlin/com/lambda/module/modules/movement/ElytraFly.kt +++ b/src/main/kotlin/com/lambda/module/modules/movement/ElytraFly.kt @@ -18,36 +18,38 @@ package com.lambda.module.modules.movement import baritone.api.pathing.goals.GoalGetToBlock -import com.lambda.config.AutomationConfig.Companion.setDefaultAutomationConfig -import com.lambda.config.applyEdits +import com.lambda.config.SettingEditor.hideAllBlocksExcept +import com.lambda.config.Group +import com.lambda.config.automation.AutomationConfig.Companion.setDefaultAutomationConfig +import com.lambda.config.withEdits import com.lambda.context.SafeContext import com.lambda.event.events.ClientEvent import com.lambda.event.events.MovementEvent import com.lambda.event.events.PacketEvent import com.lambda.event.events.TickEvent import com.lambda.event.listener.SafeListener.Companion.listen -import com.lambda.interaction.BaritoneManager +import com.lambda.interaction.BaritoneHandler import com.lambda.interaction.managers.rotating.IRotationRequest.Companion.rotationRequest import com.lambda.interaction.managers.rotating.RotationManager import com.lambda.interaction.material.StackSelection.Companion.select import com.lambda.module.Module +import com.lambda.module.hud.Speedometer import com.lambda.module.modules.movement.BetterFirework.canOpenElytra import com.lambda.module.modules.movement.BetterFirework.canTakeoff import com.lambda.module.modules.movement.BetterFirework.startFirework import com.lambda.module.tag.ModuleTag import com.lambda.threading.runSafe -import com.lambda.util.Timer -import com.lambda.util.extension.isElytraFlying -import com.lambda.util.player.MovementUtils.addSpeed -import com.lambda.util.player.SlotUtils.hotbarStacks -import com.lambda.util.player.hasFirework -import com.lambda.module.hud.Speedometer import com.lambda.util.BlockUtils.blockState import com.lambda.util.SpeedUnit +import com.lambda.util.Timer +import com.lambda.util.extension.isElytraFlying import com.lambda.util.math.dist import com.lambda.util.math.flooredBlockPos import com.lambda.util.math.isLoaded +import com.lambda.util.player.MovementUtils.addSpeed +import com.lambda.util.player.SlotUtils.hotbarStacks import com.lambda.util.player.SlotUtils.inventoryStacks +import com.lambda.util.player.hasFirework import com.lambda.util.world.raycast.InteractionMask import com.lambda.util.world.raycast.RayCastUtils.blockResult import com.lambda.util.world.raycast.RayCastUtils.rayCast @@ -72,30 +74,33 @@ import kotlin.time.Duration.Companion.seconds object ElytraFly : Module( name = "ElytraFly", description = "Allows you to fly with an elytra", - tag = ModuleTag.MOVEMENT, + tag = ModuleTag.Movement, ) { @JvmStatic val mode by setting("Mode", FlyMode.Bounce) private val inventory by setting("Inventory", true, "Allow using fireworks from the players inventory") { mode == FlyMode.GrimControl } - //ToDo: Implement these commented out settings private val takeoff by setting("Takeoff", true, "Automatically jumps and initiates gliding") { mode == FlyMode.Bounce } private val autoPitch by setting("Auto Pitch", true, "Automatically pitches the players rotation down to bounce at faster speeds") { mode == FlyMode.Bounce } private val pitch by setting("Pitch", 80.0, 0.0..90.0, 0.000001) { mode == FlyMode.Bounce && autoPitch } - private val yMotionSetting by setting("Y Motion", false, "Cancels the players y velocity to aid speed") { mode == FlyMode.Bounce } - private val yMotion - get() = yMotionSetting && (!onlyOnDiagonal || abs(RotationManager.activeRotation.yaw % 90) > minDiagonalAngle) - private val onlyOnDiagonal: Boolean by setting("Only On Diagonal", true, "Only use y motion when the player is flying on a non-axial angle") { mode == FlyMode.Bounce && yMotionSetting } - private val minDiagonalAngle by setting("Min Diagonal Angle", 15.0, 0.0..180.0, 0.1, "The minimum angle the player must be flying to use y motion") { mode == FlyMode.Bounce && yMotionSetting && onlyOnDiagonal } - private val yMotionStartSpeed by setting("Y Motion Start Speed", 30, 5..40, 1, "bps") { mode == FlyMode.Bounce && yMotionSetting } - private val speedLimit by setting("Speed Limit", 110, 10..400, 1, "bps") { mode == FlyMode.Bounce && yMotionSetting } - private val jump by setting("Jump", true, "Automatically jumps") { mode == FlyMode.Bounce } + private val jump by setting("Jump", true, "Automatically jumps") { mode == FlyMode.Bounce } private val flagPause by setting("Flag Pause", 5, 0..100, 1, "How long to pause if the server flags you for a movement check", "ticks") { mode == FlyMode.Bounce } - private val passObstacles by setting("Pass Obstacles", true, "Automatically paths around obstacles using baritone") { mode == FlyMode.Bounce } - private val applyPauseAfterBaritone by setting("Apply Pause After Baritone", false, "Ticks the flag pause after baritone has finished pathing") { mode == FlyMode.Bounce && passObstacles } - private val acceptableOffsetRange by setting("Acceptable Offset Range", 2.0, 0.1..5.0, 0.01, "Acceptable offset from the original flight line to allow when starting to fly again after passing obstacles") { mode == FlyMode.Bounce && passObstacles } - private val obstacleLookAhead by setting("Obstacle Look-Ahead", 15, 0..50, 1, "Looks ahead of the player to see if obstacles are in the way") { mode == FlyMode.Bounce && passObstacles } - private val directionStep by setting("Direction Step", 45.0, 0.0..180.0, 0.1, "The step size to use when locking the flight direction") { mode == FlyMode.Bounce && passObstacles } + + private const val YMotionGroup = "Y Motion" + @Group(YMotionGroup) private val yMotionSetting by setting("Y Motion", false, "Cancels the players y velocity to aid speed") { mode == FlyMode.Bounce } + private val yMotion + get() = yMotionSetting && (!onlyOnDiagonal || abs(RotationManager.activeRotation.yaw % 90) > minDiagonalAngle) + @Group(YMotionGroup) private val onlyOnDiagonal: Boolean by setting("Only On Diagonal", true, "Only use y motion when the player is flying on a non-axial angle") { mode == FlyMode.Bounce && yMotionSetting } + @Group(YMotionGroup) private val minDiagonalAngle by setting("Min Diagonal Angle", 15.0, 0.0..180.0, 0.1, "The minimum angle the player must be flying to use y motion") { mode == FlyMode.Bounce && yMotionSetting && onlyOnDiagonal } + @Group(YMotionGroup) private val yMotionStartSpeed by setting("Y Motion Start Speed", 30, 5..40, 1, "bps") { mode == FlyMode.Bounce && yMotion } + @Group(YMotionGroup) private val speedLimit by setting("Speed Limit", 110, 10..400, 1, "bps") { mode == FlyMode.Bounce && yMotion } + + private const val ObstaclePasserGroup = "Obstacle Passer" + @Group(ObstaclePasserGroup) private val passObstacles by setting("Pass Obstacles", true, "Automatically paths around obstacles using baritone") { mode == FlyMode.Bounce } + @Group(ObstaclePasserGroup) private val applyPauseAfterBaritone by setting("Apply Pause After Baritone", false, "Ticks the flag pause after baritone has finished pathing") { mode == FlyMode.Bounce && passObstacles } + @Group(ObstaclePasserGroup) private val acceptableOffsetRange by setting("Acceptable Offset Range", 2.0, 0.1..5.0, 0.01, "Acceptable offset from the original flight line to allow when starting to fly again after passing obstacles") { mode == FlyMode.Bounce && passObstacles } + @Group(ObstaclePasserGroup) private val obstacleLookAhead by setting("Obstacle Look-Ahead", 15, 0..50, 1, "Looks ahead of the player to see if obstacles are in the way") { mode == FlyMode.Bounce && passObstacles } + @Group(ObstaclePasserGroup) private val directionStep by setting("Direction Step", 45.0, 0.0..180.0, 0.1, "The step size to use when locking the flight direction") { mode == FlyMode.Bounce && passObstacles } private val boostSpeed by setting("Boost", 0.00, 0.0..0.5, 0.005, description = "Speed to add when flying") private val rocketSpeed by setting("Rocket Speed", 0.0, 0.0..2.0, description = "Speed multiplier that the rocket gives you") { mode == FlyMode.Enhanced } @@ -113,11 +118,10 @@ object ElytraFly : Module( private val fireworkTimer = Timer() init { - setDefaultAutomationConfig { - applyEdits { - hideAllGroupsExcept(inventoryConfig, rotationConfig) + setDefaultAutomationConfig() + .withEdits { + hideAllBlocksExcept(::inventoryConfig, ::rotationConfig) } - } listen { when (mode) { @@ -137,7 +141,7 @@ object ElytraFly : Module( onDisable { passingToPos = null - if (passObstacles) BaritoneManager.cancel() + if (passObstacles) BaritoneHandler.cancel() } listen { event -> @@ -207,7 +211,7 @@ object ElytraFly : Module( } private fun SafeContext.onTickBounce() { - if (!BaritoneManager.isActive) passingToPos = null + if (!BaritoneHandler.isActive) passingToPos = null val playerPos = player.pos if (passObstacles && playerPos.let { Vec3d(it.x, startPos.y, it.z) } dist startPos > 0.1) run obstacleChecks@{ @@ -271,7 +275,7 @@ object ElytraFly : Module( private fun passTo(pos: Vec3d) { passingToPos = pos - BaritoneManager.setGoalAndPath(GoalGetToBlock(pos.flooredBlockPos)) + BaritoneHandler.setGoalAndPath(GoalGetToBlock(pos.flooredBlockPos)) } context(safeContext: SafeContext) @@ -346,7 +350,7 @@ object ElytraFly : Module( mode == FlyMode.Bounce && previouslyFlying == true && glidePause <= 0 && - !BaritoneManager.isActive) true + !BaritoneHandler.isActive) true else { previouslyFlying = original original diff --git a/src/main/kotlin/com/lambda/module/modules/movement/EntityControl.kt b/src/main/kotlin/com/lambda/module/modules/movement/EntityControl.kt index a19a6ce11..7aa989730 100644 --- a/src/main/kotlin/com/lambda/module/modules/movement/EntityControl.kt +++ b/src/main/kotlin/com/lambda/module/modules/movement/EntityControl.kt @@ -26,10 +26,11 @@ import com.lambda.util.world.fastEntitySearch import net.minecraft.entity.passive.AbstractHorseEntity import net.minecraft.network.packet.c2s.play.PlayerInteractEntityC2SPacket +@Suppress("unused") object EntityControl : Module( name = "EntityControl", description = "Control mountable entities", - tag = ModuleTag.MOVEMENT, + tag = ModuleTag.Movement, ) { private val forceMount by setting("Force Mount", true, description = "Attempts to force mount chested entities.") diff --git a/src/main/kotlin/com/lambda/module/modules/movement/Jesus.kt b/src/main/kotlin/com/lambda/module/modules/movement/Jesus.kt index 990b85acb..b31eadcec 100644 --- a/src/main/kotlin/com/lambda/module/modules/movement/Jesus.kt +++ b/src/main/kotlin/com/lambda/module/modules/movement/Jesus.kt @@ -38,10 +38,11 @@ import net.minecraft.util.math.BlockPos import net.minecraft.util.math.Vec3d import net.minecraft.util.shape.VoxelShapes +@Suppress("unused") object Jesus : Module( name = "Jesus", description = "Allows to walk on water", - tag = ModuleTag.MOVEMENT, + tag = ModuleTag.Movement, ) { private val mode by setting("Mode", Mode.Ncp) @@ -90,7 +91,7 @@ object Jesus : Module( when (mode) { Mode.Ncp -> { if (!collidingWater || !player.isOnGround) return@listen - setSpeed(Speed.NCP_BASE_SPEED * isInputting.toInt()) + setSpeed(Speed.NcpBaseSpeed * isInputting.toInt()) } Mode.NcpDolphin -> { @@ -98,7 +99,7 @@ object Jesus : Module( player.motionY = dolphinStrength if (!waterAt(0.2)) { - setSpeed(Speed.NCP_BASE_SPEED * isInputting.toInt()) + setSpeed(Speed.NcpBaseSpeed * isInputting.toInt()) } else player.motionY = 0.18 } } @@ -111,7 +112,7 @@ object Jesus : Module( if (++swimmingTicks < 15) { if (player.isOnGround) { - setSpeed(Speed.NCP_BASE_SPEED * isInputting.toInt()) + setSpeed(Speed.NcpBaseSpeed * isInputting.toInt()) } return@listen diff --git a/src/main/kotlin/com/lambda/module/modules/movement/NoFall.kt b/src/main/kotlin/com/lambda/module/modules/movement/NoFall.kt index 9b19afc11..60012efe9 100644 --- a/src/main/kotlin/com/lambda/module/modules/movement/NoFall.kt +++ b/src/main/kotlin/com/lambda/module/modules/movement/NoFall.kt @@ -21,6 +21,7 @@ import com.lambda.event.events.MovementEvent import com.lambda.event.listener.SafeListener.Companion.listen import com.lambda.module.Module import com.lambda.module.tag.ModuleTag +import com.lambda.util.PacketUtils.sendPacket import com.lambda.util.math.component1 import com.lambda.util.math.component2 import com.lambda.util.math.component3 @@ -34,10 +35,11 @@ import net.minecraft.util.math.BlockPos import net.minecraft.util.math.Direction import net.minecraft.util.math.Vec3d +@Suppress("unused") object NoFall : Module( name = "NoFall", description = "Reduces fall damage", - tag = ModuleTag.MOVEMENT, + tag = ModuleTag.Movement, ) { private val mode by setting("Mode", Mode.Grim) @@ -54,13 +56,13 @@ object NoFall : Module( val (x, y, z) = player.pos connection.sendPacket(PlayerMoveC2SPacket.Full(x, y + 0.0000000001, z, 0.01f, 90f, false, true)) // TODO: Check this after update connection.sendPacket(PlayerInteractItemC2SPacket(Hand.OFF_HAND, 0, player.yaw, player.pitch)) // TODO: This is wrong, fix it - connection.sendPacket( + connection.sendPacket { PlayerActionC2SPacket( PlayerActionC2SPacket.Action.RELEASE_USE_ITEM, BlockPos.ORIGIN, Direction.DOWN ) - ) + } player.motion = Vec3d.ZERO player.fallDistance = 0.0 diff --git a/src/main/kotlin/com/lambda/module/modules/movement/NoJumpCooldown.kt b/src/main/kotlin/com/lambda/module/modules/movement/NoJumpCooldown.kt index 1746e1e95..58ac5f01a 100644 --- a/src/main/kotlin/com/lambda/module/modules/movement/NoJumpCooldown.kt +++ b/src/main/kotlin/com/lambda/module/modules/movement/NoJumpCooldown.kt @@ -23,5 +23,5 @@ import com.lambda.module.tag.ModuleTag object NoJumpCooldown : Module( name = "NoJumpCooldown", description = "Removes delay between jumps", - tag = ModuleTag.MOVEMENT + tag = ModuleTag.Movement ) \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/module/modules/movement/SafeWalk.kt b/src/main/kotlin/com/lambda/module/modules/movement/SafeWalk.kt index 23e7ae108..e8a2ef8dd 100644 --- a/src/main/kotlin/com/lambda/module/modules/movement/SafeWalk.kt +++ b/src/main/kotlin/com/lambda/module/modules/movement/SafeWalk.kt @@ -29,7 +29,7 @@ import net.minecraft.entity.LivingEntity object SafeWalk : Module( name = "SafeWalk", description = "Keeps you at the edge", - tag = ModuleTag.MOVEMENT, + tag = ModuleTag.Movement, ) { private val sneakOnLedge by setting("Sneak On Ledge", true) private val ledgeDistance by setting("Ledge Distance", 0.2, 0.0..0.5, 0.01, unit = " blocks") diff --git a/src/main/kotlin/com/lambda/module/modules/movement/Speed.kt b/src/main/kotlin/com/lambda/module/modules/movement/Speed.kt index 9c220061f..6edc7ddd9 100644 --- a/src/main/kotlin/com/lambda/module/modules/movement/Speed.kt +++ b/src/main/kotlin/com/lambda/module/modules/movement/Speed.kt @@ -17,16 +17,15 @@ package com.lambda.module.modules.movement +import com.lambda.config.SettingEditor.hideAllBlocksExcept +import com.lambda.config.automation.AutomationConfig.Companion.setDefaultAutomationConfig +import com.lambda.config.withEdits import com.lambda.context.SafeContext import com.lambda.event.events.ClientEvent import com.lambda.event.events.MovementEvent import com.lambda.event.events.TickEvent import com.lambda.event.listener.SafeListener.Companion.listen import com.lambda.interaction.managers.rotating.IRotationRequest.Companion.rotationRequest -import com.lambda.interaction.managers.rotating.Rotation -import com.lambda.interaction.managers.rotating.RotationConfig -import com.lambda.interaction.managers.rotating.RotationMode -import com.lambda.interaction.managers.rotating.RotationRequest import com.lambda.module.Module import com.lambda.module.tag.ModuleTag import com.lambda.util.NamedEnum @@ -48,28 +47,27 @@ import net.minecraft.entity.vehicle.BoatEntity object Speed : Module( name = "Speed", description = "Accelerates your walking speed", - tag = ModuleTag.MOVEMENT, + tag = ModuleTag.Movement, ) { @JvmStatic - val mode by setting("Mode", Mode.GrimStrafe).onValueChange { _, _ -> reset() } + val mode by setting("Mode", Mode.GrimStrafe) + .onValueChange { _, _ -> resetNcp() } // Grim - private val diagonal by setting("Diagonal", true).group(Mode.GrimStrafe) - private val grimBoatBoost by setting("Boat Boost", 0.4, 0.0..1.7, 0.01).group(Mode.GrimStrafe) + private val diagonal by setting("Diagonal", true) { mode == Mode.GrimStrafe } + private val grimBoatBoost by setting("Boat Boost", 0.4, 0.0..1.7, 0.01) { mode == Mode.GrimStrafe } // NCP - private val strict by setting("Strict", true).group(Mode.NcpStrafe) - private val lowerJump by setting("Lower Jump", true).group(Mode.NcpStrafe) - private val ncpAutoJump by setting("Auto Jump", false).group(Mode.NcpStrafe) - private val ncpTimerBoost by setting("Timer Boost", 1.08, 1.0..1.1, 0.01).group(Mode.NcpStrafe) - - override val rotationConfig = RotationConfig.Instant(RotationMode.Sync) + private val strict by setting("Strict", true) { mode == Mode.NcpStrafe } + private val lowerJump by setting("Lower Jump", true) { mode == Mode.NcpStrafe } + private val ncpAutoJump by setting("Auto Jump", false) { mode == Mode.NcpStrafe } + private val ncpTimerBoost by setting("Timer Boost", 1.08, 1.0..1.1, 0.01) { mode == Mode.NcpStrafe } // NCP state variables - const val NCP_BASE_SPEED = 0.2873 - private const val NCP_AIR_DECAY = 0.9937 + const val NcpBaseSpeed = 0.2873 + private const val NcpAirDecay = 0.9937 private var ncpPhase = NCPPhase.SlowDown - private var ncpSpeed = NCP_BASE_SPEED + private var ncpSpeed = NcpBaseSpeed private var lastDistance = 0.0 enum class Mode(override val displayName: String) : NamedEnum { @@ -84,9 +82,14 @@ object Speed : Module( } init { + setDefaultAutomationConfig() + .withEdits { + hideAllBlocksExcept(::rotationConfig) + } + listen { if (!shouldWork()) { - reset() + resetNcp() return@listen } @@ -125,7 +128,7 @@ object Speed : Module( } onEnable { - reset() + resetNcp() } } @@ -154,7 +157,7 @@ object Speed : Module( NCPPhase.Jump -> { if (player.isOnGround) { player.motionY = if (lowerJump) 0.4 else 0.42 - ncpSpeed = NCP_BASE_SPEED + 0.3 + ncpSpeed = NcpBaseSpeed + 0.3 NCPPhase.JumpPost } else NCPPhase.SlowDown } @@ -165,19 +168,19 @@ object Speed : Module( } NCPPhase.SlowDown -> { - ncpSpeed = lastDistance * NCP_AIR_DECAY + ncpSpeed = lastDistance * NcpAirDecay NCPPhase.SlowDown } } if (player.isOnGround && !shouldJump) { - ncpSpeed = NCP_BASE_SPEED + ncpSpeed = NcpBaseSpeed } - ncpSpeed = ncpSpeed.coerceIn(NCP_BASE_SPEED..1.0) + ncpSpeed = ncpSpeed.coerceIn(NcpBaseSpeed..1.0) val moveSpeed = if (isInputting) ncpSpeed else { - ncpSpeed = NCP_BASE_SPEED + ncpSpeed = NcpBaseSpeed 0.0 } @@ -197,8 +200,8 @@ object Speed : Module( } } - private fun reset() { + private fun resetNcp() { ncpPhase = NCPPhase.SlowDown - ncpSpeed = NCP_BASE_SPEED + ncpSpeed = NcpBaseSpeed } } diff --git a/src/main/kotlin/com/lambda/module/modules/movement/Sprint.kt b/src/main/kotlin/com/lambda/module/modules/movement/Sprint.kt index d31ac27cc..24a54935e 100644 --- a/src/main/kotlin/com/lambda/module/modules/movement/Sprint.kt +++ b/src/main/kotlin/com/lambda/module/modules/movement/Sprint.kt @@ -23,5 +23,5 @@ import com.lambda.module.tag.ModuleTag object Sprint : Module( name = "Sprint", description = "Sprints automatically", - tag = ModuleTag.MOVEMENT, + tag = ModuleTag.Movement, ) diff --git a/src/main/kotlin/com/lambda/module/modules/movement/TargetStrafe.kt b/src/main/kotlin/com/lambda/module/modules/movement/TargetStrafe.kt index 019df5b8c..395d9000a 100644 --- a/src/main/kotlin/com/lambda/module/modules/movement/TargetStrafe.kt +++ b/src/main/kotlin/com/lambda/module/modules/movement/TargetStrafe.kt @@ -31,14 +31,17 @@ import kotlin.math.pow object TargetStrafe : Module( name = "TargetStrafe", description = "Automatically strafes around entities", - tag = ModuleTag.MOVEMENT, + tag = ModuleTag.Movement, ) { private val targetDistance by setting("Strafe Distance", 1.0, 0.0..5.0, 0.1) private val jitterCompensation by setting("Jitter Compensation", 0.0, 0.0..1.0, 0.1) private val stabilize by setting("Stabilize", StabilizationMode.Normal) enum class StabilizationMode { - None, Weak, Normal, Strong + None, + Weak, + Normal, + Strong } private var forwardDirection = 1.0 diff --git a/src/main/kotlin/com/lambda/module/modules/movement/TickShift.kt b/src/main/kotlin/com/lambda/module/modules/movement/TickShift.kt index 7b888e52a..4c84ce175 100644 --- a/src/main/kotlin/com/lambda/module/modules/movement/TickShift.kt +++ b/src/main/kotlin/com/lambda/module/modules/movement/TickShift.kt @@ -26,7 +26,7 @@ import com.lambda.module.Module import com.lambda.module.modules.combat.KillAura import com.lambda.module.tag.ModuleTag import com.lambda.threading.runConcurrent -import com.lambda.util.Communication.info +import com.lambda.util.CommunicationUtils.info import com.lambda.util.PacketUtils.handlePacketSilently import com.lambda.util.PacketUtils.sendPacketSilently import kotlinx.coroutines.delay @@ -37,7 +37,7 @@ import net.minecraft.network.packet.s2c.play.EntityVelocityUpdateS2CPacket object TickShift : Module( name = "TickShift", description = "Smort tickshift for smort anticheats", - tag = ModuleTag.MOVEMENT, + tag = ModuleTag.Movement, ) { val maxBalance by setting("Max Balance", 20, 3..400, 1) private val boostAmount by setting("Boost", 3.0, 1.1..20.0, 0.01) diff --git a/src/main/kotlin/com/lambda/module/modules/movement/Timer.kt b/src/main/kotlin/com/lambda/module/modules/movement/Timer.kt index 3e89bd6ee..a17f24046 100644 --- a/src/main/kotlin/com/lambda/module/modules/movement/Timer.kt +++ b/src/main/kotlin/com/lambda/module/modules/movement/Timer.kt @@ -22,10 +22,11 @@ import com.lambda.event.listener.SafeListener.Companion.listen import com.lambda.module.Module import com.lambda.module.tag.ModuleTag +@Suppress("unused") object Timer : Module( name = "Timer", description = "Modify client tick speed.", - tag = ModuleTag.MOVEMENT, + tag = ModuleTag.Movement, ) { private val timer by setting("Timer", 1.0, 0.0..10.0, 0.01) diff --git a/src/main/kotlin/com/lambda/module/modules/movement/Velocity.kt b/src/main/kotlin/com/lambda/module/modules/movement/Velocity.kt index cd2470c54..71a149aa0 100644 --- a/src/main/kotlin/com/lambda/module/modules/movement/Velocity.kt +++ b/src/main/kotlin/com/lambda/module/modules/movement/Velocity.kt @@ -26,7 +26,7 @@ import net.minecraft.network.packet.s2c.play.EntityVelocityUpdateS2CPacket object Velocity : Module( name = "Velocity", description = "Modifies your velocity", - tag = ModuleTag.MOVEMENT, + tag = ModuleTag.Movement, ) { @JvmStatic val pushed by setting("Pushed", true, "Prevents the player from getting pushed by other entities") private val knockback by setting("Knockback", true, "Prevents the player from taking knockback when being attacked") diff --git a/src/main/kotlin/com/lambda/module/modules/network/PacketDelay.kt b/src/main/kotlin/com/lambda/module/modules/network/PacketDelay.kt index 239bf2b43..8b4fa31e7 100644 --- a/src/main/kotlin/com/lambda/module/modules/network/PacketDelay.kt +++ b/src/main/kotlin/com/lambda/module/modules/network/PacketDelay.kt @@ -37,10 +37,11 @@ import net.minecraft.network.packet.Packet import net.minecraft.network.packet.c2s.common.KeepAliveC2SPacket import java.util.concurrent.ConcurrentLinkedDeque +@Suppress("unused") object PacketDelay : Module( name = "PacketDelay", description = "Delays packets client-bound & server-bound", - tag = ModuleTag.NETWORK, + tag = ModuleTag.Network, ) { private val mode by setting("Mode", Mode.Static, description = "How the delay is applied: Static queues packets until a flush; Pulse delays each packet individually.") private val networkScope by setting("Network Scope", Direction.Both, description = "Which direction(s) to affect: inbound (server → you), outbound (you → server), or both.") diff --git a/src/main/kotlin/com/lambda/module/modules/network/PacketLimiter.kt b/src/main/kotlin/com/lambda/module/modules/network/PacketLimiter.kt index 3ae6f21e2..8318c6693 100644 --- a/src/main/kotlin/com/lambda/module/modules/network/PacketLimiter.kt +++ b/src/main/kotlin/com/lambda/module/modules/network/PacketLimiter.kt @@ -21,9 +21,9 @@ import com.lambda.event.events.PacketEvent import com.lambda.event.listener.SafeListener.Companion.listen import com.lambda.module.Module import com.lambda.module.tag.ModuleTag -import com.lambda.util.Communication.info +import com.lambda.util.CommunicationUtils.info +import com.lambda.util.ReflectionUtils.className import com.lambda.util.collections.LimitedDecayQueue -import com.lambda.util.reflections.className import net.minecraft.network.packet.c2s.common.CommonPongC2SPacket import net.minecraft.network.packet.c2s.play.PlayerMoveC2SPacket.Full import net.minecraft.network.packet.c2s.play.PlayerMoveC2SPacket.LookAndOnGround @@ -35,7 +35,7 @@ import net.minecraft.network.packet.c2s.play.TeleportConfirmC2SPacket object PacketLimiter : Module( name = "PacketLimiter", description = "Limits the amount of packets sent to the server", - tag = ModuleTag.NETWORK, + tag = ModuleTag.Network, ) { private var packetQueueMap = mutableMapOf>() private val globalQueue = LimitedDecayQueue(1, 1) diff --git a/src/main/kotlin/com/lambda/module/modules/network/PacketLogger.kt b/src/main/kotlin/com/lambda/module/modules/network/PacketLogger.kt index 901b5a769..b36738b41 100644 --- a/src/main/kotlin/com/lambda/module/modules/network/PacketLogger.kt +++ b/src/main/kotlin/com/lambda/module/modules/network/PacketLogger.kt @@ -21,18 +21,17 @@ import com.lambda.Lambda import com.lambda.Lambda.mc import com.lambda.event.events.PacketEvent import com.lambda.event.events.TickEvent -import com.lambda.event.listener.UnsafeListener.Companion.listenUnsafe import com.lambda.event.listener.UnsafeListener.Companion.listenConcurrentlyUnsafe +import com.lambda.event.listener.UnsafeListener.Companion.listenUnsafe import com.lambda.module.Module import com.lambda.module.tag.ModuleTag import com.lambda.threading.runIO -import com.lambda.util.Communication -import com.lambda.util.Communication.info +import com.lambda.util.CommunicationUtils +import com.lambda.util.CommunicationUtils.info import com.lambda.util.DynamicReflectionSerializer.dynamicString -import com.lambda.util.FolderRegister -import com.lambda.util.FolderRegister.relativeMCPath -import com.lambda.util.Formatting.getTime -import com.lambda.util.reflections.getInstances +import com.lambda.util.FolderRegistry +import com.lambda.util.FolderRegistry.relativeMCPath +import com.lambda.util.FormattingUtils.getTime import com.lambda.util.text.ClickEvents import com.lambda.util.text.buildText import com.lambda.util.text.clickEvent @@ -49,7 +48,7 @@ import kotlin.io.path.pathString object PacketLogger : Module( name = "PacketLogger", description = "Serializes network traffic and persists it for later analysis", - tag = ModuleTag.NETWORK, + tag = ModuleTag.Network, autoDisable = true ) { private val logToChat by setting("Log To Chat", false, "Log packets to chat") @@ -81,6 +80,7 @@ object PacketLogger : Module( enum class Scope { Any, Whitelist, Blacklist; + @Suppress("unused") fun shouldLog(packet: Packet<*>) = when (this) { Any -> true Whitelist -> false//packet::class.simpleName in whitelist @@ -105,7 +105,7 @@ object PacketLogger : Module( val fileName = "packet-log-${getTime(fileFormatter)}.txt" // ToDo: Organize files with FolderRegister.worldBoundDirectory - file = FolderRegister.packetLogs.resolve(fileName).toFile().apply { + file = FolderRegistry.packetLogs.resolve(fileName).toFile().apply { if (!parentFile.exists()) { parentFile.mkdirs() } @@ -122,8 +122,8 @@ object PacketLogger : Module( this@PacketLogger.info(info) }.apply { StringBuilder().apply { - appendLine(Communication.ascii) - appendLine("${Lambda.SYMBOL} - Lambda ${Lambda.VERSION} - Packet Log") + appendLine(CommunicationUtils.ascii) + appendLine("${Lambda.Symbol} - Lambda ${Lambda.Version} - Packet Log") val playerName = mc.player?.name?.string ?: "Unknown" appendLine("Started at ${getTime()} by $playerName") diff --git a/src/main/kotlin/com/lambda/module/modules/network/Rubberband.kt b/src/main/kotlin/com/lambda/module/modules/network/Rubberband.kt index 245d0b1e4..1bdd94c24 100644 --- a/src/main/kotlin/com/lambda/module/modules/network/Rubberband.kt +++ b/src/main/kotlin/com/lambda/module/modules/network/Rubberband.kt @@ -22,14 +22,13 @@ import com.lambda.event.events.PlayerPacketEvent import com.lambda.event.listener.SafeListener.Companion.listen import com.lambda.module.Module import com.lambda.module.tag.ModuleTag -import com.lambda.util.Communication.warn +import com.lambda.util.CommunicationUtils.warn import com.lambda.util.collections.LimitedOrderedSet import com.lambda.util.math.dist import com.lambda.util.math.distSq import com.lambda.util.text.buildText import com.lambda.util.text.color import com.lambda.util.text.literal -import net.minecraft.network.packet.c2s.play.PlayerMoveC2SPacket import net.minecraft.network.packet.s2c.play.PlayerPositionLookS2CPacket import net.minecraft.util.math.Vec3d import java.awt.Color @@ -40,7 +39,7 @@ import java.awt.Color object Rubberband : Module( name = "Rubberband", description = "Info about rubberbands", - tag = ModuleTag.NETWORK, + tag = ModuleTag.Network, ) { private val showLastPacketInfo by setting("Show Last Packet", true) private val showConnectionState by setting("Show Connection State", true) diff --git a/src/main/kotlin/com/lambda/module/modules/network/ServerSpoof.kt b/src/main/kotlin/com/lambda/module/modules/network/ServerSpoof.kt index 0dcc2fcc5..709448de7 100644 --- a/src/main/kotlin/com/lambda/module/modules/network/ServerSpoof.kt +++ b/src/main/kotlin/com/lambda/module/modules/network/ServerSpoof.kt @@ -21,7 +21,7 @@ import com.lambda.event.events.PacketEvent import com.lambda.event.listener.UnsafeListener.Companion.listenUnsafe import com.lambda.module.Module import com.lambda.module.tag.ModuleTag -import com.lambda.util.Communication.info +import com.lambda.util.CommunicationUtils.info import com.lambda.util.text.ClickEvents import com.lambda.util.text.buildText import com.lambda.util.text.clickEvent @@ -37,7 +37,7 @@ import java.awt.Color object ServerSpoof : Module( name = "ServerSpoof", description = "Decide yourself if you want to accept the server resource pack.", - tag = ModuleTag.NETWORK, + tag = ModuleTag.Network, ) { private val spoofClientBrand by setting("Spoof Client Brand", true) private val spoofName by setting("Spoof Name", "vanilla", visibility = { spoofClientBrand }) diff --git a/src/main/kotlin/com/lambda/module/modules/player/AntiAFK.kt b/src/main/kotlin/com/lambda/module/modules/player/AntiAFK.kt index a8386b7dd..168138481 100644 --- a/src/main/kotlin/com/lambda/module/modules/player/AntiAFK.kt +++ b/src/main/kotlin/com/lambda/module/modules/player/AntiAFK.kt @@ -23,10 +23,11 @@ import com.lambda.module.Module import com.lambda.module.tag.ModuleTag import net.minecraft.util.Hand +@Suppress("unused") object AntiAFK : Module( name = "AntiAFK", description = "Keeps you from getting kicked", - tag = ModuleTag.PLAYER, + tag = ModuleTag.Player, ) { private val delay by setting("Delay", 300, 5..600, 1, unit = " s", description = "Delay between swinging the hand.") private val swingHand by setting("Swing Hand", Hand.MAIN_HAND, description = "Hand to swing.") diff --git a/src/main/kotlin/com/lambda/module/modules/player/AntiAim.kt b/src/main/kotlin/com/lambda/module/modules/player/AntiAim.kt index b59b60528..6cc1e641d 100644 --- a/src/main/kotlin/com/lambda/module/modules/player/AntiAim.kt +++ b/src/main/kotlin/com/lambda/module/modules/player/AntiAim.kt @@ -17,7 +17,6 @@ package com.lambda.module.modules.player -import com.lambda.config.groups.RotationSettings import com.lambda.context.SafeContext import com.lambda.event.events.TickEvent import com.lambda.event.listener.SafeListener.Companion.listen @@ -25,50 +24,36 @@ import com.lambda.interaction.managers.rotating.IRotationRequest.Companion.rotat import com.lambda.interaction.managers.rotating.Rotation.Companion.rotationTo import com.lambda.module.Module import com.lambda.module.tag.ModuleTag -import com.lambda.util.NamedEnum import com.lambda.util.math.distSq import net.minecraft.entity.Entity import net.minecraft.entity.player.PlayerEntity import net.minecraft.util.math.MathHelper.wrapDegrees import kotlin.random.Random +@Suppress("unused") object AntiAim : Module( name = "AntiAim", description = "Rotates the player using the given configs", - tag = ModuleTag.MOVEMENT, + tag = ModuleTag.Movement, ) { - private enum class Group(override val displayName: String) : NamedEnum { - General("General"), - Rotation("Rotation") - } + private const val GeneralTab = "General" + private const val RotationTab = "Rotation" - private val yaw by setting("Yaw Mode", YawMode.Spin, "The mode used when setting the players yaw").group(Group.General) - .onValueChange { _, to -> - if (to == YawMode.Custom) { - // To bypass recursion issue - setConfigCustomYaw(player.yaw) - } - } - private val spinMode by setting("Spin Mode", LeftRight.Right) { yaw == YawMode.Spin }.group(Group.General) - private val sideMode by setting("Side Mode", LeftRight.Left) { yaw == YawMode.Sideways }.group(Group.General) - private var customYaw by setting("Custom Yaw", 0f, -179f..180f, 1f) { yaw == YawMode.Custom }.group(Group.General) - private val yawPlayerMode by setting("Yaw Player mode", PlayerMode.Closest) { yaw == YawMode.Player }.group(Group.General) - - private val pitch by setting("Pitch Mode", PitchMode.UpAndDown, "The mode used when setting the players pitch").group(Group.General) - .onValueChange { _, to -> - if (to == PitchMode.Custom) { - // To bypass recursion issue - setConfigCustomPitch(player.pitch) - } - } - private val verticalMode by setting("Vertical Mode", VerticalMode.Up) { pitch == PitchMode.Vertical }.group(Group.General) - private var customPitch by setting("Custom Pitch", 0f, -90f..90f, 1f) { pitch == PitchMode.Custom }.group(Group.General) - private val pitchPlayerMode by setting("Pitch Player Mode", PlayerMode.Closest) { pitch == PitchMode.Player }.group(Group.General) + private val yaw by setting("Yaw Mode", YawMode.Spin, "The mode used when setting the players yaw") + .onValueChange { _, to -> if (to == YawMode.Custom) customYaw = player.yaw } + private val spinMode by setting("Spin Mode", LeftRight.Right) { yaw == YawMode.Spin } + private val sideMode by setting("Side Mode", LeftRight.Left) { yaw == YawMode.Sideways } + private var customYaw: Float by setting("Custom Yaw", 0f, -179f..180f, 1f) { yaw == YawMode.Custom } + private val yawPlayerMode by setting("Yaw Player mode", PlayerMode.Closest) { yaw == YawMode.Player } - private val yawSpeed by setting("Yaw Speed", 30, 1..90, 1, "Yaw rotation degrees per tick", "°") { yaw != YawMode.None }.group(Group.General) - private val pitchSpeed by setting("Pitch Speed", 30, 1..90, 1, "Pitch rotation degrees per tick", "°") { pitch != PitchMode.None }.group(Group.General) + private val pitch by setting("Pitch Mode", PitchMode.UpAndDown, "The mode used when setting the players pitch") + .onValueChange { _, to -> if (to == PitchMode.Custom) customPitch = player.pitch } + private val upDownMode by setting("Vertical Mode", UpDown.Up) { pitch == PitchMode.Vertical } + private var customPitch: Float by setting("Custom Pitch", 0f, -90f..90f, 1f) { pitch == PitchMode.Custom } + private val pitchPlayerMode by setting("Pitch Player Mode", PlayerMode.Closest) { pitch == PitchMode.Player } - override val rotationConfig = RotationSettings(this, Group.Rotation) + private val yawSpeed by setting("Yaw Speed", 30, 1..90, 1, "Yaw rotation degrees per tick", "°") { yaw != YawMode.None } + private val pitchSpeed by setting("Pitch Speed", 30, 1..90, 1, "Pitch rotation degrees per tick", "°") { pitch != PitchMode.None } private var currentYaw = 0.0f private var currentPitch = 0.0f @@ -141,9 +126,9 @@ object AntiAim : Module( } } PitchMode.Vertical -> { - when (verticalMode) { - VerticalMode.Up -> -90f - VerticalMode.Down -> 90f + when (upDownMode) { + UpDown.Up -> -90f + UpDown.Down -> 90f } } PitchMode.Custom -> customPitch @@ -176,10 +161,6 @@ object AntiAim : Module( customYaw = newYaw } - private fun setConfigCustomPitch(newPitch: Float) { - customPitch = newPitch - } - private enum class YawMode { None, Spin, @@ -210,7 +191,7 @@ object AntiAim : Module( Player } - private enum class VerticalMode { + private enum class UpDown { Up, Down } diff --git a/src/main/kotlin/com/lambda/module/modules/player/AutoEat.kt b/src/main/kotlin/com/lambda/module/modules/player/AutoEat.kt index daa58072e..1524503f7 100644 --- a/src/main/kotlin/com/lambda/module/modules/player/AutoEat.kt +++ b/src/main/kotlin/com/lambda/module/modules/player/AutoEat.kt @@ -17,9 +17,10 @@ package com.lambda.module.modules.player -import com.lambda.config.AutomationConfig.Companion.setDefaultAutomationConfig -import com.lambda.config.applyEdits -import com.lambda.config.groups.EatConfig.Companion.reasonEating +import com.lambda.config.SettingEditor.hideAllBlocksExcept +import com.lambda.config.automation.AutomationConfig.Companion.setDefaultAutomationConfig +import com.lambda.config.settings.blocks.EatConfig.Companion.reasonEating +import com.lambda.config.withEdits import com.lambda.event.events.TickEvent import com.lambda.event.listener.SafeListener.Companion.listen import com.lambda.module.Module @@ -29,19 +30,19 @@ import com.lambda.task.tasks.EatTask import com.lambda.task.tasks.EatTask.Companion.eat import com.lambda.threading.runSafeAutomated +@Suppress("unused") object AutoEat : Module( name = "AutoEat", description = "Eats food when you are hungry", - tag = ModuleTag.PLAYER, + tag = ModuleTag.Player, ) { private var eatTask: EatTask? = null init { - setDefaultAutomationConfig { - applyEdits { - hideAllGroupsExcept(eatConfig) - } - } + setDefaultAutomationConfig() + .withEdits { + hideAllBlocksExcept(::eatConfig) + } listen { val reason = runSafeAutomated { reasonEating() } diff --git a/src/main/kotlin/com/lambda/module/modules/player/ClickFriend.kt b/src/main/kotlin/com/lambda/module/modules/player/ClickFriend.kt index 48572de75..8f225970b 100644 --- a/src/main/kotlin/com/lambda/module/modules/player/ClickFriend.kt +++ b/src/main/kotlin/com/lambda/module/modules/player/ClickFriend.kt @@ -20,23 +20,25 @@ package com.lambda.module.modules.player import com.lambda.config.settings.complex.Bind import com.lambda.config.settings.complex.KeybindSetting.Companion.onPress import com.lambda.context.SafeContext -import com.lambda.friend.FriendManager -import com.lambda.friend.FriendManager.befriend -import com.lambda.friend.FriendManager.isFriend -import com.lambda.friend.FriendManager.unfriend +import com.lambda.friend.FriendHandler +import com.lambda.friend.FriendHandler.befriend +import com.lambda.friend.FriendHandler.isFriend +import com.lambda.friend.FriendHandler.unfriend import com.lambda.module.Module import com.lambda.module.tag.ModuleTag -import com.lambda.util.Communication.info +import com.lambda.util.CommunicationUtils.info import com.lambda.util.InputUtils.isSatisfied import com.lambda.util.world.raycast.RayCastUtils.entityResult import net.minecraft.client.network.OtherClientPlayerEntity import org.lwjgl.glfw.GLFW import org.lwjgl.glfw.GLFW.GLFW_MOD_SHIFT +@Suppress("unused") object ClickFriend : Module( name = "ClickFriend", description = "Add or remove friends with a single click", - tag = ModuleTag.PLAYER, + tag = ModuleTag.Player, + modulePriority = 100 ) { private val friendBind: Bind by setting("Friend Bind", Bind(0, 0, GLFW.GLFW_MOUSE_BUTTON_MIDDLE), "Bind to press to befriend a player") .onPress { if (!unfriendBind.isSatisfied()) if (checkSetFriend(true)) it.cancel() } @@ -44,16 +46,12 @@ object ClickFriend : Module( private val unfriendBind: Bind by setting("Unfriend Bind", Bind(0, GLFW_MOD_SHIFT, GLFW.GLFW_MOUSE_BUTTON_MIDDLE), "Bind to press to unfriend a player") .onPress { if (!friendBind.isSatisfied()) if (checkSetFriend(false)) it.cancel() } - init { - setModulePriority(100) - } - private fun SafeContext.checkSetFriend(friend: Boolean): Boolean { val target = mc.crosshairTarget?.entityResult?.entity as? OtherClientPlayerEntity ?: return false - if (friend && !target.isFriend && target.befriend()) info(FriendManager.befriendedText(target.name)) - else if (!friend && target.isFriend && target.unfriend()) info(FriendManager.unfriendedText(target.name)) + if (friend && !target.isFriend && target.befriend()) info(FriendHandler.befriendedText(target.name)) + else if (!friend && target.isFriend && target.unfriend()) info(FriendHandler.unfriendedText(target.name)) return true } } diff --git a/src/main/kotlin/com/lambda/module/modules/player/FastBreak.kt b/src/main/kotlin/com/lambda/module/modules/player/FastBreak.kt index 561be16a2..1c2a047c5 100644 --- a/src/main/kotlin/com/lambda/module/modules/player/FastBreak.kt +++ b/src/main/kotlin/com/lambda/module/modules/player/FastBreak.kt @@ -17,8 +17,12 @@ package com.lambda.module.modules.player -import com.lambda.config.AutomationConfig.Companion.setDefaultAutomationConfig -import com.lambda.config.applyEdits +import com.lambda.config.SettingEditor.edit +import com.lambda.config.SettingEditor.editTyped +import com.lambda.config.SettingEditor.hide +import com.lambda.config.SettingEditor.hideAllBlocksExcept +import com.lambda.config.automation.AutomationConfig.Companion.setDefaultAutomationConfig +import com.lambda.config.withEdits import com.lambda.event.events.PlayerEvent import com.lambda.event.events.TickEvent import com.lambda.event.listener.SafeListener.Companion.listen @@ -29,17 +33,18 @@ import com.lambda.module.tag.ModuleTag import com.lambda.threading.runSafeAutomated import java.util.concurrent.ConcurrentLinkedQueue +@Suppress("unused") object FastBreak : Module( name = "FastBreak", description = "Break blocks faster.", - tag = ModuleTag.PLAYER, + tag = ModuleTag.Player, ) { private val pendingActions = ConcurrentLinkedQueue() init { - setDefaultAutomationConfig { - applyEdits { - hideAllGroupsExcept(buildConfig, breakConfig, rotationConfig, hotbarConfig) + setDefaultAutomationConfig() + .withEdits { + hideAllBlocksExcept(::buildConfig, ::breakConfig, ::rotationConfig, ::hotbarConfig) buildConfig.apply { hide( ::pathing, @@ -77,7 +82,6 @@ object FastBreak : Module( } hotbarConfig::tickStageMask.edit { defaultValue(mutableSetOf(TickEvent.Input.Post)); hide() } } - } listen { it.cancel() } listen { event -> diff --git a/src/main/kotlin/com/lambda/module/modules/player/Interact.kt b/src/main/kotlin/com/lambda/module/modules/player/Interact.kt index 22adf4154..8f73704ab 100644 --- a/src/main/kotlin/com/lambda/module/modules/player/Interact.kt +++ b/src/main/kotlin/com/lambda/module/modules/player/Interact.kt @@ -23,11 +23,8 @@ import com.lambda.module.tag.ModuleTag object Interact : Module( name = "Interact", description = "Modify players interaction with the world", - tag = ModuleTag.PLAYER, + tag = ModuleTag.Player, ) { - @JvmStatic - val placeDelay by setting("Item Use / Place Delay", 4, 0..20, 1, "Sets the delay between placing blocks or using items") - - @JvmStatic - val multiAction by setting("Multi Action", false, "Allows to use many items while breaking blocks") + @JvmStatic val placeDelay by setting("Item Use / Place Delay", 4, 0..20, 1, "Sets the delay between placing blocks or using items") + @JvmStatic val multiAction by setting("Multi Action", false, "Allows to use many items while breaking blocks") } diff --git a/src/main/kotlin/com/lambda/module/modules/player/InventoryMove.kt b/src/main/kotlin/com/lambda/module/modules/player/InventoryMove.kt index b1d961326..00d3bf79b 100644 --- a/src/main/kotlin/com/lambda/module/modules/player/InventoryMove.kt +++ b/src/main/kotlin/com/lambda/module/modules/player/InventoryMove.kt @@ -18,11 +18,11 @@ package com.lambda.module.modules.player import com.lambda.Lambda.mc +import com.lambda.config.settings.blocks.RotationConfig import com.lambda.event.events.TickEvent import com.lambda.event.listener.SafeListener.Companion.listen import com.lambda.gui.LambdaScreen import com.lambda.interaction.managers.rotating.IRotationRequest.Companion.rotationRequest -import com.lambda.interaction.managers.rotating.RotationConfig import com.lambda.interaction.managers.rotating.RotationMode import com.lambda.module.Module import com.lambda.module.tag.ModuleTag @@ -46,7 +46,7 @@ import org.lwjgl.glfw.GLFW.GLFW_KEY_UP object InventoryMove : Module( name = "InventoryMove", description = "Allows you to move with GUIs opened", - tag = ModuleTag.PLAYER, + tag = ModuleTag.Player, ) { private val clickGui by setting("ClickGui", false) private val disableSneak by setting("Disable Sneak", false) diff --git a/src/main/kotlin/com/lambda/module/modules/player/InventoryResync.kt b/src/main/kotlin/com/lambda/module/modules/player/InventoryResync.kt index 8860fe5b3..075503c33 100644 --- a/src/main/kotlin/com/lambda/module/modules/player/InventoryResync.kt +++ b/src/main/kotlin/com/lambda/module/modules/player/InventoryResync.kt @@ -28,14 +28,14 @@ import com.lambda.util.TickTimer object InventoryResync : Module( name = "InventoryResync", description = "Resyncs your inventory, with a delay between resyncs", - tag = ModuleTag.PLAYER + tag = ModuleTag.Player, + modulePriority = 10 ) { private val delay by setting("Delay", 100, 0..1000, 5, unit = " ticks") private val timer = TickTimer() init { - setModulePriority(10) listen { timer.tick() if (!timer.hasSurpassed(delay)) return@listen diff --git a/src/main/kotlin/com/lambda/module/modules/player/InventoryTweaks.kt b/src/main/kotlin/com/lambda/module/modules/player/InventoryTweaks.kt index 37c6263cd..8b66bc16e 100644 --- a/src/main/kotlin/com/lambda/module/modules/player/InventoryTweaks.kt +++ b/src/main/kotlin/com/lambda/module/modules/player/InventoryTweaks.kt @@ -17,8 +17,9 @@ package com.lambda.module.modules.player -import com.lambda.config.AutomationConfig.Companion.setDefaultAutomationConfig -import com.lambda.config.applyEdits +import com.lambda.config.SettingEditor.hideAllBlocksExcept +import com.lambda.config.automation.AutomationConfig.Companion.setDefaultAutomationConfig +import com.lambda.config.withEdits import com.lambda.event.events.InventoryEvent import com.lambda.event.events.PlayerEvent import com.lambda.event.listener.SafeListener.Companion.listen @@ -37,21 +38,21 @@ import net.minecraft.util.math.BlockPos object InventoryTweaks : Module( name = "InventoryTweaks", - tag = ModuleTag.PLAYER, + tag = ModuleTag.Player, ) { private val instantShulker by setting("Instant Shulker", true, description = "Right-click shulker boxes in your inventory to instantly place them and open them.") private val instantEChest by setting("Instant Ender-Chest", true, description = "Right-click ender chests in your inventory to instantly place them and open them.") + private var placedPos: BlockPos? = null private var placeAndOpen: Task<*>? = null private var lastBreak: Task<*>? = null private var lastOpenScreen: ScreenHandler? = null init { - setDefaultAutomationConfig { - applyEdits { - hideAllGroupsExcept(breakConfig, interactConfig, inventoryConfig, hotbarConfig) + setDefaultAutomationConfig() + .withEdits { + hideAllBlocksExcept(::breakConfig, ::interactConfig, ::inventoryConfig, ::hotbarConfig) } - } listen { if (it.action != SlotActionType.PICKUP || it.button != 1) return@listen diff --git a/src/main/kotlin/com/lambda/module/modules/player/NoForceRotate.kt b/src/main/kotlin/com/lambda/module/modules/player/NoForceRotate.kt index 29f82c674..3745528b0 100644 --- a/src/main/kotlin/com/lambda/module/modules/player/NoForceRotate.kt +++ b/src/main/kotlin/com/lambda/module/modules/player/NoForceRotate.kt @@ -23,5 +23,5 @@ import com.lambda.module.tag.ModuleTag object NoForceRotate : Module( name = "NoForceRotate", description = "Prevents the server from forcing your players rotation", - tag = ModuleTag.PLAYER + tag = ModuleTag.Player ) \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/module/modules/player/PacketMine.kt b/src/main/kotlin/com/lambda/module/modules/player/PacketMine.kt index 28447dc3a..748eeee5b 100644 --- a/src/main/kotlin/com/lambda/module/modules/player/PacketMine.kt +++ b/src/main/kotlin/com/lambda/module/modules/player/PacketMine.kt @@ -17,8 +17,14 @@ package com.lambda.module.modules.player -import com.lambda.config.AutomationConfig.Companion.setDefaultAutomationConfig -import com.lambda.config.applyEdits +import com.lambda.config.SettingEditor.edit +import com.lambda.config.SettingEditor.editTyped +import com.lambda.config.SettingEditor.hide +import com.lambda.config.SettingEditor.hideAllBlocksExcept +import com.lambda.config.Group +import com.lambda.config.automation.AutomationConfig.Companion.setDefaultAutomationConfig +import com.lambda.config.settings.blocks.BreakConfig +import com.lambda.config.withEdits import com.lambda.context.SafeContext import com.lambda.event.events.PlayerEvent import com.lambda.event.events.TickEvent @@ -29,7 +35,6 @@ import com.lambda.interaction.construction.simulation.context.BreakContext import com.lambda.interaction.construction.simulation.context.BuildContext import com.lambda.interaction.construction.simulation.result.results.BreakResult import com.lambda.interaction.construction.verify.TargetState -import com.lambda.interaction.managers.breaking.BreakConfig import com.lambda.interaction.managers.breaking.BreakRequest.Companion.breakRequest import com.lambda.module.Module import com.lambda.module.tag.ModuleTag @@ -50,35 +55,32 @@ import java.util.concurrent.ConcurrentLinkedQueue object PacketMine : Module( name = "PacketMine", description = "automatically breaks blocks, and does it faster", - tag = ModuleTag.PLAYER + tag = ModuleTag.Player ) { - private enum class Group(override val displayName: String) : NamedEnum { - General("General"), - Renders("Renders") - } - - private val ignoreWhenHolding by setting("Ignore When Holding", emptySet(), description = "These items won't initiate a break if held when attacking a block").group(Group.General) - private val rebreakMode by setting("Rebreak Mode", RebreakMode.Manual, "The method used to re-break blocks after they've been broken once").disabled { !breakConfig.rebreak }.group(Group.General) - private val breakRadius by setting("Break Radius", 0, 0..5, 1, "Selects and breaks all blocks within the break radius of the selected block").group(Group.General) - private val flatten by setting("Flatten", true, "Wont allow breaking extra blocks under your players position") { breakRadius > 0 }.group(Group.General) - private val queue by setting("Queue", false, "Queues blocks to break so you can select multiple at once").group(Group.General) + private val ignoreWhenHolding by setting("Ignore When Holding", emptySet(), description = "These items won't initiate a break if held when attacking a block") + private val rebreakMode by setting("Rebreak Mode", RebreakMode.Manual, "The method used to re-break blocks after they've been broken once").disabled { !breakConfig.rebreak } + private val breakRadius by setting("Break Radius", 0, 0..5, 1, "Selects and breaks all blocks within the break radius of the selected block") + private val flatten by setting("Flatten", true, "Wont allow breaking extra blocks under your players position") { breakRadius > 0 } + private val queue by setting("Queue", false, "Queues blocks to break so you can select multiple at once") .onValueChange { _, to -> if (!to) queuePositions.clear() } - private val queueOrder by setting("Queue Order", QueueOrder.Standard, "Which end of the queue to break blocks from") { queue }.group(Group.General) + private val queueOrder by setting("Queue Order", QueueOrder.Standard, "Which end of the queue to break blocks from") { queue } - private val renderRebreak by setting("Render Rebreak", true, "Displays what block is being checked for rebreak").group(Group.Renders) - private val rebreakColor by setting("Rebreak Color", Color.RED) { renderRebreak }.group(Group.Renders) - private val renderQueue by setting("Render Queue", true, "Adds renders to signify what block positions are queued").group(Group.Renders) - private val renderSize by setting("Queue Render Size", 0.3f, 0.01f..1f, 0.01f, "The scale of the queue renders") { renderQueue }.group(Group.Renders) - private val renderMode by setting("Queue Render Mode", RenderMode.State, "The style of the queue renders") { renderQueue }.group(Group.Renders) - private val dynamicColor by setting("Queue Dynamic Color", true, "Interpolates the color between start and end") { renderQueue }.group(Group.Renders) - private val staticColor by setting("Queue Color", Color(255, 0, 0, 60)) { renderQueue && !dynamicColor }.group(Group.Renders) - private val startColor by setting("Queue Start Color", Color(255, 255, 0, 60), "The color of the start (closest to breaking) of the queue") { renderQueue && dynamicColor }.group(Group.Renders) - private val endColor by setting("Queue End Color", Color(255, 0, 0, 60), "The color of the end (farthest from breaking) of the queue") { renderQueue && dynamicColor }.group(Group.Renders) + private const val ReBreakRendersGroup = "Queue Renders" + private const val QueueRendersGroup = "Queue Renders" + + @Group(ReBreakRendersGroup) private val renderRebreak by setting("Render Rebreak", true, "Displays what block is being checked for rebreak") + @Group(ReBreakRendersGroup) private val rebreakColor by setting("Rebreak Color", Color.RED) { renderRebreak } + @Group(QueueRendersGroup) private val renderQueue by setting("Render Queue", true, "Adds renders to signify what block positions are queued") + @Group(QueueRendersGroup) private val renderSize by setting("Render Size", 0.3f, 0.01f..1f, 0.01f, "The scale of the queue renders") { renderQueue } + @Group(QueueRendersGroup) private val renderMode by setting("Render Mode", RenderMode.State, "The style of the queue renders") { renderQueue } + @Group(QueueRendersGroup) private val dynamicColor by setting("Dynamic Color", true, "Interpolates the color between start and end") { renderQueue } + @Group(QueueRendersGroup) private val staticColor by setting("Color", Color(255, 0, 0, 60)) { renderQueue && !dynamicColor } + @Group(QueueRendersGroup) private val startColor by setting("Start Color", Color(255, 255, 0, 60), "The color of the start (closest to breaking) of the queue") { renderQueue && dynamicColor } + @Group(QueueRendersGroup) private val endColor by setting("End Color", Color(255, 0, 0, 60), "The color of the end (farthest from breaking) of the queue") { renderQueue && dynamicColor } private val pendingActions = ConcurrentLinkedQueue() private var breaks = 0 - private var itemDrops = 0 private val breakPositions = arrayOfNulls(2) private val queuePositions = ArrayList>() @@ -100,9 +102,9 @@ object PacketMine : Module( private var attackedThisTick = false init { - setDefaultAutomationConfig { - applyEdits { - hideAllGroupsExcept(buildConfig, breakConfig, breakConfig.outlineConfig, rotationConfig, hotbarConfig) + setDefaultAutomationConfig() + .withEdits { + hideAllBlocksExcept(::buildConfig, ::breakConfig, ::rotationConfig, ::hotbarConfig) buildConfig.apply { hide( ::pathing, @@ -128,7 +130,6 @@ object PacketMine : Module( } hotbarConfig::keepTicks.edit { defaultValue(0) } } - } listen { attackedThisTick = false @@ -298,7 +299,7 @@ object PacketMine : Module( return false } - enum class RebreakMode( + private enum class RebreakMode( override val displayName: String, override val description: String ) : NamedEnum, Describable { @@ -308,7 +309,7 @@ object PacketMine : Module( // AutoConstant("Auto (Constant)", "Continuously re-break as soon as conditions allow; most aggressive.") } - enum class QueueOrder( + private enum class QueueOrder( override val displayName: String, override val description: String ) : NamedEnum, Describable { diff --git a/src/main/kotlin/com/lambda/module/modules/player/PortalGui.kt b/src/main/kotlin/com/lambda/module/modules/player/PortalGui.kt index dea4ec2e1..04c10b6b4 100644 --- a/src/main/kotlin/com/lambda/module/modules/player/PortalGui.kt +++ b/src/main/kotlin/com/lambda/module/modules/player/PortalGui.kt @@ -23,5 +23,5 @@ import com.lambda.module.tag.ModuleTag object PortalGui : Module( name = "PortalGui", description = "Allows you to open guis in portals", - tag = ModuleTag.PLAYER, + tag = ModuleTag.Player, ) diff --git a/src/main/kotlin/com/lambda/module/modules/player/Replay.kt b/src/main/kotlin/com/lambda/module/modules/player/Replay.kt index 896745547..6d4c1e50e 100644 --- a/src/main/kotlin/com/lambda/module/modules/player/Replay.kt +++ b/src/main/kotlin/com/lambda/module/modules/player/Replay.kt @@ -26,9 +26,10 @@ import com.google.gson.JsonNull import com.google.gson.JsonSerializationContext import com.google.gson.JsonSerializer import com.lambda.brigadier.CommandResult +import com.lambda.config.settings.blocks.RotationConfig import com.lambda.config.settings.complex.KeybindSetting.Companion.onPress import com.lambda.context.SafeContext -import com.lambda.core.TimerManager +import com.lambda.core.TimerHandler import com.lambda.event.EventFlow.lambdaScope import com.lambda.event.events.MovementEvent import com.lambda.event.events.TickEvent @@ -36,19 +37,18 @@ import com.lambda.event.listener.SafeListener.Companion.listen import com.lambda.gui.components.ClickGuiLayout import com.lambda.interaction.managers.rotating.IRotationRequest.Companion.rotationRequest import com.lambda.interaction.managers.rotating.Rotation -import com.lambda.interaction.managers.rotating.RotationConfig import com.lambda.interaction.managers.rotating.RotationMode import com.lambda.module.Module import com.lambda.module.modules.player.Replay.InputAction.Companion.toAction import com.lambda.module.tag.ModuleTag -import com.lambda.sound.SoundManager.playSound -import com.lambda.util.Communication.info -import com.lambda.util.Communication.logError -import com.lambda.util.Communication.warn +import com.lambda.sound.SoundHandler.playSound +import com.lambda.util.CommunicationUtils.info +import com.lambda.util.CommunicationUtils.logError +import com.lambda.util.CommunicationUtils.warn import com.lambda.util.FileUtils.locationBoundDirectory -import com.lambda.util.FolderRegister -import com.lambda.util.Formatting.format -import com.lambda.util.Formatting.getTime +import com.lambda.util.FolderRegistry +import com.lambda.util.FormattingUtils.format +import com.lambda.util.FormattingUtils.getTime import com.lambda.util.KeyCode import com.lambda.util.StringUtils.sanitizeForFilename import com.lambda.util.extension.rotation @@ -81,10 +81,11 @@ import kotlin.time.toDuration // - Record other types of inputs: (place, break, inventory, etc.) // - Add HUD for recording / replaying info // - Maybe use a custom binary format to store the data (Protobuf / DB?) +@Suppress("unused") object Replay : Module( name = "Replay", description = "Record gameplay actions and replay them like a TAS.", - tag = ModuleTag.PLAYER, + tag = ModuleTag.Player, autoDisable = true ) { private val record by setting("Record", KeyCode.R) @@ -423,7 +424,7 @@ object Replay : Module( this@Replay.warn("Recording too short. Minimum length: 5 ticks.") return } - val file = FolderRegister.replay.toFile().locationBoundDirectory().resolve("$name.json") + val file = FolderRegistry.replay.toFile().locationBoundDirectory().resolve("$name.json") lambdaScope.launch(Dispatchers.IO) { file.writeText(gsonCompact.toJson(recording)) @@ -557,7 +558,7 @@ object Replay : Module( val size: Int get() = minOf(input.size, rotation.size, position.size) val duration: Duration - get() = (size * TimerManager.lastTickLength * 1.0).toDuration(DurationUnit.MILLISECONDS) + get() = (size * TimerHandler.lastTickLength * 1.0).toDuration(DurationUnit.MILLISECONDS) val startPos: Vec3d get() = position.firstOrNull() ?: Vec3d.ZERO val endPos: Vec3d diff --git a/src/main/kotlin/com/lambda/module/modules/player/RotationLock.kt b/src/main/kotlin/com/lambda/module/modules/player/RotationLock.kt index ad1349288..505f9a400 100644 --- a/src/main/kotlin/com/lambda/module/modules/player/RotationLock.kt +++ b/src/main/kotlin/com/lambda/module/modules/player/RotationLock.kt @@ -17,42 +17,39 @@ package com.lambda.module.modules.player -import com.lambda.config.applyEdits -import com.lambda.config.groups.RotationSettings +import com.lambda.config.SettingEditor.edit +import com.lambda.config.SettingEditor.hideAllBlocksExcept +import com.lambda.config.automation.AutomationConfig.Companion.setDefaultAutomationConfig +import com.lambda.config.withEdits import com.lambda.event.events.TickEvent import com.lambda.event.listener.SafeListener.Companion.listen import com.lambda.interaction.managers.rotating.IRotationRequest.Companion.rotationRequest import com.lambda.interaction.managers.rotating.RotationMode import com.lambda.module.Module import com.lambda.module.tag.ModuleTag -import com.lambda.util.NamedEnum import kotlin.math.roundToInt +@Suppress("unused") object RotationLock : Module( name = "RotationLock", description = "Locks the player rotation to the given configuration", - tag = ModuleTag.PLAYER, + tag = ModuleTag.Player, + modulePriority = 100 ) { - private enum class Group(override val displayName: String) : NamedEnum { - General("General"), - Rotation("Rotation") - } - - @JvmStatic val yawMode by setting("Yaw Mode", Mode.Snap).group(Group.General) - private val yawStep by setting("Yaw Step", 45.0, 1.0..180.0, 0.1) { yawMode == Mode.Snap }.group(Group.General) - private val customYaw by setting("Custom Yaw", 0.0, -179.0..180.0, 0.1) { yawMode == Mode.Custom }.group(Group.General) - @JvmStatic val pitchMode by setting("Pitch Mode", Mode.None).group(Group.General) - private val pitchStep by setting("Pitch Step", 45.0, 1.0..90.0, 0.1) { pitchMode == Mode.Snap }.group(Group.General) - private val customPitch by setting("Custom Pitch", 0.0, -90.0..90.0, 0.1) { pitchMode == Mode.Custom }.group(Group.General) - - override val rotationConfig = RotationSettings(this, Group.Rotation).apply { - applyEdits { - ::rotationMode.edit { defaultValue(RotationMode.Lock) } - } - } + @JvmStatic val yawMode by setting("Yaw Mode", Mode.Snap) + private val yawStep by setting("Yaw Step", 45.0, 1.0..180.0, 0.1) { yawMode == Mode.Snap } + private val customYaw by setting("Custom Yaw", 0.0, -179.0..180.0, 0.1) { yawMode == Mode.Custom } + @JvmStatic val pitchMode by setting("Pitch Mode", Mode.None) + private val pitchStep by setting("Pitch Step", 45.0, 1.0..90.0, 0.1) { pitchMode == Mode.Snap } + private val customPitch by setting("Custom Pitch", 0.0, -90.0..90.0, 0.1) { pitchMode == Mode.Custom } init { - setModulePriority(100) + setDefaultAutomationConfig() + .withEdits { + hideAllBlocksExcept(::rotationConfig) + rotationConfig::rotationMode.edit { defaultValue(RotationMode.Lock) } + } + listen { val yaw = when (yawMode) { Mode.Custom -> customYaw diff --git a/src/main/kotlin/com/lambda/module/modules/player/StackReplenish.kt b/src/main/kotlin/com/lambda/module/modules/player/StackReplenish.kt index 5823b5a5d..c56fa9586 100644 --- a/src/main/kotlin/com/lambda/module/modules/player/StackReplenish.kt +++ b/src/main/kotlin/com/lambda/module/modules/player/StackReplenish.kt @@ -17,8 +17,10 @@ package com.lambda.module.modules.player -import com.lambda.config.AutomationConfig.Companion.setDefaultAutomationConfig -import com.lambda.config.applyEdits +import com.lambda.config.SettingEditor.hide +import com.lambda.config.SettingEditor.hideAllBlocksExcept +import com.lambda.config.automation.AutomationConfig.Companion.setDefaultAutomationConfig +import com.lambda.config.withEdits import com.lambda.context.SafeContext import com.lambda.event.events.TickEvent import com.lambda.event.listener.SafeListener.Companion.listen @@ -31,23 +33,23 @@ import com.lambda.util.player.SlotUtils.inventoryStacks import net.minecraft.item.ItemStack import net.minecraft.item.Items +@Suppress("unused") object StackReplenish : Module( name = "StackReplenish", description = "Automatically refills stacks from your inventory", - tag = ModuleTag.PLAYER + tag = ModuleTag.Player ) { private val minStackPercent by setting("Min Stack Percentage", 30, 0..100, 1, "Minimum percentage of a complete stack before refilling", "%") private val offhand by setting("Offhand", false, "Replenishes the players offhand stack") init { - setDefaultAutomationConfig { - applyEdits { - hideAllGroupsExcept(inventoryConfig) + setDefaultAutomationConfig() + .withEdits { + hideAllBlocksExcept(::inventoryConfig) inventoryConfig.apply { hide(::disposables, ::swapWithDisposables, ::providerPriority, ::storePriority) } } - } listen { if (player.currentScreenHandler.cursorStack.item !== Items.AIR) return@listen diff --git a/src/main/kotlin/com/lambda/module/modules/player/ToolSaver.kt b/src/main/kotlin/com/lambda/module/modules/player/ToolSaver.kt index 54eae94ea..32a6dc0e7 100644 --- a/src/main/kotlin/com/lambda/module/modules/player/ToolSaver.kt +++ b/src/main/kotlin/com/lambda/module/modules/player/ToolSaver.kt @@ -17,8 +17,9 @@ package com.lambda.module.modules.player -import com.lambda.config.AutomationConfig.Companion.setDefaultAutomationConfig -import com.lambda.config.applyEdits +import com.lambda.config.SettingEditor.hideAllBlocksExcept +import com.lambda.config.automation.AutomationConfig.Companion.setDefaultAutomationConfig +import com.lambda.config.withEdits import com.lambda.event.events.ContainerEvent import com.lambda.event.events.TickEvent import com.lambda.event.listener.SafeListener.Companion.listen @@ -33,20 +34,20 @@ import com.lambda.util.player.SlotUtils.inventorySlots import net.minecraft.item.ItemStack import net.minecraft.screen.slot.Slot +@Suppress("unused") object ToolSaver : Module( name = "ToolSaver", description = "Moves tools from your hotbar into your inventory when they get too damaged", - ModuleTag.PLAYER + ModuleTag.Player ) { private val minDurabilityPercentage by setting("Min Durability", 5, 0..100, 1, "Minimum durability percentage before being swapped for a new piece", "%") private val replace by setting("Replace", true, "Replaces the tool with the one of the same kind") init { - setDefaultAutomationConfig { - applyEdits { - hideAllGroupsExcept(inventoryConfig) + setDefaultAutomationConfig() + .withEdits { + hideAllBlocksExcept(::inventoryConfig) } - } listen { val endangeredStacks = player.hotbarSlots.filter { it.stack.isEndangered } diff --git a/src/main/kotlin/com/lambda/module/modules/render/BlockOutline.kt b/src/main/kotlin/com/lambda/module/modules/render/BlockOutline.kt index b8f8868c3..ddc79598c 100644 --- a/src/main/kotlin/com/lambda/module/modules/render/BlockOutline.kt +++ b/src/main/kotlin/com/lambda/module/modules/render/BlockOutline.kt @@ -17,9 +17,12 @@ package com.lambda.module.modules.render -import com.lambda.config.applyEdits -import com.lambda.config.groups.OutlineSettings -import com.lambda.config.groups.WorldLineSettings +import com.lambda.config.SettingEditor.forEachSetting +import com.lambda.config.SettingEditor.hide +import com.lambda.config.Group +import com.lambda.config.settings.blocks.OutlineSettings +import com.lambda.config.settings.blocks.WorldLineSettings +import com.lambda.config.withEdits import com.lambda.event.events.TickEvent import com.lambda.event.listener.SafeListener.Companion.listen import com.lambda.graphics.mc.renderer.ImmediateRenderer.Companion.immediateRenderer @@ -27,7 +30,6 @@ import com.lambda.module.Module import com.lambda.module.tag.ModuleTag import com.lambda.threading.runSafe import com.lambda.util.BlockUtils.blockState -import com.lambda.util.NamedEnum import com.lambda.util.extension.tickDelta import com.lambda.util.math.lerp import com.lambda.util.world.raycast.RayCastUtils.blockResult @@ -37,33 +39,40 @@ import java.awt.Color object BlockOutline : Module( name = "BlockOutline", description = "Overrides the default block outline rendering", - tag = ModuleTag.RENDER + tag = ModuleTag.Render ) { private enum class Mode { Boxes, Outline } - private enum class BoxGroup(override val displayName: String) : NamedEnum { - Fill("Fill"), - Outline("Outline") - } - private val mode by setting("Mode", Mode.Boxes) private val interpolate by setting("Interpolate", true) { mode == Mode.Boxes } private val depthTest by setting("Depth Test", true) - private val fill by setting("Fill", true) { mode == Mode.Boxes }.group(BoxGroup.Fill) - private val fillColor by setting("Fill Color", Color(255, 255, 255, 20)) { fill && mode == Mode.Boxes }.group(BoxGroup.Fill) - private val boxOutline by setting("Box Outline", true) { mode == Mode.Boxes }.group(BoxGroup.Outline, WorldLineSettings.Group.General) - private val boxOutlineColor by setting("Box Outline Color", Color(255, 255, 255, 120)) { boxOutline && mode == Mode.Boxes }.group(BoxGroup.Outline, WorldLineSettings.Group.General) - private val lineConfig = WorldLineSettings(this, BoxGroup.Outline, prefix = "Outline ") { boxOutline && mode == Mode.Boxes }.apply { - applyEdits { + private const val BoxFillGroup = "Box Fill" + private const val BoxOutlineGroup = "Box Outline" + private const val OutlineGroup = "Outline" + + @Group(BoxFillGroup) private val fill by setting("Fill", true) { mode == Mode.Boxes } + @Group(BoxFillGroup) private val fillColor by setting("Fill Color", Color(255, 255, 255, 20)) { fill && mode == Mode.Boxes } + @Group(BoxOutlineGroup) private val boxOutline by setting("Box Outline", true) { mode == Mode.Boxes } + @Group(BoxOutlineGroup) private val boxOutlineColor by setting("Box Outline Color", Color(255, 255, 255, 120)) { mode == Mode.Boxes && boxOutline } + @Group(BoxOutlineGroup) private val lineConfig by configBlock(WorldLineSettings(this)) + .withEdits { hide(::startColor, ::endColor) + forEachSetting { + visibility { old -> { old() && mode == Mode.Boxes } } + } + } + + @Group(OutlineGroup) private val outlineColor by setting("Outline Color", boxOutlineColor) { mode == Mode.Outline } + @Group(OutlineGroup) private val outlineStyle by configBlock(OutlineSettings(this)) + .withEdits { + forEachSetting { + visibility { old -> { old() && mode == Mode.Outline } } + } } - } - private val outlineColor by setting("Outline Color", boxOutlineColor) { mode == Mode.Outline } - private val outlineStyle = OutlineSettings(this, prefix = "Outline") { mode == Mode.Outline } var previous: List? = null diff --git a/src/main/kotlin/com/lambda/module/modules/render/Bobbing.kt b/src/main/kotlin/com/lambda/module/modules/render/Bobbing.kt index d3d9303d5..1c53876db 100644 --- a/src/main/kotlin/com/lambda/module/modules/render/Bobbing.kt +++ b/src/main/kotlin/com/lambda/module/modules/render/Bobbing.kt @@ -23,7 +23,7 @@ import com.lambda.module.tag.ModuleTag object Bobbing : Module( name = "Bobbing", description = "Modifies vanilla view bobbing when the player walks or runs", - tag = ModuleTag.RENDER + tag = ModuleTag.Render ) { val magnitude by setting("Magnitude", 1.0, 0.0..2.0, 0.01) val speed by setting("Speed", 1.0, 0.0..2.0, 0.01) diff --git a/src/main/kotlin/com/lambda/module/modules/render/CameraTweaks.kt b/src/main/kotlin/com/lambda/module/modules/render/CameraTweaks.kt index 8822e1b32..bb43537b8 100644 --- a/src/main/kotlin/com/lambda/module/modules/render/CameraTweaks.kt +++ b/src/main/kotlin/com/lambda/module/modules/render/CameraTweaks.kt @@ -23,11 +23,8 @@ import com.lambda.module.tag.ModuleTag object CameraTweaks : Module( name = "CameraTweaks", description = "Adjusts camera settings", - tag = ModuleTag.RENDER, + tag = ModuleTag.Render, ) { - @JvmStatic - val camDistance by setting("Camera Distance", 4.0f, 1.0f..20.0f, 0.1f) - - @JvmStatic - val noClipCam by setting("No Clip Camera", true) + @JvmStatic val camDistance by setting("Camera Distance", 4.0f, 1.0f..20.0f, 0.1f) + @JvmStatic val noClipCam by setting("No Clip Camera", true) } 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 ca2e2d52e..a342acb6d 100644 --- a/src/main/kotlin/com/lambda/module/modules/render/ContainerPreview.kt +++ b/src/main/kotlin/com/lambda/module/modules/render/ContainerPreview.kt @@ -18,15 +18,14 @@ package com.lambda.module.modules.render import com.lambda.Lambda.mc +import com.lambda.config.Tab import com.lambda.config.settings.complex.Bind import com.lambda.interaction.material.container.containers.EnderChestContainer import com.lambda.module.Module import com.lambda.module.tag.ModuleTag import com.lambda.threading.runSafe -import com.lambda.util.Describable import com.lambda.util.InputUtils.isSatisfied import com.lambda.util.KeyCode -import com.lambda.util.NamedEnum import com.lambda.util.item.ItemStackUtils.bundleContents import com.lambda.util.item.ItemStackUtils.shulkerBoxContents import com.lambda.util.item.ItemUtils.bundles @@ -57,23 +56,23 @@ import net.minecraft.world.World import org.joml.Matrix3x2f import kotlin.math.max - object ContainerPreview : Module( name = "ContainerPreview", description = "Renders shulker box contents visually in tooltips", - tag = ModuleTag.RENDER, + tag = ModuleTag.Render, ) { - private val lockKey by setting("Lock Key", Bind(KeyCode.LeftShift.code, 0, -1), "Key to lock the tooltip in place for item interaction").group(Group.ContainerTooltip) - private val colorTint by setting("Color Tint", true, "Tint the background with the shulker box color").group(Group.ContainerTooltip) - - private val contentPreview by setting("Content Preview", true, "Show a preview of the most common item in a container on the container item in inventories").group(Group.ContentPreview) - private val previewItemScale by setting("Item Scale", 11f, 1f..32f, 0.1f, "Scale of the item icons on a container item") { contentPreview }.group(Group.ContentPreview) - private val previewItemXOffset by setting("Item X Offset", -2f, -32f..32f, 0.1f, "X offset of the item icons on a container item") { contentPreview }.group(Group.ContentPreview) - private val previewItemYOffset by setting("Item Y Offset", 2f, -32f..32f, 0.1f, "Y offset of the item icons on a container item") { contentPreview }.group(Group.ContentPreview) - private val previewItemWeightedCount by setting("Weighted Count", true, description = "Count items for preview in containers relative to max stack size") { contentPreview }.group(Group.ContentPreview) - .onValueChange { _, _ -> - containerCache.clear() - } + private const val ContainerTooltipTab = "Container Tooltip" + private const val ContentPreviewTab = "Content Preview" + + @Tab(ContainerTooltipTab) private val lockKey by setting("Lock Key", Bind(KeyCode.LeftShift.code, 0, -1), "Key to lock the tooltip in place for item interaction") + @Tab(ContainerTooltipTab) private val colorTint by setting("Color Tint", true, "Tint the background with the shulker box color") + + @Tab(ContentPreviewTab) private val contentPreview by setting("Content Preview", true, "Show a preview of the most common item in a container on the container item in inventories") + @Tab(ContentPreviewTab) private val previewItemScale by setting("Item Scale", 11f, 1f..32f, 0.1f, "Scale of the item icons on a container item") { contentPreview } + @Tab(ContentPreviewTab) private val previewItemXOffset by setting("Item X Offset", -2f, -32f..32f, 0.1f, "X offset of the item icons on a container item") { contentPreview } + @Tab(ContentPreviewTab) private val previewItemYOffset by setting("Item Y Offset", 2f, -32f..32f, 0.1f, "Y offset of the item icons on a container item") { contentPreview } + @Tab(ContentPreviewTab) private val previewItemWeightedCount by setting("Weighted Count", true, description = "Count items for preview in containers relative to max stack size") { contentPreview } + .onValueChange { _, _ -> containerCache.clear() } private val background = Identifier.ofVanilla("textures/gui/container/shulker_box.png") @@ -97,18 +96,18 @@ object ContainerPreview : Module( } } - private const val ROWS = 3 - private const val COLS = 9 - private const val SLOT_SIZE = 18 - private const val PADDING = 7 - private const val TITLE_HEIGHT = 14 + private const val Rows = 3 + private const val Cols = 9 + private const val SlotSize = 18 + private const val Padding = 7 + private const val TitleHeight = 14 @JvmStatic val isLocked: Boolean get() = lockedSlot != null - private fun getTooltipWidth() = PADDING + COLS * SLOT_SIZE + PADDING - private fun getTooltipHeight() = TITLE_HEIGHT + ROWS * SLOT_SIZE + PADDING + private fun getTooltipWidth() = Padding + Cols * SlotSize + Padding + private fun getTooltipHeight() = TitleHeight + Rows * SlotSize + Padding /** * Check if the mouse is over the locked tooltip area (for click blocking) @@ -195,10 +194,10 @@ object ContainerPreview : Module( drawBackground(context, x, y, width, tintColor) val name = stack.name val textColor = getTextColor(tintColor) - context.drawText(textRenderer, name, x + PADDING, y + 4, textColor, false) + context.drawText(textRenderer, name, x + Padding, y + 4, textColor, false) - val slotsStartX = x + PADDING - val slotsStartY = y + TITLE_HEIGHT + val slotsStartX = x + Padding + val slotsStartY = y + TitleHeight val actualMouseX = (mc.mouse.x * mc.window.scaledWidth / mc.window.width).toInt() val actualMouseY = (mc.mouse.y * mc.window.scaledHeight / mc.window.height).toInt() @@ -208,19 +207,19 @@ object ContainerPreview : Module( var hoveredSlotY = 0 for ((index, item) in contents.withIndex()) { - if (index >= COLS * ROWS) break + if (index >= Cols * Rows) break - val slotCol = index % COLS - val slotRow = index / COLS + val slotCol = index % Cols + val slotRow = index / Cols - val slotX = slotsStartX + slotCol * SLOT_SIZE - val slotY = slotsStartY + slotRow * SLOT_SIZE + val slotX = slotsStartX + slotCol * SlotSize + val slotY = slotsStartY + slotRow * SlotSize val itemX = slotX + 1 val itemY = slotY + 1 if (allowHover) { - val isHovered = actualMouseX >= slotX && actualMouseX < slotX + SLOT_SIZE && - actualMouseY >= slotY && actualMouseY < slotY + SLOT_SIZE + val isHovered = actualMouseX >= slotX && actualMouseX < slotX + SlotSize && + actualMouseY >= slotY && actualMouseY < slotY + SlotSize if (isHovered && !item.isEmpty) { context.fill(itemX, itemY, itemX + 16, itemY + 16, 0x80FFFFFF.toInt()) @@ -312,21 +311,21 @@ object ContainerPreview : Module( background, x, y, 0f, 0f, - width, TITLE_HEIGHT, - width, TITLE_HEIGHT, + width, TitleHeight, + width, TitleHeight, 256, 256, tintColor ) // Middle rows - (0 until ROWS).forEach { row -> + (0 until Rows).forEach { row -> context.drawTexture( RenderPipelines.GUI_TEXTURED, background, - x, y + TITLE_HEIGHT + row * SLOT_SIZE, + x, y + TitleHeight + row * SlotSize, 0f, 17f, - width, SLOT_SIZE, - width, SLOT_SIZE, + width, SlotSize, + width, SlotSize, 256, 256, tintColor ) @@ -336,10 +335,10 @@ object ContainerPreview : Module( context.drawTexture( RenderPipelines.GUI_TEXTURED, background, - x, y + TITLE_HEIGHT + ROWS * SLOT_SIZE, + x, y + TitleHeight + Rows * SlotSize, 0f, 160f, - width, PADDING, - width, PADDING, + width, Padding, + width, Padding, 256, 256, tintColor ) @@ -428,11 +427,6 @@ object ContainerPreview : Module( } } - enum class Group(override val displayName: String, override val description: String) : NamedEnum, Describable { - ContentPreview("Preview", "Settings related to the item preview rendered on container items in inventories"), - ContainerTooltip("Container", "Settings related to container tooltip previews") - } - open class ContainerComponent(val stack: ItemStack) : TooltipData, TooltipComponent { override fun drawItems(textRenderer: TextRenderer, x: Int, y: Int, width: Int, height: Int, context: DrawContext) {} override fun getHeight(textRenderer: TextRenderer): Int = 0 diff --git a/src/main/kotlin/com/lambda/module/modules/render/ESP.kt b/src/main/kotlin/com/lambda/module/modules/render/ESP.kt index ce92d6e79..0f6381fd7 100644 --- a/src/main/kotlin/com/lambda/module/modules/render/ESP.kt +++ b/src/main/kotlin/com/lambda/module/modules/render/ESP.kt @@ -17,11 +17,15 @@ package com.lambda.module.modules.render -import com.lambda.config.applyEdits -import com.lambda.config.groups.EntityColorSettings -import com.lambda.config.groups.EntitySelectionSettings -import com.lambda.config.groups.OutlineSettings -import com.lambda.config.groups.WorldLineSettings +import com.lambda.config.SettingEditor.forEachSetting +import com.lambda.config.SettingEditor.hide +import com.lambda.config.Group +import com.lambda.config.Tab +import com.lambda.config.settings.blocks.EntityColorSettings +import com.lambda.config.settings.blocks.EntitySelectionSettings +import com.lambda.config.settings.blocks.OutlineSettings +import com.lambda.config.settings.blocks.WorldLineSettings +import com.lambda.config.withEdits import com.lambda.graphics.mc.RenderBuilder import com.lambda.graphics.mc.renderer.ImmediateRenderer.Companion.immediateRenderer import com.lambda.graphics.util.DynamicAABB.Companion.interpolatedBox @@ -35,44 +39,52 @@ import net.minecraft.entity.Entity import net.minecraft.util.math.Box import java.awt.Color +@Suppress("unused") object ESP : Module( name = "ESP", description = "Highlight entities with smooth interpolated rendering", - tag = ModuleTag.RENDER + tag = ModuleTag.Render ) { - private enum class Group(override val displayName: String) : NamedEnum { - General("General"), - Shader("Shader"), - Box("Box"), -// Frame("Frame"), - Entities("Entities"), - Colors("Colors") + private enum class EspMode { + Shader, + Box, + //ToDo: Implement +// Frame } + private const val GeneralTab = "General" + private const val EntitiesTab = "Entities" + private const val ColorsTab = "Colors" + + private const val BoxOutlineGroup = "Outline" + private enum class BoxGroup(override val displayName: String) : NamedEnum { Fill("Fill"), Outline("Outline") } - private val mode by setting("Mode", EspMode.Shader).group(Group.General) - private val depthTest by setting("Depth Test", false, "Blend ESP renders into the world").group(Group.General) + @Tab(GeneralTab) private val mode by setting("Mode", EspMode.Shader) + @Tab(GeneralTab) private val depthTest by setting("Depth Test", false, "Blend ESP renders into the world") - private val outlineStyle = OutlineSettings(this, Group.Shader) { mode == EspMode.Shader } + //Shader Outline + @Tab(GeneralTab) private val outlineStyle by configBlock(OutlineSettings(this)) + .withEdits { forEachSetting { visibility { old -> { old() && mode == EspMode.Shader } } } } - private var drawFilled: Boolean by setting("Box Fill", true, "Fill entity boxes") { mode == EspMode.Box }.group(Group.Box, BoxGroup.Fill) + //Box + @Tab(GeneralTab) private var drawFilled: Boolean by setting("Box Fill", true, "Fill entity boxes") { mode == EspMode.Box } .onValueChange { _, to -> if (!to && !drawOutline) drawOutline = true } - private var drawOutline: Boolean by setting("Box Outline", true, "Draw box outlines") { mode == EspMode.Box }.group(Group.Box, BoxGroup.Outline, WorldLineSettings.Group.General) + @Tab(GeneralTab) private val fillAlpha by setting("Filled Alpha", 0.2, 0.0..1.0, 0.05) { mode == EspMode.Box && drawFilled } + @Tab(GeneralTab) @Group(BoxOutlineGroup) private var drawOutline: Boolean by setting("Box Outline", true, "Draw box outlines") { mode == EspMode.Box } .onValueChange { _, to -> if (!to && !drawFilled) drawFilled = true } - private val boxOutlineSettings = WorldLineSettings(this, Group.Box, BoxGroup.Outline) { mode == EspMode.Box && drawOutline }.apply { - applyEdits { + @Tab(GeneralTab) @Group(BoxOutlineGroup) private val outlineAlpha by setting("Outline Alpha", 0.8, 0.0..1.0, 0.05) { mode == EspMode.Box && drawOutline } + @Tab(GeneralTab) @Group(BoxOutlineGroup) private val boxOutlineSettings by configBlock(WorldLineSettings(this)) + .withEdits { + forEachSetting { visibility { old -> { old() && mode == EspMode.Box && drawOutline } } } hide(::startColor, ::endColor) } - } - private val fillAlpha by setting("Filled Alpha", 0.2, 0.0..1.0, 0.05) { mode == EspMode.Box && drawFilled }.group(Group.Box) - private val outlineAlpha by setting("Outline Alpha", 0.8, 0.0..1.0, 0.05) { mode == EspMode.Box && drawOutline }.group(Group.Box) - private val entitySettings = EntitySelectionSettings(this, Group.Entities) - private val entityColors = EntityColorSettings(this, Group.Colors) + @Tab(EntitiesTab) private val entitySettings by configBlock(EntitySelectionSettings(this)) + @Tab(ColorsTab) private val entityColors by configBlock(EntityColorSettings(this)) init { immediateRenderer("EntityESP Immediate Renderer", depthTest = { depthTest }) { @@ -127,11 +139,4 @@ object ESP : Module( } } } - - private enum class EspMode { - Shader, - Box, - //ToDo: Implement -// Frame - } } diff --git a/src/main/kotlin/com/lambda/module/modules/render/ExtraTab.kt b/src/main/kotlin/com/lambda/module/modules/render/ExtraTab.kt index d70c37a5a..86382324f 100644 --- a/src/main/kotlin/com/lambda/module/modules/render/ExtraTab.kt +++ b/src/main/kotlin/com/lambda/module/modules/render/ExtraTab.kt @@ -24,7 +24,7 @@ import java.awt.Color object ExtraTab : Module( name = "ExtraTab", description = "Adds more tabs to the main menu", - tag = ModuleTag.RENDER, + tag = ModuleTag.Render, ) { @JvmStatic val tabEntries by setting("Tab Entries", 80L, 1L..500L, 1L) @JvmStatic val rows by setting("Rows", 20, 1..100, 1) diff --git a/src/main/kotlin/com/lambda/module/modules/render/FreeLook.kt b/src/main/kotlin/com/lambda/module/modules/render/FreeLook.kt index a67af3e35..b64587d97 100644 --- a/src/main/kotlin/com/lambda/module/modules/render/FreeLook.kt +++ b/src/main/kotlin/com/lambda/module/modules/render/FreeLook.kt @@ -31,20 +31,20 @@ import net.minecraft.client.option.Perspective object FreeLook : Module( name = "FreeLook", description = "Allows you to look around freely while moving", - tag = ModuleTag.PLAYER, + tag = ModuleTag.Player, autoDisable = true ) { @JvmStatic val enableYaw by setting("Enable Yaw", false, "Don't effect pitch if enabled") @JvmStatic val enablePitch by setting("Enable Pitch", false, "Don't effect yaw if enabled") val togglePerspective by setting("Toggle Perspective", true, "Toggle perspective when enabling FreeLook") - var camera: Rotation = Rotation.ZERO + var camera: Rotation = Rotation.Zero var previousPerspective: Perspective = mc.options.perspective /** * @see net.minecraft.entity.Entity.changeLookDirection */ - private const val SENSITIVITY_FACTOR = 0.15 + private const val SensitivityFactor = 0.15 @JvmStatic fun updateCam() { @@ -69,8 +69,8 @@ object FreeLook : Module( if (!isEnabled) return@listen camera = camera.withDelta( - it.deltaYaw * SENSITIVITY_FACTOR, - it.deltaPitch * SENSITIVITY_FACTOR + it.deltaYaw * SensitivityFactor, + it.deltaPitch * SensitivityFactor ) if (enableYaw) RotationManager.setPlayerYaw(camera.yaw) diff --git a/src/main/kotlin/com/lambda/module/modules/render/Freecam.kt b/src/main/kotlin/com/lambda/module/modules/render/Freecam.kt index 959dd43ce..aa39a8b91 100644 --- a/src/main/kotlin/com/lambda/module/modules/render/Freecam.kt +++ b/src/main/kotlin/com/lambda/module/modules/render/Freecam.kt @@ -18,8 +18,10 @@ package com.lambda.module.modules.render import com.lambda.Lambda.mc -import com.lambda.config.AutomationConfig.Companion.setDefaultAutomationConfig -import com.lambda.config.applyEdits +import com.lambda.config.SettingEditor.edit +import com.lambda.config.SettingEditor.hideAllBlocksExcept +import com.lambda.config.automation.AutomationConfig.Companion.setDefaultAutomationConfig +import com.lambda.config.withEdits import com.lambda.context.SafeContext import com.lambda.event.events.MovementEvent import com.lambda.event.events.PlayerEvent @@ -29,7 +31,6 @@ import com.lambda.event.listener.SafeListener.Companion.listen import com.lambda.interaction.managers.rotating.IRotationRequest.Companion.rotationRequest import com.lambda.interaction.managers.rotating.Rotation import com.lambda.interaction.managers.rotating.RotationMode -import com.lambda.interaction.managers.rotating.visibilty.lookAt import com.lambda.module.Module import com.lambda.module.tag.ModuleTag import com.lambda.threading.runSafe @@ -51,6 +52,7 @@ import com.lambda.util.player.MovementUtils.newMovementInput import com.lambda.util.player.MovementUtils.roundedForward import com.lambda.util.player.MovementUtils.roundedStrafing import com.lambda.util.player.MovementUtils.verticalMovement +import com.lambda.util.player.RotationUtils.lookAt import com.lambda.util.world.raycast.RayCastUtils.orMiss import net.minecraft.client.network.ClientPlayerEntity import net.minecraft.client.option.Perspective @@ -69,7 +71,7 @@ import kotlin.math.sign object Freecam : Module( name = "Freecam", description = "Move your camera freely", - tag = ModuleTag.RENDER, + tag = ModuleTag.Render, autoDisable = true, ) { private val mode by setting("Mode", Mode.Free, "Freecam movement mode") @@ -84,7 +86,6 @@ object Freecam : Module( private val followMaxDistance by setting("String Length", 10.0, 2.0..50.0, 0.5, "Maximum distance before the string pulls the camera", unit = "m") { mode == Mode.FollowPlayer } private val followTrackPlayer by setting("Track Player", false, "Keeps looking at the followed player") { mode == Mode.FollowPlayer } - private var lastPerspective = Perspective.FIRST_PERSON private var lastPlayerPosition: Vec3d = Vec3d.ZERO private var prevPosition: Vec3d = Vec3d.ZERO @@ -95,7 +96,7 @@ object Freecam : Module( return prevPosition.interpolate(tickProgress, position) } - private var rotation: Rotation = Rotation.ZERO + private var rotation: Rotation = Rotation.Zero private var velocity: Vec3d = Vec3d.ZERO @JvmStatic @@ -119,17 +120,14 @@ object Freecam : Module( /** * @see net.minecraft.entity.Entity.changeLookDirection */ - private const val SENSITIVITY_FACTOR = 0.15 + private const val SensitivityFactor = 0.15 init { - setDefaultAutomationConfig { - applyEdits { - rotationConfig::rotationMode.edit { - defaultValue(RotationMode.Lock) - } - hideAllGroupsExcept(rotationConfig) + setDefaultAutomationConfig() + .withEdits { + rotationConfig::rotationMode.edit { defaultValue(RotationMode.Lock) } + hideAllBlocksExcept(::rotationConfig) } - } onEnable { lastPerspective = mc.options.perspective @@ -152,7 +150,7 @@ object Freecam : Module( } listen { - rotation = rotation.withDelta(it.deltaYaw * SENSITIVITY_FACTOR, it.deltaPitch * SENSITIVITY_FACTOR) + rotation = rotation.withDelta(it.deltaYaw * SensitivityFactor, it.deltaPitch * SensitivityFactor) it.cancel() } diff --git a/src/main/kotlin/com/lambda/module/modules/render/Fullbright.kt b/src/main/kotlin/com/lambda/module/modules/render/Fullbright.kt index 9897e4504..6a1828d52 100644 --- a/src/main/kotlin/com/lambda/module/modules/render/Fullbright.kt +++ b/src/main/kotlin/com/lambda/module/modules/render/Fullbright.kt @@ -28,7 +28,7 @@ import net.minecraft.entity.effect.StatusEffects object Fullbright : Module( name = "Fullbright", description = "Makes everything brighter", - tag = ModuleTag.RENDER, + tag = ModuleTag.Render, ) { private val nightVision by setting("Night Vision", false, description = "Adds the night vision effect client-side") .onValueChange { _, to -> setNightVision(to) } diff --git a/src/main/kotlin/com/lambda/module/modules/render/LightLevels.kt b/src/main/kotlin/com/lambda/module/modules/render/LightLevels.kt index fd9feadfc..dcd602154 100644 --- a/src/main/kotlin/com/lambda/module/modules/render/LightLevels.kt +++ b/src/main/kotlin/com/lambda/module/modules/render/LightLevels.kt @@ -17,8 +17,11 @@ package com.lambda.module.modules.render -import com.lambda.config.applyEdits -import com.lambda.config.groups.WorldLineSettings +import com.lambda.config.SettingEditor.forEachSetting +import com.lambda.config.SettingEditor.hide +import com.lambda.config.Group +import com.lambda.config.settings.blocks.WorldLineSettings +import com.lambda.config.withEdits import com.lambda.context.SafeContext import com.lambda.graphics.mc.LineDashStyle import com.lambda.graphics.mc.RenderBuilder @@ -28,7 +31,6 @@ import com.lambda.module.Module import com.lambda.module.tag.ModuleTag import com.lambda.threading.runSafe import com.lambda.util.BlockUtils.blockState -import com.lambda.util.NamedEnum import com.lambda.util.math.flooredBlockPos import com.lambda.util.math.setAlpha import com.lambda.util.math.vec3d @@ -40,17 +42,14 @@ import net.minecraft.util.math.BlockPos import net.minecraft.util.math.Direction import net.minecraft.world.LightType import java.awt.Color -import kotlin.collections.forEach object LightLevels : Module( name = "LightLevels", description = "Shows light level. Helpful for mob-proofing areas", - tag = ModuleTag.RENDER + tag = ModuleTag.Render ) { - private enum class Group(override val displayName: String) : NamedEnum { - Fill("Fill"), - Line("Line") - } + private const val FillGroup = "Fill" + private const val LineGroup = "Line" private val mode: Mode by setting("Mode", Mode.Chunked) .onValueChange { _, _ -> chunkedRenderer.clear(); refreshChunkedRenderer(this) } @@ -60,15 +59,17 @@ object LightLevels : Module( private val skyLightColor by setting("Sky Light Color", Color.YELLOW).onValueChange(::refreshChunkedRenderer) private val blockLightColor by setting("Block Light Color", Color.RED).onValueChange(::refreshChunkedRenderer) private val size by setting("Size", 14, 1..16).onValueChange(::refreshChunkedRenderer) - private val fill by setting("Fill", false) { renderMode == RenderMode.Square }.group(Group.Fill).onValueChange(::refreshChunkedRenderer) - private val fillAlpha by setting("Fill Alpha", 0.2, 0.0..1.0, 0.01) { renderMode == RenderMode.Square && fill }.group(Group.Fill).onValueChange(::refreshChunkedRenderer) - private val outline by setting("Outline", true) { renderMode == RenderMode.Square }.group(Group.Line, WorldLineSettings.Group.General).onValueChange(::refreshChunkedRenderer) - private val worldLineConfig = WorldLineSettings(this, Group.Line) { renderMode != RenderMode.Square || outline }.apply { - applyEdits { + @Group(FillGroup) private val fill by setting("Fill", false) { renderMode == RenderMode.Square }.onValueChange(::refreshChunkedRenderer) + @Group(FillGroup) private val fillAlpha by setting("Fill Alpha", 0.2, 0.0..1.0, 0.01) { renderMode == RenderMode.Square && fill }.onValueChange(::refreshChunkedRenderer) + @Group(LineGroup) private val outline by setting("Outline", true) { renderMode == RenderMode.Square }.onValueChange(::refreshChunkedRenderer) + @Group(LineGroup) private val worldLineConfig by configBlock(WorldLineSettings(this)) + .withEdits { hide(::startColor, ::endColor) - settings.forEach { it.onValueChange(::refreshChunkedRenderer) } + forEachSetting { + visibility { old -> { old() && renderMode != RenderMode.Square || outline } } + onValueChange(::refreshChunkedRenderer) + } } - } private val depthTest by setting("Depth Test", false, "Shows renders through terrain") private val horizontalRange by setting("Horizontal Range", 16, 1..32) { mode == Mode.Radius } private val verticalRange by setting("Vertical Range", 8, 1..32) { mode == Mode.Radius } @@ -155,6 +156,7 @@ object LightLevels : Module( if (mode == Mode.Chunked) chunkedRenderer.rebuildChunk(x, z) } + @Suppress("unused") private fun refreshChunkedRenderer(ctx: SafeContext, from: Any? = null, to: Any? = null) { if (mode == Mode.Chunked) chunkedRenderer.rebuild() } @@ -170,6 +172,7 @@ object LightLevels : Module( Circle } + @Suppress("unused") private enum class AreaMode(val player: Boolean, val camera: Boolean) { Both(true, true), Camera(false, true), 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 fedeea4cd..16d87f40b 100644 --- a/src/main/kotlin/com/lambda/module/modules/render/MapPreview.kt +++ b/src/main/kotlin/com/lambda/module/modules/render/MapPreview.kt @@ -36,7 +36,7 @@ import net.minecraft.util.Identifier object MapPreview : Module( name = "MapPreview", description = "Preview maps in your inventory", - tag = ModuleTag.RENDER, + tag = ModuleTag.Render, ) { @JvmStatic val showInSlot by setting("Show In Slot", true, "Shows the map in the slot rather than the basic map icon") diff --git a/src/main/kotlin/com/lambda/module/modules/render/Nametags.kt b/src/main/kotlin/com/lambda/module/modules/render/Nametags.kt index a9166d915..9d94f16f1 100644 --- a/src/main/kotlin/com/lambda/module/modules/render/Nametags.kt +++ b/src/main/kotlin/com/lambda/module/modules/render/Nametags.kt @@ -18,10 +18,14 @@ package com.lambda.module.modules.render import com.lambda.Lambda.mc -import com.lambda.config.applyEdits -import com.lambda.config.groups.EntitySelectionSettings -import com.lambda.config.groups.ScreenTextSettings -import com.lambda.friend.FriendManager.isFriend +import com.lambda.config.SettingEditor.edit +import com.lambda.config.SettingEditor.hide +import com.lambda.config.Group +import com.lambda.config.Tab +import com.lambda.config.settings.blocks.EntitySelectionSettings +import com.lambda.config.settings.blocks.ScreenTextSettings +import com.lambda.config.withEdits +import com.lambda.friend.FriendHandler.isFriend import com.lambda.graphics.mc.RenderBuilder import com.lambda.graphics.mc.renderer.ImmediateRenderer.Companion.immediateRenderer import com.lambda.graphics.mc.renderer.RendererUtils.worldToScreenNormalized @@ -30,7 +34,6 @@ import com.lambda.graphics.util.DynamicAABB.Companion.interpolatedBox import com.lambda.module.Module import com.lambda.module.tag.ModuleTag import com.lambda.threading.runSafe -import com.lambda.util.NamedEnum import com.lambda.util.extension.fullHealth import com.lambda.util.extension.maxFullHealth import com.lambda.util.math.MathUtils.roundToStep @@ -50,49 +53,45 @@ import kotlin.math.max object Nametags : Module( name = "Nametags", description = "Displays information about entities above them", - tag = ModuleTag.RENDER + tag = ModuleTag.Render ) { - private enum class Group(override val displayName: String) : NamedEnum { - General("General"), - Entities("Entities"), - Background("Background"), - Text("Text") - } + private const val GeneralTab = "General" + private const val EntityTab = "Entities" + private const val BackgroundTab = "Background" + private const val TextTab = "Text" - private enum class TextGroup(override val displayName: String): NamedEnum { - Other("Other"), - Friend("Friend") - } + @Tab(GeneralTab) private val textSize by setting("Text Size", 18, 1..50, 1) + @Tab(GeneralTab) private val itemScale by setting("Item Scale", 3f, 0.4f..5f, 0.01f) + @Tab(GeneralTab) private val yOffset by setting("Y Offset", 0.2, 0.0..1.0, 0.01) + @Tab(GeneralTab) private val spacing by setting("Spacing", 0, 0..10, 1) + @Tab(GeneralTab) private val health by setting("Health", true) + @Tab(GeneralTab) private val ping by setting("Ping", true) + @Tab(GeneralTab) private val gear by setting("Gear", true) + @Tab(GeneralTab) private val mainItem by setting("Main Item", true) { gear } + @Tab(GeneralTab) private val offhandItem by setting("Offhand Item", true) { gear } +//ToDo: Implement private val enchantments by setting("Enchantments", false) { gear } + @Tab(GeneralTab) private val itemName by setting("Item Name", true) + @Tab(GeneralTab) private val itemNameScale by setting("Item Name Scale", 0.7f, 0.1f..1.0f, 0.01f) { itemName } + @Tab(GeneralTab) private val itemCount by setting("Item Count", true) + @Tab(GeneralTab) private val durabilityMode by setting("Durability Mode", DurabilityMode.Text) { gear } - private val itemScale by setting("Item Scale", 3f, 0.4f..5f, 0.01f).group(Group.General) - private val yOffset by setting("Y Offset", 0.2, 0.0..1.0, 0.01).group(Group.General) - private val spacing by setting("Spacing", 0, 0..10, 1).group(Group.General) - private val health by setting("Health", true).group(Group.General) - private val ping by setting("Ping", true).group(Group.General) - private val gear by setting("Gear", true).group(Group.General) - private val mainItem by setting("Main Item", true) { gear }.group(Group.General) - private val offhandItem by setting("Offhand Item", true) { gear }.group(Group.General) - private val itemName by setting("Item Name", true).group(Group.General) - private val itemNameScale by setting("Item Name Scale", 0.7f, 0.1f..1.0f, 0.01f) { itemName }.group(Group.General) - private val itemCount by setting("Item Count", true).group(Group.General) - private val durabilityMode by setting("Durability Mode", DurabilityMode.Text) { gear }.group(Group.General) - private val entitySelectionSettings = EntitySelectionSettings(this, Group.Entities).apply { - applyEdits { - hide(::blockEntities) - } - } - private val background by setting("Background", true).group(Group.Background) - private val backgroundColor by setting("Background Color", Color(0, 0, 0, 60)) { background }.group(Group.Background) - private val backgroundSize by setting("Background Size", 1.0f, 1.0f..2.0f, 0.01f) { background }.group(Group.Background) - //ToDo: Implement -// private val enchantments by setting("Enchantments", false) { gear } + @Tab(EntityTab) private val entitySelectionSettings by configBlock(EntitySelectionSettings(this)) + .withEdits { hide(::blockEntities) } - private val friendTextConfig = ScreenTextSettings(this, TextGroup.Friend, prefix = "Friend ").apply { - applyEdits { + private const val FriendGroup = "Friends" + private const val OtherGroup = "Others" + + @Tab(TextTab) @Group(FriendGroup) private val friendTextConfig by configBlock(ScreenTextSettings(this)) + .withEdits { + hide(::sizeSetting) ::textColor.edit { defaultValue(Color(0, 255, 255, 255)) } } - } - private val otherTextConfig = ScreenTextSettings(this, TextGroup.Other, prefix = "Other ") + @Tab(TextTab) @Group(OtherGroup) private val otherTextConfig by configBlock(ScreenTextSettings(this)) + .withEdits { hide(::sizeSetting) } + + @Tab(BackgroundTab) private val background by setting("Background", true) + @Tab(BackgroundTab) private val backgroundColor by setting("Background Color", Color(0, 0, 0, 60)) { background } + @Tab(BackgroundTab) private val backgroundSize by setting("Background Size", 1.0f, 1.0f..2.0f, 0.01f) { background } var heightWidthRatio = 0f var trueItemScaleX = 0f @@ -121,9 +120,9 @@ object Nametags : Module( if (entity is PlayerEntity && entity.isFriend) friendTextConfig else otherTextConfig val textStyle = textConfig.getSDFStyle() - val textSize = textConfig.size + val size = textSize * 0.001f val nameText = entity.displayName?.string ?: return@forEach - val nameWidth = FontHandler.getStringWidthNormalized(nameText, textSize) + val nameWidth = FontHandler.getStringWidthNormalized(nameText, size) val box = entity.interpolatedBox val boxCenter = box.center var (anchorX, anchorY) = @@ -134,22 +133,22 @@ object Nametags : Module( if (entity !is LivingEntity) { if (background) { - screenRect(anchorX - halfNameWidth - trueBGSizeX, anchorY - trueBGSizeY, nameWidth + (trueBGSizeX * 2), textSize + (trueBGSizeY * 2), backgroundColor) + screenRect(anchorX - halfNameWidth - trueBGSizeX, anchorY - trueBGSizeY, nameWidth + (trueBGSizeX * 2), size + (trueBGSizeY * 2), backgroundColor) } - screenText(nameText, anchorX, anchorY, textSize, style = textStyle, centered = true) + screenText(nameText, anchorX, anchorY, size, style = textStyle, centered = true) return@forEach } val healthCount = if (health) entity.fullHealth else -1.0 val healthText = if (health) " ${healthCount.roundToStep(0.01)}" else "" val healthWidth = - FontHandler.getStringWidthNormalized(healthText, textSize) + FontHandler.getStringWidthNormalized(healthText, size) .let { if (healthCount > 0) it + trueSpacingX else it } val pingCount = if (ping && entity is PlayerEntity) connection.getPlayerListEntry(entity.uuid)?.latency ?: -1 else -1 val pingText = if (pingCount >= 0) " [$pingCount]" else "" val pingWidth = - FontHandler.getStringWidthNormalized(pingText, textSize) + FontHandler.getStringWidthNormalized(pingText, size) .let { if (pingCount >= 0) it + trueSpacingX else it } var combinedWidth = nameWidth + healthWidth + pingWidth @@ -157,7 +156,7 @@ object Nametags : Module( val itemName = itemName && !entity.mainHandStack.isEmpty val itemNameText = if (itemName) entity.mainHandStack.name.string else "" - val itemNameSize = if (itemName) textSize * itemNameScale else 0f + val itemNameSize = if (itemName) size * itemNameScale else 0f if (background) { anchorY += trueBGSizeY @@ -165,21 +164,21 @@ object Nametags : Module( val maxWidth = if (itemName) max(itemNameWidth, combinedWidth) else combinedWidth - screenRect((anchorX - (maxWidth * 0.5f)) - trueBGSizeX, anchorY - trueBGSizeY, maxWidth + (trueBGSizeX * 2), textSize + itemNameSize + trueSpacingY + (trueBGSizeY * 2), backgroundColor) + screenRect((anchorX - (maxWidth * 0.5f)) - trueBGSizeX, anchorY - trueBGSizeY, maxWidth + (trueBGSizeX * 2), size + itemNameSize + trueSpacingY + (trueBGSizeY * 2), backgroundColor) } if (itemName) { screenText(itemNameText, anchorX, anchorY, itemNameSize, centered = true) anchorY += (itemNameSize * 1.1f) + trueSpacingY } - screenText(nameText, nameX, anchorY, textSize, style = textStyle) + screenText(nameText, nameX, anchorY, size, style = textStyle) if (healthCount >= 0) { val healthColor = lerp(entity.fullHealth / entity.maxFullHealth, Color.RED, Color.GREEN).brighter() - screenText(healthText, nameX + nameWidth + trueSpacingX, anchorY, textSize, style = textStyle.apply { color = healthColor }) + screenText(healthText, nameX + nameWidth + trueSpacingX, anchorY, size, style = textStyle.apply { color = healthColor }) } if (pingCount >= 0) { val pingColor = lerp(pingCount / 500.0, Color.GREEN, Color.RED).brighter() - screenText(pingText, nameX + nameWidth + healthWidth + trueSpacingX, anchorY, textSize, style = textStyle.apply { color = pingColor }) + screenText(pingText, nameX + nameWidth + healthWidth + trueSpacingX, anchorY, size, style = textStyle.apply { color = pingColor }) } if (!gear) return@forEach @@ -187,12 +186,12 @@ object Nametags : Module( if (background) anchorY += trueBGSizeY if (EquipmentSlot.entries.none { it.index in 1..4 && !entity.getEquippedStack(it).isEmpty }) { - anchorY -= textSize * 0.5f + anchorY -= size * 0.5f if (mainItem && !entity.mainHandStack.isEmpty) renderItem(entity.mainHandStack, nameX - trueItemScaleX - trueSpacingX, anchorY) if (offhandItem && !entity.offHandStack.isEmpty) renderItem(entity.offHandStack, anchorX + (combinedWidth * 0.5f) + trueSpacingX, anchorY) - } else drawArmorAndItems(entity, anchorX, anchorY + textSize + trueSpacingY) + } else drawArmorAndItems(entity, anchorX, anchorY + size + trueSpacingY) } } } @@ -247,9 +246,10 @@ object Nametags : Module( @JvmStatic fun shouldRenderNametag(entity: Entity) = - (entity !== mc.player || !mc.options.perspective.isFirstPerson) && + (entity !== mc.player || !mc.options.perspective.isFirstPerson || Freecam.isEnabled) && entitySelectionSettings.isSelected(entity) && (entity !is LivingEntity || entity.isAlive) + @Suppress("unused") private enum class DurabilityMode(val text: Boolean, val bar: Boolean) { None(false, false), Text(true, false), 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 5125d4321..9c97cc621 100644 --- a/src/main/kotlin/com/lambda/module/modules/render/NoRender.kt +++ b/src/main/kotlin/com/lambda/module/modules/render/NoRender.kt @@ -17,13 +17,14 @@ package com.lambda.module.modules.render -import com.lambda.config.applyEdits -import com.lambda.config.groups.EntitySelectionSettings +import com.lambda.config.SettingEditor.editTyped +import com.lambda.config.Tab +import com.lambda.config.settings.blocks.EntitySelectionSettings +import com.lambda.config.withEdits import com.lambda.module.Module import com.lambda.module.tag.ModuleTag import com.lambda.util.EntityUtils.createNameMap -import com.lambda.util.NamedEnum -import com.lambda.util.reflections.scanResult +import com.lambda.util.ReflectionUtils.scanResult import net.minecraft.block.entity.BlockEntity import net.minecraft.client.particle.Particle import net.minecraft.entity.Entity @@ -32,65 +33,60 @@ import net.minecraft.entity.Entity object NoRender : Module( name = "NoRender", description = "Disables rendering of certain things", - tag = ModuleTag.RENDER, + tag = ModuleTag.Render, ) { private val particleMap = createParticleNameMap() - private enum class Group(override val displayName: String) : NamedEnum { - Hud("Hud"), - Entity("Entity"), - World("World"), - Effect("Effect") - } + private const val EffectTab = "Effect" + private const val HudTab = "Hud" + private const val EntityTab = "Entity" + private const val WorldTab = "World" - @JvmStatic val noBlindness by setting("No Blindness", true).group(Group.Effect) - @JvmStatic val noDarkness by setting("No Darkness", true).group(Group.Effect) - @JvmStatic val noNausea by setting("No Nausea", true).group(Group.Effect) + @Tab(EffectTab) @JvmStatic val noBlindness by setting("No Blindness", true) + @Tab(EffectTab) @JvmStatic val noDarkness by setting("No Darkness", true) + @Tab(EffectTab) @JvmStatic val noNausea by setting("No Nausea", true) - @JvmStatic val noFireOverlay by setting("No Fire Overlay", false).group(Group.Hud) - @JvmStatic val fireOverlayYOffset by setting("Fire Overlay Y Offset", 0.0, -0.4..0.4, 0.02) { !noFireOverlay }.group(Group.Hud) - @JvmStatic val noPortalOverlay by setting("No Portal Overlay", true).group(Group.Hud) - @JvmStatic val noFluidOverlay by setting("No Fluid Overlay", true).group(Group.Hud) - @JvmStatic val noPowderedSnowOverlay by setting("No Powdered Snow Overlay", true).group(Group.Hud) - @JvmStatic val noInWall by setting("No In Wall Overlay", true).group(Group.Hud) - @JvmStatic val noPumpkinOverlay by setting("No Pumpkin Overlay", true).group(Group.Hud) - @JvmStatic val noVignette by setting("No Vignette", true).group(Group.Hud) - @JvmStatic val noChatVerificationToast by setting("No Chat Verification Toast", true).group(Group.Hud) - @JvmStatic val noSpyglassOverlay by setting("No Spyglass Overlay", false).group(Group.Hud) - @JvmStatic val noGuiShadow by setting("No Gui Shadow", false).group(Group.Hud) - @JvmStatic val noFloatingItemAnimation by setting("No Floating Item Animation", false, "Disables floating item animations, typically used when a totem pops").group(Group.Hud) - @JvmStatic val noCrosshair by setting("No Crosshair", false).group(Group.Hud) - @JvmStatic val noBossBar by setting("No Boss Bar", false).group(Group.Hud) - @JvmStatic val noScoreBoard by setting("No Score Board", false).group(Group.Hud) - @JvmStatic val noStatusEffects by setting("No Status Effects", false).group(Group.Hud) - @JvmStatic val no2b2tActionText by setting("No 2b2t Action Text", true, description = "Blocks the '2b2t.org' text from the action bar 2b2t randomly sends").group(Group.Hud) + @Tab(HudTab) @JvmStatic val noFireOverlay by setting("No Fire Overlay", false) + @Tab(HudTab) @JvmStatic val fireOverlayYOffset by setting("Fire Overlay Y Offset", 0.0, -0.4..0.4, 0.02) { !noFireOverlay } + @Tab(HudTab) @JvmStatic val noPortalOverlay by setting("No Portal Overlay", true) + @Tab(HudTab) @JvmStatic val noFluidOverlay by setting("No Fluid Overlay", true) + @Tab(HudTab) @JvmStatic val noPowderedSnowOverlay by setting("No Powdered Snow Overlay", true) + @Tab(HudTab) @JvmStatic val noInWall by setting("No In Wall Overlay", true) + @Tab(HudTab) @JvmStatic val noPumpkinOverlay by setting("No Pumpkin Overlay", true) + @Tab(HudTab) @JvmStatic val noVignette by setting("No Vignette", true) + @Tab(HudTab) @JvmStatic val noChatVerificationToast by setting("No Chat Verification Toast", true) + @Tab(HudTab) @JvmStatic val noSpyglassOverlay by setting("No Spyglass Overlay", false) + @Tab(HudTab) @JvmStatic val noGuiShadow by setting("No Gui Shadow", false) + @Tab(HudTab) @JvmStatic val noFloatingItemAnimation by setting("No Floating Item Animation", false, "Disables floating item animations, typically used when a totem pops") + @Tab(HudTab) @JvmStatic val noCrosshair by setting("No Crosshair", false) + @Tab(HudTab) @JvmStatic val noBossBar by setting("No Boss Bar", false) + @Tab(HudTab) @JvmStatic val noScoreBoard by setting("No Score Board", false) + @Tab(HudTab) @JvmStatic val noStatusEffects by setting("No Status Effects", false) + @Tab(HudTab) @JvmStatic val no2b2tActionText by setting("No 2b2t Action Text", true, description = "Blocks the '2b2t.org' text from the action bar 2b2t randomly sends") - @JvmStatic val noArmor by setting("No Armor", false).group(Group.Entity) - @JvmStatic val includeNoOtherHeadItems by setting("Include No Other Head Items", false) { noArmor }.group(Group.Entity) - @JvmStatic val noElytra by setting("No Elytra", false).group(Group.Entity) - @JvmStatic val noInvisibility by setting("No Invisibility", true).group(Group.Entity) - @JvmStatic val noGlow by setting("No Glow", false).group(Group.Entity) - @JvmStatic val noNametags by setting("No Nametags", false).group(Group.Entity) + @Tab(EntityTab) @JvmStatic val noArmor by setting("No Armor", false) + @Tab(EntityTab) @JvmStatic val includeNoOtherHeadItems by setting("Include No Other Head Items", false) { noArmor } + @Tab(EntityTab) @JvmStatic val noElytra by setting("No Elytra", false) + @Tab(EntityTab) @JvmStatic val noInvisibility by setting("No Invisibility", true) + @Tab(EntityTab) @JvmStatic val noGlow by setting("No Glow", false) + @Tab(EntityTab) @JvmStatic val noNametags by setting("No Nametags", false) // RenderLayer.getArmorEntityGlint(), RenderLayer.getGlint(), RenderLayer.getGlintTranslucent(), RenderLayer.getEntityGlint() // @JvmStatic val noEnchantmentGlint by setting("No Enchantment Glint", false).group(Group.Entity) // @JvmStatic val noDeadEntities by setting("No Dead Entities", false).group(Group.Entity) - private val entitySettings = EntitySelectionSettings(this, Group.Entity).apply { - applyEdits { - editTyped(::playerEntities, ::mobEntities, ::bossEntities) { - defaultValue(mutableSetOf()) - } + @Tab(EntityTab) private val entitySettings by configBlock(EntitySelectionSettings(this)) + .withEdits { + editTyped(::playerEntities, ::mobEntities, ::bossEntities) { defaultValue(mutableSetOf()) } } - } - @JvmStatic val noTerrainFog by setting("No Terrain Fog", false).group(Group.World) - @JvmStatic val noSignText by setting("No Sign Text", false).group(Group.World) - @JvmStatic val noWorldBorder by setting("No World Border", false).group(Group.World) - @JvmStatic val noEnchantingTableBook by setting("No Enchanting Table Book", false).group(Group.World) + @Tab(WorldTab) @JvmStatic val noTerrainFog by setting("No Terrain Fog", false) + @Tab(WorldTab) @JvmStatic val noSignText by setting("No Sign Text", false) + @Tab(WorldTab) @JvmStatic val noWorldBorder by setting("No World Border", false) + @Tab(WorldTab) @JvmStatic val noEnchantingTableBook by setting("No Enchanting Table Book", false) // Couldn't get to work with block entities without crashing with sodium on boot // @JvmStatic val noBlockBreakingOverlay by setting("No Block Breaking Overlay", false).group(Group.World) - @JvmStatic val noBeaconBeams by setting("No Beacon Beams", false).group(Group.World) - @JvmStatic val noSpawnerMob by setting("No Spawner Mob", false).group(Group.World) - private val particles by setting("Particles", emptySet(), particleMap.values.toSet(), "Particles to omit from rendering").group(Group.World) + @Tab(WorldTab) @JvmStatic val noBeaconBeams by setting("No Beacon Beams", false) + @Tab(WorldTab) @JvmStatic val noSpawnerMob by setting("No Spawner Mob", false) + @Tab(WorldTab) private val particles by setting("Particles", emptySet(), particleMap.values.toSet(), "Particles to omit from rendering") private fun createParticleNameMap() = scanResult diff --git a/src/main/kotlin/com/lambda/module/modules/render/RadiusESP.kt b/src/main/kotlin/com/lambda/module/modules/render/RadiusESP.kt index f5ef040b0..25a195865 100644 --- a/src/main/kotlin/com/lambda/module/modules/render/RadiusESP.kt +++ b/src/main/kotlin/com/lambda/module/modules/render/RadiusESP.kt @@ -17,8 +17,11 @@ package com.lambda.module.modules.render -import com.lambda.config.applyEdits -import com.lambda.config.groups.WorldLineSettings +import com.lambda.config.SettingEditor.forEachSetting +import com.lambda.config.SettingEditor.hide +import com.lambda.config.Group +import com.lambda.config.settings.blocks.WorldLineSettings +import com.lambda.config.withEdits import com.lambda.context.SafeContext import com.lambda.graphics.mc.RenderBuilder import com.lambda.graphics.mc.renderer.ChunkedRenderer.Companion.chunkedRenderer @@ -27,7 +30,6 @@ import com.lambda.module.Module import com.lambda.module.tag.ModuleTag import com.lambda.threading.runSafe import com.lambda.util.BlockUtils.blockState -import com.lambda.util.NamedEnum import com.lambda.util.math.setAlpha import com.lambda.util.world.toBlockPos import net.minecraft.block.Blocks @@ -35,37 +37,33 @@ import net.minecraft.block.entity.BeaconBlockEntity import net.minecraft.util.math.Box import java.awt.Color +@Suppress("unused") object RadiusESP : Module( name = "RadiusESP", description = "Shows the radius for blocks with abnormal functionality", - tag = ModuleTag.RENDER + tag = ModuleTag.Render ) { - private enum class Group(override val displayName: String) : NamedEnum { - Blocks("Blocks"), - Render("Render") - } - - private enum class RenderGroup(override val displayName: String) : NamedEnum { - General("General"), - Outline("Outline") - } + private const val RenderGroup = "Render" + private const val OutlineGroup = "Outline" - private val beacons by setting("Beacons", true).group(Group.Blocks).onValueChange(::rebuildMesh) - private val spawners by setting("Spawners", true).group(Group.Blocks).onValueChange(::rebuildMesh) + private val beacons by setting("Beacons", true).onValueChange(::rebuildMesh) + private val spawners by setting("Spawners", true).onValueChange(::rebuildMesh) - private val beaconColor by setting("Beacon Color", Color(0, 255, 255, 255)) { beacons }.group(Group.Render, RenderGroup.General).onValueChange(::rebuildMesh) - private val spawnerColor by setting("Spawner Color", Color(255, 0, 0, 255)) { spawners }.group(Group.Render, RenderGroup.General).onValueChange(::rebuildMesh) - private var fill: Boolean by setting("Fill", true).group(Group.Render, RenderGroup.General).onValueChange(::rebuildMesh) + @Group(RenderGroup) private val beaconColor by setting("Beacon Color", Color(0, 255, 255, 255)) { beacons }.onValueChange(::rebuildMesh) + @Group(RenderGroup) private val spawnerColor by setting("Spawner Color", Color(255, 0, 0, 255)) { spawners }.onValueChange(::rebuildMesh) + @Group(RenderGroup) private var fill: Boolean by setting("Box Fill", true).onValueChange(::rebuildMesh) .onValueChange { _, to -> if (!to) outline = true } - private var outline: Boolean by setting("Outline", true).group(Group.Render, RenderGroup.General).onValueChange(::rebuildMesh) + @Group(RenderGroup) private var outline: Boolean by setting("Box Outline", true).onValueChange(::rebuildMesh) .onValueChange { _, to -> if (!to) fill = true } - private val fillAlpha by setting("Fill Alpha", 0.1, 0.0..1.0, 0.01).group(Group.Render, RenderGroup.General).onValueChange(::rebuildMesh) - private val worldLineConfig = WorldLineSettings(this, Group.Render, RenderGroup.Outline) { outline }.apply { - applyEdits { + @Group(RenderGroup) private val fillAlpha by setting("Fill Alpha", 0.1, 0.0..1.0, 0.01).onValueChange(::rebuildMesh) + @Group(RenderGroup, OutlineGroup) private val worldLineConfig by configBlock(WorldLineSettings(this)) + .withEdits { hide(::startColor, ::endColor) - settings.forEach { it.onValueChange(::rebuildMesh) } + forEachSetting { + visibility { old -> { old() && outline } } + onValueChange(::rebuildMesh) + } } - } private val chunkedRenderer = chunkedRenderer("RadiusESP Chunked Renderer") { pos -> runSafe { diff --git a/src/main/kotlin/com/lambda/module/modules/render/Search.kt b/src/main/kotlin/com/lambda/module/modules/render/Search.kt index e944ef11a..10378d419 100644 --- a/src/main/kotlin/com/lambda/module/modules/render/Search.kt +++ b/src/main/kotlin/com/lambda/module/modules/render/Search.kt @@ -17,11 +17,15 @@ package com.lambda.module.modules.render -import com.lambda.config.applyEdits -import com.lambda.config.groups.ScreenLineSettings -import com.lambda.config.groups.WorldLineSettings +import com.lambda.config.SettingEditor.editTyped +import com.lambda.config.SettingEditor.forEachSetting +import com.lambda.config.SettingEditor.hide +import com.lambda.config.Group +import com.lambda.config.settings.blocks.ScreenLineSettings +import com.lambda.config.settings.blocks.WorldLineSettings import com.lambda.config.settings.collections.CollectionSetting.Companion.onDeselect import com.lambda.config.settings.collections.CollectionSetting.Companion.onSelect +import com.lambda.config.withEdits import com.lambda.context.SafeContext import com.lambda.graphics.mc.RenderBuilder import com.lambda.graphics.mc.renderer.ChunkedRenderer.Companion.chunkedRenderer @@ -36,7 +40,6 @@ import com.lambda.threading.runSafe import com.lambda.util.BlockUtils.blockState import com.lambda.util.EntityUtils.decorationEntityMap import com.lambda.util.EntityUtils.entityGroup -import com.lambda.util.NamedEnum import com.lambda.util.extension.blockColor import com.lambda.util.extension.entityColor import com.lambda.util.extension.getBlockState @@ -51,114 +54,115 @@ import net.minecraft.util.math.Vec3d import java.awt.Color import java.util.concurrent.ConcurrentHashMap +@Suppress("unused") object Search : Module( - name = "Search", - description = "Highlight blocks within the rendered world", - tag = ModuleTag.RENDER, + name = "Search", + description = "Highlight blocks within the rendered world", + tag = ModuleTag.Render, ) { - private enum class Group(override val displayName: String) : NamedEnum { - General("General"), - Fill("Fill"), - Outline("Outline"), - Tracers("Tracers") - } - - private val blocks by setting("Blocks", setOf(Blocks.CHEST, Blocks.ENDER_CHEST, Blocks.NETHER_PORTAL, Blocks.END_PORTAL, Blocks.END_PORTAL_FRAME, Blocks.END_GATEWAY), description = "Render blocks").group(Group.General) - .onSelect { rebuildMesh(this) }.onDeselect { rebuildMesh(this) } - private val entities by setting("Entities", decorationEntityMap.values).group(Group.General) - .onSelect { rebuildMesh(this) }.onDeselect { rebuildMesh(this) } - - private var fill: Boolean by setting("Fill", true, "Fill the faces of blocks").group(Group.Fill).onValueChange(::rebuildMesh) - .onValueChange { _, to -> if (!to) outline = true } - private var outline: Boolean by setting("Outline", true, "Draw the outlines of blocks").group(Group.Outline).onValueChange(::rebuildMesh) - .onValueChange { _, to -> if (!to) fill = true } - private val mesh by setting("Mesh", true, "Connect similar adjacent blocks").group(Group.General).onValueChange(::rebuildMesh) - - private val useNaturalColor by setting("Use Natural Color", true, "Use the color of the block instead").group(Group.General).onValueChange(::rebuildMesh) - private val naturalColorAlpha by setting("Natural Color Alpha", 0.3, 0.1..1.0, 0.05) { useNaturalColor }.group(Group.General).onValueChange(::rebuildMesh) - private val naturalTracerAlpha by setting("Natural Tracer Alpha", 1.0, 0.1..1.0, 0.05) { useNaturalColor }.group(Group.General).onValueChange(::rebuildMesh) - private val minimumNaturalBrightness by setting("Min Brightness", 150, 0..255, 1) { useNaturalColor }.group(Group.General).onValueChange(::rebuildMesh) - - private val blockFillColor by setting("Block Fill Color", Color(100, 150, 255, 51), "Color of the surfaces") { fill && !useNaturalColor }.group(Group.Fill).onValueChange(::rebuildMesh) - private val blockLineColor by setting("Block Line Color", Color(100, 150, 255, 128)) { outline && !useNaturalColor }.group(Group.Outline).onValueChange(::rebuildMesh) - private val entityFillColor by setting("Entity Fill Color", Color(100, 150, 255, 51)) { fill && !useNaturalColor }.group(Group.Fill).onValueChange(::rebuildMesh) - private val entityOutlineColor by setting("Entity Outline Color", Color(100, 150, 255, 128)) { outline && !useNaturalColor }.group(Group.Outline).onValueChange(::rebuildMesh) - - private val blockOutlineMode by setting("Block Outline Mode", DirectionMask.OutlineMode.And, "Outline mode") { outline }.group(Group.Outline, WorldLineSettings.Group.General).onValueChange(::rebuildMesh) - private val outlineConfig = WorldLineSettings(this, Group.Outline, prefix = "Outline ") { outline }.apply { - applyEdits { - hide(::startColor, ::endColor) - settings.forEach { it.onValueChange(::rebuildMesh) } - } - } - private val tracers by setting("Tracers", true, "Draw a line from your cursor to the highlighted position").group(Group.Tracers) - private val tracerConfig = ScreenLineSettings(this, Group.Tracers, prefix = "Tracer ") { tracers }.apply { - applyEdits { - editTyped(::startColor, ::endColor) { - visibility { { !useNaturalColor } } - } - } - } - - private val tracerBlockPositions = ConcurrentHashMap>>() - - val chunkedRenderer = chunkedRenderer( - "Search Chunked Renderer", - { chunkPos -> if (tracers) tracerBlockPositions.keys.removeIf { it in chunkPos } }, - { chunkPos -> if (tracers) tracerBlockPositions.keys.removeIf { it in chunkPos } } + private const val FillGroup = "Fill" + private const val OutlineGroup = "Outline" + private const val TracersGroup = "Tracers" + + private val blocks by setting("Blocks", setOf(Blocks.CHEST, Blocks.ENDER_CHEST, Blocks.NETHER_PORTAL, Blocks.END_PORTAL, Blocks.END_PORTAL_FRAME, Blocks.END_GATEWAY), description = "Render blocks") + .onSelect { rebuildMesh(this) }.onDeselect { rebuildMesh(this) } + private val entities by setting("Entities", decorationEntityMap.values) + .onSelect { rebuildMesh(this) }.onDeselect { rebuildMesh(this) } + + private val mesh by setting("Mesh", true, "Connect similar adjacent blocks").onValueChange(::rebuildMesh) + + private val useNaturalColor by setting("Use Natural Color", true, "Use the color of the block instead").onValueChange(::rebuildMesh) + private val naturalColorAlpha by setting("Natural Color Alpha", 0.3, 0.1..1.0, 0.05) { useNaturalColor }.onValueChange(::rebuildMesh) + private val naturalTracerAlpha by setting("Natural Tracer Alpha", 1.0, 0.1..1.0, 0.05) { useNaturalColor }.onValueChange(::rebuildMesh) + private val minimumNaturalBrightness by setting("Min Brightness", 150, 0..255, 1) { useNaturalColor }.onValueChange(::rebuildMesh) + + @Group(FillGroup) private var fill: Boolean by setting("Fill", true, "Fill the faces of blocks").onValueChange(::rebuildMesh) + .onValueChange { _, to -> if (!to) outline = true } + @Group(FillGroup) private val blockFillColor by setting("Block Fill Color", Color(100, 150, 255, 51), "Color of the surfaces") { fill && !useNaturalColor }.onValueChange(::rebuildMesh) + @Group(FillGroup) private val entityFillColor by setting("Entity Fill Color", Color(100, 150, 255, 51)) { fill && !useNaturalColor }.onValueChange(::rebuildMesh) + + @Group(OutlineGroup) private var outline: Boolean by setting("Outline", true, "Draw the outlines of blocks").onValueChange(::rebuildMesh) + .onValueChange { _, to -> if (!to) fill = true } + @Group(OutlineGroup) private val blockLineColor by setting("Block Line Color", Color(100, 150, 255, 128)) { outline && !useNaturalColor }.onValueChange(::rebuildMesh) + @Group(OutlineGroup) private val entityOutlineColor by setting("Entity Outline Color", Color(100, 150, 255, 128)) { outline && !useNaturalColor }.onValueChange(::rebuildMesh) + + @Group(OutlineGroup) private val blockOutlineMode by setting("Block Outline Mode", DirectionMask.OutlineMode.And, "Outline mode") { outline }.onValueChange(::rebuildMesh) + @Group(OutlineGroup) private val outlineConfig by configBlock(WorldLineSettings(this)) + .withEdits { + hide(::startColor, ::endColor) + forEachSetting { + visibility { old -> { old() && outline } } + onValueChange(::rebuildMesh) + } + } + @Group(TracersGroup) private val tracers by setting("Tracers", true, "Draw a line from your cursor to the highlighted position") + @Group(TracersGroup) private val tracerConfig by configBlock(ScreenLineSettings(this)) + .withEdits { + forEachSetting { visibility { old -> { old() && tracers } } } + editTyped(::startColor, ::endColor) { + visibility { { !useNaturalColor } } + } + } + + private val tracerBlockPositions = ConcurrentHashMap>>() + + val chunkedRenderer = chunkedRenderer( + "Search Chunked Renderer", + { chunkPos -> if (tracers) tracerBlockPositions.keys.removeIf { it in chunkPos } }, + { chunkPos -> if (tracers) tracerBlockPositions.keys.removeIf { it in chunkPos } } ) { position -> - runSafe { - val pos = position.toBlockPos() - val state = blockState(pos) - if (state.block !in blocks) return@chunkedRenderer - val sides = if (mesh) { - buildSideMesh(position) { - world.getBlockState(it).block in blocks - } - } else DirectionMask.ALL - - val lineColor = getBlockColor(state, position.toBlockPos()) - val fillColor = Color(lineColor.red, lineColor.green, lineColor.blue, (naturalColorAlpha * 255).toInt()) - val shape = state.getOutlineShape(world, pos) - val boxes = - if (shape.isEmpty) listOf(Box(pos)) - else shape.boundingBoxes.map { it.offset(pos) } - if (tracers) { - val center = shape - .boundingBoxes - .reduce(Box::union) - .offset(pos) - .center - tracerBlockPositions[pos] = Pair(center, getTracerColors(lineColor)) - } - box( - boxes, - sides.inv(), - if (useNaturalColor) fillColor else blockFillColor, - if (useNaturalColor) lineColor else blockLineColor - ) - } + runSafe { + val pos = position.toBlockPos() + val state = blockState(pos) + if (state.block !in blocks) return@chunkedRenderer + val sides = if (mesh) { + buildSideMesh(position) { + world.getBlockState(it).block in blocks + } + } else DirectionMask.All + + val lineColor = getBlockColor(state, position.toBlockPos()) + val fillColor = Color(lineColor.red, lineColor.green, lineColor.blue, (naturalColorAlpha * 255).toInt()) + val shape = state.getOutlineShape(world, pos) + val boxes = + if (shape.isEmpty) listOf(Box(pos)) + else shape.boundingBoxes.map { it.offset(pos) } + if (tracers) { + val center = shape + .boundingBoxes + .reduce(Box::union) + .offset(pos) + .center + tracerBlockPositions[pos] = Pair(center, getTracerColors(lineColor)) + } + box( + boxes, + sides.inv(), + if (useNaturalColor) fillColor else blockFillColor, + if (useNaturalColor) lineColor else blockLineColor + ) + } } - init { - immediateRenderer("Search Immediate Renderer") { + init { + immediateRenderer("Search Immediate Renderer") { runSafe { world.entities.forEach { entity -> if (entity.entityGroup.nameToDisplayNameMap[entity::class.simpleName] in entities) { val entityColor = getEntityColor(entity) box( listOf(entity.interpolatedBox), - DirectionMask.NONE, + DirectionMask.None, if (useNaturalColor) entityColor.setAlpha(naturalColorAlpha) else entityFillColor, if (useNaturalColor) entityColor else entityOutlineColor ) if (tracers) tracer(Pair(entity.interpolatedBox.center, getTracerColors(entityColor))) } } - if (tracers) tracerBlockPositions.values.forEach { tracer(it) } } - } - } + if (tracers) tracerBlockPositions.values.forEach { tracer(it) } + } + } private fun RenderBuilder.tracer(pair: Pair>) { val endPoint = worldToScreenNormalized(pair.first) ?: return diff --git a/src/main/kotlin/com/lambda/module/modules/render/Time.kt b/src/main/kotlin/com/lambda/module/modules/render/Time.kt index d5e384c68..7688408cc 100644 --- a/src/main/kotlin/com/lambda/module/modules/render/Time.kt +++ b/src/main/kotlin/com/lambda/module/modules/render/Time.kt @@ -27,7 +27,7 @@ import net.minecraft.network.packet.s2c.play.WorldTimeUpdateS2CPacket object Time : Module( name = "Time", description = "Changes the time of day", - tag = ModuleTag.RENDER + tag = ModuleTag.Render ) { private val time by setting("Time", 12000L, 0L..24000L, 100L) diff --git a/src/main/kotlin/com/lambda/module/modules/render/Tracers.kt b/src/main/kotlin/com/lambda/module/modules/render/Tracers.kt index 7e37b0b0f..d68038cde 100644 --- a/src/main/kotlin/com/lambda/module/modules/render/Tracers.kt +++ b/src/main/kotlin/com/lambda/module/modules/render/Tracers.kt @@ -17,17 +17,19 @@ package com.lambda.module.modules.render -import com.lambda.config.applyEdits -import com.lambda.config.groups.EntityColorSettings -import com.lambda.config.groups.EntitySelectionSettings -import com.lambda.config.groups.ScreenLineSettings -import com.lambda.friend.FriendManager.isFriend +import com.lambda.config.SettingEditor.hide +import com.lambda.config.Group +import com.lambda.config.Tab +import com.lambda.config.settings.blocks.EntityColorSettings +import com.lambda.config.settings.blocks.EntitySelectionSettings +import com.lambda.config.settings.blocks.ScreenLineSettings +import com.lambda.config.withEdits +import com.lambda.friend.FriendHandler.isFriend import com.lambda.graphics.mc.renderer.ImmediateRenderer.Companion.immediateRenderer import com.lambda.graphics.mc.renderer.RendererUtils.worldToScreenNormalized import com.lambda.module.Module import com.lambda.module.tag.ModuleTag import com.lambda.threading.runSafe -import com.lambda.util.NamedEnum import com.lambda.util.extension.prevPos import com.lambda.util.extension.tickDelta import com.lambda.util.math.lerp @@ -36,38 +38,30 @@ import org.joml.Vector2f import org.joml.component1 import org.joml.component2 +@Suppress("unused") object Tracers : Module( name = "Tracers", description = "Draws lines to entities within the world", - tag = ModuleTag.RENDER + tag = ModuleTag.Render ) { - private enum class Group(override val displayName: String) : NamedEnum { - General("General"), - Entities("Entities"), - Colors("Colors"), - LineStyle("Line Style") - } + private const val GeneralTab = "General" + private const val EntityTab = "Entities" + private const val ColorsTab = "Colors" - private enum class LineGroup(override val displayName: String) : NamedEnum { - Other("Other"), - Friend("Friend") - } + @Tab(GeneralTab) private val target by setting("Target", TracerMode.Feet) + @Tab(GeneralTab) private val stem by setting("Stem", true) - private val target by setting("Target", TracerMode.Feet).group(Group.General) - private val stem by setting("Stem", true).group(Group.General) - private val entitySettings = EntitySelectionSettings(this, Group.Entities).apply { - applyEdits { - hide(::self, ::blockEntities) - } - } - private val entityColors = EntityColorSettings(this, Group.Colors) + private const val FriendsLineGroup = "Friends" + private const val OthersLineGroup = "Others" - private val friendLineConfig = ScreenLineSettings(this, Group.LineStyle, LineGroup.Friend, prefix = "Friend ").apply { - applyEdits { hide(::startColor, ::endColor) } - } - private val otherLineConfig = ScreenLineSettings(this, Group.LineStyle, LineGroup.Other, prefix = "Other ").apply { - applyEdits { hide(::startColor, ::endColor) } - } + @Tab(GeneralTab) @Group(FriendsLineGroup) private val friendLineConfig by configBlock(ScreenLineSettings(this)) + .withEdits { hide(::startColor, ::endColor) } + @Tab(GeneralTab) @Group(OthersLineGroup) private val otherLineConfig by configBlock(ScreenLineSettings(this)) + .withEdits { hide(::startColor, ::endColor) } + + @Tab(EntityTab) private val entitySettings by configBlock(EntitySelectionSettings(this)) + .withEdits { hide(::self, ::blockEntities) } + @Tab(ColorsTab) private val entityColors by configBlock(EntityColorSettings(this)) init { immediateRenderer("Tracers Immediate Renderer") { 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 bd5123b55..c89658cc4 100644 --- a/src/main/kotlin/com/lambda/module/modules/render/ViewModel.kt +++ b/src/main/kotlin/com/lambda/module/modules/render/ViewModel.kt @@ -18,12 +18,12 @@ package com.lambda.module.modules.render import com.lambda.Lambda.mc +import com.lambda.config.Tab import com.lambda.event.events.ButtonEvent import com.lambda.event.events.TickEvent import com.lambda.event.listener.SafeListener.Companion.listen import com.lambda.module.Module import com.lambda.module.tag.ModuleTag -import com.lambda.util.NamedEnum import net.minecraft.client.network.AbstractClientPlayerEntity import net.minecraft.client.util.math.MatrixStack import net.minecraft.item.ItemStack @@ -39,71 +39,78 @@ import kotlin.math.tan object ViewModel : Module( name = "ViewModel", description = "Adjusts hand and held item rendering", - tag = ModuleTag.RENDER, + tag = ModuleTag.Render, ) { - private val swingMode by setting("Swing Mode", SwingMode.Standard, "Changes which hands swing").group(Group.General) - val swingDuration by setting("Swing Duration", 6, 0..20, 1, "Adjusts how fast the player swings", "ticks").group(Group.General) - private val noSwingDelay by setting("No Swing Delay", false, "Removes the delay between swings").group(Group.General) - val mainSwingProgress by setting("Main Swing Progress", 0.0f, 0.0f..1.0f, 0.025f, "Renders as if the players main hand was this progress through the swing animation").group(Group.General) - val offhandSwingProgress by setting("Offhand Swing Progress", 0.0f, 0.0f..1.0f, 0.025f, "Renders as if the players offhand was this progress through the swing animation").group(Group.General) - val oldAnimations by setting("Old Animations", false, "Adjusts the animations to look like they did in 1.8").group(Group.General) - val swapAnimation by setting("Swap Animation", true, "If disabled, removes the drop down animation when swapping item") { oldAnimations }.group(Group.General) + private const val GeneralTab = "General" + private const val ScaleTab = "Scale" + private const val PositionTab = "Position" + private const val RotationTab = "Rotation" + private const val FovTab = "FOV" + private const val HandTab = "Hand" + + @Tab(GeneralTab) private val swingMode by setting("Swing Mode", SwingMode.Standard, "Changes which hands swing") + @Tab(GeneralTab)val swingDuration by setting("Swing Duration", 6, 0..20, 1, "Adjusts how fast the player swings", "ticks") + @Tab(GeneralTab)private val noSwingDelay by setting("No Swing Delay", false, "Removes the delay between swings") + @Tab(GeneralTab)val mainSwingProgress by setting("Main Swing Progress", 0.0f, 0.0f..1.0f, 0.025f, "Renders as if the players main hand was this progress through the swing animation") + @Tab(GeneralTab)val offhandSwingProgress by setting("Offhand Swing Progress", 0.0f, 0.0f..1.0f, 0.025f, "Renders as if the players offhand was this progress through the swing animation") + @Tab(GeneralTab)val oldAnimations by setting("Old Animations", false, "Adjusts the animations to look like they did in 1.8") + @Tab(GeneralTab)val swapAnimation by setting("Swap Animation", true, "If disabled, removes the drop down animation when swapping item") { oldAnimations } //ToDo: Implement // val shadow by setting("Shadows", true, "If disabled, removes shadows on the model") { page == Page.General } - private val splitScale by setting("Split Scale", false, "Splits left and right hand scale settings").group(Group.Scale) - private val xScale by setting("X Scale", 1.0f, 0.0f..2.0f, 0.025f) { !splitScale }.onValueChange { _, to -> leftXScale = to; rightXScale = to }.group(Group.Scale) - private val yScale by setting("Y Scale", 1.0f, 0.0f..2.0f, 0.025f) { !splitScale }.onValueChange { _, to -> leftYScale = to; rightYScale = to }.group(Group.Scale) - private val zScale by setting("Z Scale", 1.0f, 0.0f..2.0f, 0.025f) { !splitScale }.onValueChange { _, to -> leftZScale = to; rightZScale = to }.group(Group.Scale) - private var leftXScale by setting("Left X Scale", 1.0f, 0.0f..2.0f, 0.025f) { splitScale }.group(Group.Scale) - private var leftYScale by setting("Left Y Scale", 1.0f, 0.0f..2.0f, 0.025f) { splitScale }.group(Group.Scale) - private var leftZScale by setting("Left Z Scale", 1.0f, 0.0f..2.0f, 0.025f) { splitScale }.group(Group.Scale) - private var rightXScale by setting("Right X Scale", 1.0f, 0.0f..2.0f, 0.025f) { splitScale }.group(Group.Scale) - private var rightYScale by setting("Right Y Scale", 1.0f, 0.0f..2.0f, 0.025f) { splitScale }.group(Group.Scale) - private var rightZScale by setting("Right Z Scale", 1.0f, 0.0f..2.0f, 0.025f) { splitScale }.group(Group.Scale) - - private val splitPosition by setting("Split Position", false, "Splits left and right position settings").group(Group.Position) - private val xPosition by setting("X Position", 0.0f, -1.0f..1.0f, 0.025f) { !splitPosition }.onValueChange { _, to -> leftXPosition = to; rightXPosition = to }.group(Group.Position) - private val yPosition by setting("Y Position", 0.0f, -1.0f..1.0f, 0.025f) { !splitPosition }.onValueChange { _, to -> leftYPosition = to; rightYPosition = to }.group(Group.Position) - private val zPosition by setting("Z Position", 0.0f, -1.0f..1.0f, 0.025f) { !splitPosition }.onValueChange { _, to -> leftZPosition = to; rightZPosition = to }.group(Group.Position) - private var leftXPosition by setting("Left X Position", 0.0f, -1.0f..1.0f, 0.025f) { splitPosition }.group(Group.Position) - private var leftYPosition by setting("Left Y Position", 0.0f, -1.0f..1.0f, 0.025f) { splitPosition }.group(Group.Position) - private var leftZPosition by setting("Left Z Position", 0.0f, -1.0f..1.0f, 0.025f) { splitPosition }.group(Group.Position) - private var rightXPosition by setting("Right X Position", 0.0f, -1.0f..1.0f, 0.025f) { splitPosition }.group(Group.Position) - private var rightYPosition by setting("Right Y Position", 0.0f, -1.0f..1.0f, 0.025f) { splitPosition }.group(Group.Position) - private var rightZPosition by setting("Right Z Position", 0.0f, -1.0f..1.0f, 0.025f) { splitPosition }.group(Group.Position) - - private val splitRotation by setting("Split Rotation", false, "Splits left and right rotation settings").group(Group.Rotation) - private val xRotation by setting("X Rotation", 0, -180..180, 1) { !splitRotation }.onValueChange { _, to -> leftXRotation = to; rightXRotation = to }.group(Group.Rotation) - private val yRotation by setting("Y Rotation", 0, -180..180, 1) { !splitRotation }.onValueChange { _, to -> leftYRotation = to; rightYRotation = to }.group(Group.Rotation) - private val zRotation by setting("Z Rotation", 0, -180..180, 1) { !splitRotation }.onValueChange { _, to -> leftZRotation = to; rightZRotation = to }.group(Group.Rotation) - private var leftXRotation by setting("Left X Rotation", 0, -180..180, 1) { splitRotation }.group(Group.Rotation) - private var leftYRotation by setting("Left Y Rotation", 0, -180..180, 1) { splitRotation }.group(Group.Rotation) - private var leftZRotation by setting("Left Z Rotation", 0, -180..180, 1) { splitRotation }.group(Group.Rotation) - private var rightXRotation by setting("Right X Rotation", 0, -180..180, 1) { splitRotation }.group(Group.Rotation) - private var rightYRotation by setting("Right Y Rotation", 0, -180..180, 1) { splitRotation }.group(Group.Rotation) - private var rightZRotation by setting("Right Z Rotation", 0, -180..180, 1) { splitRotation }.group(Group.Rotation) - - private val splitFov by setting("Split FOV", false, "Splits left and right Fov settings").group(Group.Fov) - private val fov by setting("FOV", 70, 10..180, 1) { !splitFov }.onValueChange { _, to -> leftFov = to; rightFov = to }.group(Group.Fov) - private val fovAnchorDistance by setting("Anchor Distance", 0.5f, 0.0f..1.0f, 0.01f, "The distance to anchor the FOV transformation from") { !splitFov }.onValueChange { _, to -> leftFovAnchorDistance = to; rightFovAnchorDistance = to }.group(Group.Fov) - private var leftFov by setting("Left FOV", 70, 10..180, 1) { splitFov }.group(Group.Fov) - private var leftFovAnchorDistance by setting("Left Anchor Distance", 0.5f, 0.0f..1.0f, 0.01f, "The distance to anchor the left FOV transformation from") { splitFov }.group(Group.Fov) - private var rightFov by setting("Right FOV", 70, 10..180, 1) { splitFov }.group(Group.Fov) - private var rightFovAnchorDistance by setting("Right Anchor Distance", 0.5f, 0.0f..1.0f, 0.01f, "The distance to anchor the right FOV transformation from") { splitFov }.group(Group.Fov) - - private val enableHand by setting("Hand", false, "Enables settings for the players hand").group(Group.Hand) - private val handXScale by setting("Hand X Scale", 1.0f, 0.0f..2.0f, 0.025f) { enableHand }.group(Group.Hand) - private val handYScale by setting("Hand Y Scale", 1.0f, 0.0f..2.0f, 0.025f) { enableHand }.group(Group.Hand) - private val handZScale by setting("Hand Z Scale", 1.0f, 0.0f..2.0f, 0.025f) { enableHand }.group(Group.Hand) - private val handXPosition by setting("Hand X Position", 0.0f, -1.0f..1.0f, 0.025f) { enableHand }.group(Group.Hand) - private val handYPosition by setting("Hand Y Position", 0.0f, -1.0f..1.0f, 0.025f) { enableHand }.group(Group.Hand) - private val handZPosition by setting("Hand Z Position", 0.0f, -1.0f..1.0f, 0.025f) { enableHand }.group(Group.Hand) - private val handXRotation by setting("Hand X Rotation", 0, -180..180, 1) { enableHand }.group(Group.Hand) - private val handYRotation by setting("Hand Y Rotation", 0, -180..180, 1) { enableHand }.group(Group.Hand) - private val handZRotation by setting("Hand Z Rotation", 0, -180..180, 1) { enableHand }.group(Group.Hand) - private val handFov by setting("Hand FOV", 70, 10..180, 1) { enableHand }.group(Group.Hand) - private val handFovAnchorDistance by setting("Hand FOV Anchor Distance", 0.5f, 0.0f..1.0f, 0.01f, "The distance to anchor the hands FOV transformation from") { enableHand }.group(Group.Hand) + @Tab(ScaleTab) private val splitScale by setting("Split Scale", false, "Splits left and right hand scale settings") + @Tab(ScaleTab) private val xScale by setting("X Scale", 1.0f, 0.0f..2.0f, 0.025f) { !splitScale }.onValueChange { _, to -> leftXScale = to; rightXScale = to } + @Tab(ScaleTab) private val yScale by setting("Y Scale", 1.0f, 0.0f..2.0f, 0.025f) { !splitScale }.onValueChange { _, to -> leftYScale = to; rightYScale = to } + @Tab(ScaleTab) private val zScale by setting("Z Scale", 1.0f, 0.0f..2.0f, 0.025f) { !splitScale }.onValueChange { _, to -> leftZScale = to; rightZScale = to } + @Tab(ScaleTab) private var leftXScale by setting("Left X Scale", 1.0f, 0.0f..2.0f, 0.025f) { splitScale } + @Tab(ScaleTab) private var leftYScale by setting("Left Y Scale", 1.0f, 0.0f..2.0f, 0.025f) { splitScale } + @Tab(ScaleTab) private var leftZScale by setting("Left Z Scale", 1.0f, 0.0f..2.0f, 0.025f) { splitScale } + @Tab(ScaleTab) private var rightXScale by setting("Right X Scale", 1.0f, 0.0f..2.0f, 0.025f) { splitScale } + @Tab(ScaleTab) private var rightYScale by setting("Right Y Scale", 1.0f, 0.0f..2.0f, 0.025f) { splitScale } + @Tab(ScaleTab) private var rightZScale by setting("Right Z Scale", 1.0f, 0.0f..2.0f, 0.025f) { splitScale } + + @Tab(PositionTab) private val splitPosition by setting("Split Position", false, "Splits left and right position settings") + @Tab(PositionTab) private val xPosition by setting("X Position", 0.0f, -1.0f..1.0f, 0.025f) { !splitPosition }.onValueChange { _, to -> leftXPosition = to; rightXPosition = to } + @Tab(PositionTab) private val yPosition by setting("Y Position", 0.0f, -1.0f..1.0f, 0.025f) { !splitPosition }.onValueChange { _, to -> leftYPosition = to; rightYPosition = to } + @Tab(PositionTab) private val zPosition by setting("Z Position", 0.0f, -1.0f..1.0f, 0.025f) { !splitPosition }.onValueChange { _, to -> leftZPosition = to; rightZPosition = to } + @Tab(PositionTab) private var leftXPosition by setting("Left X Position", 0.0f, -1.0f..1.0f, 0.025f) { splitPosition } + @Tab(PositionTab) private var leftYPosition by setting("Left Y Position", 0.0f, -1.0f..1.0f, 0.025f) { splitPosition } + @Tab(PositionTab) private var leftZPosition by setting("Left Z Position", 0.0f, -1.0f..1.0f, 0.025f) { splitPosition } + @Tab(PositionTab) private var rightXPosition by setting("Right X Position", 0.0f, -1.0f..1.0f, 0.025f) { splitPosition } + @Tab(PositionTab) private var rightYPosition by setting("Right Y Position", 0.0f, -1.0f..1.0f, 0.025f) { splitPosition } + @Tab(PositionTab) private var rightZPosition by setting("Right Z Position", 0.0f, -1.0f..1.0f, 0.025f) { splitPosition } + + @Tab(RotationTab) private val splitRotation by setting("Split Rotation", false, "Splits left and right rotation settings") + @Tab(RotationTab) private val xRotation by setting("X Rotation", 0, -180..180, 1) { !splitRotation }.onValueChange { _, to -> leftXRotation = to; rightXRotation = to } + @Tab(RotationTab) private val yRotation by setting("Y Rotation", 0, -180..180, 1) { !splitRotation }.onValueChange { _, to -> leftYRotation = to; rightYRotation = to } + @Tab(RotationTab) private val zRotation by setting("Z Rotation", 0, -180..180, 1) { !splitRotation }.onValueChange { _, to -> leftZRotation = to; rightZRotation = to } + @Tab(RotationTab) private var leftXRotation by setting("Left X Rotation", 0, -180..180, 1) { splitRotation } + @Tab(RotationTab) private var leftYRotation by setting("Left Y Rotation", 0, -180..180, 1) { splitRotation } + @Tab(RotationTab) private var leftZRotation by setting("Left Z Rotation", 0, -180..180, 1) { splitRotation } + @Tab(RotationTab) private var rightXRotation by setting("Right X Rotation", 0, -180..180, 1) { splitRotation } + @Tab(RotationTab) private var rightYRotation by setting("Right Y Rotation", 0, -180..180, 1) { splitRotation } + @Tab(RotationTab) private var rightZRotation by setting("Right Z Rotation", 0, -180..180, 1) { splitRotation } + + @Tab(FovTab) private val splitFov by setting("Split FOV", false, "Splits left and right Fov settings") + @Tab(FovTab) private val fov by setting("FOV", 70, 10..180, 1) { !splitFov }.onValueChange { _, to -> leftFov = to; rightFov = to } + @Tab(FovTab) private val fovAnchorDistance by setting("Anchor Distance", 0.5f, 0.0f..1.0f, 0.01f, "The distance to anchor the FOV transformation from") { !splitFov }.onValueChange { _, to -> leftFovAnchorDistance = to; rightFovAnchorDistance = to } + @Tab(FovTab) private var leftFov by setting("Left FOV", 70, 10..180, 1) { splitFov } + @Tab(FovTab) private var leftFovAnchorDistance by setting("Left Anchor Distance", 0.5f, 0.0f..1.0f, 0.01f, "The distance to anchor the left FOV transformation from") { splitFov } + @Tab(FovTab) private var rightFov by setting("Right FOV", 70, 10..180, 1) { splitFov } + @Tab(FovTab) private var rightFovAnchorDistance by setting("Right Anchor Distance", 0.5f, 0.0f..1.0f, 0.01f, "The distance to anchor the right FOV transformation from") { splitFov } + + @Tab(HandTab) private val enableHand by setting("Hand", false, "Enables settings for the players hand") + @Tab(HandTab) private val handXScale by setting("Hand X Scale", 1.0f, 0.0f..2.0f, 0.025f) { enableHand } + @Tab(HandTab) private val handYScale by setting("Hand Y Scale", 1.0f, 0.0f..2.0f, 0.025f) { enableHand } + @Tab(HandTab) private val handZScale by setting("Hand Z Scale", 1.0f, 0.0f..2.0f, 0.025f) { enableHand } + @Tab(HandTab) private val handXPosition by setting("Hand X Position", 0.0f, -1.0f..1.0f, 0.025f) { enableHand } + @Tab(HandTab) private val handYPosition by setting("Hand Y Position", 0.0f, -1.0f..1.0f, 0.025f) { enableHand } + @Tab(HandTab) private val handZPosition by setting("Hand Z Position", 0.0f, -1.0f..1.0f, 0.025f) { enableHand } + @Tab(HandTab) private val handXRotation by setting("Hand X Rotation", 0, -180..180, 1) { enableHand } + @Tab(HandTab) private val handYRotation by setting("Hand Y Rotation", 0, -180..180, 1) { enableHand } + @Tab(HandTab) private val handZRotation by setting("Hand Z Rotation", 0, -180..180, 1) { enableHand } + @Tab(HandTab) private val handFov by setting("Hand FOV", 70, 10..180, 1) { enableHand } + @Tab(HandTab) private val handFovAnchorDistance by setting("Hand FOV Anchor Distance", 0.5f, 0.0f..1.0f, 0.01f, "The distance to anchor the hands FOV transformation from") { enableHand } private var attackKeyTicksPressed = -1 @@ -236,15 +243,6 @@ object ViewModel : Module( } } - private enum class Group(override val displayName: String): NamedEnum { - General("General"), - Scale("Scale"), - Position("Position"), - Rotation("Rotation"), - Fov("FOV"), - Hand("Hand") - } - private enum class Side { Left, Right } diff --git a/src/main/kotlin/com/lambda/module/modules/render/Weather.kt b/src/main/kotlin/com/lambda/module/modules/render/Weather.kt index 5b3d3c539..7f6e9a3c8 100644 --- a/src/main/kotlin/com/lambda/module/modules/render/Weather.kt +++ b/src/main/kotlin/com/lambda/module/modules/render/Weather.kt @@ -17,27 +17,25 @@ package com.lambda.module.modules.render +import com.lambda.config.Tab import com.lambda.module.Module import com.lambda.module.tag.ModuleTag import com.lambda.threading.runSafe -import com.lambda.util.NamedEnum import net.minecraft.world.World object Weather : Module( name = "Weather", description = "Modifies the client side weather", - tag = ModuleTag.RENDER + tag = ModuleTag.Render ) { - private enum class Group(override val displayName: String) : NamedEnum { - Overworld("Overworld"), - Nether("Nether"), - End("End") - } + private const val OverworldTab = "Overworld" + private const val NetherTab = "Nether" + private const val EndTab = "End" - @JvmStatic val overworldMode by setting("Overworld Mode", WeatherMode.Clear).group(Group.Overworld) - @JvmStatic val overrideSnow by setting("Override Snow", false) { overworldMode == WeatherMode.Rain }.group(Group.Overworld) - @JvmStatic val netherMode by setting("Nether Mode", WeatherMode.Clear).group(Group.Nether) - @JvmStatic val endMode by setting("End Mode", WeatherMode.Clear).group(Group.End) + @Tab(OverworldTab) @JvmStatic val overworldMode by setting("Overworld Mode", WeatherMode.Clear) + @Tab(OverworldTab) @JvmStatic val overrideSnow by setting("Override Snow", false) { overworldMode == WeatherMode.Rain } + @Tab(NetherTab) @JvmStatic val netherMode by setting("Nether Mode", WeatherMode.Clear) + @Tab(EndTab) @JvmStatic val endMode by setting("End Mode", WeatherMode.Clear) @JvmStatic fun getWeatherMode() = runSafe { diff --git a/src/main/kotlin/com/lambda/module/modules/render/WorldColors.kt b/src/main/kotlin/com/lambda/module/modules/render/WorldColors.kt index 4fb783aad..2de24cb4c 100644 --- a/src/main/kotlin/com/lambda/module/modules/render/WorldColors.kt +++ b/src/main/kotlin/com/lambda/module/modules/render/WorldColors.kt @@ -23,34 +23,20 @@ import com.lambda.util.math.vec3d import net.minecraft.util.math.Vec3d import java.awt.Color +@Suppress("unused") object WorldColors : Module( name = "WorldColors", description = "Changes the color of the sky, clouds and fog", - tag = ModuleTag.RENDER, + tag = ModuleTag.Render, ) { - @JvmStatic - val customSky by setting("Custom Sky", true) - - @JvmStatic - val skyColor by setting("Sky Color", Color(255, 24, 75), "The color of your sky") { customSky } - - @JvmStatic - val customFogOfWar by setting("Custom Fog of War", false) - - @JvmStatic - val fogOfWarColor by setting("Fog of War Color", Color(255, 24, 75, 255), "The color of your fog") { customFogOfWar } - - @JvmStatic - val customClouds by setting("Custom Clouds", false) - - @JvmStatic - val cloudColor by setting("Cloud Color", Color(255, 24, 75)) { customClouds } - - @JvmStatic - val customWaterFog by setting("Custom Water Fog", true) - - @JvmStatic - val waterFogColor by setting("Water Fog Color", Color(255, 24, 75, 255), "The color of your water fog") { customWaterFog } + @JvmStatic val customSky by setting("Custom Sky", true) + @JvmStatic val skyColor by setting("Sky Color", Color(255, 24, 75), "The color of your sky") { customSky } + @JvmStatic val customFogOfWar by setting("Custom Fog of War", false) + @JvmStatic val fogOfWarColor by setting("Fog of War Color", Color(255, 24, 75, 255), "The color of your fog") { customFogOfWar } + @JvmStatic val customClouds by setting("Custom Clouds", false) + @JvmStatic val cloudColor by setting("Cloud Color", Color(255, 24, 75)) { customClouds } + @JvmStatic val customWaterFog by setting("Custom Water Fog", true) + @JvmStatic val waterFogColor by setting("Water Fog Color", Color(255, 24, 75, 255), "The color of your water fog") { customWaterFog } @JvmStatic fun fogOfWarColor(base: Vec3d) = 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 529e41577..0b58bf173 100644 --- a/src/main/kotlin/com/lambda/module/modules/render/XRay.kt +++ b/src/main/kotlin/com/lambda/module/modules/render/XRay.kt @@ -25,7 +25,7 @@ import net.minecraft.block.Blocks object XRay : Module( name = "XRay", description = "Allows you to see ores through walls", - tag = ModuleTag.RENDER, + tag = ModuleTag.Render, ) { val defaultBlocks = setOf( Blocks.COAL_ORE, Blocks.DEEPSLATE_COAL_ORE, @@ -53,6 +53,7 @@ object XRay : Module( @JvmStatic fun isSelected(blockState: BlockState) = mode.select(blockState) + @Suppress("unused") enum class Selection(val select: (BlockState) -> Boolean) { Whitelist({ it.block in selection }), Blacklist({ it.block !in selection }) diff --git a/src/main/kotlin/com/lambda/module/modules/render/Zoom.kt b/src/main/kotlin/com/lambda/module/modules/render/Zoom.kt index 432684807..5bf50544f 100644 --- a/src/main/kotlin/com/lambda/module/modules/render/Zoom.kt +++ b/src/main/kotlin/com/lambda/module/modules/render/Zoom.kt @@ -18,7 +18,6 @@ package com.lambda.module.modules.render import com.lambda.event.events.ButtonEvent -import com.lambda.event.events.RenderEvent import com.lambda.event.listener.SafeListener.Companion.listen import com.lambda.module.Module import com.lambda.module.tag.ModuleTag @@ -28,7 +27,7 @@ import java.lang.Math.clamp object Zoom : Module( name = "Zoom", description = "Zooms the current view", - tag = ModuleTag.RENDER, + tag = ModuleTag.Render, ) { private var zoom by setting("Zoom", 2f, 1f..10f, 0.1f) private val style by setting("Style", ZoomStyle.EaseOut) @@ -83,6 +82,7 @@ object Zoom : Module( if (lerpedZoom == targetZoom) lerpedZoom = targetZoom } + @Suppress("unused") private enum class ZoomStyle( override val displayName: String, val apply: (Float, Float, Float) -> Float, diff --git a/src/main/kotlin/com/lambda/module/modules/world/AirPlace.kt b/src/main/kotlin/com/lambda/module/modules/world/AirPlace.kt index e08b7511b..74fb9815b 100644 --- a/src/main/kotlin/com/lambda/module/modules/world/AirPlace.kt +++ b/src/main/kotlin/com/lambda/module/modules/world/AirPlace.kt @@ -18,9 +18,11 @@ package com.lambda.module.modules.world import com.lambda.Lambda.mc -import com.lambda.config.AutomationConfig.Companion.setDefaultAutomationConfig -import com.lambda.config.applyEdits +import com.lambda.config.SettingEditor.hideAllBlocksExcept +import com.lambda.config.Group +import com.lambda.config.automation.AutomationConfig.Companion.setDefaultAutomationConfig import com.lambda.config.settings.complex.Bind +import com.lambda.config.withEdits import com.lambda.context.SafeContext import com.lambda.event.events.ButtonEvent import com.lambda.event.events.PlayerEvent @@ -38,7 +40,6 @@ import com.lambda.module.tag.ModuleTag import com.lambda.threading.runSafeAutomated import com.lambda.util.InputUtils.isSatisfied import com.lambda.util.KeyCode -import com.lambda.util.NamedEnum import com.lambda.util.math.setAlpha import com.lambda.util.math.vec3d import net.minecraft.block.BlockState @@ -56,24 +57,22 @@ import org.lwjgl.glfw.GLFW import java.awt.Color import java.util.concurrent.ConcurrentLinkedQueue +@Suppress("unused") object AirPlace : Module( name = "AirPlace", description = "Allows placing blocks in air", - tag = ModuleTag.WORLD + tag = ModuleTag.World ) { - private enum class Group(override val displayName: String) : NamedEnum { - General("General"), - Render("Render") - } + private const val RenderGroup = "Renders" - private var distance by setting("Distance", 4.0, 1.0..7.0, 0.01).group(Group.General) - private val distanceScrollBind by setting("Distance Scroll Bind", Bind(KeyCode.Unbound.code, GLFW.GLFW_MOD_CONTROL), "Allows you to hold the given key and scroll to adjust distance").group(Group.General) + private var distance by setting("Distance", 4.0, 1.0..7.0, 0.01) + private val distanceScrollBind by setting("Distance Scroll Bind", Bind(KeyCode.Unbound.code, GLFW.GLFW_MOD_CONTROL), "Allows you to hold the given key and scroll to adjust distance") // Credit to THCFree for the rotation scroll idea - private val rotationScrollBind by setting("Rotation Scroll Bind", Bind(KeyCode.Unbound.code, GLFW.GLFW_MOD_ALT), "Allows you to hold the given key and scroll to adjust the rotation of the block you're placing").group(Group.General) + private val rotationScrollBind by setting("Rotation Scroll Bind", Bind(KeyCode.Unbound.code, GLFW.GLFW_MOD_ALT), "Allows you to hold the given key and scroll to adjust the rotation of the block you're placing") - private val renderState by setting("Render State", true).group(Group.Render) - private val lineColor by setting("Line Color", Color.WHITE).group(Group.Render) - private val stateAlpha by setting("State Alpha", 0.5, 0.01..1.0, 0.01).group(Group.Render) + @Group(RenderGroup) private val renderState by setting("Render State", true) + @Group(RenderGroup) private val lineColor by setting("Line Color", Color.WHITE) + @Group(RenderGroup) private val stateAlpha by setting("State Alpha", 0.5, 0.01..1.0, 0.01) private var placementPos: BlockPos? = null private var backingState: BlockState? = null @@ -93,11 +92,10 @@ object AirPlace : Module( ) init { - setDefaultAutomationConfig { - applyEdits { - hideAllGroupsExcept(interactConfig) + setDefaultAutomationConfig() + .withEdits { + hideAllBlocksExcept(::interactConfig) } - } listen { if (request?.done == false) { diff --git a/src/main/kotlin/com/lambda/module/modules/world/AutoPortal.kt b/src/main/kotlin/com/lambda/module/modules/world/AutoPortal.kt index bc1028ad1..a25281f6c 100644 --- a/src/main/kotlin/com/lambda/module/modules/world/AutoPortal.kt +++ b/src/main/kotlin/com/lambda/module/modules/world/AutoPortal.kt @@ -18,18 +18,23 @@ package com.lambda.module.modules.world import baritone.api.pathing.goals.GoalBlock -import com.lambda.config.AutomationConfig.Companion.setDefaultAutomationConfig -import com.lambda.config.applyEdits -import com.lambda.config.groups.WorldLineSettings +import com.lambda.config.SettingEditor.edit +import com.lambda.config.SettingEditor.forEachSetting +import com.lambda.config.SettingEditor.hide +import com.lambda.config.SettingEditor.hideBlock +import com.lambda.config.Group +import com.lambda.config.automation.AutomationConfig.Companion.setDefaultAutomationConfig +import com.lambda.config.settings.blocks.WorldLineSettings import com.lambda.config.settings.complex.Bind import com.lambda.config.settings.complex.KeybindSetting.Companion.onPress import com.lambda.config.settings.complex.KeybindSetting.Companion.onRelease +import com.lambda.config.withEdits import com.lambda.context.SafeContext import com.lambda.event.events.TickEvent import com.lambda.event.listener.SafeListener.Companion.listen import com.lambda.graphics.mc.renderer.ImmediateRenderer.Companion.immediateRenderer import com.lambda.graphics.util.DirectionMask -import com.lambda.interaction.BaritoneManager +import com.lambda.interaction.BaritoneHandler import com.lambda.interaction.construction.verify.TargetState import com.lambda.interaction.managers.hotbar.HotbarRequest import com.lambda.interaction.managers.inventory.InventoryRequest.Companion.inventoryRequest @@ -47,7 +52,7 @@ import com.lambda.threading.runSafe import com.lambda.util.BlockUtils.blockState import com.lambda.util.BlockUtils.isEmpty import com.lambda.util.BlockUtils.isNotEmpty -import com.lambda.util.NamedEnum +import com.lambda.util.PacketUtils.sendPacket import com.lambda.util.extension.blockColor import com.lambda.util.extension.tickDelta import com.lambda.util.math.lerp @@ -67,22 +72,17 @@ import net.minecraft.util.math.Box import net.minecraft.util.math.Direction import net.minecraft.util.math.Vec3d +@Suppress("unused") object AutoPortal : Module( name = "AutoPortal", description = "Automatically places and lights a nether portal", - tag = ModuleTag.WORLD + tag = ModuleTag.World ) { - private enum class Group(override val displayName: String) : NamedEnum { - General("General"), - Render("Render") - } - - private enum class RenderGroup(override val displayName: String) : NamedEnum { - Fill("Fill"), - Outline("Outline") - } + private const val RenderGroup = "Renders" + private const val FillGroup = "Fill" + private const val OutlineGroup = "Outline" - private val previewPlace by setting("Preview Place", Bind.EMPTY, "The keybind to preview the portal placement and subsequentially place the portal").group(Group.General) + private val previewPlace by setting("Preview Place", Bind.Empty, "The keybind to preview the portal placement and subsequentially place the portal") .onPress { preview = true } .onRelease { preview = false @@ -108,38 +108,39 @@ object AutoPortal : Module( } .run() } - private val corners by setting("Corners", false).group(Group.General) - private val light by setting("Light", true, "Attempts to automatically light the portal after building").group(Group.General) - private val walkIn by setting("Walk In", true, "Automatically paths into the portal with baritone") { light }.group(Group.General) - private val inventory by setting("Inventory", true, "Allows access to the players inventory when retrieving a flint and steel for lighting the portal").group(Group.General) - private val forwardOffset by setting("Forward Offset", 3, 0..10).group(Group.General) - private val sidewaysOffset by setting("Sideways Offset", 0, -5..5).group(Group.General) - private val yOffset by setting("Y Offset", 0, -5..5).group(Group.General) - private val lockToGround by setting("Lock To Ground", true).group(Group.General) - private val allowUpwardShift by setting("Allow Upward Shift", true, "Allows shifting the portal up to find ground when it would be placed inside blocks") { lockToGround }.group(Group.General) - - private val renders by setting("Renders", true).group(Group.Render) - private val interpolate by setting("Interpolate", true, "Interpolates the portal renders from position to position") { renders }.group(Group.Render) - private val depthTest by setting("Depth Test", false) { renders }.group(Group.Render) - private val fillAlpha by setting("Fill Alpha", 0.3, 0.0..1.0, 0.01) { renders }.group(Group.Render, RenderGroup.Fill) - private val outlineConfig = WorldLineSettings(this, Group.Render, RenderGroup.Outline) { renders }.apply { - applyEdits { + private val corners by setting("Corners", false) + private val light by setting("Light", true, "Attempts to automatically light the portal after building") + private val walkIn by setting("Walk In", true, "Automatically paths into the portal with baritone") { light } + private val inventory by setting("Inventory", true, "Allows access to the players inventory when retrieving a flint and steel for lighting the portal") + private val forwardOffset by setting("Forward Offset", 3, 0..10) + private val sidewaysOffset by setting("Sideways Offset", 0, -5..5) + private val yOffset by setting("Y Offset", 0, -5..5) + private val lockToGround by setting("Lock To Ground", true) + private val allowUpwardShift by setting("Allow Upward Shift", true, "Allows shifting the portal up to find ground when it would be placed inside blocks") { lockToGround } + + @Group(RenderGroup) private val renders by setting("Renders", true) + @Group(RenderGroup) private val interpolate by setting("Interpolate", true, "Interpolates the portal renders from position to position") { renders } + @Group(RenderGroup) private val depthTest by setting("Depth Test", false) { renders } + @Group(RenderGroup, FillGroup) private val fillAlpha by setting("Fill Alpha", 0.3, 0.0..1.0, 0.01) { renders } + @Group(RenderGroup, OutlineGroup) private val outlineConfig by configBlock(WorldLineSettings(this)) + .withEdits { hide(::startColor, ::endColor) + forEachSetting { + visibility { old -> { old() && renders } } + } } - } private var preview = false private var buildTask: Task<*>? = null init { - setDefaultAutomationConfig { - applyEdits { - hideGroup(eatConfig) + setDefaultAutomationConfig() + .withEdits { + hideBlock(::eatConfig) hotbarConfig::tickStageMask.edit { defaultValue(mutableSetOf(TickEvent.Pre, TickEvent.Input.Post)) } } - } listen { PosHandler.tick() @@ -301,7 +302,7 @@ object AutoPortal : Module( } swapPacket() if (walkIn) { - BaritoneManager.setGoalAndPath(GoalBlock(currAnchorPos.up())) + BaritoneHandler.setGoalAndPath(GoalBlock(currAnchorPos.up())) } success() } @@ -309,13 +310,13 @@ object AutoPortal : Module( } private fun SafeContext.swapPacket() = - connection.sendPacket( + connection.sendPacket { PlayerActionC2SPacket( PlayerActionC2SPacket.Action.SWAP_ITEM_WITH_OFFHAND, BlockPos.ORIGIN, Direction.DOWN ) - ) + } private fun SafeContext.withFlintAndSteel(block: SafeContext.() -> Unit) { if (player.mainHandStack.item == Items.FLINT_AND_STEEL) { diff --git a/src/main/kotlin/com/lambda/module/modules/world/AutoSign.kt b/src/main/kotlin/com/lambda/module/modules/world/AutoSign.kt index 3b2a05508..1d10b348e 100644 --- a/src/main/kotlin/com/lambda/module/modules/world/AutoSign.kt +++ b/src/main/kotlin/com/lambda/module/modules/world/AutoSign.kt @@ -24,13 +24,14 @@ import com.lambda.module.Module import com.lambda.module.tag.ModuleTag import com.lambda.threading.runConcurrent import com.lambda.threading.runSafeGameScheduled +import com.lambda.util.PacketUtils.sendPacket import kotlinx.coroutines.delay import net.minecraft.block.entity.HangingSignBlockEntity import net.minecraft.client.gui.screen.ingame.AbstractSignEditScreen import net.minecraft.client.gui.screen.ingame.HangingSignEditScreen import net.minecraft.client.gui.screen.ingame.SignEditScreen import net.minecraft.network.packet.c2s.play.UpdateSignC2SPacket -import java.util.Date +import java.util.* @Suppress("unused") object AutoSign : Module( @@ -48,7 +49,7 @@ object AutoSign : Module( | - Minute (00-59) | - Second (00-59) """.trimMargin(), - tag = ModuleTag.WORLD + tag = ModuleTag.World ) { private var autoWrite by setting("Auto Write", true) private var line1 by setting("Line 1", "Welcome to Lambda!") { autoWrite } @@ -95,13 +96,13 @@ object AutoSign : Module( runConcurrent { delay(signWriteDelay) runSafeGameScheduled { - connection.sendPacket( + connection.sendPacket { UpdateSignC2SPacket( pos, writeOnFront, messages[0], messages[1], messages[2], messages[3] ) - ) + } } } } else mc.setScreen(editor) diff --git a/src/main/kotlin/com/lambda/module/modules/world/AutoVillagerCycle.kt b/src/main/kotlin/com/lambda/module/modules/world/AutoVillagerCycle.kt index 4d2c9b7d4..a3e0a597d 100644 --- a/src/main/kotlin/com/lambda/module/modules/world/AutoVillagerCycle.kt +++ b/src/main/kotlin/com/lambda/module/modules/world/AutoVillagerCycle.kt @@ -17,10 +17,12 @@ package com.lambda.module.modules.world -import com.lambda.config.AutomationConfig.Companion.setDefaultAutomationConfig -import com.lambda.config.applyEdits +import com.lambda.config.SettingEditor.hideAllBlocksExcept +import com.lambda.config.Group +import com.lambda.config.automation.AutomationConfig.Companion.setDefaultAutomationConfig import com.lambda.config.settings.complex.Bind import com.lambda.config.settings.complex.KeybindSetting.Companion.onPress +import com.lambda.config.withEdits import com.lambda.context.SafeContext import com.lambda.event.events.PacketEvent import com.lambda.event.events.TickEvent @@ -29,19 +31,18 @@ import com.lambda.interaction.construction.blueprint.Blueprint.Companion.toStruc import com.lambda.interaction.construction.blueprint.StaticBlueprint.Companion.toBlueprint import com.lambda.interaction.construction.verify.TargetState import com.lambda.interaction.managers.rotating.IRotationRequest.Companion.rotationRequest -import com.lambda.interaction.managers.rotating.visibilty.lookAtEntity import com.lambda.module.Module import com.lambda.module.tag.ModuleTag -import com.lambda.sound.SoundManager.playSound +import com.lambda.sound.SoundHandler.playSound import com.lambda.task.RootTask.run import com.lambda.task.Task import com.lambda.task.tasks.BuildTask.Companion.build import com.lambda.threading.runSafeAutomated import com.lambda.util.BlockUtils.blockState import com.lambda.util.BlockUtils.isEmpty -import com.lambda.util.Communication.info -import com.lambda.util.Communication.logError -import com.lambda.util.NamedEnum +import com.lambda.util.CommunicationUtils.info +import com.lambda.util.CommunicationUtils.logError +import com.lambda.util.player.RotationUtils.lookAtEntity import com.lambda.util.world.closestEntity import net.minecraft.block.Blocks import net.minecraft.component.DataComponentTypes @@ -56,24 +57,20 @@ import net.minecraft.util.Hand import net.minecraft.util.hit.EntityHitResult import net.minecraft.util.math.BlockPos +@Suppress("unused") object AutoVillagerCycle : Module( name = "AutoVillagerCycle", description = "Automatically cycles librarian villagers with lecterns until a desired enchanted book is found", - tag = ModuleTag.WORLD + tag = ModuleTag.World ) { - private enum class Group(override val displayName: String) : NamedEnum { - General("General"), - Enchantments("Enchantments") - } - private val allEnchantments = ArrayList() - private val lecternPos by setting("Lectern Pos", BlockPos.ORIGIN, "Position where the lectern should be placed/broken").group(Group.General) - private val logFoundBooks by setting("Log Found Books", true, "Log all enchanted books found during cycling").group(Group.General) - private val interactDelay by setting("Interact Delay", 20, 1..40, 1, "Ticks to wait before interacting with the villager", " ticks").group(Group.General) - private val breakDelay by setting("Break Delay", 5, 1..20, 1, "Ticks to wait after breaking the lectern", " ticks").group(Group.General) - private val searchRange by setting("Search Range", 5.0, 1.0..10.0, 0.5, "Range to search for nearby villagers", " blocks").group(Group.General) - private val startCyclingBind by setting("Start Cycling", Bind.EMPTY, "Press to start/stop cycling").group(Group.General) + private val lecternPos by setting("Lectern Pos", BlockPos.ORIGIN, "Position where the lectern should be placed/broken") + private val logFoundBooks by setting("Log Found Books", true, "Log all enchanted books found during cycling") + private val interactDelay by setting("Interact Delay", 20, 1..40, 1, "Ticks to wait before interacting with the villager", " ticks") + private val breakDelay by setting("Break Delay", 5, 1..20, 1, "Ticks to wait after breaking the lectern", " ticks") + private val searchRange by setting("Search Range", 5.0, 1.0..10.0, 0.5, "Range to search for nearby villagers", " blocks") + private val startCyclingBind by setting("Start Cycling", Bind.Empty, "Press to start/stop cycling") .onPress { if (cycleState != CycleState.Idle) { info("Stopped villager cycling.") @@ -85,8 +82,10 @@ object AutoVillagerCycle : Module( switchState(CycleState.PlaceLectern) } } - private val desiredEnchantments by setting("Desired Enchantments", emptySet(), allEnchantments).group(Group.Enchantments) - private val minLevel by setting("Min Level", 1, 1..5, 1, "Minimum enchantment level to look for").group(Group.Enchantments) + + private const val EnchantmentsGroup = "Enchantments" + @Group(EnchantmentsGroup) private val desiredEnchantments by setting("Desired Enchantments", emptySet(), allEnchantments) + @Group(EnchantmentsGroup) private val minLevel by setting("Min Level", 1, 1..5, 1, "Minimum enchantment level to look for") private var cycleState = CycleState.Idle private var tickCounter = 0 @@ -94,11 +93,10 @@ object AutoVillagerCycle : Module( private var buildTask: Task<*>? = null init { - setDefaultAutomationConfig { - applyEdits { - hideAllGroupsExcept(rotationConfig, inventoryConfig, breakConfig, interactConfig, buildConfig) + setDefaultAutomationConfig() + .withEdits { + hideAllBlocksExcept(::rotationConfig, ::inventoryConfig, ::breakConfig, ::interactConfig, ::buildConfig) } - } onEnable { allEnchantments.clear() diff --git a/src/main/kotlin/com/lambda/module/modules/world/HighwayTools.kt b/src/main/kotlin/com/lambda/module/modules/world/HighwayTools.kt index fdcb878b6..66a799d24 100644 --- a/src/main/kotlin/com/lambda/module/modules/world/HighwayTools.kt +++ b/src/main/kotlin/com/lambda/module/modules/world/HighwayTools.kt @@ -17,9 +17,10 @@ package com.lambda.module.modules.world -import com.lambda.config.AutomationConfig.Companion.setDefaultAutomationConfig -import com.lambda.config.applyEdits -import com.lambda.interaction.BaritoneManager +import com.lambda.config.SettingEditor.editTyped +import com.lambda.config.automation.AutomationConfig.Companion.setDefaultAutomationConfig +import com.lambda.config.withEdits +import com.lambda.interaction.BaritoneHandler import com.lambda.interaction.construction.blueprint.Blueprint.Companion.emptyStructure import com.lambda.interaction.construction.blueprint.PropagatingBlueprint.Companion.propagatingBlueprint import com.lambda.interaction.construction.verify.TargetState @@ -28,7 +29,7 @@ import com.lambda.module.tag.ModuleTag import com.lambda.task.RootTask.run import com.lambda.task.Task import com.lambda.task.tasks.BuildTask.Companion.build -import com.lambda.util.Communication.info +import com.lambda.util.CommunicationUtils.info import com.lambda.util.Describable import com.lambda.util.NamedEnum import com.lambda.util.extension.Structure @@ -47,7 +48,7 @@ import net.minecraft.util.math.Vec3i object HighwayTools : Module( name = "HighwayTools", description = "Auto highway builder", - tag = ModuleTag.WORLD, + tag = ModuleTag.World, ) { private val height by setting("Height", 4, 2..10, 1) private val width by setting("Width", 6, 1..30, 1) @@ -81,6 +82,7 @@ object HighwayTools : Module( Block("Block", "Paves the highway with a specific block. Will use the block you specified in the settings"), } + @Suppress("unused") enum class Corner( override val displayName: String, override val description: String @@ -90,13 +92,12 @@ object HighwayTools : Module( } init { - setDefaultAutomationConfig { - applyEdits { - buildConfig.apply { - editTyped(::pathing, ::stayInRange) { defaultValue(true) } - } + setDefaultAutomationConfig() + .withEdits { + buildConfig.apply { + editTyped(::pathing, ::stayInRange) { defaultValue(true) } + } } - } onEnable { octant = player.octant @@ -108,7 +109,7 @@ object HighwayTools : Module( runningTask?.cancel() runningTask = null distanceMoved = 0 - BaritoneManager.cancel() + BaritoneHandler.cancel() } } diff --git a/src/main/kotlin/com/lambda/module/modules/world/MapDownloader.kt b/src/main/kotlin/com/lambda/module/modules/world/MapDownloader.kt index 20d1034ea..359cf1868 100644 --- a/src/main/kotlin/com/lambda/module/modules/world/MapDownloader.kt +++ b/src/main/kotlin/com/lambda/module/modules/world/MapDownloader.kt @@ -22,7 +22,7 @@ import com.lambda.event.listener.SafeListener.Companion.listen import com.lambda.module.Module import com.lambda.module.tag.ModuleTag import com.lambda.util.FileUtils.locationBoundDirectory -import com.lambda.util.FolderRegister +import com.lambda.util.FolderRegistry import com.lambda.util.StringUtils.hashString import com.lambda.util.player.SlotUtils.allStacks import com.lambda.util.world.entitySearch @@ -33,10 +33,11 @@ import net.minecraft.item.map.MapState import java.awt.image.BufferedImage import javax.imageio.ImageIO +@Suppress("unused") object MapDownloader : Module( name = "MapDownloader", description = "Save map data to your computer", - tag = ModuleTag.WORLD, + tag = ModuleTag.World, ) { init { listen { @@ -48,7 +49,7 @@ object MapDownloader : Module( val name = map.hash val image = map.toBufferedImage() - val file = FolderRegister.maps.toFile().locationBoundDirectory().resolve("$name.png") + val file = FolderRegistry.maps.toFile().locationBoundDirectory().resolve("$name.png") if (file.exists()) return@listen ImageIO.write(image, "png", file) diff --git a/src/main/kotlin/com/lambda/module/modules/world/Nuker.kt b/src/main/kotlin/com/lambda/module/modules/world/Nuker.kt index 7e8314b32..2c45f3837 100644 --- a/src/main/kotlin/com/lambda/module/modules/world/Nuker.kt +++ b/src/main/kotlin/com/lambda/module/modules/world/Nuker.kt @@ -17,8 +17,9 @@ package com.lambda.module.modules.world -import com.lambda.config.AutomationConfig.Companion.setDefaultAutomationConfig -import com.lambda.config.applyEdits +import com.lambda.config.SettingEditor.editTyped +import com.lambda.config.automation.AutomationConfig.Companion.setDefaultAutomationConfig +import com.lambda.config.withEdits import com.lambda.context.SafeContext import com.lambda.interaction.construction.blueprint.TickingBlueprint.Companion.tickingBlueprint import com.lambda.interaction.construction.verify.TargetState @@ -28,16 +29,17 @@ import com.lambda.task.RootTask.run import com.lambda.task.Task import com.lambda.task.tasks.BuildTask.Companion.build import com.lambda.util.BlockUtils.blockPos -import net.minecraft.block.Blocks -import net.minecraft.util.math.BlockPos import com.lambda.util.PlayerBuildLayerUtils.FlattenMode -import com.lambda.util.PlayerBuildLayerUtils.isInFlatten import com.lambda.util.PlayerBuildLayerUtils.isInBaritoneSelection +import com.lambda.util.PlayerBuildLayerUtils.isInFlatten +import net.minecraft.block.Blocks +import net.minecraft.util.math.BlockPos +@Suppress("unused") object Nuker : Module( name = "Nuker", description = "Breaks blocks around you", - tag = ModuleTag.WORLD, + tag = ModuleTag.World, autoDisable = true ) { private val height by setting("Height", 6, 1..8, 1) @@ -55,13 +57,12 @@ object Nuker : Module( private var buildTask: Task<*>? = null init { - setDefaultAutomationConfig { - applyEdits { + setDefaultAutomationConfig() + .withEdits { buildConfig.apply { editTyped(::pathing, ::stayInRange) { defaultValue(false) } } } - } onEnable { startBuildTask() diff --git a/src/main/kotlin/com/lambda/module/modules/world/Printer.kt b/src/main/kotlin/com/lambda/module/modules/world/Printer.kt index d4595963e..36f2131fe 100644 --- a/src/main/kotlin/com/lambda/module/modules/world/Printer.kt +++ b/src/main/kotlin/com/lambda/module/modules/world/Printer.kt @@ -17,7 +17,7 @@ package com.lambda.module.modules.world -import com.lambda.config.AutomationConfig.Companion.setDefaultAutomationConfig +import com.lambda.config.automation.AutomationConfig.Companion.setDefaultAutomationConfig import com.lambda.context.SafeContext import com.lambda.interaction.construction.blueprint.TickingBlueprint.Companion.tickingBlueprint import com.lambda.interaction.construction.simulation.result.BuildResult @@ -30,21 +30,22 @@ import com.lambda.task.RootTask.run import com.lambda.task.Task import com.lambda.task.tasks.BuildTask.Companion.build import com.lambda.util.BlockUtils.blockPos -import com.lambda.util.Communication.logError +import com.lambda.util.CommunicationUtils.logError import com.lambda.util.Describable import com.lambda.util.NamedEnum -import com.lambda.util.PlayerBuildLayerUtils.isInBaritoneSelection -import com.lambda.util.PlayerBuildLayerUtils.isInFlatten import com.lambda.util.PlayerBuildLayerUtils.FlattenMode import com.lambda.util.PlayerBuildLayerUtils.inSchematic +import com.lambda.util.PlayerBuildLayerUtils.isInBaritoneSelection +import com.lambda.util.PlayerBuildLayerUtils.isInFlatten import fi.dy.masa.litematica.data.DataManager import fi.dy.masa.litematica.world.SchematicWorldHandler import net.minecraft.util.math.BlockPos +@Suppress("unused") object Printer : Module( name = "Printer", description = "Automatically prints schematics", - tag = ModuleTag.WORLD + tag = ModuleTag.World ) { private val range by setting("Range", 5, 1..7, 1, description = "The range around the player to check for blocks to print") private val air by setting("Air", false, description = "Consider breaking blocks in the world that are air in the schematic.\nNote: Breaking can also be disabled in the Automation Config.") diff --git a/src/main/kotlin/com/lambda/module/modules/world/Scaffold.kt b/src/main/kotlin/com/lambda/module/modules/world/Scaffold.kt index f4bd238e5..85b63843c 100644 --- a/src/main/kotlin/com/lambda/module/modules/world/Scaffold.kt +++ b/src/main/kotlin/com/lambda/module/modules/world/Scaffold.kt @@ -17,16 +17,20 @@ package com.lambda.module.modules.world -import com.lambda.config.AutomationConfig.Companion.setDefaultAutomationConfig -import com.lambda.config.applyEdits +import com.lambda.config.SettingEditor.edit +import com.lambda.config.SettingEditor.editTyped +import com.lambda.config.SettingEditor.hide +import com.lambda.config.SettingEditor.hideAllBlocksExcept +import com.lambda.config.automation.AutomationConfig.Companion.setDefaultAutomationConfig +import com.lambda.config.settings.blocks.InteractConfig import com.lambda.config.settings.complex.Bind +import com.lambda.config.withEdits import com.lambda.context.SafeContext import com.lambda.event.events.TickEvent import com.lambda.event.listener.SafeListener.Companion.listen import com.lambda.interaction.construction.simulation.BuildSimulator.simulate import com.lambda.interaction.construction.simulation.context.BuildContext import com.lambda.interaction.construction.verify.TargetState -import com.lambda.interaction.managers.interacting.InteractConfig import com.lambda.interaction.managers.interacting.InteractRequest.Companion.interactRequest import com.lambda.interaction.material.StackSelection.Companion.selectStack import com.lambda.interaction.material.container.containers.HotbarContainer @@ -46,19 +50,19 @@ import java.util.concurrent.ConcurrentLinkedQueue object Scaffold : Module( name = "Scaffold", description = "Places blocks under the player", - tag = ModuleTag.WORLD, + tag = ModuleTag.World, ) { private val blacklistedBlocks by setting("Blacklisted Blocks", mutableSetOf()) private val bridgeRange by setting("Bridge Range", 5, 0..5, 1, "The range at which blocks can be placed to help build support for the player", unit = " blocks") private val onlyBelow by setting("Only Below", true, "Restricts bridging to only below the player to avoid place spam if it's impossible to reach the supporting position") { bridgeRange > 0 } - private val descend by setting("Descend", Bind.EMPTY, "Lower the place position by one to allow the player to lower y level") - private val descendAmount by setting("Descend Amount", 1, 1..5, 1, "The amount to lower the place position by when descending", unit = " blocks") { descend != Bind.EMPTY } + private val descend by setting("Descend", Bind.Empty, "Lower the place position by one to allow the player to lower y level") + private val descendAmount by setting("Descend Amount", 1, 1..5, 1, "The amount to lower the place position by when descending", unit = " blocks") { descend != Bind.Empty } private val pendingActions = ConcurrentLinkedQueue() init { - setDefaultAutomationConfig { - applyEdits { + setDefaultAutomationConfig() + .withEdits { buildConfig.apply { editTyped(::pathing, ::stayInRange, ::collectDrops, ::spleefEntities) { defaultValue(false) @@ -73,9 +77,8 @@ object Scaffold : Module( ::mean.edit { defaultValue(120.0) } ::spread.edit { defaultValue(0.0) } } - hideAllGroupsExcept(buildConfig, interactConfig, rotationConfig, hotbarConfig) + hideAllBlocksExcept(::buildConfig, ::interactConfig, ::rotationConfig, ::hotbarConfig) } - } listen { val selection = selectStack { diff --git a/src/main/kotlin/com/lambda/module/modules/world/StashMover.kt b/src/main/kotlin/com/lambda/module/modules/world/StashMover.kt index 833f6b541..53422611b 100644 --- a/src/main/kotlin/com/lambda/module/modules/world/StashMover.kt +++ b/src/main/kotlin/com/lambda/module/modules/world/StashMover.kt @@ -19,10 +19,16 @@ package com.lambda.module.modules.world import baritone.api.pathing.goals.GoalBlock import com.lambda.Lambda.mc -import com.lambda.config.AutomationConfig.Companion.setDefaultAutomationConfig -import com.lambda.config.applyEdits +import com.lambda.config.SettingEditor.edit +import com.lambda.config.SettingEditor.editTyped +import com.lambda.config.SettingEditor.hide +import com.lambda.config.SettingEditor.hideBlock +import com.lambda.config.Tab +import com.lambda.config.automation.AutomationConfig.Companion.setDefaultAutomationConfig +import com.lambda.config.settings.blocks.InteractConfig import com.lambda.config.settings.complex.Bind import com.lambda.config.settings.complex.KeybindSetting.Companion.onPress +import com.lambda.config.withEdits import com.lambda.context.SafeContext import com.lambda.event.events.ButtonEvent import com.lambda.event.events.ChatEvent @@ -32,10 +38,9 @@ import com.lambda.event.events.TickEvent import com.lambda.event.listener.SafeListener.Companion.listen import com.lambda.event.listener.UnsafeListener.Companion.listenUnsafe import com.lambda.graphics.mc.renderer.TickedRenderer.Companion.tickedRenderer -import com.lambda.interaction.BaritoneManager +import com.lambda.interaction.BaritoneHandler import com.lambda.interaction.construction.verify.TargetState import com.lambda.interaction.managers.hotbar.HotbarRequest -import com.lambda.interaction.managers.interacting.InteractConfig import com.lambda.interaction.managers.inventory.InventoryRequest.Companion.inventoryRequest import com.lambda.interaction.managers.rotating.IRotationRequest.Companion.rotationRequest import com.lambda.interaction.managers.rotating.Rotation @@ -51,9 +56,9 @@ import com.lambda.task.tasks.OpenContainerTask import com.lambda.threading.runSafeAutomated import com.lambda.util.BlockUtils.blockEntity import com.lambda.util.BlockUtils.blockState -import com.lambda.util.Communication.info -import com.lambda.util.Communication.logError -import com.lambda.util.Communication.warn +import com.lambda.util.CommunicationUtils.info +import com.lambda.util.CommunicationUtils.logError +import com.lambda.util.CommunicationUtils.warn import com.lambda.util.NamedEnum import com.lambda.util.TickTimer import com.lambda.util.extension.containerSlots @@ -91,21 +96,18 @@ import net.minecraft.util.math.Box import org.lwjgl.glfw.GLFW import java.awt.Color import kotlin.math.min -import kotlin.run -import kotlin.to @Suppress("unused") object StashMover : Module( name = "StashMover", description = "Moves items from one stash location to another", - tag = ModuleTag.WORLD + tag = ModuleTag.World, + modulePriority = 100 ) { - private enum class Group(override val displayName: String) : NamedEnum { - General("General"), - CommandBinds("Command Binds") - } + private const val GeneralTab = "General" + private const val CommandBindsTab = "Command Binds" - enum class Role(val createTask: () -> Task<*>) { + private enum class Role(val createTask: () -> Task<*>) { MoverBot({ MoverBot() }), PearlBot({ PearlBot() }) } @@ -115,70 +117,45 @@ object StashMover : Module( Drop("Drop") } - val role: Role by setting("Role", Role.MoverBot).group(Group.General) + @Tab(GeneralTab) private val role: Role by setting("Role", Role.MoverBot) .onValueChange { _, _ -> clearModule() } - private val pearlBotName by setting("PearlBot Name", "Steve") { role == Role.MoverBot }.group(Group.General) - private val moverBotName by setting("MoverBot Name", "Steve") { role == Role.PearlBot }.group(Group.General) - private val dropOffMode by setting("Drop-Off Mode", DropOffMode.Chests) { role == Role.MoverBot }.group(Group.General) - private var chestPullSelMode: Boolean by setting("Chest Pull Sel Mode", false, "Enables the mode to select the stash containers you want to move items from") { role == Role.MoverBot }.group(Group.General) + @Tab(GeneralTab) private val pearlBotName by setting("PearlBot Name", "Steve") { role == Role.MoverBot } + @Tab(GeneralTab) private val moverBotName by setting("MoverBot Name", "Steve") { role == Role.PearlBot } + @Tab(GeneralTab) private val dropOffMode by setting("Drop-Off Mode", DropOffMode.Chests) { role == Role.MoverBot } + @Tab(GeneralTab) private var chestPullSelMode: Boolean by setting("Chest Pull Sel Mode", false, "Enables the mode to select the stash containers you want to move items from") { role == Role.MoverBot } .onValueChange { _, to -> if (to) { chestPutSelMode = false; StashMover.info("Enabled chest pull selection mode!") } } - private var chestPutSelMode: Boolean by setting("Chest Put Sel Mode", false, "Enables the mod to select the stash containers you want to move items into") { role == Role.MoverBot }.group(Group.General) + @Tab(GeneralTab) private var chestPutSelMode: Boolean by setting("Chest Put Sel Mode", false, "Enables the mod to select the stash containers you want to move items into") { role == Role.MoverBot } .onValueChange { _, to -> if (to) { chestPullSelMode = false; StashMover.info("Enabled chest put selection mode!") } } - private val pearlMsgTimeout by setting("Pearl Msg Timeout", 100, 0..1500, 1, "Ticks before messaging the pearl bot again", "ticks") { role == Role.MoverBot }.group(Group.General) - private val pearlButtonTimeout by setting("Pearl Button Timeout", 100, 0..1500, 1, "Ticks before pressing the pearl dispenser button again", "ticks") { role == Role.MoverBot }.group(Group.General) - private val killRespawnTimeout by setting("Kill/Respawn Timeout", 100, 0..1500, 1, "Ticks before sending the kill command or attempting to respawn again", "ticks") { role == Role.MoverBot }.group(Group.General) - private val actionDelay by setting("Action Delay", 3, 0..20, 1, "The delay after performing one action, before the next") { role == Role.MoverBot }.group(Group.General) - private val useEnderChest by setting("Use Ender Chest", false, "Uses the ender chest to move more items at once. (Ender chests are included in the pull/put selections)") { role == Role.MoverBot }.group(Group.General) + @Tab(GeneralTab) private val pearlMsgTimeout by setting("Pearl Msg Timeout", 100, 0..1500, 1, "Ticks before messaging the pearl bot again", "ticks") { role == Role.MoverBot } + @Tab(GeneralTab) private val pearlButtonTimeout by setting("Pearl Button Timeout", 100, 0..1500, 1, "Ticks before pressing the pearl dispenser button again", "ticks") { role == Role.MoverBot } + @Tab(GeneralTab) private val killRespawnTimeout by setting("Kill/Respawn Timeout", 100, 0..1500, 1, "Ticks before sending the kill command or attempting to respawn again", "ticks") { role == Role.MoverBot } + @Tab(GeneralTab) private val actionDelay by setting("Action Delay", 3, 0..20, 1, "The delay after performing one action, before the next") { role == Role.MoverBot } + @Tab(GeneralTab) private val useEnderChest by setting("Use Ender Chest", false, "Uses the ender chest to move more items at once. (Ender chests are included in the pull/put selections)") { role == Role.MoverBot } .onValueChange { _, to -> if (!to) { putEnderChests.clear() pullEnderChests.clear() } } - private val breakEmptyPullContainers by setting("Break Empty Pull Containers", false, "Breaks empty pull containers after taking their items") { role == Role.MoverBot }.group(Group.General) - private val disconnectOnFinish by setting("Disconnect On Finish", false, "Disconnects the mover bot when it's finished") { role == Role.MoverBot }.group(Group.General) - private val disconnectOnFail by setting("Disconnect On Fail", false, "Disconnects the mover bot if it fails") { role == Role.MoverBot }.group(Group.General) - private val startStop by setting("Start/Stop", Bind.EMPTY, "Starts and stops the selected role").group(Group.General) - .onPress { event -> - event.cancel() - startStop() - } - private val pauseUnpause by setting("Pause/Unpause", Bind.EMPTY, "Pauses and unpauses the selected role").group(Group.General) - .onPress { event -> - event.cancel() - pauseUnpause() - } - - private val indexSelectedContainers by setting("Index Selected Containers", Bind.EMPTY, "Indexes the selected containers to pull/push items from/to") { role == Role.MoverBot }.group(Group.CommandBinds) - .onPress { event -> - event.cancel() - indexSelectedContainers() - } - private val removeSelectedContainers by setting("Remove Selected Containers", Bind.EMPTY, "Removes the selected containers from being pull/pushed from/to") { role == Role.MoverBot }.group(Group.CommandBinds) - .onPress { event -> - event.cancel() - removeSelectedContainers() - } - private val setItemThrowPosAndRotation by setting("Set Item Throw", Bind.EMPTY, "Sets the item throw position and rotation. (This is usually set to throw into hoppers to pickup the items)") { role == Role.MoverBot }.group(Group.CommandBinds) - .onPress { event -> - event.cancel() - setItemThrow() - } - private val setPearlButtonPos by setting("Set Pearl Button Pos", Bind.EMPTY, "Sets the button used to dispense a pearl for the player") { role == Role.MoverBot }.group(Group.CommandBinds) - .onPress { event -> - event.cancel() - setPearlButtonPos() - } - private val setPearlThrowPosAndRotation by setting("Set Pearl Throw", Bind.EMPTY, "Sets the pearl throw position and rotation. (This is best if you throw somewhat sideways into a line of bubble columns)") { role == Role.MoverBot }.group(Group.CommandBinds) - .onPress { event -> - event.cancel() - setPearlThrow() - } - private val setPearlBotButton by setting("Set PearlBot Button", Bind.EMPTY, "Sets the button position for the pearl bot to press to load the mover bot") { role == Role.PearlBot }.group(Group.CommandBinds) - .onPress { event -> - event.cancel() - setPearlBotButton() - } + @Tab(GeneralTab) private val breakEmptyPullContainers by setting("Break Empty Pull Containers", false, "Breaks empty pull containers after taking their items") { role == Role.MoverBot } + @Tab(GeneralTab) private val disconnectOnFinish by setting("Disconnect On Finish", false, "Disconnects the mover bot when it's finished") { role == Role.MoverBot } + @Tab(GeneralTab) private val disconnectOnFail by setting("Disconnect On Fail", false, "Disconnects the mover bot if it fails") { role == Role.MoverBot } + @Tab(GeneralTab) private val startStop by setting("Start/Stop", Bind.Empty, "Starts and stops the selected role") + .onPress { event -> event.cancel(); startStop() } + @Tab(GeneralTab) private val pauseUnpause by setting("Pause/Unpause", Bind.Empty, "Pauses and unpauses the selected role") + .onPress { event -> event.cancel(); pauseUnpause() } + @Tab(CommandBindsTab) private val indexSelectedContainers by setting("Index Selected Containers", Bind.Empty, "Indexes the selected containers to pull/push items from/to") { role == Role.MoverBot } + .onPress { event -> event.cancel(); indexSelectedContainers() } + @Tab(CommandBindsTab) private val removeSelectedContainers by setting("Remove Selected Containers", Bind.Empty, "Removes the selected containers from being pull/pushed from/to") { role == Role.MoverBot } + .onPress { event -> event.cancel(); removeSelectedContainers() } + @Tab(CommandBindsTab) private val setItemThrowPosAndRotation by setting("Set Item Throw", Bind.Empty, "Sets the item throw position and rotation. (This is usually set to throw into hoppers to pickup the items)") { role == Role.MoverBot } + .onPress { event -> event.cancel(); setItemThrow() } + @Tab(CommandBindsTab) private val setPearlButtonPos by setting("Set Pearl Button Pos", Bind.Empty, "Sets the button used to dispense a pearl for the player") { role == Role.MoverBot } + .onPress { event -> event.cancel(); setPearlButtonPos() } + @Tab(CommandBindsTab) private val setPearlThrowPosAndRotation by setting("Set Pearl Throw", Bind.Empty, "Sets the pearl throw position and rotation. (This is best if you throw somewhat sideways into a line of bubble columns)") { role == Role.MoverBot } + .onPress { event -> event.cancel(); setPearlThrow() } + @Tab(CommandBindsTab) private val setPearlBotButton by setting("Set PearlBot Button", Bind.Empty, "Sets the button position for the pearl bot to press to load the mover bot") { role == Role.PearlBot } + .onPress { event -> event.cancel(); setPearlBotButton() } private var sel1: BlockPos? = null private var sel2: BlockPos? = null @@ -202,20 +179,18 @@ object StashMover : Module( private var task: Task<*>? = null init { - setModulePriority(100) - setDefaultAutomationConfig { - applyEdits { + setDefaultAutomationConfig() + .withEdits { buildConfig.apply { editTyped(::pathing, ::stayInRange, ::checkSideVisibility) { defaultValue(true) } hide(::pathing, ::stayInRange, ::collectDrops, ::spleefEntities, ::entityReach) - hideGroup(eatConfig) + hideBlock(::eatConfig) } interactConfig::airPlace.edit { defaultValue(InteractConfig.AirPlaceMode.None) } breakConfig.apply { editTyped(::suitableToolsOnly, ::efficientOnly) { defaultValue(false) } } } - } listen { event -> if (!chestPullSelMode && !chestPutSelMode) return@listen @@ -602,10 +577,10 @@ object StashMover : Module( private fun SafeContext.handleDroppingItems() { val throwPos = itemThrowPos ?: run { failWithLog("No item throw pos set!"); return } if (player.blockPos != throwPos) { - BaritoneManager.setGoalAndPath(GoalBlock(throwPos)) + BaritoneHandler.setGoalAndPath(GoalBlock(throwPos)) return } - if (BaritoneManager.isActive) return + if (BaritoneHandler.isActive) return val rotation = itemThrowRotation ?: run { failWithLog("No item throw rotation set!"); return } val rotationRequest = rotationRequest { rotation(rotation) @@ -655,10 +630,10 @@ object StashMover : Module( private fun SafeContext.handleDispensingPearl() { val dispensePos = pearlDispensePos ?: run { failWithLog("No pearl button set!"); return } if (player.blockPos != dispensePos) { - BaritoneManager.setGoalAndPath(GoalBlock(dispensePos)) + BaritoneHandler.setGoalAndPath(GoalBlock(dispensePos)) return } - if (BaritoneManager.isActive) return + if (BaritoneHandler.isActive) return if (player.hotbarStacks.none { it.isEmpty }) { val firstSlot = player.hotbarSlots.getOrNull(0) ?: run { failWithLog("No first slot? This shouldn't occur."); return } if (player.inventoryStacks.any { it.isEmpty }) { @@ -682,10 +657,10 @@ object StashMover : Module( private fun SafeContext.handleThrowingPearl() { val throwPos = pearlThrowPos ?: run { failWithLog("No pearl throw pos set!"); return } if (player.blockPos != throwPos) { - BaritoneManager.setGoalAndPath(GoalBlock(throwPos)) + BaritoneHandler.setGoalAndPath(GoalBlock(throwPos)) return } - if (BaritoneManager.isActive) return + if (BaritoneHandler.isActive) return if (player.velocity.y < -0.08 || player.velocity.x !in -0.001..0.001 || player.velocity.z !in -0.001..0.001) return if (pearlThrown) { diff --git a/src/main/kotlin/com/lambda/module/modules/world/WorldEater.kt b/src/main/kotlin/com/lambda/module/modules/world/WorldEater.kt deleted file mode 100644 index 1de112cbc..000000000 --- a/src/main/kotlin/com/lambda/module/modules/world/WorldEater.kt +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright 2026 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.module.modules.world - -import com.lambda.graphics.mc.renderer.TickedRenderer.Companion.tickedRenderer -import com.lambda.interaction.BaritoneManager -import com.lambda.interaction.construction.blueprint.Blueprint.Companion.toStructure -import com.lambda.interaction.construction.blueprint.StaticBlueprint.Companion.toBlueprint -import com.lambda.interaction.construction.verify.TargetState -import com.lambda.module.Module -import com.lambda.module.tag.ModuleTag -import com.lambda.task.RootTask.run -import com.lambda.task.Task -import com.lambda.task.tasks.BuildTask.Companion.build -import net.minecraft.util.math.BlockBox -import net.minecraft.util.math.BlockPos -import net.minecraft.util.math.Box -import java.awt.Color - -object WorldEater : Module( - name = "WorldEater", - description = "Eats the world", - tag = ModuleTag.WORLD, -) { -// private val height by setting("Height", 4, 1..10, 1) -// private val width by setting("Width", 6, 1..30, 1) - private val pos1 by setting("Position 1", BlockPos(351, 104, 103)) - private val pos2 by setting("Position 2", BlockPos(361, 70, 113)) - private val layerSize by setting("Layer Size", 1, 1..10, 1) - private var runningTask: Task<*>? = null - private var area = BlockBox.create(pos1, pos2) - private val work = mutableListOf() - - init { - onEnable { - area = BlockBox.create(pos1, pos2) - val layerRanges = (area.minY..area.maxY step layerSize).reversed() - work.addAll(layerRanges.mapNotNull { y -> - if (y == area.minY) return@mapNotNull null - BlockBox(area.minX, y - layerSize, area.minZ, area.maxX, y, area.maxZ) - }) - - buildLayer() - } - - onDisable { - runningTask?.cancel() - runningTask = null - work.clear() - BaritoneManager.cancel() - } - - tickedRenderer("WorldEater Ticked Renderer") { - box(Box.enclosing(pos1, pos2)) { - hideFill() - outlineColor(Color.BLUE) - } - } - } - - private fun buildLayer() { - work.firstOrNull()?.let { box -> - runningTask = build { - box.toStructure(TargetState.Air) - .toBlueprint() - }.finally { - work.removeFirstOrNull() - buildLayer() - }.run() - } ?: disable() - } -} \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/module/tag/ModuleTag.kt b/src/main/kotlin/com/lambda/module/tag/ModuleTag.kt index caab346cc..e44630f94 100644 --- a/src/main/kotlin/com/lambda/module/tag/ModuleTag.kt +++ b/src/main/kotlin/com/lambda/module/tag/ModuleTag.kt @@ -36,18 +36,18 @@ data class ModuleTag(override val name: String) : Nameable { // Totally needs to be reworked // ToDo: Add registry for tags companion object { - val COMBAT = ModuleTag("Combat") - val MOVEMENT = ModuleTag("Movement") - val RENDER = ModuleTag("Render") - val PLAYER = ModuleTag("Player") - val WORLD = ModuleTag("World") - val CHAT = ModuleTag("Chat") - val CLIENT = ModuleTag("Client") - val NETWORK = ModuleTag("Network") - val DEBUG = ModuleTag("Debug") - val HUD = ModuleTag("Hud") + val Combat = ModuleTag("Combat") + val Movement = ModuleTag("Movement") + val Render = ModuleTag("Render") + val Player = ModuleTag("Player") + val World = ModuleTag("World") + val Chat = ModuleTag("Chat") + val Client = ModuleTag("Client") + val Network = ModuleTag("Network") + val Debug = ModuleTag("Debug") + val Hud = ModuleTag("Hud") - val defaults = setOf(COMBAT, MOVEMENT, RENDER, PLAYER, WORLD, NETWORK, CHAT, CLIENT, HUD) + val defaults = setOf(Combat, Movement, Render, Player, World, Network, Chat, Client, Hud) val shownTags = defaults.toMutableSet() diff --git a/src/main/kotlin/com/lambda/network/CapeManager.kt b/src/main/kotlin/com/lambda/network/CapeHandler.kt similarity index 91% rename from src/main/kotlin/com/lambda/network/CapeManager.kt rename to src/main/kotlin/com/lambda/network/CapeHandler.kt index 4e2a7ca4a..ab89539f9 100644 --- a/src/main/kotlin/com/lambda/network/CapeManager.kt +++ b/src/main/kotlin/com/lambda/network/CapeHandler.kt @@ -17,10 +17,10 @@ package com.lambda.network -import com.lambda.Lambda.LOG +import com.lambda.Lambda.Log import com.lambda.Lambda.mc -import com.lambda.config.Configurable -import com.lambda.config.configurations.SecretsConfig +import com.lambda.config.Config +import com.lambda.config.categories.SecretsCategory import com.lambda.core.Loadable import com.lambda.event.events.WorldEvent import com.lambda.event.listener.SafeListener.Companion.listen @@ -34,7 +34,7 @@ import com.lambda.util.FileUtils.downloadCompare import com.lambda.util.FileUtils.downloadIfNotPresent import com.lambda.util.FileUtils.ifNotExists import com.lambda.util.FileUtils.isOlderThan -import com.lambda.util.FolderRegister.capes +import com.lambda.util.FolderRegistry.capes import com.lambda.util.StringUtils.asIdentifier import com.lambda.util.extension.resolveFile import kotlinx.coroutines.runBlocking @@ -48,9 +48,11 @@ import kotlin.concurrent.fixedRateTimer import kotlin.time.Duration.Companion.hours import kotlin.time.Duration.Companion.seconds -object CapeManager : Configurable(SecretsConfig), Loadable { - override val name: String = "capes" - +@Suppress("unused") +object CapeHandler : Config( + "capes", + SecretsCategory +), Loadable { var currentCape by setting("cape", "") .onValueChangeUnsafe { _, to -> updateCape(to) } @@ -61,11 +63,11 @@ object CapeManager : Configurable(SecretsConfig), Loadable { capes.resolveFile("capes.txt") .isOlderThan(24.hours) { it.downloadIfNotPresent("${LambdaAPI.capes}.txt") - .onFailure { err -> LOG.error("Could not download the cape list: $err") } + .onFailure { err -> Log.error("Could not download the cape list: $err") } } .ifNotExists { it.downloadCompare("${LambdaAPI.capes}.txt", -1) - .onFailure { err -> LOG.error("Could not download the cape list: $err") } + .onFailure { err -> Log.error("Could not download the cape list: $err") } } .createIfNotExists() .readText() diff --git a/src/main/kotlin/com/lambda/network/LambdaAPI.kt b/src/main/kotlin/com/lambda/network/LambdaAPI.kt index f720edddc..62e99443b 100644 --- a/src/main/kotlin/com/lambda/network/LambdaAPI.kt +++ b/src/main/kotlin/com/lambda/network/LambdaAPI.kt @@ -17,16 +17,16 @@ package com.lambda.network -import com.lambda.Lambda.LOG +import com.lambda.Lambda.Log import com.lambda.Lambda.mc -import com.lambda.config.Configurable -import com.lambda.config.configurations.LambdaConfig +import com.lambda.config.Config +import com.lambda.config.categories.LambdaCategory import com.lambda.event.events.ClientEvent import com.lambda.event.events.ConnectionEvent import com.lambda.event.events.ConnectionEvent.Connect.Login.EncryptionResponse -import com.lambda.event.listener.UnsafeListener.Companion.listenUnsafe import com.lambda.event.listener.UnsafeListener.Companion.listenConcurrentlyUnsafe -import com.lambda.network.NetworkManager.updateToken +import com.lambda.event.listener.UnsafeListener.Companion.listenUnsafe +import com.lambda.network.NetworkHandler.updateToken import com.lambda.network.api.v1.endpoints.login import com.lambda.util.StringUtils.hash import com.lambda.util.extension.isOffline @@ -42,9 +42,10 @@ import net.minecraft.text.Text import java.math.BigInteger import kotlin.jvm.optionals.getOrElse -object LambdaAPI : Configurable(LambdaConfig) { - override val name = "api" - +object LambdaAPI : Config( + "api", + LambdaCategory +) { val authServer by setting("Auth Server", "auth.lambda-client.org") val apiUrl by setting("API Server", "https://api.lambda-client.org") val apiVersion by setting("API Version", ApiVersion.V1) @@ -71,14 +72,14 @@ object LambdaAPI : Configurable(LambdaConfig) { listenConcurrentlyUnsafe { // FixMe: If the player have the properties but are invalid this doesn't work - if (NetworkManager.isValid || mc.gameProfile.isOffline) return@listenConcurrentlyUnsafe + if (NetworkHandler.isValid || mc.gameProfile.isOffline) return@listenConcurrentlyUnsafe // If we log in right as the client responds to the encryption request, we start // a race condition where the game server haven't acknowledged the packets // and posted to the sessionserver api login(mc.session.username, hash ?: return@listenConcurrentlyUnsafe) .onSuccess { updateToken(it) } - .onFailure { LOG.warn(it) } + .onFailure { Log.warn(it) } } } diff --git a/src/main/kotlin/com/lambda/network/LambdaHttp.kt b/src/main/kotlin/com/lambda/network/LambdaHttp.kt index 3805f11d2..9062a40a0 100644 --- a/src/main/kotlin/com/lambda/network/LambdaHttp.kt +++ b/src/main/kotlin/com/lambda/network/LambdaHttp.kt @@ -17,20 +17,18 @@ package com.lambda.network -import com.lambda.Lambda import io.ktor.client.* import io.ktor.client.plugins.contentnegotiation.* import io.ktor.client.request.* import io.ktor.client.statement.* import io.ktor.http.* -import io.ktor.serialization.gson.* +import io.ktor.serialization.jackson.* import java.io.File import java.io.OutputStream val LambdaHttp = HttpClient { install(ContentNegotiation) { - // Use our gson instance - register(ContentType.Application.Json, GsonConverter(Lambda.gson)) + register(ContentType.Application.Json, JacksonConverter()) } } diff --git a/src/main/kotlin/com/lambda/network/NetworkManager.kt b/src/main/kotlin/com/lambda/network/NetworkHandler.kt similarity index 86% rename from src/main/kotlin/com/lambda/network/NetworkManager.kt rename to src/main/kotlin/com/lambda/network/NetworkHandler.kt index 94103bff0..72d1e7cf8 100644 --- a/src/main/kotlin/com/lambda/network/NetworkManager.kt +++ b/src/main/kotlin/com/lambda/network/NetworkHandler.kt @@ -17,19 +17,20 @@ package com.lambda.network +import com.lambda.Lambda.mapper import com.lambda.Lambda.mc -import com.lambda.config.Configurable -import com.lambda.config.configurations.SecretsConfig +import com.lambda.config.Config +import com.lambda.config.categories.SecretsCategory import com.lambda.core.Loadable import com.lambda.network.api.v1.models.Authentication import com.lambda.network.api.v1.models.Authentication.Data import com.lambda.util.StringUtils.base64UrlDecode -import com.lambda.util.StringUtils.json import com.lambda.util.collections.updatableLazy -object NetworkManager : Configurable(SecretsConfig), Loadable { - override val name = "network" - +object NetworkHandler : Config( + "network", + SecretsCategory +), Loadable { var accessToken by setting("access_token", "") { false }; private set val isValid: Boolean @@ -42,7 +43,7 @@ object NetworkManager : Configurable(SecretsConfig), Loadable { if (parts.size != 3) return@updatableLazy null val payload = parts[1] - val data = payload.base64UrlDecode().json() + val data = mapper.readValue(payload.base64UrlDecode(), Data::class.java) return@updatableLazy if (System.currentTimeMillis() < data.expirationDate) null else data diff --git a/src/main/kotlin/com/lambda/network/api/v1/endpoints/LinkDiscord.kt b/src/main/kotlin/com/lambda/network/api/v1/endpoints/LinkDiscord.kt index 31c8a7ad2..5a87d79e8 100644 --- a/src/main/kotlin/com/lambda/network/api/v1/endpoints/LinkDiscord.kt +++ b/src/main/kotlin/com/lambda/network/api/v1/endpoints/LinkDiscord.kt @@ -20,7 +20,7 @@ package com.lambda.network.api.v1.endpoints import com.lambda.network.LambdaAPI.apiUrl import com.lambda.network.LambdaAPI.apiVersion import com.lambda.network.LambdaHttp -import com.lambda.network.NetworkManager +import com.lambda.network.NetworkHandler import com.lambda.network.api.v1.models.Authentication import io.ktor.client.call.* import io.ktor.client.request.* @@ -35,7 +35,7 @@ import io.ktor.http.* suspend fun linkDiscord(discordToken: String) = runCatching { LambdaHttp.post("${apiUrl}/api/$apiVersion/link/discord") { setBody("""{ "token": "$discordToken" }""") - bearerAuth(NetworkManager.accessToken) + bearerAuth(NetworkHandler.accessToken) contentType(ContentType.Application.Json) }.body() } diff --git a/src/main/kotlin/com/lambda/network/api/v1/endpoints/SetCape.kt b/src/main/kotlin/com/lambda/network/api/v1/endpoints/SetCape.kt index 16682bbcb..5086396e1 100644 --- a/src/main/kotlin/com/lambda/network/api/v1/endpoints/SetCape.kt +++ b/src/main/kotlin/com/lambda/network/api/v1/endpoints/SetCape.kt @@ -20,7 +20,7 @@ package com.lambda.network.api.v1.endpoints import com.lambda.network.LambdaAPI.apiUrl import com.lambda.network.LambdaAPI.apiVersion import com.lambda.network.LambdaHttp -import com.lambda.network.NetworkManager +import com.lambda.network.NetworkHandler import io.ktor.client.request.* import io.ktor.http.* @@ -32,7 +32,7 @@ import io.ktor.http.* */ suspend fun setCape(id: String) = runCatching { val resp = LambdaHttp.put("$apiUrl/api/$apiVersion/cape?id=$id") { - bearerAuth(NetworkManager.accessToken) + bearerAuth(NetworkHandler.accessToken) contentType(ContentType.Application.Json) } diff --git a/src/main/kotlin/com/lambda/network/api/v1/models/Authentication.kt b/src/main/kotlin/com/lambda/network/api/v1/models/Authentication.kt index f91d78e7d..3a5cbf243 100644 --- a/src/main/kotlin/com/lambda/network/api/v1/models/Authentication.kt +++ b/src/main/kotlin/com/lambda/network/api/v1/models/Authentication.kt @@ -17,29 +17,29 @@ package com.lambda.network.api.v1.models -import com.google.gson.annotations.SerializedName +import com.fasterxml.jackson.annotation.JsonProperty data class Authentication( - @SerializedName("access_token") + @JsonProperty("access_token") val accessToken: String, - @SerializedName("expires_in") + @JsonProperty("expires_in") val expiresIn: Long, - @SerializedName("token_type") + @JsonProperty("token_type") val tokenType: String, ) { data class Data( - @SerializedName("nbf") + @JsonProperty("nbf") val notBefore: Long, - @SerializedName("iat") + @JsonProperty("iat") val issuedAt: Long, - @SerializedName("exp") + @JsonProperty("exp") val expirationDate: Long, - @SerializedName("data") + @JsonProperty("data") val data: Player, ) } diff --git a/src/main/kotlin/com/lambda/network/api/v1/models/Cape.kt b/src/main/kotlin/com/lambda/network/api/v1/models/Cape.kt index 30853200e..ae22cb2b0 100644 --- a/src/main/kotlin/com/lambda/network/api/v1/models/Cape.kt +++ b/src/main/kotlin/com/lambda/network/api/v1/models/Cape.kt @@ -17,15 +17,15 @@ package com.lambda.network.api.v1.models -import com.google.gson.annotations.SerializedName +import com.fasterxml.jackson.annotation.JsonProperty import com.lambda.network.LambdaAPI import java.util.* class Cape( - @SerializedName("uuid") + @JsonProperty("uuid") val uuid: UUID, - @SerializedName("type") + @JsonProperty("type") val id: String, ) { val url: String diff --git a/src/main/kotlin/com/lambda/network/api/v1/models/Player.kt b/src/main/kotlin/com/lambda/network/api/v1/models/Player.kt index a8f8137dc..fc3b52b1f 100644 --- a/src/main/kotlin/com/lambda/network/api/v1/models/Player.kt +++ b/src/main/kotlin/com/lambda/network/api/v1/models/Player.kt @@ -17,20 +17,20 @@ package com.lambda.network.api.v1.models -import com.google.gson.annotations.SerializedName +import com.fasterxml.jackson.annotation.JsonProperty import java.util.* data class Player( - @SerializedName("name") + @JsonProperty("name") val name: String, - @SerializedName("id") + @JsonProperty("id") val uuid: UUID, - @SerializedName("discord_id") + @JsonProperty("discord_id") val discordId: String, // Whether the player is verified or not - @SerializedName("unsafe") + @JsonProperty("unsafe") val unsafe: Boolean, ) diff --git a/src/main/kotlin/com/lambda/sound/SoundManager.kt b/src/main/kotlin/com/lambda/sound/SoundHandler.kt similarity index 98% rename from src/main/kotlin/com/lambda/sound/SoundManager.kt rename to src/main/kotlin/com/lambda/sound/SoundHandler.kt index e2f63d11e..1125a5061 100644 --- a/src/main/kotlin/com/lambda/sound/SoundManager.kt +++ b/src/main/kotlin/com/lambda/sound/SoundHandler.kt @@ -26,7 +26,7 @@ import net.minecraft.registry.Registry import net.minecraft.registry.SimpleRegistry import net.minecraft.sound.SoundEvent -object SoundManager : Loadable { +object SoundHandler : Loadable { fun playSound(event: SoundEvent, pitch: Double = 1.0) { mc.soundManager.play( PositionedSoundInstance.master(event, pitch.toFloat()) diff --git a/src/main/kotlin/com/lambda/task/Task.kt b/src/main/kotlin/com/lambda/task/Task.kt index e36f62778..af71d6332 100644 --- a/src/main/kotlin/com/lambda/task/Task.kt +++ b/src/main/kotlin/com/lambda/task/Task.kt @@ -17,16 +17,16 @@ package com.lambda.task -import com.lambda.Lambda.LOG -import com.lambda.module.modules.client.Client.verboseDebug +import com.lambda.Lambda.Log import com.lambda.context.SafeContext import com.lambda.event.EventFlow.unsubscribe import com.lambda.event.Muteable import com.lambda.event.events.TickEvent import com.lambda.event.listener.SafeListener.Companion.listen import com.lambda.module.modules.client.Client +import com.lambda.module.modules.client.Client.verboseDebug import com.lambda.threading.runSafe -import com.lambda.util.Communication.logError +import com.lambda.util.CommunicationUtils.logError import com.lambda.util.Nameable import com.lambda.util.StringUtils.capitalize import kotlin.time.Duration.Companion.milliseconds @@ -37,6 +37,7 @@ typealias TaskGenerator = SafeContext.(R) -> Task<*> typealias TaskGeneratorOrNull = SafeContext.(R) -> Task<*>? typealias TaskGeneratorUnit = SafeContext.(R) -> Unit +@Suppress("unused") abstract class Task : Nameable, Muteable { var parent: Task<*>? = null var parentPausing = false @@ -119,10 +120,10 @@ abstract class Task : Nameable, Muteable { require(owner != this) { "Cannot execute a task as a child of itself" } owner.subTasks.add(this) parent = owner - if (verboseDebug) LOG.info("${owner.name} started $name") + if (verboseDebug) Log.info("${owner.name} started $name") if (pauseParent) { parentPausing = true - if (verboseDebug) LOG.info("$name pausing parent ${owner.name}") + if (verboseDebug) Log.info("$name pausing parent ${owner.name}") if (owner !is RootTask) owner.pause() } state = State.Running @@ -229,7 +230,7 @@ abstract class Task : Nameable, Muteable { } } } - LOG.error(message, e) + Log.error(message, e) logError(message) } } diff --git a/src/main/kotlin/com/lambda/task/tasks/AcquireMaterialTask.kt b/src/main/kotlin/com/lambda/task/tasks/AcquireMaterialTask.kt index d4d139595..2041fe7db 100644 --- a/src/main/kotlin/com/lambda/task/tasks/AcquireMaterialTask.kt +++ b/src/main/kotlin/com/lambda/task/tasks/AcquireMaterialTask.kt @@ -20,8 +20,8 @@ package com.lambda.task.tasks import com.lambda.context.Automated import com.lambda.context.SafeContext import com.lambda.interaction.material.StackSelection -import com.lambda.interaction.material.container.ContainerManager -import com.lambda.interaction.material.container.ContainerManager.findContainerWithMaterial +import com.lambda.interaction.material.container.ContainerHandler +import com.lambda.interaction.material.container.ContainerHandler.findContainerWithMaterial import com.lambda.interaction.material.container.containers.HotbarContainer import com.lambda.task.Task import com.lambda.threading.runSafeAutomated @@ -40,7 +40,7 @@ class AcquireMaterialTask @Ta5kBuilder constructor( ?.finally { success(selection) }?.execute(this@AcquireMaterialTask) - ?: failure(ContainerManager.NoContainerFound(selection)) // ToDo: Create crafting path + ?: failure(ContainerHandler.NoContainerFound(selection)) // ToDo: Create crafting path } } diff --git a/src/main/kotlin/com/lambda/task/tasks/BuildTask.kt b/src/main/kotlin/com/lambda/task/tasks/BuildTask.kt index 71741c9fc..db9a60a8e 100644 --- a/src/main/kotlin/com/lambda/task/tasks/BuildTask.kt +++ b/src/main/kotlin/com/lambda/task/tasks/BuildTask.kt @@ -18,15 +18,15 @@ package com.lambda.task.tasks import baritone.api.pathing.goals.GoalBlock -import com.lambda.Lambda.LOG -import com.lambda.config.groups.EatConfig.Companion.reasonEating +import com.lambda.Lambda.Log +import com.lambda.config.settings.blocks.EatConfig.Companion.reasonEating import com.lambda.context.Automated import com.lambda.context.AutomatedSafeContext import com.lambda.context.SafeContext import com.lambda.event.events.PacketEvent import com.lambda.event.events.TickEvent import com.lambda.event.listener.SafeListener.Companion.listen -import com.lambda.interaction.BaritoneManager +import com.lambda.interaction.BaritoneHandler import com.lambda.interaction.construction.blueprint.Blueprint import com.lambda.interaction.construction.blueprint.Blueprint.Companion.toStructure import com.lambda.interaction.construction.blueprint.PropagatingBlueprint @@ -59,7 +59,7 @@ import com.lambda.threading.runSafeAutomated import com.lambda.util.BlockUtils.blockState import com.lambda.util.EntityUtils.getClosestPointTo import com.lambda.util.EntityUtils.getPositionsWithinBox -import com.lambda.util.Formatting.format +import com.lambda.util.FormattingUtils.format import com.lambda.util.extension.Structure import com.lambda.util.extension.playerSlots import com.lambda.util.math.dist @@ -73,7 +73,7 @@ import net.minecraft.network.packet.s2c.play.ChunkDeltaUpdateS2CPacket import net.minecraft.network.packet.s2c.play.EntityPositionS2CPacket import net.minecraft.network.packet.s2c.play.PlayerPositionLookS2CPacket import net.minecraft.util.math.BlockPos -import java.util.Collections +import java.util.* import java.util.concurrent.ConcurrentLinkedQueue import kotlin.coroutines.cancellation.CancellationException import kotlin.math.sqrt @@ -275,11 +275,11 @@ class BuildTask private constructor( if (!buildConfig.pathing) return val sim = blueprint.simulation() val goal = BuildGoal(sim, player.blockPos) - BaritoneManager.setGoalAndPath(goal) + BaritoneHandler.setGoalAndPath(goal) } is Navigable -> { - if (buildConfig.pathing) BaritoneManager.setGoalAndPath(result.goal) + if (buildConfig.pathing) BaritoneHandler.setGoalAndPath(result.goal ?: return) } is Contextual -> { @@ -304,7 +304,7 @@ class BuildTask private constructor( is Dependent -> handleResult(result.lastDependency, allResults) is Resolvable -> { - LOG.info("Resolving: ${result.name}") + Log.info("Resolving: ${result.name}") result.resolve() } } @@ -318,7 +318,7 @@ class BuildTask private constructor( if (!world.entities.contains(itemDrop)) { dropsToCollect.remove(itemDrop) - BaritoneManager.cancel() + BaritoneHandler.cancel() return@let true } @@ -335,8 +335,8 @@ class BuildTask private constructor( return@let true } - BaritoneManager.setGoalAndPath(GoalBlock(itemDrop.blockPos)) - return@let true + BaritoneHandler.setGoalAndPath(GoalBlock(itemDrop.blockPos)) + true } ?: false fun iteratePropagating() = diff --git a/src/main/kotlin/com/lambda/task/tasks/EatTask.kt b/src/main/kotlin/com/lambda/task/tasks/EatTask.kt index 9257c76a0..6b5051ffb 100644 --- a/src/main/kotlin/com/lambda/task/tasks/EatTask.kt +++ b/src/main/kotlin/com/lambda/task/tasks/EatTask.kt @@ -17,17 +17,15 @@ package com.lambda.task.tasks -import com.lambda.config.groups.EatConfig -import com.lambda.config.groups.EatConfig.Companion.reasonEating +import com.lambda.config.settings.blocks.EatConfig +import com.lambda.config.settings.blocks.EatConfig.Companion.reasonEating import com.lambda.context.Automated import com.lambda.context.SafeContext import com.lambda.event.events.TickEvent import com.lambda.event.listener.SafeListener.Companion.listen import com.lambda.interaction.managers.hotbar.HotbarRequest -import com.lambda.interaction.material.container.ContainerManager.transfer import com.lambda.interaction.material.container.containers.HotbarContainer import com.lambda.interaction.material.container.containers.InventoryContainer -import com.lambda.interaction.material.container.containers.MainHandContainer import com.lambda.task.Task import com.lambda.threading.runSafeAutomated import net.minecraft.item.ItemStack diff --git a/src/main/kotlin/com/lambda/task/tasks/OpenContainerTask.kt b/src/main/kotlin/com/lambda/task/tasks/OpenContainerTask.kt index 9a1e9aaec..48ce8c309 100644 --- a/src/main/kotlin/com/lambda/task/tasks/OpenContainerTask.kt +++ b/src/main/kotlin/com/lambda/task/tasks/OpenContainerTask.kt @@ -22,12 +22,12 @@ import com.lambda.context.Automated import com.lambda.event.events.InventoryEvent import com.lambda.event.events.TickEvent import com.lambda.event.listener.SafeListener.Companion.listen -import com.lambda.interaction.BaritoneManager +import com.lambda.interaction.BaritoneHandler import com.lambda.interaction.managers.rotating.IRotationRequest.Companion.rotationRequest -import com.lambda.interaction.managers.rotating.visibilty.lookAtBlock import com.lambda.task.Task import com.lambda.threading.runSafeAutomated import com.lambda.util.TickTimer +import com.lambda.util.player.RotationUtils.lookAtBlock import com.lambda.util.world.raycast.RayCastUtils.blockResult import net.minecraft.screen.ScreenHandler import net.minecraft.util.Hand @@ -98,7 +98,7 @@ class OpenContainerTask @Ta5kBuilder constructor( val checkedHit = runSafeAutomated { lookAtBlock(blockPos, sides) } ?: run { containerState = State.Pathing - if (!BaritoneManager.isActive) BaritoneManager.setGoalAndPath(GoalNear(blockPos, 3)) + if (!BaritoneHandler.isActive) BaritoneHandler.setGoalAndPath(GoalNear(blockPos, 3)) return@listen } if (interactConfig.rotate && !rotationRequest { rotation(checkedHit.rotation) }.submit().done) return@listen diff --git a/src/main/kotlin/com/lambda/util/Communication.kt b/src/main/kotlin/com/lambda/util/CommunicationUtils.kt similarity index 94% rename from src/main/kotlin/com/lambda/util/Communication.kt rename to src/main/kotlin/com/lambda/util/CommunicationUtils.kt index 08c644b95..c83cd1576 100644 --- a/src/main/kotlin/com/lambda/util/Communication.kt +++ b/src/main/kotlin/com/lambda/util/CommunicationUtils.kt @@ -21,7 +21,7 @@ import com.lambda.Lambda import com.lambda.Lambda.mc import com.lambda.command.CommandRegistry import com.lambda.command.LambdaCommand -import com.lambda.config.Configuration +import com.lambda.config.ConfigLoader import com.lambda.core.Loader import com.lambda.event.EventFlow import com.lambda.gui.components.ClickGuiLayout @@ -46,7 +46,7 @@ import java.time.ZoneId import java.time.format.DateTimeFormatter import java.time.format.FormatStyle -object Communication { +object CommunicationUtils { val ascii = """ ⣰⡛⠶⣄⠀⠀⠀⠀⠀⠀ @@ -199,16 +199,20 @@ object Communication { hoverEvent(HoverEvents.showText(buildText { literal("Lambda ") color(color) { - literal(Lambda.SYMBOL) + literal(Lambda.Symbol) } - literal(" v${Lambda.VERSION}\n") + literal(" v${Lambda.Version}\n") literal("Runtime: ${Loader.runtime}\n") literal("Modules: ${ModuleRegistry.modules.size}\n") literal("Commands: ${CommandRegistry.commands.size}\n") literal( "Settings: ${ - Configuration.configurations.sumOf { config -> - config.configurables.sumOf { it.settings.size } + ConfigLoader.configCategories.sumOf { config -> + config.configs.sumOf { + var count = 0 + it.forEachSetting { _, _ -> count++ } + count + } } }" ) @@ -218,7 +222,7 @@ object Communication { })) { styled(color) { - literal(Lambda.SYMBOL) + literal(Lambda.Symbol) } literal(" ") } diff --git a/src/main/kotlin/com/lambda/util/DebugInfoHud.kt b/src/main/kotlin/com/lambda/util/DebugInfoHud.kt deleted file mode 100644 index 83fd62349..000000000 --- a/src/main/kotlin/com/lambda/util/DebugInfoHud.kt +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2026 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.util - -import com.lambda.Lambda -import com.lambda.Lambda.mc -import com.lambda.command.CommandRegistry -import com.lambda.event.EventFlow -import com.lambda.module.ModuleRegistry -import com.lambda.util.Formatting.format -import com.lambda.util.extension.tickDeltaF -import net.minecraft.util.Formatting -import net.minecraft.util.hit.BlockHitResult -import net.minecraft.util.hit.EntityHitResult - -object DebugInfoHud { - @JvmStatic - fun MutableList.addDebugInfo() { - add("") - add("" + Formatting.UNDERLINE + "Lambda ${Lambda.VERSION}+${mc.versionType}") - add("Modules: ${ModuleRegistry.modules.size} with ${ModuleRegistry.modules.sumOf { it.settings.size }} settings") - add("Commands: ${CommandRegistry.commands.size}") - add("Synchronous Listeners: ${EventFlow.syncListeners.size}") - add("Concurrent Listeners: ${EventFlow.concurrentListeners.size}") - - when (val hit = mc.crosshairTarget) { - is BlockHitResult -> { - add("Crosshair Target: Block") - add(" Vec3d: %.5f, %.5f, %.5f".format(hit.pos.x, hit.pos.y, hit.pos.z)) - add(" BlockPos: ${hit.blockPos.toShortString()}") - add(" Side: ${hit.side}") - } - - is EntityHitResult -> { - add("Crosshair Target: Entity") - add(" Vec3d: ${hit.pos}") - add(" Entity: ${hit.entity}") - } - - null -> add("Crosshair Target: None") - } - - add("Eye Pos: ${mc.cameraEntity?.getCameraPosVec(mc.tickDeltaF)?.format()}") - - return - } -} diff --git a/src/main/kotlin/com/lambda/util/Diagnostics.kt b/src/main/kotlin/com/lambda/util/Diagnostics.kt index d8eadc37f..c1cdb51f7 100644 --- a/src/main/kotlin/com/lambda/util/Diagnostics.kt +++ b/src/main/kotlin/com/lambda/util/Diagnostics.kt @@ -25,11 +25,12 @@ object Diagnostics { modules.filter { it.isEnabled } .forEach { module -> append("\t${module.name}") - module.settings - .filter { it.isModified } - .forEach { setting -> - append("\t\t${setting.name} -> ${setting.value}") + module.forEachSetting { path, single -> + val setting = single.setting + if (setting.isModified) { + append("\t\t${path.joinToString(".", postfix = ".") { it.name }}${setting.name} -> ${setting.value}") } + } } } } \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/util/DynamicException.kt b/src/main/kotlin/com/lambda/util/DynamicException.kt index 0461eafbd..75c7a6116 100644 --- a/src/main/kotlin/com/lambda/util/DynamicException.kt +++ b/src/main/kotlin/com/lambda/util/DynamicException.kt @@ -18,7 +18,6 @@ package com.lambda.util import com.lambda.util.DynamicReflectionSerializer.simpleRemappedName -import kotlin.collections.toTypedArray /** * Remaps the stacktrace in production to have readable, class, method and field names diff --git a/src/main/kotlin/com/lambda/util/DynamicReflectionSerializer.kt b/src/main/kotlin/com/lambda/util/DynamicReflectionSerializer.kt index 12bf6d209..2b6b45d45 100644 --- a/src/main/kotlin/com/lambda/util/DynamicReflectionSerializer.kt +++ b/src/main/kotlin/com/lambda/util/DynamicReflectionSerializer.kt @@ -18,11 +18,11 @@ package com.lambda.util import com.lambda.Lambda -import com.lambda.Lambda.LOG +import com.lambda.Lambda.Log import com.lambda.core.Loadable import com.lambda.network.LambdaAPI import com.lambda.util.FileUtils.downloadIfNotPresent -import com.lambda.util.FolderRegister.cache +import com.lambda.util.FolderRegistry.cache import com.lambda.util.extension.resolveFile import com.mojang.serialization.Codec import kotlinx.coroutines.runBlocking @@ -77,20 +77,20 @@ object DynamicReflectionSerializer : Loadable { Codec::class, ) - private const val INDENT = 2 + private const val Indent = 2 private val qualifiedMappings = runBlocking { cache.resolveFile(LambdaAPI.gameVersion) .also { if (it.exists() && !it.readText().contains("net.minecraft.client.MinecraftClient")) { - LOG.debug("Re-downloading yarn mappings as the current cache is improperly generated") + Log.debug("Re-downloading yarn mappings as the current cache is improperly generated") it.delete() } } .downloadIfNotPresent("${LambdaAPI.mappings}/${LambdaAPI.gameVersion}") .map(::buildMappingsMap) .getOrElse { - LOG.error("Unable to download simplified deobfuscated qualifiers", it) + Log.error("Unable to download simplified deobfuscated qualifiers", it) emptyMap() } } @@ -174,7 +174,7 @@ object DynamicReflectionSerializer : Loadable { } val fieldValue = field.javaField?.get(this) - val fieldIndent = "$indent${" ".repeat(INDENT)}" + val fieldIndent = "$indent${" ".repeat(Indent)}" builder.appendLine("$fieldIndent${field.dynamicName(remap)}: ${fieldValue.formatFieldValue(remap)}") if (currentDepth < maxRecursionDepth @@ -187,7 +187,7 @@ object DynamicReflectionSerializer : Loadable { fieldValue.dynamicString( maxRecursionDepth, currentDepth + 1, - "$fieldIndent${" ".repeat(INDENT)}", + "$fieldIndent${" ".repeat(Indent)}", visitedObjects, builder, remap diff --git a/src/main/kotlin/com/lambda/util/EntityUtils.kt b/src/main/kotlin/com/lambda/util/EntityUtils.kt index a1b98369e..3a3fea047 100644 --- a/src/main/kotlin/com/lambda/util/EntityUtils.kt +++ b/src/main/kotlin/com/lambda/util/EntityUtils.kt @@ -18,16 +18,16 @@ package com.lambda.util import com.lambda.util.DynamicReflectionSerializer.remappedName +import com.lambda.util.ReflectionUtils.scanResult import com.lambda.util.math.MathUtils.floorToInt -import com.lambda.util.reflections.scanResult import io.github.classgraph.ClassInfo 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.math.Vec3d -import kotlin.jvm.java +@Suppress("unused") object EntityUtils { val entities: Collection = scanResult .getSubclasses(Entity::class.java) diff --git a/src/main/kotlin/com/lambda/util/FolderRegister.kt b/src/main/kotlin/com/lambda/util/FolderRegistry.kt similarity index 93% rename from src/main/kotlin/com/lambda/util/FolderRegister.kt rename to src/main/kotlin/com/lambda/util/FolderRegistry.kt index dd2f68e97..d02d89b6f 100644 --- a/src/main/kotlin/com/lambda/util/FolderRegister.kt +++ b/src/main/kotlin/com/lambda/util/FolderRegistry.kt @@ -25,9 +25,9 @@ import kotlin.io.path.createDirectories import kotlin.io.path.notExists /** - * The [FolderRegister] object is responsible for managing the directory structure of the application. + * Object responsible for managing the directory structure of the application. */ -object FolderRegister : Loadable { +object FolderRegistry : Loadable { val minecraft: Path = mc.runDirectory.toPath() val lambda: Path = minecraft.resolve("lambda") val config: Path = lambda.resolve("config") diff --git a/src/main/kotlin/com/lambda/util/Formatting.kt b/src/main/kotlin/com/lambda/util/FormattingUtils.kt similarity index 97% rename from src/main/kotlin/com/lambda/util/Formatting.kt rename to src/main/kotlin/com/lambda/util/FormattingUtils.kt index 4b0b56055..f88c9af5b 100644 --- a/src/main/kotlin/com/lambda/util/Formatting.kt +++ b/src/main/kotlin/com/lambda/util/FormattingUtils.kt @@ -17,8 +17,7 @@ package com.lambda.util -import com.lambda.config.Setting -import com.lambda.config.groups.FormatterConfig +import com.lambda.config.settings.blocks.FormatterConfig import com.lambda.util.math.Vec2d import net.minecraft.util.math.Vec2f import net.minecraft.util.math.Vec3d @@ -30,7 +29,7 @@ import java.time.ZonedDateTime import java.time.format.DateTimeFormatter import java.util.* -object Formatting { +object FormattingUtils { fun Short.format(formatter: FormatterConfig) = format(formatter.locale) fun Short.format(locale: Locale = Default.locale) = "%d".format(locale, this) @@ -124,8 +123,6 @@ object Formatting { } object Default : FormatterConfig { - override val settings = mutableListOf>() - override val visibility: () -> Boolean = { true } override val locale: Locale = Locale.US override val separator: String = "," override val prefix: String = "(" diff --git a/src/main/kotlin/com/lambda/util/InputUtils.kt b/src/main/kotlin/com/lambda/util/InputUtils.kt index 92576a77a..a35d8517e 100644 --- a/src/main/kotlin/com/lambda/util/InputUtils.kt +++ b/src/main/kotlin/com/lambda/util/InputUtils.kt @@ -20,7 +20,6 @@ package com.lambda.util import com.lambda.Lambda.mc import com.lambda.config.settings.complex.Bind import com.lambda.context.SafeContext -import com.lambda.core.Loadable import com.lambda.event.events.ButtonEvent import it.unimi.dsi.fastutil.ints.Int2IntArrayMap import org.lwjgl.glfw.GLFW @@ -38,7 +37,7 @@ import org.lwjgl.glfw.GLFW.GLFW_PRESS import org.lwjgl.glfw.GLFW.glfwGetKey import org.lwjgl.glfw.GLFW.glfwGetMouseButton -object InputUtils : Loadable { +object InputUtils { private val lastPressedKeys = Int2IntArrayMap() // Keep track of the previously pressed keys to report GLFW_RELEASE states /** diff --git a/src/main/kotlin/com/lambda/util/KeyCode.kt b/src/main/kotlin/com/lambda/util/KeyCode.kt index 09bda2f42..863b8c3a5 100644 --- a/src/main/kotlin/com/lambda/util/KeyCode.kt +++ b/src/main/kotlin/com/lambda/util/KeyCode.kt @@ -144,7 +144,7 @@ enum class KeyCode(val code: Int) { Last(GLFW.GLFW_KEY_LAST); companion object { - private const val PRINTABLE_POOL = "`-=[]\\,;\'./" + private const val PrintablePool = "`-=[]\\,;\'./" private val glfwPool = intArrayOf( GLFW.GLFW_KEY_GRAVE_ACCENT, GLFW.GLFW_KEY_MINUS, GLFW.GLFW_KEY_EQUAL, GLFW.GLFW_KEY_LEFT_BRACKET, GLFW.GLFW_KEY_RIGHT_BRACKET, GLFW.GLFW_KEY_BACKSLASH, @@ -180,7 +180,7 @@ enum class KeyCode(val code: Int) { in 'A'..'Z' -> GLFW.GLFW_KEY_A + (char - 'A') in 'a'..'z' -> GLFW.GLFW_KEY_A + (char - 'a') else -> { - val i = PRINTABLE_POOL.indexOf(keyName) + val i = PrintablePool.indexOf(keyName) if (i >= 0) glfwPool[i] else keyCode } }) diff --git a/src/main/kotlin/com/lambda/util/LambdaResource.kt b/src/main/kotlin/com/lambda/util/LambdaResource.kt index 4920339c9..6bfd43650 100644 --- a/src/main/kotlin/com/lambda/util/LambdaResource.kt +++ b/src/main/kotlin/com/lambda/util/LambdaResource.kt @@ -15,6 +15,8 @@ * along with this program. If not, see . */ +@file:Suppress("unused") + package com.lambda.util import com.lambda.Lambda @@ -22,7 +24,6 @@ import java.awt.image.BufferedImage import java.io.FileNotFoundException import java.io.InputStream import java.net.URL -import java.nio.file.Paths import javax.imageio.ImageIO typealias LambdaResource = String diff --git a/src/main/kotlin/com/lambda/interaction/managers/rotating/visibilty/PlaceDirection.kt b/src/main/kotlin/com/lambda/util/PlaceDirection.kt similarity index 92% rename from src/main/kotlin/com/lambda/interaction/managers/rotating/visibilty/PlaceDirection.kt rename to src/main/kotlin/com/lambda/util/PlaceDirection.kt index fb7c9b17f..b6e3b0484 100644 --- a/src/main/kotlin/com/lambda/interaction/managers/rotating/visibilty/PlaceDirection.kt +++ b/src/main/kotlin/com/lambda/util/PlaceDirection.kt @@ -15,15 +15,13 @@ * along with this program. If not, see . */ -package com.lambda.interaction.managers.rotating.visibilty +package com.lambda.util import com.lambda.interaction.managers.rotating.Rotation -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 +@Suppress("unused") enum class PlaceDirection( val rotation: Rotation, val vector: Vec3i, @@ -54,9 +52,9 @@ enum class PlaceDirection( companion object { /** * A modified version of the minecraft getEntityFacingOrder method. This version takes a - * [Rotation] instead of an [Entity] + * [Rotation] instead of an [net.minecraft.entity.Entity] * - * @see Direction.getEntityFacingOrder + * @see net.minecraft.util.math.Direction.getEntityFacingOrder */ fun fromRotation(rotation: Rotation): PlaceDirection { val pitchRad = rotation.pitchF * (Math.PI.toFloat() / 180f).toDouble() @@ -98,4 +96,4 @@ enum class PlaceDirection( } } } -} +} \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/util/PlayerBuildLayerUtils.kt b/src/main/kotlin/com/lambda/util/PlayerBuildLayerUtils.kt index e733a3c37..1d7d0fe5f 100644 --- a/src/main/kotlin/com/lambda/util/PlayerBuildLayerUtils.kt +++ b/src/main/kotlin/com/lambda/util/PlayerBuildLayerUtils.kt @@ -18,7 +18,7 @@ package com.lambda.util import com.lambda.context.SafeContext -import com.lambda.interaction.BaritoneManager +import com.lambda.interaction.BaritoneHandler import com.lambda.util.BlockUtils.blockState import com.lambda.util.BlockUtils.isNotEmpty import com.lambda.util.math.MathUtils.ceilToInt @@ -67,7 +67,7 @@ object PlayerBuildLayerUtils { } fun isInBaritoneSelection(pos: BlockPos) = - BaritoneManager.primary?.selectionManager?.selections?.any { + BaritoneHandler.primary?.selectionManager?.selections?.any { val min = it.min() val max = it.max() pos.x >= min.x && pos.x <= max.x diff --git a/src/main/kotlin/com/lambda/util/ReflectionUtils.kt b/src/main/kotlin/com/lambda/util/ReflectionUtils.kt new file mode 100644 index 000000000..0d38c6f09 --- /dev/null +++ b/src/main/kotlin/com/lambda/util/ReflectionUtils.kt @@ -0,0 +1,100 @@ +/* + * Copyright 2026 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.util + +import com.lambda.util.extension.isObject +import com.lambda.util.extension.objectInstance +import io.github.classgraph.ClassGraph +import io.github.classgraph.ClassInfo +import io.github.classgraph.ClassInfoList +import io.github.classgraph.Resource +import io.github.classgraph.ResourceList +import io.github.classgraph.ScanResult +import java.lang.reflect.Modifier +import kotlin.reflect.KClass + +@Suppress("unused") +object ReflectionUtils { + val scanResult: ScanResult by lazy { ClassGraph().enableAllInfo().scan() } + + val Any.className: String get() = this::class.java.name + .substringAfter("${this::class.java.packageName}.") + .replace('$', '.') + + val KClass<*>.className: String get() = java.name + .substringAfter("${java.packageName}.") + .replace('$', '.') + + /** + * This function returns an instance of subtype [T]. + * + * When [T] is an interface, the function with returns a list of classes that implements [T]. + * When [T] is an abstract class (open classes too), the function will return a list of classes extending [T]. + * + * Only final classes with empty constructors will be created. + */ + inline fun getInstances(crossinline block: (ClassInfo) -> Boolean = { true }): List { + if (scanResult.isClosed) return emptyList() + + val clazz = T::class.java + + return when { + clazz.isInterface -> scanResult.getClassesImplementing(clazz) + Modifier.isAbstract(clazz.modifiers) -> scanResult.getSubclasses(clazz) + else -> throw IllegalStateException("class ${clazz.name} is neither an interface or open class") + }.filter { block(it) } + .mapNotNull { createInstance(Class.forName(it.name)) } + } + + @JvmName("getInstancesImplementingWithParameters1") + inline fun getInstancesImplementingWithParameters() = + getInstancesImplementingWithParameters(A1::class) + + @JvmName("getInstancesImplementingWithParameters2") + inline fun getInstancesImplementingWithParameters() = + getInstancesImplementingWithParameters(A1::class, A2::class) + + @JvmName("getInstancesImplementingWithParameters3") + inline fun getInstancesImplementingWithParameters() = + getInstancesImplementingWithParameters(A1::class, A2::class, A3::class) + + inline fun getInstancesImplementingWithParameters(vararg arguments: KClass<*>): ClassInfoList = + scanResult.getClassesImplementing(T::class.java) + .filter { + it.typeSignature.superinterfaceSignatures + .any { int -> int.typeArguments + .any { arg -> arguments.any { it.qualifiedName == arg.typeSignature.toString() }} } + } + + inline fun getResources(pattern: String, crossinline block: (Resource) -> Boolean): ResourceList = + scanResult.getResourcesMatchingWildcard(pattern) + .filter { block(it) } + + inline fun createInstance(clazz: Class<*>) = + when { + clazz.isInterface || clazz.isEnum || clazz.isAnnotation || clazz.isObject -> + // Handle objects (singletons) or invalid types + clazz.objectInstance as? T + else -> { + // Look for a constructor with no parameters + clazz.constructors + .filterNot { Modifier.isAbstract(it.declaringClass.modifiers) } // Avoid abstract constructors + .firstOrNull { it.parameterCount == 0 }?.newInstance() as? T + } + } +} diff --git a/src/main/kotlin/com/lambda/util/ServerTPS.kt b/src/main/kotlin/com/lambda/util/ServerTPSUtils.kt similarity index 98% rename from src/main/kotlin/com/lambda/util/ServerTPS.kt rename to src/main/kotlin/com/lambda/util/ServerTPSUtils.kt index 855cbbf7c..86e95246f 100644 --- a/src/main/kotlin/com/lambda/util/ServerTPS.kt +++ b/src/main/kotlin/com/lambda/util/ServerTPSUtils.kt @@ -23,7 +23,7 @@ import com.lambda.event.listener.SafeListener.Companion.listen import com.lambda.util.collections.LimitedDecayQueue import net.minecraft.network.packet.s2c.play.WorldTimeUpdateS2CPacket -object ServerTPS { +object ServerTPSUtils { // Server sends exactly one world time update every 20 server ticks (one per second). private val updateHistory = LimitedDecayQueue(61, 60000) private var lastUpdate = 0L diff --git a/src/main/kotlin/com/lambda/util/StringUtils.kt b/src/main/kotlin/com/lambda/util/StringUtils.kt index 5120fad8d..e42936e68 100644 --- a/src/main/kotlin/com/lambda/util/StringUtils.kt +++ b/src/main/kotlin/com/lambda/util/StringUtils.kt @@ -18,11 +18,11 @@ package com.lambda.util import com.lambda.Lambda -import com.lambda.Lambda.gson import net.minecraft.util.Identifier import java.security.MessageDigest -import java.util.Base64 +import java.util.* +@Suppress("unused") object StringUtils { fun String.sanitizeForFilename() = replace(Regex("[\\\\/:*?\"<>|]"), "_") @@ -32,7 +32,7 @@ object StringUtils { fun String.capitalize() = replaceFirstChar { it.titlecase() } - fun String.toIdentifier(namespace: String = Lambda.MOD_ID): Identifier = + fun String.toIdentifier(namespace: String = Lambda.ModId): Identifier = Identifier.of(namespace, this) val String.asIdentifier: Identifier get() = toIdentifier() @@ -89,8 +89,6 @@ object StringUtils { return cost[len0 - 1] } - inline fun String.json() = gson.fromJson(this, T::class.java) - fun String.base64UrlDecode() = Base64.getUrlDecoder().decode(toByteArray()).decodeToString() /** diff --git a/src/main/kotlin/com/lambda/util/VarIntIterator.kt b/src/main/kotlin/com/lambda/util/VarIntIterator.kt index ed40f64eb..0fc152aaa 100644 --- a/src/main/kotlin/com/lambda/util/VarIntIterator.kt +++ b/src/main/kotlin/com/lambda/util/VarIntIterator.kt @@ -33,17 +33,17 @@ class VarIntIterator( do { val b = bytes[index++].toInt() - value = value or ((b and SEGMENT_BIT) shl (size++ * 7)) + value = value or ((b and SegmentBit) shl (size++ * 7)) if (size > 5) throw IllegalArgumentException("VarInt size cannot exceed 5 bytes") - } while ((b and CONTINUE_BIT) != 0) + } while ((b and ContinueBit) != 0) return value } companion object { - const val SEGMENT_BIT = 127 - const val CONTINUE_BIT = 128 + const val SegmentBit = 127 + const val ContinueBit = 128 } } diff --git a/src/main/kotlin/com/lambda/util/WindowUtils.kt b/src/main/kotlin/com/lambda/util/WindowUtils.kt index c8e269a88..5be733b24 100644 --- a/src/main/kotlin/com/lambda/util/WindowUtils.kt +++ b/src/main/kotlin/com/lambda/util/WindowUtils.kt @@ -17,9 +17,9 @@ package com.lambda.util -import com.lambda.Lambda.MOD_NAME -import com.lambda.Lambda.SYMBOL -import com.lambda.Lambda.VERSION +import com.lambda.Lambda.ModName +import com.lambda.Lambda.Symbol +import com.lambda.Lambda.Version import com.lambda.Lambda.mc import com.lambda.gui.components.ClickGuiLayout.lambdaTitleAppendixName import net.minecraft.client.util.MacWindowUtil @@ -37,7 +37,7 @@ object WindowUtils { @JvmStatic fun setLambdaTitle() { val name = if (lambdaTitleAppendixName) " - ${mc.session.username}" else "" - mc.window.setTitle("$SYMBOL $MOD_NAME $VERSION - ${mc.windowTitle}$name") + mc.window.setTitle("$Symbol $ModName $Version - ${mc.windowTitle}$name") } fun setLambdaWindowIcon() { diff --git a/src/main/kotlin/com/lambda/util/extension/World.kt b/src/main/kotlin/com/lambda/util/extension/World.kt index eeead30f2..781b5c0b1 100644 --- a/src/main/kotlin/com/lambda/util/extension/World.kt +++ b/src/main/kotlin/com/lambda/util/extension/World.kt @@ -15,11 +15,12 @@ * along with this program. If not, see . */ +@file:Suppress("unused") + package com.lambda.util.extension import com.lambda.Lambda.mc import com.lambda.context.SafeContext -import com.lambda.util.extension.paintingColorCache import com.lambda.util.world.FastVector import com.lambda.util.world.toBlockPos import com.lambda.util.world.x diff --git a/src/main/kotlin/com/lambda/util/math/MathUtils.kt b/src/main/kotlin/com/lambda/util/math/MathUtils.kt index 2a3afd405..e043c8c7c 100644 --- a/src/main/kotlin/com/lambda/util/math/MathUtils.kt +++ b/src/main/kotlin/com/lambda/util/math/MathUtils.kt @@ -28,16 +28,16 @@ import kotlin.math.min import kotlin.random.Random.Default.nextDouble object MathUtils { - private const val PI_FLOAT = 3.141593f + private const val PiFloat = 3.141593f inline val Int.sq: Int get() = this * this inline val Float.sq: Float get() = this * this inline val Double.sq: Double get() = this * this - fun Float.toRadian() = this / 180.0f * PI_FLOAT + fun Float.toRadian() = this / 180.0f * PiFloat fun Double.toRadian() = this / 180.0 * PI - fun Float.toDegree() = this * 180.0f / PI_FLOAT + fun Float.toDegree() = this * 180.0f / PiFloat fun Double.toDegree() = this * 180.0 / PI fun Boolean.toInt() = if (this) 1 else 0 diff --git a/src/main/kotlin/com/lambda/util/player/PlayerUtils.kt b/src/main/kotlin/com/lambda/util/player/PlayerUtils.kt index 69c1fb781..10f15edc5 100644 --- a/src/main/kotlin/com/lambda/util/player/PlayerUtils.kt +++ b/src/main/kotlin/com/lambda/util/player/PlayerUtils.kt @@ -17,7 +17,7 @@ package com.lambda.util.player -import com.lambda.config.groups.BuildConfig +import com.lambda.config.settings.blocks.BuildConfig import com.lambda.context.SafeContext import com.lambda.util.world.fastEntitySearch import net.minecraft.client.network.ClientPlayerEntity diff --git a/src/main/kotlin/com/lambda/interaction/managers/rotating/visibilty/VisibilityChecker.kt b/src/main/kotlin/com/lambda/util/player/RotationUtils.kt similarity index 90% rename from src/main/kotlin/com/lambda/interaction/managers/rotating/visibilty/VisibilityChecker.kt rename to src/main/kotlin/com/lambda/util/player/RotationUtils.kt index 9e25611b9..29888425a 100644 --- a/src/main/kotlin/com/lambda/interaction/managers/rotating/visibilty/VisibilityChecker.kt +++ b/src/main/kotlin/com/lambda/util/player/RotationUtils.kt @@ -15,10 +15,11 @@ * along with this program. If not, see . */ -package com.lambda.interaction.managers.rotating.visibilty +package com.lambda.util.player import com.lambda.context.Automated import com.lambda.context.AutomatedSafeContext +import com.lambda.context.SafeContext import com.lambda.interaction.construction.simulation.processing.PreProcessingData import com.lambda.interaction.construction.verify.ScanMode import com.lambda.interaction.construction.verify.SurfaceScan @@ -27,7 +28,9 @@ import com.lambda.interaction.managers.rotating.Rotation.Companion.rotationTo import com.lambda.interaction.managers.rotating.RotationManager import com.lambda.module.modules.client.Client import com.lambda.util.BlockUtils.blockState +import com.lambda.util.PlaceDirection import com.lambda.util.extension.component6 +import com.lambda.util.extension.rotation import com.lambda.util.math.distSq import com.lambda.util.world.raycast.RayCastUtils.blockResult import com.lambda.util.world.raycast.RayCastUtils.entityResult @@ -40,6 +43,8 @@ import net.minecraft.util.math.Box import net.minecraft.util.math.Direction import net.minecraft.util.math.Vec3d import java.util.* +import kotlin.math.atan2 +import kotlin.math.hypot import kotlin.math.max import kotlin.math.min import kotlin.math.pow @@ -47,9 +52,33 @@ import kotlin.math.pow /** * Object for handling visibility checks, rotation calculations, and hit detection. */ -object VisibilityChecker { +object RotationUtils { val ALL_SIDES = Direction.entries.toSet() + fun SafeContext.lookAt(pos: Vec3d): Rotation { + val direction = pos.subtract(player.eyePos).normalize() + val yaw = Math.toDegrees(atan2(direction.z, direction.x)) - 90.0 + val pitch = -Math.toDegrees(atan2(direction.y, hypot(direction.x, direction.z))) + return Rotation(yaw, pitch) + } + + fun SafeContext.lookInDirection(direction: PlaceDirection) = + if (!direction.isInArea(player.rotation)) direction.snapToArea(RotationManager.activeRotation) + else player.rotation + + fun AutomatedSafeContext.lookAtHit(hit: HitResult) = + when (hit) { + is BlockHitResult -> lookAtBlock(hit.blockPos, setOf(hit.side)) + is EntityHitResult -> lookAtEntity(hit.entity) + else -> null + } + + fun AutomatedSafeContext.lookAtEntity(entity: Entity, sides: Set = ALL_SIDES) = + entity.findRotation(buildConfig.entityReach, player.eyePos, sides) + + fun AutomatedSafeContext.lookAtBlock(pos: BlockPos, sides: Set = ALL_SIDES) = + pos.findRotation(buildConfig.blockReach, player.eyePos, sides) + /** * Finds a rotation that intersects with one of the specified bounding boxes, allowing the player to look at entities or blocks. * To increase the stability, it will pause the rotation if eye position is within any of the bounding boxes @@ -330,9 +359,9 @@ object VisibilityChecker { ) = if (automated.buildConfig.checkSideVisibility || automated.buildConfig.strictRayCast) { intersect(box.getVisibleSurfaces(eye)) } else this - - class CheckedHit( - val hit: HitResult, - val rotation: Rotation - ) } + +class CheckedHit( + val hit: HitResult, + val rotation: Rotation +) \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/util/reflections/Reflections.kt b/src/main/kotlin/com/lambda/util/reflections/Reflections.kt deleted file mode 100644 index 700f68045..000000000 --- a/src/main/kotlin/com/lambda/util/reflections/Reflections.kt +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright 2026 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.util.reflections - -import com.lambda.util.extension.isObject -import com.lambda.util.extension.objectInstance -import io.github.classgraph.ClassGraph -import io.github.classgraph.ClassInfo -import io.github.classgraph.Resource -import io.github.classgraph.ResourceList -import io.github.classgraph.ScanResult -import java.lang.reflect.Modifier -import kotlin.reflect.KClass - -val scanResult: ScanResult by lazy { ClassGraph().enableAllInfo().scan() } - -val Any.className: String get() = this::class.java.name - .substringAfter("${this::class.java.packageName}.") - .replace('$', '.') - -val KClass<*>.className: String get() = java.name - .substringAfter("${java.packageName}.") - .replace('$', '.') - -/** - * This function returns a instance of subtype [T]. - * - * When [T] is an interface, the function with returns a list of classes that implements [T]. - * When [T] is an abstract class (open classes too), the function will return a list of classes extending [T]. - * - * Only final classes with empty constructors will be created. - */ -inline fun getInstances(crossinline block: (ClassInfo) -> Boolean = { true }): List { - if (scanResult.isClosed) return emptyList() - - val clazz = T::class.java - - return when { - clazz.isInterface -> scanResult.getClassesImplementing(clazz) - Modifier.isAbstract(clazz.modifiers) -> scanResult.getSubclasses(clazz) - - else -> throw IllegalStateException("class ${clazz.name} is neither an interface or open class") - }.filter { block(it) } - .mapNotNull { createInstance(Class.forName(it.name)) } -} - -@JvmName("getInstancesImplementingWithParameters1") -inline fun getInstancesImplementingWithParameters() = getInstancesImplementingWithParameters(A1::class) - -@JvmName("getInstancesImplementingWithParameters2") -inline fun getInstancesImplementingWithParameters() = getInstancesImplementingWithParameters(A1::class, A2::class) - -@JvmName("getInstancesImplementingWithParameters3") -inline fun getInstancesImplementingWithParameters() = getInstancesImplementingWithParameters(A1::class, A2::class, A3::class) - -inline fun getInstancesImplementingWithParameters(vararg arguments: KClass<*>) = - scanResult.getClassesImplementing(T::class.java) - .filter { - it.typeSignature.superinterfaceSignatures - .any { int -> int.typeArguments - .any { arg -> arguments.any { it.qualifiedName == arg.typeSignature.toString() }} } - } - -inline fun getResources(pattern: String, crossinline block: (Resource) -> Boolean): ResourceList = - scanResult.getResourcesMatchingWildcard(pattern) - .filter { block(it) } - -inline fun createInstance(clazz: Class<*>): T? { - return when { - clazz.isInterface || clazz.isEnum || clazz.isAnnotation || clazz.isObject -> { - // Handle objects (singletons) or invalid types - clazz.objectInstance as? T - } - else -> { - // Look for a constructor with no parameters - clazz.constructors - .filterNot { Modifier.isAbstract(it.declaringClass.modifiers) } // Avoid abstract constructors - .firstOrNull { it.parameterCount == 0 }?.newInstance() as? T - } - } -} diff --git a/src/main/kotlin/com/lambda/util/text/TextDsl.kt b/src/main/kotlin/com/lambda/util/text/TextDsl.kt index 9fe7ea476..1f209f697 100644 --- a/src/main/kotlin/com/lambda/util/text/TextDsl.kt +++ b/src/main/kotlin/com/lambda/util/text/TextDsl.kt @@ -17,7 +17,7 @@ package com.lambda.util.text -import com.lambda.module.modules.client.StyleEditor +import com.lambda.module.modules.client.Client import net.minecraft.text.ClickEvent import net.minecraft.text.HoverEvent import net.minecraft.text.MutableText @@ -218,7 +218,7 @@ inline fun TextBuilder.color(color: Color?, action: TextBuilder.() -> Unit) { @TextDsl fun TextBuilder.highlighted(value: String) { - color(StyleEditor.highlightColor) { + color(Client.highlightColor) { literal(value) } } diff --git a/src/main/kotlin/com/lambda/util/world/Position.kt b/src/main/kotlin/com/lambda/util/world/Position.kt index e6a3ee284..46e3289fc 100644 --- a/src/main/kotlin/com/lambda/util/world/Position.kt +++ b/src/main/kotlin/com/lambda/util/world/Position.kt @@ -34,48 +34,48 @@ import net.minecraft.util.math.Vec3i */ typealias FastVector = Long -internal const val X_BITS = 26 -internal const val Z_BITS = 26 -internal const val Y_BITS = 12 +internal const val XBits = 26 +internal const val ZBits = 26 +internal const val YBits = 12 -internal const val X_SHIFT = Y_BITS + Z_BITS -internal const val Z_SHIFT = Y_BITS +internal const val XShift = YBits + ZBits +internal const val ZShift = YBits -internal const val X_MASK = (1L shl X_BITS) - 1L -internal const val Z_MASK = (1L shl Z_BITS) - 1L -internal const val Y_MASK = (1L shl Y_BITS) - 1L +internal const val XMask = (1L shl XBits) - 1L +internal const val ZMask = (1L shl ZBits) - 1L +internal const val YMask = (1L shl YBits) - 1L -internal const val MIN_X = -(1L shl X_BITS - 1) -internal const val MIN_Z = -(1L shl Z_BITS - 1) -internal const val MAX_X = (1L shl X_BITS - 1) - 1L -internal const val MAX_Z = (1L shl Z_BITS - 1) - 1L +internal const val MinX = -(1L shl XBits - 1) +internal const val MinZ = -(1L shl ZBits - 1) +internal const val MaxX = (1L shl XBits - 1) - 1L +internal const val MaxZ = (1L shl ZBits - 1) - 1L /** * Serialized representation of (1, 1, 1) */ -const val F_ONE = 274945015809L +const val FOne = 274945015809L fun fastVectorOf(x: Long, y: Long, z: Long): FastVector { - require(x in MIN_X..MAX_X) { "X coordinate out of bounds for $X_BITS bits: $x" } - require(z in MIN_Z..MAX_Z) { "Z coordinate out of bounds for $Z_BITS bits: $z" } + require(x in MinX..MaxX) { "X coordinate out of bounds for $XBits bits: $x" } + require(z in MinZ..MaxZ) { "Z coordinate out of bounds for $ZBits bits: $z" } - return ((x and X_MASK) shl X_SHIFT) or ((z and Z_MASK) shl Z_SHIFT) or (y and Y_MASK) + return ((x and XMask) shl XShift) or ((z and ZMask) shl ZShift) or (y and YMask) } fun fastVectorOf(x: Int, y: Int, z: Int): FastVector = fastVectorOf(x.toLong(), y.toLong(), z.toLong()) val FastVector.x: Int - get() = ((this shr X_SHIFT and X_MASK).toInt() shl (32 - X_BITS)) shr (32 - X_BITS) + get() = ((this shr XShift and XMask).toInt() shl (32 - XBits)) shr (32 - XBits) val FastVector.z: Int - get() = ((this shr Z_SHIFT and Z_MASK).toInt() shl (32 - Z_BITS)) shr (32 - Z_BITS) + get() = ((this shr ZShift and ZMask).toInt() shl (32 - ZBits)) shr (32 - ZBits) val FastVector.y: Int - get() = ((this and Y_MASK).toInt() shl (32 - Y_BITS)) shr (32 - Y_BITS) + get() = ((this and YMask).toInt() shl (32 - YBits)) shr (32 - YBits) -infix fun FastVector.setX(x: Int): FastVector = bitSetTo(x.toLong(), X_SHIFT, X_BITS) -infix fun FastVector.setY(y: Int): FastVector = bitSetTo(y.toLong(), 0, Y_BITS) -infix fun FastVector.setZ(z: Int): FastVector = bitSetTo(z.toLong(), Z_SHIFT, Z_BITS) +infix fun FastVector.setX(x: Int): FastVector = bitSetTo(x.toLong(), XShift, XBits) +infix fun FastVector.setY(y: Int): FastVector = bitSetTo(y.toLong(), 0, YBits) +infix fun FastVector.setZ(z: Int): FastVector = bitSetTo(z.toLong(), ZShift, ZBits) infix fun FastVector.addX(value: Int): FastVector = setX(x + value) infix fun FastVector.addY(value: Int): FastVector = setY(y + value) diff --git a/src/main/kotlin/com/lambda/util/world/WorldUtils.kt b/src/main/kotlin/com/lambda/util/world/WorldUtils.kt index fb9bed16c..9b0f0d6d8 100644 --- a/src/main/kotlin/com/lambda/util/world/WorldUtils.kt +++ b/src/main/kotlin/com/lambda/util/world/WorldUtils.kt @@ -29,9 +29,7 @@ import net.minecraft.fluid.Fluid import net.minecraft.fluid.FluidState import net.minecraft.util.math.BlockPos import net.minecraft.util.math.ChunkSectionPos -import kotlin.collections.asSequence import kotlin.math.ceil -import kotlin.sequences.filter object WorldUtils { fun SafeContext.isLoaded(pos: BlockPos) = @@ -137,8 +135,8 @@ object WorldUtils { */ inline fun SafeContext.internalSearchBlocks( pos: FastVector, - range: FastVector = F_ONE times 7, - step: FastVector = F_ONE, + range: FastVector = FOne times 7, + step: FastVector = FOne, crossinline filter: (FastVector, BlockState) -> Boolean = { _, _ -> true }, ) = fastSequence(pos, range, step) .filter { @@ -154,8 +152,8 @@ object WorldUtils { */ inline fun SafeContext.internalSearchFluids( pos: FastVector, - range: FastVector = F_ONE times 7, - step: FastVector = F_ONE, + range: FastVector = FOne times 7, + step: FastVector = FOne, crossinline filter: (FastVector, FluidState) -> Boolean = { _, _ -> true }, ) = fastSequence(pos, range, step) .filter { diff --git a/src/main/kotlin/com/lambda/util/world/raycast/RayCastUtils.kt b/src/main/kotlin/com/lambda/util/world/raycast/RayCastUtils.kt index 599186cb9..e126f5689 100644 --- a/src/main/kotlin/com/lambda/util/world/raycast/RayCastUtils.kt +++ b/src/main/kotlin/com/lambda/util/world/raycast/RayCastUtils.kt @@ -72,7 +72,7 @@ object RayCastUtils { // ToDo: Should rather move player hitbox down and check collision fun SafeContext.distanceToGround(maxDist: Double = 100.0): Double { val pos = player.pos.add(0.0, 0.1, 0.0) - val cast = Rotation.DOWN.rayCast(maxDist, pos, false, InteractionMask.Block) ?: return maxDist + val cast = Rotation.Down.rayCast(maxDist, pos, false, InteractionMask.Block) ?: return maxDist return max(0.0, pos.y - cast.pos.y) } diff --git a/src/main/resources/lambda.mixins.json b/src/main/resources/lambda.mixins.json index 33829e0d4..35bd9479b 100644 --- a/src/main/resources/lambda.mixins.json +++ b/src/main/resources/lambda.mixins.json @@ -29,6 +29,7 @@ "network.HandshakeC2SPacketMixin", "network.LoginHelloC2SPacketMixin", "network.LoginKeyC2SPacketMixin", + "render.AbstractBlockRenderContextMixin", "render.AbstractTerrainRenderContextMixin", "render.ArmorFeatureRendererMixin", "render.BlockEntityRendererMixin", @@ -63,7 +64,6 @@ "render.RenderLayersMixin", "render.ScreenHandlerMixin", "render.ScreenMixin", - "render.AbstractBlockRenderContextMixin", "render.SodiumBlockRendererMixin", "render.SodiumFluidRendererImplMixin", "render.SodiumLightDataAccessMixin", diff --git a/src/test/kotlin/FastVectorTest.kt b/src/test/kotlin/FastVectorTest.kt index ca09e4363..d1888409d 100644 --- a/src/test/kotlin/FastVectorTest.kt +++ b/src/test/kotlin/FastVectorTest.kt @@ -15,8 +15,8 @@ * along with this program. If not, see . */ -import com.lambda.util.world.X_BITS -import com.lambda.util.world.Z_BITS +import com.lambda.util.world.XBits +import com.lambda.util.world.ZBits import com.lambda.util.world.addX import com.lambda.util.world.addY import com.lambda.util.world.addZ @@ -71,7 +71,7 @@ class FastVectorTest { @Test fun `test fast vector with invalid X coordinate`() { - val x = (1L shl X_BITS - 1) + val x = (1L shl XBits - 1) val y = 10L val z = 20L @@ -82,7 +82,7 @@ class FastVectorTest { fun `test fast vector with invalid Z coordinate`() { val x = 10L val y = 20L - val z = (1L shl Z_BITS - 1) + val z = (1L shl ZBits - 1) assertFails { fastVectorOf(x, y, z) } } diff --git a/src/test/kotlin/PlaceDirectionTest.kt b/src/test/kotlin/PlaceDirectionTest.kt index 713fd5d75..02b5fb6e3 100644 --- a/src/test/kotlin/PlaceDirectionTest.kt +++ b/src/test/kotlin/PlaceDirectionTest.kt @@ -16,7 +16,7 @@ */ import com.lambda.interaction.managers.rotating.Rotation -import com.lambda.interaction.managers.rotating.visibilty.PlaceDirection +import com.lambda.util.PlaceDirection import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertFalse diff --git a/src/test/kotlin/RotationTest.kt b/src/test/kotlin/RotationTest.kt index f57a3c33e..6fa33a311 100644 --- a/src/test/kotlin/RotationTest.kt +++ b/src/test/kotlin/RotationTest.kt @@ -130,14 +130,14 @@ class RotationTest { @Test fun `test companion object constants`() { - assertEquals(0.0, Rotation.ZERO.yaw) - assertEquals(0.0, Rotation.ZERO.pitch) + assertEquals(0.0, Rotation.Zero.yaw) + assertEquals(0.0, Rotation.Zero.pitch) - assertEquals(0.0, Rotation.DOWN.yaw) - assertEquals(90.0, Rotation.DOWN.pitch) + assertEquals(0.0, Rotation.Down.yaw) + assertEquals(90.0, Rotation.Down.pitch) - assertEquals(0.0, Rotation.UP.yaw) - assertEquals(-90.0, Rotation.UP.pitch) + assertEquals(0.0, Rotation.Up.yaw) + assertEquals(-90.0, Rotation.Up.pitch) } @Test