/* * CraftZ * Copyright (C) JangoBrick <http://jangobrick.de/> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package craftZ.modules; import java.util.*; import java.util.Map.Entry; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.entity.EntityDamageEvent; import org.bukkit.event.entity.PlayerDeathEvent; import org.bukkit.event.player.PlayerChangedWorldEvent; import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.player.PlayerKickEvent; import org.bukkit.event.player.PlayerMoveEvent; import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.PlayerInventory; import org.bukkit.potion.PotionEffect; import org.bukkit.potion.PotionEffectType; import org.bukkit.util.Vector; import craftZ.CraftZ; import craftZ.Module; import craftZ.util.ItemRenamer; import craftZ.util.Rewarder.RewardType; import craftZ.worldData.PlayerData; import craftZ.worldData.PlayerSpawnpoint; import craftZ.worldData.WorldData; public class PlayerManager extends Module { private List<PlayerSpawnpoint> spawns = new ArrayList<PlayerSpawnpoint>(); private Map<UUID, PlayerData> players = new HashMap<UUID, PlayerData>(); private Map<UUID, Integer> movingPlayers = new HashMap<UUID, Integer>(); private Map<UUID, Long> lastDeaths = new HashMap<UUID, Long>(); public PlayerManager(CraftZ craftZ) { super(craftZ); } public static Player p(UUID uuid) { return Bukkit.getPlayer(uuid); } @Override public void onLoad(boolean configReload) { spawns.clear(); ConfigurationSection sec = WorldData.get().getConfigurationSection("Data.playerspawns"); if (sec != null) { for (String entry : sec.getKeys(false)) { ConfigurationSection data = sec.getConfigurationSection(entry); PlayerSpawnpoint spawn = new PlayerSpawnpoint(this, data); spawns.add(spawn); } } for (Player p : world().getPlayers()) { joinPlayer(p); } } @Override public void onDisable() { saveAllPlayers(); } @EventHandler(priority = EventPriority.HIGHEST) public void onPlayerJoin(PlayerJoinEvent event) { Player p = event.getPlayer(); if (isWorld(p.getWorld())) { joinPlayer(p); } } @EventHandler(priority = EventPriority.HIGHEST) public void onWorldChanged(PlayerChangedWorldEvent event) { Player p = event.getPlayer(); World w = p.getWorld(); World f = event.getFrom(); if (isWorld(f)) { savePlayer(p); } else if (isWorld(w)) { joinPlayer(p); } } public void joinPlayer(Player p) { if (existsInConfig(p)) { loadPlayer(p, false, null); } else { boolean reset = getConfig("config").getBoolean("Config.players.reset-in-lobby"); if (reset || p.getHealth() == 0) p.setHealth(p.getMaxHealth()); if (reset) { p.setFoodLevel(20); p.getInventory().clear(); p.getInventory().setArmorContents(new ItemStack[4]); } p.teleport(getLobby()); Kit kit = getCraftZ().getKits().getDefaultKit(); if (kit != null) { kit.select(p); } } } @EventHandler(priority = EventPriority.HIGHEST) public void onPlayerQuit(PlayerQuitEvent event) { Player p = event.getPlayer(); if (isWorld(p.getWorld())) { savePlayer(p); } } @EventHandler(priority = EventPriority.HIGHEST) public void onPlayerKick(PlayerKickEvent event) { Player p = event.getPlayer(); if (isWorld(p.getWorld())) { if (!event.getReason().startsWith(getCraftZ().getPrefix())) { savePlayer(p); } } } @EventHandler(priority = EventPriority.HIGHEST) public void onPlayerDeath(PlayerDeathEvent event) { final Player p = event.getEntity(); if (isWorld(p.getWorld())) { FileConfiguration config = getConfig("config"); Player killer = p.getKiller(); if (killer != null) { getData(killer).playersKilled++; if (config.getBoolean("Config.players.send-kill-stat-messages")) { killer.sendMessage(ChatColor.GOLD + getMsg("Messages.killed.player").replaceAll("%p", p.getDisplayName()) .replaceAll("%k", "" + getData(killer).playersKilled)); } RewardType.KILL_PLAYER.reward(killer); } final String kickMsg = (getCraftZ().getPrefix() + " " + getMsg("Messages.died")) .replaceAll("%z", "" + getData(p).zombiesKilled) .replaceAll("%p", "" + getData(p).playersKilled) .replaceAll("%m", "" + getData(p).minutesSurvived); resetPlayer(p); setLastDeath(p, System.currentTimeMillis()); if (config.getBoolean("Config.players.kick-on-death") && !p.hasPermission("craftz.bypassKick")) { p.kickPlayer(kickMsg); } else { p.sendMessage(ChatColor.GREEN + kickMsg); p.setHealth(p.getMaxHealth()); p.setFoodLevel(20); Bukkit.getScheduler().runTask(getCraftZ(), new Runnable() { @Override public void run() { p.getInventory().clear(); p.getInventory().setArmorContents(new ItemStack[4]); p.setVelocity(new Vector()); p.teleport(getLobby()); Kit kit = getCraftZ().getKits().getDefaultKit(); if (kit != null) { kit.select(p); } } }); } } } @EventHandler(priority = EventPriority.HIGHEST) public void onEntityDamage(EntityDamageEvent event) { EntityType type = event.getEntityType(); if (type == EntityType.PLAYER) { Player p = (Player) event.getEntity(); if (isInsideOfLobby(p) || (isWorld(p.getWorld()) && !isPlaying(p))) { event.setCancelled(true); } } } public boolean hasPlayer(Player p) { return hasPlayer(p.getUniqueId()); } public boolean hasPlayer(UUID uuid) { return players.containsKey(uuid); } public void savePlayer(Player p) { if (hasPlayer(p)) { WorldData.get().set("Data.players." + p.getUniqueId(), getData(p).toString()); WorldData.save(); } } public void saveAllPlayers() { for (Player p : world().getPlayers()) { if (hasPlayer(p)) { WorldData.get().set("Data.players." + p.getUniqueId(), getData(p).toString()); } } WorldData.save(); } public void loadPlayer(Player p, boolean forceRespawn, PlayerSpawnpoint spawnpoint) { if (hasPlayer(p) && !forceRespawn) { return; } FileConfiguration config = getConfig("config"); int invulnTime = 0; if (existsInConfig(p) && !forceRespawn) { putPlayer(p, false); invulnTime = (int) (config.getDouble("Config.players.invulnerability.on-return") * 20); } else { if (spawnpoint == null && (spawnpoint = randomSpawn()) == null) { p.sendMessage(ChatColor.RED + getMsg("Messages.errors.no-player-spawns")); return; } putPlayer(p, true); savePlayer(p); if (config.getBoolean("Config.players.clear-inventory-on-spawn")) { PlayerInventory inv = p.getInventory(); Kits kits = getCraftZ().getKits(); for (int i=0; i<inv.getSize(); i++) { ItemStack stack = inv.getItem(i); if (!kits.isSoulbound(stack)) inv.setItem(i, null); } if (!kits.isSoulbound(inv.getHelmet())) inv.setHelmet(null); if (!kits.isSoulbound(inv.getChestplate())) inv.setChestplate(null); if (!kits.isSoulbound(inv.getLeggings())) inv.setLeggings(null); if (!kits.isSoulbound(inv.getBoots())) inv.setBoots(null); } p.setHealth(p.getMaxHealth()); p.setFoodLevel(20); spawnpoint.spawn(p); invulnTime = (int) (config.getDouble("Config.players.invulnerability.on-spawn") * 20); } if (config.getBoolean("Config.players.medical.thirst.enable")) { p.setLevel(players.get(p.getUniqueId()).thirst); } p.addPotionEffect(new PotionEffect(PotionEffectType.DAMAGE_RESISTANCE, invulnTime, 1000)); getCraftZ().getScoreboardHelper().addPlayer(p); } private void putPlayer(Player p, boolean defaults) { if (defaults) { players.put(p.getUniqueId(), new PlayerData(20, 0, 0, 0, false, false, false)); } else { String s = WorldData.get().getString("Data.players." + p.getUniqueId()); players.put(p.getUniqueId(), PlayerData.fromString(s)); } } public void resetPlayer(Player p) { if (hasPlayer(p)) { PlayerData data = getData(p); addToHighscores(p, data); } WorldData.get().set("Data.players." + p.getUniqueId(), null); WorldData.save(); getCraftZ().getScoreboardHelper().removePlayer(p.getUniqueId()); players.remove(p.getUniqueId()); } public static String makeSpawnID(Location signLoc) { return "x" + signLoc.getBlockX() + "y" + signLoc.getBlockY() + "z" + signLoc.getBlockZ(); } public PlayerSpawnpoint getSpawnpoint(String signID) { for (PlayerSpawnpoint spawn : spawns) { if (spawn.getID().equals(signID)) return spawn; } return null; } public PlayerSpawnpoint getSpawnpoint(Location signLoc) { return getSpawnpoint(makeSpawnID(signLoc)); } public void addSpawn(Location signLoc, String name) { String id = makeSpawnID(signLoc); PlayerSpawnpoint spawn = new PlayerSpawnpoint(this, id, signLoc, name); spawns.add(spawn); spawn.save(); Dynmap dynmap = getCraftZ().getDynmap(); dynmap.createMarker(dynmap.SET_PLAYERSPAWNS, "playerspawn_" + id, "Spawn: " + name, signLoc, dynmap.ICON_PLAYERSPAWN); } public void removeSpawn(String signID) { WorldData.get().set("Data.playerspawns." + signID, null); WorldData.save(); PlayerSpawnpoint spawn = getSpawnpoint(signID); if (spawn != null) spawns.remove(spawn); Dynmap dynmap = getCraftZ().getDynmap(); dynmap.removeMarker(dynmap.getMarker(dynmap.SET_PLAYERSPAWNS, "playerspawn_" + signID)); } public List<PlayerSpawnpoint> getSpawns() { return Collections.unmodifiableList(spawns); } public PlayerSpawnpoint matchSpawn(String name) { for (PlayerSpawnpoint spawn : spawns) { if (spawn.getName().equalsIgnoreCase(name.trim())) return spawn; } return null; } public PlayerSpawnpoint randomSpawn() { if (spawns.isEmpty()) return null; return spawns.get(CraftZ.RANDOM.nextInt(spawns.size())); } public int getSpawnCount() { return spawns.size(); } public int getRespawnCountdown(Player player) { if (!lastDeaths.containsKey(player.getUniqueId()) || player.hasPermission("craftz.instantRespawn")) return 0; int countdown = getConfig("config").getInt("Config.players.respawn-countdown"); return (int) (countdown*1000 - (System.currentTimeMillis() - lastDeaths.get(player.getUniqueId()))); } public void setLastDeath(Player p, long timestamp) { lastDeaths.put(p.getUniqueId(), timestamp); } @Override public PlayerData getData(UUID p) { if (!players.containsKey(p)) loadPlayer(p(p), false, null); return players.get(p); } @Override public PlayerData getData(Player p) { if (!players.containsKey(p.getUniqueId())) loadPlayer(p, false, null); return players.get(p.getUniqueId()); } @Override public void onServerTick(long tick) { for (Iterator<Entry<UUID, PlayerData>> it=players.entrySet().iterator(); it.hasNext(); ) { Entry<UUID, PlayerData> entry = it.next(); UUID id = entry.getKey(); PlayerData data = entry.getValue(); Player p = p(id); if (!isPlaying(id)) { if (p != null) savePlayer(p); getCraftZ().getScoreboardHelper().removePlayer(id); it.remove(); continue; } for (Module m : getCraftZ().getModules()) { if (m != this) m.onPlayerTick(p, tick); } if (isSurvival(p) && tick % 1200 == 0) { data.minutesSurvived++; } if (tick % 10 == 0) { ItemRenamer.on(p).setSpecificNames(ItemRenamer.DEFAULT_MAP); } } for (Iterator<Entry<UUID, Integer>> it=movingPlayers.entrySet().iterator(); it.hasNext(); ) { Entry<UUID, Integer> entry = it.next(); int v = entry.getValue() + 1; entry.setValue(v); if (v > 8) it.remove(); } } @EventHandler(priority = EventPriority.HIGHEST) public void onPlayerMove(PlayerMoveEvent event) { Player p = event.getPlayer(); if (isWorld(p.getWorld())) { double distance = event.getFrom().distance(event.getTo()); if (distance > 0) { movingPlayers.put(p.getUniqueId(), 0); } } } public boolean isMoving(Player p) { return movingPlayers.containsKey(p.getUniqueId()); } public boolean isLobby(Location loc) { Location lobby = getLobby(); int radius = getConfig("config").getInt("Config.world.lobby.radius"); return loc.getWorld().getName().equals(lobby.getWorld().getName()) && lobby.distance(loc) <= radius; } public boolean isInsideOfLobby(Player p) { return isLobby(p.getLocation()); } public Location getLobby() { World cw = world(); if (cw == null) return null; Location lobby = cw.getSpawnLocation(); ConfigurationSection sec = getConfig("config").getConfigurationSection("Config.world.lobby"); String ws = sec.getString("world"); World w = ws == null ? null : Bukkit.getWorld(ws); if (w != null) lobby.setWorld(w); lobby.setX(sec.getDouble("x")); lobby.setY(sec.getDouble("y")); lobby.setZ(sec.getDouble("z")); lobby.setYaw((float) sec.getDouble("yaw")); lobby.setPitch((float) sec.getDouble("pitch")); return lobby; } public void setLobby(Location loc, double radius) { ConfigurationSection sec = getConfig("config").getConfigurationSection("Config.world.lobby"); sec.set("world", loc.getWorld().getName()); sec.set("x", Math.round(loc.getX() * 100) / 100.0); sec.set("y", Math.round(loc.getY() * 100) / 100.0); sec.set("z", Math.round(loc.getZ() * 100) / 100.0); sec.set("yaw", Math.round(loc.getYaw() * 100) / 100f); sec.set("pitch", Math.round(loc.getPitch() * 100) / 100f); sec.set("radius", radius); saveConfig("config"); } public boolean existsInConfig(Player p) { return WorldData.get().contains("Data.players." + p.getUniqueId()); } public boolean existsInWorld(Player p) { return players.containsKey(p.getUniqueId()); } public int getPlayerCount() { return players.size(); } public Player randomPlayer() { List<Player> players = world().getPlayers(); if (players.isEmpty()) return null; Collections.shuffle(players); for (int i=0; i<players.size(); i++) { Player chosen = players.get(i); if (!isInsideOfLobby(chosen)) return chosen; } return null; } public boolean isPlaying(Player p) { return players.containsKey(p.getUniqueId()) && isWorld(p.getWorld()) && !isInsideOfLobby(p); } public boolean isPlaying(UUID id) { Player p = p(id); return p != null && players.containsKey(id) && isWorld(p.getWorld()) && !isInsideOfLobby(p); } public Map<String, Integer> getHighscores(String category) { LinkedHashMap<String, Integer> scores = new LinkedHashMap<String, Integer>(); ConfigurationSection sec = getConfig("highscores").getConfigurationSection("Highscores." + category); if (sec != null) { for (String player : sec.getKeys(false)) { scores.put(player, sec.getInt(player)); } } return scores; } public static SortedSet<Map.Entry<String, Integer>> sortHighscores(Map<String, Integer> scoresMap) { SortedSet<Map.Entry<String, Integer>> scores = new TreeSet<Map.Entry<String, Integer>>(new Comparator<Map.Entry<String, Integer>>() { @Override public int compare(Map.Entry<String, Integer> e1, Map.Entry<String, Integer> e2) { int res = e2.getValue().compareTo(e1.getValue()); return res != 0 ? res : 1; } }); scores.addAll(scoresMap.entrySet()); return scores; } public void addToHighscores(Player p, PlayerData data) { addToHighscores(p, data.minutesSurvived, "minutes-survived"); addToHighscores(p, data.zombiesKilled, "zombies-killed"); addToHighscores(p, data.playersKilled, "players-killed"); } public void addToHighscores(Player p, int v, String category) { Map<String, Integer> scores = getHighscores(category); SortedSet<Map.Entry<String, Integer>> scoresSorted = sortHighscores(scores); if (scores.containsKey(p.getName())) { int score = scores.get(p.getName()); if (v < score) { return; } } Map.Entry<String, Integer> scoresLast = scores.isEmpty() ? null : scoresSorted.last(); if (scores.size() < 10 || scoresLast.getValue() < v) { scores.put(p.getName(), v); scores.remove(scoresLast); } if (scores.size() > 10) { scores.remove(scoresLast); } getConfig("highscores").createSection("Highscores." + category, scores); saveConfig("highscores"); } @Override public void onDynmapEnabled(Dynmap dynmap) { FileConfiguration config = getConfig("config"); dynmap.clearSet(dynmap.SET_WORLDBORDER); if (config.getBoolean("Config.dynmap.show-worldborder") && config.getBoolean("Config.world.world-border.enable")) { double r = config.getDouble("Config.world.world-border.radius"); dynmap.createCircleMarker(dynmap.SET_WORLDBORDER, "worldborder", "World Border", 6, 0.4, 0xEE2222, getLobby(), r, r); } dynmap.clearSet(dynmap.SET_PLAYERSPAWNS); if (config.getBoolean("Config.dynmap.show-playerspawns")) { for (PlayerSpawnpoint spawn : spawns) { String id = "playerspawn_" + spawn.getID(); String label = "Spawn: " + spawn.getName(); dynmap.createMarker(dynmap.SET_PLAYERSPAWNS, id, label, spawn.getLocation(), dynmap.ICON_PLAYERSPAWN); } } } }