Splits the portal class into Portal, PortalActivator, PortalOpener and PortalStructure
PortalStructure now contains information about the gate's physical structure, such as the location of border blocks, the location of entrances, the gate type and the button location. PortalActivator is responsible for activating/de-activating portals, destination toggling and getting information about available destinations. PortalOpener is responsible for opening/closing a portal. It's also the place to go for checking if the portal is open for a given player. Comments of the Portal class have been improved, but the comments of the three new classes need fixing.
This commit is contained in:
parent
635d08b1b3
commit
d2e8c81a5a
@ -513,7 +513,7 @@ public class Stargate extends JavaPlugin {
|
||||
public void closeAllPortals() {
|
||||
// Close all gates prior to reloading
|
||||
for (Portal openPortal : openPortalsQueue) {
|
||||
openPortal.close(true);
|
||||
openPortal.getPortalOpener().closePortal(true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -563,7 +563,7 @@ public class Stargate extends JavaPlugin {
|
||||
public void reload(CommandSender sender) {
|
||||
// Deactivate portals
|
||||
for (Portal activePortal : activePortalsQueue) {
|
||||
activePortal.deactivate();
|
||||
activePortal.getPortalActivator().deactivate();
|
||||
}
|
||||
// Close portals
|
||||
closeAllPortals();
|
||||
|
@ -4,6 +4,7 @@ import net.knarcraft.stargate.Stargate;
|
||||
import net.knarcraft.stargate.container.BlockLocation;
|
||||
import net.knarcraft.stargate.portal.PlayerTeleporter;
|
||||
import net.knarcraft.stargate.portal.Portal;
|
||||
import net.knarcraft.stargate.portal.PortalActivator;
|
||||
import net.knarcraft.stargate.portal.PortalHandler;
|
||||
import net.knarcraft.stargate.portal.VehicleTeleporter;
|
||||
import net.knarcraft.stargate.utility.BungeeHelper;
|
||||
@ -81,7 +82,7 @@ public class PlayerEventListener implements Listener {
|
||||
return;
|
||||
}
|
||||
Portal entrancePortal = PortalHandler.getByEntrance(toLocation);
|
||||
Portal destination = entrancePortal.getDestination(player);
|
||||
Portal destination = entrancePortal.getPortalActivator().getDestination(player);
|
||||
|
||||
//Teleport the vehicle to the player
|
||||
Entity playerVehicle = player.getVehicle();
|
||||
@ -99,7 +100,7 @@ public class PlayerEventListener implements Listener {
|
||||
new PlayerTeleporter(destination, player).teleport(entrancePortal, event);
|
||||
}
|
||||
Stargate.sendSuccessMessage(player, Stargate.getString("teleportMsg"));
|
||||
entrancePortal.close(false);
|
||||
entrancePortal.getPortalOpener().closePortal(false);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -124,7 +125,7 @@ public class PlayerEventListener implements Listener {
|
||||
return false;
|
||||
}
|
||||
|
||||
Portal destination = entrancePortal.getDestination(player);
|
||||
Portal destination = entrancePortal.getPortalActivator().getDestination(player);
|
||||
|
||||
//Catch always open portals without a valid destination to prevent the user for being teleported and denied
|
||||
if (destination == null) {
|
||||
@ -200,10 +201,11 @@ public class PlayerEventListener implements Listener {
|
||||
|
||||
//Cycle portal destination
|
||||
if ((!portal.isOpen()) && (!portal.getOptions().isFixed())) {
|
||||
PortalActivator destinations = portal.getPortalActivator();
|
||||
if (leftClick) {
|
||||
portal.cycleDestination(player, -1);
|
||||
destinations.cycleDestination(player, -1);
|
||||
} else {
|
||||
portal.cycleDestination(player);
|
||||
destinations.cycleDestination(player);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -260,7 +262,7 @@ public class PlayerEventListener implements Listener {
|
||||
}
|
||||
|
||||
PermissionHelper.openPortal(player, portal);
|
||||
if (portal.isOpenFor(player)) {
|
||||
if (portal.getPortalOpener().isOpenFor(player)) {
|
||||
event.setUseInteractedBlock(Event.Result.ALLOW);
|
||||
}
|
||||
}
|
||||
@ -302,7 +304,7 @@ public class PlayerEventListener implements Listener {
|
||||
//Check if bungee is actually enabled
|
||||
if (!Stargate.enableBungee) {
|
||||
Stargate.sendErrorMessage(player, Stargate.getString("bungeeDisabled"));
|
||||
entrancePortal.close(false);
|
||||
entrancePortal.getPortalOpener().closePortal(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -323,7 +325,7 @@ public class PlayerEventListener implements Listener {
|
||||
|
||||
// Close portal if required (Should never be)
|
||||
Stargate.debug("bungeeTeleport", "Teleported player to another server");
|
||||
entrancePortal.close(false);
|
||||
entrancePortal.getPortalOpener().closePortal(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -64,11 +64,11 @@ public class PortalEventListener implements Listener {
|
||||
//Remove any old player teleportations in case weird things happen
|
||||
playersFromTheEnd.removeIf((teleportation -> teleportation.getPlayer() == player));
|
||||
//Decide if the anything stops the player from teleporting
|
||||
if (PermissionHelper.playerCannotTeleport(portal, portal.getDestination(), player, null)) {
|
||||
if (PermissionHelper.playerCannotTeleport(portal, portal.getPortalActivator().getDestination(), player, null)) {
|
||||
//Teleport the player back to the portal they came in, just in case
|
||||
playersFromTheEnd.add(new FromTheEndTeleportation(player, portal));
|
||||
}
|
||||
playersFromTheEnd.add(new FromTheEndTeleportation(player, portal.getDestination()));
|
||||
playersFromTheEnd.add(new FromTheEndTeleportation(player, portal.getPortalActivator().getDestination()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -92,7 +92,7 @@ public class PortalEventListener implements Listener {
|
||||
event.setRespawnLocation(new PlayerTeleporter(exitPortal, respawningPlayer).getExit(respawningPlayer,
|
||||
respawningPlayer.getLocation()));
|
||||
//Properly close the portal to prevent it from staying in a locked state until it times out
|
||||
exitPortal.close(false);
|
||||
exitPortal.getPortalOpener().closePortal(false);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -68,7 +68,7 @@ public class VehicleEventListener implements Listener {
|
||||
teleportPlayerAndVehicle(entrancePortal, vehicle, passengers);
|
||||
} else {
|
||||
Stargate.debug(route, prefix + "Found empty vehicle");
|
||||
Portal destinationPortal = entrancePortal.getDestination();
|
||||
Portal destinationPortal = entrancePortal.getPortalActivator().getDestination();
|
||||
if (destinationPortal == null) {
|
||||
Stargate.debug(route, prefix + "Unable to find portal destination");
|
||||
return;
|
||||
@ -90,13 +90,13 @@ public class VehicleEventListener implements Listener {
|
||||
Player player = (Player) passengers.get(0);
|
||||
//On the assumption that a non-player cannot sit in the driver's seat and since some portals can only be open
|
||||
// to one player at a time, we only need to check if the portal is open to the driver.
|
||||
if (!entrancePortal.isOpenFor(player)) {
|
||||
if (!entrancePortal.getPortalOpener().isOpenFor(player)) {
|
||||
Stargate.sendErrorMessage(player, Stargate.getString("denyMsg"));
|
||||
return;
|
||||
}
|
||||
|
||||
//If no destination exists, the teleportation cannot happen
|
||||
Portal destinationPortal = entrancePortal.getDestination(player);
|
||||
Portal destinationPortal = entrancePortal.getPortalActivator().getDestination(player);
|
||||
if (destinationPortal == null) {
|
||||
return;
|
||||
}
|
||||
@ -119,7 +119,7 @@ public class VehicleEventListener implements Listener {
|
||||
|
||||
Stargate.sendSuccessMessage(player, Stargate.getString("teleportMsg"));
|
||||
new VehicleTeleporter(destinationPortal, vehicle).teleport(entrancePortal);
|
||||
entrancePortal.close(false);
|
||||
entrancePortal.getPortalOpener().closePortal(false);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -152,7 +152,7 @@ public class VehicleEventListener implements Listener {
|
||||
//Make sure the user can access the portal
|
||||
if (PermissionHelper.cannotAccessPortal(player, entrancePortal, destinationPortal)) {
|
||||
Stargate.sendErrorMessage(player, Stargate.getString("denyMsg"));
|
||||
entrancePortal.close(false);
|
||||
entrancePortal.getPortalOpener().closePortal(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1,24 +1,11 @@
|
||||
package net.knarcraft.stargate.portal;
|
||||
|
||||
import net.knarcraft.stargate.Stargate;
|
||||
import net.knarcraft.stargate.container.BlockChangeRequest;
|
||||
import net.knarcraft.stargate.container.BlockLocation;
|
||||
import net.knarcraft.stargate.container.RelativeBlockVector;
|
||||
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 org.bukkit.Axis;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.data.Orientable;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
@ -26,59 +13,77 @@ import java.util.UUID;
|
||||
*/
|
||||
public class Portal {
|
||||
|
||||
// Gate location block info
|
||||
// Gate information
|
||||
private final String name;
|
||||
private final String network;
|
||||
private final String ownerName;
|
||||
private final UUID ownerUUID;
|
||||
|
||||
private final PortalOptions options;
|
||||
private final PortalOpener portalOpener;
|
||||
private final PortalLocation location;
|
||||
private final PortalSignDrawer signDrawer;
|
||||
|
||||
// Block references
|
||||
private final Gate gate;
|
||||
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 String ownerName;
|
||||
private UUID ownerUUID;
|
||||
private boolean verified;
|
||||
private final PortalOptions options;
|
||||
|
||||
// In-use information
|
||||
private Player player;
|
||||
private Player activePlayer;
|
||||
private List<String> destinations = new ArrayList<>();
|
||||
private boolean isOpen = false;
|
||||
private long openTime;
|
||||
private final PortalStructure structure;
|
||||
private final PortalActivator portalActivator;
|
||||
|
||||
/**
|
||||
* Instantiates a new portal
|
||||
*
|
||||
* @param portalLocation <p>Object containing locations of all relevant blocks</p>
|
||||
* @param button <p>The location of the portal's open button</p>
|
||||
* @param destination <p>The destination defined on the sign's destination line</p>
|
||||
* @param destination <p>The destination defined on the sign's destination line. "" for non-fixed gates</p>
|
||||
* @param name <p>The name of the portal defined on the sign's first line</p>
|
||||
* @param network <p>The network the portal belongs to, defined on the sign's network line</p>
|
||||
* @param gate <p>The gate template this portal uses</p>
|
||||
* @param network <p>The network the portal belongs to, defined on the sign's third</p>
|
||||
* @param gate <p>The gate type to use for this portal</p>
|
||||
* @param ownerUUID <p>The UUID of the gate's owner</p>
|
||||
* @param ownerName <p>The name of the gate's owner</p>
|
||||
* @param options <p>A map containing all possible portal options</p>
|
||||
* @param options <p>A map containing all possible portal options, with true for the ones enabled</p>
|
||||
*/
|
||||
Portal(PortalLocation portalLocation, BlockLocation button, String destination, String name, String network,
|
||||
Gate gate, UUID ownerUUID, String ownerName, Map<PortalOption, Boolean> options) {
|
||||
public Portal(PortalLocation portalLocation, BlockLocation button, String destination, String name, String network,
|
||||
Gate gate, UUID ownerUUID, String ownerName, Map<PortalOption, Boolean> options) {
|
||||
this.location = portalLocation;
|
||||
this.destination = destination;
|
||||
this.button = button;
|
||||
this.verified = false;
|
||||
this.network = network;
|
||||
this.name = name;
|
||||
this.gate = gate;
|
||||
this.ownerUUID = ownerUUID;
|
||||
this.ownerName = ownerName;
|
||||
this.options = new PortalOptions(options, destination.length() > 0);
|
||||
this.signDrawer = new PortalSignDrawer(this);
|
||||
this.portalOpener = new PortalOpener(this, destination);
|
||||
this.structure = new PortalStructure(this, gate, button);
|
||||
this.portalActivator = portalOpener.getPortalOpener();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the location data for this portal
|
||||
*
|
||||
* @return <p>This portal's location data</p>
|
||||
*/
|
||||
public PortalLocation getLocation() {
|
||||
return this.location;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the structure of this portal
|
||||
*
|
||||
* <p>The structure contains information about the portal's gate, button and real locations of frames and
|
||||
* entrances. The structure is also responsible for verifying built StarGates to make sure they match the gate.</p>
|
||||
*
|
||||
* @return <p>This portal's structure</p>
|
||||
*/
|
||||
public PortalStructure getStructure() {
|
||||
return this.structure;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets this portal's activator
|
||||
*
|
||||
* <p>The activator is responsible for activating/de-activating the portal and contains information about
|
||||
* available destinations and which player activated the portal.</p>
|
||||
*
|
||||
* @return <p>This portal's activator</p>
|
||||
*/
|
||||
public PortalActivator getPortalActivator() {
|
||||
return this.portalActivator;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -103,7 +108,7 @@ public class Portal {
|
||||
* @return <p>Whether this portal is open</p>
|
||||
*/
|
||||
public boolean isOpen() {
|
||||
return isOpen || options.isAlwaysOn();
|
||||
return portalOpener.isOpen();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -112,35 +117,28 @@ public class Portal {
|
||||
* @return <p>The player currently using this portal</p>
|
||||
*/
|
||||
public Player getActivePlayer() {
|
||||
return activePlayer;
|
||||
return portalActivator.getActivePlayer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the network this gate belongs to
|
||||
* Gets the network this portal belongs to
|
||||
*
|
||||
* @return <p>The network this gate belongs to</p>
|
||||
* @return <p>The network this portal belongs to</p>
|
||||
*/
|
||||
public String getNetwork() {
|
||||
return network;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the network this gate belongs to
|
||||
*
|
||||
* @param network <p>The new network for this gate</p>
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public void setNetwork(String network) {
|
||||
this.network = network;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the time this portal opened
|
||||
*
|
||||
* <p>The time is given in the equivalent of a Unix timestamp. It's used to decide when a portal times out and
|
||||
* automatically closes.</p>
|
||||
*
|
||||
* @return <p>The time this portal opened</p>
|
||||
*/
|
||||
public long getOpenTime() {
|
||||
return openTime;
|
||||
return portalOpener.getOpenTime();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -153,94 +151,39 @@ public class Portal {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of this portal
|
||||
* Gets the portal opener used by this portal
|
||||
*
|
||||
* @param name <p>The new name of this portal</p>
|
||||
* <p>The portal opener is responsible for opening and closing this portal.</p>
|
||||
*
|
||||
* @return <p>This portal's portal opener</p>
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public void setName(String name) {
|
||||
this.name = filterName(name);
|
||||
this.drawSign();
|
||||
public PortalOpener getPortalOpener() {
|
||||
return portalOpener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the destinations of this portal
|
||||
* Gets the name of this portal's destination portal
|
||||
*
|
||||
* @return <p>The destinations of this portal</p>
|
||||
*/
|
||||
public List<String> getDestinations() {
|
||||
return new ArrayList<>(this.destinations);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the portal destination given a player
|
||||
*
|
||||
* @param player <p>Used for random gates to determine which destinations are available</p>
|
||||
* @return <p>The destination portal the player should teleport to</p>
|
||||
*/
|
||||
public Portal getDestination(Player player) {
|
||||
if (options.isRandom()) {
|
||||
destinations = PortalHandler.getDestinations(this, player, getNetwork());
|
||||
if (destinations.size() == 0) {
|
||||
return null;
|
||||
}
|
||||
String destination = destinations.get((new Random()).nextInt(destinations.size()));
|
||||
destinations.clear();
|
||||
return PortalHandler.getByName(destination, getNetwork());
|
||||
}
|
||||
return PortalHandler.getByName(destination, getNetwork());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the portal destination
|
||||
*
|
||||
* <p>If this portal is random, a player should be given to get correct destinations.</p>
|
||||
*
|
||||
* @return <p>The portal destination</p>
|
||||
*/
|
||||
public Portal getDestination() {
|
||||
return getDestination(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the destination of this portal
|
||||
*
|
||||
* @param destination <p>The new destination of this portal</p>
|
||||
*/
|
||||
public void setDestination(Portal destination) {
|
||||
setDestination(destination.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the destination of this portal
|
||||
*
|
||||
* @param destination <p>The new destination of this portal</p>
|
||||
*/
|
||||
public void setDestination(String destination) {
|
||||
this.destination = destination;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of the destination of this portal
|
||||
*
|
||||
* @return <p>The name of this portal's destination</p>
|
||||
* @return <p>The name of this portal's destination portal</p>
|
||||
*/
|
||||
public String getDestinationName() {
|
||||
return destination;
|
||||
return portalOpener.getPortalOpener().getDestinationName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the gate used by this portal
|
||||
* Gets the gate type used by this portal
|
||||
*
|
||||
* @return <p>The gate used by this portal</p>
|
||||
* @return <p>The gate type used by this portal</p>
|
||||
*/
|
||||
public Gate getGate() {
|
||||
return gate;
|
||||
return structure.getGate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of this portal's owner
|
||||
*
|
||||
* <p>The owner is the player which created the portal.</p>
|
||||
*
|
||||
* @return <p>The name of this portal's owner</p>
|
||||
*/
|
||||
public String getOwnerName() {
|
||||
@ -250,22 +193,14 @@ public class Portal {
|
||||
/**
|
||||
* Gets the UUID of this portal's owner
|
||||
*
|
||||
* <p>The owner is the player which created the portal.</p>
|
||||
*
|
||||
* @return <p>The UUID of this portal's owner</p>
|
||||
*/
|
||||
public UUID getOwnerUUID() {
|
||||
return ownerUUID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the UUId of this portal's owner
|
||||
*
|
||||
* @param owner <p>The new UUID of this portal's owner</p>
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public void setOwner(UUID owner) {
|
||||
this.ownerUUID = owner;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a given player is the owner of this portal
|
||||
*
|
||||
@ -280,30 +215,6 @@ public class Portal {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the locations of this portal's entrances
|
||||
*
|
||||
* @return <p>The locations of this portal's entrances</p>
|
||||
*/
|
||||
public BlockLocation[] getEntrances() {
|
||||
if (entrances == null) {
|
||||
entrances = relativeBlockVectorsToBlockLocations(gate.getLayout().getEntrances());
|
||||
}
|
||||
return entrances;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the locations of this portal's frame
|
||||
*
|
||||
* @return <p>The locations of this portal's frame</p>
|
||||
*/
|
||||
public BlockLocation[] getFrame() {
|
||||
if (frame == null) {
|
||||
frame = relativeBlockVectorsToBlockLocations(gate.getLayout().getBorder());
|
||||
}
|
||||
return frame;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the world this portal belongs to
|
||||
*
|
||||
@ -314,167 +225,21 @@ public class Portal {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the location of this portal's button
|
||||
* Gets the location of this portal's sign
|
||||
*
|
||||
* @return <p>The location of this portal's button</p>
|
||||
*/
|
||||
public BlockLocation getButton() {
|
||||
return button;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the location of this portal's button
|
||||
*
|
||||
* @param button <p>The location of this portal's button</p>
|
||||
*/
|
||||
public void setButton(BlockLocation button) {
|
||||
this.button = button;
|
||||
}
|
||||
|
||||
/**
|
||||
* Open this portal
|
||||
*
|
||||
* @param force <p>Whether to force this portal open, even if it's already open for some player</p>
|
||||
*/
|
||||
public void open(boolean force) {
|
||||
open(null, force);
|
||||
}
|
||||
|
||||
/**
|
||||
* Open this portal
|
||||
*
|
||||
* @param force <p>Whether to force this portal open, even if it's already open for some player</p>
|
||||
*/
|
||||
public void open(Player openFor, boolean force) {
|
||||
//Call the StargateOpenEvent
|
||||
StargateOpenEvent event = new StargateOpenEvent(openFor, this, force);
|
||||
Stargate.server.getPluginManager().callEvent(event);
|
||||
if (event.isCancelled() || (isOpen() && !event.getForce())) {
|
||||
return;
|
||||
}
|
||||
|
||||
//Change the opening blocks to the correct type
|
||||
Material openType = gate.getPortalOpenBlock();
|
||||
Axis axis = (openType.createBlockData() instanceof Orientable) ? location.getRotationAxis() : null;
|
||||
for (BlockLocation inside : getEntrances()) {
|
||||
Stargate.blockChangeRequestQueue.add(new BlockChangeRequest(inside, openType, axis));
|
||||
}
|
||||
|
||||
updatePortalOpenState(openFor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates this portal to be recognized as open and opens its destination portal
|
||||
*
|
||||
* @param openFor <p>The player to open this portal for</p>
|
||||
*/
|
||||
private void updatePortalOpenState(Player openFor) {
|
||||
//Update the open state of this portal
|
||||
isOpen = true;
|
||||
openTime = System.currentTimeMillis() / 1000;
|
||||
Stargate.openPortalsQueue.add(this);
|
||||
Stargate.activePortalsQueue.remove(this);
|
||||
|
||||
//Open remote portal
|
||||
if (!options.isAlwaysOn()) {
|
||||
player = openFor;
|
||||
|
||||
Portal destination = getDestination();
|
||||
//Only open destination if it's not-fixed or points at this portal
|
||||
if (!options.isRandom() && destination != null && (!destination.options.isFixed() ||
|
||||
destination.getDestinationName().equalsIgnoreCase(getName())) && !destination.isOpen()) {
|
||||
destination.open(openFor, false);
|
||||
destination.setDestination(this);
|
||||
if (destination.isVerified()) {
|
||||
destination.drawSign();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes this portal
|
||||
*
|
||||
* @param force <p>Whether to force this portal closed, even if it's set as always on</p>
|
||||
*/
|
||||
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();
|
||||
|
||||
//Only close always-open if forced to
|
||||
if (options.isAlwaysOn() && !force) {
|
||||
return;
|
||||
}
|
||||
|
||||
//Close this gate, then the dest gate.
|
||||
Material closedType = gate.getPortalClosedBlock();
|
||||
for (BlockLocation inside : getEntrances()) {
|
||||
Stargate.blockChangeRequestQueue.add(new BlockChangeRequest(inside, closedType, null));
|
||||
}
|
||||
|
||||
updatePortalClosedState();
|
||||
deactivate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates this portal to be recognized as closed and closes its destination portal
|
||||
*/
|
||||
private void updatePortalClosedState() {
|
||||
//Update the closed state of this portal
|
||||
player = null;
|
||||
isOpen = false;
|
||||
Stargate.openPortalsQueue.remove(this);
|
||||
Stargate.activePortalsQueue.remove(this);
|
||||
|
||||
//Close remote portal
|
||||
if (!options.isAlwaysOn()) {
|
||||
Portal end = getDestination();
|
||||
|
||||
if (end != null && end.isOpen()) {
|
||||
//Clear its destination first
|
||||
end.deactivate();
|
||||
end.close(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether this portal is open for the given player
|
||||
*
|
||||
* @param player <p>The player to check portal state for</p>
|
||||
* @return <p>True if this portal is open to the given player</p>
|
||||
*/
|
||||
public boolean isOpenFor(Player player) {
|
||||
if (!isOpen) {
|
||||
return false;
|
||||
}
|
||||
if (options.isAlwaysOn() || this.player == null) {
|
||||
return true;
|
||||
}
|
||||
return player != null && player.getName().equalsIgnoreCase(this.player.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the identity (sign) location of the portal
|
||||
*
|
||||
* @return <p>The identity location of the portal</p>
|
||||
* @return <p>The location of this portal's sign</p>
|
||||
*/
|
||||
public BlockLocation getSignLocation() {
|
||||
return this.location.getSignLocation();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the rotation of this portal
|
||||
* Gets the rotation (yaw) of this portal
|
||||
*
|
||||
* @return <p>The rotation of this portal</p>
|
||||
* <p>The yaw is used to calculate all kinds of directions. See DirectionHelper to see how the yaw is used to
|
||||
* calculate to/from other direction types.</p>
|
||||
*
|
||||
* @return <p>The rotation (yaw) of this portal</p>
|
||||
*/
|
||||
public float getYaw() {
|
||||
return this.location.getYaw();
|
||||
@ -490,213 +255,19 @@ public class Portal {
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that all control blocks in this portal follows its gate template
|
||||
* Gets the block at the given location relative to this portal's top-left block
|
||||
*
|
||||
* @return <p>True if all control blocks were verified</p>
|
||||
*/
|
||||
public boolean isVerified() {
|
||||
verified = true;
|
||||
if (!Stargate.verifyPortals) {
|
||||
return true;
|
||||
}
|
||||
for (RelativeBlockVector control : gate.getLayout().getControls()) {
|
||||
verified = verified && getBlockAt(control).getBlock().getType().equals(gate.getControlBlock());
|
||||
}
|
||||
return verified;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the result of the last portal verification
|
||||
*
|
||||
* @return <p>True if this portal was verified</p>
|
||||
*/
|
||||
public boolean wasVerified() {
|
||||
if (!Stargate.verifyPortals) {
|
||||
return true;
|
||||
}
|
||||
return verified;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if all blocks in a gate matches the gate template
|
||||
*
|
||||
* @return <p>True if all blocks match the gate template</p>
|
||||
*/
|
||||
public boolean checkIntegrity() {
|
||||
if (!Stargate.verifyPortals) {
|
||||
return true;
|
||||
}
|
||||
return gate.matches(getTopLeft(), getYaw());
|
||||
}
|
||||
|
||||
/**
|
||||
* Activates this portal for the given player
|
||||
*
|
||||
* @param player <p>The player to activate the portal for</p>
|
||||
* @return <p>True if the portal was activated</p>
|
||||
*/
|
||||
private boolean activate(Player player) {
|
||||
destinations.clear();
|
||||
destination = "";
|
||||
Stargate.activePortalsQueue.add(this);
|
||||
activePlayer = player;
|
||||
String network = getNetwork();
|
||||
destinations = PortalHandler.getDestinations(this, player, network);
|
||||
if (Stargate.sortNetworkDestinations) {
|
||||
Collections.sort(destinations);
|
||||
}
|
||||
if (Stargate.rememberDestination && !lastDestination.isEmpty() && destinations.contains(lastDestination)) {
|
||||
destination = lastDestination;
|
||||
}
|
||||
|
||||
StargateActivateEvent event = new StargateActivateEvent(this, player, destinations, destination);
|
||||
Stargate.server.getPluginManager().callEvent(event);
|
||||
if (event.isCancelled()) {
|
||||
Stargate.activePortalsQueue.remove(this);
|
||||
return false;
|
||||
}
|
||||
destination = event.getDestination();
|
||||
destinations = event.getDestinations();
|
||||
this.drawSign();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deactivates this portal
|
||||
*/
|
||||
public void deactivate() {
|
||||
StargateDeactivateEvent event = new StargateDeactivateEvent(this);
|
||||
Stargate.server.getPluginManager().callEvent(event);
|
||||
if (event.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Stargate.activePortalsQueue.remove(this);
|
||||
if (options.isFixed()) {
|
||||
return;
|
||||
}
|
||||
destinations.clear();
|
||||
destination = "";
|
||||
activePlayer = null;
|
||||
this.drawSign();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether this portal is active
|
||||
*
|
||||
* @return <p>Whether this portal is active</p>
|
||||
*/
|
||||
public boolean isActive() {
|
||||
return options.isFixed() || (destinations.size() > 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cycles destination for a network gate forwards
|
||||
*
|
||||
* @param player <p>The player to cycle the gate for</p>
|
||||
*/
|
||||
public void cycleDestination(Player player) {
|
||||
cycleDestination(player, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cycles destination for a network gate
|
||||
*
|
||||
* @param player <p>The player cycling destinations</p>
|
||||
* @param direction <p>The direction of the cycle (+1 for next, -1 for previous)</p>
|
||||
*/
|
||||
public void cycleDestination(Player player, int direction) {
|
||||
if (direction != 1 && direction != -1) {
|
||||
throw new IllegalArgumentException("The destination direction must be 1 or -1.");
|
||||
}
|
||||
|
||||
boolean activate = false;
|
||||
if (!isActive() || getActivePlayer() != player) {
|
||||
//If the stargate activate 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.sendErrorMessage(player, Stargate.getString("destEmpty"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Stargate.rememberDestination || !activate || lastDestination.isEmpty()) {
|
||||
cycleDestination(direction);
|
||||
}
|
||||
openTime = System.currentTimeMillis() / 1000;
|
||||
this.drawSign();
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the actual destination cycling with no input checks
|
||||
*
|
||||
* @param direction <p>The direction of the cycle (+1 for next, -1 for previous)</p>
|
||||
*/
|
||||
private void cycleDestination(int direction) {
|
||||
int index = destinations.indexOf(destination);
|
||||
index += direction;
|
||||
|
||||
//Wrap around if the last destination has been reached
|
||||
if (index >= destinations.size()) {
|
||||
index = 0;
|
||||
} else if (index < 0) {
|
||||
index = destinations.size() - 1;
|
||||
}
|
||||
//Store selected destination
|
||||
destination = destinations.get(index);
|
||||
lastDestination = destination;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the block at the given location relative to this portal's location
|
||||
*
|
||||
* @param vector <p>The relative block vector</p>
|
||||
* @param vector <p>The relative block vector explaining the position of the block</p>
|
||||
* @return <p>The block at the given relative position</p>
|
||||
*/
|
||||
public BlockLocation getBlockAt(RelativeBlockVector vector) {
|
||||
return getTopLeft().getRelativeLocation(vector, getYaw());
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the special characters |, : and # from a portal name
|
||||
*
|
||||
* @param input <p>The name to filter</p>
|
||||
* @return <p>The filtered name</p>
|
||||
*/
|
||||
private static String filterName(String input) {
|
||||
if (input == null) {
|
||||
return "";
|
||||
}
|
||||
return input.replaceAll("[|:#]", "").trim();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of block locations from a list of relative block vectors
|
||||
*
|
||||
* <p>The block locations will be calculated by using this portal's top-left block as the origin for the relative
|
||||
* vectors..</p>
|
||||
*
|
||||
* @param vectors <p>The relative block vectors to convert</p>
|
||||
* @return <p>A list of block locations</p>
|
||||
*/
|
||||
private BlockLocation[] relativeBlockVectorsToBlockLocations(RelativeBlockVector[] vectors) {
|
||||
BlockLocation[] locations = new BlockLocation[vectors.length];
|
||||
for (int i = 0; i < vectors.length; i++) {
|
||||
locations[i] = getBlockAt(vectors[i]);
|
||||
}
|
||||
return locations;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("Portal [id=%s, network=%s name=%s, type=%s]", getSignLocation(), network, name,
|
||||
gate.getFilename());
|
||||
structure.getGate().getFilename());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
241
src/main/java/net/knarcraft/stargate/portal/PortalActivator.java
Normal file
241
src/main/java/net/knarcraft/stargate/portal/PortalActivator.java
Normal file
@ -0,0 +1,241 @@
|
||||
package net.knarcraft.stargate.portal;
|
||||
|
||||
import net.knarcraft.stargate.Stargate;
|
||||
import net.knarcraft.stargate.event.StargateActivateEvent;
|
||||
import net.knarcraft.stargate.event.StargateDeactivateEvent;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* The portal destinations contain information about a portal's destinations, and is responsible for cycling destinations
|
||||
*
|
||||
* <p>The activator is responsible for activating/de-activating the portal and contains information about
|
||||
* available destinations and which player activated the portal.</p>
|
||||
*/
|
||||
public class PortalActivator {
|
||||
|
||||
private String destination;
|
||||
private String lastDestination = "";
|
||||
private List<String> destinations = new ArrayList<>();
|
||||
private final Portal portal;
|
||||
private final PortalOpener activator;
|
||||
private Player activePlayer;
|
||||
|
||||
/**
|
||||
* Instantiates a new portal destinations object
|
||||
*
|
||||
* @param portal <p>The portal which this this object stores destinations for</p>
|
||||
* @param activator <p>The activator to use when a player activates a portal</p>
|
||||
* @param destination <p></p>
|
||||
*/
|
||||
public PortalActivator(Portal portal, PortalOpener activator, String destination) {
|
||||
this.portal = portal;
|
||||
this.activator = activator;
|
||||
this.destination = destination;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the player currently using this portal activator's portal
|
||||
*
|
||||
* @return <p>The player currently using this portal activator's portal</p>
|
||||
*/
|
||||
public Player getActivePlayer() {
|
||||
return activePlayer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the destinations of this portal
|
||||
*
|
||||
* @return <p>The destinations of this portal</p>
|
||||
*/
|
||||
public List<String> getDestinations() {
|
||||
return new ArrayList<>(this.destinations);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the portal destination given a player
|
||||
*
|
||||
* @param player <p>Used for random gates to determine which destinations are available</p>
|
||||
* @return <p>The destination portal the player should teleport to</p>
|
||||
*/
|
||||
public Portal getDestination(Player player) {
|
||||
if (portal.getOptions().isRandom()) {
|
||||
destinations = PortalHandler.getDestinations(portal, player, portal.getNetwork());
|
||||
if (destinations.size() == 0) {
|
||||
return null;
|
||||
}
|
||||
String destination = destinations.get((new Random()).nextInt(destinations.size()));
|
||||
destinations.clear();
|
||||
return PortalHandler.getByName(destination, portal.getNetwork());
|
||||
}
|
||||
return PortalHandler.getByName(destination, portal.getNetwork());
|
||||
}
|
||||
|
||||
/**
|
||||
* Activates this portal for the given player
|
||||
*
|
||||
* @param player <p>The player to activate the portal for</p>
|
||||
* @return <p>True if the portal was activated</p>
|
||||
*/
|
||||
boolean activate(Player player) {
|
||||
this.destination = "";
|
||||
this.destinations.clear();
|
||||
Stargate.activePortalsQueue.add(portal);
|
||||
activePlayer = player;
|
||||
String network = portal.getNetwork();
|
||||
destinations = PortalHandler.getDestinations(portal, player, network);
|
||||
if (Stargate.sortNetworkDestinations) {
|
||||
Collections.sort(destinations);
|
||||
}
|
||||
if (Stargate.rememberDestination && !lastDestination.isEmpty() && destinations.contains(lastDestination)) {
|
||||
destination = lastDestination;
|
||||
}
|
||||
|
||||
StargateActivateEvent event = new StargateActivateEvent(portal, player, destinations, destination);
|
||||
Stargate.server.getPluginManager().callEvent(event);
|
||||
if (event.isCancelled()) {
|
||||
Stargate.activePortalsQueue.remove(portal);
|
||||
return false;
|
||||
}
|
||||
destination = event.getDestination();
|
||||
destinations = event.getDestinations();
|
||||
portal.drawSign();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deactivates this portal
|
||||
*/
|
||||
public void deactivate() {
|
||||
StargateDeactivateEvent event = new StargateDeactivateEvent(portal);
|
||||
Stargate.server.getPluginManager().callEvent(event);
|
||||
if (event.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Stargate.activePortalsQueue.remove(portal);
|
||||
if (portal.getOptions().isFixed()) {
|
||||
return;
|
||||
}
|
||||
destinations.clear();
|
||||
destination = "";
|
||||
activePlayer = null;
|
||||
portal.drawSign();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether this portal is active
|
||||
*
|
||||
* @return <p>Whether this portal is active</p>
|
||||
*/
|
||||
public boolean isActive() {
|
||||
return portal.getOptions().isFixed() || (destinations.size() > 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the portal destination
|
||||
*
|
||||
* <p>If this portal is random, a player should be given to get correct destinations.</p>
|
||||
*
|
||||
* @return <p>The portal destination</p>
|
||||
*/
|
||||
public Portal getDestination() {
|
||||
return getDestination(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the destination of this portal
|
||||
*
|
||||
* @param destination <p>The new destination of this portal</p>
|
||||
*/
|
||||
public void setDestination(Portal destination) {
|
||||
setDestination(destination.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the destination of this portal
|
||||
*
|
||||
* @param destination <p>The new destination of this portal</p>
|
||||
*/
|
||||
public void setDestination(String destination) {
|
||||
this.destination = destination;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of the destination of this portal
|
||||
*
|
||||
* @return <p>The name of this portal's destination</p>
|
||||
*/
|
||||
public String getDestinationName() {
|
||||
return destination;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cycles destination for a network gate forwards
|
||||
*
|
||||
* @param player <p>The player to cycle the gate for</p>
|
||||
*/
|
||||
public void cycleDestination(Player player) {
|
||||
cycleDestination(player, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cycles destination for a network gate
|
||||
*
|
||||
* @param player <p>The player cycling destinations</p>
|
||||
* @param direction <p>The direction of the cycle (+1 for next, -1 for previous)</p>
|
||||
*/
|
||||
public void cycleDestination(Player player, int direction) {
|
||||
if (direction != 1 && direction != -1) {
|
||||
throw new IllegalArgumentException("The destination direction must be 1 or -1.");
|
||||
}
|
||||
|
||||
boolean activate = false;
|
||||
if (!isActive() || getActivePlayer() != player) {
|
||||
//If the stargate activate event is cancelled, return
|
||||
if (!activate(player)) {
|
||||
return;
|
||||
}
|
||||
Stargate.debug("cycleDestination", "Network Size: " +
|
||||
PortalHandler.getNetwork(portal.getNetwork()).size());
|
||||
Stargate.debug("cycleDestination", "Player has access to: " + destinations.size());
|
||||
activate = true;
|
||||
}
|
||||
|
||||
if (destinations.size() == 0) {
|
||||
Stargate.sendErrorMessage(player, Stargate.getString("destEmpty"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Stargate.rememberDestination || !activate || lastDestination.isEmpty()) {
|
||||
cycleDestination(direction);
|
||||
}
|
||||
activator.setOpenTime(System.currentTimeMillis() / 1000);
|
||||
portal.drawSign();
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the actual destination cycling with no input checks
|
||||
*
|
||||
* @param direction <p>The direction of the cycle (+1 for next, -1 for previous)</p>
|
||||
*/
|
||||
private void cycleDestination(int direction) {
|
||||
int index = destinations.indexOf(destination);
|
||||
index += direction;
|
||||
|
||||
//Wrap around if the last destination has been reached
|
||||
if (index >= destinations.size()) {
|
||||
index = 0;
|
||||
} else if (index < 0) {
|
||||
index = destinations.size() - 1;
|
||||
}
|
||||
//Store selected destination
|
||||
destination = destinations.get(index);
|
||||
lastDestination = destination;
|
||||
}
|
||||
|
||||
}
|
@ -119,26 +119,28 @@ public class PortalHandler {
|
||||
*/
|
||||
public static void unregisterPortal(Portal portal, boolean removeAll) {
|
||||
Stargate.debug("Unregister", "Unregistering gate " + portal.getName());
|
||||
portal.close(true);
|
||||
portal.getPortalOpener().closePortal(true);
|
||||
|
||||
String portalName = portal.getName().toLowerCase();
|
||||
String networkName = portal.getNetwork().toLowerCase();
|
||||
|
||||
//Remove portal from lookup blocks
|
||||
for (BlockLocation block : portal.getFrame()) {
|
||||
for (BlockLocation block : portal.getStructure().getFrame()) {
|
||||
lookupBlocks.remove(block);
|
||||
}
|
||||
|
||||
//Remove registered info about the lookup controls and blocks
|
||||
lookupBlocks.remove(portal.getSignLocation());
|
||||
lookupControls.remove(portal.getSignLocation());
|
||||
if (portal.getButton() != null) {
|
||||
lookupBlocks.remove(portal.getButton());
|
||||
lookupControls.remove(portal.getButton());
|
||||
|
||||
BlockLocation button = portal.getStructure().getButton();
|
||||
if (button != null) {
|
||||
lookupBlocks.remove(button);
|
||||
lookupControls.remove(button);
|
||||
}
|
||||
|
||||
//Remove entrances
|
||||
for (BlockLocation entrance : portal.getEntrances()) {
|
||||
for (BlockLocation entrance : portal.getStructure().getEntrances()) {
|
||||
lookupEntrances.remove(entrance);
|
||||
}
|
||||
|
||||
@ -158,7 +160,8 @@ public class PortalHandler {
|
||||
//Update all portals in the same network with this portal as its destination
|
||||
for (String originName : allPortalNetworks.get(networkName)) {
|
||||
Portal origin = getByName(originName, portal.getNetwork());
|
||||
if (origin == null || !origin.getDestinationName().equalsIgnoreCase(portalName) || !origin.isVerified()) {
|
||||
if (origin == null || !origin.getDestinationName().equalsIgnoreCase(portalName) ||
|
||||
!origin.getStructure().isVerified()) {
|
||||
continue;
|
||||
}
|
||||
//Update the portal's sign
|
||||
@ -167,7 +170,7 @@ public class PortalHandler {
|
||||
}
|
||||
//Close portal without destination
|
||||
if (origin.getOptions().isAlwaysOn()) {
|
||||
origin.close(true);
|
||||
origin.getPortalOpener().closePortal(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -218,19 +221,21 @@ public class PortalHandler {
|
||||
}
|
||||
|
||||
//Register all frame blocks to the lookup list
|
||||
for (BlockLocation block : portal.getFrame()) {
|
||||
for (BlockLocation block : portal.getStructure().getFrame()) {
|
||||
lookupBlocks.put(block, portal);
|
||||
}
|
||||
//Register the sign and button to the lookup lists
|
||||
lookupBlocks.put(portal.getSignLocation(), portal);
|
||||
lookupControls.put(portal.getSignLocation(), portal);
|
||||
if (portal.getButton() != null) {
|
||||
lookupBlocks.put(portal.getButton(), portal);
|
||||
lookupControls.put(portal.getButton(), portal);
|
||||
|
||||
BlockLocation button = portal.getStructure().getButton();
|
||||
if (button != null) {
|
||||
lookupBlocks.put(button, portal);
|
||||
lookupControls.put(button, portal);
|
||||
}
|
||||
|
||||
//Register entrances to the lookup list
|
||||
for (BlockLocation entrance : portal.getEntrances()) {
|
||||
for (BlockLocation entrance : portal.getStructure().getEntrances()) {
|
||||
lookupEntrances.put(entrance, portal);
|
||||
}
|
||||
|
||||
@ -574,7 +579,7 @@ public class PortalHandler {
|
||||
Directional buttonData = (Directional) Bukkit.createBlockData(portal.getGate().getPortalButton());
|
||||
buttonData.setFacing(buttonFacing);
|
||||
button.getBlock().setBlockData(buttonData);
|
||||
portal.setButton(button);
|
||||
portal.getStructure().setButton(button);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -587,16 +592,16 @@ public class PortalHandler {
|
||||
portal.drawSign();
|
||||
//Open an always on portal
|
||||
if (portal.getOptions().isRandom() || portal.getOptions().isBungee()) {
|
||||
portal.open(true);
|
||||
portal.getPortalOpener().openPortal(true);
|
||||
} else if (portal.getOptions().isAlwaysOn()) {
|
||||
Portal destinationPortal = getByName(destinationName, portal.getNetwork());
|
||||
if (destinationPortal != null) {
|
||||
portal.open(true);
|
||||
portal.getPortalOpener().openPortal(true);
|
||||
destinationPortal.drawSign();
|
||||
}
|
||||
} else {
|
||||
//Update the block type for the portal's opening to the closed block
|
||||
for (BlockLocation entrance : portal.getEntrances()) {
|
||||
for (BlockLocation entrance : portal.getStructure().getEntrances()) {
|
||||
entrance.setType(portal.getGate().getPortalClosedBlock());
|
||||
}
|
||||
}
|
||||
@ -612,7 +617,7 @@ public class PortalHandler {
|
||||
Portal origin = getByName(originName, portal.getNetwork());
|
||||
if (origin == null ||
|
||||
!origin.getDestinationName().equalsIgnoreCase(portal.getName()) ||
|
||||
!origin.isVerified()) {
|
||||
!origin.getStructure().isVerified()) {
|
||||
continue;
|
||||
}
|
||||
//Update sign of fixed gates pointing at this gate
|
||||
@ -621,7 +626,7 @@ public class PortalHandler {
|
||||
}
|
||||
//Open any always on portal pointing at this portal
|
||||
if (origin.getOptions().isAlwaysOn()) {
|
||||
origin.open(true);
|
||||
origin.getPortalOpener().openPortal(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -791,7 +796,7 @@ public class PortalHandler {
|
||||
String wName = portal.getWorld().getName();
|
||||
if (!wName.equalsIgnoreCase(world.getName())) continue;
|
||||
StringBuilder builder = new StringBuilder();
|
||||
BlockLocation button = portal.getButton();
|
||||
BlockLocation button = portal.getStructure().getButton();
|
||||
|
||||
builder.append(portal.getName()).append(':');
|
||||
builder.append(portal.getSignLocation().toString()).append(':');
|
||||
@ -1007,7 +1012,7 @@ public class PortalHandler {
|
||||
network, gate, ownerUUID, ownerName, getPortalOptions(portalData));
|
||||
|
||||
registerPortal(portal);
|
||||
portal.close(true);
|
||||
portal.getPortalOpener().closePortal(true);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1040,7 +1045,8 @@ public class PortalHandler {
|
||||
}
|
||||
|
||||
// Verify portal integrity/register portal
|
||||
if (!portal.wasVerified() && (!portal.isVerified() || !portal.checkIntegrity())) {
|
||||
PortalStructure structure = portal.getStructure();
|
||||
if (!structure.wasVerified() && (!structure.isVerified() || !structure.checkIntegrity())) {
|
||||
destroyInvalidPortal(portal);
|
||||
iterator.remove();
|
||||
continue;
|
||||
@ -1049,8 +1055,8 @@ public class PortalHandler {
|
||||
|
||||
//Open the gate if it's set as always open or if it's a bungee gate
|
||||
if (portal.getOptions().isFixed() && (Stargate.enableBungee && portal.getOptions().isBungee() ||
|
||||
portal.getDestination() != null && portal.getOptions().isAlwaysOn())) {
|
||||
portal.open(true);
|
||||
portal.getPortalActivator().getDestination() != null && portal.getOptions().isAlwaysOn())) {
|
||||
portal.getPortalOpener().openPortal(true);
|
||||
openCount++;
|
||||
}
|
||||
}
|
||||
@ -1080,7 +1086,7 @@ public class PortalHandler {
|
||||
Stargate.logger.info("Closing all stargates.");
|
||||
for (Portal portal : allPortals) {
|
||||
if (portal != null) {
|
||||
portal.close(true);
|
||||
portal.getPortalOpener().closePortal(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
203
src/main/java/net/knarcraft/stargate/portal/PortalOpener.java
Normal file
203
src/main/java/net/knarcraft/stargate/portal/PortalOpener.java
Normal file
@ -0,0 +1,203 @@
|
||||
package net.knarcraft.stargate.portal;
|
||||
|
||||
import net.knarcraft.stargate.Stargate;
|
||||
import net.knarcraft.stargate.container.BlockChangeRequest;
|
||||
import net.knarcraft.stargate.container.BlockLocation;
|
||||
import net.knarcraft.stargate.event.StargateCloseEvent;
|
||||
import net.knarcraft.stargate.event.StargateOpenEvent;
|
||||
import org.bukkit.Axis;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.data.Orientable;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
/**
|
||||
* The portal opener is responsible for opening and closing a portal
|
||||
*/
|
||||
public class PortalOpener {
|
||||
|
||||
private boolean isOpen = false;
|
||||
private final Portal portal;
|
||||
private long openTime;
|
||||
private Player player;
|
||||
private final PortalActivator portalActivator;
|
||||
|
||||
/**
|
||||
* Instantiates a new portal opener
|
||||
*
|
||||
* @param portal <p>The portal this portal opener should open</p>
|
||||
* @param destination <p>The fixed destination defined on the portal's sign</p>
|
||||
*/
|
||||
public PortalOpener(Portal portal, String destination) {
|
||||
this.portal = portal;
|
||||
this.portalActivator = new PortalActivator(portal, this, destination);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether this portal activator's portal is currently open
|
||||
*
|
||||
* @return <p>Whether this portal activator's portal is open</p>
|
||||
*/
|
||||
public boolean isOpen() {
|
||||
return isOpen || portal.getOptions().isAlwaysOn();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the time when this portal was activated
|
||||
*
|
||||
* @param openTime <p>Unix timestamp when portal was activated</p>
|
||||
*/
|
||||
public void setOpenTime(long openTime) {
|
||||
this.openTime = openTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the destinations this portal activator has available
|
||||
*
|
||||
* @return <p>The available destinations</p>
|
||||
*/
|
||||
public PortalActivator getPortalOpener() {
|
||||
return this.portalActivator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Open this portal
|
||||
*
|
||||
* @param force <p>Whether to force this portal open, even if it's already open for some player</p>
|
||||
*/
|
||||
public void openPortal(boolean force) {
|
||||
openPortal(null, force);
|
||||
}
|
||||
|
||||
/**
|
||||
* Open this portal
|
||||
*
|
||||
* @param force <p>Whether to force this portal open, even if it's already open for some player</p>
|
||||
*/
|
||||
public void openPortal(Player openFor, boolean force) {
|
||||
//Call the StargateOpenEvent
|
||||
StargateOpenEvent event = new StargateOpenEvent(openFor, portal, force);
|
||||
Stargate.server.getPluginManager().callEvent(event);
|
||||
if (event.isCancelled() || (isOpen() && !event.getForce())) {
|
||||
return;
|
||||
}
|
||||
|
||||
//Change the opening blocks to the correct type
|
||||
Material openType = portal.getGate().getPortalOpenBlock();
|
||||
Axis axis = (openType.createBlockData() instanceof Orientable) ? portal.getLocation().getRotationAxis() : null;
|
||||
for (BlockLocation inside : portal.getStructure().getEntrances()) {
|
||||
Stargate.blockChangeRequestQueue.add(new BlockChangeRequest(inside, openType, axis));
|
||||
}
|
||||
|
||||
updatePortalOpenState(openFor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates this portal to be recognized as open and opens its destination portal
|
||||
*
|
||||
* @param openFor <p>The player to open this portal for</p>
|
||||
*/
|
||||
private void updatePortalOpenState(Player openFor) {
|
||||
//Update the open state of this portal
|
||||
isOpen = true;
|
||||
openTime = System.currentTimeMillis() / 1000;
|
||||
Stargate.openPortalsQueue.add(portal);
|
||||
Stargate.activePortalsQueue.remove(portal);
|
||||
PortalOptions options = portal.getOptions();
|
||||
|
||||
//Open remote portal
|
||||
if (!options.isAlwaysOn()) {
|
||||
player = openFor;
|
||||
|
||||
Portal destination = portal.getPortalActivator().getDestination();
|
||||
//Only open destination if it's not-fixed or points at this portal
|
||||
if (!options.isRandom() && destination != null && (!destination.getOptions().isFixed() ||
|
||||
destination.getDestinationName().equalsIgnoreCase(portal.getName())) && !destination.isOpen()) {
|
||||
destination.getPortalOpener().openPortal(openFor, false);
|
||||
destination.getPortalActivator().setDestination(portal);
|
||||
if (destination.getStructure().isVerified()) {
|
||||
destination.drawSign();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes this portal
|
||||
*
|
||||
* @param force <p>Whether to force this portal closed, even if it's set as always on</p>
|
||||
*/
|
||||
public void closePortal(boolean force) {
|
||||
if (!isOpen) {
|
||||
return;
|
||||
}
|
||||
//Call the StargateCloseEvent
|
||||
StargateCloseEvent event = new StargateCloseEvent(portal, force);
|
||||
Stargate.server.getPluginManager().callEvent(event);
|
||||
if (event.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
force = event.getForce();
|
||||
|
||||
//Only close always-open if forced to
|
||||
if (portal.getOptions().isAlwaysOn() && !force) {
|
||||
return;
|
||||
}
|
||||
|
||||
//Close this gate, then the dest gate.
|
||||
Material closedType = portal.getGate().getPortalClosedBlock();
|
||||
for (BlockLocation inside : portal.getStructure().getEntrances()) {
|
||||
Stargate.blockChangeRequestQueue.add(new BlockChangeRequest(inside, closedType, null));
|
||||
}
|
||||
|
||||
updatePortalClosedState();
|
||||
portalActivator.deactivate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates this portal to be recognized as closed and closes its destination portal
|
||||
*/
|
||||
private void updatePortalClosedState() {
|
||||
//Update the closed state of this portal
|
||||
player = null;
|
||||
isOpen = false;
|
||||
Stargate.openPortalsQueue.remove(portal);
|
||||
Stargate.activePortalsQueue.remove(portal);
|
||||
|
||||
//Close remote portal
|
||||
if (!portal.getOptions().isAlwaysOn()) {
|
||||
Portal end = portal.getPortalActivator().getDestination();
|
||||
|
||||
if (end != null && end.isOpen()) {
|
||||
//Clear its destination first
|
||||
end.getPortalActivator().deactivate();
|
||||
end.getPortalOpener().closePortal(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether this portal is open for the given player
|
||||
*
|
||||
* @param player <p>The player to check portal state for</p>
|
||||
* @return <p>True if this portal is open to the given player</p>
|
||||
*/
|
||||
public boolean isOpenFor(Player player) {
|
||||
if (!isOpen) {
|
||||
return false;
|
||||
}
|
||||
if (portal.getOptions().isAlwaysOn() || this.player == null) {
|
||||
return true;
|
||||
}
|
||||
return player != null && player.getName().equalsIgnoreCase(this.player.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the time this portal activator's portal opened
|
||||
*
|
||||
* @return <p>The time this portal activator's portal opened</p>
|
||||
*/
|
||||
public long getOpenTime() {
|
||||
return openTime;
|
||||
}
|
||||
|
||||
}
|
@ -53,7 +53,7 @@ public class PortalSignDrawer {
|
||||
Stargate.setLine(sign, 0, ChatColor.WHITE + "-" + Stargate.signColor + portal.getName() +
|
||||
ChatColor.WHITE + "-");
|
||||
|
||||
if (!portal.isActive()) {
|
||||
if (!portal.getPortalActivator().isActive()) {
|
||||
//Default sign text
|
||||
drawInactiveSign(sign);
|
||||
} else {
|
||||
@ -78,9 +78,10 @@ public class PortalSignDrawer {
|
||||
* @param sign <p>The sign to re-draw</p>
|
||||
*/
|
||||
private void drawNetworkSign(Sign sign) {
|
||||
int maxIndex = portal.getDestinations().size() - 1;
|
||||
PortalActivator destinations = portal.getPortalActivator();
|
||||
int maxIndex = destinations.getDestinations().size() - 1;
|
||||
int signLineIndex = 0;
|
||||
int destinationIndex = portal.getDestinations().indexOf(portal.getDestinationName());
|
||||
int destinationIndex = destinations.getDestinations().indexOf(portal.getDestinationName());
|
||||
boolean freeGatesGreen = EconomyHandler.useEconomy() && EconomyHandler.freeGatesGreen;
|
||||
|
||||
//Last, and not only entry. Draw the entry two back
|
||||
@ -131,12 +132,15 @@ public class PortalSignDrawer {
|
||||
* @param destinationIndex <p>The index of the destination to draw</p>
|
||||
*/
|
||||
private void drawNetworkSignLine(boolean freeGatesGreen, Sign sign, int signLineIndex, int destinationIndex) {
|
||||
PortalActivator destinations = portal.getPortalActivator();
|
||||
if (freeGatesGreen) {
|
||||
Portal destination = PortalHandler.getByName(portal.getDestinations().get(destinationIndex), portal.getNetwork());
|
||||
Portal destination = PortalHandler.getByName(destinations.getDestinations().get(destinationIndex),
|
||||
portal.getNetwork());
|
||||
boolean green = PermissionHelper.isFree(portal.getActivePlayer(), portal, destination);
|
||||
Stargate.setLine(sign, signLineIndex, (green ? ChatColor.DARK_GREEN : "") + portal.getDestinations().get(destinationIndex));
|
||||
Stargate.setLine(sign, signLineIndex, (green ? ChatColor.DARK_GREEN : "") +
|
||||
destinations.getDestinations().get(destinationIndex));
|
||||
} else {
|
||||
Stargate.setLine(sign, signLineIndex, portal.getDestinations().get(destinationIndex));
|
||||
Stargate.setLine(sign, signLineIndex, destinations.getDestinations().get(destinationIndex));
|
||||
}
|
||||
}
|
||||
|
||||
|
147
src/main/java/net/knarcraft/stargate/portal/PortalStructure.java
Normal file
147
src/main/java/net/knarcraft/stargate/portal/PortalStructure.java
Normal file
@ -0,0 +1,147 @@
|
||||
package net.knarcraft.stargate.portal;
|
||||
|
||||
import net.knarcraft.stargate.Stargate;
|
||||
import net.knarcraft.stargate.container.BlockLocation;
|
||||
import net.knarcraft.stargate.container.RelativeBlockVector;
|
||||
|
||||
/**
|
||||
* The portal structure is responsible for the physical properties of a portal
|
||||
*
|
||||
* <p>The portal structure knows which gate type is used, where the real locations of buttons, frames and entrances are
|
||||
* and whether the portal is verified.</p>
|
||||
*/
|
||||
public class PortalStructure {
|
||||
|
||||
private final Portal portal;
|
||||
private final Gate gate;
|
||||
private BlockLocation button;
|
||||
private BlockLocation[] frame;
|
||||
private BlockLocation[] entrances;
|
||||
private boolean verified;
|
||||
|
||||
/**
|
||||
* Instantiates a new portal structure
|
||||
*
|
||||
* @param portal <p>The portal whose structure to store</p>
|
||||
* @param gate <p>The gate type used by this portal structure</p>
|
||||
* @param button <p>The real location of the portal's button</p>
|
||||
*/
|
||||
public PortalStructure(Portal portal, Gate gate, BlockLocation button) {
|
||||
this.portal = portal;
|
||||
this.gate = gate;
|
||||
this.verified = false;
|
||||
this.button = button;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the gate used by this portal structure
|
||||
*
|
||||
* @return <p>The gate used by this portal structure</p>
|
||||
*/
|
||||
public Gate getGate() {
|
||||
return gate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the location of this portal's button
|
||||
*
|
||||
* @return <p>The location of this portal's button</p>
|
||||
*/
|
||||
public BlockLocation getButton() {
|
||||
return button;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the location of this portal's button
|
||||
*
|
||||
* @param button <p>The location of this portal's button</p>
|
||||
*/
|
||||
public void setButton(BlockLocation button) {
|
||||
this.button = button;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that all control blocks in this portal follows its gate template
|
||||
*
|
||||
* @return <p>True if all control blocks were verified</p>
|
||||
*/
|
||||
public boolean isVerified() {
|
||||
boolean verified = true;
|
||||
if (!Stargate.verifyPortals) {
|
||||
return true;
|
||||
}
|
||||
for (RelativeBlockVector control : gate.getLayout().getControls()) {
|
||||
verified = verified && portal.getBlockAt(control).getBlock().getType().equals(gate.getControlBlock());
|
||||
}
|
||||
this.verified = verified;
|
||||
return verified;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the result of the last portal verification
|
||||
*
|
||||
* @return <p>True if this portal was verified</p>
|
||||
*/
|
||||
public boolean wasVerified() {
|
||||
if (!Stargate.verifyPortals) {
|
||||
return true;
|
||||
}
|
||||
return verified;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if all blocks in a gate matches the gate template
|
||||
*
|
||||
* @return <p>True if all blocks match the gate template</p>
|
||||
*/
|
||||
public boolean checkIntegrity() {
|
||||
if (!Stargate.verifyPortals) {
|
||||
return true;
|
||||
}
|
||||
return gate.matches(portal.getTopLeft(), portal.getYaw());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of block locations from a list of relative block vectors
|
||||
*
|
||||
* <p>The block locations will be calculated by using this portal's top-left block as the origin for the relative
|
||||
* vectors..</p>
|
||||
*
|
||||
* @param vectors <p>The relative block vectors to convert</p>
|
||||
* @return <p>A list of block locations</p>
|
||||
*/
|
||||
private BlockLocation[] relativeBlockVectorsToBlockLocations(RelativeBlockVector[] vectors) {
|
||||
BlockLocation[] locations = new BlockLocation[vectors.length];
|
||||
for (int i = 0; i < vectors.length; i++) {
|
||||
locations[i] = portal.getBlockAt(vectors[i]);
|
||||
}
|
||||
return locations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the locations of this portal's entrances
|
||||
*
|
||||
* @return <p>The locations of this portal's entrances</p>
|
||||
*/
|
||||
public BlockLocation[] getEntrances() {
|
||||
if (entrances == null) {
|
||||
//Get the locations of the entrances once, and only if necessary as it's an expensive operation
|
||||
entrances = relativeBlockVectorsToBlockLocations(gate.getLayout().getEntrances());
|
||||
}
|
||||
return entrances;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the locations of this portal's frame
|
||||
*
|
||||
* @return <p>The locations of this portal's frame</p>
|
||||
*/
|
||||
public BlockLocation[] getFrame() {
|
||||
if (frame == null) {
|
||||
//Get the locations of the frame blocks once, and only if necessary as it's an expensive operation
|
||||
frame = relativeBlockVectorsToBlockLocations(gate.getLayout().getBorder());
|
||||
}
|
||||
return frame;
|
||||
}
|
||||
|
||||
}
|
@ -21,18 +21,18 @@ public class StarGateThread implements Runnable {
|
||||
continue;
|
||||
}
|
||||
if (time > portal.getOpenTime() + Stargate.getOpenTime()) {
|
||||
portal.close(false);
|
||||
portal.getPortalOpener().closePortal(false);
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
//Deactivate active portals
|
||||
for (Iterator<Portal> iterator = Stargate.activePortalsQueue.iterator(); iterator.hasNext(); ) {
|
||||
Portal portal = iterator.next();
|
||||
if (!portal.isActive()) {
|
||||
if (!portal.getPortalActivator().isActive()) {
|
||||
continue;
|
||||
}
|
||||
if (time > portal.getOpenTime() + Stargate.getActiveTime()) {
|
||||
portal.deactivate();
|
||||
portal.getPortalActivator().deactivate();
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ public final class EconomyHelper {
|
||||
// Insufficient Funds
|
||||
if (!success) {
|
||||
sendInsufficientFundsMessage(entrancePortal.getName(), player, cost);
|
||||
entrancePortal.close(false);
|
||||
entrancePortal.getPortalOpener().closePortal(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,7 @@ public final class PermissionHelper {
|
||||
* @param portal <p>The portal to open</p>
|
||||
*/
|
||||
public static void openPortal(Player player, Portal portal) {
|
||||
Portal destination = portal.getDestination();
|
||||
Portal destination = portal.getPortalActivator().getDestination();
|
||||
|
||||
//Always-open gate -- Do nothing
|
||||
if (portal.getOptions().isAlwaysOn()) {
|
||||
@ -46,13 +46,14 @@ public final class PermissionHelper {
|
||||
if (portal.isOpen()) {
|
||||
// Close if this player opened the gate
|
||||
if (portal.getActivePlayer() == player) {
|
||||
portal.close(false);
|
||||
portal.getPortalOpener().closePortal(false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
//Gate that someone else is using -- Deny access
|
||||
if ((!portal.getOptions().isFixed()) && portal.isActive() && (portal.getActivePlayer() != player)) {
|
||||
if ((!portal.getOptions().isFixed()) && portal.getPortalActivator().isActive() &&
|
||||
(portal.getActivePlayer() != player)) {
|
||||
Stargate.sendErrorMessage(player, Stargate.getString("denyMsg"));
|
||||
return;
|
||||
}
|
||||
@ -70,7 +71,7 @@ public final class PermissionHelper {
|
||||
}
|
||||
|
||||
//Open gate
|
||||
portal.open(player, false);
|
||||
portal.getPortalOpener().openPortal(player, false);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -388,7 +389,7 @@ public final class PermissionHelper {
|
||||
}
|
||||
|
||||
// Not open for this player
|
||||
if (!entrancePortal.isOpenFor(player)) {
|
||||
if (!entrancePortal.getPortalOpener().isOpenFor(player)) {
|
||||
Stargate.sendErrorMessage(player, Stargate.getString("denyMsg"));
|
||||
new PlayerTeleporter(entrancePortal, player).teleport(entrancePortal, event);
|
||||
return true;
|
||||
@ -403,7 +404,7 @@ public final class PermissionHelper {
|
||||
if (PermissionHelper.cannotAccessPortal(player, entrancePortal, destination)) {
|
||||
Stargate.sendErrorMessage(player, Stargate.getString("denyMsg"));
|
||||
new PlayerTeleporter(entrancePortal, player).teleport(entrancePortal, event);
|
||||
entrancePortal.close(false);
|
||||
entrancePortal.getPortalOpener().closePortal(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user