From 87964a82b3d4e070f56bba364750033731435a91 Mon Sep 17 00:00:00 2001 From: Kotos Date: Sun, 10 May 2026 23:40:37 +0100 Subject: [PATCH 01/23] Fixed translations for auto claiming --- .../capitol/server/commands/claim/ClaimCommand.java | 4 ++-- .../capitol/server/events/AutoClaimEvents.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/createcivilization/capitol/server/commands/claim/ClaimCommand.java b/src/main/java/com/createcivilization/capitol/server/commands/claim/ClaimCommand.java index d8899b7..880ef68 100644 --- a/src/main/java/com/createcivilization/capitol/server/commands/claim/ClaimCommand.java +++ b/src/main/java/com/createcivilization/capitol/server/commands/claim/ClaimCommand.java @@ -175,10 +175,10 @@ private static int auto(CommandContext context) { if (AutoClaimEvents.isAutoClaimer(player)) { AutoClaimEvents.removeAutoClaimer(player); - context.getSource().sendSuccess(() -> Component.translatable("commands.capitol.claim.auto_claim.stop").withStyle(ChatFormatting.GREEN), true); + context.getSource().sendSuccess(() -> Component.translatable("commands.capitol.claim.auto_claiming.stop").withStyle(ChatFormatting.GREEN), true); } else { AutoClaimEvents.updateAutoClaimer(player); - context.getSource().sendSuccess(() -> Component.translatable("commands.capitol.claim.auto_claim.start").withStyle(ChatFormatting.GREEN), true); + context.getSource().sendSuccess(() -> Component.translatable("commands.capitol.claim.auto_claiming.start").withStyle(ChatFormatting.GREEN), true); } return 1; } diff --git a/src/main/java/com/createcivilization/capitol/server/events/AutoClaimEvents.java b/src/main/java/com/createcivilization/capitol/server/events/AutoClaimEvents.java index 70385db..23fe886 100644 --- a/src/main/java/com/createcivilization/capitol/server/events/AutoClaimEvents.java +++ b/src/main/java/com/createcivilization/capitol/server/events/AutoClaimEvents.java @@ -32,7 +32,7 @@ public static void onEntityEnterSection(EntityEvent.EnteringSection event) { } if (isAutoClaimer(player)) { if (Calendar.getInstance().getTimeInMillis() - autoClaimingPlayers.get(player.getUUID()) < CapitolConfig.AUTO_CLAIM_COOLDOWN.get() * 1000) { - player.displayClientMessage(Component.translatable("commands.capitol.claim.auto_claim.too_fast").withStyle(ChatFormatting.RED), false); + player.displayClientMessage(Component.translatable("commands.capitol.claim.auto_claiming.too_fast").withStyle(ChatFormatting.RED), false); return; } From a745097177476c4c964dedd4ab597c908fb095cd Mon Sep 17 00:00:00 2001 From: Kotos Date: Mon, 11 May 2026 00:49:49 +0100 Subject: [PATCH 02/23] Added permissions list --- .../server/commands/team/TeamRoleCommand.java | 44 +++++++++++++++++++ .../resources/assets/capitol/lang/en_us.json | 2 + 2 files changed, 46 insertions(+) diff --git a/src/main/java/com/createcivilization/capitol/server/commands/team/TeamRoleCommand.java b/src/main/java/com/createcivilization/capitol/server/commands/team/TeamRoleCommand.java index d7b7912..157bf0c 100644 --- a/src/main/java/com/createcivilization/capitol/server/commands/team/TeamRoleCommand.java +++ b/src/main/java/com/createcivilization/capitol/server/commands/team/TeamRoleCommand.java @@ -10,7 +10,10 @@ import net.minecraft.ChatFormatting; import net.minecraft.commands.CommandSourceStack; import net.minecraft.commands.Commands; +import net.minecraft.network.chat.ClickEvent; import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.HoverEvent; +import net.minecraft.network.chat.MutableComponent; import net.minecraft.server.players.GameProfileCache; import java.util.List; @@ -67,6 +70,7 @@ static LiteralArgumentBuilder register() { return builder.buildFuture(); }) .executes(TeamRoleCommand::editRolePerms))) + .then(Commands.literal("list").executes(TeamRoleCommand::viewRolePermList)) .then(Commands.literal("name") .then(Commands.argument("new_name", StringArgumentType.string()) .executes(TeamRoleCommand::editRoleName))) @@ -278,6 +282,46 @@ private static int editRolePerms(CommandContext context) { return 1; } + private static int viewRolePermList(CommandContext context) { + CapitolDatabase database = DatabaseManager.database; + var player = context.getSource().getPlayer(); + Team team = database.getPlayerTeam(player); + if (team == null) { + return failCommand(context, "commands.capitol.not_in_team_error"); + } + + String roleName = StringArgumentType.getString(context, "role_name"); + TeamRole role = database.getRoleByName(team, roleName); + + if (role == null) { + return failCommand(context, "commands.capitol.team.role.not_found", roleName, team.getName()); + } + + context.getSource().sendSuccess(() -> + Component.translatable("commands.capitol.team.role.permission_list.role").append(roleName).withStyle(ChatFormatting.GOLD) + , false); + + for (Permission perm : Permission.values()) { + MutableComponent comp = Component.literal("[").append(perm.hasPermission(role.permissions()) ? Component.literal("✔").withStyle(ChatFormatting.GREEN) : Component.literal("❌").withStyle(ChatFormatting.RED)).append("]"); + comp.withStyle(s -> s.withClickEvent( + new ClickEvent(ClickEvent.Action.RUN_COMMAND, String.format("", roleName, perm.name().toLowerCase())) + ).withHoverEvent( + new HoverEvent(HoverEvent.Action.SHOW_TEXT, Component.literal("Click to swap permissions")) + )); + context.getSource().sendSuccess(() -> + comp.append(Component.literal(" ").withStyle(ChatFormatting.GOLD)).append(Component.literal(perm.name()).withStyle(ChatFormatting.WHITE)) + , false); + } + + /*context.getSource().sendSuccess(() -> Component.translatable("commands.capitol.permission_toggle", + Component.literal(permissionName.toLowerCase()).withStyle(ChatFormatting.AQUA), + Component.literal(roleName).withStyle(ChatFormatting.GOLD), + Component.literal(String.valueOf(oldState)).withStyle(oldState ? ChatFormatting.GREEN : ChatFormatting.RED), + Component.literal(String.valueOf(newState)).withStyle(newState ? ChatFormatting.GREEN : ChatFormatting.RED)) + .withStyle(ChatFormatting.GRAY), true);*/ + return 1; + } + static int failCommand(CommandContext context, String key, Object... args) { context.getSource().sendFailure(Component.translatable(key, args).withStyle(ChatFormatting.RED)); return 0; diff --git a/src/main/resources/assets/capitol/lang/en_us.json b/src/main/resources/assets/capitol/lang/en_us.json index 515e35d..f6e6096 100644 --- a/src/main/resources/assets/capitol/lang/en_us.json +++ b/src/main/resources/assets/capitol/lang/en_us.json @@ -72,6 +72,8 @@ "commands.capitol.team.role.edit.no_default": "You cannot edit default role name.", "commands.capitol.team.role.name.success": "Renamed role %s → %s", + "commands.capitol.team.role.permission_list.role": "Role: ", + "commands.capitol.team.player.no_permission": "You do not have permission to manage individual permissions", "commands.capitol.team.player.perms.reset": "Individual permissions for %s reset to role defaults.", From 2c0293d521fdd4baf43b2e11865f74095da04b44 Mon Sep 17 00:00:00 2001 From: Kotos Date: Mon, 11 May 2026 00:53:36 +0100 Subject: [PATCH 03/23] Added translations for hover text --- .../capitol/server/commands/team/TeamRoleCommand.java | 4 ++-- src/main/resources/assets/capitol/lang/en_us.json | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/createcivilization/capitol/server/commands/team/TeamRoleCommand.java b/src/main/java/com/createcivilization/capitol/server/commands/team/TeamRoleCommand.java index 157bf0c..da24835 100644 --- a/src/main/java/com/createcivilization/capitol/server/commands/team/TeamRoleCommand.java +++ b/src/main/java/com/createcivilization/capitol/server/commands/team/TeamRoleCommand.java @@ -304,9 +304,9 @@ private static int viewRolePermList(CommandContext context) for (Permission perm : Permission.values()) { MutableComponent comp = Component.literal("[").append(perm.hasPermission(role.permissions()) ? Component.literal("✔").withStyle(ChatFormatting.GREEN) : Component.literal("❌").withStyle(ChatFormatting.RED)).append("]"); comp.withStyle(s -> s.withClickEvent( - new ClickEvent(ClickEvent.Action.RUN_COMMAND, String.format("", roleName, perm.name().toLowerCase())) + new ClickEvent(ClickEvent.Action.RUN_COMMAND, String.format("/capitol team role edit %s permission %s", roleName, perm.name().toLowerCase())) ).withHoverEvent( - new HoverEvent(HoverEvent.Action.SHOW_TEXT, Component.literal("Click to swap permissions")) + new HoverEvent(HoverEvent.Action.SHOW_TEXT, Component.translatable("commands.capitol.team.role.permission_list.hover")) )); context.getSource().sendSuccess(() -> comp.append(Component.literal(" ").withStyle(ChatFormatting.GOLD)).append(Component.literal(perm.name()).withStyle(ChatFormatting.WHITE)) diff --git a/src/main/resources/assets/capitol/lang/en_us.json b/src/main/resources/assets/capitol/lang/en_us.json index f6e6096..3d37df4 100644 --- a/src/main/resources/assets/capitol/lang/en_us.json +++ b/src/main/resources/assets/capitol/lang/en_us.json @@ -73,6 +73,7 @@ "commands.capitol.team.role.name.success": "Renamed role %s → %s", "commands.capitol.team.role.permission_list.role": "Role: ", + "commands.capitol.team.role.permission_list.hover": "Click to swap permissions", "commands.capitol.team.player.no_permission": "You do not have permission to manage individual permissions", "commands.capitol.team.player.perms.reset": "Individual permissions for %s reset to role defaults.", From 5e99e261cc0581b30cc76835c9fb80f831920d2f Mon Sep 17 00:00:00 2001 From: Kotos Date: Mon, 11 May 2026 13:43:35 +0100 Subject: [PATCH 04/23] Added basic name formatting --- .../server/events/NameFormatEvents.java | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 src/main/java/com/createcivilization/capitol/server/events/NameFormatEvents.java diff --git a/src/main/java/com/createcivilization/capitol/server/events/NameFormatEvents.java b/src/main/java/com/createcivilization/capitol/server/events/NameFormatEvents.java new file mode 100644 index 0000000..ddacdce --- /dev/null +++ b/src/main/java/com/createcivilization/capitol/server/events/NameFormatEvents.java @@ -0,0 +1,28 @@ +package com.createcivilization.capitol.server.events; + +import com.createcivilization.capitol.Capitol; +import com.createcivilization.capitol.common.data.Team; +import com.createcivilization.capitol.common.managers.DatabaseManager; +import com.createcivilization.capitol.common.modules.database.CapitolDatabase; +import com.createcivilization.capitol.common.modules.database.Database; +import net.minecraft.ChatFormatting; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.TextColor; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.neoforge.event.entity.player.PlayerEvent; + +@EventBusSubscriber(modid = Capitol.MOD_ID, value = Dist.DEDICATED_SERVER) +public class NameFormatEvents { + @SubscribeEvent + public static void onNameFormat(PlayerEvent.NameFormat event) { + Team team = DatabaseManager.database.getTeam(event.getEntity().getUUID()); + if (team == null) { + return; + } + Component prevName = event.getDisplayname(); + Component tag = Component.literal(team.getTag()).withStyle(style -> style.withColor(TextColor.fromRgb(team.getColor().getRGB()))); + event.setDisplayname(Component.literal("[").append(tag).append("] ").append(prevName)); + } +} From d1c18488d82f5b0498eb5bca506c395c254737c5 Mon Sep 17 00:00:00 2001 From: Kotos Date: Mon, 11 May 2026 13:44:32 +0100 Subject: [PATCH 05/23] Added list command to help command --- .../capitol/server/commands/help/HelpCommand.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/createcivilization/capitol/server/commands/help/HelpCommand.java b/src/main/java/com/createcivilization/capitol/server/commands/help/HelpCommand.java index ba66b4f..d90fc50 100644 --- a/src/main/java/com/createcivilization/capitol/server/commands/help/HelpCommand.java +++ b/src/main/java/com/createcivilization/capitol/server/commands/help/HelpCommand.java @@ -31,7 +31,7 @@ private static int showHelp(CommandContext context) { msg.append(entry("/capitol team invite ", Component.translatable("commands.capitol.help.team.invite"))); msg.append(entry("/capitol team kick ", Component.translatable("commands.capitol.help.team.kick"))); msg.append(entry("/capitol team disband", Component.translatable("commands.capitol.help.team.disband"))); - msg.append(entry("/capitol team role edit remove|rename|assign|permission", Component.translatable("commands.capitol.help.team.role.edit"))); + msg.append(entry("/capitol team role edit remove|rename|assign|permission|list", Component.translatable("commands.capitol.help.team.role.edit"))); msg.append(entry("/capitol team role create ", Component.translatable("commands.capitol.help.team.role.create"))); msg.append(entry("/capitol team protection ", Component.translatable("commands.capitol.help.team.protection"))); msg.append(entry("/capitol team player permission ", Component.translatable("commands.capitol.help.team.player.permission"))); From beca404baca968a96f277deb5d4d22c398e0dced Mon Sep 17 00:00:00 2001 From: Kotos Date: Mon, 11 May 2026 14:07:08 +0100 Subject: [PATCH 06/23] Added nation tags to show before player names. Currently is surrounded by [TAG] name in the tab list and in the chat. --- .../server/events/NameFormatEvents.java | 26 +++++++++++++++---- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/createcivilization/capitol/server/events/NameFormatEvents.java b/src/main/java/com/createcivilization/capitol/server/events/NameFormatEvents.java index ddacdce..95f26e9 100644 --- a/src/main/java/com/createcivilization/capitol/server/events/NameFormatEvents.java +++ b/src/main/java/com/createcivilization/capitol/server/events/NameFormatEvents.java @@ -6,23 +6,39 @@ import com.createcivilization.capitol.common.modules.database.CapitolDatabase; import com.createcivilization.capitol.common.modules.database.Database; import net.minecraft.ChatFormatting; +import net.minecraft.network.chat.ClickEvent; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.TextColor; import net.neoforged.api.distmarker.Dist; import net.neoforged.bus.api.SubscribeEvent; import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.neoforge.event.ServerChatEvent; import net.neoforged.neoforge.event.entity.player.PlayerEvent; @EventBusSubscriber(modid = Capitol.MOD_ID, value = Dist.DEDICATED_SERVER) public class NameFormatEvents { @SubscribeEvent - public static void onNameFormat(PlayerEvent.NameFormat event) { - Team team = DatabaseManager.database.getTeam(event.getEntity().getUUID()); + public static void onNameFormat(PlayerEvent.NameFormat event) { // Mainly for chat messages + Team team = DatabaseManager.database.getPlayerTeam(event.getEntity().getUUID()); if (team == null) { return; } - Component prevName = event.getDisplayname(); - Component tag = Component.literal(team.getTag()).withStyle(style -> style.withColor(TextColor.fromRgb(team.getColor().getRGB()))); - event.setDisplayname(Component.literal("[").append(tag).append("] ").append(prevName)); + Component prevName = event.getDisplayname(); // the spelling mistake in getDisplayname instead of getDisplayName lmao + Component tag = getTag(team); + event.setDisplayname(Component.literal("").append(tag).append(" ").append(prevName)); + } + + @SubscribeEvent + public static void onTabListNameFormat(PlayerEvent.TabListNameFormat event) { // Only for tab list + Team team = DatabaseManager.database.getPlayerTeam(event.getEntity().getUUID()); + if (team == null) { + return; + } + Component tag = getTag(team); + event.setDisplayName(Component.literal("[").append(tag).append("] ").append(event.getEntity().getName())); + } + + public static Component getTag(Team team) { + return Component.literal(team.getTag()).withStyle(style -> style.withColor(TextColor.fromRgb(team.getColor().getRGB()))); } } From f88c8316c50be472d1707d284382650322c27c47 Mon Sep 17 00:00:00 2001 From: Kotos Date: Mon, 11 May 2026 14:11:58 +0100 Subject: [PATCH 07/23] Added config for toggling tags --- .../capitol/common/config/CapitolConfig.java | 17 +++++++++++++++++ .../capitol/server/events/NameFormatEvents.java | 11 +++++++++++ 2 files changed, 28 insertions(+) diff --git a/src/main/java/com/createcivilization/capitol/common/config/CapitolConfig.java b/src/main/java/com/createcivilization/capitol/common/config/CapitolConfig.java index cf465a3..bb092df 100644 --- a/src/main/java/com/createcivilization/capitol/common/config/CapitolConfig.java +++ b/src/main/java/com/createcivilization/capitol/common/config/CapitolConfig.java @@ -48,6 +48,11 @@ public class CapitolConfig { public static final ModConfigSpec.ConfigValue> BLOCK_PLACE_EXCEPTIONS; public static final ModConfigSpec.ConfigValue> ITEM_USE_EXCEPTIONS; + // Role Exceptions + + public static final ModConfigSpec.BooleanValue DISPLAY_TAGS_IN_CHAT; + public static final ModConfigSpec.BooleanValue DISPLAY_TAGS_IN_TAB_LIST; + public enum ListType { ONLY, ALL_BUT @@ -169,6 +174,18 @@ public enum ListType { builder.pop(); + builder.comment("Role settings").push("roles"); + + DISPLAY_TAGS_IN_CHAT = builder + .comment("Whether chat messages with have the players nation tag attached.") + .define("displayTagsInChat", true); + + DISPLAY_TAGS_IN_TAB_LIST = builder + .comment("Whether the tab list will have the players nation tag attached.") + .define("displayTagsInTabList", true); + + builder.pop(); + SPEC = builder.build(); } } diff --git a/src/main/java/com/createcivilization/capitol/server/events/NameFormatEvents.java b/src/main/java/com/createcivilization/capitol/server/events/NameFormatEvents.java index 95f26e9..a2c8156 100644 --- a/src/main/java/com/createcivilization/capitol/server/events/NameFormatEvents.java +++ b/src/main/java/com/createcivilization/capitol/server/events/NameFormatEvents.java @@ -1,6 +1,7 @@ package com.createcivilization.capitol.server.events; import com.createcivilization.capitol.Capitol; +import com.createcivilization.capitol.common.config.CapitolConfig; import com.createcivilization.capitol.common.data.Team; import com.createcivilization.capitol.common.managers.DatabaseManager; import com.createcivilization.capitol.common.modules.database.CapitolDatabase; @@ -19,10 +20,15 @@ public class NameFormatEvents { @SubscribeEvent public static void onNameFormat(PlayerEvent.NameFormat event) { // Mainly for chat messages + if (!CapitolConfig.DISPLAY_TAGS_IN_CHAT.get()) { + return; + } + Team team = DatabaseManager.database.getPlayerTeam(event.getEntity().getUUID()); if (team == null) { return; } + Component prevName = event.getDisplayname(); // the spelling mistake in getDisplayname instead of getDisplayName lmao Component tag = getTag(team); event.setDisplayname(Component.literal("").append(tag).append(" ").append(prevName)); @@ -30,10 +36,15 @@ public static void onNameFormat(PlayerEvent.NameFormat event) { // Mainly for ch @SubscribeEvent public static void onTabListNameFormat(PlayerEvent.TabListNameFormat event) { // Only for tab list + if (!CapitolConfig.DISPLAY_TAGS_IN_TAB_LIST.get()) { + return; + } + Team team = DatabaseManager.database.getPlayerTeam(event.getEntity().getUUID()); if (team == null) { return; } + Component tag = getTag(team); event.setDisplayName(Component.literal("[").append(tag).append("] ").append(event.getEntity().getName())); } From 89a9970905f2799f780ea37c093b6611698d7ae0 Mon Sep 17 00:00:00 2001 From: Kotos Date: Mon, 11 May 2026 22:37:16 +0100 Subject: [PATCH 08/23] Added role-based coloring Added auto-refreshing for player names Modified the look of tags increased reliability when setting colors Added translations for setting the roles color --- .../capitol/common/data/TeamRole.java | 11 +- .../common/managers/DatabaseManager.java | 1 + .../modules/database/CapitolDatabase.java | 31 ++- .../server/commands/invite/InviteCommand.java | 5 +- .../server/commands/team/TeamCommand.java | 4 + .../server/commands/team/TeamRoleCommand.java | 194 +++++++++++++----- .../server/events/NameFormatEvents.java | 17 +- .../resources/assets/capitol/lang/en_us.json | 3 + 8 files changed, 202 insertions(+), 64 deletions(-) diff --git a/src/main/java/com/createcivilization/capitol/common/data/TeamRole.java b/src/main/java/com/createcivilization/capitol/common/data/TeamRole.java index 3b21122..fe91971 100644 --- a/src/main/java/com/createcivilization/capitol/common/data/TeamRole.java +++ b/src/main/java/com/createcivilization/capitol/common/data/TeamRole.java @@ -1,10 +1,11 @@ package com.createcivilization.capitol.common.data; +import java.awt.*; import java.sql.ResultSet; import java.sql.SQLException; import java.util.UUID; -public record TeamRole(int id, UUID teamId, String name, long permissions) { +public record TeamRole(int id, UUID teamId, String name, long permissions, Color color) { public static final String OWNER_ROLE_NAME = "owner"; public static final String DEFAULT_ROLE_NAME = "default"; @@ -22,11 +23,17 @@ public boolean hasPermission(Permission perm) { } public static TeamRole fromResultSet(ResultSet rs) throws SQLException { + Color color = null; + if (rs.getInt("color") != -1) { + color = new Color(rs.getInt("color")); + } + return new TeamRole( rs.getInt("id"), UUID.fromString(rs.getString("team_id")), rs.getString("name"), - rs.getLong("permissions") + rs.getLong("permissions"), + color ); } diff --git a/src/main/java/com/createcivilization/capitol/common/managers/DatabaseManager.java b/src/main/java/com/createcivilization/capitol/common/managers/DatabaseManager.java index 66eceb0..95d7cfb 100644 --- a/src/main/java/com/createcivilization/capitol/common/managers/DatabaseManager.java +++ b/src/main/java/com/createcivilization/capitol/common/managers/DatabaseManager.java @@ -67,6 +67,7 @@ private static void createTables() throws SQLException { "team_id TEXT NOT NULL," + "name TEXT NOT NULL," + "permissions INTEGER NOT NULL DEFAULT 0," + + "color INTEGER NOT NULL DEFAULT -1,"+ "UNIQUE (team_id, name)," + "FOREIGN KEY (team_id) REFERENCES teams (id) ON DELETE CASCADE)" ); diff --git a/src/main/java/com/createcivilization/capitol/common/modules/database/CapitolDatabase.java b/src/main/java/com/createcivilization/capitol/common/modules/database/CapitolDatabase.java index 0c52f20..e3421c0 100644 --- a/src/main/java/com/createcivilization/capitol/common/modules/database/CapitolDatabase.java +++ b/src/main/java/com/createcivilization/capitol/common/modules/database/CapitolDatabase.java @@ -8,9 +8,11 @@ import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.Level; +import java.awt.*; import java.sql.*; import java.time.Instant; import java.util.*; +import java.util.List; import java.util.concurrent.ConcurrentHashMap; public class CapitolDatabase extends Database { @@ -78,19 +80,31 @@ public void setTeamPermissions(Team team, long permissions) { * @param team the team this role belongs to * @param name the role name (e.g. "owner", "default") * @param permissions the bitfield of {@link Permission} flags + * @param color the color this role will override to for nation tags */ - public void addRole(Team team, String name, long permissions) { + public void addRole(Team team, String name, long permissions, Color color) { try (PreparedStatement ps = getConnection().prepareStatement( - "INSERT INTO team_roles (team_id, name, permissions) VALUES (?, ?, ?)")) { + "INSERT INTO team_roles (team_id, name, permissions, color) VALUES (?, ?, ?, ?)")) { ps.setString(1, team.getId().toString()); ps.setString(2, name); ps.setLong(3, permissions); + ps.setInt(4, color == null ? -1 : color.getRGB()); // -1 if the role has no associated color ps.execute(); } catch (SQLException e) { Capitol.LOGGER.error("Error while adding role to database.", e); throw new RuntimeException(e); } } + /** + * Inserts a new role into the {@code team_roles} table. + * + * @param team the team this role belongs to + * @param name the role name (e.g. "owner", "default") + * @param permissions the bitfield of {@link Permission} flags + */ + public void addRole(Team team, String name, long permissions) { + addRole(team, name, permissions, null); + } /** * Retrieves a role by its auto-incremented database ID. @@ -200,6 +214,19 @@ public void updateRoleName(Team team, String roleName, String newName) { } } + public void updateRoleColor(Team team, String roleName, Color color) { + try (PreparedStatement ps = getConnection().prepareStatement( + "UPDATE team_roles SET color = ? WHERE team_id = ? AND name = ?")) { + ps.setInt(1, color == null ? -1 : color.getRGB()); + ps.setString(2, team.getId().toString()); + ps.setString(3, roleName); + ps.execute(); + } catch (SQLException e) { + Capitol.LOGGER.error("Error while updating role color in database.", e); + throw new RuntimeException(e); + } + } + /** * Deletes a role by team and role name. * diff --git a/src/main/java/com/createcivilization/capitol/server/commands/invite/InviteCommand.java b/src/main/java/com/createcivilization/capitol/server/commands/invite/InviteCommand.java index 2c4fad9..43f9ff9 100644 --- a/src/main/java/com/createcivilization/capitol/server/commands/invite/InviteCommand.java +++ b/src/main/java/com/createcivilization/capitol/server/commands/invite/InviteCommand.java @@ -38,7 +38,7 @@ public static LiteralArgumentBuilder register() { } private static int acceptInvite(CommandContext context) { - Player player = context.getSource().getPlayer(); + ServerPlayer player = context.getSource().getPlayer(); if (player == null) return 0; Team team = resolveInvitedTeam(context, player); @@ -48,6 +48,9 @@ private static int acceptInvite(CommandContext context) { DatabaseManager.database.addPlayerToTeam(player, team, role); InviteHandler.clearInvites(player); + player.refreshDisplayName(); + player.refreshTabListName(); // needs to be a ServerPlayer for this. + MutableComponent joinMsg = Component.translatable("commands.capitol.invites.join.announcement", Component.literal(player.getName().getString()).withStyle(ChatFormatting.WHITE), Component.literal(team.getName()).withStyle(ChatFormatting.GOLD)) diff --git a/src/main/java/com/createcivilization/capitol/server/commands/team/TeamCommand.java b/src/main/java/com/createcivilization/capitol/server/commands/team/TeamCommand.java index 9dcd61f..8e9f516 100644 --- a/src/main/java/com/createcivilization/capitol/server/commands/team/TeamCommand.java +++ b/src/main/java/com/createcivilization/capitol/server/commands/team/TeamCommand.java @@ -339,4 +339,8 @@ private static int confirmDisband(CommandContext context) { context.getSource().sendSuccess(() -> Component.translatable("commands.capitol.team.disband.success").withStyle(ChatFormatting.GREEN), true); return 1; } + + public static Map getNamedColors() { + return NAMED_COLORS; + } } \ No newline at end of file diff --git a/src/main/java/com/createcivilization/capitol/server/commands/team/TeamRoleCommand.java b/src/main/java/com/createcivilization/capitol/server/commands/team/TeamRoleCommand.java index d7b7912..66aef63 100644 --- a/src/main/java/com/createcivilization/capitol/server/commands/team/TeamRoleCommand.java +++ b/src/main/java/com/createcivilization/capitol/server/commands/team/TeamRoleCommand.java @@ -11,8 +11,13 @@ import net.minecraft.commands.CommandSourceStack; import net.minecraft.commands.Commands; import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.TextColor; +import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.players.GameProfileCache; +import net.minecraft.world.entity.player.Player; +import javax.xml.crypto.Data; +import java.awt.*; import java.util.List; import java.util.Objects; import java.util.Optional; @@ -26,52 +31,116 @@ static LiteralArgumentBuilder register() { .executes(TeamRoleCommand::createRole))) .then(Commands.literal("edit") .then(Commands.argument("role_name", StringArgumentType.word()) - .suggests((context, builder) -> { - CapitolDatabase database = DatabaseManager.database; - Team team = database.getPlayerTeam(context.getSource().getPlayer()); - if (team == null) { - builder.suggest("YOU ARE NOT IN A TEAM"); + .suggests((context, builder) -> { + CapitolDatabase database = DatabaseManager.database; + Team team = database.getPlayerTeam(context.getSource().getPlayer()); + if (team == null) { + builder.suggest("YOU ARE NOT IN A TEAM"); + return builder.buildFuture(); + } + List roles = database.getTeamRoles(team); + for (TeamRole role : roles) { + builder.suggest(role.name()); + } return builder.buildFuture(); - } - List roles = database.getTeamRoles(team); - for (TeamRole role : roles) { - builder.suggest(role.name()); - } - return builder.buildFuture(); - }) - .then(Commands.literal("assign") - .then(Commands.argument("player", StringArgumentType.string()) - .suggests((context, builder) -> { - CapitolDatabase database = DatabaseManager.database; - Team team = database.getPlayerTeam(context.getSource().getPlayer()); - if (team == null) { - builder.suggest("YOU ARE NOT IN A TEAM"); + }) + .then(Commands.literal("assign") + .then(Commands.argument("player", StringArgumentType.string()) + .suggests((context, builder) -> { + CapitolDatabase database = DatabaseManager.database; + Team team = database.getPlayerTeam(context.getSource().getPlayer()); + if (team == null) { + builder.suggest("YOU ARE NOT IN A TEAM"); + return builder.buildFuture(); + } + List members = database.getTeamMembers(team); + GameProfileCache profileCache = context.getSource().getServer().getProfileCache(); + for (TeamMember member : members) { + profileCache.get(member.playerUUID()).ifPresent( + gameProfile -> builder.suggest(gameProfile.getName()) + ); + } return builder.buildFuture(); - } - List members = database.getTeamMembers(team); - GameProfileCache profileCache = context.getSource().getServer().getProfileCache(); - for (TeamMember member : members) { - profileCache.get(member.playerUUID()).ifPresent( - gameProfile -> builder.suggest(gameProfile.getName()) - ); - } - return builder.buildFuture(); - }) - .executes(TeamRoleCommand::assignRole))) - .then(Commands.literal("permission") - .then(Commands.argument("permission_value", StringArgumentType.word()) - .suggests((context, builder) -> { - for (Permission perm : Permission.values()) { - builder.suggest(perm.name().toLowerCase()); - } - return builder.buildFuture(); - }) - .executes(TeamRoleCommand::editRolePerms))) - .then(Commands.literal("name") - .then(Commands.argument("new_name", StringArgumentType.string()) - .executes(TeamRoleCommand::editRoleName))) - .then(Commands.literal("remove") - .executes(TeamRoleCommand::removeRole)))); + }) + .executes(TeamRoleCommand::assignRole))) + .then(Commands.literal("permission") + .then(Commands.argument("permission_value", StringArgumentType.word()) + .suggests((context, builder) -> { + for (Permission perm : Permission.values()) { + builder.suggest(perm.name().toLowerCase()); + } + return builder.buildFuture(); + }) + .executes(TeamRoleCommand::editRolePerms))) + .then(Commands.literal("name") + .then(Commands.argument("new_name", StringArgumentType.string()) + .executes(TeamRoleCommand::editRoleName))) + .then(Commands.literal("remove") + .executes(TeamRoleCommand::removeRole)) + .then(Commands.literal("color") + .then(Commands.argument("new_color", StringArgumentType.string()) + .suggests((context, builder) -> { + TeamCommand.getNamedColors().keySet().forEach(builder::suggest); + builder.suggest("none"); + return builder.buildFuture(); + }) + .executes(TeamRoleCommand::setColor))) + )); + + } + + private static int setColor(CommandContext context) { + CapitolDatabase database = DatabaseManager.database; + var player = context.getSource().getPlayer(); + if (player == null) { + return failCommand(context, "commands.capitol.command_source_was_console_error"); + } + + Team team = database.getPlayerTeam(player); + if (team == null) { + return failCommand(context, "commands.capitol.not_in_team_error"); + } + + if (!Permission.MANAGE_ROLES.hasPermission(database.getPlayerPermission(player, team))) { + return failCommand(context, "commands.capitol.team.role.no_manage_permission"); + } + String roleName = StringArgumentType.getString(context, "role_name"); + + TeamRole role = database.getRoleByName(team, roleName); + + if (role == null) { + return failCommand(context, "commands.capitol.team.role.color.failure", roleName, team.getName()); + } + + if (StringArgumentType.getString(context, "new_color").equalsIgnoreCase("none")) { + database.updateRoleColor(team, roleName, null); + + context.getSource().sendSuccess(() -> Component.translatable("commands.capitol.team.role.color.clear.success", + Component.literal(roleName).withStyle(ChatFormatting.AQUA)), true); + } else { + String hex = TeamCommand.getNamedColors().getOrDefault( + StringArgumentType.getString(context, "new_color").toLowerCase(), + StringArgumentType.getString(context, "new_color") + ).replace("#", ""); + Color color = new Color((int) Long.parseLong(hex, 16), true); + + database.updateRoleColor(team, roleName, color); + + context.getSource().sendSuccess(() -> Component.translatable("commands.capitol.team.role.color.success", + Component.literal(roleName).withStyle(ChatFormatting.AQUA), + Component.literal(hex).withStyle(style -> style.withColor(TextColor.fromRgb(color.getRGB()))) + .withStyle(ChatFormatting.GRAY)), true); + } + + for (TeamMember member : database.getTeamMembers(team)) { + ServerPlayer online = context.getSource().getServer().getPlayerList().getPlayer(member.playerUUID()); + if (online != null) { + online.refreshDisplayName(); + online.refreshTabListName(); + } + } + + return 1; } private static int createRole(CommandContext context) { @@ -93,8 +162,8 @@ private static int createRole(CommandContext context) { database.addRole(team, roleName, 0); context.getSource().sendSuccess(() -> Component.translatable("commands.capitol.team.role.create.success", - Component.literal(roleName).withStyle(ChatFormatting.AQUA), - Component.literal(team.getName()).withStyle(ChatFormatting.GOLD)) + Component.literal(roleName).withStyle(ChatFormatting.AQUA), + Component.literal(team.getName()).withStyle(ChatFormatting.GOLD)) .withStyle(ChatFormatting.GRAY), true); return 1; } @@ -132,8 +201,16 @@ private static int removeRole(CommandContext context) { database.deleteRole(team, roleName); + for (TeamMember member : database.getTeamMembers(team)) { // Sweeping update, applies to all players in a team currently online. + ServerPlayer online = context.getSource().getServer().getPlayerList().getPlayer(member.playerUUID()); + if (online != null) { + online.refreshDisplayName(); + online.refreshTabListName(); + } + } + context.getSource().sendSuccess(() -> Component.translatable("commands.capitol.team.role.remove.success", - Component.literal(roleName).withStyle(ChatFormatting.AQUA)) + Component.literal(roleName).withStyle(ChatFormatting.AQUA)) .withStyle(ChatFormatting.GRAY), true); return 1; } @@ -182,9 +259,16 @@ private static int assignRole(CommandContext context) { database.updatePlayerRole(gameProfile.getId(), team, role); + ServerPlayer target = context.getSource().getServer().getPlayerList().getPlayer(gameProfile.getId()); // Specifically refreshes the targeted player + if (target != null) { + target.refreshTabListName(); + target.refreshDisplayName(); + } + + context.getSource().sendSuccess(() -> Component.translatable("commands.capitol.team.role.assign.success", - Component.literal(gameProfile.getName()).withStyle(ChatFormatting.WHITE), - Component.literal(roleName).withStyle(ChatFormatting.AQUA)) + Component.literal(gameProfile.getName()).withStyle(ChatFormatting.WHITE), + Component.literal(roleName).withStyle(ChatFormatting.AQUA)) .withStyle(ChatFormatting.GRAY), true); return 1; } @@ -225,8 +309,8 @@ private static int editRoleName(CommandContext context) { database.updateRoleName(team, roleName, newRoleName); context.getSource().sendSuccess(() -> Component.translatable("commands.capitol.team.role.name.success", - Component.literal(roleName).withStyle(ChatFormatting.AQUA), - Component.literal(newRoleName).withStyle(ChatFormatting.AQUA)) + Component.literal(roleName).withStyle(ChatFormatting.AQUA), + Component.literal(newRoleName).withStyle(ChatFormatting.AQUA)) .withStyle(ChatFormatting.GRAY), true); return 1; } @@ -270,10 +354,10 @@ private static int editRolePerms(CommandContext context) { database.updateRolePermissions(team, roleName, rolePerms); context.getSource().sendSuccess(() -> Component.translatable("commands.capitol.permission_toggle", - Component.literal(permissionName.toLowerCase()).withStyle(ChatFormatting.AQUA), - Component.literal(roleName).withStyle(ChatFormatting.GOLD), - Component.literal(String.valueOf(oldState)).withStyle(oldState ? ChatFormatting.GREEN : ChatFormatting.RED), - Component.literal(String.valueOf(newState)).withStyle(newState ? ChatFormatting.GREEN : ChatFormatting.RED)) + Component.literal(permissionName.toLowerCase()).withStyle(ChatFormatting.AQUA), + Component.literal(roleName).withStyle(ChatFormatting.GOLD), + Component.literal(String.valueOf(oldState)).withStyle(oldState ? ChatFormatting.GREEN : ChatFormatting.RED), + Component.literal(String.valueOf(newState)).withStyle(newState ? ChatFormatting.GREEN : ChatFormatting.RED)) .withStyle(ChatFormatting.GRAY), true); return 1; } diff --git a/src/main/java/com/createcivilization/capitol/server/events/NameFormatEvents.java b/src/main/java/com/createcivilization/capitol/server/events/NameFormatEvents.java index a2c8156..3994848 100644 --- a/src/main/java/com/createcivilization/capitol/server/events/NameFormatEvents.java +++ b/src/main/java/com/createcivilization/capitol/server/events/NameFormatEvents.java @@ -3,6 +3,7 @@ import com.createcivilization.capitol.Capitol; import com.createcivilization.capitol.common.config.CapitolConfig; import com.createcivilization.capitol.common.data.Team; +import com.createcivilization.capitol.common.data.TeamRole; import com.createcivilization.capitol.common.managers.DatabaseManager; import com.createcivilization.capitol.common.modules.database.CapitolDatabase; import com.createcivilization.capitol.common.modules.database.Database; @@ -16,6 +17,8 @@ import net.neoforged.neoforge.event.ServerChatEvent; import net.neoforged.neoforge.event.entity.player.PlayerEvent; +import javax.management.relation.Role; + @EventBusSubscriber(modid = Capitol.MOD_ID, value = Dist.DEDICATED_SERVER) public class NameFormatEvents { @SubscribeEvent @@ -28,9 +31,10 @@ public static void onNameFormat(PlayerEvent.NameFormat event) { // Mainly for ch if (team == null) { return; } + TeamRole role = DatabaseManager.database.getPlayerRole(event.getEntity(), team); Component prevName = event.getDisplayname(); // the spelling mistake in getDisplayname instead of getDisplayName lmao - Component tag = getTag(team); + Component tag = getTag(team, role); event.setDisplayname(Component.literal("").append(tag).append(" ").append(prevName)); } @@ -44,12 +48,17 @@ public static void onTabListNameFormat(PlayerEvent.TabListNameFormat event) { // if (team == null) { return; } + TeamRole role = DatabaseManager.database.getPlayerRole(event.getEntity(), team); - Component tag = getTag(team); + Component tag = getTag(team, role); event.setDisplayName(Component.literal("[").append(tag).append("] ").append(event.getEntity().getName())); } - public static Component getTag(Team team) { - return Component.literal(team.getTag()).withStyle(style -> style.withColor(TextColor.fromRgb(team.getColor().getRGB()))); + public static Component getTag(Team team, TeamRole role) { + if (role.color() == null) { + return Component.literal(team.getTag()).withStyle(style -> style.withColor(TextColor.fromRgb(team.getColor().getRGB()))); + } else { + return Component.literal(team.getTag()).withStyle(style -> style.withColor(TextColor.fromRgb(role.color().getRGB()))); + } } } diff --git a/src/main/resources/assets/capitol/lang/en_us.json b/src/main/resources/assets/capitol/lang/en_us.json index 515e35d..0ff1433 100644 --- a/src/main/resources/assets/capitol/lang/en_us.json +++ b/src/main/resources/assets/capitol/lang/en_us.json @@ -72,6 +72,9 @@ "commands.capitol.team.role.edit.no_default": "You cannot edit default role name.", "commands.capitol.team.role.name.success": "Renamed role %s → %s", + "commands.capitol.team.role.color.success": "Set role %s's color to %s", + "commands.capitol.team.role.color.clear.success": "Cleared role %s's color", + "commands.capitol.team.player.no_permission": "You do not have permission to manage individual permissions", "commands.capitol.team.player.perms.reset": "Individual permissions for %s reset to role defaults.", From 10bd921cfd1fc9a4f44c8aee981b2eb8e5b39c2e Mon Sep 17 00:00:00 2001 From: Kotos Date: Mon, 11 May 2026 22:38:20 +0100 Subject: [PATCH 09/23] Cleaning up --- .../capitol/server/commands/team/TeamRoleCommand.java | 2 -- .../capitol/server/events/NameFormatEvents.java | 7 ------- 2 files changed, 9 deletions(-) diff --git a/src/main/java/com/createcivilization/capitol/server/commands/team/TeamRoleCommand.java b/src/main/java/com/createcivilization/capitol/server/commands/team/TeamRoleCommand.java index 66aef63..bc76607 100644 --- a/src/main/java/com/createcivilization/capitol/server/commands/team/TeamRoleCommand.java +++ b/src/main/java/com/createcivilization/capitol/server/commands/team/TeamRoleCommand.java @@ -14,9 +14,7 @@ import net.minecraft.network.chat.TextColor; import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.players.GameProfileCache; -import net.minecraft.world.entity.player.Player; -import javax.xml.crypto.Data; import java.awt.*; import java.util.List; import java.util.Objects; diff --git a/src/main/java/com/createcivilization/capitol/server/events/NameFormatEvents.java b/src/main/java/com/createcivilization/capitol/server/events/NameFormatEvents.java index 3994848..a4bd125 100644 --- a/src/main/java/com/createcivilization/capitol/server/events/NameFormatEvents.java +++ b/src/main/java/com/createcivilization/capitol/server/events/NameFormatEvents.java @@ -5,20 +5,13 @@ import com.createcivilization.capitol.common.data.Team; import com.createcivilization.capitol.common.data.TeamRole; import com.createcivilization.capitol.common.managers.DatabaseManager; -import com.createcivilization.capitol.common.modules.database.CapitolDatabase; -import com.createcivilization.capitol.common.modules.database.Database; -import net.minecraft.ChatFormatting; -import net.minecraft.network.chat.ClickEvent; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.TextColor; import net.neoforged.api.distmarker.Dist; import net.neoforged.bus.api.SubscribeEvent; import net.neoforged.fml.common.EventBusSubscriber; -import net.neoforged.neoforge.event.ServerChatEvent; import net.neoforged.neoforge.event.entity.player.PlayerEvent; -import javax.management.relation.Role; - @EventBusSubscriber(modid = Capitol.MOD_ID, value = Dist.DEDICATED_SERVER) public class NameFormatEvents { @SubscribeEvent From 439993436fe8fac941a6efe2d4e5952e1da67f46 Mon Sep 17 00:00:00 2001 From: Kotos Date: Mon, 11 May 2026 22:48:59 +0100 Subject: [PATCH 10/23] Added a max length to team tags (configurable) --- .../capitol/common/config/CapitolConfig.java | 13 ++++++++++++- .../common/modules/database/CapitolDatabase.java | 2 +- .../capitol/server/commands/team/TeamCommand.java | 6 ++++++ src/main/resources/assets/capitol/lang/en_us.json | 1 + 4 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/createcivilization/capitol/common/config/CapitolConfig.java b/src/main/java/com/createcivilization/capitol/common/config/CapitolConfig.java index bb092df..314182d 100644 --- a/src/main/java/com/createcivilization/capitol/common/config/CapitolConfig.java +++ b/src/main/java/com/createcivilization/capitol/common/config/CapitolConfig.java @@ -48,11 +48,14 @@ public class CapitolConfig { public static final ModConfigSpec.ConfigValue> BLOCK_PLACE_EXCEPTIONS; public static final ModConfigSpec.ConfigValue> ITEM_USE_EXCEPTIONS; - // Role Exceptions + // Roles public static final ModConfigSpec.BooleanValue DISPLAY_TAGS_IN_CHAT; public static final ModConfigSpec.BooleanValue DISPLAY_TAGS_IN_TAB_LIST; + // Teams + public static final ModConfigSpec.IntValue TEAM_TAG_MAX_LENGTH; + public enum ListType { ONLY, ALL_BUT @@ -186,6 +189,14 @@ public enum ListType { builder.pop(); + builder.comment("Role settings").push("team"); + + TEAM_TAG_MAX_LENGTH = builder + .comment("Max length for a team to have as a tag.") + .defineInRange("teamTagMaxLength", 3, 0, 16); + + builder.pop(); + SPEC = builder.build(); } } diff --git a/src/main/java/com/createcivilization/capitol/common/modules/database/CapitolDatabase.java b/src/main/java/com/createcivilization/capitol/common/modules/database/CapitolDatabase.java index e3421c0..21705f8 100644 --- a/src/main/java/com/createcivilization/capitol/common/modules/database/CapitolDatabase.java +++ b/src/main/java/com/createcivilization/capitol/common/modules/database/CapitolDatabase.java @@ -335,7 +335,7 @@ public void addTeam(Team team) { throw new RuntimeException(e); } - addRole(team, TeamRole.OWNER_ROLE_NAME, TeamRole.ownerPermissions()); + addRole(team, TeamRole.OWNER_ROLE_NAME, TeamRole.ownerPermissions(), new Color(0x800080)); addRole(team, TeamRole.DEFAULT_ROLE_NAME, TeamRole.defaultPermissions()); } diff --git a/src/main/java/com/createcivilization/capitol/server/commands/team/TeamCommand.java b/src/main/java/com/createcivilization/capitol/server/commands/team/TeamCommand.java index 8e9f516..b3f7de3 100644 --- a/src/main/java/com/createcivilization/capitol/server/commands/team/TeamCommand.java +++ b/src/main/java/com/createcivilization/capitol/server/commands/team/TeamCommand.java @@ -1,5 +1,6 @@ package com.createcivilization.capitol.server.commands.team; +import com.createcivilization.capitol.common.config.CapitolConfig; import com.createcivilization.capitol.common.data.*; import com.createcivilization.capitol.common.managers.DatabaseManager; import com.createcivilization.capitol.common.modules.database.CapitolDatabase; @@ -198,6 +199,11 @@ private static int createTeam(CommandContext context) { ).replace("#", ""); String tag = StringArgumentType.getString(context, "tag"); + if (tag.length() > CapitolConfig.TEAM_TAG_MAX_LENGTH.get()) { + context.getSource().sendFailure(Component.translatable("commands.capitol.team.create.tag_too_long", CapitolConfig.TEAM_TAG_MAX_LENGTH.get()).withStyle(ChatFormatting.RED)); + return 0; + } + String description; try { description = StringArgumentType.getString(context, "description"); diff --git a/src/main/resources/assets/capitol/lang/en_us.json b/src/main/resources/assets/capitol/lang/en_us.json index 0ff1433..01463e9 100644 --- a/src/main/resources/assets/capitol/lang/en_us.json +++ b/src/main/resources/assets/capitol/lang/en_us.json @@ -38,6 +38,7 @@ "commands.capitol.team.create.already_in_team": "You are already in a team, please leave before creating a new one", "commands.capitol.team.create.name_exists": "A team with that name already exists.", + "commands.capitol.team.create.tag_too_long": "Tag is too long, max length of %d", "commands.capitol.team.create.invalid_color": "Invalid hex color: #%s", "commands.capitol.team.create.success": "Team %s created!", From b711f65934d6ab9d2eb54b1ad79a5a38a43ee6c7 Mon Sep 17 00:00:00 2001 From: Kotos Date: Mon, 11 May 2026 23:44:40 +0100 Subject: [PATCH 11/23] Added player check to viewRolePermList --- .../capitol/server/commands/team/TeamRoleCommand.java | 6 +++++- src/main/resources/assets/capitol/lang/en_us.json | 3 ++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/createcivilization/capitol/server/commands/team/TeamRoleCommand.java b/src/main/java/com/createcivilization/capitol/server/commands/team/TeamRoleCommand.java index da24835..7f26002 100644 --- a/src/main/java/com/createcivilization/capitol/server/commands/team/TeamRoleCommand.java +++ b/src/main/java/com/createcivilization/capitol/server/commands/team/TeamRoleCommand.java @@ -14,6 +14,7 @@ import net.minecraft.network.chat.Component; import net.minecraft.network.chat.HoverEvent; import net.minecraft.network.chat.MutableComponent; +import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.players.GameProfileCache; import java.util.List; @@ -284,7 +285,10 @@ private static int editRolePerms(CommandContext context) { private static int viewRolePermList(CommandContext context) { CapitolDatabase database = DatabaseManager.database; - var player = context.getSource().getPlayer(); + ServerPlayer player = context.getSource().getPlayer(); + if (player == null) { + return failCommand(context, "commands.capitol.not_player"); + } Team team = database.getPlayerTeam(player); if (team == null) { return failCommand(context, "commands.capitol.not_in_team_error"); diff --git a/src/main/resources/assets/capitol/lang/en_us.json b/src/main/resources/assets/capitol/lang/en_us.json index 3d37df4..981f7d9 100644 --- a/src/main/resources/assets/capitol/lang/en_us.json +++ b/src/main/resources/assets/capitol/lang/en_us.json @@ -18,7 +18,8 @@ "gui.journeymap.capitol.claim_chunk": "Claim chunk", "gui.journeymap.capitol.unclaim_chunk": "Unclaim chunk", -"commands.capitol.not_in_team_error": "You are not in any team", + "commands.capitol.not_player": "You must be a player to run this command.", + "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", "commands.capitol.invalid_permission": "%s is not a valid permission.", From 8bafd549bd496076e074403a03722041fb88b7ef Mon Sep 17 00:00:00 2001 From: Kotos Date: Mon, 11 May 2026 13:43:35 +0100 Subject: [PATCH 12/23] Added basic name formatting --- .../server/events/NameFormatEvents.java | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 src/main/java/com/createcivilization/capitol/server/events/NameFormatEvents.java diff --git a/src/main/java/com/createcivilization/capitol/server/events/NameFormatEvents.java b/src/main/java/com/createcivilization/capitol/server/events/NameFormatEvents.java new file mode 100644 index 0000000..ddacdce --- /dev/null +++ b/src/main/java/com/createcivilization/capitol/server/events/NameFormatEvents.java @@ -0,0 +1,28 @@ +package com.createcivilization.capitol.server.events; + +import com.createcivilization.capitol.Capitol; +import com.createcivilization.capitol.common.data.Team; +import com.createcivilization.capitol.common.managers.DatabaseManager; +import com.createcivilization.capitol.common.modules.database.CapitolDatabase; +import com.createcivilization.capitol.common.modules.database.Database; +import net.minecraft.ChatFormatting; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.TextColor; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.neoforge.event.entity.player.PlayerEvent; + +@EventBusSubscriber(modid = Capitol.MOD_ID, value = Dist.DEDICATED_SERVER) +public class NameFormatEvents { + @SubscribeEvent + public static void onNameFormat(PlayerEvent.NameFormat event) { + Team team = DatabaseManager.database.getTeam(event.getEntity().getUUID()); + if (team == null) { + return; + } + Component prevName = event.getDisplayname(); + Component tag = Component.literal(team.getTag()).withStyle(style -> style.withColor(TextColor.fromRgb(team.getColor().getRGB()))); + event.setDisplayname(Component.literal("[").append(tag).append("] ").append(prevName)); + } +} From c90467e844aeea6527f702e63125085c5d6d5a6f Mon Sep 17 00:00:00 2001 From: Kotos Date: Mon, 11 May 2026 14:07:08 +0100 Subject: [PATCH 13/23] Added nation tags to show before player names. Currently is surrounded by [TAG] name in the tab list and in the chat. --- .../server/events/NameFormatEvents.java | 26 +++++++++++++++---- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/createcivilization/capitol/server/events/NameFormatEvents.java b/src/main/java/com/createcivilization/capitol/server/events/NameFormatEvents.java index ddacdce..95f26e9 100644 --- a/src/main/java/com/createcivilization/capitol/server/events/NameFormatEvents.java +++ b/src/main/java/com/createcivilization/capitol/server/events/NameFormatEvents.java @@ -6,23 +6,39 @@ import com.createcivilization.capitol.common.modules.database.CapitolDatabase; import com.createcivilization.capitol.common.modules.database.Database; import net.minecraft.ChatFormatting; +import net.minecraft.network.chat.ClickEvent; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.TextColor; import net.neoforged.api.distmarker.Dist; import net.neoforged.bus.api.SubscribeEvent; import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.neoforge.event.ServerChatEvent; import net.neoforged.neoforge.event.entity.player.PlayerEvent; @EventBusSubscriber(modid = Capitol.MOD_ID, value = Dist.DEDICATED_SERVER) public class NameFormatEvents { @SubscribeEvent - public static void onNameFormat(PlayerEvent.NameFormat event) { - Team team = DatabaseManager.database.getTeam(event.getEntity().getUUID()); + public static void onNameFormat(PlayerEvent.NameFormat event) { // Mainly for chat messages + Team team = DatabaseManager.database.getPlayerTeam(event.getEntity().getUUID()); if (team == null) { return; } - Component prevName = event.getDisplayname(); - Component tag = Component.literal(team.getTag()).withStyle(style -> style.withColor(TextColor.fromRgb(team.getColor().getRGB()))); - event.setDisplayname(Component.literal("[").append(tag).append("] ").append(prevName)); + Component prevName = event.getDisplayname(); // the spelling mistake in getDisplayname instead of getDisplayName lmao + Component tag = getTag(team); + event.setDisplayname(Component.literal("").append(tag).append(" ").append(prevName)); + } + + @SubscribeEvent + public static void onTabListNameFormat(PlayerEvent.TabListNameFormat event) { // Only for tab list + Team team = DatabaseManager.database.getPlayerTeam(event.getEntity().getUUID()); + if (team == null) { + return; + } + Component tag = getTag(team); + event.setDisplayName(Component.literal("[").append(tag).append("] ").append(event.getEntity().getName())); + } + + public static Component getTag(Team team) { + return Component.literal(team.getTag()).withStyle(style -> style.withColor(TextColor.fromRgb(team.getColor().getRGB()))); } } From b6f14f81ee0a2c70ca24a6fc0b32a8a32d58a277 Mon Sep 17 00:00:00 2001 From: Kotos Date: Mon, 11 May 2026 14:11:58 +0100 Subject: [PATCH 14/23] Added config for toggling tags --- .../capitol/common/config/CapitolConfig.java | 17 +++++++++++++++++ .../capitol/server/events/NameFormatEvents.java | 11 +++++++++++ 2 files changed, 28 insertions(+) diff --git a/src/main/java/com/createcivilization/capitol/common/config/CapitolConfig.java b/src/main/java/com/createcivilization/capitol/common/config/CapitolConfig.java index cf465a3..bb092df 100644 --- a/src/main/java/com/createcivilization/capitol/common/config/CapitolConfig.java +++ b/src/main/java/com/createcivilization/capitol/common/config/CapitolConfig.java @@ -48,6 +48,11 @@ public class CapitolConfig { public static final ModConfigSpec.ConfigValue> BLOCK_PLACE_EXCEPTIONS; public static final ModConfigSpec.ConfigValue> ITEM_USE_EXCEPTIONS; + // Role Exceptions + + public static final ModConfigSpec.BooleanValue DISPLAY_TAGS_IN_CHAT; + public static final ModConfigSpec.BooleanValue DISPLAY_TAGS_IN_TAB_LIST; + public enum ListType { ONLY, ALL_BUT @@ -169,6 +174,18 @@ public enum ListType { builder.pop(); + builder.comment("Role settings").push("roles"); + + DISPLAY_TAGS_IN_CHAT = builder + .comment("Whether chat messages with have the players nation tag attached.") + .define("displayTagsInChat", true); + + DISPLAY_TAGS_IN_TAB_LIST = builder + .comment("Whether the tab list will have the players nation tag attached.") + .define("displayTagsInTabList", true); + + builder.pop(); + SPEC = builder.build(); } } diff --git a/src/main/java/com/createcivilization/capitol/server/events/NameFormatEvents.java b/src/main/java/com/createcivilization/capitol/server/events/NameFormatEvents.java index 95f26e9..a2c8156 100644 --- a/src/main/java/com/createcivilization/capitol/server/events/NameFormatEvents.java +++ b/src/main/java/com/createcivilization/capitol/server/events/NameFormatEvents.java @@ -1,6 +1,7 @@ package com.createcivilization.capitol.server.events; import com.createcivilization.capitol.Capitol; +import com.createcivilization.capitol.common.config.CapitolConfig; import com.createcivilization.capitol.common.data.Team; import com.createcivilization.capitol.common.managers.DatabaseManager; import com.createcivilization.capitol.common.modules.database.CapitolDatabase; @@ -19,10 +20,15 @@ public class NameFormatEvents { @SubscribeEvent public static void onNameFormat(PlayerEvent.NameFormat event) { // Mainly for chat messages + if (!CapitolConfig.DISPLAY_TAGS_IN_CHAT.get()) { + return; + } + Team team = DatabaseManager.database.getPlayerTeam(event.getEntity().getUUID()); if (team == null) { return; } + Component prevName = event.getDisplayname(); // the spelling mistake in getDisplayname instead of getDisplayName lmao Component tag = getTag(team); event.setDisplayname(Component.literal("").append(tag).append(" ").append(prevName)); @@ -30,10 +36,15 @@ public static void onNameFormat(PlayerEvent.NameFormat event) { // Mainly for ch @SubscribeEvent public static void onTabListNameFormat(PlayerEvent.TabListNameFormat event) { // Only for tab list + if (!CapitolConfig.DISPLAY_TAGS_IN_TAB_LIST.get()) { + return; + } + Team team = DatabaseManager.database.getPlayerTeam(event.getEntity().getUUID()); if (team == null) { return; } + Component tag = getTag(team); event.setDisplayName(Component.literal("[").append(tag).append("] ").append(event.getEntity().getName())); } From cf37900ffc72c98aa32fa9e9cc754bfc6cc1ce09 Mon Sep 17 00:00:00 2001 From: Kotos Date: Mon, 11 May 2026 22:37:16 +0100 Subject: [PATCH 15/23] Added role-based coloring Added auto-refreshing for player names Modified the look of tags increased reliability when setting colors Added translations for setting the roles color --- .../capitol/common/data/TeamRole.java | 11 +- .../common/managers/DatabaseManager.java | 1 + .../modules/database/CapitolDatabase.java | 31 ++- .../server/commands/invite/InviteCommand.java | 5 +- .../server/commands/team/TeamCommand.java | 4 + .../server/commands/team/TeamRoleCommand.java | 190 +++++++++++++----- .../server/events/NameFormatEvents.java | 17 +- .../resources/assets/capitol/lang/en_us.json | 3 + 8 files changed, 198 insertions(+), 64 deletions(-) diff --git a/src/main/java/com/createcivilization/capitol/common/data/TeamRole.java b/src/main/java/com/createcivilization/capitol/common/data/TeamRole.java index 3b21122..fe91971 100644 --- a/src/main/java/com/createcivilization/capitol/common/data/TeamRole.java +++ b/src/main/java/com/createcivilization/capitol/common/data/TeamRole.java @@ -1,10 +1,11 @@ package com.createcivilization.capitol.common.data; +import java.awt.*; import java.sql.ResultSet; import java.sql.SQLException; import java.util.UUID; -public record TeamRole(int id, UUID teamId, String name, long permissions) { +public record TeamRole(int id, UUID teamId, String name, long permissions, Color color) { public static final String OWNER_ROLE_NAME = "owner"; public static final String DEFAULT_ROLE_NAME = "default"; @@ -22,11 +23,17 @@ public boolean hasPermission(Permission perm) { } public static TeamRole fromResultSet(ResultSet rs) throws SQLException { + Color color = null; + if (rs.getInt("color") != -1) { + color = new Color(rs.getInt("color")); + } + return new TeamRole( rs.getInt("id"), UUID.fromString(rs.getString("team_id")), rs.getString("name"), - rs.getLong("permissions") + rs.getLong("permissions"), + color ); } diff --git a/src/main/java/com/createcivilization/capitol/common/managers/DatabaseManager.java b/src/main/java/com/createcivilization/capitol/common/managers/DatabaseManager.java index 66eceb0..95d7cfb 100644 --- a/src/main/java/com/createcivilization/capitol/common/managers/DatabaseManager.java +++ b/src/main/java/com/createcivilization/capitol/common/managers/DatabaseManager.java @@ -67,6 +67,7 @@ private static void createTables() throws SQLException { "team_id TEXT NOT NULL," + "name TEXT NOT NULL," + "permissions INTEGER NOT NULL DEFAULT 0," + + "color INTEGER NOT NULL DEFAULT -1,"+ "UNIQUE (team_id, name)," + "FOREIGN KEY (team_id) REFERENCES teams (id) ON DELETE CASCADE)" ); diff --git a/src/main/java/com/createcivilization/capitol/common/modules/database/CapitolDatabase.java b/src/main/java/com/createcivilization/capitol/common/modules/database/CapitolDatabase.java index 0c52f20..e3421c0 100644 --- a/src/main/java/com/createcivilization/capitol/common/modules/database/CapitolDatabase.java +++ b/src/main/java/com/createcivilization/capitol/common/modules/database/CapitolDatabase.java @@ -8,9 +8,11 @@ import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.Level; +import java.awt.*; import java.sql.*; import java.time.Instant; import java.util.*; +import java.util.List; import java.util.concurrent.ConcurrentHashMap; public class CapitolDatabase extends Database { @@ -78,19 +80,31 @@ public void setTeamPermissions(Team team, long permissions) { * @param team the team this role belongs to * @param name the role name (e.g. "owner", "default") * @param permissions the bitfield of {@link Permission} flags + * @param color the color this role will override to for nation tags */ - public void addRole(Team team, String name, long permissions) { + public void addRole(Team team, String name, long permissions, Color color) { try (PreparedStatement ps = getConnection().prepareStatement( - "INSERT INTO team_roles (team_id, name, permissions) VALUES (?, ?, ?)")) { + "INSERT INTO team_roles (team_id, name, permissions, color) VALUES (?, ?, ?, ?)")) { ps.setString(1, team.getId().toString()); ps.setString(2, name); ps.setLong(3, permissions); + ps.setInt(4, color == null ? -1 : color.getRGB()); // -1 if the role has no associated color ps.execute(); } catch (SQLException e) { Capitol.LOGGER.error("Error while adding role to database.", e); throw new RuntimeException(e); } } + /** + * Inserts a new role into the {@code team_roles} table. + * + * @param team the team this role belongs to + * @param name the role name (e.g. "owner", "default") + * @param permissions the bitfield of {@link Permission} flags + */ + public void addRole(Team team, String name, long permissions) { + addRole(team, name, permissions, null); + } /** * Retrieves a role by its auto-incremented database ID. @@ -200,6 +214,19 @@ public void updateRoleName(Team team, String roleName, String newName) { } } + public void updateRoleColor(Team team, String roleName, Color color) { + try (PreparedStatement ps = getConnection().prepareStatement( + "UPDATE team_roles SET color = ? WHERE team_id = ? AND name = ?")) { + ps.setInt(1, color == null ? -1 : color.getRGB()); + ps.setString(2, team.getId().toString()); + ps.setString(3, roleName); + ps.execute(); + } catch (SQLException e) { + Capitol.LOGGER.error("Error while updating role color in database.", e); + throw new RuntimeException(e); + } + } + /** * Deletes a role by team and role name. * diff --git a/src/main/java/com/createcivilization/capitol/server/commands/invite/InviteCommand.java b/src/main/java/com/createcivilization/capitol/server/commands/invite/InviteCommand.java index 2c4fad9..43f9ff9 100644 --- a/src/main/java/com/createcivilization/capitol/server/commands/invite/InviteCommand.java +++ b/src/main/java/com/createcivilization/capitol/server/commands/invite/InviteCommand.java @@ -38,7 +38,7 @@ public static LiteralArgumentBuilder register() { } private static int acceptInvite(CommandContext context) { - Player player = context.getSource().getPlayer(); + ServerPlayer player = context.getSource().getPlayer(); if (player == null) return 0; Team team = resolveInvitedTeam(context, player); @@ -48,6 +48,9 @@ private static int acceptInvite(CommandContext context) { DatabaseManager.database.addPlayerToTeam(player, team, role); InviteHandler.clearInvites(player); + player.refreshDisplayName(); + player.refreshTabListName(); // needs to be a ServerPlayer for this. + MutableComponent joinMsg = Component.translatable("commands.capitol.invites.join.announcement", Component.literal(player.getName().getString()).withStyle(ChatFormatting.WHITE), Component.literal(team.getName()).withStyle(ChatFormatting.GOLD)) diff --git a/src/main/java/com/createcivilization/capitol/server/commands/team/TeamCommand.java b/src/main/java/com/createcivilization/capitol/server/commands/team/TeamCommand.java index 9dcd61f..8e9f516 100644 --- a/src/main/java/com/createcivilization/capitol/server/commands/team/TeamCommand.java +++ b/src/main/java/com/createcivilization/capitol/server/commands/team/TeamCommand.java @@ -339,4 +339,8 @@ private static int confirmDisband(CommandContext context) { context.getSource().sendSuccess(() -> Component.translatable("commands.capitol.team.disband.success").withStyle(ChatFormatting.GREEN), true); return 1; } + + public static Map getNamedColors() { + return NAMED_COLORS; + } } \ No newline at end of file diff --git a/src/main/java/com/createcivilization/capitol/server/commands/team/TeamRoleCommand.java b/src/main/java/com/createcivilization/capitol/server/commands/team/TeamRoleCommand.java index 7f26002..d8e2da5 100644 --- a/src/main/java/com/createcivilization/capitol/server/commands/team/TeamRoleCommand.java +++ b/src/main/java/com/createcivilization/capitol/server/commands/team/TeamRoleCommand.java @@ -17,6 +17,7 @@ import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.players.GameProfileCache; +import java.awt.*; import java.util.List; import java.util.Objects; import java.util.Optional; @@ -30,53 +31,117 @@ static LiteralArgumentBuilder register() { .executes(TeamRoleCommand::createRole))) .then(Commands.literal("edit") .then(Commands.argument("role_name", StringArgumentType.word()) - .suggests((context, builder) -> { - CapitolDatabase database = DatabaseManager.database; - Team team = database.getPlayerTeam(context.getSource().getPlayer()); - if (team == null) { - builder.suggest("YOU ARE NOT IN A TEAM"); + .suggests((context, builder) -> { + CapitolDatabase database = DatabaseManager.database; + Team team = database.getPlayerTeam(context.getSource().getPlayer()); + if (team == null) { + builder.suggest("YOU ARE NOT IN A TEAM"); + return builder.buildFuture(); + } + List roles = database.getTeamRoles(team); + for (TeamRole role : roles) { + builder.suggest(role.name()); + } return builder.buildFuture(); - } - List roles = database.getTeamRoles(team); - for (TeamRole role : roles) { - builder.suggest(role.name()); - } - return builder.buildFuture(); - }) - .then(Commands.literal("assign") - .then(Commands.argument("player", StringArgumentType.string()) - .suggests((context, builder) -> { - CapitolDatabase database = DatabaseManager.database; - Team team = database.getPlayerTeam(context.getSource().getPlayer()); - if (team == null) { - builder.suggest("YOU ARE NOT IN A TEAM"); + }) + .then(Commands.literal("assign") + .then(Commands.argument("player", StringArgumentType.string()) + .suggests((context, builder) -> { + CapitolDatabase database = DatabaseManager.database; + Team team = database.getPlayerTeam(context.getSource().getPlayer()); + if (team == null) { + builder.suggest("YOU ARE NOT IN A TEAM"); + return builder.buildFuture(); + } + List members = database.getTeamMembers(team); + GameProfileCache profileCache = context.getSource().getServer().getProfileCache(); + for (TeamMember member : members) { + profileCache.get(member.playerUUID()).ifPresent( + gameProfile -> builder.suggest(gameProfile.getName()) + ); + } return builder.buildFuture(); - } - List members = database.getTeamMembers(team); - GameProfileCache profileCache = context.getSource().getServer().getProfileCache(); - for (TeamMember member : members) { - profileCache.get(member.playerUUID()).ifPresent( - gameProfile -> builder.suggest(gameProfile.getName()) - ); - } - return builder.buildFuture(); - }) - .executes(TeamRoleCommand::assignRole))) - .then(Commands.literal("permission") - .then(Commands.argument("permission_value", StringArgumentType.word()) - .suggests((context, builder) -> { - for (Permission perm : Permission.values()) { - builder.suggest(perm.name().toLowerCase()); - } - return builder.buildFuture(); - }) - .executes(TeamRoleCommand::editRolePerms))) + }) + .executes(TeamRoleCommand::assignRole))) + .then(Commands.literal("permission") + .then(Commands.argument("permission_value", StringArgumentType.word()) + .suggests((context, builder) -> { + for (Permission perm : Permission.values()) { + builder.suggest(perm.name().toLowerCase()); + } + return builder.buildFuture(); + }) + .executes(TeamRoleCommand::editRolePerms))) .then(Commands.literal("list").executes(TeamRoleCommand::viewRolePermList)) - .then(Commands.literal("name") - .then(Commands.argument("new_name", StringArgumentType.string()) - .executes(TeamRoleCommand::editRoleName))) - .then(Commands.literal("remove") - .executes(TeamRoleCommand::removeRole)))); + .then(Commands.literal("name") + .then(Commands.argument("new_name", StringArgumentType.string()) + .executes(TeamRoleCommand::editRoleName))) + .then(Commands.literal("remove") + .executes(TeamRoleCommand::removeRole)) + .then(Commands.literal("color") + .then(Commands.argument("new_color", StringArgumentType.string()) + .suggests((context, builder) -> { + TeamCommand.getNamedColors().keySet().forEach(builder::suggest); + builder.suggest("none"); + return builder.buildFuture(); + }) + .executes(TeamRoleCommand::setColor))) + )); + + } + + private static int setColor(CommandContext context) { + CapitolDatabase database = DatabaseManager.database; + var player = context.getSource().getPlayer(); + if (player == null) { + return failCommand(context, "commands.capitol.command_source_was_console_error"); + } + + Team team = database.getPlayerTeam(player); + if (team == null) { + return failCommand(context, "commands.capitol.not_in_team_error"); + } + + if (!Permission.MANAGE_ROLES.hasPermission(database.getPlayerPermission(player, team))) { + return failCommand(context, "commands.capitol.team.role.no_manage_permission"); + } + String roleName = StringArgumentType.getString(context, "role_name"); + + TeamRole role = database.getRoleByName(team, roleName); + + if (role == null) { + return failCommand(context, "commands.capitol.team.role.color.failure", roleName, team.getName()); + } + + if (StringArgumentType.getString(context, "new_color").equalsIgnoreCase("none")) { + database.updateRoleColor(team, roleName, null); + + context.getSource().sendSuccess(() -> Component.translatable("commands.capitol.team.role.color.clear.success", + Component.literal(roleName).withStyle(ChatFormatting.AQUA)), true); + } else { + String hex = TeamCommand.getNamedColors().getOrDefault( + StringArgumentType.getString(context, "new_color").toLowerCase(), + StringArgumentType.getString(context, "new_color") + ).replace("#", ""); + Color color = new Color((int) Long.parseLong(hex, 16), true); + + database.updateRoleColor(team, roleName, color); + + context.getSource().sendSuccess(() -> Component.translatable("commands.capitol.team.role.color.success", + Component.literal(roleName).withStyle(ChatFormatting.AQUA), + Component.literal(hex).withStyle(style -> style.withColor(TextColor.fromRgb(color.getRGB()))) + .withStyle(ChatFormatting.GRAY)), true); + } + + for (TeamMember member : database.getTeamMembers(team)) { + ServerPlayer online = context.getSource().getServer().getPlayerList().getPlayer(member.playerUUID()); + if (online != null) { + online.refreshDisplayName(); + online.refreshTabListName(); + } + } + + return 1; } private static int createRole(CommandContext context) { @@ -98,8 +163,8 @@ private static int createRole(CommandContext context) { database.addRole(team, roleName, 0); context.getSource().sendSuccess(() -> Component.translatable("commands.capitol.team.role.create.success", - Component.literal(roleName).withStyle(ChatFormatting.AQUA), - Component.literal(team.getName()).withStyle(ChatFormatting.GOLD)) + Component.literal(roleName).withStyle(ChatFormatting.AQUA), + Component.literal(team.getName()).withStyle(ChatFormatting.GOLD)) .withStyle(ChatFormatting.GRAY), true); return 1; } @@ -137,8 +202,16 @@ private static int removeRole(CommandContext context) { database.deleteRole(team, roleName); + for (TeamMember member : database.getTeamMembers(team)) { // Sweeping update, applies to all players in a team currently online. + ServerPlayer online = context.getSource().getServer().getPlayerList().getPlayer(member.playerUUID()); + if (online != null) { + online.refreshDisplayName(); + online.refreshTabListName(); + } + } + context.getSource().sendSuccess(() -> Component.translatable("commands.capitol.team.role.remove.success", - Component.literal(roleName).withStyle(ChatFormatting.AQUA)) + Component.literal(roleName).withStyle(ChatFormatting.AQUA)) .withStyle(ChatFormatting.GRAY), true); return 1; } @@ -187,9 +260,16 @@ private static int assignRole(CommandContext context) { database.updatePlayerRole(gameProfile.getId(), team, role); + ServerPlayer target = context.getSource().getServer().getPlayerList().getPlayer(gameProfile.getId()); // Specifically refreshes the targeted player + if (target != null) { + target.refreshTabListName(); + target.refreshDisplayName(); + } + + context.getSource().sendSuccess(() -> Component.translatable("commands.capitol.team.role.assign.success", - Component.literal(gameProfile.getName()).withStyle(ChatFormatting.WHITE), - Component.literal(roleName).withStyle(ChatFormatting.AQUA)) + Component.literal(gameProfile.getName()).withStyle(ChatFormatting.WHITE), + Component.literal(roleName).withStyle(ChatFormatting.AQUA)) .withStyle(ChatFormatting.GRAY), true); return 1; } @@ -230,8 +310,8 @@ private static int editRoleName(CommandContext context) { database.updateRoleName(team, roleName, newRoleName); context.getSource().sendSuccess(() -> Component.translatable("commands.capitol.team.role.name.success", - Component.literal(roleName).withStyle(ChatFormatting.AQUA), - Component.literal(newRoleName).withStyle(ChatFormatting.AQUA)) + Component.literal(roleName).withStyle(ChatFormatting.AQUA), + Component.literal(newRoleName).withStyle(ChatFormatting.AQUA)) .withStyle(ChatFormatting.GRAY), true); return 1; } @@ -275,10 +355,10 @@ private static int editRolePerms(CommandContext context) { database.updateRolePermissions(team, roleName, rolePerms); context.getSource().sendSuccess(() -> Component.translatable("commands.capitol.permission_toggle", - Component.literal(permissionName.toLowerCase()).withStyle(ChatFormatting.AQUA), - Component.literal(roleName).withStyle(ChatFormatting.GOLD), - Component.literal(String.valueOf(oldState)).withStyle(oldState ? ChatFormatting.GREEN : ChatFormatting.RED), - Component.literal(String.valueOf(newState)).withStyle(newState ? ChatFormatting.GREEN : ChatFormatting.RED)) + Component.literal(permissionName.toLowerCase()).withStyle(ChatFormatting.AQUA), + Component.literal(roleName).withStyle(ChatFormatting.GOLD), + Component.literal(String.valueOf(oldState)).withStyle(oldState ? ChatFormatting.GREEN : ChatFormatting.RED), + Component.literal(String.valueOf(newState)).withStyle(newState ? ChatFormatting.GREEN : ChatFormatting.RED)) .withStyle(ChatFormatting.GRAY), true); return 1; } diff --git a/src/main/java/com/createcivilization/capitol/server/events/NameFormatEvents.java b/src/main/java/com/createcivilization/capitol/server/events/NameFormatEvents.java index a2c8156..3994848 100644 --- a/src/main/java/com/createcivilization/capitol/server/events/NameFormatEvents.java +++ b/src/main/java/com/createcivilization/capitol/server/events/NameFormatEvents.java @@ -3,6 +3,7 @@ import com.createcivilization.capitol.Capitol; import com.createcivilization.capitol.common.config.CapitolConfig; import com.createcivilization.capitol.common.data.Team; +import com.createcivilization.capitol.common.data.TeamRole; import com.createcivilization.capitol.common.managers.DatabaseManager; import com.createcivilization.capitol.common.modules.database.CapitolDatabase; import com.createcivilization.capitol.common.modules.database.Database; @@ -16,6 +17,8 @@ import net.neoforged.neoforge.event.ServerChatEvent; import net.neoforged.neoforge.event.entity.player.PlayerEvent; +import javax.management.relation.Role; + @EventBusSubscriber(modid = Capitol.MOD_ID, value = Dist.DEDICATED_SERVER) public class NameFormatEvents { @SubscribeEvent @@ -28,9 +31,10 @@ public static void onNameFormat(PlayerEvent.NameFormat event) { // Mainly for ch if (team == null) { return; } + TeamRole role = DatabaseManager.database.getPlayerRole(event.getEntity(), team); Component prevName = event.getDisplayname(); // the spelling mistake in getDisplayname instead of getDisplayName lmao - Component tag = getTag(team); + Component tag = getTag(team, role); event.setDisplayname(Component.literal("").append(tag).append(" ").append(prevName)); } @@ -44,12 +48,17 @@ public static void onTabListNameFormat(PlayerEvent.TabListNameFormat event) { // if (team == null) { return; } + TeamRole role = DatabaseManager.database.getPlayerRole(event.getEntity(), team); - Component tag = getTag(team); + Component tag = getTag(team, role); event.setDisplayName(Component.literal("[").append(tag).append("] ").append(event.getEntity().getName())); } - public static Component getTag(Team team) { - return Component.literal(team.getTag()).withStyle(style -> style.withColor(TextColor.fromRgb(team.getColor().getRGB()))); + public static Component getTag(Team team, TeamRole role) { + if (role.color() == null) { + return Component.literal(team.getTag()).withStyle(style -> style.withColor(TextColor.fromRgb(team.getColor().getRGB()))); + } else { + return Component.literal(team.getTag()).withStyle(style -> style.withColor(TextColor.fromRgb(role.color().getRGB()))); + } } } diff --git a/src/main/resources/assets/capitol/lang/en_us.json b/src/main/resources/assets/capitol/lang/en_us.json index 981f7d9..a1584c2 100644 --- a/src/main/resources/assets/capitol/lang/en_us.json +++ b/src/main/resources/assets/capitol/lang/en_us.json @@ -73,6 +73,9 @@ "commands.capitol.team.role.edit.no_default": "You cannot edit default role name.", "commands.capitol.team.role.name.success": "Renamed role %s → %s", + "commands.capitol.team.role.color.success": "Set role %s's color to %s", + "commands.capitol.team.role.color.clear.success": "Cleared role %s's color", + "commands.capitol.team.role.permission_list.role": "Role: ", "commands.capitol.team.role.permission_list.hover": "Click to swap permissions", From 27acf752a952ddaf0d20fa2bd6fbac6218b2c0b0 Mon Sep 17 00:00:00 2001 From: Kotos Date: Mon, 11 May 2026 22:38:20 +0100 Subject: [PATCH 16/23] Cleaning up --- .../capitol/server/events/NameFormatEvents.java | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/main/java/com/createcivilization/capitol/server/events/NameFormatEvents.java b/src/main/java/com/createcivilization/capitol/server/events/NameFormatEvents.java index 3994848..a4bd125 100644 --- a/src/main/java/com/createcivilization/capitol/server/events/NameFormatEvents.java +++ b/src/main/java/com/createcivilization/capitol/server/events/NameFormatEvents.java @@ -5,20 +5,13 @@ import com.createcivilization.capitol.common.data.Team; import com.createcivilization.capitol.common.data.TeamRole; import com.createcivilization.capitol.common.managers.DatabaseManager; -import com.createcivilization.capitol.common.modules.database.CapitolDatabase; -import com.createcivilization.capitol.common.modules.database.Database; -import net.minecraft.ChatFormatting; -import net.minecraft.network.chat.ClickEvent; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.TextColor; import net.neoforged.api.distmarker.Dist; import net.neoforged.bus.api.SubscribeEvent; import net.neoforged.fml.common.EventBusSubscriber; -import net.neoforged.neoforge.event.ServerChatEvent; import net.neoforged.neoforge.event.entity.player.PlayerEvent; -import javax.management.relation.Role; - @EventBusSubscriber(modid = Capitol.MOD_ID, value = Dist.DEDICATED_SERVER) public class NameFormatEvents { @SubscribeEvent From 375fce87ed7d980476a8f339b4993eaf38a203bf Mon Sep 17 00:00:00 2001 From: Kotos Date: Mon, 11 May 2026 22:48:59 +0100 Subject: [PATCH 17/23] Added a max length to team tags (configurable) --- .../capitol/common/config/CapitolConfig.java | 13 ++++++++++++- .../common/modules/database/CapitolDatabase.java | 2 +- .../capitol/server/commands/team/TeamCommand.java | 6 ++++++ src/main/resources/assets/capitol/lang/en_us.json | 1 + 4 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/createcivilization/capitol/common/config/CapitolConfig.java b/src/main/java/com/createcivilization/capitol/common/config/CapitolConfig.java index bb092df..314182d 100644 --- a/src/main/java/com/createcivilization/capitol/common/config/CapitolConfig.java +++ b/src/main/java/com/createcivilization/capitol/common/config/CapitolConfig.java @@ -48,11 +48,14 @@ public class CapitolConfig { public static final ModConfigSpec.ConfigValue> BLOCK_PLACE_EXCEPTIONS; public static final ModConfigSpec.ConfigValue> ITEM_USE_EXCEPTIONS; - // Role Exceptions + // Roles public static final ModConfigSpec.BooleanValue DISPLAY_TAGS_IN_CHAT; public static final ModConfigSpec.BooleanValue DISPLAY_TAGS_IN_TAB_LIST; + // Teams + public static final ModConfigSpec.IntValue TEAM_TAG_MAX_LENGTH; + public enum ListType { ONLY, ALL_BUT @@ -186,6 +189,14 @@ public enum ListType { builder.pop(); + builder.comment("Role settings").push("team"); + + TEAM_TAG_MAX_LENGTH = builder + .comment("Max length for a team to have as a tag.") + .defineInRange("teamTagMaxLength", 3, 0, 16); + + builder.pop(); + SPEC = builder.build(); } } diff --git a/src/main/java/com/createcivilization/capitol/common/modules/database/CapitolDatabase.java b/src/main/java/com/createcivilization/capitol/common/modules/database/CapitolDatabase.java index e3421c0..21705f8 100644 --- a/src/main/java/com/createcivilization/capitol/common/modules/database/CapitolDatabase.java +++ b/src/main/java/com/createcivilization/capitol/common/modules/database/CapitolDatabase.java @@ -335,7 +335,7 @@ public void addTeam(Team team) { throw new RuntimeException(e); } - addRole(team, TeamRole.OWNER_ROLE_NAME, TeamRole.ownerPermissions()); + addRole(team, TeamRole.OWNER_ROLE_NAME, TeamRole.ownerPermissions(), new Color(0x800080)); addRole(team, TeamRole.DEFAULT_ROLE_NAME, TeamRole.defaultPermissions()); } diff --git a/src/main/java/com/createcivilization/capitol/server/commands/team/TeamCommand.java b/src/main/java/com/createcivilization/capitol/server/commands/team/TeamCommand.java index 8e9f516..b3f7de3 100644 --- a/src/main/java/com/createcivilization/capitol/server/commands/team/TeamCommand.java +++ b/src/main/java/com/createcivilization/capitol/server/commands/team/TeamCommand.java @@ -1,5 +1,6 @@ package com.createcivilization.capitol.server.commands.team; +import com.createcivilization.capitol.common.config.CapitolConfig; import com.createcivilization.capitol.common.data.*; import com.createcivilization.capitol.common.managers.DatabaseManager; import com.createcivilization.capitol.common.modules.database.CapitolDatabase; @@ -198,6 +199,11 @@ private static int createTeam(CommandContext context) { ).replace("#", ""); String tag = StringArgumentType.getString(context, "tag"); + if (tag.length() > CapitolConfig.TEAM_TAG_MAX_LENGTH.get()) { + context.getSource().sendFailure(Component.translatable("commands.capitol.team.create.tag_too_long", CapitolConfig.TEAM_TAG_MAX_LENGTH.get()).withStyle(ChatFormatting.RED)); + return 0; + } + String description; try { description = StringArgumentType.getString(context, "description"); diff --git a/src/main/resources/assets/capitol/lang/en_us.json b/src/main/resources/assets/capitol/lang/en_us.json index a1584c2..8063940 100644 --- a/src/main/resources/assets/capitol/lang/en_us.json +++ b/src/main/resources/assets/capitol/lang/en_us.json @@ -39,6 +39,7 @@ "commands.capitol.team.create.already_in_team": "You are already in a team, please leave before creating a new one", "commands.capitol.team.create.name_exists": "A team with that name already exists.", + "commands.capitol.team.create.tag_too_long": "Tag is too long, max length of %d", "commands.capitol.team.create.invalid_color": "Invalid hex color: #%s", "commands.capitol.team.create.success": "Team %s created!", From 41f444b7e065bc27f3056cb682378bbb281c4993 Mon Sep 17 00:00:00 2001 From: Kotos Date: Tue, 12 May 2026 00:43:54 +0100 Subject: [PATCH 18/23] Import fix --- .../capitol/server/commands/team/TeamRoleCommand.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main/java/com/createcivilization/capitol/server/commands/team/TeamRoleCommand.java b/src/main/java/com/createcivilization/capitol/server/commands/team/TeamRoleCommand.java index d8e2da5..178879b 100644 --- a/src/main/java/com/createcivilization/capitol/server/commands/team/TeamRoleCommand.java +++ b/src/main/java/com/createcivilization/capitol/server/commands/team/TeamRoleCommand.java @@ -10,10 +10,8 @@ import net.minecraft.ChatFormatting; import net.minecraft.commands.CommandSourceStack; import net.minecraft.commands.Commands; -import net.minecraft.network.chat.ClickEvent; +import net.minecraft.network.chat.*; import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.HoverEvent; -import net.minecraft.network.chat.MutableComponent; import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.players.GameProfileCache; From 568753c4dea7b90d523b4c4eff13f9ed5edb36f9 Mon Sep 17 00:00:00 2001 From: Kotos Date: Tue, 12 May 2026 11:58:08 +0100 Subject: [PATCH 19/23] Fixed downcast --- .../capitol/server/commands/team/TeamRoleCommand.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/createcivilization/capitol/server/commands/team/TeamRoleCommand.java b/src/main/java/com/createcivilization/capitol/server/commands/team/TeamRoleCommand.java index 178879b..5801719 100644 --- a/src/main/java/com/createcivilization/capitol/server/commands/team/TeamRoleCommand.java +++ b/src/main/java/com/createcivilization/capitol/server/commands/team/TeamRoleCommand.java @@ -121,7 +121,7 @@ private static int setColor(CommandContext context) { StringArgumentType.getString(context, "new_color").toLowerCase(), StringArgumentType.getString(context, "new_color") ).replace("#", ""); - Color color = new Color((int) Long.parseLong(hex, 16), true); + Color color = new Color(Integer.parseInt(hex, 16), true); database.updateRoleColor(team, roleName, color); From 7b7a434aa20b321643191e70b885fc3c017a1672 Mon Sep 17 00:00:00 2001 From: Kotos Date: Tue, 12 May 2026 11:59:38 +0100 Subject: [PATCH 20/23] Changed "nation" to "team" --- .../capitol/common/config/CapitolConfig.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/createcivilization/capitol/common/config/CapitolConfig.java b/src/main/java/com/createcivilization/capitol/common/config/CapitolConfig.java index 314182d..e04639c 100644 --- a/src/main/java/com/createcivilization/capitol/common/config/CapitolConfig.java +++ b/src/main/java/com/createcivilization/capitol/common/config/CapitolConfig.java @@ -180,11 +180,11 @@ public enum ListType { builder.comment("Role settings").push("roles"); DISPLAY_TAGS_IN_CHAT = builder - .comment("Whether chat messages with have the players nation tag attached.") + .comment("Whether chat messages with have the players team tag attached.") .define("displayTagsInChat", true); DISPLAY_TAGS_IN_TAB_LIST = builder - .comment("Whether the tab list will have the players nation tag attached.") + .comment("Whether the tab list will have the players team tag attached.") .define("displayTagsInTabList", true); builder.pop(); From 07e5b3bd8801bddde72f61555c981568fb9386ef Mon Sep 17 00:00:00 2001 From: Kotos Date: Tue, 12 May 2026 12:04:48 +0100 Subject: [PATCH 21/23] Added translations to the command suggestion --- .../capitol/server/commands/team/TeamRoleCommand.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/createcivilization/capitol/server/commands/team/TeamRoleCommand.java b/src/main/java/com/createcivilization/capitol/server/commands/team/TeamRoleCommand.java index 5801719..9f871af 100644 --- a/src/main/java/com/createcivilization/capitol/server/commands/team/TeamRoleCommand.java +++ b/src/main/java/com/createcivilization/capitol/server/commands/team/TeamRoleCommand.java @@ -33,7 +33,7 @@ static LiteralArgumentBuilder register() { CapitolDatabase database = DatabaseManager.database; Team team = database.getPlayerTeam(context.getSource().getPlayer()); if (team == null) { - builder.suggest("YOU ARE NOT IN A TEAM"); + builder.suggest(Component.translatable("commands.capitol.not_in_team_error").toString()); return builder.buildFuture(); } List roles = database.getTeamRoles(team); @@ -48,7 +48,7 @@ static LiteralArgumentBuilder register() { CapitolDatabase database = DatabaseManager.database; Team team = database.getPlayerTeam(context.getSource().getPlayer()); if (team == null) { - builder.suggest("YOU ARE NOT IN A TEAM"); + builder.suggest(Component.translatable("commands.capitol.not_in_team_error").toString()); return builder.buildFuture(); } List members = database.getTeamMembers(team); From 9e76af03be87ca9f6a07252d0a065cacd9f95a5d Mon Sep 17 00:00:00 2001 From: Kotos Date: Tue, 12 May 2026 12:08:49 +0100 Subject: [PATCH 22/23] cleaned up getTag --- .../capitol/server/events/NameFormatEvents.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/createcivilization/capitol/server/events/NameFormatEvents.java b/src/main/java/com/createcivilization/capitol/server/events/NameFormatEvents.java index a4bd125..6677809 100644 --- a/src/main/java/com/createcivilization/capitol/server/events/NameFormatEvents.java +++ b/src/main/java/com/createcivilization/capitol/server/events/NameFormatEvents.java @@ -48,10 +48,14 @@ public static void onTabListNameFormat(PlayerEvent.TabListNameFormat event) { // } public static Component getTag(Team team, TeamRole role) { - if (role.color() == null) { - return Component.literal(team.getTag()).withStyle(style -> style.withColor(TextColor.fromRgb(team.getColor().getRGB()))); + TextColor color; + + if (role.color() != null) { + color = TextColor.fromRgb(role.color().getRGB()); } else { - return Component.literal(team.getTag()).withStyle(style -> style.withColor(TextColor.fromRgb(role.color().getRGB()))); + color = TextColor.fromRgb(team.getColor().getRGB()); } + + return Component.literal(team.getTag()).withStyle(style -> style.withColor(color)); } } From 8c7ed21d192382e0e772f31f93e709048a0dd2c4 Mon Sep 17 00:00:00 2001 From: Kotos Date: Tue, 12 May 2026 12:12:23 +0100 Subject: [PATCH 23/23] Pulled duplicated code into its own function --- .../server/commands/team/TeamRoleCommand.java | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/main/java/com/createcivilization/capitol/server/commands/team/TeamRoleCommand.java b/src/main/java/com/createcivilization/capitol/server/commands/team/TeamRoleCommand.java index 9f871af..805f274 100644 --- a/src/main/java/com/createcivilization/capitol/server/commands/team/TeamRoleCommand.java +++ b/src/main/java/com/createcivilization/capitol/server/commands/team/TeamRoleCommand.java @@ -20,6 +20,8 @@ import java.util.Objects; import java.util.Optional; +import static com.createcivilization.capitol.common.managers.DatabaseManager.database; + class TeamRoleCommand { static LiteralArgumentBuilder register() { @@ -131,13 +133,7 @@ private static int setColor(CommandContext context) { .withStyle(ChatFormatting.GRAY)), true); } - for (TeamMember member : database.getTeamMembers(team)) { - ServerPlayer online = context.getSource().getServer().getPlayerList().getPlayer(member.playerUUID()); - if (online != null) { - online.refreshDisplayName(); - online.refreshTabListName(); - } - } + refreshTeamPlayers(context, team); return 1; } @@ -200,13 +196,7 @@ private static int removeRole(CommandContext context) { database.deleteRole(team, roleName); - for (TeamMember member : database.getTeamMembers(team)) { // Sweeping update, applies to all players in a team currently online. - ServerPlayer online = context.getSource().getServer().getPlayerList().getPlayer(member.playerUUID()); - if (online != null) { - online.refreshDisplayName(); - online.refreshTabListName(); - } - } + refreshTeamPlayers(context, team); context.getSource().sendSuccess(() -> Component.translatable("commands.capitol.team.role.remove.success", Component.literal(roleName).withStyle(ChatFormatting.AQUA)) @@ -404,6 +394,16 @@ private static int viewRolePermList(CommandContext context) return 1; } + public static void refreshTeamPlayers(CommandContext context, Team team) { + for (TeamMember member : database.getTeamMembers(team)) { + ServerPlayer online = context.getSource().getServer().getPlayerList().getPlayer(member.playerUUID()); + if (online != null) { + online.refreshDisplayName(); + online.refreshTabListName(); + } + } + } + static int failCommand(CommandContext context, String key, Object... args) { context.getSource().sendFailure(Component.translatable(key, args).withStyle(ChatFormatting.RED)); return 0;