diff --git a/game/src/main/java/net/onelitefeather/cygnus/Cygnus.java b/game/src/main/java/net/onelitefeather/cygnus/Cygnus.java index 15c08c5..e7dd6e1 100644 --- a/game/src/main/java/net/onelitefeather/cygnus/Cygnus.java +++ b/game/src/main/java/net/onelitefeather/cygnus/Cygnus.java @@ -39,6 +39,7 @@ import net.onelitefeather.cygnus.common.util.Helper; import net.onelitefeather.cygnus.event.GameFinishEvent; import net.onelitefeather.cygnus.event.SlenderReviveEvent; +import net.onelitefeather.cygnus.event.SlenderVisibilityChangeEvent; import net.onelitefeather.cygnus.event.StaminaStateChangeEvent; import net.onelitefeather.cygnus.listener.PlayerChatListener; import net.onelitefeather.cygnus.listener.PlayerDeathListener; @@ -54,6 +55,7 @@ import net.onelitefeather.cygnus.listener.game.PlayerStartSprintingListener; import net.onelitefeather.cygnus.listener.game.PlayerStopSprintingListener; import net.onelitefeather.cygnus.listener.game.SlenderItemListener; +import net.onelitefeather.cygnus.listener.game.SlenderVisibilityChangeListener; import net.onelitefeather.cygnus.movement.CygnusEntityActionListener; import net.onelitefeather.cygnus.movement.PlayerStartSprintingEvent; import net.onelitefeather.cygnus.movement.PlayerStopSprintingEvent; @@ -65,7 +67,6 @@ import net.onelitefeather.cygnus.stamina.SlenderBarTrigger; import net.onelitefeather.cygnus.stamina.StaminaService; import net.onelitefeather.cygnus.utils.StaminaHelper; -import net.onelitefeather.cygnus.utils.ViewRuleUpdater; import net.onelitefeather.cygnus.view.GameView; import net.onelitefeather.cygnus.view.GameViewImpl; import org.jetbrains.annotations.NotNull; @@ -143,8 +144,9 @@ private void registerGameListener() { Supplier phaseSupplier = this.linearPhaseSeries::getCurrentPhase; var manager = MinecraftServer.getGlobalEventHandler(); - SlenderBarTrigger trigger = new SlenderBarTrigger(this.staminaService::getSlenderBar, this::triggerViewRuleUpdate); + SlenderBarTrigger trigger = new SlenderBarTrigger(this.staminaService::getSlenderBar); new SlenderItemListener(trigger, manager); + manager.addListener(SlenderVisibilityChangeEvent.class, new SlenderVisibilityChangeListener()); manager.addListener(GameFinishEvent.class, new GameFinishListener()); manager.addListener(GameStartEvent.class, new GameStartListener(this.teamService, this.ambientProvider, this.staminaService, this.pageProvider)); manager.addListener(PlayerDeathEvent.class, new PlayerDeathListener(phaseSupplier, this.teamService)); @@ -182,8 +184,4 @@ private void finishGame() { this.ambientProvider.stopTask(); MinecraftServer.getPacketListenerManager().setPlayListener(ClientEntityActionPacket.class, EntityActionListener::listener); } - - private void triggerViewRuleUpdate(@NotNull Player player) { - ViewRuleUpdater.updateViewer(player, this.teamService.getTeams().get(TeamHelper.SURVIVOR_TEAM_ID)); - } } diff --git a/game/src/main/java/net/onelitefeather/cygnus/event/SlenderVisibilityChangeEvent.java b/game/src/main/java/net/onelitefeather/cygnus/event/SlenderVisibilityChangeEvent.java new file mode 100644 index 0000000..5614e8b --- /dev/null +++ b/game/src/main/java/net/onelitefeather/cygnus/event/SlenderVisibilityChangeEvent.java @@ -0,0 +1,46 @@ +package net.onelitefeather.cygnus.event; + +import net.minestom.server.entity.Player; +import net.minestom.server.event.trait.PlayerEvent; + +/** + * Called when the slender changes their visibility state. + * + * @author theEvilReaper + * @version 1.0.0 + * @since 2.6.6 + **/ +@SuppressWarnings("java:S6206") +public final class SlenderVisibilityChangeEvent implements PlayerEvent { + + private final Player player; + private final boolean hidden; + + /** + * Creates a new instance of the {@link SlenderVisibilityChangeEvent}. + * + * @param player the slender player whose visibility changed + * @param hidden true if the slender is now hidden, false if visible + */ + public SlenderVisibilityChangeEvent(Player player, boolean hidden) { + this.player = player; + this.hidden = hidden; + } + + /** + * {@inheritDoc} + */ + @Override + public Player getPlayer() { + return this.player; + } + + /** + * Returns whether the slender is now hidden. + * + * @return true if hidden, false if visible + */ + public boolean isHidden() { + return hidden; + } +} diff --git a/game/src/main/java/net/onelitefeather/cygnus/listener/game/GameStartListener.java b/game/src/main/java/net/onelitefeather/cygnus/listener/game/GameStartListener.java index 5030301..0376dfd 100644 --- a/game/src/main/java/net/onelitefeather/cygnus/listener/game/GameStartListener.java +++ b/game/src/main/java/net/onelitefeather/cygnus/listener/game/GameStartListener.java @@ -41,7 +41,6 @@ public void accept(GameStartEvent event) { var message = Messages.getSurvivorJoinMessage(String.valueOf(this.pageProvider.getMaxPageAmount())); this.teamService.getTeams().get(TeamHelper.SURVIVOR_TEAM_ID).getPlayers().forEach(player -> { player.sendMessage(message); - player.setTag(Tags.HIDDEN, SlenderBarHelper.VISIBLE); }); TeamHelper.updateTabList(this.teamService); PacketSendingUtils.broadcastPlayPacket(slenderPlayer.getMetadataPacket()); diff --git a/game/src/main/java/net/onelitefeather/cygnus/listener/game/SlenderReviveListener.java b/game/src/main/java/net/onelitefeather/cygnus/listener/game/SlenderReviveListener.java index 670349a..749e96c 100644 --- a/game/src/main/java/net/onelitefeather/cygnus/listener/game/SlenderReviveListener.java +++ b/game/src/main/java/net/onelitefeather/cygnus/listener/game/SlenderReviveListener.java @@ -1,9 +1,11 @@ package net.onelitefeather.cygnus.listener.game; +import net.minestom.server.MinecraftServer; import net.minestom.server.entity.Player; import net.onelitefeather.cygnus.common.Tags; import net.onelitefeather.cygnus.common.map.GameMap; import net.onelitefeather.cygnus.event.SlenderReviveEvent; +import net.onelitefeather.cygnus.event.SlenderVisibilityChangeEvent; import net.onelitefeather.cygnus.stamina.StaminaService; import net.onelitefeather.cygnus.team.TeamHelper; import net.onelitefeather.cygnus.utils.Items; @@ -32,6 +34,7 @@ public void accept(SlenderReviveEvent event) { Player player = event.getPlayer(); staminaService.setSlenderBar(player, true); player.setTag(Tags.TEAM_ID, TeamHelper.SLENDER_TEAM_ID); + MinecraftServer.getGlobalEventHandler().call(new SlenderVisibilityChangeEvent(player, false)); player.teleport(gameMap.getSlenderSpawn()); Items.setSlenderEye(player); } diff --git a/game/src/main/java/net/onelitefeather/cygnus/listener/game/SlenderVisibilityChangeListener.java b/game/src/main/java/net/onelitefeather/cygnus/listener/game/SlenderVisibilityChangeListener.java new file mode 100644 index 0000000..064ce61 --- /dev/null +++ b/game/src/main/java/net/onelitefeather/cygnus/listener/game/SlenderVisibilityChangeListener.java @@ -0,0 +1,23 @@ +package net.onelitefeather.cygnus.listener.game; + +import net.minestom.server.entity.Player; +import net.onelitefeather.cygnus.event.SlenderVisibilityChangeEvent; + +import java.util.function.Consumer; + +/** + * Listens for the {@link SlenderVisibilityChangeEvent} to update the visibility rule of the Slender. + * + * @author theEvilReaper + * @version 1.0.0 + * @since 1.0.0 + */ +public final class SlenderVisibilityChangeListener implements Consumer { + + @Override + public void accept(SlenderVisibilityChangeEvent event) { + Player slender = event.getPlayer(); + boolean hidden = event.isHidden(); + slender.updateViewableRule(viewer -> !hidden); + } +} diff --git a/game/src/main/java/net/onelitefeather/cygnus/stamina/SlenderBarTrigger.java b/game/src/main/java/net/onelitefeather/cygnus/stamina/SlenderBarTrigger.java index a64e9e4..f8a2459 100644 --- a/game/src/main/java/net/onelitefeather/cygnus/stamina/SlenderBarTrigger.java +++ b/game/src/main/java/net/onelitefeather/cygnus/stamina/SlenderBarTrigger.java @@ -1,11 +1,12 @@ package net.onelitefeather.cygnus.stamina; +import net.minestom.server.event.EventDispatcher; import net.onelitefeather.cygnus.team.TeamHelper; -import net.theevilreaper.aves.util.functional.PlayerConsumer; import net.kyori.adventure.sound.Sound; import net.minestom.server.entity.Player; import net.minestom.server.sound.SoundEvent; import net.onelitefeather.cygnus.common.Tags; +import net.onelitefeather.cygnus.event.SlenderVisibilityChangeEvent; import org.jetbrains.annotations.Nullable; import java.util.function.Supplier; @@ -25,7 +26,6 @@ public final class SlenderBarTrigger { private static final Sound ABORT_SOUND = Sound.sound(SoundEvent.ENTITY_ITEM_BREAK, Sound.Source.MASTER, 1F, 0F); private final Supplier<@Nullable StaminaBar> slenderBarSupplier; - private final PlayerConsumer updateRuneFunction; private long lastSoundTimeStamp = 0; @@ -33,11 +33,9 @@ public final class SlenderBarTrigger { * Creates a new instance of this class. * * @param slenderBarSupplier the supplier to get the {@link SlenderBar} - * @param updateRuneFunction the function to update the rune status */ - public SlenderBarTrigger(Supplier<@Nullable StaminaBar> slenderBarSupplier, PlayerConsumer updateRuneFunction) { + public SlenderBarTrigger(Supplier<@Nullable StaminaBar> slenderBarSupplier) { this.slenderBarSupplier = slenderBarSupplier; - this.updateRuneFunction = updateRuneFunction; } /** @@ -57,7 +55,6 @@ public void trigger(Player player) { lastSoundTimeStamp = System.currentTimeMillis() + COOLDOWN_TIME; if (slenderBar.changeStatus()) { this.changeVisibilityStatus(player); - this.updateRuneFunction.accept(player); } } @@ -69,6 +66,8 @@ public void trigger(Player player) { private void changeVisibilityStatus(Player player) { Byte value = player.getTag(Tags.HIDDEN); byte currentValue = value != null ? value : SlenderBarHelper.VISIBLE; - player.setTag(Tags.HIDDEN, currentValue == SlenderBarHelper.VISIBLE ? SlenderBarHelper.HIDDEN : SlenderBarHelper.VISIBLE); + byte newValue = currentValue == SlenderBarHelper.VISIBLE ? SlenderBarHelper.HIDDEN : SlenderBarHelper.VISIBLE; + player.setTag(Tags.HIDDEN, newValue); + EventDispatcher.call(new SlenderVisibilityChangeEvent(player, newValue == SlenderBarHelper.HIDDEN)); } } diff --git a/game/src/main/java/net/onelitefeather/cygnus/team/TeamHelper.java b/game/src/main/java/net/onelitefeather/cygnus/team/TeamHelper.java index 0be75c2..53d3312 100644 --- a/game/src/main/java/net/onelitefeather/cygnus/team/TeamHelper.java +++ b/game/src/main/java/net/onelitefeather/cygnus/team/TeamHelper.java @@ -1,7 +1,8 @@ package net.onelitefeather.cygnus.team; +import net.minestom.server.event.EventDispatcher; import net.onelitefeather.cygnus.common.strategy.TeleportStrategy; -import net.onelitefeather.cygnus.utils.ViewRuleUpdater; +import net.onelitefeather.cygnus.event.SlenderVisibilityChangeEvent; import net.theevilreaper.aves.util.Players; import net.theevilreaper.xerus.api.team.Team; import net.theevilreaper.xerus.api.team.TeamService; @@ -83,7 +84,7 @@ private static Player selectSlenderPlayer() { */ private static void assignSlender(Player player, Team slenderTeam) { player.setTag(Tags.TEAM_ID, SLENDER_TEAM_ID); - player.updateViewableRule(ViewRuleUpdater::viewableRuleForSlender); + EventDispatcher.call(new SlenderVisibilityChangeEvent(player, false)); slenderTeam.addPlayer(player); } diff --git a/game/src/main/java/net/onelitefeather/cygnus/utils/ViewRuleUpdater.java b/game/src/main/java/net/onelitefeather/cygnus/utils/ViewRuleUpdater.java deleted file mode 100644 index cee972a..0000000 --- a/game/src/main/java/net/onelitefeather/cygnus/utils/ViewRuleUpdater.java +++ /dev/null @@ -1,48 +0,0 @@ -package net.onelitefeather.cygnus.utils; - -import net.theevilreaper.xerus.api.team.Team; -import net.minestom.server.MinecraftServer; -import net.minestom.server.entity.Player; -import net.onelitefeather.cygnus.common.Tags; -import net.onelitefeather.cygnus.stamina.SlenderBarHelper; - -public final class ViewRuleUpdater { - - public static boolean isViewAble(Player player) { - return player.hasTag(Tags.HIDDEN) && player.getTag(Tags.HIDDEN) == SlenderBarHelper.HIDDEN; - } - - public static void updateViewer(Player target, Team survivor) { - for (Player onlinePlayer : MinecraftServer.getConnectionManager().getOnlinePlayers()) { - if (onlinePlayer.getUuid().equals(target.getUuid())) continue; - onlinePlayer.updateViewableRule(); - } - survivor.getPlayers().forEach(ViewRuleUpdater::showSlender); - showSurvivor(target); - target.updateViewableRule(); - survivor.getPlayers().forEach(Player::updateViewableRule); - } - - public static void showSurvivor(Player player) { - if (isViewAble(player)) { - player.setTag(Tags.HIDDEN, SlenderBarHelper.VISIBLE); - } else { - player.setTag(Tags.HIDDEN, SlenderBarHelper.HIDDEN); - } - } - - public static void showSlender(Player player) { - if (!isViewAble(player)) { - player.setTag(Tags.HIDDEN, SlenderBarHelper.HIDDEN); - } else { - player.setTag(Tags.HIDDEN, SlenderBarHelper.VISIBLE); - } - } - - public static boolean viewableRuleForSlender(Player player) { - return player.hasTag(Tags.HIDDEN) && player.getTag(Tags.HIDDEN) == SlenderBarHelper.HIDDEN; - } - - private ViewRuleUpdater() { - } -} diff --git a/game/src/test/java/net/onelitefeather/cygnus/listener/game/SlenderVisibilityChangeListenerTest.java b/game/src/test/java/net/onelitefeather/cygnus/listener/game/SlenderVisibilityChangeListenerTest.java new file mode 100644 index 0000000..12eea0a --- /dev/null +++ b/game/src/test/java/net/onelitefeather/cygnus/listener/game/SlenderVisibilityChangeListenerTest.java @@ -0,0 +1,57 @@ +package net.onelitefeather.cygnus.listener.game; + +import net.minestom.server.entity.Player; +import net.minestom.server.instance.Instance; +import net.minestom.testing.Env; +import net.minestom.testing.extension.MicrotusExtension; +import net.onelitefeather.cygnus.event.SlenderVisibilityChangeEvent; +import org.jetbrains.annotations.NotNull; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@ExtendWith(MicrotusExtension.class) +class SlenderVisibilityChangeListenerTest { + + @Test + void testSlenderHidden(@NotNull Env env) { + Instance instance = env.createFlatInstance(); + Player slender = env.createPlayer(instance); + Player viewer = env.createPlayer(instance); + + // Register the listener to the test environment's EventNode + env.process().eventHandler().addListener(SlenderVisibilityChangeEvent.class, new SlenderVisibilityChangeListener()); + + // Fire the event via Minestom's event handler + SlenderVisibilityChangeEvent event = new SlenderVisibilityChangeEvent(slender, true); + env.process().eventHandler().call(event); + + assertFalse(slender.isViewer(viewer), "Slender should be hidden to viewers"); + + env.destroyInstance(instance, true); + } + + @Test + void testSlenderVisible(@NotNull Env env) { + Instance instance = env.createFlatInstance(); + Player slender = env.createPlayer(instance); + Player viewer = env.createPlayer(instance); + + // Register the listener to the test environment's EventNode + env.process().eventHandler().addListener(SlenderVisibilityChangeEvent.class, new SlenderVisibilityChangeListener()); + + // Set up the state first as hidden, to test visibility toggle + slender.updateViewableRule(v -> false); + assertFalse(slender.isViewer(viewer)); + + // Fire the event via Minestom's event handler + SlenderVisibilityChangeEvent event = new SlenderVisibilityChangeEvent(slender, false); + env.process().eventHandler().call(event); + + assertTrue(slender.isViewer(viewer), "Slender should be visible to viewers"); + + env.destroyInstance(instance, true); + } +}