/* * This file is part of NucleusFramework for Bukkit, licensed under the MIT License (MIT). * * Copyright (c) JCThePants (www.jcwhatever.com) * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.jcwhatever.nucleus.internal.providers.jail; import com.jcwhatever.nucleus.Nucleus; import com.jcwhatever.nucleus.internal.NucMsg; import com.jcwhatever.nucleus.managed.scheduler.Scheduler; import com.jcwhatever.nucleus.providers.jail.IJail; import com.jcwhatever.nucleus.providers.jail.IJailSession; import com.jcwhatever.nucleus.regions.Region; import com.jcwhatever.nucleus.regions.options.LeaveRegionReason; import com.jcwhatever.nucleus.storage.IDataNode; import com.jcwhatever.nucleus.utils.PreCon; import com.jcwhatever.nucleus.utils.Rand; import com.jcwhatever.nucleus.utils.TimeScale; import com.jcwhatever.nucleus.utils.coords.NamedLocation; import com.jcwhatever.nucleus.utils.coords.SyncLocation; import com.jcwhatever.nucleus.utils.text.TextUtils; import org.bukkit.GameMode; import org.bukkit.Location; import org.bukkit.entity.Player; import org.bukkit.plugin.Plugin; import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.annotation.Nullable; /** * Nucleus Implementation of {@link IJail}. */ class NucleusJail implements IJail { private final NucleusJailProvider _provider; private final Plugin _plugin; private final String _name; private final String _searchName; private final IDataNode _dataNode; private final Bounds _bounds; private final Map<String, NamedLocation> _jailLocations = new HashMap<>(10); private Location _releaseLocation; private boolean _isDisposed; NucleusJail(NucleusJailProvider provider, Plugin plugin, String name, IDataNode dataNode) { PreCon.notNull(provider); PreCon.notNull(plugin); PreCon.notNullOrEmpty(name); _provider = provider; _plugin = plugin; _name = name; _searchName = name.toLowerCase(); _dataNode = dataNode; _bounds = new Bounds(plugin, name, dataNode.getNode("bounds")); load(); } @Override public Plugin getPlugin() { return _plugin; } @Override public String getName() { return _name; } @Override public String getSearchName() { return _searchName; } @Nullable @Override public IJailSession imprison(Player player, int duration, TimeScale timeScale) { PreCon.greaterThanZero(duration); PreCon.notNull(timeScale); return imprison(player, new Date(System.currentTimeMillis() + (duration * timeScale.getTimeFactor()))); } @Nullable @Override public IJailSession imprison(Player player, Date expires) { PreCon.notNull(player); checkDisposed(); // teleport player to jail Location teleport = getRandomTeleport(); if (teleport == null) { if (!_bounds.isDefined()) { NucMsg.debug(getPlugin(), "Cannot imprison player in jail '{0}' because its coordinates " + "are undefined and no teleport location has been assigned."); return null; } teleport = _bounds.getCenter(); } // register session IJailSession session = _provider.createSession(this, player.getUniqueId(), expires); if (session == null) return null; player.teleport(teleport); player.setGameMode(GameMode.SURVIVAL); return session; } @Override public boolean isPrisoner(Player player) { PreCon.notNull(player); IJailSession session = _provider.getSession(player.getUniqueId()); return session != null && session.getJail().equals(this); } @Override public Bounds getRegion() { return _bounds; } @Override public boolean addTeleport(String name, Location teleport) { PreCon.notNullOrEmpty(name); PreCon.notNull(teleport); PreCon.isValid(TextUtils.isValidName(name)); return addTeleport(new NamedLocation(name, teleport)); } @Override public boolean addTeleport(NamedLocation teleport) { PreCon.notNull(teleport); checkDisposed(); // make sure the name is not already in use NamedLocation location = _jailLocations.get(teleport.getSearchName()); if (location != null) return false; _jailLocations.put(teleport.getSearchName(), teleport); IDataNode teleportNode = _dataNode.getNode("teleport"); teleportNode.set(teleport.getSearchName(), teleport); teleportNode.save(); return true; } @Override public boolean removeTeleport(String name) { PreCon.notNullOrEmpty(name); checkDisposed(); NamedLocation location = _jailLocations.remove(name.toLowerCase()); if (location == null) return false; IDataNode teleportNode = _dataNode.getNode("teleport"); teleportNode.set(name, null); teleportNode.save(); return true; } @Nullable @Override public NamedLocation getRandomTeleport() { List<NamedLocation> locations = new ArrayList<>(_jailLocations.values()); if (locations.isEmpty()) return null; return Rand.get(locations); } @Nullable @Override public NamedLocation getTeleport(String name) { PreCon.notNullOrEmpty(name); return _jailLocations.get(name.toLowerCase()); } @Override public Collection<NamedLocation> getTeleports() { return new ArrayList<>(_jailLocations.values()); } @Override public <T extends Collection<NamedLocation>> T getTeleports(T output) { PreCon.notNull(output); output.addAll(_jailLocations.values()); return output; } @Nullable @Override public Location getReleaseLocation() { if (_releaseLocation == null && _bounds.getWorld() != null) { return _bounds.getWorld().getSpawnLocation(); } return _releaseLocation != null ? _releaseLocation.clone() : null; } @Override public void setReleaseLocation(@Nullable Location location) { _releaseLocation = location; checkDisposed(); _dataNode.set("release-location", location); _dataNode.save(); } @Override public boolean isDisposed() { return _isDisposed; } @Override public void dispose() { if (this.equals(_provider.getServerJail())) throw new IllegalStateException("Cannot dispose server jail."); _provider.removeJail(this); _dataNode.remove(); _dataNode.save(); _isDisposed = true; } NucleusJailProvider getProvider() { return _provider; } private void checkDisposed() { if (_isDisposed) throw new IllegalStateException("Cannot use a disposed jail."); } private void load() { IDataNode teleportNode = _dataNode.getNode("teleport"); for (IDataNode node : teleportNode) { SyncLocation syncLocation = node.getLocation(""); if (syncLocation == null) continue; NamedLocation location = new NamedLocation(node.getName(), syncLocation); _jailLocations.put(location.getSearchName(), location); } _releaseLocation = _dataNode.getLocation("release-location"); } public class Bounds extends Region { /** * Constructor * * @param plugin * @param name * @param dataNode */ public Bounds(Plugin plugin, String name, @Nullable IDataNode dataNode) { super(plugin, name, dataNode); setEventListener(true); } @Override protected boolean canDoPlayerLeave(Player player, LeaveRegionReason reason) { PreCon.notNull(player); return reason != LeaveRegionReason.QUIT_SERVER && isPrisoner(player); } @Override protected void onPlayerLeave (final Player player, LeaveRegionReason reason) { PreCon.notNull(player); Scheduler.runTaskLater(Nucleus.getPlugin(), 10, new Runnable() { @Override public void run() { // prevent player from leaving jail Location tpLocation = getRandomTeleport(); if (tpLocation == null) tpLocation = getCenter(); player.teleport(tpLocation); } }); } } }