From 721eefc6c62e04c1413a846f0aeaeb8c80a5b54b Mon Sep 17 00:00:00 2001 From: Matyrobbrt Date: Sun, 1 Oct 2023 22:16:28 +0300 Subject: [PATCH] Add behaviour to glow teammates Fixes #128 --- .../core/game/behavior/GameBehaviorTypes.java | 2 + .../game/behavior/event/GameTeamEvents.java | 10 +++++ .../instances/team/SyncTeamsBehavior.java | 39 +++++++++++++++++++ .../instances/team/TeamsBehavior.java | 15 ++++--- .../client_state/GameClientStateTypes.java | 4 ++ .../instance/GlowTeamMembersState.java | 15 +++++++ .../instance/TeamMembersClientState.java | 21 ++++++++++ .../mixin/client/MinecraftMixin.java | 33 ++++++++++++++++ src/main/resources/ltminigames.mixins.json | 3 +- 9 files changed, 135 insertions(+), 7 deletions(-) create mode 100644 src/main/java/com/lovetropics/minigames/common/core/game/behavior/instances/team/SyncTeamsBehavior.java create mode 100644 src/main/java/com/lovetropics/minigames/common/core/game/client_state/instance/GlowTeamMembersState.java create mode 100644 src/main/java/com/lovetropics/minigames/common/core/game/client_state/instance/TeamMembersClientState.java create mode 100644 src/main/java/com/lovetropics/minigames/mixin/client/MinecraftMixin.java diff --git a/src/main/java/com/lovetropics/minigames/common/core/game/behavior/GameBehaviorTypes.java b/src/main/java/com/lovetropics/minigames/common/core/game/behavior/GameBehaviorTypes.java index 54e7fdd13..bd04f4523 100644 --- a/src/main/java/com/lovetropics/minigames/common/core/game/behavior/GameBehaviorTypes.java +++ b/src/main/java/com/lovetropics/minigames/common/core/game/behavior/GameBehaviorTypes.java @@ -65,6 +65,7 @@ import com.lovetropics.minigames.common.core.game.behavior.instances.statistics.PlaceByStatisticBehavior; import com.lovetropics.minigames.common.core.game.behavior.instances.statistics.TimeSurvivedTrackerBehavior; import com.lovetropics.minigames.common.core.game.behavior.instances.team.SetupTeamsBehavior; +import com.lovetropics.minigames.common.core.game.behavior.instances.team.SyncTeamsBehavior; import com.lovetropics.minigames.common.core.game.behavior.instances.team.TeamWinTrigger; import com.lovetropics.minigames.common.core.game.behavior.instances.team.TeamsBehavior; import com.lovetropics.minigames.common.core.game.behavior.instances.trigger.BindControlsBehavior; @@ -150,6 +151,7 @@ public class GameBehaviorTypes { public static final GameBehaviorEntry SET_MAX_HEALTH = register("set_max_health", SetMaxHealthBehavior.CODEC); public static final GameBehaviorEntry INDIVIDUAL_WIN_TRIGGER = register("individual_win_trigger", IndividualWinTrigger.CODEC); public static final GameBehaviorEntry TEAM_WIN_TRIGGER = register("team_win_trigger", TeamWinTrigger.CODEC); + public static final GameBehaviorEntry SYNC_TEAMS = register("sync_teams", SyncTeamsBehavior.CODEC); public static final GameBehaviorEntry EQUIP_PARTICIPANTS = register("equip_participants", EquipParticipantsBehavior.CODEC); public static final GameBehaviorEntry ARMOR_PARTICIPANTS = register("armor_participants", ArmorParticipantsBehavior.CODEC); public static final GameBehaviorEntry SET_TIME_SPEED = register("set_time_speed", SetTimeSpeedBehavior.CODEC); diff --git a/src/main/java/com/lovetropics/minigames/common/core/game/behavior/event/GameTeamEvents.java b/src/main/java/com/lovetropics/minigames/common/core/game/behavior/event/GameTeamEvents.java index a6a220fac..207db1f69 100644 --- a/src/main/java/com/lovetropics/minigames/common/core/game/behavior/event/GameTeamEvents.java +++ b/src/main/java/com/lovetropics/minigames/common/core/game/behavior/event/GameTeamEvents.java @@ -11,10 +11,20 @@ public final class GameTeamEvents { } }); + public static final GameEventType REMOVE_FROM_TEAM = GameEventType.create(RemoveFromTeam.class, listeners -> (player, teams, team) -> { + for (RemoveFromTeam listener : listeners) { + listener.onRemoveFromTeam(player, teams, team); + } + }); + private GameTeamEvents() { } public interface SetGameTeam { void onSetGameTeam(ServerPlayer player, TeamState teams, GameTeamKey team); } + + public interface RemoveFromTeam { + void onRemoveFromTeam(ServerPlayer player, TeamState teams, GameTeamKey team); + } } diff --git a/src/main/java/com/lovetropics/minigames/common/core/game/behavior/instances/team/SyncTeamsBehavior.java b/src/main/java/com/lovetropics/minigames/common/core/game/behavior/instances/team/SyncTeamsBehavior.java new file mode 100644 index 000000000..bd71c67c5 --- /dev/null +++ b/src/main/java/com/lovetropics/minigames/common/core/game/behavior/instances/team/SyncTeamsBehavior.java @@ -0,0 +1,39 @@ +package com.lovetropics.minigames.common.core.game.behavior.instances.team; + +import com.lovetropics.minigames.common.core.game.GameException; +import com.lovetropics.minigames.common.core.game.IGamePhase; +import com.lovetropics.minigames.common.core.game.behavior.IGameBehavior; +import com.lovetropics.minigames.common.core.game.behavior.event.EventRegistrar; +import com.lovetropics.minigames.common.core.game.behavior.event.GamePhaseEvents; +import com.lovetropics.minigames.common.core.game.behavior.event.GameTeamEvents; +import com.lovetropics.minigames.common.core.game.client_state.GameClientStateSender; +import com.lovetropics.minigames.common.core.game.client_state.GameClientStateTypes; +import com.lovetropics.minigames.common.core.game.client_state.instance.TeamMembersClientState; +import com.lovetropics.minigames.common.core.game.state.team.GameTeamKey; +import com.lovetropics.minigames.common.core.game.state.team.TeamState; +import com.lovetropics.minigames.common.core.network.LoveTropicsNetwork; +import com.lovetropics.minigames.common.core.network.SetGameClientStateMessage; +import com.mojang.serialization.Codec; +import net.minecraft.server.level.ServerPlayer; +import net.minecraftforge.network.PacketDistributor; + +public class SyncTeamsBehavior implements IGameBehavior { + public static final Codec CODEC = Codec.unit(SyncTeamsBehavior::new); + + @Override + public void register(IGamePhase game, EventRegistrar events) throws GameException { + events.listen(GameTeamEvents.SET_GAME_TEAM, (player, teams, team) -> sendSync(teams, team)); + events.listen(GameTeamEvents.REMOVE_FROM_TEAM, (player, teams, team) -> { + sendSync(teams, team); + GameClientStateSender.get().byPlayer(player).enqueueRemove(GameClientStateTypes.TEAM_MEMBERS.get()); + }); + + events.listen(GamePhaseEvents.STOP, reason -> LoveTropicsNetwork.CHANNEL.send(PacketDistributor.ALL.with(() -> null), SetGameClientStateMessage.remove(GameClientStateTypes.TEAM_MEMBERS.get()))); + } + + private void sendSync(TeamState teams, GameTeamKey key) { + final var team = teams.getPlayersForTeam(key); + team.forEach(player -> GameClientStateSender.get().byPlayer(player).enqueueSet(new TeamMembersClientState(team.stream().filter(p -> p != player) + .map(ServerPlayer::getUUID).toList()))); + } +} diff --git a/src/main/java/com/lovetropics/minigames/common/core/game/behavior/instances/team/TeamsBehavior.java b/src/main/java/com/lovetropics/minigames/common/core/game/behavior/instances/team/TeamsBehavior.java index c0cead6ad..dd7993dbe 100644 --- a/src/main/java/com/lovetropics/minigames/common/core/game/behavior/instances/team/TeamsBehavior.java +++ b/src/main/java/com/lovetropics/minigames/common/core/game/behavior/instances/team/TeamsBehavior.java @@ -79,8 +79,8 @@ public void register(IGamePhase game, EventRegistrar events) { events.listen(GamePhaseEvents.DESTROY, () -> onDestroy(game)); events.listen(GamePlayerEvents.ALLOCATE_ROLES, allocator -> reassignPlayerRoles(game, allocator)); - events.listen(GamePlayerEvents.SET_ROLE, this::onPlayerSetRole); - events.listen(GamePlayerEvents.LEAVE, this::removePlayerFromTeams); + events.listen(GamePlayerEvents.SET_ROLE, (player, role, lastRole) -> onPlayerSetRole(game, player, role, lastRole)); + events.listen(GamePlayerEvents.LEAVE, player -> removePlayerFromTeams(game, player)); events.listen(GamePlayerEvents.DAMAGE, this::onPlayerHurt); events.listen(GamePlayerEvents.ATTACK, this::onPlayerAttack); @@ -135,9 +135,9 @@ private void onDestroy(IGamePhase game) { } } - private void onPlayerSetRole(ServerPlayer player, @Nullable PlayerRole role, @Nullable PlayerRole lastRole) { + private void onPlayerSetRole(IGamePhase game, ServerPlayer player, @Nullable PlayerRole role, @Nullable PlayerRole lastRole) { if (lastRole == PlayerRole.PARTICIPANT && role != PlayerRole.PARTICIPANT) { - removePlayerFromTeams(player); + removePlayerFromTeams(game, player); } } @@ -166,8 +166,11 @@ private void addPlayerToTeam(IGamePhase game, ServerPlayer player, GameTeamKey t ); } - private void removePlayerFromTeams(ServerPlayer player) { - teams.removePlayer(player); + private void removePlayerFromTeams(IGamePhase game, ServerPlayer player) { + final var teamKey = teams.removePlayer(player); + if (teamKey != null) { + game.invoker(GameTeamEvents.REMOVE_FROM_TEAM).onRemoveFromTeam(player, teams, teamKey); + } ServerScoreboard scoreboard = player.server.getScoreboard(); scoreboard.removePlayerFromTeam(player.getScoreboardName()); diff --git a/src/main/java/com/lovetropics/minigames/common/core/game/client_state/GameClientStateTypes.java b/src/main/java/com/lovetropics/minigames/common/core/game/client_state/GameClientStateTypes.java index 60d852008..4816737ab 100644 --- a/src/main/java/com/lovetropics/minigames/common/core/game/client_state/GameClientStateTypes.java +++ b/src/main/java/com/lovetropics/minigames/common/core/game/client_state/GameClientStateTypes.java @@ -4,11 +4,13 @@ import com.lovetropics.minigames.LoveTropics; import com.lovetropics.minigames.common.core.game.client_state.instance.BeaconClientState; import com.lovetropics.minigames.common.core.game.client_state.instance.FogClientState; +import com.lovetropics.minigames.common.core.game.client_state.instance.GlowTeamMembersState; import com.lovetropics.minigames.common.core.game.client_state.instance.HealthTagClientState; import com.lovetropics.minigames.common.core.game.client_state.instance.ReplaceTexturesClientState; import com.lovetropics.minigames.common.core.game.client_state.instance.ResourcePackClientState; import com.lovetropics.minigames.common.core.game.client_state.instance.SidebarClientState; import com.lovetropics.minigames.common.core.game.client_state.instance.SpectatingClientState; +import com.lovetropics.minigames.common.core.game.client_state.instance.TeamMembersClientState; import com.lovetropics.minigames.common.core.game.client_state.instance.TimeInterpolationClientState; import com.lovetropics.minigames.common.util.registry.GameClientTweakEntry; import com.lovetropics.minigames.common.util.registry.LoveTropicsRegistrate; @@ -43,6 +45,8 @@ public final class GameClientStateTypes { public static final GameClientTweakEntry SIDEBAR = register("sidebar", SidebarClientState.CODEC); public static final GameClientTweakEntry BEACON = register("beacon", BeaconClientState.CODEC); public static final GameClientTweakEntry FOG = register("fog", FogClientState.CODEC); + public static final GameClientTweakEntry TEAM_MEMBERS = register("team_members", TeamMembersClientState.CODEC); + public static final GameClientTweakEntry GLOW_TEAM_MEMBERS = register("glow_team_members", Codec.unit(GlowTeamMembersState.INSTANCE)); public static GameClientTweakEntry register(final String name, final Codec codec) { return REGISTRATE.object(name) diff --git a/src/main/java/com/lovetropics/minigames/common/core/game/client_state/instance/GlowTeamMembersState.java b/src/main/java/com/lovetropics/minigames/common/core/game/client_state/instance/GlowTeamMembersState.java new file mode 100644 index 000000000..995b51364 --- /dev/null +++ b/src/main/java/com/lovetropics/minigames/common/core/game/client_state/instance/GlowTeamMembersState.java @@ -0,0 +1,15 @@ +package com.lovetropics.minigames.common.core.game.client_state.instance; + +import com.lovetropics.minigames.common.core.game.client_state.GameClientState; +import com.lovetropics.minigames.common.core.game.client_state.GameClientStateType; +import com.lovetropics.minigames.common.core.game.client_state.GameClientStateTypes; + +public class GlowTeamMembersState implements GameClientState { + public static final GlowTeamMembersState INSTANCE = new GlowTeamMembersState(); + private GlowTeamMembersState() {} + + @Override + public GameClientStateType getType() { + return GameClientStateTypes.GLOW_TEAM_MEMBERS.get(); + } +} diff --git a/src/main/java/com/lovetropics/minigames/common/core/game/client_state/instance/TeamMembersClientState.java b/src/main/java/com/lovetropics/minigames/common/core/game/client_state/instance/TeamMembersClientState.java new file mode 100644 index 000000000..fe70622fc --- /dev/null +++ b/src/main/java/com/lovetropics/minigames/common/core/game/client_state/instance/TeamMembersClientState.java @@ -0,0 +1,21 @@ +package com.lovetropics.minigames.common.core.game.client_state.instance; + +import com.lovetropics.minigames.common.core.game.client_state.GameClientState; +import com.lovetropics.minigames.common.core.game.client_state.GameClientStateType; +import com.lovetropics.minigames.common.core.game.client_state.GameClientStateTypes; +import com.mojang.serialization.Codec; +import net.minecraft.core.UUIDUtil; + +import java.util.List; +import java.util.UUID; + +public record TeamMembersClientState(List teamMembers) implements GameClientState { + public static final Codec CODEC = UUIDUtil.CODEC.listOf().fieldOf("members") + .xmap(TeamMembersClientState::new, TeamMembersClientState::teamMembers) + .codec(); + + @Override + public GameClientStateType getType() { + return GameClientStateTypes.TEAM_MEMBERS.get(); + } +} diff --git a/src/main/java/com/lovetropics/minigames/mixin/client/MinecraftMixin.java b/src/main/java/com/lovetropics/minigames/mixin/client/MinecraftMixin.java new file mode 100644 index 000000000..4837e38d2 --- /dev/null +++ b/src/main/java/com/lovetropics/minigames/mixin/client/MinecraftMixin.java @@ -0,0 +1,33 @@ +package com.lovetropics.minigames.mixin.client; + +import com.lovetropics.minigames.client.game.ClientGameStateManager; +import com.lovetropics.minigames.common.core.game.client_state.GameClientStateTypes; +import net.minecraft.client.Minecraft; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityType; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import javax.annotation.Nullable; + +@Mixin(Minecraft.class) +public class MinecraftMixin { + @Nullable + @Shadow + private LocalPlayer player; + + @Inject(at = @At("HEAD"), method = "shouldEntityAppearGlowing", cancellable = true) + private void ltminigames$glowingTeamMembers(Entity entity, CallbackInfoReturnable cir) { + if (entity.getType() == EntityType.PLAYER && ClientGameStateManager.getOrNull(GameClientStateTypes.GLOW_TEAM_MEMBERS) != null) { + final var team = ClientGameStateManager.getOrNull(GameClientStateTypes.TEAM_MEMBERS); + + if (team != null && (team.teamMembers().contains(entity.getUUID()) || player == entity)) { + cir.setReturnValue(true); + } + } + } +} diff --git a/src/main/resources/ltminigames.mixins.json b/src/main/resources/ltminigames.mixins.json index 9194843c8..6190e0651 100644 --- a/src/main/resources/ltminigames.mixins.json +++ b/src/main/resources/ltminigames.mixins.json @@ -18,7 +18,8 @@ "client.BossOverlayGuiMixin", "client.HotbarOverride", "client.PlayerTabOverlayGuiMixin", - "client.PoseStackAccessor" + "client.PoseStackAccessor", + "client.MinecraftMixin" ], "injectors": { "defaultRequire": 1