Package com.bergerkiller.bukkit.mw

Source Code of com.bergerkiller.bukkit.mw.Portal

package com.bergerkiller.bukkit.mw;

import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;

import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.World.Environment;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.Sign;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.event.entity.EntityPortalEvent;
import org.bukkit.material.Directional;
import org.bukkit.material.MaterialData;

import com.bergerkiller.bukkit.common.utils.EntityUtil;
import com.bergerkiller.bukkit.common.utils.FaceUtil;
import com.bergerkiller.bukkit.common.utils.LogicUtil;
import com.bergerkiller.bukkit.common.utils.MaterialUtil;
import com.bergerkiller.bukkit.common.utils.StringUtil;
import com.bergerkiller.bukkit.common.utils.WorldUtil;

public class Portal extends PortalStore {
  private String name;
  private String destination;
  private String destdisplayname;
  private Location location;

  /**
   * Gets the identifier name of this Portal
   *
   * @return Portal identifier name
   */
  public String getName() {
    return this.name;
  }

  /**
   * Gets the Location of this Portal
   *
   * @return Portal location
   */
  public Location getLocation() {
    return this.location;
  }

  /**
   * Gets the destination name of this Portal
   *
   * @return Portal destination name
   */
  public String getDestinationName() {
    if (this.destination == null) {
      return null;
    } else {
      return this.destination.substring(this.destination.indexOf('.') + 1);
    }
  }

  /**
   * Gets the destination display name of this Portal
   *
   * @return Portal destination display name
   */
  public String getDestinationDisplayName() {
    return this.destdisplayname;
  }

  /**
   * Gets the destination location of this Portal
   *
   * @return Portal destination
   */
  public Location getDestination() {
    final String worldName = this.location == null ? null : this.location.getWorld().getName();
    Location loc = getPortalLocation(this.destination, worldName, true);
    if (loc == null) {
      String portalname = WorldManager.matchWorld(this.destination);
      World w = WorldManager.getWorld(portalname);
      if (w != null) {
        loc = WorldManager.getSpawnLocation(w);
      }
    }
    return loc;
  }

  /**
   * Checks if this Portal has an available destination
   *
   * @return True if it has a destination, False if not
   */
  public boolean hasDestination() {
    if (this.destination == null || this.destination.trim().isEmpty()) {
      return false;
    }
    return getDestination() != null;
  }

  /**
   * Gets a new non-existing Portal object that teleports to this Portal
   *
   * @return new Portal with this Portal as destination
   */
  public Portal getOtherEnd() {
    Portal p = new Portal();
    p.name = "Unknown";
    p.destdisplayname = p.destination = this.name;
    p.location = null;
    return p;
  }

  /**
   * Teleports an Entity to the location of this Portal
   *
   * @param entity to teleport
   * @return True if successful, False if not
   */
  public boolean teleportSelf(Entity entity) {
    if (entity instanceof Player) {
      MWListenerPost.setLastEntered((Player) entity, this.getOtherEnd());
    }
    boolean rval = EntityUtil.teleport(entity, Util.spawnOffset(this.getLocation()));
    return rval;
  }

  /**
   * Adds this Portal to the internal mapping
   */
  public void add() {
    getPortalLocations(location.getWorld().getName()).put(name, new Position(location));
  }

  /**
   * Removes this Portal from the internal mapping
   *
   * @return True if successful, False if not
   */
  public boolean remove() {
    return remove(this.name, this.location.getWorld().getName());
  }

  /**
   * Checks if this Portal is added to the internal mapping
   *
   * @return True if it is added, False if not
   */
  public boolean isAdded() {
    return getPortalLocations(this.location.getWorld().getName()).containsKey(this.getName());
  }

  @Override
  public String toString() {
    return "Portal {name=" + getName() + ", loc=" + getLocation() + ", dest=" + (hasDestination() ? getDestinationName() : "None") + "}";
  }

  public static boolean exists(String world, String portalname) {
    return getPortalLocations(world).containsKey(portalname);
  }

  public static boolean remove(String name, String world) {
    return getPortalLocations(world).remove(name) != null;
  }

  /**
   * Gets the nearest portal (sign) near a given point using the SEARCH_RADIUS as radius
   *
   * @param middle point of the sphere to look in
   * @return Nearest portal, or null if none are found
   */
  public static Portal getNear(Location middle) {
    return getNear(middle, MyWorlds.maxPortalSignDistance);
  }

  /**
   * Gets the nearest portal (sign) in a given spherical area
   *
   * @param middle point of the sphere to look in
   * @param radius of the sphere to look in
   * @return Nearest portal, or null if none are found
   */
  public static Portal getNear(Location middle, double radius) {
    Portal p = null;
    HashMap<String, Position> positions = getPortalLocations(middle.getWorld().getName());
    for (Map.Entry<String, Position> pos : positions.entrySet()) {
      Location ploc = Util.getLocation(pos.getValue());
      String portalname = pos.getKey();
      if (ploc != null && ploc.getWorld() == middle.getWorld()) {
        double distance = ploc.distance(middle);
        if (distance <= radius) {
          Portal newp = Portal.get(ploc);
          if (newp != null) {
            p = newp;
            radius = distance;
          } else if (ploc.getWorld().isChunkLoaded(ploc.getBlockX() >> 4, ploc.getBlockZ() >> 4)) {
            //In loaded chunk and NOT found!
            //Remove it
            positions.remove(portalname);
            MyWorlds.plugin.log(Level.WARNING, "Removed portal '" + portalname + "' because it is no longer there!");
            //End the loop and call the function again
            return getNear(middle, radius);
          }
        }
      }
    }
    return p;
  }

  public static Portal get(String name) {
    return get(getPortalLocation(name, null));
  }

  public static Portal get(Location signloc) {
    if (signloc == null) return null;
    return get(signloc.getBlock(), false);
  }

  public static Portal get(Block signblock, boolean loadchunk) {
    if (loadchunk) {
      signblock.getChunk();
    } else if (!WorldUtil.isLoaded(signblock)) {
      return null;
    }
    if (signblock.getState() instanceof Sign) {
      return get(signblock, ((Sign) signblock.getState()).getLines());
    }
    return null;
  }

  public static Portal get(Block signblock, String[] lines) {
    if (signblock.getState() instanceof Sign && lines[0].equalsIgnoreCase("[portal]")) {
      Portal p = new Portal();
      // Read name, if none set, use portal location as name
      p.name = Util.filterPortalName(lines[1]);
      if (LogicUtil.nullOrEmpty(p.name)) {
        p.name = StringUtil.blockToString(signblock);
      }
      // Read destination, if none set, set to null so it's clear there is no destination set
      p.destination = Util.filterPortalName(lines[2]);
      if (p.destination.isEmpty()) {
        p.destination = null;
      }
      // Read destination name, if none set, use destination instead
      if (lines[3].isEmpty()) {
        p.destdisplayname = p.getDestinationName();
      } else {
        p.destdisplayname = lines[3];
      }
      // Set portal locatiol using sign location and orientation
      p.location = signblock.getLocation();
      MaterialData data = signblock.getState().getData();
      float yaw = 0;
      if (data instanceof Directional) {
        yaw = FaceUtil.faceToYaw(((Directional) data).getFacing()) + 90;
      }
      p.location.setYaw(yaw);
      return p;
    }
    return null;
  }

  /**
   * Handles an entity entering a certain portal block.
   * If this method returns False, the caller should set the event to cancelled.
   * The destination Location and travel agent are updated by this method if True
   * is returned. If the Entity is a Player, messages are sent when teleportation
   * failed.
   *
   * @param event of the entering
   * @param portalMaterial of the block that was used as portal
   * @return True if a new destination was set, False if not
   */
  public static boolean handlePortalEnter(EntityPortalEvent event, Material portalMaterial) {
    // First, see whether a portal or default world will be used
    Entity entity = event.getEntity();
    Portal enteredPortal = getNear(entity.getLocation());
    World enteredWorld = null;
    if (enteredPortal == null) {
      // Default portals
      String def = null;
      if (portalMaterial == Material.PORTAL) {
        def = WorldConfig.get(entity).getNetherPortal();
      } else if (portalMaterial == Material.ENDER_PORTAL) {
        def = WorldConfig.get(entity).getEnderPortal();
      }
      if (def != null) {
        enteredPortal = get(getPortalLocation(def, entity.getWorld().getName()));
        if (enteredPortal != null) {
          // Teleport to a specific portal - change perspective
          enteredPortal = enteredPortal.getOtherEnd();
        } else {
          // Resort back to a potential default world
          enteredWorld = WorldManager.getWorld(def);
        }
      }
    }
    // Proceed to further handle this request
    Location destinationLoc = null;
    boolean useTravelAgent = false;

    // Further handle portal entering
    if (enteredPortal != null) {
      destinationLoc = enteredPortal.getDestination();
      if (destinationLoc == null) {
        String name = enteredPortal.getDestinationName();
        if (name != null && entity instanceof Player) {
          // Show message indicating the destination is unavailable
          Localization.PORTAL_NOTFOUND.message((Player) entity, name);
          // Return here to avoid an additional 'no destination' message later on
          return false;
        }
      } else if (entity instanceof Player) {
        // For later on: set up the right portal for permissions and messages
        MWListenerPost.setLastEntered((Player) entity, enteredPortal);
      }
    }

    // Further handle teleportation to worlds
    if (enteredWorld != null) {
      if (MyWorlds.allowPersonalPortals) {
        // Personal portals - which means a portal may have to be created on the other end
        // To find out where to place this portal, compare the from and to environments
        Environment oldEnvironment = entity.getWorld().getEnvironment();
        Environment newEnvironment = enteredWorld.getEnvironment();
        if (newEnvironment == Environment.THE_END) {
          // Always use this location of the world as destination
          // Anything else will cause internal logic to break
          destinationLoc = new Location(enteredWorld, 100, 50, 0);
          useTravelAgent = true;
        } else if (oldEnvironment == Environment.THE_END) {
          // No special portal type or anything is used
          // Instead, teleport to a personal bed or otherwise world spawn
          if (entity instanceof Player) {
            destinationLoc = ((Player) entity).getBedSpawnLocation();
          }
        } else {
          // Find out what location to teleport to
          // Use source block as the location to search from
          double blockRatio = 1.0;
          if (oldEnvironment != newEnvironment) {
            if (newEnvironment == Environment.NETHER) {
              blockRatio = 0.125;
            } else if (oldEnvironment == Environment.NETHER) {
              blockRatio = 8.0;
            }
          }
          Location start = entity.getLocation();
          Location end = new Location(enteredWorld, blockRatio * start.getX(), start.getY(), blockRatio * start.getZ());
          Block destB = end.getBlock();
          // Figure out the best yaw to use here by checking for air blocks
          float yaw = 0.0f;
          for (BlockFace face : FaceUtil.AXIS) {
            if (MaterialUtil.isType(destB.getRelative(face), Material.AIR)) {
              yaw = FaceUtil.faceToYaw(face) + 90f;
              break;
            }
          }
          destinationLoc = new Location(destB.getWorld(), destB.getX() + 0.5, destB.getY(), destB.getZ() + 0.5, yaw, 0.0f);
          useTravelAgent = true;
        }
      }
      // No destination found or set, resort back to using world spawn
      if (destinationLoc == null) {
        if (entity instanceof Player) {
          destinationLoc = WorldManager.getPlayerWorldSpawn((Player) entity, enteredWorld);
        } else {
          destinationLoc = WorldManager.getSpawnLocation(enteredWorld);
        }
      }
    }

    if (destinationLoc == null) {
      // No destination available
      // Send a missing destination message for non-water portals
      if (entity instanceof Player && portalMaterial != Material.STATIONARY_WATER) {
        Localization.PORTAL_NODESTINATION.message((Player) entity);
      }
    } else if (canTeleportTo(entity, destinationLoc)) {
      // Successful teleport
      event.useTravelAgent(useTravelAgent);
      event.setTo(destinationLoc);
      return true;
    }
    return false;
  }

  private static boolean canTeleportTo(Entity e, Location dest) {
    // Check permissions for players
    if (e instanceof Player) {
      return MWListenerPost.handleTeleportPermission((Player) e, dest);
    }
    // Non-player entity was denied from teleporting there because of spawn control
    return !WorldConfig.get(dest).spawnControl.isDenied(e);
  }
}
TOP

Related Classes of com.bergerkiller.bukkit.mw.Portal

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.