From b1f188dece4d7942df8a25b3b76765cb6cc175e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elias=20M=C3=BCller?= Date: Mon, 9 Jun 2025 13:52:39 +0200 Subject: [PATCH] generic tweaks started implementation of FightDetector --- .../spawn/core/api/client/HttpRepository.java | 7 ++- .../spawn/core/api/client/Repository.java | 5 +- .../varo/api/repositories/TeamRepository.java | 1 - .../repositories/VaroPlayerRepository.java | 19 +++++++ .../fightDetector/FightDetector.java | 36 ++++++++++++++ .../FightOnDistanceListener.java | 7 +++ .../FightOnInteractionListener.java | 27 ++++++++++ .../joinProtection/JoinProtection.java | 49 +++++++++++++------ .../teams/ConnectivityChangeListener.java | 7 +++ .../appliances/metaGameplay/teams/Teams.java | 14 +----- .../metaGameplay/teams/VaroTeam.java | 14 +----- .../metaGameplay/varoDeath/VaroDeath.java | 16 +++++- 12 files changed, 158 insertions(+), 44 deletions(-) create mode 100644 varo/src/main/java/eu/mhsl/craftattack/spawn/varo/api/repositories/VaroPlayerRepository.java create mode 100644 varo/src/main/java/eu/mhsl/craftattack/spawn/varo/appliances/metaGameplay/fightDetector/FightDetector.java create mode 100644 varo/src/main/java/eu/mhsl/craftattack/spawn/varo/appliances/metaGameplay/fightDetector/FightOnDistanceListener.java create mode 100644 varo/src/main/java/eu/mhsl/craftattack/spawn/varo/appliances/metaGameplay/fightDetector/FightOnInteractionListener.java diff --git a/core/src/main/java/eu/mhsl/craftattack/spawn/core/api/client/HttpRepository.java b/core/src/main/java/eu/mhsl/craftattack/spawn/core/api/client/HttpRepository.java index 9d3e1d1..f655f33 100644 --- a/core/src/main/java/eu/mhsl/craftattack/spawn/core/api/client/HttpRepository.java +++ b/core/src/main/java/eu/mhsl/craftattack/spawn/core/api/client/HttpRepository.java @@ -92,7 +92,12 @@ public abstract class HttpRepository extends Repository { private ReqResp execute(HttpRequest request, Class clazz) { ReqResp rawResponse = this.sendHttp(request); - Main.logger().info(String.format("HTTP-Repository fired %s, response: %s", request, rawResponse)); + Main.logger().info(String.format( + "HTTP-Repository fired %s, sending: %s, response: %s", + request, + request.bodyPublisher().orElse(HttpRequest.BodyPublishers.ofString("none")), + rawResponse + )); return new ReqResp<>(rawResponse.status(), this.gson.fromJson(rawResponse.data(), clazz)); } diff --git a/core/src/main/java/eu/mhsl/craftattack/spawn/core/api/client/Repository.java b/core/src/main/java/eu/mhsl/craftattack/spawn/core/api/client/Repository.java index b0eee01..09f6422 100644 --- a/core/src/main/java/eu/mhsl/craftattack/spawn/core/api/client/Repository.java +++ b/core/src/main/java/eu/mhsl/craftattack/spawn/core/api/client/Repository.java @@ -1,6 +1,7 @@ package eu.mhsl.craftattack.spawn.core.api.client; import com.google.gson.Gson; +import com.google.gson.GsonBuilder; import eu.mhsl.craftattack.spawn.core.Main; import org.bukkit.Bukkit; @@ -12,7 +13,9 @@ public abstract class Repository { public Repository(URI basePath) { this.basePath = basePath; - this.gson = new Gson(); + this.gson = new GsonBuilder() + .serializeNulls() + .create(); } protected void validateThread(String commandName) { diff --git a/varo/src/main/java/eu/mhsl/craftattack/spawn/varo/api/repositories/TeamRepository.java b/varo/src/main/java/eu/mhsl/craftattack/spawn/varo/api/repositories/TeamRepository.java index b98d8a7..e4b414f 100644 --- a/varo/src/main/java/eu/mhsl/craftattack/spawn/varo/api/repositories/TeamRepository.java +++ b/varo/src/main/java/eu/mhsl/craftattack/spawn/varo/api/repositories/TeamRepository.java @@ -28,7 +28,6 @@ public class TeamRepository extends HttpRepository { public ReqResp> getTeams() { var resp = this.get("team", Object.class); - System.out.println(resp.toString()); return resp .convertToTypeToken(new TypeToken>() {}.getType()) .cast(); diff --git a/varo/src/main/java/eu/mhsl/craftattack/spawn/varo/api/repositories/VaroPlayerRepository.java b/varo/src/main/java/eu/mhsl/craftattack/spawn/varo/api/repositories/VaroPlayerRepository.java new file mode 100644 index 0000000..58aa882 --- /dev/null +++ b/varo/src/main/java/eu/mhsl/craftattack/spawn/varo/api/repositories/VaroPlayerRepository.java @@ -0,0 +1,19 @@ +package eu.mhsl.craftattack.spawn.varo.api.repositories; + +import eu.mhsl.craftattack.spawn.core.api.client.HttpRepository; +import eu.mhsl.craftattack.spawn.core.api.client.ReqResp; +import eu.mhsl.craftattack.spawn.varo.api.VaroApi; +import org.jetbrains.annotations.Nullable; + +import java.util.UUID; + +public class VaroPlayerRepository extends HttpRepository { + public VaroPlayerRepository() { + super(VaroApi.getBaseUri(), new RequestModifier(null, VaroApi::authorizationHeader)); + } + + public record VaroDeath(UUID user, @Nullable UUID killer, String message) {} + public ReqResp registerDeath(VaroDeath death) { + return this.post("player/death", death, Void.class); + } +} diff --git a/varo/src/main/java/eu/mhsl/craftattack/spawn/varo/appliances/metaGameplay/fightDetector/FightDetector.java b/varo/src/main/java/eu/mhsl/craftattack/spawn/varo/appliances/metaGameplay/fightDetector/FightDetector.java new file mode 100644 index 0000000..7a774f1 --- /dev/null +++ b/varo/src/main/java/eu/mhsl/craftattack/spawn/varo/appliances/metaGameplay/fightDetector/FightDetector.java @@ -0,0 +1,36 @@ +package eu.mhsl.craftattack.spawn.varo.appliances.metaGameplay.fightDetector; + +import eu.mhsl.craftattack.spawn.core.appliance.Appliance; +import eu.mhsl.craftattack.spawn.varo.appliances.metaGameplay.teams.Teams; +import eu.mhsl.craftattack.spawn.varo.appliances.metaGameplay.teams.VaroTeam; +import org.bukkit.entity.Player; +import org.bukkit.event.Listener; +import org.jetbrains.annotations.NotNull; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class FightDetector extends Appliance { + public static final Long FIGHT_TIMEOUT = 60 * 1000L; + public final Map fights = new HashMap<>(); + + public boolean isInFight(VaroTeam team) { + Long lastFightTime = this.fights.get(team); + if(lastFightTime == null) return false; + return (System.currentTimeMillis() - lastFightTime <= FIGHT_TIMEOUT); + } + + public void setInFight(Player player) { + VaroTeam team = this.queryAppliance(Teams.class).getTeamFromPlayer(player.getUniqueId()); + this.fights.put(team, System.currentTimeMillis()); + } + + @Override + protected @NotNull List listeners() { + return List.of( + new FightOnDistanceListener(), + new FightOnInteractionListener() + ); + } +} diff --git a/varo/src/main/java/eu/mhsl/craftattack/spawn/varo/appliances/metaGameplay/fightDetector/FightOnDistanceListener.java b/varo/src/main/java/eu/mhsl/craftattack/spawn/varo/appliances/metaGameplay/fightDetector/FightOnDistanceListener.java new file mode 100644 index 0000000..ddc4d46 --- /dev/null +++ b/varo/src/main/java/eu/mhsl/craftattack/spawn/varo/appliances/metaGameplay/fightDetector/FightOnDistanceListener.java @@ -0,0 +1,7 @@ +package eu.mhsl.craftattack.spawn.varo.appliances.metaGameplay.fightDetector; + +import eu.mhsl.craftattack.spawn.core.appliance.ApplianceListener; + +class FightOnDistanceListener extends ApplianceListener { + //TODO implementation +} diff --git a/varo/src/main/java/eu/mhsl/craftattack/spawn/varo/appliances/metaGameplay/fightDetector/FightOnInteractionListener.java b/varo/src/main/java/eu/mhsl/craftattack/spawn/varo/appliances/metaGameplay/fightDetector/FightOnInteractionListener.java new file mode 100644 index 0000000..ccdbeda --- /dev/null +++ b/varo/src/main/java/eu/mhsl/craftattack/spawn/varo/appliances/metaGameplay/fightDetector/FightOnInteractionListener.java @@ -0,0 +1,27 @@ +package eu.mhsl.craftattack.spawn.varo.appliances.metaGameplay.fightDetector; + +import eu.mhsl.craftattack.spawn.core.Main; +import eu.mhsl.craftattack.spawn.core.appliance.ApplianceListener; +import eu.mhsl.craftattack.spawn.varo.appliances.metaGameplay.teams.Teams; +import eu.mhsl.craftattack.spawn.varo.appliances.metaGameplay.teams.VaroTeam; +import io.papermc.paper.event.player.PrePlayerAttackEntityEvent; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; + +class FightOnInteractionListener extends ApplianceListener { + @EventHandler + public void onAttack(PrePlayerAttackEntityEvent event) { + if(!event.willAttack()) return; + + if(event.getAttacked() instanceof Player attackedPlayer) { + Teams teamsAppliance = Main.instance().getAppliance(Teams.class); + VaroTeam attacker = teamsAppliance.getTeamFromPlayer(event.getPlayer().getUniqueId()); + VaroTeam attacked = teamsAppliance.getTeamFromPlayer(event.getAttacked().getUniqueId()); + if(attacked == null) return; + if(attacker.equals(attacked)) return; + + this.getAppliance().setInFight(event.getPlayer()); + this.getAppliance().setInFight(attackedPlayer); + } + } +} diff --git a/varo/src/main/java/eu/mhsl/craftattack/spawn/varo/appliances/metaGameplay/joinProtection/JoinProtection.java b/varo/src/main/java/eu/mhsl/craftattack/spawn/varo/appliances/metaGameplay/joinProtection/JoinProtection.java index e395176..8cdd56c 100644 --- a/varo/src/main/java/eu/mhsl/craftattack/spawn/varo/appliances/metaGameplay/joinProtection/JoinProtection.java +++ b/varo/src/main/java/eu/mhsl/craftattack/spawn/varo/appliances/metaGameplay/joinProtection/JoinProtection.java @@ -2,7 +2,7 @@ package eu.mhsl.craftattack.spawn.varo.appliances.metaGameplay.joinProtection; import eu.mhsl.craftattack.spawn.core.Main; import eu.mhsl.craftattack.spawn.core.appliance.Appliance; -import eu.mhsl.craftattack.spawn.varo.appliances.metaGameplay.teams.Teams; +import eu.mhsl.craftattack.spawn.core.util.IteratorUtil; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.util.Ticks; @@ -32,10 +32,11 @@ public class JoinProtection extends Appliance { PotionEffect blindness = new PotionEffect(PotionEffectType.DARKNESS, Ticks.TICKS_PER_SECOND * 3, 1); player.addPotionEffects(List.of(resistance, blindness)); - Bukkit.getScheduler().runTaskLater( + Bukkit.getScheduler().runTaskTimer( Main.instance(), - () -> this.protectedPlayers.remove(player.getUniqueId()), - Ticks.TICKS_PER_SECOND * resistanceDuration + this::notifyPlayers, + Ticks.TICKS_PER_SECOND, + Ticks.TICKS_PER_SECOND ); } @@ -43,18 +44,36 @@ public class JoinProtection extends Appliance { return this.protectedPlayers.get(player.getUniqueId()); } - public void cancelEvent(Player player, Cancellable event) { - var teamCountdown = Main.instance().getAppliance(Teams.class).getTeamJoinCountdown(player); - if(teamCountdown.isFree(resistanceDuration)) return; - event.setCancelled(true); + public boolean isNotProtected(Player player) { + Options options = this.protectedPlayers.get(player.getUniqueId()); + if(options == null) return true; + return options.joinTime <= System.currentTimeMillis() - (resistanceDuration * 1000L); + } - int secondsLeft = Math.abs((int) ((System.currentTimeMillis() - teamCountdown.timestampSince()) / 1000) - resistanceDuration); - player.sendActionBar( - Component.text( - String.format("Du bist in %d Sekunden angreifbar", secondsLeft), - NamedTextColor.RED - ) - ); + public void cancelEvent(Player player, Cancellable event) { + if(this.isNotProtected(player)) return; + event.setCancelled(true); + } + + public void notifyPlayers() { + IteratorUtil.onlinePlayers(player -> { + Options options = this.protectedPlayers.get(player.getUniqueId()); + if(options == null) return; + + if(this.isNotProtected(player)) { + this.protectedPlayers.remove(player.getUniqueId()); + } + + int secondsLeft = Math.abs((int) ((System.currentTimeMillis() - options.joinTime) / 1000) - resistanceDuration); + player.sendActionBar( + Component.text( + secondsLeft > 0 + ? String.format("Du bist in %d Sekunden angreifbar!", secondsLeft) + : "Du jetzt angreifbar!", + NamedTextColor.RED + ) + ); + }); } @Override diff --git a/varo/src/main/java/eu/mhsl/craftattack/spawn/varo/appliances/metaGameplay/teams/ConnectivityChangeListener.java b/varo/src/main/java/eu/mhsl/craftattack/spawn/varo/appliances/metaGameplay/teams/ConnectivityChangeListener.java index 44d59a2..9c554a5 100644 --- a/varo/src/main/java/eu/mhsl/craftattack/spawn/varo/appliances/metaGameplay/teams/ConnectivityChangeListener.java +++ b/varo/src/main/java/eu/mhsl/craftattack/spawn/varo/appliances/metaGameplay/teams/ConnectivityChangeListener.java @@ -1,5 +1,6 @@ package eu.mhsl.craftattack.spawn.varo.appliances.metaGameplay.teams; +import eu.mhsl.craftattack.spawn.core.Main; import eu.mhsl.craftattack.spawn.core.appliance.ApplianceListener; import eu.mhsl.craftattack.spawn.core.util.text.DisconnectInfo; import org.bukkit.event.EventHandler; @@ -27,6 +28,12 @@ class ConnectivityChangeListener extends ApplianceListener { @EventHandler public void onLeave(PlayerQuitEvent event) { + if(event.getReason().equals(PlayerQuitEvent.QuitReason.KICKED)) { + Main.logger().info(String.format( + "Player %s left the Server. The 'teamLeave' enforcement was skipped, since the QuitReqson is 'kicked'", + event.getPlayer().getName() + )); + } this.getAppliance().enforceTeamLeave(event.getPlayer()); } } diff --git a/varo/src/main/java/eu/mhsl/craftattack/spawn/varo/appliances/metaGameplay/teams/Teams.java b/varo/src/main/java/eu/mhsl/craftattack/spawn/varo/appliances/metaGameplay/teams/Teams.java index 35be6a4..0fa27b0 100644 --- a/varo/src/main/java/eu/mhsl/craftattack/spawn/varo/appliances/metaGameplay/teams/Teams.java +++ b/varo/src/main/java/eu/mhsl/craftattack/spawn/varo/appliances/metaGameplay/teams/Teams.java @@ -44,7 +44,7 @@ public class Teams extends Appliance implements DisplayName.Prefixed, DisplayNam .anyMatch(varoTeam -> varoTeam.hasMember(playerId) && !Objects.requireNonNull(varoTeam.getMemberById(playerId)).isDead); } - VaroTeam getTeamFromPlayer(UUID playerId) { + public VaroTeam getTeamFromPlayer(UUID playerId) { return this.teams.stream() .filter(varoTeam -> varoTeam.hasMember(playerId)) .findFirst() @@ -52,8 +52,6 @@ public class Teams extends Appliance implements DisplayName.Prefixed, DisplayNam } public void enforceTeamJoin(Player joinedPlayer) { - this.getTeamFromPlayer(joinedPlayer.getUniqueId()).joinCountdown = new VaroTeam.JoinCountdown(); - DisconnectInfo disconnectInfo = new DisconnectInfo( "Teampartner nicht beigetreten", "Deine Verbindung wurde getrennt, da dein Teampartner keine Verbindung zum Server hergestellt hat!", @@ -84,15 +82,7 @@ public class Teams extends Appliance implements DisplayName.Prefixed, DisplayNam leftPlayer.getUniqueId() ); VaroTeam team = this.getTeamFromPlayer(leftPlayer.getUniqueId()); - Bukkit.getScheduler().scheduleSyncDelayedTask( - Main.instance(), - () -> team.kickTeam(disconnectInfo), - Ticks.TICKS_PER_SECOND - ); - } - - public VaroTeam.JoinCountdown getTeamJoinCountdown(Player player) { - return this.getTeamFromPlayer(player.getUniqueId()).joinCountdown; + team.kickTeam(disconnectInfo); } @Override diff --git a/varo/src/main/java/eu/mhsl/craftattack/spawn/varo/appliances/metaGameplay/teams/VaroTeam.java b/varo/src/main/java/eu/mhsl/craftattack/spawn/varo/appliances/metaGameplay/teams/VaroTeam.java index e0dafe5..998342e 100644 --- a/varo/src/main/java/eu/mhsl/craftattack/spawn/varo/appliances/metaGameplay/teams/VaroTeam.java +++ b/varo/src/main/java/eu/mhsl/craftattack/spawn/varo/appliances/metaGameplay/teams/VaroTeam.java @@ -9,7 +9,7 @@ import java.util.List; import java.util.Objects; import java.util.UUID; -class VaroTeam { +public class VaroTeam { public static class Member { public final OfflinePlayer player; public boolean isDead; @@ -20,23 +20,11 @@ class VaroTeam { } } - public record JoinCountdown(long timestampSince) { - public JoinCountdown() { - this(System.currentTimeMillis()); - } - - public boolean isFree(int countdownSeconds) { - return this.timestampSince < System.currentTimeMillis() - (countdownSeconds * 1000L); - } - } - public final List members; public final UUID teamUuid; public final String name; public final String color; - public JoinCountdown joinCountdown; - public VaroTeam(List members, String name, String color) { this.teamUuid = UUID.randomUUID(); this.members = members; diff --git a/varo/src/main/java/eu/mhsl/craftattack/spawn/varo/appliances/metaGameplay/varoDeath/VaroDeath.java b/varo/src/main/java/eu/mhsl/craftattack/spawn/varo/appliances/metaGameplay/varoDeath/VaroDeath.java index 7dfb75a..acfd6dd 100644 --- a/varo/src/main/java/eu/mhsl/craftattack/spawn/varo/appliances/metaGameplay/varoDeath/VaroDeath.java +++ b/varo/src/main/java/eu/mhsl/craftattack/spawn/varo/appliances/metaGameplay/varoDeath/VaroDeath.java @@ -1,11 +1,15 @@ package eu.mhsl.craftattack.spawn.varo.appliances.metaGameplay.varoDeath; import eu.mhsl.craftattack.spawn.core.Main; +import eu.mhsl.craftattack.spawn.core.api.HttpStatus; +import eu.mhsl.craftattack.spawn.core.api.client.ReqResp; import eu.mhsl.craftattack.spawn.core.appliance.Appliance; import eu.mhsl.craftattack.spawn.core.util.text.DisconnectInfo; +import eu.mhsl.craftattack.spawn.varo.api.repositories.VaroPlayerRepository; import eu.mhsl.craftattack.spawn.varo.appliances.metaGameplay.teams.Teams; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; +import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import org.bukkit.event.Listener; import org.jetbrains.annotations.NotNull; @@ -13,6 +17,7 @@ import org.jetbrains.annotations.Nullable; import java.util.List; import java.util.Objects; +import java.util.Optional; public class VaroDeath extends Appliance { public void registerPlayerDeath(Player player, @Nullable Component component) { @@ -24,7 +29,16 @@ public class VaroDeath extends Appliance { player.getUniqueId() ); - //TODO send player death to backend + var death = new VaroPlayerRepository.VaroDeath( + player.getUniqueId(), + Optional.ofNullable(player.getKiller()) + .map(Entity::getUniqueId) + .orElse(null), + deathMessage + ); + + ReqResp response = this.queryRepository(VaroPlayerRepository.class).registerDeath(death); + if(response.status() != HttpStatus.OK) Main.logger().warning(String.format("Failed to send death: %s", response)); disconnectInfo.applyKick(player); Main.instance().getAppliance(Teams.class).refreshTeamList();