package com.earth2me.essentials; import com.earth2me.essentials.storage.AsyncStorageObjectHolder; import net.ess3.api.IEssentials; import net.ess3.api.IUser; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.event.block.BlockDamageEvent; import org.bukkit.event.block.BlockPlaceEvent; import org.bukkit.event.entity.EntityDamageByEntityEvent; import org.bukkit.event.entity.EntityDamageEvent.DamageCause; import org.bukkit.event.player.PlayerGameModeChangeEvent; import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.player.PlayerRespawnEvent; import org.bukkit.event.player.PlayerTeleportEvent; import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; import org.bukkit.plugin.PluginManager; import java.io.File; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Locale; import java.util.concurrent.CompletableFuture; import java.util.logging.Level; import java.util.logging.Logger; import static com.earth2me.essentials.I18n.tl; public class Jails extends AsyncStorageObjectHolder implements net.ess3.api.IJails { private static final transient Logger LOGGER = Bukkit.getLogger(); private static transient boolean enabled = false; public Jails(final IEssentials ess) { super(ess, com.earth2me.essentials.settings.Jails.class); reloadConfig(); } private void registerListeners() { enabled = true; final PluginManager pluginManager = ess.getServer().getPluginManager(); final JailListener blockListener = new JailListener(); pluginManager.registerEvents(blockListener, ess); if (ess.getSettings().isDebug()) { LOGGER.log(Level.INFO, "Registering Jail listener"); } } @Override public File getStorageFile() { return new File(ess.getDataFolder(), "jail.yml"); } @Override public void finishRead() { checkRegister(); } @Override public void finishWrite() { checkRegister(); } public void resetListener() { enabled = false; checkRegister(); } private void checkRegister() { if (!enabled && getCount() > 0) { registerListeners(); } } @Override public Location getJail(final String jailName) throws Exception { acquireReadLock(); try { if (getData().getJails() == null || jailName == null || !getData().getJails().containsKey(jailName.toLowerCase(Locale.ENGLISH))) { throw new Exception(tl("jailNotExist")); } final Location loc = getData().getJails().get(jailName.toLowerCase(Locale.ENGLISH)); if (loc == null || loc.getWorld() == null) { throw new Exception(tl("jailNotExist")); } return loc; } finally { unlock(); } } @Override public Collection getList() throws Exception { acquireReadLock(); try { if (getData().getJails() == null) { return Collections.emptyList(); } return new ArrayList<>(getData().getJails().keySet()); } finally { unlock(); } } @Override public void removeJail(final String jail) throws Exception { acquireWriteLock(); try { if (getData().getJails() == null) { return; } getData().getJails().remove(jail.toLowerCase(Locale.ENGLISH)); } finally { unlock(); } } /** * @deprecated This method does not use asynchronous teleportation. Use {@link Jails#sendToJail(IUser, String, CompletableFuture)} */ @Override @Deprecated public void sendToJail(final IUser user, final String jail) throws Exception { acquireReadLock(); try { if (user.getBase().isOnline()) { final Location loc = getJail(jail); user.getTeleport().now(loc, false, TeleportCause.COMMAND); } user.setJail(jail); } finally { unlock(); } } @Override public void sendToJail(final IUser user, final String jail, final CompletableFuture future) throws Exception { acquireReadLock(); try { if (user.getBase().isOnline()) { final Location loc = getJail(jail); user.getAsyncTeleport().now(loc, false, TeleportCause.COMMAND, future); future.thenAccept(success -> user.setJail(jail)); return; } user.setJail(jail); } finally { unlock(); } } @Override public void setJail(final String jailName, final Location loc) throws Exception { acquireWriteLock(); try { if (getData().getJails() == null) { getData().setJails(new HashMap<>()); } getData().getJails().put(jailName.toLowerCase(Locale.ENGLISH), loc); } finally { unlock(); } } @Override public int getCount() { try { return getList().size(); } catch (final Exception ex) { return 0; } } private class JailListener implements Listener { @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) public void onJailBlockBreak(final BlockBreakEvent event) { final User user = ess.getUser(event.getPlayer()); if (user.isJailed() && !user.isAuthorized("essentials.jail.allow-break")) { event.setCancelled(true); } } @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) public void onJailBlockPlace(final BlockPlaceEvent event) { final User user = ess.getUser(event.getPlayer()); if (user.isJailed() && !user.isAuthorized("essentials.jail.allow-place")) { event.setCancelled(true); } } @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) public void onJailBlockDamage(final BlockDamageEvent event) { final User user = ess.getUser(event.getPlayer()); if (user.isJailed() && !user.isAuthorized("essentials.jail.allow-block-damage")) { event.setCancelled(true); } } @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) public void onJailEntityDamageByEntity(final EntityDamageByEntityEvent event) { if (event.getCause() != DamageCause.ENTITY_ATTACK || event.getEntity().getType() != EntityType.PLAYER) { return; } final Entity damager = event.getDamager(); if (damager.getType() == EntityType.PLAYER) { final User user = ess.getUser((Player) damager); if (user != null && user.isJailed()) { event.setCancelled(true); } } } @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) public void onJailPlayerInteract(final PlayerInteractEvent event) { final User user = ess.getUser(event.getPlayer()); if (user.isJailed() && !user.isAuthorized("essentials.jail.allow-interact")) { event.setCancelled(true); } } @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) public void onJailPlayerGameModeChange(final PlayerGameModeChangeEvent event) { final User user = ess.getUser(event.getPlayer()); if (user.isJailed()) { event.setCancelled(true); } } @EventHandler(priority = EventPriority.HIGHEST) public void onJailPlayerRespawn(final PlayerRespawnEvent event) { final User user = ess.getUser(event.getPlayer()); if (!user.isJailed() || user.getJail() == null || user.getJail().isEmpty()) { return; } try { event.setRespawnLocation(getJail(user.getJail())); } catch (final Exception ex) { if (ess.getSettings().isDebug()) { LOGGER.log(Level.INFO, tl("returnPlayerToJailError", user.getName(), ex.getLocalizedMessage()), ex); } else { LOGGER.log(Level.INFO, tl("returnPlayerToJailError", user.getName(), ex.getLocalizedMessage())); } } } @EventHandler(priority = EventPriority.HIGH) public void onJailPlayerTeleport(final PlayerTeleportEvent event) { final User user = ess.getUser(event.getPlayer()); if (!user.isJailed() || user.getJail() == null || user.getJail().isEmpty()) { return; } try { event.setTo(getJail(user.getJail())); } catch (final Exception ex) { if (ess.getSettings().isDebug()) { LOGGER.log(Level.INFO, tl("returnPlayerToJailError", user.getName(), ex.getLocalizedMessage()), ex); } else { LOGGER.log(Level.INFO, tl("returnPlayerToJailError", user.getName(), ex.getLocalizedMessage())); } } user.sendMessage(tl("jailMessage")); } @EventHandler(priority = EventPriority.HIGHEST) public void onJailPlayerJoin(final PlayerJoinEvent event) { final User user = ess.getUser(event.getPlayer()); final long currentTime = System.currentTimeMillis(); user.checkJailTimeout(currentTime); if (!user.isJailed() || user.getJail() == null || user.getJail().isEmpty()) { return; } final CompletableFuture future = new CompletableFuture<>(); future.exceptionally(ex -> { if (ess.getSettings().isDebug()) { LOGGER.log(Level.INFO, tl("returnPlayerToJailError", user.getName(), ex.getLocalizedMessage()), ex); } else { LOGGER.log(Level.INFO, tl("returnPlayerToJailError", user.getName(), ex.getLocalizedMessage())); } return false; }); future.thenAccept(success -> user.sendMessage(tl("jailMessage"))); try { sendToJail(user, user.getJail(), future); } catch (final Exception ex) { future.completeExceptionally(ex); } } } }