/* * Copyright or © or Copr. Amaury Carrade (2014 - 2016) * * http://amaury.carrade.eu * * This software is governed by the CeCILL-B license under French law and * abiding by the rules of distribution of free software. You can use, * modify and/ or redistribute the software under the terms of the CeCILL-B * license as circulated by CEA, CNRS and INRIA at the following URL * "http://www.cecill.info". * * As a counterpart to the access to the source code and rights to copy, * modify and redistribute granted by the license, users are provided only * with a limited warranty and the software's author, the holder of the * economic rights, and the successive licensors have only limited * liability. * * In this respect, the user's attention is drawn to the risks associated * with loading, using, modifying and/or developing or reproducing the * software by the user in light of its specific status of free software, * that may mean that it is complicated to manipulate, and that also * therefore means that it is reserved for developers and experienced * professionals having in-depth computer knowledge. Users are therefore * encouraged to load and test the software's suitability as regards their * requirements in conditions enabling the security of their systems and/or * data to be ensured and, more generally, to use and operate it in the * same conditions as regards security. * * The fact that you are presently reading this means that you have had * knowledge of the CeCILL-B license and that you accept its terms. */ package eu.carrade.amaury.UHCReloaded.misc; import eu.carrade.amaury.UHCReloaded.UHCReloaded; import eu.carrade.amaury.UHCReloaded.listeners.FreezerListener; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.entity.Creature; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import org.bukkit.event.HandlerList; import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; import org.bukkit.potion.PotionEffect; import org.bukkit.potion.PotionEffectType; import java.util.ArrayList; import java.util.HashMap; import java.util.UUID; public class Freezer { private UHCReloaded p = null; private boolean isListenerRegistered = false; private FreezerListener freezerListener = null; private Boolean globalFreeze = false; private ArrayList<UUID> frozenPlayers = new ArrayList<>(); private HashMap<UUID, Boolean> oldAllowFly = new HashMap<>(); private HashMap<UUID, Boolean> oldFlyMode = new HashMap<>(); private boolean hiddenFreeze = false; public Freezer(UHCReloaded plugin) { this.p = plugin; this.freezerListener = new FreezerListener(p); } /** * Freezes a player, if needed. * The player is blocked inside the block he is currently. * * This method is intended to be executed when a player moves. * * @param player The player to freeze * @param from The old position from the PlayerMoveEvent * @param to The new position from the PlayerMoveEvent */ public void freezePlayerIfNeeded(Player player, Location from, Location to) { if (frozenPlayers.contains(player.getUniqueId())) { // If the X, Y or Z coordinate of the player change, he needs to be teleported inside the old block. // The yaw and pitch are conserved, to teleport more smoothly. if (from.getBlockX() != to.getBlockX() || from.getBlockY() != to.getBlockY() || from.getBlockZ() != to.getBlockZ()) { player.teleport(new Location(from.getWorld(), from.getBlockX() + 0.5, from.getBlockY(), from.getBlockZ() + 0.5, to.getYaw(), to.getPitch()), TeleportCause.PLUGIN); } } } /** * Enables or disables the global freeze of players, mobs, timer. * * @param frozen If true the global freeze will be enabled. * @param showStateInScoreboard If false, the freeze state will not be displayed in the scoreboard. */ public void setGlobalFreezeState(Boolean frozen, Boolean showStateInScoreboard) { this.globalFreeze = frozen; this.hiddenFreeze = !showStateInScoreboard; if (frozen) { for (Player player : p.getGameManager().getOnlineAlivePlayers()) { this.setPlayerFreezeState(player, true); } // Freezes the mobs by applying a Slowness effect. There isn't any EntityMoveEvent, so... for (World world : p.getServer().getWorlds()) { for (Entity entity : world.getLivingEntities()) { if (entity instanceof Creature) { freezeCreature((Creature) entity, true); } } } // Freezes the timers. p.getTimerManager().pauseAllRunning(true); } else { // All the online players are listed, not the internal list of frozen players, // to avoid a ConcurrentModificationException if the iterated list is being emptied. for (Player player : p.getServer().getOnlinePlayers()) { if (this.isPlayerFrozen(player)) { this.setPlayerFreezeState(player, false); } } // Removes the slowness effect for (World world : p.getServer().getWorlds()) { for (Entity entity : world.getLivingEntities()) { if (entity instanceof Creature) { freezeCreature((Creature) entity, false); } } } // Unfreezes the timers. p.getTimerManager().pauseAllRunning(false); } updateListenerRegistration(); } /** * Enables or disables the global freeze of players, mobs, timer. * * @param frozen If true the global freeze will be enabled. */ public void setGlobalFreezeState(Boolean frozen) { setGlobalFreezeState(frozen, true); } /** * Returns the current state of the global freeze. * * @return True if the global freeze is enabled. */ public boolean getGlobalFreezeState() { return this.globalFreeze; } /** * Freezes a player. * * @param player The player to freeze. * @param frozen If true the player will be frozen. If false, unfrozen. */ public void setPlayerFreezeState(Player player, Boolean frozen) { if (frozen && !this.frozenPlayers.contains(player.getUniqueId())) { this.frozenPlayers.add(player.getUniqueId()); this.oldAllowFly.put(player.getUniqueId(), player.getAllowFlight()); this.oldFlyMode.put(player.getUniqueId(), player.isFlying()); // Used to prevent the player to be kicked for fly if he was frozen during a fall. // He is blocked inside his current block anyway. player.setAllowFlight(true); } if (!frozen && this.frozenPlayers.contains(player.getUniqueId())) { this.frozenPlayers.remove(player.getUniqueId()); player.setFlying(this.oldFlyMode.get(player.getUniqueId())); player.setAllowFlight(this.oldAllowFly.get(player.getUniqueId())); this.oldAllowFly.remove(player.getUniqueId()); this.oldFlyMode.remove(player.getUniqueId()); } updateListenerRegistration(); } /** * Returns true if the given player is frozen. * * @param player The player to be checked. * @return true if the given player is frozen. */ public boolean isPlayerFrozen(Player player) { return frozenPlayers.contains(player.getUniqueId()); } /** * Returns {@code true} if the current freeze must be hidden in the sidebar. * * @return {@code true} to hide it. */ public boolean isHiddenFreeze() { return hiddenFreeze; } /** * (Un)freezes a creature. * * @param creature The creature to freeze. * @param frozen If true the creature will be frozen. Else... */ public void freezeCreature(Creature creature, Boolean frozen) { if (frozen) { // Freezes the creature for about 68 years. creature.addPotionEffect(new PotionEffect(PotionEffectType.SLOW, Integer.MAX_VALUE, 100, true)); } else { creature.removePotionEffect(PotionEffectType.SLOW); } } /** * Registers the listener if it wasn't registered, and unregisters this listener * if there isn't any frozen player. * * Call this AFTER registering the first frozen player, and AFTER unregistering * the last one. */ private void updateListenerRegistration() { // Registers the listener if needed // (i.e if there isn't any frozen player, or if the global freeze is enabled). if (!this.isListenerRegistered) { if (!this.frozenPlayers.isEmpty() || this.getGlobalFreezeState()) { p.getServer().getPluginManager().registerEvents(freezerListener, p); this.isListenerRegistered = true; } } // Unregisters the listener if needed else { if (this.frozenPlayers.isEmpty() && !this.getGlobalFreezeState()) { HandlerList.unregisterAll(freezerListener); this.isListenerRegistered = false; } } } /** * Returns the list of the currently frozen players. * * @return The list. */ public ArrayList<Player> getFrozenPlayers() { ArrayList<Player> frozenPlayersList = new ArrayList<>(); for (UUID id : frozenPlayers) { frozenPlayersList.add(p.getServer().getPlayer(id)); } return frozenPlayersList; } }