package net.knarcraft.stargate; import net.knarcraft.stargate.event.StargateActivateEvent; import net.knarcraft.stargate.event.StargateCloseEvent; import net.knarcraft.stargate.event.StargateDeactivateEvent; import net.knarcraft.stargate.event.StargateOpenEvent; import net.knarcraft.stargate.event.StargatePortalEvent; import org.bukkit.Axis; import org.bukkit.ChatColor; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.BlockState; import org.bukkit.block.Sign; import org.bukkit.block.data.Bisected; import org.bukkit.block.data.BlockData; import org.bukkit.block.data.Powerable; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import org.bukkit.entity.Vehicle; import org.bukkit.entity.minecart.StorageMinecart; import org.bukkit.event.player.PlayerMoveEvent; import org.bukkit.util.Vector; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Random; import java.util.UUID; import java.util.logging.Level; public class Portal { // Gate location block info private final BlockLocation topLeft; private final int modX; private final int modZ; private final float rotX; private final Axis rot; // Block references private final BlockLocation id; private BlockLocation button; private BlockLocation[] frame; private BlockLocation[] entrances; // Gate information private String name; private String destination; private String lastDestination = ""; private String network; private final Gate gate; private String ownerName; private UUID ownerUUID; private final World world; private boolean verified; private boolean fixed; // Options private boolean hidden = false; private boolean alwaysOn = false; private boolean isPrivate = false; private boolean free = false; private boolean backwards = false; private boolean show = false; private boolean noNetwork = false; private boolean random = false; private boolean bungee = false; // In-use information private Player player; private Player activePlayer; private ArrayList destinations = new ArrayList<>(); private boolean isOpen = false; private long openTime; Portal(BlockLocation topLeft, int modX, int modZ, float rotX, BlockLocation id, BlockLocation button, String dest, String name, boolean verified, String network, Gate gate, UUID ownerUUID, String ownerName) { this.topLeft = topLeft; this.modX = modX; this.modZ = modZ; this.rotX = rotX; this.rot = rotX == 0.0F || rotX == 180.0F ? Axis.X : Axis.Z; this.id = id; this.destination = dest; this.button = button; this.verified = verified; this.network = network; this.name = name; this.gate = gate; this.ownerUUID = ownerUUID; this.ownerName = ownerName; this.world = topLeft.getWorld(); this.fixed = dest.length() > 0 || this.random || this.bungee; if (this.isAlwaysOn() && !this.isFixed()) { this.alwaysOn = false; Stargate.debug("Portal", "Can not create a non-fixed always-on gate. Setting AlwaysOn = false"); } if (this.random && !this.isAlwaysOn()) { this.alwaysOn = true; Stargate.debug("Portal", "Gate marked as random, set to always-on"); } if (verified) { this.drawSign(); } } Portal(BlockLocation topLeft, int modX, int modZ, float rotX, BlockLocation id, BlockLocation button, String dest, String name, boolean verified, String network, Gate gate, UUID ownerUUID, String ownerName, boolean hidden, boolean alwaysOn, boolean isPrivate, boolean free, boolean backwards, boolean show, boolean noNetwork, boolean random, boolean bungee) { this.topLeft = topLeft; this.modX = modX; this.modZ = modZ; this.rotX = rotX; this.rot = rotX == 0.0F || rotX == 180.0F ? Axis.X : Axis.Z; this.id = id; this.destination = dest; this.button = button; this.verified = verified; this.network = network; this.name = name; this.gate = gate; this.ownerUUID = ownerUUID; this.ownerName = ownerName; this.hidden = hidden; this.alwaysOn = alwaysOn; this.isPrivate = isPrivate; this.free = free; this.backwards = backwards; this.show = show; this.noNetwork = noNetwork; this.random = random; this.bungee = bungee; this.world = topLeft.getWorld(); this.fixed = dest.length() > 0 || this.random || this.bungee; if (this.isAlwaysOn() && !this.isFixed()) { this.alwaysOn = false; Stargate.debug("Portal", "Can not create a non-fixed always-on gate. Setting AlwaysOn = false"); } if (this.random && !this.isAlwaysOn()) { this.alwaysOn = true; Stargate.debug("Portal", "Gate marked as random, set to always-on"); } if (verified) { this.drawSign(); } } /** * Option Check Functions */ public boolean isOpen() { return isOpen || isAlwaysOn(); } public boolean isAlwaysOn() { return alwaysOn; } public boolean isHidden() { return hidden; } public boolean isPrivate() { return isPrivate; } public boolean isFree() { return free; } public boolean isBackwards() { return backwards; } public boolean isShown() { return show; } public boolean isNoNetwork() { return noNetwork; } public boolean isRandom() { return random; } public boolean isBungee() { return bungee; } public Portal setAlwaysOn(boolean alwaysOn) { this.alwaysOn = alwaysOn; return this; } public Portal setHidden(boolean hidden) { this.hidden = hidden; return this; } public Portal setPrivate(boolean priv) { this.isPrivate = priv; return this; } public Portal setFree(boolean free) { this.free = free; return this; } public Portal setBackwards(boolean backwards) { this.backwards = backwards; return this; } public Portal setShown(boolean show) { this.show = show; return this; } public Portal setNoNetwork(boolean noNetwork) { this.noNetwork = noNetwork; return this; } public Portal setRandom(boolean random) { this.random = random; return this; } public Portal setBungee(boolean bungee) { this.bungee = bungee; return this; } public void setFixed(boolean fixed) { this.fixed = fixed; } /** * Getters and Setters */ public float getRotation() { return rotX; } public Axis getAxis() { return rot; } public Player getActivePlayer() { return activePlayer; } public String getNetwork() { return network; } public void setNetwork(String network) { this.network = network; } public long getOpenTime() { return openTime; } public String getName() { return name; } public void setName(String name) { this.name = filterName(name); drawSign(); } public Portal getDestination(Player player) { if (isRandom()) { destinations = PortalHandler.getDestinations(player, getNetwork()); if (destinations.size() == 0) { return null; } String dest = destinations.get((new Random()).nextInt(destinations.size())); destinations.clear(); return PortalHandler.getByName(dest, getNetwork()); } return PortalHandler.getByName(destination, getNetwork()); } public Portal getDestination() { return getDestination(null); } public void setDestination(Portal destination) { setDestination(destination.getName()); } public void setDestination(String destination) { this.destination = destination; } public String getDestinationName() { return destination; } public Gate getGate() { return gate; } public String getOwnerName() { return ownerName; } public UUID getOwnerUUID() { return ownerUUID; } public void setOwner(UUID owner) { this.ownerUUID = owner; } public boolean isOwner(Player player) { if (this.ownerUUID != null) { return player.getUniqueId().compareTo(this.ownerUUID) == 0; } else { return player.getName().equalsIgnoreCase(this.ownerName); } } public BlockLocation[] getEntrances() { if (entrances == null) { RelativeBlockVector[] space = gate.getEntrances(); entrances = new BlockLocation[space.length]; int i = 0; for (RelativeBlockVector vector : space) { entrances[i++] = getBlockAt(vector); } } return entrances; } public BlockLocation[] getFrame() { if (frame == null) { RelativeBlockVector[] border = gate.getBorder(); frame = new BlockLocation[border.length]; int i = 0; for (RelativeBlockVector vector : border) { frame[i++] = getBlockAt(vector); } } return frame; } public BlockLocation getSign() { return id; } public World getWorld() { return world; } public BlockLocation getButton() { return button; } public void setButton(BlockLocation button) { this.button = button; } public boolean open(boolean force) { return open(null, force); } public boolean open(Player openFor, boolean force) { // Call the StargateOpenEvent StargateOpenEvent event = new StargateOpenEvent(openFor, this, force); Stargate.server.getPluginManager().callEvent(event); if (event.isCancelled()) return false; force = event.getForce(); if (isOpen() && !force) return false; Material openType = gate.getPortalBlockOpen(); Axis ax = openType == Material.NETHER_PORTAL ? rot : null; for (BlockLocation inside : getEntrances()) { Stargate.blockPopulatorQueue.add(new BloxPopulator(inside, openType, ax)); } isOpen = true; openTime = System.currentTimeMillis() / 1000; Stargate.openList.add(this); Stargate.activeList.remove(this); // Open remote gate if (!isAlwaysOn()) { player = openFor; Portal end = getDestination(); // Only open dest if it's not-fixed or points at this gate if (!random && end != null && (!end.isFixed() || end.getDestinationName().equalsIgnoreCase(getName())) && !end.isOpen()) { end.open(openFor, false); end.setDestination(this); if (end.isVerified()) end.drawSign(); } } return true; } public void close(boolean force) { if (!isOpen) return; // Call the StargateCloseEvent StargateCloseEvent event = new StargateCloseEvent(this, force); Stargate.server.getPluginManager().callEvent(event); if (event.isCancelled()) return; force = event.getForce(); if (isAlwaysOn() && !force) return; // Only close always-open if forced // Close this gate, then the dest gate. Material closedType = gate.getPortalBlockClosed(); for (BlockLocation inside : getEntrances()) { Stargate.blockPopulatorQueue.add(new BloxPopulator(inside, closedType)); } player = null; isOpen = false; Stargate.openList.remove(this); Stargate.activeList.remove(this); if (!isAlwaysOn()) { Portal end = getDestination(); if (end != null && end.isOpen()) { end.deactivate(); // Clear it's destination first. end.close(false); } } deactivate(); } public boolean isOpenFor(Player player) { if (!isOpen) { return false; } if ((isAlwaysOn()) || (this.player == null)) { return true; } return (player != null) && (player.getName().equalsIgnoreCase(this.player.getName())); } public boolean isFixed() { return fixed; } public boolean isPowered() { RelativeBlockVector[] controls = gate.getControls(); for (RelativeBlockVector vector : controls) { BlockData data = getBlockAt(vector).getBlock().getBlockData(); if (data instanceof Powerable && ((Powerable) data).isPowered()) { return true; } } return false; } public void teleport(Player player, Portal origin, PlayerMoveEvent event) { Location traveller = player.getLocation(); Location exit = getExit(traveller); // Handle backwards gates int adjust = 180; if (isBackwards() != origin.isBackwards()) adjust = 0; exit.setYaw(traveller.getYaw() - origin.getRotation() + this.getRotation() + adjust); // Call the StargatePortalEvent to allow plugins to change destination if (!origin.equals(this)) { StargatePortalEvent pEvent = new StargatePortalEvent(player, origin, this, exit); Stargate.server.getPluginManager().callEvent(pEvent); // Teleport is cancelled if (pEvent.isCancelled()) { origin.teleport(player, origin, event); return; } // Update exit if needed exit = pEvent.getExit(); } // If no event is passed in, assume it's a teleport, and act as such if (event == null) { exit.setYaw(this.getRotation()); player.teleport(exit); } else { // The new method to teleport in a move event is set the "to" field. event.setTo(exit); } } public void teleport(final Vehicle vehicle) { Location traveller = new Location(this.world, vehicle.getLocation().getX(), vehicle.getLocation().getY(), vehicle.getLocation().getZ()); Location exit = getExit(traveller); double velocity = vehicle.getVelocity().length(); // Stop and teleport vehicle.setVelocity(new Vector()); // Get new velocity final Vector newVelocity = new Vector(modX, 0.0F, modZ); newVelocity.multiply(velocity); List passengers = vehicle.getPassengers(); World vehicleWorld = exit.getWorld(); if (vehicleWorld == null) { Stargate.log.warning(Stargate.getString("prefix") + "Unable to get the world to teleport the vehicle to"); return; } Vehicle mineCart = vehicleWorld.spawn(exit, vehicle.getClass()); if (!passengers.isEmpty()) { final Entity passenger = passengers.get(0); vehicle.eject(); vehicle.remove(); passenger.eject(); passenger.teleport(exit); Stargate.server.getScheduler().scheduleSyncDelayedTask(Stargate.stargate, () -> { mineCart.addPassenger(passenger); mineCart.setVelocity(newVelocity); }, 1); } else { if (mineCart instanceof StorageMinecart) { StorageMinecart storageMinecart = (StorageMinecart) mineCart; storageMinecart.getInventory().setContents(((StorageMinecart) vehicle).getInventory().getContents()); } Stargate.log.info(Stargate.getString("prefix") + "Teleported minecart to " + mineCart.getLocation()); vehicle.remove(); Stargate.server.getScheduler().scheduleSyncDelayedTask(Stargate.stargate, () -> { mineCart.setVelocity(newVelocity); }, 1); } } public Location getExit(Location traveller) { Location loc = null; // Check if the gate has an exit block if (gate.getExit() != null) { BlockLocation exit = getBlockAt(gate.getExit()); int back = (isBackwards()) ? -1 : 1; loc = exit.modRelativeLoc(0D, 0D, 1D, traveller.getYaw(), traveller.getPitch(), modX * back, 1, modZ * back); } else { Stargate.log.log(Level.WARNING, Stargate.getString("prefix") + "Missing destination point in .gate file " + gate.getFilename()); } if (loc != null) { BlockData bd = getWorld().getBlockAt(loc).getBlockData(); if (bd instanceof Bisected && ((Bisected) bd).getHalf() == Bisected.Half.BOTTOM) { loc.add(0, 0.5, 0); } loc.setPitch(traveller.getPitch()); return loc; } return traveller; } public boolean isChunkLoaded() { return getWorld().isChunkLoaded(topLeft.getBlock().getChunk()); } public BlockLocation getId() { return this.id; } public int getModX() { return this.modX; } public int getModZ() { return this.modZ; } public float getRotX() { return this.rotX; } public BlockLocation getTopLeft() { return this.topLeft; } public boolean isVerified() { verified = true; if (!Stargate.verifyPortals) { return true; } for (RelativeBlockVector control : gate.getControls()) { verified = verified && getBlockAt(control).getBlock().getType().equals(gate.getControlBlock()); } return verified; } public boolean wasVerified() { if (!Stargate.verifyPortals) { return true; } return verified; } public boolean checkIntegrity() { if (!Stargate.verifyPortals) { return true; } return gate.matches(topLeft, modX, modZ); } public boolean activate(Player player) { destinations.clear(); destination = ""; Stargate.activeList.add(this); activePlayer = player; String network = getNetwork(); destinations = PortalHandler.getDestinations(player, network); if (Stargate.sortLists) { Collections.sort(destinations); } if (Stargate.destMemory && !lastDestination.isEmpty() && destinations.contains(lastDestination)) { destination = lastDestination; } StargateActivateEvent event = new StargateActivateEvent(this, player, destinations, destination); Stargate.server.getPluginManager().callEvent(event); if (event.isCancelled()) { Stargate.activeList.remove(this); return false; } destination = event.getDestination(); destinations = event.getDestinations(); drawSign(); return true; } public void deactivate() { StargateDeactivateEvent event = new StargateDeactivateEvent(this); Stargate.server.getPluginManager().callEvent(event); if (event.isCancelled()) return; Stargate.activeList.remove(this); if (isFixed()) { return; } destinations.clear(); destination = ""; activePlayer = null; drawSign(); } public boolean isActive() { return isFixed() || (destinations.size() > 0); } public void cycleDestination(Player player) { cycleDestination(player, 1); } public void cycleDestination(Player player, int dir) { boolean activate = false; if (!isActive() || getActivePlayer() != player) { // If the event is cancelled, return if (!activate(player)) { return; } Stargate.debug("cycleDestination", "Network Size: " + PortalHandler.getNetwork(network).size()); Stargate.debug("cycleDestination", "Player has access to: " + destinations.size()); activate = true; } if (destinations.size() == 0) { Stargate.sendMessage(player, Stargate.getString("destEmpty")); return; } if (!Stargate.destMemory || !activate || lastDestination.isEmpty()) { int index = destinations.indexOf(destination); index += dir; if (index >= destinations.size()) index = 0; else if (index < 0) index = destinations.size() - 1; destination = destinations.get(index); lastDestination = destination; } openTime = System.currentTimeMillis() / 1000; drawSign(); } public final void drawSign() { BlockState state = id.getBlock().getState(); if (!(state instanceof Sign)) { Stargate.log.warning(Stargate.getString("prefix") + "Sign block is not a Sign object"); Stargate.debug("Portal::drawSign", "Block: " + id.getBlock().getType() + " @ " + id.getBlock().getLocation()); return; } Sign sign = (Sign) state; Stargate.setLine(sign, 0, "-" + name + "-"); int max = destinations.size() - 1; int done = 0; if (!isActive()) { Stargate.setLine(sign, ++done, Stargate.getString("signRightClick")); Stargate.setLine(sign, ++done, Stargate.getString("signToUse")); if (!noNetwork) { Stargate.setLine(sign, ++done, "(" + network + ")"); } } else { // Awesome new logic for Bungee gates if (isBungee()) { Stargate.setLine(sign, ++done, Stargate.getString("bungeeSign")); Stargate.setLine(sign, ++done, ">" + destination + "<"); Stargate.setLine(sign, ++done, "[" + network + "]"); } else if (isFixed()) { if (isRandom()) { Stargate.setLine(sign, ++done, "> " + Stargate.getString("signRandom") + " <"); } else { Stargate.setLine(sign, ++done, ">" + destination + "<"); } if (noNetwork) { Stargate.setLine(sign, ++done, ""); } else { Stargate.setLine(sign, ++done, "(" + network + ")"); } Portal dest = PortalHandler.getByName(destination, network); if (dest == null && !isRandom()) { Stargate.setLine(sign, ++done, Stargate.getString("signDisconnected")); } else { Stargate.setLine(sign, ++done, ""); } } else { int index = destinations.indexOf(destination); if ((index == max) && (max > 1) && (++done <= 3)) { if (EconomyHandler.useEconomy() && EconomyHandler.freeGatesGreen) { Portal dest = PortalHandler.getByName(destinations.get(index - 2), network); boolean green = Stargate.isFree(activePlayer, this, dest); Stargate.setLine(sign, done, (green ? ChatColor.DARK_GREEN : "") + destinations.get(index - 2)); } else { Stargate.setLine(sign, done, destinations.get(index - 2)); } } if ((index > 0) && (++done <= 3)) { if (EconomyHandler.useEconomy() && EconomyHandler.freeGatesGreen) { Portal dest = PortalHandler.getByName(destinations.get(index - 1), network); boolean green = Stargate.isFree(activePlayer, this, dest); Stargate.setLine(sign, done, (green ? ChatColor.DARK_GREEN : "") + destinations.get(index - 1)); } else { Stargate.setLine(sign, done, destinations.get(index - 1)); } } if (++done <= 3) { if (EconomyHandler.useEconomy() && EconomyHandler.freeGatesGreen) { Portal dest = PortalHandler.getByName(destination, network); boolean green = Stargate.isFree(activePlayer, this, dest); Stargate.setLine(sign, done, (green ? ChatColor.DARK_GREEN : "") + ">" + destination + "<"); } else { Stargate.setLine(sign, done, " >" + destination + "< "); } } if ((max >= index + 1) && (++done <= 3)) { if (EconomyHandler.useEconomy() && EconomyHandler.freeGatesGreen) { Portal dest = PortalHandler.getByName(destinations.get(index + 1), network); boolean green = Stargate.isFree(activePlayer, this, dest); Stargate.setLine(sign, done, (green ? ChatColor.DARK_GREEN : "") + destinations.get(index + 1)); } else { Stargate.setLine(sign, done, destinations.get(index + 1)); } } if ((max >= index + 2) && (++done <= 3)) { if (EconomyHandler.useEconomy() && EconomyHandler.freeGatesGreen) { Portal dest = PortalHandler.getByName(destinations.get(index + 2), network); boolean green = Stargate.isFree(activePlayer, this, dest); Stargate.setLine(sign, done, (green ? ChatColor.DARK_GREEN : "") + destinations.get(index + 2)); } else { Stargate.setLine(sign, done, destinations.get(index + 2)); } } } } for (done++; done <= 3; done++) { sign.setLine(done, ""); } sign.update(); } BlockLocation getBlockAt(RelativeBlockVector vector) { return topLeft.modRelative(vector.getRight(), vector.getDepth(), vector.getDistance(), modX, 1, modZ); } /** * Removes the special characters |, : and # from a portal name * @param input

The name to filter

* @return

The filtered name

*/ public static String filterName(String input) { if (input == null) { return ""; } return input.replaceAll("[|:#]", "").trim(); } @Override public String toString() { return String.format("Portal [id=%s, network=%s name=%s, type=%s]", id, network, name, gate.getFilename()); } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((name == null) ? 0 : name.hashCode()); result = prime * result + ((network == null) ? 0 : network.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Portal other = (Portal) obj; if (name == null) { if (other.name != null) return false; } else if (!name.equalsIgnoreCase(other.name)) return false; if (network == null) { return other.network == null; } else { return network.equalsIgnoreCase(other.network); } } }