From 76297bb3af6c36b1d1cb8d8ed0e46d31f86b0b88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elias=20M=C3=BCller?= Date: Sun, 22 Jun 2025 10:34:27 +0200 Subject: [PATCH] WIP: basic strike handling --- .../metaGameplay/strike/CordLeak.java | 75 ++++++++++++++++ .../metaGameplay/strike/InvClear.java | 63 +++++++++++++ .../strike/OnStrikeActionListener.java | 12 +++ .../metaGameplay/strike/Strike.java | 90 +++++++++++++++++-- 4 files changed, 235 insertions(+), 5 deletions(-) create mode 100644 varo/src/main/java/eu/mhsl/craftattack/spawn/varo/appliances/metaGameplay/strike/CordLeak.java create mode 100644 varo/src/main/java/eu/mhsl/craftattack/spawn/varo/appliances/metaGameplay/strike/InvClear.java create mode 100644 varo/src/main/java/eu/mhsl/craftattack/spawn/varo/appliances/metaGameplay/strike/OnStrikeActionListener.java diff --git a/varo/src/main/java/eu/mhsl/craftattack/spawn/varo/appliances/metaGameplay/strike/CordLeak.java b/varo/src/main/java/eu/mhsl/craftattack/spawn/varo/appliances/metaGameplay/strike/CordLeak.java new file mode 100644 index 0000000..f6925d3 --- /dev/null +++ b/varo/src/main/java/eu/mhsl/craftattack/spawn/varo/appliances/metaGameplay/strike/CordLeak.java @@ -0,0 +1,75 @@ +package eu.mhsl.craftattack.spawn.varo.appliances.metaGameplay.strike; + +import com.google.common.reflect.TypeToken; +import com.google.gson.Gson; +import eu.mhsl.craftattack.spawn.core.Main; +import eu.mhsl.craftattack.spawn.core.util.IteratorUtil; +import org.bukkit.Bukkit; +import org.bukkit.Location; + +import java.io.IOException; +import java.io.Reader; +import java.io.Writer; +import java.lang.reflect.Type; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +public class CordLeak { + private static final Path saveFile = Paths.get(Main.instance().getDataFolder().getAbsolutePath(), "cordleak.json"); + private static final Map locations = new HashMap<>(); + + static { + load(); + } + + private record LocationDto(String world, double x, double y, double z, float yaw, float pitch) { + static LocationDto from(Location loc) { + return new LocationDto(loc.getWorld().getName(), loc.getX(), loc.getY(), loc.getZ(), loc.getYaw(), loc.getPitch()); + } + + Location toLocation() { + return new Location(Bukkit.getWorld(this.world), this.x, this.y, this.z, this.yaw, this.pitch); + } + } + + public static void update() { + IteratorUtil.onlinePlayers(player -> locations.put(player.getUniqueId(), player.getLocation())); + Bukkit.getScheduler().runTaskAsynchronously(Main.instance(), CordLeak::save); + } + + private static void load() { + if (!Files.exists(saveFile)) return; + try (Reader reader = Files.newBufferedReader(saveFile)) { + Type type = new TypeToken>() {}.getType(); + Map raw = new Gson().fromJson(reader, type); + for (Map.Entry entry : raw.entrySet()) { + locations.put(UUID.fromString(entry.getKey()), entry.getValue().toLocation()); + } + } catch (IOException e) { + Main.logger().warning("Failed to load CordLeak data: " + e.getMessage()); + } + } + + private static void save() { + try { + Files.createDirectories(saveFile.getParent()); + Map raw = new HashMap<>(); + for (Map.Entry entry : locations.entrySet()) { + raw.put(entry.getKey().toString(), LocationDto.from(entry.getValue())); + } + try (Writer writer = Files.newBufferedWriter(saveFile)) { + new Gson().toJson(raw, writer); + } + } catch (IOException e) { + Main.logger().warning("Failed to save CordLeak data: " + e.getMessage()); + } + } + + public static Location getLastKnownLocation(UUID uuid) { + return locations.get(uuid); + } +} diff --git a/varo/src/main/java/eu/mhsl/craftattack/spawn/varo/appliances/metaGameplay/strike/InvClear.java b/varo/src/main/java/eu/mhsl/craftattack/spawn/varo/appliances/metaGameplay/strike/InvClear.java new file mode 100644 index 0000000..135d3de --- /dev/null +++ b/varo/src/main/java/eu/mhsl/craftattack/spawn/varo/appliances/metaGameplay/strike/InvClear.java @@ -0,0 +1,63 @@ +package eu.mhsl.craftattack.spawn.varo.appliances.metaGameplay.strike; + +import com.google.common.reflect.TypeToken; +import com.google.gson.Gson; +import eu.mhsl.craftattack.spawn.core.Main; +import org.bukkit.Bukkit; + +import java.io.IOException; +import java.io.Reader; +import java.io.Writer; +import java.lang.reflect.Type; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.*; + +public class InvClear { + private static final Path saveFile = Paths.get(Main.instance().getDataFolder().getAbsolutePath(), "invClear.json"); + private static final List players = new ArrayList<>(); + + static { + load(); + } + + public static void add(UUID player) { + players.add(player); + Bukkit.getScheduler().runTaskAsynchronously(Main.instance(), InvClear::save); + } + + public static boolean contains(UUID player) { + return players.contains(player); + } + + public static void remove(UUID player) { + players.remove(player); + Bukkit.getScheduler().runTaskAsynchronously(Main.instance(), InvClear::save); + } + + private static void load() { + if (!Files.exists(saveFile)) return; + try (Reader reader = Files.newBufferedReader(saveFile)) { + Type type = new TypeToken>() {}.getType(); + List loaded = new Gson().fromJson(reader, type); + if (loaded != null) { + players.clear(); + players.addAll(loaded); + } + } catch (IOException e) { + Main.logger().warning("Failed to load InvClear data: " + e.getMessage()); + } + } + + private static void save() { + try { + Files.createDirectories(saveFile.getParent()); + try (Writer writer = Files.newBufferedWriter(saveFile)) { + new Gson().toJson(players, writer); + } + } catch (IOException e) { + Main.logger().warning("Failed to save InvClear data: " + e.getMessage()); + } + } +} diff --git a/varo/src/main/java/eu/mhsl/craftattack/spawn/varo/appliances/metaGameplay/strike/OnStrikeActionListener.java b/varo/src/main/java/eu/mhsl/craftattack/spawn/varo/appliances/metaGameplay/strike/OnStrikeActionListener.java new file mode 100644 index 0000000..0fd5a88 --- /dev/null +++ b/varo/src/main/java/eu/mhsl/craftattack/spawn/varo/appliances/metaGameplay/strike/OnStrikeActionListener.java @@ -0,0 +1,12 @@ +package eu.mhsl.craftattack.spawn.varo.appliances.metaGameplay.strike; + +import eu.mhsl.craftattack.spawn.core.appliance.ApplianceListener; +import org.bukkit.event.EventHandler; +import org.bukkit.event.player.PlayerJoinEvent; + +public class OnStrikeActionListener extends ApplianceListener { + @EventHandler + public void onJoin(PlayerJoinEvent event) { + this.getAppliance().checkJoin(event.getPlayer()); + } +} diff --git a/varo/src/main/java/eu/mhsl/craftattack/spawn/varo/appliances/metaGameplay/strike/Strike.java b/varo/src/main/java/eu/mhsl/craftattack/spawn/varo/appliances/metaGameplay/strike/Strike.java index 9d7451a..f0c0bf1 100644 --- a/varo/src/main/java/eu/mhsl/craftattack/spawn/varo/appliances/metaGameplay/strike/Strike.java +++ b/varo/src/main/java/eu/mhsl/craftattack/spawn/varo/appliances/metaGameplay/strike/Strike.java @@ -3,15 +3,40 @@ package eu.mhsl.craftattack.spawn.varo.appliances.metaGameplay.strike; import eu.mhsl.craftattack.spawn.core.Main; import eu.mhsl.craftattack.spawn.core.api.server.HttpServer; import eu.mhsl.craftattack.spawn.core.appliance.Appliance; +import eu.mhsl.craftattack.spawn.core.util.IteratorUtil; import eu.mhsl.craftattack.spawn.varo.appliances.metaGameplay.teams.Teams; import eu.mhsl.craftattack.spawn.varo.appliances.metaGameplay.teams.VaroTeam; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.ComponentBuilder; +import net.kyori.adventure.text.TextComponent; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.util.Ticks; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.OfflinePlayer; +import org.bukkit.entity.Player; +import org.bukkit.event.Listener; +import org.jetbrains.annotations.NotNull; import java.util.List; import java.util.Objects; +import java.util.Optional; import java.util.UUID; import java.util.stream.Collectors; public class Strike extends Appliance { + public Strike() { + Bukkit.getScheduler().scheduleSyncRepeatingTask( + Main.instance(), + CordLeak::update, + Ticks.TICKS_PER_SECOND, + Ticks.TICKS_PER_SECOND * 3 + ); + } + + public void leakCoordinates() { + } + @Override public void httpApi(HttpServer.ApiBuilder apiBuilder) { record StrikeInfo(List users, int totalWeight) { @@ -22,16 +47,71 @@ public class Strike extends Appliance { data.users.stream().map(UUID::toString).collect(Collectors.joining(", "))) ); - VaroTeam team = null; + VaroTeam select = null; for(UUID uuid : data.users) { - team = this.queryAppliance(Teams.class).getTeamFromPlayer(uuid); - if(team != null) break; + select = this.queryAppliance(Teams.class).getTeamFromPlayer(uuid); + if(select != null) break; } - Objects.requireNonNull(team); + Objects.requireNonNull(select); + VaroTeam team = select; - System.out.println(team.name); + switch(data.totalWeight) { + case 1 -> { + Main.logger().info(String.format("Cord leak for Team %s", team.name)); + ComponentBuilder text = Component.text() + .append( + Component.text( + String.format("Das Team %s hat einen Strike erhalten. Daher werden folgende Koordinaten des Teams veröffentlicht:", team.name), + NamedTextColor.RED + ) + ); + + data.users.forEach(uuid -> { + OfflinePlayer player = Bukkit.getOfflinePlayer(uuid); + Location cords = CordLeak.getLastKnownLocation(uuid); + if(cords == null) return; + + text.appendNewline(); + text.append(Component.text(Objects.requireNonNull(player.getName()), NamedTextColor.DARK_AQUA)); + text.append(Component.text(": ", NamedTextColor.GRAY)); + text.append(Component.text( + String.format( + "(%s) %d, %d, %d", + cords.getWorld().getName(), + cords.getBlockX(), + cords.getBlockY(), + cords.getBlockZ() + ), + NamedTextColor.AQUA) + ); + }); + + IteratorUtil.onlinePlayers(player -> player.sendMessage(text)); + } + + case 2 -> team.members.forEach(member -> { + Optional player = Optional.ofNullable(Bukkit.getPlayer(member.player.getUniqueId())); + player.ifPresentOrElse( + p -> p.getInventory().clear(), + () -> InvClear.add(member.player.getUniqueId()) + ); + }); + case 3 -> team.members.forEach(member -> member.player.banPlayer("projektausschluss")); + } return HttpServer.nothing; }); } + + public void checkJoin(@NotNull Player player) { + if(InvClear.contains(player.getUniqueId())) { + player.getInventory().clear(); + InvClear.remove(player.getUniqueId()); + } + } + + @Override + protected @NotNull List listeners() { + return List.of(new OnStrikeActionListener()); + } }