From 3b694a936c7138acc5eaca3da2ec528c2e8c0894 Mon Sep 17 00:00:00 2001 From: Anhgelus Morhtuuzh Date: Wed, 18 Mar 2026 13:04:34 +0100 Subject: fix(timer): too long task converting into milliseconds instead of ticks --- src/main/java/world/anhgelus/molehunt/game/Game.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src/main') diff --git a/src/main/java/world/anhgelus/molehunt/game/Game.java b/src/main/java/world/anhgelus/molehunt/game/Game.java index 98fe2b8..4f3234c 100644 --- a/src/main/java/world/anhgelus/molehunt/game/Game.java +++ b/src/main/java/world/anhgelus/molehunt/game/Game.java @@ -67,9 +67,9 @@ public class Game { timer.dds_runTask(new TickTask(() -> worldBorder.interpolateSize( Molehunt.CONFIG.getInitialWorldSize(), Molehunt.CONFIG.getFinalWorldSize(), - (long) (Molehunt.CONFIG.getGameDuration() - Molehunt.CONFIG.getBorderShrinkingStartingTimeOffset()) * 60 * 1000, + (Molehunt.CONFIG.getGameDuration() - Molehunt.CONFIG.getBorderShrinkingStartingTimeOffset()) * 60 * 20L, 0L - ), (long) Molehunt.CONFIG.getBorderShrinkingStartingTimeOffset() * 60 * 1000)); + ), Molehunt.CONFIG.getBorderShrinkingStartingTimeOffset() * 60 * 20L)); } final var title = new TitleS2CPacket(Text.translatable("molehunt.game.start.suspense")); @@ -114,8 +114,8 @@ public class Game { }); playerManager.sendToAll(timing); if (remaining == 0) end(); - }, 5 * 1000, 1000)); - }, 4 * 1000)); + }, 5 * 20, 20)); + }, 4 * 20)); } public void stop() { @@ -150,7 +150,7 @@ public class Game { pm.sendToAll(winner); pm.sendToAll(timing); moles.clear(); - }, 4 * 1000)); + }, 4 * 20)); } public Text getRemainingText() { -- cgit v1.2.3 From 7ba39f866a3ab293ce81b5397c1e2975241919cb Mon Sep 17 00:00:00 2001 From: Anhgelus Morhtuuzh Date: Wed, 18 Mar 2026 13:11:45 +0100 Subject: style(): switch to tab and to lf --- .../java/world/anhgelus/molehunt/Molehunt.java | 377 +++++++++--------- .../world/anhgelus/molehunt/config/Config.java | 262 ++++++------- .../anhgelus/molehunt/config/ConfigPayload.java | 24 +- .../anhgelus/molehunt/config/SimpleConfig.java | 422 ++++++++++----------- .../java/world/anhgelus/molehunt/game/Game.java | 344 ++++++++--------- .../world/anhgelus/molehunt/game/GamePayload.java | 20 +- .../molehunt/mixin/NoJoinLeaveMessage.java | 12 +- .../anhgelus/molehunt/mixin/NoMsgCommand.java | 8 +- .../world/anhgelus/molehunt/mixin/NoPortals.java | 10 +- .../anhgelus/molehunt/mixin/WorldTimerAccess.java | 56 +-- .../world/anhgelus/molehunt/timer/TickTask.java | 118 +++--- .../world/anhgelus/molehunt/timer/TimerAccess.java | 96 ++--- .../world/anhgelus/molehunt/utils/TimeUtils.java | 93 ++--- src/main/resources/fabric.mod.json | 69 ++-- src/main/resources/molehunt.mixins.json | 26 +- 15 files changed, 962 insertions(+), 975 deletions(-) (limited to 'src/main') diff --git a/src/main/java/world/anhgelus/molehunt/Molehunt.java b/src/main/java/world/anhgelus/molehunt/Molehunt.java index d5df320..6486700 100644 --- a/src/main/java/world/anhgelus/molehunt/Molehunt.java +++ b/src/main/java/world/anhgelus/molehunt/Molehunt.java @@ -40,199 +40,186 @@ import static net.minecraft.server.command.CommandManager.literal; public class Molehunt implements ModInitializer { - public static final String MOD_ID = "molehunt"; - public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID); - public static Config CONFIG; - - public static final SimpleConfig CONFIG_FILE = Config.configFile(MOD_ID); - - public static final GameRule GAME_DURATION = GameRuleBuilder - .forInteger(CONFIG_FILE.getOrDefault("game_duration", 90)) - .category(GameRuleCategory.MISC) - .buildAndRegister(Identifier.of(MOD_ID, "gameDurationMinutes")); - - public static final GameRule MOLE_PERCENTAGE = GameRuleBuilder - .forInteger(CONFIG_FILE.getOrDefault("mole_percentage", 25)) - .range(0, 100) - .category(GameRuleCategory.MISC) - .buildAndRegister(Identifier.of(MOD_ID, "molePercentage")); - - public static final GameRule MOLE_COUNT = GameRuleBuilder - .forInteger(CONFIG_FILE.getOrDefault("mole_count", -1)) - .category(GameRuleCategory.MISC) - .buildAndRegister(Identifier.of(MOD_ID, "moleCount")); - - public static final GameRule SHOW_NAMETAGS = GameRuleBuilder - .forBoolean(CONFIG_FILE.getOrDefault("show_nametags", false)) - .category(GameRuleCategory.MISC) - .buildAndRegister(Identifier.of(MOD_ID, "showNametags")); - - public static final GameRule SHOW_TAB = GameRuleBuilder - .forBoolean(CONFIG_FILE.getOrDefault("show_tab", false)) - .category(GameRuleCategory.MISC) - .buildAndRegister(Identifier.of(MOD_ID, "showTab")); - - public static final GameRule SHOW_SKINS = GameRuleBuilder - .forBoolean(CONFIG_FILE.getOrDefault("show_skins", false)) - .category(GameRuleCategory.MISC) - .buildAndRegister(Identifier.of(MOD_ID, "showSkins")); - - public static final GameRule INITIAL_WORLD_SIZE = GameRuleBuilder - .forInteger(CONFIG_FILE.getOrDefault("initial_world_size", 600)) - .minValue(0) - .category(GameRuleCategory.MISC) - .buildAndRegister(Identifier.of(MOD_ID, "initialWorldSize")); - - public static final GameRule FINAL_WORLD_SIZE = GameRuleBuilder - .forInteger(CONFIG_FILE.getOrDefault("final_world_size", 100)) - .minValue(0) - .category(GameRuleCategory.MISC) - .buildAndRegister(Identifier.of(MOD_ID, "finalWorldSize")); - - public static final GameRule MOVING_STARTING_TIME_OFFSET = GameRuleBuilder - .forInteger(CONFIG_FILE.getOrDefault("border_moving_starting_time_offset", 30)) - .minValue(0) - .category(GameRuleCategory.MISC) - .buildAndRegister(Identifier.of(MOD_ID, "borderMovingStartingTimeOffsetMinutes")); - - public static final GameRule ENABLE_PORTALS = GameRuleBuilder - .forBoolean(CONFIG_FILE.getOrDefault("enable_portals", false)) - .category(GameRuleCategory.MISC) - .buildAndRegister(Identifier.of(MOD_ID, "enablePortals")); - - public static final GameRule FOOD_ON_START = GameRuleBuilder - .forBoolean(CONFIG_FILE.getOrDefault("food_on_start", true)) - .category(GameRuleCategory.MISC) - .buildAndRegister(Identifier.of(MOD_ID, "foodOnStart")); - - public Game game; - - public static HashMap timerVisibility = new HashMap<>(); - - private static void sendConfigPayload(T v, MinecraftServer server) { - if (CONFIG == null) return; - CONFIG.sendConfigPayload(); - } - - static { - GameRuleEvents.changeCallback(SHOW_NAMETAGS).register(Molehunt::sendConfigPayload); - GameRuleEvents.changeCallback(SHOW_TAB).register(Molehunt::sendConfigPayload); - GameRuleEvents.changeCallback(SHOW_SKINS).register(Molehunt::sendConfigPayload); - } - - @Override - public void onInitialize() { - LOGGER.info("Initializing Molehunt"); - - final var command = literal("molehunt"); - command.then(literal("start") - .requires(CommandManager.requirePermissionLevel(CommandManager.GAMEMASTERS_CHECK)) - .executes(context -> { - game = new Game(context.getSource().getServer()); - game.start(); - return Command.SINGLE_SUCCESS; - })); - command.then(literal("timer").requires(ServerCommandSource::isExecutedByPlayer).then( - literal("show").executes(context -> { - var player = context.getSource().getPlayer(); - assert player != null; - - timerVisibility.put(player.getUuid(), true); - context.getSource().sendFeedback(() -> Text.translatable("commands.molehunt.timer.show"), false); - - if (game == null || !game.started()) { - player.networkHandler.sendPacket(new OverlayMessageS2CPacket( - Text.translatable("commands.molehunt.error.game_not_started").formatted(Formatting.RED) - )); - } else { - player.networkHandler.sendPacket(new OverlayMessageS2CPacket(Text.of(game.getRemainingText()))); - } - - return Command.SINGLE_SUCCESS; - }) - ).then( - literal("hide").executes(context -> { - var player = context.getSource().getPlayer(); - assert player != null; - - timerVisibility.put(player.getUuid(), false); - context.getSource().sendFeedback(() -> Text.translatable("commands.molehunt.timer.hide"), false); - return Command.SINGLE_SUCCESS; - }) - )); - command.then(literal("role") - .requires(ServerCommandSource::isExecutedByPlayer) - .executes(context -> { - if (game == null || !game.started()) { - throw (new SimpleCommandExceptionType(Text.translatable("commands.molehunt.error.game_not_started"))).create(); - } - - final var source = context.getSource(); - final var player = source.getPlayer(); - assert player != null; - - if (game.isMole(player)) { - source.sendFeedback( - () -> Text.translatable("commands.molehunt.role.mole") - .append("\n\n") - .append(Text.translatable("commands.molehunt.role.mole.list", game.getMolesAsString())), - false); - } else if (player.isSpectator()) { - source.sendFeedback( - () -> Text.translatable("commands.molehunt.role.survivor.mole_count", game.getMoles().size()), - false); - } else { - source.sendFeedback( - () -> Text.translatable("commands.molehunt.role.survivor") - .append("\n\n") - .append(Text.translatable("commands.molehunt.role.survivor.mole_count", game.getMoles().size())), - false); - } - - return Command.SINGLE_SUCCESS; - })); - command.then(literal("stop") - .requires(CommandManager.requirePermissionLevel(CommandManager.GAMEMASTERS_CHECK)) - .executes(context -> { - if (game == null || !game.started()) { - throw (new SimpleCommandExceptionType(Text.translatable("commands.molehunt.error.game_not_started"))).create(); - } - - game.stop(); - - return Command.SINGLE_SUCCESS; - })); - - ServerLifecycleEvents.SERVER_STARTED.register(server -> CONFIG = new Config(server)); - - CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> dispatcher.register(command)); - - ServerMessageEvents.ALLOW_CHAT_MESSAGE.register((message, sender, params) -> false); - - ServerLivingEntityEvents.AFTER_DEATH.register((entity, damageSource) -> { - if (!(entity instanceof ServerPlayerEntity) || game == null) return; - if (!game.started()) return; - if (game.wonByMoles()) game.end(); - }); - - ServerPlayerEvents.AFTER_RESPAWN.register((oldPlayer, newPlayer, alive) -> { - if (game == null) return; - if (!game.started()) return; - newPlayer.changeGameMode(GameMode.SPECTATOR); - }); - - ServerPlayConnectionEvents.JOIN.register((handler, sender, server) -> { - ServerPlayNetworking.send( - handler.player, - new ConfigPayload(CONFIG.nametagsEnabled(), CONFIG.skinsEnabled(), CONFIG.tabEnabled()) - ); - ServerPlayNetworking.send( - handler.player, - new GamePayload(game != null && game.started()) - ); - }); - - PayloadTypeRegistry.playS2C().register(ConfigPayload.ID, ConfigPayload.CODEC); - PayloadTypeRegistry.playS2C().register(GamePayload.ID, GamePayload.CODEC); - } + public static final String MOD_ID = "molehunt"; + public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID); + public static final SimpleConfig CONFIG_FILE = Config.configFile(MOD_ID); + public static final GameRule GAME_DURATION = GameRuleBuilder + .forInteger(CONFIG_FILE.getOrDefault("game_duration", 90)) + .category(GameRuleCategory.MISC) + .buildAndRegister(Identifier.of(MOD_ID, "gameDurationMinutes")); + public static final GameRule MOLE_PERCENTAGE = GameRuleBuilder + .forInteger(CONFIG_FILE.getOrDefault("mole_percentage", 25)) + .range(0, 100) + .category(GameRuleCategory.MISC) + .buildAndRegister(Identifier.of(MOD_ID, "molePercentage")); + public static final GameRule MOLE_COUNT = GameRuleBuilder + .forInteger(CONFIG_FILE.getOrDefault("mole_count", -1)) + .category(GameRuleCategory.MISC) + .buildAndRegister(Identifier.of(MOD_ID, "moleCount")); + public static final GameRule SHOW_NAMETAGS = GameRuleBuilder + .forBoolean(CONFIG_FILE.getOrDefault("show_nametags", false)) + .category(GameRuleCategory.MISC) + .buildAndRegister(Identifier.of(MOD_ID, "showNametags")); + public static final GameRule SHOW_TAB = GameRuleBuilder + .forBoolean(CONFIG_FILE.getOrDefault("show_tab", false)) + .category(GameRuleCategory.MISC) + .buildAndRegister(Identifier.of(MOD_ID, "showTab")); + public static final GameRule SHOW_SKINS = GameRuleBuilder + .forBoolean(CONFIG_FILE.getOrDefault("show_skins", false)) + .category(GameRuleCategory.MISC) + .buildAndRegister(Identifier.of(MOD_ID, "showSkins")); + public static final GameRule INITIAL_WORLD_SIZE = GameRuleBuilder + .forInteger(CONFIG_FILE.getOrDefault("initial_world_size", 600)) + .minValue(0) + .category(GameRuleCategory.MISC) + .buildAndRegister(Identifier.of(MOD_ID, "initialWorldSize")); + public static final GameRule FINAL_WORLD_SIZE = GameRuleBuilder + .forInteger(CONFIG_FILE.getOrDefault("final_world_size", 100)) + .minValue(0) + .category(GameRuleCategory.MISC) + .buildAndRegister(Identifier.of(MOD_ID, "finalWorldSize")); + public static final GameRule MOVING_STARTING_TIME_OFFSET = GameRuleBuilder + .forInteger(CONFIG_FILE.getOrDefault("border_moving_starting_time_offset", 30)) + .minValue(0) + .category(GameRuleCategory.MISC) + .buildAndRegister(Identifier.of(MOD_ID, "borderMovingStartingTimeOffsetMinutes")); + public static final GameRule ENABLE_PORTALS = GameRuleBuilder + .forBoolean(CONFIG_FILE.getOrDefault("enable_portals", false)) + .category(GameRuleCategory.MISC) + .buildAndRegister(Identifier.of(MOD_ID, "enablePortals")); + public static final GameRule FOOD_ON_START = GameRuleBuilder + .forBoolean(CONFIG_FILE.getOrDefault("food_on_start", true)) + .category(GameRuleCategory.MISC) + .buildAndRegister(Identifier.of(MOD_ID, "foodOnStart")); + public static Config CONFIG; + public static HashMap timerVisibility = new HashMap<>(); + + static { + GameRuleEvents.changeCallback(SHOW_NAMETAGS).register(Molehunt::sendConfigPayload); + GameRuleEvents.changeCallback(SHOW_TAB).register(Molehunt::sendConfigPayload); + GameRuleEvents.changeCallback(SHOW_SKINS).register(Molehunt::sendConfigPayload); + } + + public Game game; + + private static void sendConfigPayload(T v, MinecraftServer server) { + if (CONFIG == null) return; + CONFIG.sendConfigPayload(); + } + + @Override + public void onInitialize() { + LOGGER.info("Initializing Molehunt"); + + final var command = literal("molehunt"); + command.then(literal("start") + .requires(CommandManager.requirePermissionLevel(CommandManager.GAMEMASTERS_CHECK)) + .executes(context -> { + game = new Game(context.getSource().getServer()); + game.start(); + return Command.SINGLE_SUCCESS; + })); + command.then(literal("timer").requires(ServerCommandSource::isExecutedByPlayer).then( + literal("show").executes(context -> { + var player = context.getSource().getPlayer(); + assert player != null; + + timerVisibility.put(player.getUuid(), true); + context.getSource().sendFeedback(() -> Text.translatable("commands.molehunt.timer.show"), false); + + if (game == null || !game.started()) { + player.networkHandler.sendPacket(new OverlayMessageS2CPacket( + Text.translatable("commands.molehunt.error.game_not_started").formatted(Formatting.RED) + )); + } else { + player.networkHandler.sendPacket(new OverlayMessageS2CPacket(Text.of(game.getRemainingText()))); + } + + return Command.SINGLE_SUCCESS; + }) + ).then( + literal("hide").executes(context -> { + var player = context.getSource().getPlayer(); + assert player != null; + + timerVisibility.put(player.getUuid(), false); + context.getSource().sendFeedback(() -> Text.translatable("commands.molehunt.timer.hide"), false); + return Command.SINGLE_SUCCESS; + }) + )); + command.then(literal("role") + .requires(ServerCommandSource::isExecutedByPlayer) + .executes(context -> { + if (game == null || !game.started()) { + throw (new SimpleCommandExceptionType(Text.translatable("commands.molehunt.error.game_not_started"))).create(); + } + + final var source = context.getSource(); + final var player = source.getPlayer(); + assert player != null; + + if (game.isMole(player)) { + source.sendFeedback( + () -> Text.translatable("commands.molehunt.role.mole") + .append("\n\n") + .append(Text.translatable("commands.molehunt.role.mole.list", game.getMolesAsString())), + false); + } else if (player.isSpectator()) { + source.sendFeedback( + () -> Text.translatable("commands.molehunt.role.survivor.mole_count", game.getMoles().size()), + false); + } else { + source.sendFeedback( + () -> Text.translatable("commands.molehunt.role.survivor") + .append("\n\n") + .append(Text.translatable("commands.molehunt.role.survivor.mole_count", game.getMoles().size())), + false); + } + + return Command.SINGLE_SUCCESS; + })); + command.then(literal("stop") + .requires(CommandManager.requirePermissionLevel(CommandManager.GAMEMASTERS_CHECK)) + .executes(context -> { + if (game == null || !game.started()) { + throw (new SimpleCommandExceptionType(Text.translatable("commands.molehunt.error.game_not_started"))).create(); + } + + game.stop(); + + return Command.SINGLE_SUCCESS; + })); + + ServerLifecycleEvents.SERVER_STARTED.register(server -> CONFIG = new Config(server)); + + CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> dispatcher.register(command)); + + ServerMessageEvents.ALLOW_CHAT_MESSAGE.register((message, sender, params) -> false); + + ServerLivingEntityEvents.AFTER_DEATH.register((entity, damageSource) -> { + if (!(entity instanceof ServerPlayerEntity) || game == null) return; + if (!game.started()) return; + if (game.wonByMoles()) game.end(); + }); + + ServerPlayerEvents.AFTER_RESPAWN.register((oldPlayer, newPlayer, alive) -> { + if (game == null) return; + if (!game.started()) return; + newPlayer.changeGameMode(GameMode.SPECTATOR); + }); + + ServerPlayConnectionEvents.JOIN.register((handler, sender, server) -> { + ServerPlayNetworking.send( + handler.player, + new ConfigPayload(CONFIG.nametagsEnabled(), CONFIG.skinsEnabled(), CONFIG.tabEnabled()) + ); + ServerPlayNetworking.send( + handler.player, + new GamePayload(game != null && game.started()) + ); + }); + + PayloadTypeRegistry.playS2C().register(ConfigPayload.ID, ConfigPayload.CODEC); + PayloadTypeRegistry.playS2C().register(GamePayload.ID, GamePayload.CODEC); + } } diff --git a/src/main/java/world/anhgelus/molehunt/config/Config.java b/src/main/java/world/anhgelus/molehunt/config/Config.java index 08c3850..d65b569 100644 --- a/src/main/java/world/anhgelus/molehunt/config/Config.java +++ b/src/main/java/world/anhgelus/molehunt/config/Config.java @@ -6,135 +6,135 @@ import world.anhgelus.molehunt.Molehunt; public class Config { - private final MinecraftServer server; - - public Config(MinecraftServer server) { - this.server = server; - - sendConfigPayload(nametagsEnabled(), skinsEnabled(), tabEnabled()); - } - - public void sendConfigPayload() { - final var payload = new ConfigPayload(nametagsEnabled(), skinsEnabled(), tabEnabled()); - server.getPlayerManager().getPlayerList().forEach(p -> ServerPlayNetworking.send(p, payload)); - } - - public void sendConfigPayload(boolean showNametags, boolean showSkins, boolean showTab) { - final var payload = new ConfigPayload(showNametags, showSkins, showTab); - server.getPlayerManager().getPlayerList().forEach(p -> ServerPlayNetworking.send(p, payload)); - } - - public int getGameDuration() { - return server.getOverworld().getGameRules().getValue(Molehunt.GAME_DURATION); - } - - public int getMolePercentage() { - return server.getOverworld().getGameRules().getValue(Molehunt.MOLE_PERCENTAGE); - } - - public int getMoleCount() { - return server.getOverworld().getGameRules().getValue(Molehunt.MOLE_COUNT); - } - - public boolean nametagsEnabled() { - return server.getOverworld().getGameRules().getValue(Molehunt.SHOW_NAMETAGS); - } - - public boolean skinsEnabled() { - return server.getOverworld().getGameRules().getValue(Molehunt.SHOW_SKINS); - } - - public boolean tabEnabled() { - return server.getOverworld().getGameRules().getValue(Molehunt.SHOW_TAB); - } - - public int getInitialWorldSize() { - return server.getOverworld().getGameRules().getValue(Molehunt.INITIAL_WORLD_SIZE); - } - - public int getFinalWorldSize() { - return server.getOverworld().getGameRules().getValue(Molehunt.FINAL_WORLD_SIZE); - } - - public int getBorderShrinkingStartingTimeOffset() { - return server.getOverworld().getGameRules().getValue(Molehunt.MOVING_STARTING_TIME_OFFSET); - } - - public boolean portalsEnabled() { - return server.getOverworld().getGameRules().getValue(Molehunt.ENABLE_PORTALS); - } - - public boolean foodOnStart() { - return server.getOverworld().getGameRules().getValue(Molehunt.FOOD_ON_START); - } - - public static SimpleConfig configFile(String fileName) { - return SimpleConfig.of(fileName).provider(Config::defaultConfig).request(); - } - - private static String defaultConfig(String s) { - return """ - # Molehunt mod configuration file - # To regenerate the default configuration, delete, move or rename this file. - - # Game settings - - # The duration of a molehunt game, in minutes. - # Default: 90 minutes (1 hour 30 minutes). - game_duration = 90 - - # Mole percentage. - # For example, a mole percentage of 25% will get 1 mole every 4 players. - # Default: 25 %. - mole_percentage = 25 - - # Mole count (absolute). - # This setting will overwrite the mole_percentage setting. - # If set below 0, this setting is disabled. - # Default: -1. - mole_count = -1 - - # Give food on start - # Default: true - food_on_start = true - - - # Client-side settings (applies to all players) - - # Show nametags - # Default: false - show_nametags = false - - # Show skins - # Default: false - show_skins = false - - # Show tab - # Default: false - show_tab = false - - - # World border settings - - # Initial world size (in blocks). - # Default: 600 blocks. - initial_world_size = 600 - - # Final world size (in blocks). - # Default: 100 blocks. - final_world_size = 100 - - # Moving starting time offset (in minutes) - # The time before starting to move the world borders. - # If this value is greater than the game duration, borders will never move. - # Default: 30 minutes. - border_moving_starting_time_offset = 30 - - # Other - - # Enable portals (nether, end, end gateway). - # Default: false. - enable_portals = false - """; - } + private final MinecraftServer server; + + public Config(MinecraftServer server) { + this.server = server; + + sendConfigPayload(nametagsEnabled(), skinsEnabled(), tabEnabled()); + } + + public static SimpleConfig configFile(String fileName) { + return SimpleConfig.of(fileName).provider(Config::defaultConfig).request(); + } + + private static String defaultConfig(String s) { + return """ + # Molehunt mod configuration file + # To regenerate the default configuration, delete, move or rename this file. + + # Game settings + + # The duration of a molehunt game, in minutes. + # Default: 90 minutes (1 hour 30 minutes). + game_duration = 90 + + # Mole percentage. + # For example, a mole percentage of 25% will get 1 mole every 4 players. + # Default: 25 %. + mole_percentage = 25 + + # Mole count (absolute). + # This setting will overwrite the mole_percentage setting. + # If set below 0, this setting is disabled. + # Default: -1. + mole_count = -1 + + # Give food on start + # Default: true + food_on_start = true + + + # Client-side settings (applies to all players) + + # Show nametags + # Default: false + show_nametags = false + + # Show skins + # Default: false + show_skins = false + + # Show tab + # Default: false + show_tab = false + + + # World border settings + + # Initial world size (in blocks). + # Default: 600 blocks. + initial_world_size = 600 + + # Final world size (in blocks). + # Default: 100 blocks. + final_world_size = 100 + + # Moving starting time offset (in minutes) + # The time before starting to move the world borders. + # If this value is greater than the game duration, borders will never move. + # Default: 30 minutes. + border_moving_starting_time_offset = 30 + + # Other + + # Enable portals (nether, end, end gateway). + # Default: false. + enable_portals = false + """; + } + + public void sendConfigPayload() { + final var payload = new ConfigPayload(nametagsEnabled(), skinsEnabled(), tabEnabled()); + server.getPlayerManager().getPlayerList().forEach(p -> ServerPlayNetworking.send(p, payload)); + } + + public void sendConfigPayload(boolean showNametags, boolean showSkins, boolean showTab) { + final var payload = new ConfigPayload(showNametags, showSkins, showTab); + server.getPlayerManager().getPlayerList().forEach(p -> ServerPlayNetworking.send(p, payload)); + } + + public int getGameDuration() { + return server.getOverworld().getGameRules().getValue(Molehunt.GAME_DURATION); + } + + public int getMolePercentage() { + return server.getOverworld().getGameRules().getValue(Molehunt.MOLE_PERCENTAGE); + } + + public int getMoleCount() { + return server.getOverworld().getGameRules().getValue(Molehunt.MOLE_COUNT); + } + + public boolean nametagsEnabled() { + return server.getOverworld().getGameRules().getValue(Molehunt.SHOW_NAMETAGS); + } + + public boolean skinsEnabled() { + return server.getOverworld().getGameRules().getValue(Molehunt.SHOW_SKINS); + } + + public boolean tabEnabled() { + return server.getOverworld().getGameRules().getValue(Molehunt.SHOW_TAB); + } + + public int getInitialWorldSize() { + return server.getOverworld().getGameRules().getValue(Molehunt.INITIAL_WORLD_SIZE); + } + + public int getFinalWorldSize() { + return server.getOverworld().getGameRules().getValue(Molehunt.FINAL_WORLD_SIZE); + } + + public int getBorderShrinkingStartingTimeOffset() { + return server.getOverworld().getGameRules().getValue(Molehunt.MOVING_STARTING_TIME_OFFSET); + } + + public boolean portalsEnabled() { + return server.getOverworld().getGameRules().getValue(Molehunt.ENABLE_PORTALS); + } + + public boolean foodOnStart() { + return server.getOverworld().getGameRules().getValue(Molehunt.FOOD_ON_START); + } } diff --git a/src/main/java/world/anhgelus/molehunt/config/ConfigPayload.java b/src/main/java/world/anhgelus/molehunt/config/ConfigPayload.java index b43bd1b..f33e2c5 100644 --- a/src/main/java/world/anhgelus/molehunt/config/ConfigPayload.java +++ b/src/main/java/world/anhgelus/molehunt/config/ConfigPayload.java @@ -8,18 +8,18 @@ import net.minecraft.util.Identifier; import world.anhgelus.molehunt.Molehunt; public record ConfigPayload(boolean showNametags, boolean showSkins, boolean showTab) implements CustomPayload { - public static final Identifier CONFIG_PACKET_ID = Identifier.of(Molehunt.MOD_ID, "config"); + public static final Identifier CONFIG_PACKET_ID = Identifier.of(Molehunt.MOD_ID, "config"); - public static final CustomPayload.Id ID = new CustomPayload.Id<>(CONFIG_PACKET_ID); - public static final PacketCodec CODEC = PacketCodec.tuple( - PacketCodecs.BOOLEAN, ConfigPayload::showNametags, - PacketCodecs.BOOLEAN, ConfigPayload::showSkins, - PacketCodecs.BOOLEAN, ConfigPayload::showTab, - ConfigPayload::new - ); + public static final CustomPayload.Id ID = new CustomPayload.Id<>(CONFIG_PACKET_ID); + public static final PacketCodec CODEC = PacketCodec.tuple( + PacketCodecs.BOOLEAN, ConfigPayload::showNametags, + PacketCodecs.BOOLEAN, ConfigPayload::showSkins, + PacketCodecs.BOOLEAN, ConfigPayload::showTab, + ConfigPayload::new + ); - @Override - public Id getId() { - return ID; - } + @Override + public Id getId() { + return ID; + } } diff --git a/src/main/java/world/anhgelus/molehunt/config/SimpleConfig.java b/src/main/java/world/anhgelus/molehunt/config/SimpleConfig.java index 2b65829..6b7060a 100644 --- a/src/main/java/world/anhgelus/molehunt/config/SimpleConfig.java +++ b/src/main/java/world/anhgelus/molehunt/config/SimpleConfig.java @@ -38,216 +38,216 @@ import java.util.Scanner; public class SimpleConfig { - private static final Logger LOGGER = LogManager.getLogger("SimpleConfig"); - private final HashMap config = new HashMap<>(); - private final ConfigRequest request; - private boolean broken = false; - - public interface DefaultConfig { - String get( String namespace ); - - static String empty( String namespace ) { - return ""; - } - } - - public static class ConfigRequest { - - private final File file; - private final String filename; - private DefaultConfig provider; - - private ConfigRequest(File file, String filename ) { - this.file = file; - this.filename = filename; - this.provider = DefaultConfig::empty; - } - - /** - * Sets the default config provider, used to generate the - * config if it's missing. - * - * @param provider default config provider - * @return current config request object - * @see DefaultConfig - */ - public ConfigRequest provider( DefaultConfig provider ) { - this.provider = provider; - return this; - } - - /** - * Loads the config from the filesystem. - * - * @return config object - * @see SimpleConfig - */ - public SimpleConfig request() { - return new SimpleConfig( this ); - } - - private String getConfig() { - return provider.get( filename ) + "\n"; - } - - } - - /** - * Creates new config request object, ideally `namespace` - * should be the name of the mod id of the requesting mod - * - * @param filename - name of the config file - * @return new config request object - */ - public static ConfigRequest of( String filename ) { - Path path = FabricLoader.getInstance().getConfigDir(); - return new ConfigRequest( path.resolve( filename + ".properties" ).toFile(), filename ); - } - - private void createConfig() throws IOException { - - // try creating missing files - request.file.getParentFile().mkdirs(); - Files.createFile( request.file.toPath() ); - - // write default config data - PrintWriter writer = new PrintWriter(request.file, StandardCharsets.UTF_8); - writer.write( request.getConfig() ); - writer.close(); - - } - - private void loadConfig() throws IOException { - Scanner reader = new Scanner( request.file ); - for( int line = 1; reader.hasNextLine(); line ++ ) { - parseConfigEntry( reader.nextLine(), line ); - } - } - - private void parseConfigEntry( String entry, int line ) { - if( !entry.isEmpty() && !entry.startsWith( "#" ) ) { - String[] parts = entry.split("=", 2); - if( parts.length == 2 ) { - config.put( parts[0].stripTrailing(), parts[1].strip() ); - }else{ - throw new RuntimeException("Syntax error in config file on line " + line + "!"); - } - } - } - - private SimpleConfig( ConfigRequest request ) { - this.request = request; - String identifier = "Config '" + request.filename + "'"; - - if( !request.file.exists() ) { - LOGGER.info("{} is missing, generating default one...", identifier); - - try { - createConfig(); - } catch (IOException e) { - LOGGER.error("{} failed to generate!", identifier); - LOGGER.trace( e ); - broken = true; - } - } - - if( !broken ) { - try { - loadConfig(); - } catch (Exception e) { - LOGGER.error("{} failed to load!", identifier); - LOGGER.trace( e ); - broken = true; - } - } - - } - - /** - * Queries a value from config, returns `null` if the - * key does not exist. - * - * @return value corresponding to the given key - * @see SimpleConfig#getOrDefault - */ - @Deprecated - public String get( String key ) { - return config.get( key ); - } - - /** - * Returns string value from config corresponding to the given - * key, or the default string if the key is missing. - * - * @return value corresponding to the given key, or the default value - */ - public String getOrDefault( String key, String def ) { - String val = get(key); - return val == null ? def : val; - } - - /** - * Returns integer value from config corresponding to the given - * key, or the default integer if the key is missing or invalid. - * - * @return value corresponding to the given key, or the default value - */ - public int getOrDefault( String key, int def ) { - try { - return Integer.parseInt( get(key) ); - } catch (Exception e) { - return def; - } - } - - /** - * Returns boolean value from config corresponding to the given - * key, or the default boolean if the key is missing. - * - * @return value corresponding to the given key, or the default value - */ - public boolean getOrDefault( String key, boolean def ) { - String val = get(key); - if( val != null ) { - return val.equalsIgnoreCase("true"); - } - - return def; - } - - /** - * Returns double value from config corresponding to the given - * key, or the default string if the key is missing or invalid. - * - * @return value corresponding to the given key, or the default value - */ - public double getOrDefault( String key, double def ) { - try { - return Double.parseDouble( get(key) ); - } catch (Exception e) { - return def; - } - } - - /** - * If any error occurred during loading or reading from the config - * a 'broken' flag is set, indicating that the config's state - * is undefined and should be discarded using `delete()` - * - * @return the 'broken' flag of the configuration - */ - public boolean isBroken() { - return broken; - } - - /** - * deletes the config file from the filesystem - * - * @return true if the operation was successful - */ - public boolean delete() { - LOGGER.warn("Config '{}' was removed from existence! Restart the game to regenerate it.", request.filename); - return request.file.delete(); - } + private static final Logger LOGGER = LogManager.getLogger("SimpleConfig"); + private final HashMap config = new HashMap<>(); + private final ConfigRequest request; + private boolean broken = false; + + private SimpleConfig(ConfigRequest request) { + this.request = request; + String identifier = "Config '" + request.filename + "'"; + + if (!request.file.exists()) { + LOGGER.info("{} is missing, generating default one...", identifier); + + try { + createConfig(); + } catch (IOException e) { + LOGGER.error("{} failed to generate!", identifier); + LOGGER.trace(e); + broken = true; + } + } + + if (!broken) { + try { + loadConfig(); + } catch (Exception e) { + LOGGER.error("{} failed to load!", identifier); + LOGGER.trace(e); + broken = true; + } + } + + } + + /** + * Creates new config request object, ideally `namespace` + * should be the name of the mod id of the requesting mod + * + * @param filename - name of the config file + * @return new config request object + */ + public static ConfigRequest of(String filename) { + Path path = FabricLoader.getInstance().getConfigDir(); + return new ConfigRequest(path.resolve(filename + ".properties").toFile(), filename); + } + + private void createConfig() throws IOException { + + // try creating missing files + request.file.getParentFile().mkdirs(); + Files.createFile(request.file.toPath()); + + // write default config data + PrintWriter writer = new PrintWriter(request.file, StandardCharsets.UTF_8); + writer.write(request.getConfig()); + writer.close(); + + } + + private void loadConfig() throws IOException { + Scanner reader = new Scanner(request.file); + for (int line = 1; reader.hasNextLine(); line++) { + parseConfigEntry(reader.nextLine(), line); + } + } + + private void parseConfigEntry(String entry, int line) { + if (!entry.isEmpty() && !entry.startsWith("#")) { + String[] parts = entry.split("=", 2); + if (parts.length == 2) { + config.put(parts[0].stripTrailing(), parts[1].strip()); + } else { + throw new RuntimeException("Syntax error in config file on line " + line + "!"); + } + } + } + + /** + * Queries a value from config, returns `null` if the + * key does not exist. + * + * @return value corresponding to the given key + * @see SimpleConfig#getOrDefault + */ + @Deprecated + public String get(String key) { + return config.get(key); + } + + /** + * Returns string value from config corresponding to the given + * key, or the default string if the key is missing. + * + * @return value corresponding to the given key, or the default value + */ + public String getOrDefault(String key, String def) { + String val = get(key); + return val == null ? def : val; + } + + /** + * Returns integer value from config corresponding to the given + * key, or the default integer if the key is missing or invalid. + * + * @return value corresponding to the given key, or the default value + */ + public int getOrDefault(String key, int def) { + try { + return Integer.parseInt(get(key)); + } catch (Exception e) { + return def; + } + } + + /** + * Returns boolean value from config corresponding to the given + * key, or the default boolean if the key is missing. + * + * @return value corresponding to the given key, or the default value + */ + public boolean getOrDefault(String key, boolean def) { + String val = get(key); + if (val != null) { + return val.equalsIgnoreCase("true"); + } + + return def; + } + + /** + * Returns double value from config corresponding to the given + * key, or the default string if the key is missing or invalid. + * + * @return value corresponding to the given key, or the default value + */ + public double getOrDefault(String key, double def) { + try { + return Double.parseDouble(get(key)); + } catch (Exception e) { + return def; + } + } + + /** + * If any error occurred during loading or reading from the config + * a 'broken' flag is set, indicating that the config's state + * is undefined and should be discarded using `delete()` + * + * @return the 'broken' flag of the configuration + */ + public boolean isBroken() { + return broken; + } + + /** + * deletes the config file from the filesystem + * + * @return true if the operation was successful + */ + public boolean delete() { + LOGGER.warn("Config '{}' was removed from existence! Restart the game to regenerate it.", request.filename); + return request.file.delete(); + } + + public interface DefaultConfig { + static String empty(String namespace) { + return ""; + } + + String get(String namespace); + } + + public static class ConfigRequest { + + private final File file; + private final String filename; + private DefaultConfig provider; + + private ConfigRequest(File file, String filename) { + this.file = file; + this.filename = filename; + this.provider = DefaultConfig::empty; + } + + /** + * Sets the default config provider, used to generate the + * config if it's missing. + * + * @param provider default config provider + * @return current config request object + * @see DefaultConfig + */ + public ConfigRequest provider(DefaultConfig provider) { + this.provider = provider; + return this; + } + + /** + * Loads the config from the filesystem. + * + * @return config object + * @see SimpleConfig + */ + public SimpleConfig request() { + return new SimpleConfig(this); + } + + private String getConfig() { + return provider.get(filename) + "\n"; + } + + } } \ No newline at end of file diff --git a/src/main/java/world/anhgelus/molehunt/game/Game.java b/src/main/java/world/anhgelus/molehunt/game/Game.java index 4f3234c..35c45fa 100644 --- a/src/main/java/world/anhgelus/molehunt/game/Game.java +++ b/src/main/java/world/anhgelus/molehunt/game/Game.java @@ -25,176 +25,176 @@ import java.util.stream.Collectors; public class Game { - public final int defaultTime = Molehunt.CONFIG.getGameDuration() * 60; - private final MinecraftServer server; - private final List moles = new ArrayList<>(); - private final TitleFadeS2CPacket timing = new TitleFadeS2CPacket(20, 40, 20); - private int remaining = defaultTime; - private boolean started = false; - - public Game(MinecraftServer server) { - this.server = server; - } - - public void start() { - final int n = Molehunt.CONFIG.getMoleCount() < 0 - ? Math.floorDiv(server.getCurrentPlayerCount(), Math.floorDiv(100, Molehunt.CONFIG.getMolePercentage())) - : Molehunt.CONFIG.getMoleCount(); - - final var playerManager = server.getPlayerManager(); - - final var players = new ArrayList<>(playerManager.getPlayerList()); - for (int i = 0; i < n && !players.isEmpty(); i++) { - final var r = ThreadLocalRandom.current().nextInt(0, players.size()); - final var mole = players.get(r); - if (mole == null) throw new IllegalStateException("Mole is null!"); - moles.add(mole.getUuid()); - players.remove(r); - } - - final var gamerules = server.getOverworld().getGameRules(); - // immutable gamerules - gamerules.setValue(GameRules.SHOW_DEATH_MESSAGES, false, server); - gamerules.setValue(GameRules.ANNOUNCE_ADVANCEMENTS, false, server); - // gamerules for the start - gamerules.setValue(GameRules.DO_IMMEDIATE_RESPAWN, true, server); - - final var timer = TimerAccess.getTimerFromOverworld(server); - - final var worldBorder = server.getOverworld().getWorldBorder(); - worldBorder.setSize(Molehunt.CONFIG.getInitialWorldSize()); - if (Molehunt.CONFIG.getBorderShrinkingStartingTimeOffset() < Molehunt.CONFIG.getGameDuration()) { - timer.dds_runTask(new TickTask(() -> worldBorder.interpolateSize( - Molehunt.CONFIG.getInitialWorldSize(), - Molehunt.CONFIG.getFinalWorldSize(), - (Molehunt.CONFIG.getGameDuration() - Molehunt.CONFIG.getBorderShrinkingStartingTimeOffset()) * 60 * 20L, - 0L - ), Molehunt.CONFIG.getBorderShrinkingStartingTimeOffset() * 60 * 20L)); - } - - final var title = new TitleS2CPacket(Text.translatable("molehunt.game.start.suspense")); - playerManager.getPlayerList().forEach(p -> { - p.getInventory().clear(); - p.kill(p.getEntityWorld()); - p.networkHandler.sendPacket(timing); - p.networkHandler.sendPacket(title); - p.changeGameMode(GameMode.SURVIVAL); - if (Molehunt.CONFIG.foodOnStart()) p.giveItemStack(new ItemStack(Items.COOKED_BEEF, 64)); - }); - - server.setDefaultGameMode(GameMode.SPECTATOR); - - timer.dds_runTask(new TickTask(() -> { - playerManager.getPlayerList().forEach(p -> { - p.networkHandler.sendPacket(timing); - if (moles.contains(p.getUuid())) { - p.networkHandler.sendPacket(new TitleS2CPacket(Text.translatable("molehunt.game.start.mole.title"))); - p.networkHandler.sendPacket(new SubtitleS2CPacket(Text.translatable("molehunt.game.start.mole.subtitle"))); - } else { - p.networkHandler.sendPacket(new TitleS2CPacket(Text.translatable("molehunt.game.start.survivor.title"))); - p.networkHandler.sendPacket(new SubtitleS2CPacket(Text.translatable("molehunt.game.start.survivor.subtitle"))); - } - // reset health and food level - p.setHealth(p.getMaxHealth()); - p.getHungerManager().setFoodLevel(20); - p.getHungerManager().setSaturationLevel(5.0f); - }); - // reset gamerules after the start - gamerules.setValue(GameRules.DO_IMMEDIATE_RESPAWN, false, server); - // reset time and weather - server.getOverworld().setTimeOfDay(0); - server.getOverworld().resetWeather(); - changeState(true); - timer.dds_runTask(new TickTask(() -> { - remaining--; - playerManager.getPlayerList().forEach(player -> { - if (Molehunt.timerVisibility.getOrDefault(player.getUuid(), true)) { - player.networkHandler.sendPacket(new OverlayMessageS2CPacket(Text.of(getRemainingText()))); - } - }); - playerManager.sendToAll(timing); - if (remaining == 0) end(); - }, 5 * 20, 20)); - }, 4 * 20)); - } - - public void stop() { - server.getPlayerManager().broadcast(Text.translatable("commands.molehunt.stop.success"), false); - end(); - } - - public void end() { - final var timer = TimerAccess.getTimerFromOverworld(server); - timer.dds_cancel(); - - final var worldBorder = server.getOverworld().getWorldBorder(); - // Stops the border shrinking. - worldBorder.setSize(worldBorder.getSize()); - - changeState(false); - final var pm = server.getPlayerManager(); - final var winnerSuspense = new TitleS2CPacket(Text.translatable("molehunt.game.end.suspense.title")); - pm.getPlayerList().forEach(p -> { - p.networkHandler.sendPacket(timing); - p.networkHandler.sendPacket(winnerSuspense); - p.changeGameMode(GameMode.CREATIVE); - }); - timer.dds_runTask(new TickTask(() -> { - TitleS2CPacket winner; - if (wonByMoles()) { - winner = new TitleS2CPacket(Text.translatable("molehunt.game.end.winners.moles.title")); - } else { - winner = new TitleS2CPacket(Text.translatable("molehunt.game.end.winners.survivors.title")); - } - pm.sendToAll(new SubtitleS2CPacket(Text.translatable("molehunt.game.end.winners.subtitle", getMolesAsString()))); - pm.sendToAll(winner); - pm.sendToAll(timing); - moles.clear(); - }, 4 * 20)); - } - - public Text getRemainingText() { - return Text.of("§c" + TimeUtils.generateShortString(remaining)); - } - - public List getMoles() { - return moles.stream() - .map(uuid -> server.getPlayerManager().getPlayer(uuid)) - .filter(Objects::nonNull) - .filter(p -> !p.isSpectator()) - .toList(); - } - - public String getMolesAsString() { - return getMoles().stream() - .map(PlayerEntity::getDisplayName) - .filter(Objects::nonNull) - .map(Object::toString) - .collect(Collectors.joining(", ")); - } - - public boolean isMole(ServerPlayerEntity player) { - return moles.contains(player.getUuid()); - } - - public boolean wonByMoles() { - return new HashSet<>(moles).containsAll( - server.getPlayerManager() - .getPlayerList() - .stream() - .filter(p -> !p.isSpectator() && !p.isCreative()) - .map(Entity::getUuid) - .toList() - ); - } - - public boolean started() { - return started; - } - - private void changeState(boolean hasStarted) { - started = hasStarted; - final var payload = new GamePayload(hasStarted); - server.getPlayerManager().getPlayerList().forEach(p -> ServerPlayNetworking.send(p, payload)); - } + public final int defaultTime = Molehunt.CONFIG.getGameDuration() * 60; + private final MinecraftServer server; + private final List moles = new ArrayList<>(); + private final TitleFadeS2CPacket timing = new TitleFadeS2CPacket(20, 40, 20); + private int remaining = defaultTime; + private boolean started = false; + + public Game(MinecraftServer server) { + this.server = server; + } + + public void start() { + final int n = Molehunt.CONFIG.getMoleCount() < 0 + ? Math.floorDiv(server.getCurrentPlayerCount(), Math.floorDiv(100, Molehunt.CONFIG.getMolePercentage())) + : Molehunt.CONFIG.getMoleCount(); + + final var playerManager = server.getPlayerManager(); + + final var players = new ArrayList<>(playerManager.getPlayerList()); + for (int i = 0; i < n && !players.isEmpty(); i++) { + final var r = ThreadLocalRandom.current().nextInt(0, players.size()); + final var mole = players.get(r); + if (mole == null) throw new IllegalStateException("Mole is null!"); + moles.add(mole.getUuid()); + players.remove(r); + } + + final var gamerules = server.getOverworld().getGameRules(); + // immutable gamerules + gamerules.setValue(GameRules.SHOW_DEATH_MESSAGES, false, server); + gamerules.setValue(GameRules.ANNOUNCE_ADVANCEMENTS, false, server); + // gamerules for the start + gamerules.setValue(GameRules.DO_IMMEDIATE_RESPAWN, true, server); + + final var timer = TimerAccess.getTimerFromOverworld(server); + + final var worldBorder = server.getOverworld().getWorldBorder(); + worldBorder.setSize(Molehunt.CONFIG.getInitialWorldSize()); + if (Molehunt.CONFIG.getBorderShrinkingStartingTimeOffset() < Molehunt.CONFIG.getGameDuration()) { + timer.dds_runTask(new TickTask(() -> worldBorder.interpolateSize( + Molehunt.CONFIG.getInitialWorldSize(), + Molehunt.CONFIG.getFinalWorldSize(), + (Molehunt.CONFIG.getGameDuration() - Molehunt.CONFIG.getBorderShrinkingStartingTimeOffset()) * 60 * 20L, + 0L + ), Molehunt.CONFIG.getBorderShrinkingStartingTimeOffset() * 60 * 20L)); + } + + final var title = new TitleS2CPacket(Text.translatable("molehunt.game.start.suspense")); + playerManager.getPlayerList().forEach(p -> { + p.getInventory().clear(); + p.kill(p.getEntityWorld()); + p.networkHandler.sendPacket(timing); + p.networkHandler.sendPacket(title); + p.changeGameMode(GameMode.SURVIVAL); + if (Molehunt.CONFIG.foodOnStart()) p.giveItemStack(new ItemStack(Items.COOKED_BEEF, 64)); + }); + + server.setDefaultGameMode(GameMode.SPECTATOR); + + timer.dds_runTask(new TickTask(() -> { + playerManager.getPlayerList().forEach(p -> { + p.networkHandler.sendPacket(timing); + if (moles.contains(p.getUuid())) { + p.networkHandler.sendPacket(new TitleS2CPacket(Text.translatable("molehunt.game.start.mole.title"))); + p.networkHandler.sendPacket(new SubtitleS2CPacket(Text.translatable("molehunt.game.start.mole.subtitle"))); + } else { + p.networkHandler.sendPacket(new TitleS2CPacket(Text.translatable("molehunt.game.start.survivor.title"))); + p.networkHandler.sendPacket(new SubtitleS2CPacket(Text.translatable("molehunt.game.start.survivor.subtitle"))); + } + // reset health and food level + p.setHealth(p.getMaxHealth()); + p.getHungerManager().setFoodLevel(20); + p.getHungerManager().setSaturationLevel(5.0f); + }); + // reset gamerules after the start + gamerules.setValue(GameRules.DO_IMMEDIATE_RESPAWN, false, server); + // reset time and weather + server.getOverworld().setTimeOfDay(0); + server.getOverworld().resetWeather(); + changeState(true); + timer.dds_runTask(new TickTask(() -> { + remaining--; + playerManager.getPlayerList().forEach(player -> { + if (Molehunt.timerVisibility.getOrDefault(player.getUuid(), true)) { + player.networkHandler.sendPacket(new OverlayMessageS2CPacket(Text.of(getRemainingText()))); + } + }); + playerManager.sendToAll(timing); + if (remaining == 0) end(); + }, 5 * 20, 20)); + }, 4 * 20)); + } + + public void stop() { + server.getPlayerManager().broadcast(Text.translatable("commands.molehunt.stop.success"), false); + end(); + } + + public void end() { + final var timer = TimerAccess.getTimerFromOverworld(server); + timer.dds_cancel(); + + final var worldBorder = server.getOverworld().getWorldBorder(); + // Stops the border shrinking. + worldBorder.setSize(worldBorder.getSize()); + + changeState(false); + final var pm = server.getPlayerManager(); + final var winnerSuspense = new TitleS2CPacket(Text.translatable("molehunt.game.end.suspense.title")); + pm.getPlayerList().forEach(p -> { + p.networkHandler.sendPacket(timing); + p.networkHandler.sendPacket(winnerSuspense); + p.changeGameMode(GameMode.CREATIVE); + }); + timer.dds_runTask(new TickTask(() -> { + TitleS2CPacket winner; + if (wonByMoles()) { + winner = new TitleS2CPacket(Text.translatable("molehunt.game.end.winners.moles.title")); + } else { + winner = new TitleS2CPacket(Text.translatable("molehunt.game.end.winners.survivors.title")); + } + pm.sendToAll(new SubtitleS2CPacket(Text.translatable("molehunt.game.end.winners.subtitle", getMolesAsString()))); + pm.sendToAll(winner); + pm.sendToAll(timing); + moles.clear(); + }, 4 * 20)); + } + + public Text getRemainingText() { + return Text.of("§c" + TimeUtils.generateShortString(remaining)); + } + + public List getMoles() { + return moles.stream() + .map(uuid -> server.getPlayerManager().getPlayer(uuid)) + .filter(Objects::nonNull) + .filter(p -> !p.isSpectator()) + .toList(); + } + + public String getMolesAsString() { + return getMoles().stream() + .map(PlayerEntity::getDisplayName) + .filter(Objects::nonNull) + .map(Object::toString) + .collect(Collectors.joining(", ")); + } + + public boolean isMole(ServerPlayerEntity player) { + return moles.contains(player.getUuid()); + } + + public boolean wonByMoles() { + return new HashSet<>(moles).containsAll( + server.getPlayerManager() + .getPlayerList() + .stream() + .filter(p -> !p.isSpectator() && !p.isCreative()) + .map(Entity::getUuid) + .toList() + ); + } + + public boolean started() { + return started; + } + + private void changeState(boolean hasStarted) { + started = hasStarted; + final var payload = new GamePayload(hasStarted); + server.getPlayerManager().getPlayerList().forEach(p -> ServerPlayNetworking.send(p, payload)); + } } diff --git a/src/main/java/world/anhgelus/molehunt/game/GamePayload.java b/src/main/java/world/anhgelus/molehunt/game/GamePayload.java index 66e3209..1532fa9 100644 --- a/src/main/java/world/anhgelus/molehunt/game/GamePayload.java +++ b/src/main/java/world/anhgelus/molehunt/game/GamePayload.java @@ -8,16 +8,16 @@ import net.minecraft.util.Identifier; import world.anhgelus.molehunt.Molehunt; public record GamePayload(boolean gameLaunched) implements CustomPayload { - public static final Identifier GAME_PACKET_ID = Identifier.of(Molehunt.MOD_ID, "game"); + public static final Identifier GAME_PACKET_ID = Identifier.of(Molehunt.MOD_ID, "game"); - public static final CustomPayload.Id ID = new CustomPayload.Id<>(GAME_PACKET_ID); - public static final PacketCodec CODEC = PacketCodec.tuple( - PacketCodecs.BOOLEAN, GamePayload::gameLaunched, - GamePayload::new - ); + public static final CustomPayload.Id ID = new CustomPayload.Id<>(GAME_PACKET_ID); + public static final PacketCodec CODEC = PacketCodec.tuple( + PacketCodecs.BOOLEAN, GamePayload::gameLaunched, + GamePayload::new + ); - @Override - public Id getId() { - return ID; - } + @Override + public Id getId() { + return ID; + } } diff --git a/src/main/java/world/anhgelus/molehunt/mixin/NoJoinLeaveMessage.java b/src/main/java/world/anhgelus/molehunt/mixin/NoJoinLeaveMessage.java index a82a21e..0dfd624 100644 --- a/src/main/java/world/anhgelus/molehunt/mixin/NoJoinLeaveMessage.java +++ b/src/main/java/world/anhgelus/molehunt/mixin/NoJoinLeaveMessage.java @@ -9,10 +9,10 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(PlayerManager.class) public class NoJoinLeaveMessage { - @Inject(at = @At("HEAD"), method = "broadcast*", cancellable = true) - public void broadcastNoJoinLeaveMessage(Text message, boolean overlay, CallbackInfo ci) { - final var content = message.getContent().toString(); - if (content.startsWith("translation{key='multiplayer.player.joined")) ci.cancel(); - else if (content.startsWith("translation{key='multiplayer.player.left")) ci.cancel(); - } + @Inject(at = @At("HEAD"), method = "broadcast*", cancellable = true) + public void broadcastNoJoinLeaveMessage(Text message, boolean overlay, CallbackInfo ci) { + final var content = message.getContent().toString(); + if (content.startsWith("translation{key='multiplayer.player.joined")) ci.cancel(); + else if (content.startsWith("translation{key='multiplayer.player.left")) ci.cancel(); + } } diff --git a/src/main/java/world/anhgelus/molehunt/mixin/NoMsgCommand.java b/src/main/java/world/anhgelus/molehunt/mixin/NoMsgCommand.java index 2727143..f698f1c 100644 --- a/src/main/java/world/anhgelus/molehunt/mixin/NoMsgCommand.java +++ b/src/main/java/world/anhgelus/molehunt/mixin/NoMsgCommand.java @@ -10,8 +10,8 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(MessageCommand.class) public class NoMsgCommand { - @Inject(at = @At("HEAD"), method = "register", cancellable = true) - private static void register(CommandDispatcher dispatcher, CallbackInfo ci) { - ci.cancel(); - } + @Inject(at = @At("HEAD"), method = "register", cancellable = true) + private static void register(CommandDispatcher dispatcher, CallbackInfo ci) { + ci.cancel(); + } } diff --git a/src/main/java/world/anhgelus/molehunt/mixin/NoPortals.java b/src/main/java/world/anhgelus/molehunt/mixin/NoPortals.java index a71e6d1..2648f25 100644 --- a/src/main/java/world/anhgelus/molehunt/mixin/NoPortals.java +++ b/src/main/java/world/anhgelus/molehunt/mixin/NoPortals.java @@ -11,9 +11,9 @@ import world.anhgelus.molehunt.Molehunt; @Mixin(PortalManager.class) public class NoPortals { - @Inject(at = @At("HEAD"), method = "tick", cancellable = true) - public void disableTick(ServerWorld world, Entity entity, boolean canUsePortals, CallbackInfoReturnable cir) { - if (Molehunt.CONFIG == null || Molehunt.CONFIG.portalsEnabled()) return; - cir.setReturnValue(false); - } + @Inject(at = @At("HEAD"), method = "tick", cancellable = true) + public void disableTick(ServerWorld world, Entity entity, boolean canUsePortals, CallbackInfoReturnable cir) { + if (Molehunt.CONFIG == null || Molehunt.CONFIG.portalsEnabled()) return; + cir.setReturnValue(false); + } } diff --git a/src/main/java/world/anhgelus/molehunt/mixin/WorldTimerAccess.java b/src/main/java/world/anhgelus/molehunt/mixin/WorldTimerAccess.java index cd8a1b4..1e0ba12 100644 --- a/src/main/java/world/anhgelus/molehunt/mixin/WorldTimerAccess.java +++ b/src/main/java/world/anhgelus/molehunt/mixin/WorldTimerAccess.java @@ -14,32 +14,32 @@ import java.util.function.BooleanSupplier; @Mixin(ServerWorld.class) public class WorldTimerAccess implements TimerAccess { - @Unique - private final List tasks = new ArrayList<>(); - - @Unique - private final List tasksToAdd = new ArrayList<>(); - - @Inject(method = "tick", at = @At("TAIL")) - private void onTick(BooleanSupplier shouldKeepTicking, CallbackInfo ci) { - tasks.stream().filter(TickTask::isRunning).forEach(TickTask::tick); - tasks.addAll(tasksToAdd); - tasksToAdd.clear(); - } - - @Override - public void dds_runTask(TimerAccess.TickTask task) { - tasksToAdd.add(task); - } - - @Override - public void dds_cancel() { - tasks.stream().filter(TickTask::isRunning).forEach(TickTask::cancel); - tasks.clear(); - } - - @Override - public List dds_getTasks() { - return tasks.stream().filter(TickTask::isRunning).toList(); - } + @Unique + private final List tasks = new ArrayList<>(); + + @Unique + private final List tasksToAdd = new ArrayList<>(); + + @Inject(method = "tick", at = @At("TAIL")) + private void onTick(BooleanSupplier shouldKeepTicking, CallbackInfo ci) { + tasks.stream().filter(TickTask::isRunning).forEach(TickTask::tick); + tasks.addAll(tasksToAdd); + tasksToAdd.clear(); + } + + @Override + public void dds_runTask(TimerAccess.TickTask task) { + tasksToAdd.add(task); + } + + @Override + public void dds_cancel() { + tasks.stream().filter(TickTask::isRunning).forEach(TickTask::cancel); + tasks.clear(); + } + + @Override + public List dds_getTasks() { + return tasks.stream().filter(TickTask::isRunning).toList(); + } } \ No newline at end of file diff --git a/src/main/java/world/anhgelus/molehunt/timer/TickTask.java b/src/main/java/world/anhgelus/molehunt/timer/TickTask.java index 8c74b89..1cc83e2 100644 --- a/src/main/java/world/anhgelus/molehunt/timer/TickTask.java +++ b/src/main/java/world/anhgelus/molehunt/timer/TickTask.java @@ -4,69 +4,69 @@ package world.anhgelus.molehunt.timer; * Represents a complete task called each tick */ public class TickTask implements TimerAccess.TickTask { - public final long ticksDelay; - public final long ticksRepeat; - public final boolean repeating; - public final TimerAccess.Task task; - private boolean cancelled = false; - private long currentTicking; + public final long ticksDelay; + public final long ticksRepeat; + public final boolean repeating; + public final TimerAccess.Task task; + private boolean cancelled = false; + private long currentTicking; - /** - * Create a new repeating TickTask - * - * @param task Task to run after the delay or the repeat time - * @param ticksDelay Delay before the first task's run - * @param ticksRepeat Repeat each tick (if the repeat is 0, it will repeat each tick, if it is below 0, it will not repeat) - * @throws IllegalArgumentException if ticksDelay is below 0 - */ - public TickTask(TimerAccess.Task task, long ticksDelay, long ticksRepeat) { - if (ticksDelay < 0) throw new IllegalArgumentException("Ticks delay must be non-negative"); - this.ticksDelay = ticksDelay; - this.ticksRepeat = ticksRepeat; - this.task = task; - repeating = ticksRepeat >= 0; - currentTicking = ticksDelay; - } + /** + * Create a new repeating TickTask + * + * @param task Task to run after the delay or the repeat time + * @param ticksDelay Delay before the first task's run + * @param ticksRepeat Repeat each tick (if the repeat is 0, it will repeat each tick, if it is below 0, it will not repeat) + * @throws IllegalArgumentException if ticksDelay is below 0 + */ + public TickTask(TimerAccess.Task task, long ticksDelay, long ticksRepeat) { + if (ticksDelay < 0) throw new IllegalArgumentException("Ticks delay must be non-negative"); + this.ticksDelay = ticksDelay; + this.ticksRepeat = ticksRepeat; + this.task = task; + repeating = ticksRepeat >= 0; + currentTicking = ticksDelay; + } - /** - * Create a new delayed TickTask - * - * @param task Task to run after the delay or the repeat time - * @param ticksDelay Delay before the first task's run - * @throws IllegalArgumentException if ticksDelay or if ticksRepeat is below 0 - */ - public TickTask(TimerAccess.Task task, long ticksDelay) { - if (ticksDelay < 0) throw new IllegalArgumentException("Ticks delay must be non-negative"); - this.ticksDelay = ticksDelay; - this.ticksRepeat = -1; - this.task = task; - repeating = false; - currentTicking = ticksDelay; - } + /** + * Create a new delayed TickTask + * + * @param task Task to run after the delay or the repeat time + * @param ticksDelay Delay before the first task's run + * @throws IllegalArgumentException if ticksDelay or if ticksRepeat is below 0 + */ + public TickTask(TimerAccess.Task task, long ticksDelay) { + if (ticksDelay < 0) throw new IllegalArgumentException("Ticks delay must be non-negative"); + this.ticksDelay = ticksDelay; + this.ticksRepeat = -1; + this.task = task; + repeating = false; + currentTicking = ticksDelay; + } - public void tick() { - if (--currentTicking > 0) return; - task.run(); - if (repeating) { - currentTicking = ticksRepeat; - } else { - cancel(); - } - } + public void tick() { + if (--currentTicking > 0) return; + task.run(); + if (repeating) { + currentTicking = ticksRepeat; + } else { + cancel(); + } + } - public long cancel() { - if (cancelled) throw new IllegalStateException("Task already cancelled"); - cancelled = true; - return currentTicking; - } + public long cancel() { + if (cancelled) throw new IllegalStateException("Task already cancelled"); + cancelled = true; + return currentTicking; + } - public boolean isRunning() { - return !cancelled; - } + public boolean isRunning() { + return !cancelled; + } - @Override - public long getTickingBeforeRun() { - if (cancelled) return -1; - return currentTicking; - } + @Override + public long getTickingBeforeRun() { + if (cancelled) return -1; + return currentTicking; + } } \ No newline at end of file diff --git a/src/main/java/world/anhgelus/molehunt/timer/TimerAccess.java b/src/main/java/world/anhgelus/molehunt/timer/TimerAccess.java index 2e02b12..32ee611 100644 --- a/src/main/java/world/anhgelus/molehunt/timer/TimerAccess.java +++ b/src/main/java/world/anhgelus/molehunt/timer/TimerAccess.java @@ -6,60 +6,60 @@ import net.minecraft.world.World; import java.util.List; public interface TimerAccess { - /** - * Get the timer linked to the overworld - * - * @param server Current server - * @return TimerAccess linked to the overworld - */ - static TimerAccess getTimerFromOverworld(MinecraftServer server) { - final var timer = (TimerAccess) server.getWorld(World.OVERWORLD); - if (timer == null) - throw new NullPointerException("Impossible to get TimerAccess from the overworld (it is null)"); - return timer; - } + /** + * Get the timer linked to the overworld + * + * @param server Current server + * @return TimerAccess linked to the overworld + */ + static TimerAccess getTimerFromOverworld(MinecraftServer server) { + final var timer = (TimerAccess) server.getWorld(World.OVERWORLD); + if (timer == null) + throw new NullPointerException("Impossible to get TimerAccess from the overworld (it is null)"); + return timer; + } - /** - * Run a task (called each tick ticked) - * - * @param task Task to run - */ - void dds_runTask(TimerAccess.TickTask task); + /** + * Run a task (called each tick ticked) + * + * @param task Task to run + */ + void dds_runTask(TimerAccess.TickTask task); - void dds_cancel(); + void dds_cancel(); - /** - * @return All non-cancelled tasks - */ - List dds_getTasks(); + /** + * @return All non-cancelled tasks + */ + List dds_getTasks(); - interface TickTask { - /** - * Tick the task - */ - void tick(); + interface TickTask { + /** + * Tick the task + */ + void tick(); - /** - * Cancel the task - * - * @return the remaining ticks before the run of the Task - * @throws IllegalStateException if the task is already cancelled - */ - long cancel(); + /** + * Cancel the task + * + * @return the remaining ticks before the run of the Task + * @throws IllegalStateException if the task is already cancelled + */ + long cancel(); - boolean isRunning(); + boolean isRunning(); - /** - * @return the number of ticks before run of the task (if the task is cancelled, returns -1) - */ - long getTickingBeforeRun(); - } + /** + * @return the number of ticks before run of the task (if the task is cancelled, returns -1) + */ + long getTickingBeforeRun(); + } - /** - * Represents a task to run after ticking - */ - @FunctionalInterface - interface Task { - void run(); - } + /** + * Represents a task to run after ticking + */ + @FunctionalInterface + interface Task { + void run(); + } } diff --git a/src/main/java/world/anhgelus/molehunt/utils/TimeUtils.java b/src/main/java/world/anhgelus/molehunt/utils/TimeUtils.java index 2b96606..952f2d2 100644 --- a/src/main/java/world/anhgelus/molehunt/utils/TimeUtils.java +++ b/src/main/java/world/anhgelus/molehunt/utils/TimeUtils.java @@ -2,50 +2,51 @@ package world.anhgelus.molehunt.utils; public class TimeUtils { - private record Time(long hours, long minutes, long seconds) {} - - public static String generateString(long time) { - final var pt = generateTime(time); - - StringBuilder sb = new StringBuilder(); - if (pt.hours != 0) { - sb.append(pt.hours).append(" hours "); - } - if (pt.minutes != 0 || pt.hours != 0) { - sb.append(pt.minutes).append(" minutes "); - } - sb.append(pt.seconds).append(" seconds"); - - return sb.toString(); - } - - public static String generateShortString(long time) { - final var pt = generateTime(time); - - return padLeft(pt.hours) + ":" + - padLeft(pt.minutes) + ":" + - padLeft(pt.seconds); - } - - private static Time generateTime(long time) { - long hours = 0; - if (time > 3600) { - hours = Math.floorDiv(time, 3600); - } - long minutes = 0; - if (hours != 0 || time > 60) { - minutes = Math.floorDiv(time - hours * 3600, 60); - } - long seconds = (long) Math.floor(time - hours * 3600 - minutes * 60); - return new Time(hours, minutes, seconds); - } - - private static String padLeft(long n) { - if (n < 10 && n != 0) { - return "0" + Math.round(n); - } else if (n == 0) { - return "00"; - } - return Long.toString(Math.round(n)); - } + public static String generateString(long time) { + final var pt = generateTime(time); + + StringBuilder sb = new StringBuilder(); + if (pt.hours != 0) { + sb.append(pt.hours).append(" hours "); + } + if (pt.minutes != 0 || pt.hours != 0) { + sb.append(pt.minutes).append(" minutes "); + } + sb.append(pt.seconds).append(" seconds"); + + return sb.toString(); + } + + public static String generateShortString(long time) { + final var pt = generateTime(time); + + return padLeft(pt.hours) + ":" + + padLeft(pt.minutes) + ":" + + padLeft(pt.seconds); + } + + private static Time generateTime(long time) { + long hours = 0; + if (time > 3600) { + hours = Math.floorDiv(time, 3600); + } + long minutes = 0; + if (hours != 0 || time > 60) { + minutes = Math.floorDiv(time - hours * 3600, 60); + } + long seconds = (long) Math.floor(time - hours * 3600 - minutes * 60); + return new Time(hours, minutes, seconds); + } + + private static String padLeft(long n) { + if (n < 10 && n != 0) { + return "0" + Math.round(n); + } else if (n == 0) { + return "00"; + } + return Long.toString(Math.round(n)); + } + + private record Time(long hours, long minutes, long seconds) { + } } diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index 09a65fe..43d56c8 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -1,37 +1,36 @@ { - "schemaVersion": 1, - "id": "molehunt", - "version": "${version}", - "name": "Molehunt", - "description": "Molehunt mod", - "authors": [ - "Anhgelus Morhtuuzh" - ], - "contact": {}, - "license": "AGPL-3.0", - "icon": "assets/molehunt/icon.png", - "environment": "*", - "entrypoints": { - "client": [ - "world.anhgelus.molehunt.client.MolehuntClient" - ], - "server": [ - - ], - "main": [ - "world.anhgelus.molehunt.Molehunt" - ] - }, - "mixins": [ - "molehunt.mixins.json", - { - "config": "molehunt.client.mixins.json", - "environment": "client" - } - ], - "depends": { - "fabricloader": ">=${loader_version}", - "fabric-api": "*", - "minecraft": "${minecraft_version}" - } + "schemaVersion": 1, + "id": "molehunt", + "version": "${version}", + "name": "Molehunt", + "description": "Molehunt mod", + "authors": [ + "Anhgelus Morhtuuzh" + ], + "contact": {}, + "license": "AGPL-3.0", + "icon": "assets/molehunt/icon.png", + "environment": "*", + "entrypoints": { + "client": [ + "world.anhgelus.molehunt.client.MolehuntClient" + ], + "server": [ + ], + "main": [ + "world.anhgelus.molehunt.Molehunt" + ] + }, + "mixins": [ + "molehunt.mixins.json", + { + "config": "molehunt.client.mixins.json", + "environment": "client" + } + ], + "depends": { + "fabricloader": ">=${loader_version}", + "fabric-api": "*", + "minecraft": "${minecraft_version}" + } } diff --git a/src/main/resources/molehunt.mixins.json b/src/main/resources/molehunt.mixins.json index 2dc5bb9..8013886 100644 --- a/src/main/resources/molehunt.mixins.json +++ b/src/main/resources/molehunt.mixins.json @@ -1,15 +1,15 @@ { - "required": true, - "minVersion": "0.8", - "package": "world.anhgelus.molehunt.mixin", - "compatibilityLevel": "JAVA_21", - "mixins": [ - "NoJoinLeaveMessage", - "NoMsgCommand", - "NoPortals", - "WorldTimerAccess" - ], - "injectors": { - "defaultRequire": 1 - } + "required": true, + "minVersion": "0.8", + "package": "world.anhgelus.molehunt.mixin", + "compatibilityLevel": "JAVA_21", + "mixins": [ + "NoJoinLeaveMessage", + "NoMsgCommand", + "NoPortals", + "WorldTimerAccess" + ], + "injectors": { + "defaultRequire": 1 + } } -- cgit v1.2.3 From 02965b5cf44e64f12fd41fb32e0a7cc300541753 Mon Sep 17 00:00:00 2001 From: Anhgelus Morhtuuzh Date: Wed, 18 Mar 2026 13:22:53 +0100 Subject: fix(): cannot launch game due to invalid gamerule names --- .../java/world/anhgelus/molehunt/Molehunt.java | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'src/main') diff --git a/src/main/java/world/anhgelus/molehunt/Molehunt.java b/src/main/java/world/anhgelus/molehunt/Molehunt.java index 6486700..74687d1 100644 --- a/src/main/java/world/anhgelus/molehunt/Molehunt.java +++ b/src/main/java/world/anhgelus/molehunt/Molehunt.java @@ -46,51 +46,51 @@ public class Molehunt implements ModInitializer { public static final GameRule GAME_DURATION = GameRuleBuilder .forInteger(CONFIG_FILE.getOrDefault("game_duration", 90)) .category(GameRuleCategory.MISC) - .buildAndRegister(Identifier.of(MOD_ID, "gameDurationMinutes")); + .buildAndRegister(Identifier.of(MOD_ID, "game_duration_minutes")); public static final GameRule MOLE_PERCENTAGE = GameRuleBuilder .forInteger(CONFIG_FILE.getOrDefault("mole_percentage", 25)) .range(0, 100) .category(GameRuleCategory.MISC) - .buildAndRegister(Identifier.of(MOD_ID, "molePercentage")); + .buildAndRegister(Identifier.of(MOD_ID, "mole_percentage")); public static final GameRule MOLE_COUNT = GameRuleBuilder .forInteger(CONFIG_FILE.getOrDefault("mole_count", -1)) .category(GameRuleCategory.MISC) - .buildAndRegister(Identifier.of(MOD_ID, "moleCount")); + .buildAndRegister(Identifier.of(MOD_ID, "mole_count")); public static final GameRule SHOW_NAMETAGS = GameRuleBuilder .forBoolean(CONFIG_FILE.getOrDefault("show_nametags", false)) .category(GameRuleCategory.MISC) - .buildAndRegister(Identifier.of(MOD_ID, "showNametags")); + .buildAndRegister(Identifier.of(MOD_ID, "show_nametags")); public static final GameRule SHOW_TAB = GameRuleBuilder .forBoolean(CONFIG_FILE.getOrDefault("show_tab", false)) .category(GameRuleCategory.MISC) - .buildAndRegister(Identifier.of(MOD_ID, "showTab")); + .buildAndRegister(Identifier.of(MOD_ID, "show_tab")); public static final GameRule SHOW_SKINS = GameRuleBuilder .forBoolean(CONFIG_FILE.getOrDefault("show_skins", false)) .category(GameRuleCategory.MISC) - .buildAndRegister(Identifier.of(MOD_ID, "showSkins")); + .buildAndRegister(Identifier.of(MOD_ID, "show_skins")); public static final GameRule INITIAL_WORLD_SIZE = GameRuleBuilder .forInteger(CONFIG_FILE.getOrDefault("initial_world_size", 600)) .minValue(0) .category(GameRuleCategory.MISC) - .buildAndRegister(Identifier.of(MOD_ID, "initialWorldSize")); + .buildAndRegister(Identifier.of(MOD_ID, "initial_world_size")); public static final GameRule FINAL_WORLD_SIZE = GameRuleBuilder .forInteger(CONFIG_FILE.getOrDefault("final_world_size", 100)) .minValue(0) .category(GameRuleCategory.MISC) - .buildAndRegister(Identifier.of(MOD_ID, "finalWorldSize")); + .buildAndRegister(Identifier.of(MOD_ID, "final_world_size")); public static final GameRule MOVING_STARTING_TIME_OFFSET = GameRuleBuilder .forInteger(CONFIG_FILE.getOrDefault("border_moving_starting_time_offset", 30)) .minValue(0) .category(GameRuleCategory.MISC) - .buildAndRegister(Identifier.of(MOD_ID, "borderMovingStartingTimeOffsetMinutes")); + .buildAndRegister(Identifier.of(MOD_ID, "border_moving_starting_time_offset_minutes")); public static final GameRule ENABLE_PORTALS = GameRuleBuilder .forBoolean(CONFIG_FILE.getOrDefault("enable_portals", false)) .category(GameRuleCategory.MISC) - .buildAndRegister(Identifier.of(MOD_ID, "enablePortals")); + .buildAndRegister(Identifier.of(MOD_ID, "enable_portals")); public static final GameRule FOOD_ON_START = GameRuleBuilder .forBoolean(CONFIG_FILE.getOrDefault("food_on_start", true)) .category(GameRuleCategory.MISC) - .buildAndRegister(Identifier.of(MOD_ID, "foodOnStart")); + .buildAndRegister(Identifier.of(MOD_ID, "food_on_start")); public static Config CONFIG; public static HashMap timerVisibility = new HashMap<>(); -- cgit v1.2.3 From 5221052b004117e8aa2763c2a8085372391b13c4 Mon Sep 17 00:00:00 2001 From: Anhgelus Morhtuuzh Date: Wed, 18 Mar 2026 13:39:58 +0100 Subject: fix(game): #18 (last one was not fixing) --- src/main/java/world/anhgelus/molehunt/Molehunt.java | 4 ++-- src/main/java/world/anhgelus/molehunt/game/Game.java | 18 +++++++++++------- 2 files changed, 13 insertions(+), 9 deletions(-) (limited to 'src/main') diff --git a/src/main/java/world/anhgelus/molehunt/Molehunt.java b/src/main/java/world/anhgelus/molehunt/Molehunt.java index 74687d1..d31be6b 100644 --- a/src/main/java/world/anhgelus/molehunt/Molehunt.java +++ b/src/main/java/world/anhgelus/molehunt/Molehunt.java @@ -166,13 +166,13 @@ public class Molehunt implements ModInitializer { false); } else if (player.isSpectator()) { source.sendFeedback( - () -> Text.translatable("commands.molehunt.role.survivor.mole_count", game.getMoles().size()), + () -> Text.translatable("commands.molehunt.role.survivor.mole_count", game.getMolesCount()), false); } else { source.sendFeedback( () -> Text.translatable("commands.molehunt.role.survivor") .append("\n\n") - .append(Text.translatable("commands.molehunt.role.survivor.mole_count", game.getMoles().size())), + .append(Text.translatable("commands.molehunt.role.survivor.mole_count", game.getMolesCount())), false); } diff --git a/src/main/java/world/anhgelus/molehunt/game/Game.java b/src/main/java/world/anhgelus/molehunt/game/Game.java index 35c45fa..98784c3 100644 --- a/src/main/java/world/anhgelus/molehunt/game/Game.java +++ b/src/main/java/world/anhgelus/molehunt/game/Game.java @@ -22,6 +22,7 @@ import world.anhgelus.molehunt.utils.TimeUtils; import java.util.*; import java.util.concurrent.ThreadLocalRandom; import java.util.stream.Collectors; +import java.util.stream.Stream; public class Game { @@ -157,17 +158,19 @@ public class Game { return Text.of("§c" + TimeUtils.generateShortString(remaining)); } - public List getMoles() { + private Stream getMoles() { return moles.stream() .map(uuid -> server.getPlayerManager().getPlayer(uuid)) .filter(Objects::nonNull) - .filter(p -> !p.isSpectator()) - .toList(); + .filter(p -> !p.isSpectator() && !p.isCreative()); + } + + public int getMolesCount() { + return getMoles().toArray().length; } public String getMolesAsString() { - return getMoles().stream() - .map(PlayerEntity::getDisplayName) + return getMoles().map(PlayerEntity::getDisplayName) .filter(Objects::nonNull) .map(Object::toString) .collect(Collectors.joining(", ")); @@ -178,7 +181,8 @@ public class Game { } public boolean wonByMoles() { - return new HashSet<>(moles).containsAll( + final var moles = getMoles().map(PlayerEntity::getUuid).toList(); + return !moles.isEmpty() && new HashSet<>(moles).containsAll( server.getPlayerManager() .getPlayerList() .stream() @@ -195,6 +199,6 @@ public class Game { private void changeState(boolean hasStarted) { started = hasStarted; final var payload = new GamePayload(hasStarted); - server.getPlayerManager().getPlayerList().forEach(p -> ServerPlayNetworking.send(p, payload)); + server.getPlayerManager().sendToAll(ServerPlayNetworking.createS2CPacket(payload)); } } -- cgit v1.2.3