From b07bc080f917b32fd175ed61ca56734ef6371207 Mon Sep 17 00:00:00 2001 From: starpanda24825 Date: Sun, 10 May 2026 13:09:53 +0100 Subject: [PATCH 1/3] autoclaim compat + issue fix + displaying territory's name upon entering --- .../capitol/client/events/ChunkEvents.java | 81 +++++++++++++++++++ .../client/journeymap/ClientJMClaims.java | 19 ++++- .../networking/ClientPayloadHandler.java | 3 + .../journeymap/CapitolJourneyMapPlugin.java | 25 +++++- .../networking/ServerPayloadHandler.java | 6 +- 5 files changed, 129 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/createcivilization/capitol/client/events/ChunkEvents.java b/src/main/java/com/createcivilization/capitol/client/events/ChunkEvents.java index c33ebbc..71711e3 100644 --- a/src/main/java/com/createcivilization/capitol/client/events/ChunkEvents.java +++ b/src/main/java/com/createcivilization/capitol/client/events/ChunkEvents.java @@ -2,17 +2,30 @@ import com.createcivilization.capitol.Capitol; import com.createcivilization.capitol.client.networking.ClientClaimCache; +import com.createcivilization.capitol.common.data.Team; import com.createcivilization.capitol.common.networking.packets.C2SChunkRequest; +import net.minecraft.ChatFormatting; +import net.minecraft.client.Minecraft; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.TextColor; import net.minecraft.world.level.ChunkPos; import net.neoforged.api.distmarker.Dist; import net.neoforged.bus.api.SubscribeEvent; import net.neoforged.fml.common.EventBusSubscriber; import net.neoforged.neoforge.client.event.ClientPlayerNetworkEvent; +import net.neoforged.neoforge.client.event.ClientTickEvent; import net.neoforged.neoforge.event.level.ChunkEvent; import net.neoforged.neoforge.network.PacketDistributor; +import java.util.Objects; +import java.util.UUID; + @EventBusSubscriber(modid = Capitol.MOD_ID, value = Dist.CLIENT) public class ChunkEvents { + private static ChunkPos lastPlayerChunk; + private static ChunkPos pendingChunkAnnouncement; + private static boolean hasLastTerritory; + private static UUID lastTerritoryTeamId; /** * Handles sending packets to server when loading chunks to fetch claims and adding to cache @@ -26,6 +39,70 @@ private static void onChunkLoad(ChunkEvent.Load event) { PacketDistributor.sendToServer(packet); } + @SubscribeEvent + private static void onClientTick(ClientTickEvent.Post event) { + var mc = Minecraft.getInstance(); + var player = mc.player; + if (player == null) return; + + ChunkPos current = player.chunkPosition(); + if (current.equals(lastPlayerChunk)) return; + lastPlayerChunk = current; + + Team team = ClientClaimCache.getClaim(current); + if (team != null) { + onTerritoryResolved(team); + pendingChunkAnnouncement = null; + return; + } + + pendingChunkAnnouncement = current; + PacketDistributor.sendToServer(new C2SChunkRequest(current.toLong())); + } + + public static void onClaimInfoUpdated(ChunkPos chunkPos) { + var mc = Minecraft.getInstance(); + var player = mc.player; + if (player == null) return; + if (pendingChunkAnnouncement == null || !pendingChunkAnnouncement.equals(chunkPos)) return; + if (!chunkPos.equals(player.chunkPosition())) return; + + Team team = ClientClaimCache.getClaim(chunkPos); + onTerritoryResolved(team); + pendingChunkAnnouncement = null; + } + + private static void onTerritoryResolved(Team team) { + UUID teamId = (team == null) ? null : team.getId(); + boolean changed = !hasLastTerritory || !Objects.equals(lastTerritoryTeamId, teamId); + lastTerritoryTeamId = teamId; + hasLastTerritory = true; + + if (!changed) return; + + if (team == null) { + showWilderness(); + } else { + showTerritory(team); + } + } + + private static void showTerritory(Team team) { + var player = Minecraft.getInstance().player; + if (player == null) return; + int rgb = team.getColor().getRGB() & 0xFFFFFF; + player.displayClientMessage( + Component.literal(team.getName()).withStyle(style -> style.withColor(TextColor.fromRgb(rgb))), + true + ); + } + + private static void showWilderness() { + var player = Minecraft.getInstance().player; + if (player == null) return; + player.displayClientMessage(Component.literal("Wilderness").withStyle(ChatFormatting.DARK_GREEN), true); + } + /** * Removes chunks from client claim cache when they are unloaded */ @@ -42,6 +119,10 @@ private static void onChunkUnload(ChunkEvent.Unload event) { @SubscribeEvent private static void onClientDisconnect(ClientPlayerNetworkEvent.LoggingOut event) { ClientClaimCache.clearClaims(); + lastPlayerChunk = null; + pendingChunkAnnouncement = null; + hasLastTerritory = false; + lastTerritoryTeamId = null; } } diff --git a/src/main/java/com/createcivilization/capitol/client/journeymap/ClientJMClaims.java b/src/main/java/com/createcivilization/capitol/client/journeymap/ClientJMClaims.java index bc7031f..16ac12e 100644 --- a/src/main/java/com/createcivilization/capitol/client/journeymap/ClientJMClaims.java +++ b/src/main/java/com/createcivilization/capitol/client/journeymap/ClientJMClaims.java @@ -55,10 +55,19 @@ public synchronized void setJourneyMapDataPath(File addonDataModPath) { Path nextClaimsFile = worldDir.resolve("claims").resolve("claims.json"); if (claimsFile != null && claimsFile.equals(nextClaimsFile)) return; + boolean hadExistingFile = claimsFile != null; + if (hadExistingFile) { + flush(); + } + claimsFile = nextClaimsFile; loaded = false; - claims.clear(); - dirty = false; + if (hadExistingFile) { + claims.clear(); + dirty = false; + } else if (dirty) { + flush(); + } } public synchronized Map snapshot() { @@ -70,6 +79,11 @@ public synchronized Map snapshot() { return out; } + public synchronized int signature() { + ensureLoaded(); + return claims.entrySet().hashCode(); + } + public synchronized void upsert(ChunkPos pos, Team team) { Objects.requireNonNull(pos, "pos"); Objects.requireNonNull(team, "team"); @@ -88,6 +102,7 @@ public synchronized void remove(ChunkPos pos) { public synchronized void flush() { if (!dirty) return; + if (claimsFile == null) return; ensureLoaded(); writeFile(); dirty = false; diff --git a/src/main/java/com/createcivilization/capitol/client/networking/ClientPayloadHandler.java b/src/main/java/com/createcivilization/capitol/client/networking/ClientPayloadHandler.java index 6ea6a36..b56837d 100644 --- a/src/main/java/com/createcivilization/capitol/client/networking/ClientPayloadHandler.java +++ b/src/main/java/com/createcivilization/capitol/client/networking/ClientPayloadHandler.java @@ -1,5 +1,6 @@ package com.createcivilization.capitol.client.networking; +import com.createcivilization.capitol.client.events.ChunkEvents; import com.createcivilization.capitol.client.journeymap.ClientJMClaims; import com.createcivilization.capitol.common.data.Team; import com.createcivilization.capitol.common.networking.packets.S2CChunkData; @@ -15,6 +16,7 @@ public static void chunkDataHandler(final S2CChunkData chunkData, final IPayload ClientClaimCache.addClaim(chunkPos, team); ClientJMClaims.instance().upsert(chunkPos, team); ClientJMClaims.instance().flush(); + ChunkEvents.onClaimInfoUpdated(chunkPos); } public static void chunkRemoveHandler(final S2CChunkRemove chunkData, final IPayloadContext context) { @@ -22,5 +24,6 @@ public static void chunkRemoveHandler(final S2CChunkRemove chunkData, final IPay ClientClaimCache.removeClaim(chunkPos); ClientJMClaims.instance().remove(chunkPos); ClientJMClaims.instance().flush(); + ChunkEvents.onClaimInfoUpdated(chunkPos); } } diff --git a/src/main/java/com/createcivilization/capitol/common/compat/journeymap/CapitolJourneyMapPlugin.java b/src/main/java/com/createcivilization/capitol/common/compat/journeymap/CapitolJourneyMapPlugin.java index 8c6cb1c..d8d459c 100644 --- a/src/main/java/com/createcivilization/capitol/common/compat/journeymap/CapitolJourneyMapPlugin.java +++ b/src/main/java/com/createcivilization/capitol/common/compat/journeymap/CapitolJourneyMapPlugin.java @@ -48,7 +48,7 @@ public class CapitolJourneyMapPlugin implements IClientPlugin { private IClientAPI api; private int tickCounter; - private int lastSignature; + private int lastSignature = Integer.MIN_VALUE; private ChunkPos lastPlayerChunk; private ChunkPos lastAreaCenterChunk; private PolygonOverlay rangeOverlay; @@ -70,6 +70,7 @@ public class CapitolJourneyMapPlugin implements IClientPlugin { private IThemeButton claimModeButton; private IThemeButton claimSelectedButton; private IThemeButton unclaimSelectedButton; + private IThemeButton autoClaimButton; @Override public String getModId() { @@ -108,6 +109,11 @@ private void onAddonButtonDisplay(FullscreenDisplayEvent.AddonButtonDisplayEvent unclaimSelected(); }); + autoClaimButton = event.getThemeButtonDisplay().addThemeToggleButton("Autoclaim", icon, false, button -> { + button.setToggled(false); + toggleAutoClaim(); + }); + updateClaimModeUiState(); } @@ -276,7 +282,9 @@ private void tick(ClientTickEvent.Post event) { if (++tickCounter < REFRESH_INTERVAL_TICKS) return; tickCounter = 0; - int signature = ClientClaimCache.claims.entrySet().hashCode(); + int signature = 1; + signature = 31 * signature + ClientJMClaims.instance().signature(); + signature = 31 * signature + ClientClaimCache.claims.entrySet().hashCode(); if (signature == lastSignature) return; lastSignature = signature; @@ -342,6 +350,19 @@ private void updateClaimModeUiState() { } catch (Throwable ignored) { } } + if (autoClaimButton != null) { + try { + autoClaimButton.setEnabled(claimingMode); + } catch (Throwable ignored) { + } + } + } + + private void toggleAutoClaim() { + var player = Minecraft.getInstance().player; + if (player == null || player.connection == null) return; + + player.connection.sendCommand("capitol claim auto"); } // this sends a single packet for the whole selection, so chat doesn't get spammed diff --git a/src/main/java/com/createcivilization/capitol/server/networking/ServerPayloadHandler.java b/src/main/java/com/createcivilization/capitol/server/networking/ServerPayloadHandler.java index e1984db..2fb6b75 100644 --- a/src/main/java/com/createcivilization/capitol/server/networking/ServerPayloadHandler.java +++ b/src/main/java/com/createcivilization/capitol/server/networking/ServerPayloadHandler.java @@ -24,7 +24,11 @@ public static void handleChunkRequest(final C2SChunkRequest request, final IPayl CapitolDatabase database = DatabaseManager.database; ChunkPos chunkPos = new ChunkPos(request.packedChunkPos()); Team team = database.getChunkOwner(chunkPos, context.player().level()); - if(team == null) return; + if (team == null) { + S2CChunkRemove packet = new S2CChunkRemove(request.packedChunkPos()); + PacketDistributor.sendToPlayersTrackingChunk((ServerLevel) context.player().level(), chunkPos, packet); + return; + } S2CChunkData packet = new S2CChunkData(request.packedChunkPos(), team); PacketDistributor.sendToPlayersTrackingChunk((ServerLevel) context.player().level(), chunkPos, packet); } From f33d0ddf228cf54769bd1da6d5968f849f56962e Mon Sep 17 00:00:00 2001 From: starpanda24825 Date: Tue, 12 May 2026 19:18:18 +0100 Subject: [PATCH 2/3] requested changes --- .../capitol/client/events/ChunkEvents.java | 16 ++++++++-------- .../journeymap/CapitolJourneyMapPlugin.java | 11 ++++++++--- .../resources/assets/capitol/lang/en_us.json | 2 ++ 3 files changed, 18 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/createcivilization/capitol/client/events/ChunkEvents.java b/src/main/java/com/createcivilization/capitol/client/events/ChunkEvents.java index 71711e3..90e4e78 100644 --- a/src/main/java/com/createcivilization/capitol/client/events/ChunkEvents.java +++ b/src/main/java/com/createcivilization/capitol/client/events/ChunkEvents.java @@ -22,10 +22,11 @@ @EventBusSubscriber(modid = Capitol.MOD_ID, value = Dist.CLIENT) public class ChunkEvents { - private static ChunkPos lastPlayerChunk; - private static ChunkPos pendingChunkAnnouncement; - private static boolean hasLastTerritory; - private static UUID lastTerritoryTeamId; + private static final int RGB_24_BIT_MASK = 0xFFFFFF; + private static ChunkPos lastPlayerChunk = null; + private static ChunkPos pendingChunkAnnouncement = null; + private static boolean hasLastTerritory = false; + private static UUID lastTerritoryTeamId = null; /** * Handles sending packets to server when loading chunks to fetch claims and adding to cache @@ -41,8 +42,7 @@ private static void onChunkLoad(ChunkEvent.Load event) { @SubscribeEvent private static void onClientTick(ClientTickEvent.Post event) { - var mc = Minecraft.getInstance(); - var player = mc.player; + var player = Minecraft.getInstance().player; if (player == null) return; ChunkPos current = player.chunkPosition(); @@ -90,7 +90,7 @@ private static void onTerritoryResolved(Team team) { private static void showTerritory(Team team) { var player = Minecraft.getInstance().player; if (player == null) return; - int rgb = team.getColor().getRGB() & 0xFFFFFF; + int rgb = team.getColor().getRGB() & RGB_24_BIT_MASK; player.displayClientMessage( Component.literal(team.getName()).withStyle(style -> style.withColor(TextColor.fromRgb(rgb))), true @@ -100,7 +100,7 @@ private static void showTerritory(Team team) { private static void showWilderness() { var player = Minecraft.getInstance().player; if (player == null) return; - player.displayClientMessage(Component.literal("Wilderness").withStyle(ChatFormatting.DARK_GREEN), true); + player.displayClientMessage(Component.translatable("hud.capitol.territory.wilderness").withStyle(ChatFormatting.DARK_GREEN), true); } /** diff --git a/src/main/java/com/createcivilization/capitol/common/compat/journeymap/CapitolJourneyMapPlugin.java b/src/main/java/com/createcivilization/capitol/common/compat/journeymap/CapitolJourneyMapPlugin.java index d8d459c..5b6b4fa 100644 --- a/src/main/java/com/createcivilization/capitol/common/compat/journeymap/CapitolJourneyMapPlugin.java +++ b/src/main/java/com/createcivilization/capitol/common/compat/journeymap/CapitolJourneyMapPlugin.java @@ -282,9 +282,7 @@ private void tick(ClientTickEvent.Post event) { if (++tickCounter < REFRESH_INTERVAL_TICKS) return; tickCounter = 0; - int signature = 1; - signature = 31 * signature + ClientJMClaims.instance().signature(); - signature = 31 * signature + ClientClaimCache.claims.entrySet().hashCode(); + int signature = computeClaimsSignature(); if (signature == lastSignature) return; lastSignature = signature; @@ -309,6 +307,13 @@ private void tick(ClientTickEvent.Post event) { } } + private int computeClaimsSignature() { + int signature = 1; + signature = 31 * signature + ClientJMClaims.instance().signature(); + signature = 31 * signature + ClientClaimCache.claims.entrySet().hashCode(); + return signature; + } + // hard reset when claim mode toggles off // also makes sure we instantly show the purple radius when toggling on private void updateClaimModeState() { diff --git a/src/main/resources/assets/capitol/lang/en_us.json b/src/main/resources/assets/capitol/lang/en_us.json index 515e35d..75064b8 100644 --- a/src/main/resources/assets/capitol/lang/en_us.json +++ b/src/main/resources/assets/capitol/lang/en_us.json @@ -18,6 +18,8 @@ "gui.journeymap.capitol.claim_chunk": "Claim chunk", "gui.journeymap.capitol.unclaim_chunk": "Unclaim chunk", + "hud.capitol.territory.wilderness": "Wilderness", + "commands.capitol.not_in_team_error": "You are not in any team", "commands.capitol.no_player_found": "There is no player called %s", "commands.capitol.player_not_in_team": "%s is not a member of %s", From 0a7fa266c63e522cdede5f4cd940867bbe744c75 Mon Sep 17 00:00:00 2001 From: starpanda24825 Date: Tue, 12 May 2026 19:34:21 +0100 Subject: [PATCH 3/3] requested changes --- src/main/resources/assets/capitol/lang/en_us.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/assets/capitol/lang/en_us.json b/src/main/resources/assets/capitol/lang/en_us.json index fcbbef0..1bf743d 100644 --- a/src/main/resources/assets/capitol/lang/en_us.json +++ b/src/main/resources/assets/capitol/lang/en_us.json @@ -139,4 +139,4 @@ "commands.capitol.help.team.player.permission.reset": "Reset a player's individual permission overrides", "commands.capitol.help.invites": "Accept or deny a team invite", "commands.capitol.help.claim.auto": "Toggles auto claiming mode, while in auto mode walk into unclaimed chunks to claim them." -} +} \ No newline at end of file