From dfbc5bbfd20a22edb2596b4d73248df57a4cce20 Mon Sep 17 00:00:00 2001 From: anhgelus Date: Sat, 24 Aug 2024 13:05:11 +0000 Subject: feat(network): send game state to client and disable mixins when game is not launched --- src/main/java/world/anhgelus/molehunt/Game.java | 178 -------------------- .../java/world/anhgelus/molehunt/Molehunt.java | 17 +- .../java/world/anhgelus/molehunt/game/Game.java | 186 +++++++++++++++++++++ .../world/anhgelus/molehunt/game/GamePayload.java | 23 +++ 4 files changed, 222 insertions(+), 182 deletions(-) delete mode 100644 src/main/java/world/anhgelus/molehunt/Game.java create mode 100644 src/main/java/world/anhgelus/molehunt/game/Game.java create mode 100644 src/main/java/world/anhgelus/molehunt/game/GamePayload.java (limited to 'src/main') diff --git a/src/main/java/world/anhgelus/molehunt/Game.java b/src/main/java/world/anhgelus/molehunt/Game.java deleted file mode 100644 index dbe7ebd..0000000 --- a/src/main/java/world/anhgelus/molehunt/Game.java +++ /dev/null @@ -1,178 +0,0 @@ -package world.anhgelus.molehunt; - -import net.minecraft.network.packet.s2c.play.OverlayMessageS2CPacket; -import net.minecraft.network.packet.s2c.play.SubtitleS2CPacket; -import net.minecraft.network.packet.s2c.play.TitleFadeS2CPacket; -import net.minecraft.network.packet.s2c.play.TitleS2CPacket; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.network.ServerPlayerEntity; -import net.minecraft.text.Text; -import net.minecraft.world.GameMode; -import net.minecraft.world.GameRules; -import world.anhgelus.molehunt.utils.TimeUtils; - -import java.util.*; -import java.util.concurrent.ThreadLocalRandom; -import java.util.stream.Collectors; - -public class Game { - - private Timer timer = new Timer(); - public final int defaultTime = Molehunt.CONFIG.getGameDuration()*60; - private int remaining = defaultTime; - - private final MinecraftServer server; - - private final List moles = new ArrayList<>(); - - private final TitleFadeS2CPacket timing = new TitleFadeS2CPacket(20, 40, 20); - - 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); - players.remove(r); - } - - final var gamerules = server.getGameRules(); - // immutable gamerules - gamerules.get(GameRules.SHOW_DEATH_MESSAGES).set(false, server); - gamerules.get(GameRules.ANNOUNCE_ADVANCEMENTS).set(false, server); - // gamerules for the start - gamerules.get(GameRules.DO_IMMEDIATE_RESPAWN).set(true, server); - gamerules.get(GameRules.DO_ENTITY_DROPS).set(false, server); - - final var title = new TitleS2CPacket(Text.translatable("molehunt.game.start.suspense")); - playerManager.getPlayerList().forEach(p -> { - p.kill(); - p.networkHandler.sendPacket(timing); - p.networkHandler.sendPacket(title); - p.changeGameMode(GameMode.SURVIVAL); - }); - - server.setDefaultGameMode(GameMode.SPECTATOR); - - timer.schedule(new TimerTask() { - @Override - public void run() { - playerManager.getPlayerList().forEach(p -> { - p.networkHandler.sendPacket(timing); - if (moles.contains(p)) { - 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"))); - } - // reset health and food level - p.setHealth(p.getMaxHealth()); - p.getHungerManager().setFoodLevel(20); - p.getHungerManager().setSaturationLevel(5.0f); - }); - // reset gamerules after the start - gamerules.get(GameRules.DO_IMMEDIATE_RESPAWN).set(false, server); - gamerules.get(GameRules.DO_ENTITY_DROPS).set(true, server); - // reset time and weather - server.getOverworld().setTimeOfDay(0); - server.getOverworld().resetWeather(); - started = true; - - timer.scheduleAtFixedRate(new TimerTask() { - @Override - public void run() { - remaining--; - playerManager.getPlayerList().forEach(player -> { - if (Molehunt.timerVisibility.getOrDefault(player, true)) { - player.networkHandler.sendPacket(new OverlayMessageS2CPacket(Text.of(getShortRemainingText()))); - } - }); - playerManager.sendToAll(timing); - if (remaining == 0) end(); - } - }, 5*1000, 1000); - } - }, 4*1000); - } - - public void stop() { - server.getPlayerManager().broadcast(Text.translatable("commands.molehunt.stop.success"), false); - end(); - } - - public void end() { - timer.cancel(); - timer = new Timer(); - started = 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.schedule(new TimerTask() { - @Override - public void run() { - TitleS2CPacket winner; - if (gameWonByMoles()) { - 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") - .append(" " + getMolesAsString())) - ); - pm.sendToAll(winner); - pm.sendToAll(timing); - moles.clear(); - } - }, 4*1000); - } - - public Text getShortRemainingText() { - return Text.of("§c" + TimeUtils.printShortTime(remaining)); - } - - public List getMoles() { - return moles; - } - - public String getMolesAsString() { - return moles.stream() - .map(ServerPlayerEntity::getDisplayName) - .filter(Objects::nonNull) - .map(Text::getString) - .collect(Collectors.joining(", ")); - } - - public boolean isAMole(ServerPlayerEntity player) { - return moles.contains(player); - } - - public boolean gameWonByMoles() { - return new HashSet<>(moles).containsAll(server.getPlayerManager().getPlayerList()); - } - - public void updateMole(ServerPlayerEntity oldPlayer, ServerPlayerEntity newPlayer) { - moles.remove(oldPlayer); - moles.add(newPlayer); - } - - public boolean hasStarted() { - return started; - } -} diff --git a/src/main/java/world/anhgelus/molehunt/Molehunt.java b/src/main/java/world/anhgelus/molehunt/Molehunt.java index d7c0d58..afd6960 100644 --- a/src/main/java/world/anhgelus/molehunt/Molehunt.java +++ b/src/main/java/world/anhgelus/molehunt/Molehunt.java @@ -24,6 +24,8 @@ import org.slf4j.LoggerFactory; import world.anhgelus.molehunt.config.Config; import world.anhgelus.molehunt.config.ConfigPayload; import world.anhgelus.molehunt.config.SimpleConfig; +import world.anhgelus.molehunt.game.Game; +import world.anhgelus.molehunt.game.GamePayload; import java.util.HashMap; @@ -150,11 +152,18 @@ public class Molehunt implements ModInitializer { newPlayer.changeGameMode(GameMode.SPECTATOR); }); - ServerPlayConnectionEvents.JOIN.register((handler, sender, server) -> ServerPlayNetworking.send( - handler.player, - new ConfigPayload(CONFIG.areNametagsEnabled(), CONFIG.areSkinsEnabled(), CONFIG.isTabEnabled()) - )); + ServerPlayConnectionEvents.JOIN.register((handler, sender, server) -> { + ServerPlayNetworking.send( + handler.player, + new ConfigPayload(CONFIG.areNametagsEnabled(), CONFIG.areSkinsEnabled(), CONFIG.isTabEnabled()) + ); + ServerPlayNetworking.send( + handler.player, + new GamePayload(game != null && game.hasStarted()) + ); + }); PayloadTypeRegistry.playS2C().register(ConfigPayload.ID, ConfigPayload.CODEC); + PayloadTypeRegistry.playS2C().register(GamePayload.ID, GamePayload.CODEC); } } diff --git a/src/main/java/world/anhgelus/molehunt/game/Game.java b/src/main/java/world/anhgelus/molehunt/game/Game.java new file mode 100644 index 0000000..a98516c --- /dev/null +++ b/src/main/java/world/anhgelus/molehunt/game/Game.java @@ -0,0 +1,186 @@ +package world.anhgelus.molehunt.game; + +import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; +import net.minecraft.network.packet.s2c.play.OverlayMessageS2CPacket; +import net.minecraft.network.packet.s2c.play.SubtitleS2CPacket; +import net.minecraft.network.packet.s2c.play.TitleFadeS2CPacket; +import net.minecraft.network.packet.s2c.play.TitleS2CPacket; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.text.Text; +import net.minecraft.world.GameMode; +import net.minecraft.world.GameRules; +import world.anhgelus.molehunt.Molehunt; +import world.anhgelus.molehunt.utils.TimeUtils; + +import java.util.*; +import java.util.concurrent.ThreadLocalRandom; +import java.util.stream.Collectors; + +public class Game { + + private Timer timer = new Timer(); + public final int defaultTime = Molehunt.CONFIG.getGameDuration()*60; + private int remaining = defaultTime; + + private final MinecraftServer server; + + private final List moles = new ArrayList<>(); + + private final TitleFadeS2CPacket timing = new TitleFadeS2CPacket(20, 40, 20); + + 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); + players.remove(r); + } + + final var gamerules = server.getGameRules(); + // immutable gamerules + gamerules.get(GameRules.SHOW_DEATH_MESSAGES).set(false, server); + gamerules.get(GameRules.ANNOUNCE_ADVANCEMENTS).set(false, server); + // gamerules for the start + gamerules.get(GameRules.DO_IMMEDIATE_RESPAWN).set(true, server); + gamerules.get(GameRules.DO_ENTITY_DROPS).set(false, server); + + final var title = new TitleS2CPacket(Text.translatable("molehunt.game.start.suspense")); + playerManager.getPlayerList().forEach(p -> { + p.kill(); + p.networkHandler.sendPacket(timing); + p.networkHandler.sendPacket(title); + p.changeGameMode(GameMode.SURVIVAL); + }); + + server.setDefaultGameMode(GameMode.SPECTATOR); + + timer.schedule(new TimerTask() { + @Override + public void run() { + playerManager.getPlayerList().forEach(p -> { + p.networkHandler.sendPacket(timing); + if (moles.contains(p)) { + 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"))); + } + // reset health and food level + p.setHealth(p.getMaxHealth()); + p.getHungerManager().setFoodLevel(20); + p.getHungerManager().setSaturationLevel(5.0f); + }); + // reset gamerules after the start + gamerules.get(GameRules.DO_IMMEDIATE_RESPAWN).set(false, server); + gamerules.get(GameRules.DO_ENTITY_DROPS).set(true, server); + // reset time and weather + server.getOverworld().setTimeOfDay(0); + server.getOverworld().resetWeather(); + changeState(true); + + timer.scheduleAtFixedRate(new TimerTask() { + @Override + public void run() { + remaining--; + playerManager.getPlayerList().forEach(player -> { + if (Molehunt.timerVisibility.getOrDefault(player, true)) { + player.networkHandler.sendPacket(new OverlayMessageS2CPacket(Text.of(getShortRemainingText()))); + } + }); + playerManager.sendToAll(timing); + if (remaining == 0) end(); + } + }, 5*1000, 1000); + } + }, 4*1000); + } + + public void stop() { + server.getPlayerManager().broadcast(Text.translatable("commands.molehunt.stop.success"), false); + end(); + } + + public void end() { + timer.cancel(); + timer = new Timer(); + 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.schedule(new TimerTask() { + @Override + public void run() { + TitleS2CPacket winner; + if (gameWonByMoles()) { + 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") + .append(" " + getMolesAsString())) + ); + pm.sendToAll(winner); + pm.sendToAll(timing); + moles.clear(); + } + }, 4*1000); + } + + public Text getShortRemainingText() { + return Text.of("§c" + TimeUtils.printShortTime(remaining)); + } + + public List getMoles() { + return moles; + } + + public String getMolesAsString() { + return moles.stream() + .map(ServerPlayerEntity::getDisplayName) + .filter(Objects::nonNull) + .map(Text::getString) + .collect(Collectors.joining(", ")); + } + + public boolean isAMole(ServerPlayerEntity player) { + return moles.contains(player); + } + + public boolean gameWonByMoles() { + return new HashSet<>(moles).containsAll(server.getPlayerManager().getPlayerList()); + } + + public void updateMole(ServerPlayerEntity oldPlayer, ServerPlayerEntity newPlayer) { + moles.remove(oldPlayer); + moles.add(newPlayer); + } + + public boolean hasStarted() { + 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 new file mode 100644 index 0000000..4f7b8ce --- /dev/null +++ b/src/main/java/world/anhgelus/molehunt/game/GamePayload.java @@ -0,0 +1,23 @@ +package world.anhgelus.molehunt.game; + +import net.minecraft.network.RegistryByteBuf; +import net.minecraft.network.codec.PacketCodec; +import net.minecraft.network.codec.PacketCodecs; +import net.minecraft.network.packet.CustomPayload; +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 CustomPayload.Id ID = new CustomPayload.Id<>(GAME_PACKET_ID); + public static final PacketCodec CODEC = PacketCodec.tuple( + PacketCodecs.BOOL, GamePayload::gameLaunched, + GamePayload::new + ); + + @Override + public Id getId() { + return ID; + } +} -- cgit v1.2.3