package org.biltopia; import org.bukkit.*; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.block.Action; import org.bukkit.event.entity.EntityDamageEvent; import org.bukkit.event.entity.PlayerDeathEvent; import org.bukkit.event.player.*; import org.bukkit.inventory.ItemStack; import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.scoreboard.Scoreboard; import org.bukkit.scoreboard.ScoreboardManager; import org.bukkit.scoreboard.Team; import org.bukkit.util.io.BukkitObjectInputStream; import org.bukkit.util.io.BukkitObjectOutputStream; import javax.annotation.Nullable; import java.io.*; import java.util.*; record Data(Map playerGroups, Map> uuidMap) implements Serializable { } public class Main extends JavaPlugin implements Listener { private final Map playerGroups = new HashMap<>(); private static final double MAX_DISTANCE_SQUARED = 200.0; private static final String FILEPATH = "dump"; private final Map> uuidMap = new HashMap<>(); private final List colors = List.of( ChatColor.BLUE, ChatColor.RED, ChatColor.DARK_BLUE, ChatColor.DARK_PURPLE, ChatColor.DARK_AQUA, ChatColor.DARK_GRAY, ChatColor.DARK_GREEN, ChatColor.WHITE, ChatColor.AQUA, ChatColor.BLACK, ChatColor.GOLD, ChatColor.YELLOW, ChatColor.LIGHT_PURPLE ); private static ScoreboardManager sm; private static Scoreboard scoreboard; @Override public void onEnable() { getLogger().info("onEnable is called!"); getServer().getPluginManager().registerEvents(this, this); Objects.requireNonNull(getCommand("groupAdd")).setExecutor(this::addToGroupCommand); Objects.requireNonNull(getCommand("groupRemove")).setExecutor(this::removeFromGroupCommand); Objects.requireNonNull(getCommand("groupList")).setExecutor(this::groupListCommand); Objects.requireNonNull(getCommand("groupsSave")).setExecutor(this::groupsSaveCommand); Objects.requireNonNull(getCommand("groupsLoad")).setExecutor(this::groupsLoadCommand); Objects.requireNonNull(getCommand("startSaving")).setExecutor(this::startSavingCommand); sm = Bukkit.getScoreboardManager(); scoreboard = sm.getMainScoreboard(); scoreboard.getTeams().forEach(Team::unregister); loadData(); } @Override public void onDisable() { getLogger().info("onDisable is called!"); saveData(); } public boolean saveData() { try { BukkitObjectOutputStream out = new BukkitObjectOutputStream(new FileOutputStream(FILEPATH)); Data data = new Data(playerGroups, uuidMap); out.writeObject(data); out.close(); getLogger().info("Saved groups!"); return true; } catch (IOException e) { System.out.println(e.toString()); return false; } } public boolean loadData() { try { BukkitObjectInputStream in = new BukkitObjectInputStream(new FileInputStream(FILEPATH)); Data data = (Data) in.readObject(); in.close(); for (Map.Entry entry : data.playerGroups().entrySet()) { Player player = Bukkit.getPlayer(entry.getKey()); if (player != null) { addPlayer(player, entry.getValue()); } else { OfflinePlayer offline = Bukkit.getOfflinePlayer(entry.getKey()); addPlayer(offline,entry.getValue()); } } return true; } catch (ClassNotFoundException | IOException e) { System.out.println(e); return false; } } private double getDistanceSquared(Location loc, Location loc2) { return Math.pow(loc.getX() - loc2.getX(), 2) + Math.pow(loc.getZ() - loc2.getZ(), 2); } @Nullable private Location getGroupCenter(Player player) { if (playerGroups.containsKey(player.getUniqueId())) { // Calculate center of locations double x = 0.0; double y = 0.0; double z = 0.0; ArrayList list = uuidMap.get(playerGroups.get(player.getUniqueId())); int size = 0; for (UUID id : list) { Player p = Bukkit.getPlayer(id); if (p != null) { size++; x += p.getLocation().getX(); y += p.getLocation().getY(); z += p.getLocation().getZ(); } } x /= size; y /= size; z /= size; return new Location(player.getWorld(), x, y, z); } return null; } @EventHandler public void onPlayerMove(PlayerMoveEvent event) { if (event.getFrom().getX() != event.getTo().getX() || event.getFrom().getZ() != event.getTo().getZ() || event.getFrom().getY() != event.getTo().getY()) { Player player = event.getPlayer(); Location center = getGroupCenter(player); if (center != null) { double distanceFrom = getDistanceSquared(event.getFrom(), center); double distanceTo = getDistanceSquared(event.getTo(), center); if (distanceTo > MAX_DISTANCE_SQUARED && distanceTo > distanceFrom) { event.setCancelled(true); player.sendMessage(ChatColor.RED + "You're too far from your group!!"); } } } } @EventHandler void onRightClick(PlayerInteractEvent event) { if ((event.getAction() == Action.RIGHT_CLICK_AIR || event.getAction() == Action.RIGHT_CLICK_BLOCK) && event.getMaterial() == Material.COMPASS && playerGroups.containsKey(event.getPlayer().getUniqueId())) { event.getPlayer().setCompassTarget(Objects.requireNonNull(getGroupCenter(event.getPlayer()))); event.getPlayer().sendMessage(ChatColor.BLUE + "Updated compass direction to group center."); } } @EventHandler public void onPlayerJoin(PlayerJoinEvent event) { Player player = event.getPlayer(); player.setGlowing(true); if (playerGroups.containsKey(player.getUniqueId())) { for (UUID id : uuidMap.get(playerGroups.get(player.getUniqueId()))) { Player p = Bukkit.getPlayer(id); if (p != null && p.getUniqueId() != player.getUniqueId()) { player.teleport(p); return; } } } } @EventHandler public void onPlayerTeleport(PlayerTeleportEvent event) { UUID uuid = event.getPlayer().getUniqueId(); if (event.getCause() != PlayerTeleportEvent.TeleportCause.PLUGIN && playerGroups.containsKey(uuid) && event.getTo() != null) { for (UUID id : uuidMap.get(playerGroups.get(uuid))) { Player p = Bukkit.getPlayer(id); if (p != null && p.getUniqueId() != uuid && event.getTo().getWorld() != null && (p.getWorld().getEnvironment() != event.getTo().getWorld().getEnvironment() || getDistanceSquared(p.getLocation(), event.getTo()) > MAX_DISTANCE_SQUARED)) { p.teleport(event.getTo()); } } } } @EventHandler public void onSpawnChange(PlayerSpawnChangeEvent event) { if (event.getCause() == PlayerSpawnChangeEvent.Cause.RESPAWN_ANCHOR) { event.getPlayer().sendMessage(ChatColor.RED + "Not supported, sorry..."); event.setCancelled(true); } } @EventHandler public void onSpawnBed(PlayerBedEnterEvent event) { Player player = event.getPlayer(); if (playerGroups.containsKey(player.getUniqueId())) { for (UUID id : uuidMap.get(playerGroups.get(player.getUniqueId()))) { Player p = Bukkit.getPlayer(id); if (p != null) { p.setBedSpawnLocation(event.getBed().getLocation()); } } } } @EventHandler public void onPlayerDeath(PlayerDeathEvent event) { Player player = event.getEntity(); EntityDamageEvent damageEvent = player.getLastDamageCause(); if (damageEvent != null && damageEvent.getCause() == EntityDamageEvent.DamageCause.CUSTOM) { event.setKeepInventory(true); event.getDrops().clear(); } else if (playerGroups.containsKey(player.getUniqueId())) { uuidMap.get(playerGroups.get(player.getUniqueId())).forEach(uuid -> { Player target = Bukkit.getPlayer(uuid); if (target != null && target.getUniqueId() != player.getUniqueId()) { target.setLastDamageCause(new EntityDamageEvent(target, EntityDamageEvent.DamageCause.CUSTOM, 0)); target.setHealth(0); } }); } } @EventHandler public void onPlayerRespawn(PlayerRespawnEvent event) { Player player = event.getPlayer(); if (playerGroups.containsKey(player.getUniqueId()) && !player.getInventory().contains(Material.COMPASS)) { player.getInventory().addItem(new ItemStack(Material.COMPASS, 1)); } } private void addPlayer(OfflinePlayer player, Integer index) { if (player.getName() == null) { getLogger().warning("Player name not found"); return; }; ArrayList list = uuidMap.getOrDefault(index, new ArrayList<>()); playerGroups.put(player.getUniqueId(), index); list.add(player.getUniqueId()); if (!uuidMap.containsKey(index)) { uuidMap.put(index, list); Team team = scoreboard.registerNewTeam(index.toString()); if (index == 69) { team.setColor(ChatColor.MAGIC); } else { team.setColor(colors.get(index % colors.size())); } team.setPrefix("Team " + index.toString() + " "); team.setAllowFriendlyFire(false); team.addEntry(player.getName()); } else { Team team = scoreboard.getTeam(index.toString()); if (team != null) { team.addEntry(player.getName()); } } if (player instanceof Player onlinePlayer) { onlinePlayer.sendMessage(ChatColor.GREEN + "You have been added to team " + index.toString()); if (!onlinePlayer.getInventory().contains(Material.COMPASS)) { onlinePlayer.getInventory().addItem(new ItemStack(Material.COMPASS, 1)); } } } public boolean addToGroupCommand(CommandSender sender, Command cmd, String label, String[] args) { try { if (args.length == 2) { Player player = Bukkit.getPlayerExact(args[0]); if (player != null && !playerGroups.containsKey(player.getUniqueId())) { Integer index = Integer.parseInt(args[1]); addPlayer(player, index); } else { sender.sendMessage("Player " + args[0] + " does not exist."); } } else { sender.sendMessage("groupAdd usage: /groupAdd "); return false; } } catch (NumberFormatException ex) { sender.sendMessage(ChatColor.RED + "usage: /groupAdd "); return false; } return true; } public boolean removeFromGroupCommand(CommandSender sender, Command cmd, String label, String[] args) { if (args.length > 0) { Player player = Bukkit.getPlayerExact(args[0]); if (player != null) { if (playerGroups.containsKey(player.getUniqueId())) { Integer index = playerGroups.get(player.getUniqueId()); ArrayList list = uuidMap.get(index); list.remove(player.getUniqueId()); playerGroups.remove(player.getUniqueId()); player.sendMessage(ChatColor.RED + "You have been removed from your team"); Team team = scoreboard.getTeam(index.toString()); if (team != null) { team.removeEntry(player.getName()); } } else { getLogger().warning("Player not in group!"); } } else { getLogger().warning("Player " + args[0] + " does not exist."); } } else { getLogger().warning("groupAdd usage: /groupAdd "); return false; } return true; } public boolean groupListCommand(CommandSender sender, Command cmd, String label, String[] args) { if (sender instanceof Player player) { uuidMap.forEach((num, list) -> { player.sendMessage(ChatColor.BLUE + "Group: " + num); list.forEach(item -> { OfflinePlayer p = Bukkit.getPlayer(item); if (p == null) { p = Bukkit.getOfflinePlayer(item); } player.sendMessage((p.isOnline() ? ChatColor.GREEN : ChatColor.RED) + " " + p.getName()); }); }); return true; } return false; } public boolean groupsSaveCommand(CommandSender sender, Command cmd, String label, String[] args) { return this.saveData(); } public boolean groupsLoadCommand(CommandSender sender, Command cmd, String label, String[] args) { return this.loadData(); } public boolean startSavingCommand(CommandSender sender, Command cmd, String label, String[] args) { new SaveTask(this).runTaskTimer(this, 0, 400); return true; } }