From 67a1e07b82bd708d0b6db4d4c1cbbf12596f9b02 Mon Sep 17 00:00:00 2001 From: George Date: Sun, 7 Jun 2026 20:02:38 +0100 Subject: [PATCH] Add /lw hud debug command to toggle region HUD without compass /lw hud toggles a persistent per-player flag stored in LivingWorldBootstrap. When enabled, the action-bar HUD (Eco/Poll/Soil/Wat) is shown every 20 ticks alongside the existing compass-based trigger. Flag is cleared on server stop. Requires operator permission level 2. Co-Authored-By: Claude Sonnet 4.6 --- .../java/com/livingworld/LivingWorldMod.java | 7 +++-- .../bootstrap/LivingWorldBootstrap.java | 19 +++++++++++- .../commands/LivingWorldCommandRoot.java | 31 ++++++++++++++++--- 3 files changed, 50 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/livingworld/LivingWorldMod.java b/src/main/java/com/livingworld/LivingWorldMod.java index a199b04..74493c9 100644 --- a/src/main/java/com/livingworld/LivingWorldMod.java +++ b/src/main/java/com/livingworld/LivingWorldMod.java @@ -235,8 +235,11 @@ public class LivingWorldMod { } } - // Step 2: Compass HUD — display region health while holding a compass. - if (player.getMainHandItem().is(Items.COMPASS) || player.getOffhandItem().is(Items.COMPASS)) { + // Step 2: Compass HUD — display region health while holding a compass, or debug HUD is on. + boolean showHud = player.getMainHandItem().is(Items.COMPASS) + || player.getOffhandItem().is(Items.COMPASS) + || bootstrap.isHudEnabled(player.getUUID()); + if (showHud) { Optional metricsOpt = bootstrap.getMetricsAt(dimId, player.getX(), player.getZ()); metricsOpt.ifPresent(m -> player.displayClientMessage(buildHud(coord, m), true)); } diff --git a/src/main/java/com/livingworld/bootstrap/LivingWorldBootstrap.java b/src/main/java/com/livingworld/bootstrap/LivingWorldBootstrap.java index b6b36ba..e53a601 100644 --- a/src/main/java/com/livingworld/bootstrap/LivingWorldBootstrap.java +++ b/src/main/java/com/livingworld/bootstrap/LivingWorldBootstrap.java @@ -48,10 +48,13 @@ import com.mojang.brigadier.CommandDispatcher; import java.nio.file.Path; import java.util.Collection; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Random; +import java.util.Set; +import java.util.UUID; import com.livingworld.regions.RegionMetrics; import net.minecraft.commands.CommandSourceStack; @@ -70,6 +73,7 @@ public final class LivingWorldBootstrap { private double windAngle = 0.0; private final Random windRandom = new Random(); + private final Set hudEnabledPlayers = new HashSet<>(); private PlatformAdapter platformAdapter; private Path worldSaveDirectory; @@ -199,6 +203,7 @@ public final class LivingWorldBootstrap { } regionManager.flushAll(); moduleRegistry.shutdownAll(); + hudEnabledPlayers.clear(); serverReady = false; LivingWorldLogger.info( DiagnosticCategory.BOOTSTRAP, @@ -413,13 +418,25 @@ public final class LivingWorldBootstrap { } } + /** Toggles the debug HUD for the given player. Returns true if HUD is now enabled. */ + public boolean toggleHud(UUID playerId) { + if (hudEnabledPlayers.remove(playerId)) return false; + hudEnabledPlayers.add(playerId); + return true; + } + + public boolean isHudEnabled(UUID playerId) { + return hudEnabledPlayers.contains(playerId); + } + public void registerCommands(CommandDispatcher dispatcher) { requireInitialized(); LivingWorldCommandRoot.registerDeferred( dispatcher, () -> requireService(regionManager, "regionManager"), () -> requireService(moduleRegistry, "moduleRegistry"), - () -> requireService(simulationManager, "simulationManager")); + () -> requireService(simulationManager, "simulationManager"), + this::toggleHud); } public Path getWorldSaveDirectory() { diff --git a/src/main/java/com/livingworld/commands/LivingWorldCommandRoot.java b/src/main/java/com/livingworld/commands/LivingWorldCommandRoot.java index 87c78b1..4d3a905 100644 --- a/src/main/java/com/livingworld/commands/LivingWorldCommandRoot.java +++ b/src/main/java/com/livingworld/commands/LivingWorldCommandRoot.java @@ -1,14 +1,18 @@ package com.livingworld.commands; -import java.util.stream.Collectors; +import java.util.UUID; +import java.util.function.Function; import java.util.function.Supplier; +import java.util.stream.Collectors; import com.mojang.brigadier.CommandDispatcher; import com.mojang.brigadier.arguments.IntegerArgumentType; +import com.mojang.brigadier.exceptions.CommandSyntaxException; import net.minecraft.commands.CommandSourceStack; import net.minecraft.commands.Commands; import net.minecraft.network.chat.Component; +import net.minecraft.server.level.ServerPlayer; import com.livingworld.core.simulation.SimulationManager; import com.livingworld.modules.ModuleRegistry; @@ -33,14 +37,16 @@ public final class LivingWorldCommandRoot { dispatcher, () -> regionManager, () -> moduleRegistry, - () -> simulationManager); + () -> simulationManager, + uuid -> false); } public static void registerDeferred( CommandDispatcher dispatcher, Supplier regionManager, Supplier moduleRegistry, - Supplier simulationManager) { + Supplier simulationManager, + Function hudToggle) { if (dispatcher == null) { throw new IllegalArgumentException("dispatcher must not be null"); } @@ -96,7 +102,24 @@ public final class LivingWorldCommandRoot { .executes(context -> SimulateCommand.execute( context.getSource(), requireService(simulationManager, "simulationManager"), - IntegerArgumentType.getInteger(context, "ticks")))))); + IntegerArgumentType.getInteger(context, "ticks"))))) + .then(Commands.literal("hud") + .executes(context -> toggleHud(context.getSource(), hudToggle)))); + } + + private static int toggleHud(CommandSourceStack source, Function hudToggle) { + ServerPlayer player; + try { + player = source.getPlayerOrException(); + } catch (CommandSyntaxException e) { + source.sendFailure(Component.literal("/lw hud can only be used by a player")); + return 0; + } + boolean nowEnabled = hudToggle.apply(player.getUUID()); + source.sendSuccess( + () -> Component.literal("Region HUD " + (nowEnabled ? "enabled" : "disabled")), + false); + return 1; } private static T requireService(Supplier supplier, String name) {