Merge branch 'region_manager_thread_safety' into 'master'
Add thread safety to the region manager as well as a kotlin conversion. See merge request 2009scape/2009scape!72
This commit is contained in:
@@ -29,7 +29,7 @@ public final class SilverSicklePlugin extends OptionHandler {
|
||||
|
||||
@Override
|
||||
public boolean handle(Player player, Node node, String option) {
|
||||
Region region = RegionManager.getRegionCache().get(player.getLocation().getRegionId());
|
||||
Region region = RegionManager.forId(player.getLocation().getRegionId());
|
||||
switch (option) {
|
||||
case "operate":
|
||||
case "cast bloom":
|
||||
@@ -48,6 +48,7 @@ public final class SilverSicklePlugin extends OptionHandler {
|
||||
}
|
||||
}
|
||||
}
|
||||
RegionManager.getLock().unlock();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -761,7 +761,7 @@ public class Player extends Entity {
|
||||
*/
|
||||
public void updateSceneGraph(boolean login) {
|
||||
Region region = getViewport().getRegion();
|
||||
if (region instanceof DynamicRegion || (region == null && (region = RegionManager.getRegionCache().get(location.getRegionId())) instanceof DynamicRegion || region == null)) {
|
||||
if (region instanceof DynamicRegion || region == null && (region = RegionManager.forId(location.getRegionId())) instanceof DynamicRegion) {
|
||||
PacketRepository.send(BuildDynamicScene.class, new DynamicSceneContext(this, login));
|
||||
} else {
|
||||
PacketRepository.send(UpdateSceneGraph.class, new SceneGraphContext(this, login));
|
||||
|
||||
@@ -381,7 +381,7 @@ public final class HouseManager {
|
||||
region = new DynamicRegion(-1, borders.getSouthWestX() >> 6, borders.getSouthWestY() >> 6);
|
||||
region.setBorders(borders);
|
||||
region.setUpdateAllPlanes(true);
|
||||
RegionManager.getRegionCache().put(region.getId(), region);
|
||||
RegionManager.addRegion(region.getId(), region);
|
||||
configureRoofs();
|
||||
for (int z = 0; z < 3; z++) {
|
||||
for (int x = 0; x < 8; x++) {
|
||||
@@ -406,7 +406,7 @@ public final class HouseManager {
|
||||
dungeon = new DynamicRegion(-1, borders.getSouthWestX() >> 6, borders.getSouthWestY() >> 6);
|
||||
dungeon.setBorders(borders);
|
||||
dungeon.setUpdateAllPlanes(true);
|
||||
RegionManager.getRegionCache().put(dungeon.getId(), dungeon);
|
||||
RegionManager.addRegion(dungeon.getId(), dungeon);
|
||||
for (int x = 0; x < 8; x++) {
|
||||
for (int y = 0; y < 8; y++) {
|
||||
Room room = rooms[3][x][y];
|
||||
|
||||
@@ -1,737 +0,0 @@
|
||||
package core.game.world.map;
|
||||
|
||||
import core.game.node.Node;
|
||||
import core.game.node.entity.Entity;
|
||||
import core.game.node.entity.npc.NPC;
|
||||
import core.game.node.entity.player.Player;
|
||||
import core.game.node.object.Scenery;
|
||||
import rs09.game.system.SystemLogger;
|
||||
import core.game.world.map.zone.ZoneBorders;
|
||||
import core.tools.RandomFunction;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Manages the regions.
|
||||
* @author Emperor
|
||||
*
|
||||
*/
|
||||
public final class RegionManager {
|
||||
|
||||
/**
|
||||
* The region cache mapping.
|
||||
*/
|
||||
private static final Map<Integer, Region> REGION_CACHE = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Gets the region for the given region id.
|
||||
* @param regionId The region id.
|
||||
* @return The region.
|
||||
*/
|
||||
public static Region forId(int regionId) {
|
||||
Region region = REGION_CACHE.get(regionId);
|
||||
if (region == null) {
|
||||
region = new Region(regionId >> 8 & 0xFF, regionId & 0xFF);
|
||||
REGION_CACHE.put(regionId, region);
|
||||
}
|
||||
return region;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pulses the active regions.
|
||||
*/
|
||||
public static void pulse() {
|
||||
Object[] rCacheArray = new Object[0];
|
||||
try {
|
||||
rCacheArray = REGION_CACHE.values().toArray();
|
||||
} catch (ConcurrentModificationException e){
|
||||
SystemLogger.logErr("Region Cache tried to process too early -- restarting...");
|
||||
System.exit(0);
|
||||
}
|
||||
int rCacheLength = rCacheArray.length;
|
||||
for (int i = 0; i < rCacheLength; i++) {
|
||||
Region r = (Region) rCacheArray[i];
|
||||
if (r != null && r.isActive()) {
|
||||
RegionPlane[] planes = r.getPlanes();
|
||||
int size = planes.length;
|
||||
for (int j = 0; j < size; j++) {
|
||||
planes[j].pulse();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the clipping flag on the given location.
|
||||
* @param l The location.
|
||||
* @return The clipping flag.
|
||||
*/
|
||||
public static int getClippingFlag(Location l) {
|
||||
return getClippingFlag(l.getZ(), l.getX(), l.getY());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the clipping flag.
|
||||
* @param z The plane.
|
||||
* @param x The absolute x-coordinate.
|
||||
* @param y The absolute y-coordinate.
|
||||
* @return The clipping flags.
|
||||
*/
|
||||
public static int getClippingFlag(int z, int x, int y) {
|
||||
Region region = forId((x >> 6) << 8 | y >> 6);
|
||||
Region.load(region);
|
||||
if (!region.isHasFlags()) {
|
||||
return -1;
|
||||
}
|
||||
x -= (x >> 6) << 6;
|
||||
y -= (y >> 6) << 6;
|
||||
return region.getPlanes()[z].getFlags().getClippingFlags()[x][y];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the water variant of a tile's clipping flag
|
||||
* Essentially strips the landscape flag off a tile and keeps other flags, and makes normally walkable tiles unwalkable.
|
||||
* @author Ceikry
|
||||
*/
|
||||
public static int getWaterClipFlag(int z, int x, int y){
|
||||
int flag = getClippingFlag(z,x,y);
|
||||
if(!isClipped(z,x,y)){
|
||||
return flag | 0x100;
|
||||
}
|
||||
return flag & (~0x200000);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the tile is part of the landscape.
|
||||
* @param l The location.
|
||||
* @return {@code True} if so.
|
||||
*/
|
||||
public static boolean isLandscape(Location l) {
|
||||
return isLandscape(l.getZ(), l.getX(), l.getY());
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the tile is part of the landscape.
|
||||
* @param z The plane.
|
||||
* @param x The absolute x-coordinate.
|
||||
* @param y The absolute y-coordinate.
|
||||
* @return {@code True} if so.
|
||||
*/
|
||||
public static boolean isLandscape(int z, int x, int y) {
|
||||
Region region = forId((x >> 6) << 8 | y >> 6);
|
||||
Region.load(region);
|
||||
if (!region.isHasFlags() || region.getPlanes()[z].getFlags().getLandscape() == null) {
|
||||
return false;
|
||||
}
|
||||
x -= (x >> 6) << 6;
|
||||
y -= (y >> 6) << 6;
|
||||
return region.getPlanes()[z].getFlags().getLandscape()[x][y];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the clipping flag on the given location.
|
||||
* @param l The location.
|
||||
* @param flag The flag to set.
|
||||
*/
|
||||
public static void setClippingFlag(Location l, int flag) {
|
||||
int x = l.getX();
|
||||
int y = l.getY();
|
||||
int z = l.getZ();
|
||||
Region region = forId((x >> 6) << 8 | y >> 6);
|
||||
Region.load(region);
|
||||
if (!region.isHasFlags()) {
|
||||
return;
|
||||
}
|
||||
x -= (x >> 6) << 6;
|
||||
y -= (y >> 6) << 6;
|
||||
region.getPlanes()[z].getFlags().getClippingFlags()[x][y] = flag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a clipping flag.
|
||||
* @param z The plane.
|
||||
* @param x The absolute x-coordinate.
|
||||
* @param y The absolute y-coordinate.
|
||||
* @param projectile If the flag is being set for projectile pathfinding.
|
||||
* @param flag The clipping flag.
|
||||
*/
|
||||
public static void addClippingFlag(int z, int x, int y, boolean projectile, int flag) {
|
||||
Region region = forId((x >> 6) << 8 | y >> 6);
|
||||
Region.load(region);
|
||||
if (!region.isHasFlags()) {
|
||||
return;
|
||||
}
|
||||
x -= (x >> 6) << 6;
|
||||
y -= (y >> 6) << 6;
|
||||
if (projectile) {
|
||||
region.getPlanes()[z].getProjectileFlags().flag(x, y, flag);
|
||||
} else {
|
||||
region.getPlanes()[z].getFlags().flag(x, y, flag);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a clipping flag.
|
||||
* @param z The plane.
|
||||
* @param x The absolute x-coordinate.
|
||||
* @param y The absolute y-coordinate.
|
||||
* @param projectile If the flag is being set for projectile pathfinding.
|
||||
* @param flag The clipping flag.
|
||||
*/
|
||||
public static void removeClippingFlag(int z, int x, int y, boolean projectile, int flag) {
|
||||
Region region = forId((x >> 6) << 8 | y >> 6);
|
||||
Region.load(region);
|
||||
if (!region.isHasFlags()) {
|
||||
return;
|
||||
}
|
||||
x -= (x >> 6) << 6;
|
||||
y -= (y >> 6) << 6;
|
||||
if (projectile) {
|
||||
region.getPlanes()[z].getProjectileFlags().unflag(x, y, flag);
|
||||
} else {
|
||||
region.getPlanes()[z].getFlags().unflag(x, y, flag);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the clipping flag.
|
||||
* @param z The plane.
|
||||
* @param x The absolute x-coordinate.
|
||||
* @param y The absolute y-coordinate.
|
||||
* @return The clipping flags.
|
||||
*/
|
||||
public static int getProjectileFlag(int z, int x, int y) {
|
||||
Region region = forId((x >> 6) << 8 | y >> 6);
|
||||
Region.load(region);
|
||||
if (!region.isHasFlags()) {
|
||||
return -1;
|
||||
}
|
||||
x -= (x >> 6) << 6;
|
||||
y -= (y >> 6) << 6;
|
||||
return region.getPlanes()[z].getProjectileFlags().getClippingFlags()[x][y];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the clipping flag
|
||||
* @param location the Location
|
||||
* @return the clipping flag
|
||||
*/
|
||||
public static boolean isTeleportPermitted(Location location) {
|
||||
return isTeleportPermitted(location.getZ(), location.getX(), location.getY());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the clipping flag.
|
||||
* @param z The plane.
|
||||
* @param x The absolute x-coordinate.
|
||||
* @param y The absolute y-coordinate.
|
||||
* @return The clipping flags.
|
||||
*/
|
||||
public static boolean isTeleportPermitted(int z, int x, int y) {
|
||||
if (!isLandscape(z, x, y)) {
|
||||
return false;
|
||||
}
|
||||
int flag = getClippingFlag(z, x, y);
|
||||
return (flag & 0x12c0102) == 0 || (flag & 0x12c0108) == 0 || (flag & 0x12c0120) == 0 || (flag & 0x12c0180) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the location has any clipping flags.
|
||||
* @param location The location.
|
||||
* @return {@code True} if a clipping flag disables access for this location.
|
||||
*/
|
||||
public static boolean isClipped(Location location) {
|
||||
return isClipped(location.getZ(), location.getX(), location.getY());
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the location has any clipping flags.
|
||||
* @param z The plane.
|
||||
* @param x The x-coordinate.
|
||||
* @param y The y-coordinate.
|
||||
* @return {@code True} if a clipping flag disables access for this location.
|
||||
*/
|
||||
public static boolean isClipped(int z, int x, int y) {
|
||||
if (!isLandscape(z, x, y)) {
|
||||
return true;
|
||||
}
|
||||
int flag = getClippingFlag(z, x, y);
|
||||
return (flag & 0x12c0102) != 0 || (flag & 0x12c0108) != 0 || (flag & 0x12c0120) != 0 || (flag & 0x12c0180) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the spawn location of a node.
|
||||
* @param owner the owner.
|
||||
* @param node the node.
|
||||
* @return the location.
|
||||
*/
|
||||
public static Location getSpawnLocation(Player owner, Node node) {
|
||||
if (owner == null || node == null) {
|
||||
return null;
|
||||
}
|
||||
Location destination = null;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
Direction dir = Direction.get(i);
|
||||
Location l = owner.getLocation().transform(dir, dir.toInteger() < 2 ? 1 : node.size());
|
||||
boolean success = true;
|
||||
loop:{
|
||||
for (int x = 0; x < node.size(); x++) {
|
||||
for (int y = 0; y < node.size(); y++) {
|
||||
if (RegionManager.isClipped(l.transform(x, y, 0))) {
|
||||
success = false;
|
||||
break loop;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (success) {
|
||||
destination = l;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return destination;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the scenery on the current location.
|
||||
* @param l The location.
|
||||
* @return The scenery, or {@code null} if no object was found.
|
||||
*/
|
||||
public static Scenery getObject(Location l) {
|
||||
return getObject(l.getZ(), l.getX(), l.getY());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the scenery on the current absolute coordinates.
|
||||
* @param z The height.
|
||||
* @param x The x-coordinate.
|
||||
* @param y The y-coordinate.
|
||||
* @return The scenery, or {@code null} if no object was found.
|
||||
*/
|
||||
public static Scenery getObject(int z, int x, int y) {
|
||||
return getObject(z, x, y, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the object on the given absolute coordinates.
|
||||
* @param z The height.
|
||||
* @param x The x-coordinate.
|
||||
* @param y The y-coordinate.
|
||||
* @param objectId The object id.
|
||||
* @return The scenery, or {@code null} if no object was found.
|
||||
*/
|
||||
public static Scenery getObject(int z, int x, int y, int objectId) {
|
||||
int regionId = ((x >> 6) << 8) | y >> 6;
|
||||
x -= ((x >> 6) << 6);
|
||||
y -= ((y >> 6) << 6);
|
||||
Region region = forId(regionId);
|
||||
Region.load(region);
|
||||
Scenery object = region.getPlanes()[z].getChunkObject(x, y, objectId);
|
||||
if (object != null && !object.isRenderable()) {
|
||||
return null;
|
||||
}
|
||||
return object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the region plane for this location.
|
||||
* @param l The location.
|
||||
* @return The region plane.
|
||||
*/
|
||||
public static RegionPlane getRegionPlane(Location l) {
|
||||
int regionId = ((l.getX() >> 6) << 8) | l.getY() >> 6;
|
||||
return forId(regionId).getPlanes()[l.getZ()];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a region chunk.
|
||||
* @param l The location.
|
||||
* @return The region chunk.
|
||||
*/
|
||||
public static RegionChunk getRegionChunk(Location l) {
|
||||
RegionPlane plane = getRegionPlane(l);
|
||||
return plane.getRegionChunk(l.getLocalX() / RegionChunk.SIZE, l.getLocalY() / RegionChunk.SIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves the entity from the current region to the new one.
|
||||
* @param entity The entity.
|
||||
*/
|
||||
public static void move(Entity entity) {
|
||||
boolean player = entity instanceof Player;
|
||||
int regionId = (entity.getLocation().getRegionX() >> 3) << 8 | (entity.getLocation().getRegionY() >> 3);
|
||||
Viewport viewport = entity.getViewport();
|
||||
Region current = forId(regionId);
|
||||
int z = entity.getLocation().getZ();
|
||||
RegionPlane plane = current.getPlanes()[z];
|
||||
viewport.updateViewport(entity);
|
||||
if (plane == viewport.getCurrentPlane()) {
|
||||
entity.getZoneMonitor().updateLocation(entity.getWalkingQueue().getFootPrint());
|
||||
return;
|
||||
}
|
||||
viewport.remove(entity);
|
||||
if (player) {
|
||||
current.add((Player) entity);
|
||||
} else {
|
||||
current.add((NPC) entity);
|
||||
}
|
||||
viewport.setRegion(current);
|
||||
viewport.setCurrentPlane(plane);
|
||||
List<RegionPlane> view = new LinkedList<>();
|
||||
for (int regionX = (entity.getLocation().getRegionX() >> 3) - 1; regionX <= (entity.getLocation().getRegionX() >> 3) + 1; regionX++) {
|
||||
for (int regionY = (entity.getLocation().getRegionY() >> 3) - 1; regionY <= (entity.getLocation().getRegionY() >> 3) + 1; regionY++) {
|
||||
if (regionX < 0 || regionY < 0) {
|
||||
continue;
|
||||
}
|
||||
Region region = forId(regionX << 8 | regionY);
|
||||
RegionPlane p = region.getPlanes()[z];
|
||||
if (player) {
|
||||
region.incrementViewAmount();
|
||||
region.flagActive();
|
||||
}
|
||||
view.add(p);
|
||||
}
|
||||
}
|
||||
viewport.setViewingPlanes(view);
|
||||
entity.getZoneMonitor().updateLocation(entity.getWalkingQueue().getFootPrint());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the list of local NPCs with a maximum distance of 16.
|
||||
* @param n The entity.
|
||||
* @return The list of local NPCs.
|
||||
*/
|
||||
public static List<NPC> getLocalNpcs(Entity n) {
|
||||
return getLocalNpcs(n, MapDistance.RENDERING.getDistance());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the location entitys.
|
||||
* @param location the location.
|
||||
* @param distance the distance.
|
||||
* @return the list.
|
||||
*/
|
||||
public static List<Entity> getLocalEntitys(Location location, int distance){
|
||||
List<Entity> entitys = new ArrayList<>(20);
|
||||
entitys.addAll(getLocalNpcs(location, distance));
|
||||
entitys.addAll(getLocalPlayers(location, distance));
|
||||
return entitys;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the location entitys.
|
||||
* @param entity the entity.
|
||||
* @param distance the distance.
|
||||
* @return the list.
|
||||
*/
|
||||
public static List<Entity> getLocalEntitys(Entity entity, int distance) {
|
||||
return getLocalEntitys(entity.getLocation(), distance);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the local entitys.
|
||||
* @param entity the entity.
|
||||
* @return the entitys.
|
||||
*/
|
||||
public static List<Entity> getLocalEntitys(Entity entity) {
|
||||
return getLocalEntitys(entity.getLocation(), MapDistance.RENDERING.getDistance());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the list of local NPCs.
|
||||
* @param n The entity.
|
||||
* @param distance The distance to the entity.
|
||||
* @return The list of local NPCs.
|
||||
*/
|
||||
public static List<NPC> getLocalNpcs(Entity n, int distance) {
|
||||
List<NPC> npcs = new LinkedList<>();
|
||||
for (RegionPlane r : n.getViewport().getViewingPlanes()) {
|
||||
for (NPC npc : r.getNpcs()) {
|
||||
if (npc.getLocation().withinDistance(n.getLocation(), distance)) {
|
||||
npcs.add(npc);
|
||||
}
|
||||
}
|
||||
}
|
||||
return npcs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the list of local players with a maximum distance of 15.
|
||||
* @param n The entity.
|
||||
* @return The list of local players.
|
||||
*/
|
||||
public static List<Player> getLocalPlayers(Entity n) {
|
||||
return getLocalPlayers(n, MapDistance.RENDERING.getDistance());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the list of local players.
|
||||
* @param n The entity.
|
||||
* @param distance The distance to the entity.
|
||||
* @return The list of local players.
|
||||
*/
|
||||
public static List<Player> getLocalPlayers(Entity n, int distance) {
|
||||
List<Player> players = new LinkedList<>();
|
||||
for (RegionPlane r : n.getViewport().getViewingPlanes()) {
|
||||
for (Player p : r.getPlayers()) {
|
||||
if (p.getLocation().withinDistance(n.getLocation(), distance)) {
|
||||
players.add(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
return players;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the surrounding players.
|
||||
* @param n The node the players should be surrounding.
|
||||
* @param ignore The nodes not to add to the list.
|
||||
* @return The list of players.
|
||||
*/
|
||||
public static List<Player> getSurroundingPlayers(Node n, Node...ignore) {
|
||||
return getSurroundingPlayers(n, 9, ignore);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the surrounding players.
|
||||
* @param n The node the players should be surrounding.
|
||||
* @param ignore The nodes not to add to the list.
|
||||
* @return The list of players.
|
||||
*/
|
||||
public static List<Player> getSurroundingPlayers(Node n, int maximum, Node...ignore) {
|
||||
List<Player> players = getLocalPlayers(n.getLocation(), 1);
|
||||
int count = 0;
|
||||
for (Iterator<Player> it = players.iterator(); it.hasNext();) {
|
||||
Player p = it.next();
|
||||
if (++count >= maximum) {
|
||||
it.remove();
|
||||
continue;
|
||||
}
|
||||
for (Node node : ignore) {
|
||||
if (p == node) {
|
||||
count--;
|
||||
it.remove();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return players;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the surrounding players.
|
||||
* @param n The node the players should be surrounding.
|
||||
* @param ignore The nodes not to add to the list.
|
||||
* @return The list of players.
|
||||
*/
|
||||
public static List<NPC> getSurroundingNPCs(Node n, Node...ignore) {
|
||||
return getSurroundingNPCs(n, 9, ignore);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the surrounding players.
|
||||
* @param n The node the npcs should be surrounding.
|
||||
* @param ignore The nodes not to add to the list.
|
||||
* @return The list of npcs.
|
||||
*/
|
||||
public static List<NPC> getSurroundingNPCs(Node n, int maximum, Node...ignore) {
|
||||
List<NPC> npcs = getLocalNpcs(n.getLocation(), 1);
|
||||
int count = 0;
|
||||
for (Iterator<NPC> it = npcs.iterator(); it.hasNext();) {
|
||||
NPC p = it.next();
|
||||
if (++count > maximum) {
|
||||
it.remove();
|
||||
continue;
|
||||
}
|
||||
for (Node node : ignore) {
|
||||
if (p == node) {
|
||||
count--;
|
||||
it.remove();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return npcs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a random teleport location in the radius around the given location.
|
||||
* @param location The centre location.
|
||||
* @param radius The radius.
|
||||
* @return A random teleport location.
|
||||
*/
|
||||
public static Location getTeleportLocation(Location location, int radius) {
|
||||
int mod = radius >> 1;
|
||||
if (mod == 0) {
|
||||
mod++;
|
||||
radius--;
|
||||
}
|
||||
return getTeleportLocation(location.transform(-mod, -mod, 0), mod + radius, mod + radius);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a random teleport location in the radius around the given location.
|
||||
* @param location The centre location.
|
||||
* @return A random teleport location.
|
||||
*/
|
||||
public static Location getTeleportLocation(Location location, int areaX, int areaY) {
|
||||
Location destination = location;
|
||||
int x = RandomFunction.random(1 + areaX);
|
||||
int y = RandomFunction.random(1 + areaY);
|
||||
int count = 0;
|
||||
while (!isTeleportPermitted(destination = location.transform(x, y, 0))) {
|
||||
x = RandomFunction.random(1 + areaX);
|
||||
y = RandomFunction.random(1 + areaY);
|
||||
if (count++ >= areaX * 2) {
|
||||
//This would be able to keep looping for several seconds otherwise (this actually happens).
|
||||
for (x = 0; x < areaX + 1; x++) {
|
||||
for (y = 0; y < areaY + 1; y++) {
|
||||
if (isTeleportPermitted(destination = location.transform(x, y, 0))) {
|
||||
return destination;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return destination;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current viewport for the location.
|
||||
* @param l The location.
|
||||
* @return The viewport.
|
||||
*/
|
||||
public static List<Player> getViewportPlayers(Location l) {
|
||||
List<Player> players = new LinkedList<>();
|
||||
l = l.getChunkBase().transform(-8, -8, 0);
|
||||
ZoneBorders b = new ZoneBorders(l.getX(), l.getY(), l.getX() + 24, l.getY() + 24);
|
||||
for (int regionX = (l.getRegionX() - 6) >> 3; regionX <= (l.getRegionX() + 6) >> 3; regionX++) {
|
||||
for (int regionY = (l.getRegionY() - 6) >> 3; regionY <= (l.getRegionY() + 6) >> 3; regionY++) {
|
||||
for (Player player : forId(regionX << 8 | regionY).getPlanes()[l.getZ()].getPlayers()) {
|
||||
l = player.getLocation();
|
||||
if (b.insideBorder(l.getX(), l.getY())) {
|
||||
players.add(player);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return players;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of players in the given region.
|
||||
* @param regionId The region id.
|
||||
* @return The list of players in this region.
|
||||
*/
|
||||
public static List<Player> getRegionPlayers(int regionId) {
|
||||
Region r = forId(regionId);
|
||||
List<Player> players = new ArrayList<>(20);
|
||||
for (RegionPlane plane : r.getPlanes()) {
|
||||
players.addAll(plane.getPlayers());
|
||||
}
|
||||
return players;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of local players within rendering distance of the location.
|
||||
* @param l The location.
|
||||
* @return The list of players.
|
||||
*/
|
||||
public static List<Player> getLocalPlayers(Location l) {
|
||||
return getLocalPlayers(l, MapDistance.RENDERING.getDistance());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of local players.
|
||||
* @param l The location.
|
||||
* @param distance The distance to that location.
|
||||
* @return The list of players.
|
||||
*/
|
||||
public static List<Player> getLocalPlayers(Location l, int distance) {
|
||||
List<Player> players = new LinkedList<>();
|
||||
for (int regionX = (l.getRegionX() - 6) >> 3; regionX <= (l.getRegionX() + 6) >> 3; regionX++) {
|
||||
for (int regionY = (l.getRegionY() - 6) >> 3; regionY <= (l.getRegionY() + 6) >> 3; regionY++) {
|
||||
for (Player player : forId(regionX << 8 | regionY).getPlanes()[l.getZ()].getPlayers()) {
|
||||
if (player.getLocation().withinDistance(l, distance)) {
|
||||
players.add(player);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return players;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of local players within 16 tile distance of the location.
|
||||
* @param l The location.
|
||||
* @return The list of players.
|
||||
*/
|
||||
public static List<NPC> getLocalNpcs(Location l) {
|
||||
return getLocalNpcs(l, MapDistance.RENDERING.getDistance());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the npc.
|
||||
* @param entity the entity.
|
||||
* @param id the id.
|
||||
*/
|
||||
public static NPC getNpc(final Entity entity, final int id) {
|
||||
return getNpc(entity, id, 16);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the npc.
|
||||
* @param entity the entity.
|
||||
* @param id the id.
|
||||
* @param distance the distance.
|
||||
* @return the npc.
|
||||
*/
|
||||
public static NPC getNpc(Entity entity, int id, int distance) {
|
||||
return getNpc(entity.getLocation(), id, distance);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an npc near the entity.
|
||||
* @param id the id,
|
||||
* @param distance the dinstance.
|
||||
* @return the npc.
|
||||
*/
|
||||
public static NPC getNpc(final Location location, int id, int distance) {
|
||||
List<NPC> npcs = getLocalNpcs(location, distance);
|
||||
for (NPC n : npcs) {
|
||||
if (n.getId() == id) {
|
||||
return n;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of local players.
|
||||
* @param l The location.
|
||||
* @param distance The distance to that location.
|
||||
* @return The list of players.
|
||||
*/
|
||||
public static List<NPC> getLocalNpcs(Location l, int distance) {
|
||||
List<NPC> npcs = new LinkedList<>();
|
||||
for (int regionX = (l.getRegionX() - 6) >> 3; regionX <= (l.getRegionX() + 6) >> 3; regionX++) {
|
||||
for (int regionY = (l.getRegionY() - 6) >> 3; regionY <= (l.getRegionY() + 6) >> 3; regionY++) {
|
||||
for (NPC n : forId(regionX << 8 | regionY).getPlanes()[l.getZ()].getNpcs()) {
|
||||
if (n.getLocation().withinDistance(l, (n.size() >> 1) + distance)) {
|
||||
npcs.add(n);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return npcs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the regionCache.
|
||||
* @return The regionCache.
|
||||
*/
|
||||
public static Map<Integer, Region> getRegionCache() {
|
||||
return REGION_CACHE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,807 @@
|
||||
package core.game.world.map
|
||||
|
||||
import core.game.world.map.RegionManager
|
||||
import core.game.world.map.RegionPlane
|
||||
import core.game.node.`object`.Scenery
|
||||
import core.game.node.Node
|
||||
import core.game.node.entity.Entity
|
||||
import core.game.node.entity.npc.NPC
|
||||
import core.game.node.entity.player.Player
|
||||
import core.game.world.map.zone.ZoneBorders
|
||||
import core.tools.RandomFunction
|
||||
import rs09.game.system.SystemLogger
|
||||
import java.util.*
|
||||
import java.util.concurrent.TimeUnit
|
||||
import java.util.concurrent.locks.ReentrantLock
|
||||
|
||||
/**
|
||||
* Manages the regions.
|
||||
* @author Emperor
|
||||
*/
|
||||
object RegionManager {
|
||||
/**
|
||||
* The region cache mapping.
|
||||
*/
|
||||
private val REGION_CACHE: MutableMap<Int, Region> = HashMap()
|
||||
|
||||
public val LOCK = ReentrantLock()
|
||||
|
||||
/**
|
||||
* Gets the region for the given region id.
|
||||
* @param regionId The region id.
|
||||
* @return The region.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun forId(regionId: Int): Region {
|
||||
LOCK.tryLock(10000, TimeUnit.MILLISECONDS)
|
||||
var region = REGION_CACHE[regionId]
|
||||
if (region == null) {
|
||||
region = Region((regionId shr 8) and 0xFF, regionId and 0xFF)
|
||||
if(region!!.regionId != regionId){
|
||||
SystemLogger.logErr("IDs do NOT match - ${region!!.regionId} supposed to be $regionId")
|
||||
}
|
||||
REGION_CACHE[regionId] = region
|
||||
}
|
||||
LOCK.unlock()
|
||||
return REGION_CACHE[regionId]!!
|
||||
}
|
||||
|
||||
/**
|
||||
* Pulses the active regions.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun pulse() {
|
||||
LOCK.tryLock(10000,TimeUnit.MILLISECONDS)
|
||||
for (r in REGION_CACHE.values) {
|
||||
if (r != null && r.isActive) {
|
||||
for (p in r.planes) {
|
||||
p.pulse()
|
||||
}
|
||||
}
|
||||
}
|
||||
LOCK.unlock()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the clipping flag on the given location.
|
||||
* @param l The location.
|
||||
* @return The clipping flag.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getClippingFlag(l: Location): Int {
|
||||
return getClippingFlag(l.z, l.x, l.y)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the clipping flag.
|
||||
* @param z The plane.
|
||||
* @param x The absolute x-coordinate.
|
||||
* @param y The absolute y-coordinate.
|
||||
* @return The clipping flags.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getClippingFlag(z: Int, x: Int, y: Int): Int {
|
||||
var x = x
|
||||
var y = y
|
||||
val region = forId(((x shr 6) shl 8) or (y shr 6))
|
||||
Region.load(region)
|
||||
if (!region.isHasFlags) {
|
||||
return -1
|
||||
}
|
||||
x -= x shr 6 shl 6
|
||||
y -= y shr 6 shl 6
|
||||
return region.planes[z].flags.clippingFlags[x][y]
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the water variant of a tile's clipping flag
|
||||
* Essentially strips the landscape flag off a tile and keeps other flags, and makes normally walkable tiles unwalkable.
|
||||
* @author Ceikry
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getWaterClipFlag(z: Int, x: Int, y: Int): Int {
|
||||
val flag = getClippingFlag(z, x, y)
|
||||
return if (!isClipped(z, x, y)) {
|
||||
flag or 0x100
|
||||
} else flag and 0x200000.inv()
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the tile is part of the landscape.
|
||||
* @param l The location.
|
||||
* @return `True` if so.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun isLandscape(l: Location): Boolean {
|
||||
return isLandscape(l.z, l.x, l.y)
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the tile is part of the landscape.
|
||||
* @param z The plane.
|
||||
* @param x The absolute x-coordinate.
|
||||
* @param y The absolute y-coordinate.
|
||||
* @return `True` if so.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun isLandscape(z: Int, x: Int, y: Int): Boolean {
|
||||
var x = x
|
||||
var y = y
|
||||
val region = forId(((x shr 6) shl 8) or (y shr 6))
|
||||
Region.load(region)
|
||||
if (!region.isHasFlags || region.planes[z].flags.landscape == null) {
|
||||
return false
|
||||
}
|
||||
x -= x shr 6 shl 6
|
||||
y -= y shr 6 shl 6
|
||||
return region.planes[z].flags.landscape[x][y]
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the clipping flag on the given location.
|
||||
* @param l The location.
|
||||
* @param flag The flag to set.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun setClippingFlag(l: Location, flag: Int) {
|
||||
var x = l.x
|
||||
var y = l.y
|
||||
val z = l.z
|
||||
val region = forId(((x shr 6) shl 8) or (y shr 6))
|
||||
Region.load(region)
|
||||
if (!region.isHasFlags) {
|
||||
return
|
||||
}
|
||||
x -= x shr 6 shl 6
|
||||
y -= y shr 6 shl 6
|
||||
region.planes[z].flags.clippingFlags[x][y] = flag
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a clipping flag.
|
||||
* @param z The plane.
|
||||
* @param x The absolute x-coordinate.
|
||||
* @param y The absolute y-coordinate.
|
||||
* @param projectile If the flag is being set for projectile pathfinding.
|
||||
* @param flag The clipping flag.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun addClippingFlag(z: Int, x: Int, y: Int, projectile: Boolean, flag: Int) {
|
||||
var x = x
|
||||
var y = y
|
||||
val region = forId(((x shr 6) shl 8) or (y shr 6))
|
||||
Region.load(region)
|
||||
if (!region.isHasFlags) {
|
||||
return
|
||||
}
|
||||
x -= x shr 6 shl 6
|
||||
y -= y shr 6 shl 6
|
||||
if (projectile) {
|
||||
region.planes[z].projectileFlags.flag(x, y, flag)
|
||||
} else {
|
||||
region.planes[z].flags.flag(x, y, flag)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a clipping flag.
|
||||
* @param z The plane.
|
||||
* @param x The absolute x-coordinate.
|
||||
* @param y The absolute y-coordinate.
|
||||
* @param projectile If the flag is being set for projectile pathfinding.
|
||||
* @param flag The clipping flag.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun removeClippingFlag(z: Int, x: Int, y: Int, projectile: Boolean, flag: Int) {
|
||||
var x = x
|
||||
var y = y
|
||||
val region = forId(((x shr 6) shl 8) or (y shr 6))
|
||||
Region.load(region)
|
||||
if (!region.isHasFlags) {
|
||||
return
|
||||
}
|
||||
x -= x shr 6 shl 6
|
||||
y -= y shr 6 shl 6
|
||||
if (projectile) {
|
||||
region.planes[z].projectileFlags.unflag(x, y, flag)
|
||||
} else {
|
||||
region.planes[z].flags.unflag(x, y, flag)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the clipping flag.
|
||||
* @param z The plane.
|
||||
* @param x The absolute x-coordinate.
|
||||
* @param y The absolute y-coordinate.
|
||||
* @return The clipping flags.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getProjectileFlag(z: Int, x: Int, y: Int): Int {
|
||||
var x = x
|
||||
var y = y
|
||||
val region = forId(((x shr 6) shl 8) or (y shr 6))
|
||||
Region.load(region)
|
||||
if (!region.isHasFlags) {
|
||||
return -1
|
||||
}
|
||||
x -= x shr 6 shl 6
|
||||
y -= y shr 6 shl 6
|
||||
return region.planes[z].projectileFlags.clippingFlags[x][y]
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the clipping flag
|
||||
* @param location the Location
|
||||
* @return the clipping flag
|
||||
*/
|
||||
@JvmStatic
|
||||
fun isTeleportPermitted(location: Location): Boolean {
|
||||
return isTeleportPermitted(location.z, location.x, location.y)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the clipping flag.
|
||||
* @param z The plane.
|
||||
* @param x The absolute x-coordinate.
|
||||
* @param y The absolute y-coordinate.
|
||||
* @return The clipping flags.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun isTeleportPermitted(z: Int, x: Int, y: Int): Boolean {
|
||||
if (!isLandscape(z, x, y)) {
|
||||
return false
|
||||
}
|
||||
val flag = getClippingFlag(z, x, y)
|
||||
return flag and 0x12c0102 == 0 || flag and 0x12c0108 == 0 || flag and 0x12c0120 == 0 || flag and 0x12c0180 == 0
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the location has any clipping flags.
|
||||
* @param location The location.
|
||||
* @return `True` if a clipping flag disables access for this location.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun isClipped(location: Location): Boolean {
|
||||
return isClipped(location.z, location.x, location.y)
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the location has any clipping flags.
|
||||
* @param z The plane.
|
||||
* @param x The x-coordinate.
|
||||
* @param y The y-coordinate.
|
||||
* @return `True` if a clipping flag disables access for this location.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun isClipped(z: Int, x: Int, y: Int): Boolean {
|
||||
if (!isLandscape(z, x, y)) {
|
||||
return true
|
||||
}
|
||||
val flag = getClippingFlag(z, x, y)
|
||||
return flag and 0x12c0102 != 0 || flag and 0x12c0108 != 0 || flag and 0x12c0120 != 0 || flag and 0x12c0180 != 0
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the spawn location of a node.
|
||||
* @param owner the owner.
|
||||
* @param node the node.
|
||||
* @return the location.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getSpawnLocation(owner: Player?, node: Node?): Location? {
|
||||
if (owner == null || node == null) {
|
||||
return null
|
||||
}
|
||||
var destination: Location? = null
|
||||
for (i in 0..3) {
|
||||
val dir = Direction.get(i)
|
||||
val l = owner.location.transform(dir, if (dir.toInteger() < 2) 1 else node.size())
|
||||
var success = true
|
||||
for (x in 0 until node.size()) {
|
||||
for (y in 0 until node.size()) {
|
||||
if (isClipped(l.transform(x, y, 0))) {
|
||||
success = false
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if (success) {
|
||||
destination = l
|
||||
break
|
||||
}
|
||||
}
|
||||
return destination
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the scenery on the current location.
|
||||
* @param l The location.
|
||||
* @return The scenery, or `null` if no object was found.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getObject(l: Location): Scenery? {
|
||||
return getObject(l.z, l.x, l.y)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the scenery on the current absolute coordinates.
|
||||
* @param z The height.
|
||||
* @param x The x-coordinate.
|
||||
* @param y The y-coordinate.
|
||||
* @return The scenery, or `null` if no object was found.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getObject(z: Int, x: Int, y: Int): Scenery? {
|
||||
return getObject(z, x, y, -1)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the object on the given absolute coordinates.
|
||||
* @param z The height.
|
||||
* @param x The x-coordinate.
|
||||
* @param y The y-coordinate.
|
||||
* @param objectId The object id.
|
||||
* @return The scenery, or `null` if no object was found.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getObject(z: Int, x: Int, y: Int, objectId: Int): Scenery? {
|
||||
var x = x
|
||||
var y = y
|
||||
val regionId = ((x shr 6) shl 8) or (y shr 6)
|
||||
x -= (x shr 6) shl 6
|
||||
y -= (y shr 6) shl 6
|
||||
val region = forId(regionId)
|
||||
Region.load(region)
|
||||
val `object`: Scenery? = region.planes[z].getChunkObject(x, y, objectId)
|
||||
return if (`object` != null && !`object`.isRenderable()) {
|
||||
null
|
||||
} else `object`
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the region plane for this location.
|
||||
* @param l The location.
|
||||
* @return The region plane.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getRegionPlane(l: Location): RegionPlane {
|
||||
val regionId = ((l.x shr 6) shl 8) or (l.y shr 6)
|
||||
return forId(regionId).planes[l.z]
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a region chunk.
|
||||
* @param l The location.
|
||||
* @return The region chunk.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getRegionChunk(l: Location): RegionChunk {
|
||||
val plane = getRegionPlane(l)
|
||||
return plane.getRegionChunk(l.localX / RegionChunk.SIZE, l.localY / RegionChunk.SIZE)
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves the entity from the current region to the new one.
|
||||
* @param entity The entity.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun move(entity: Entity) {
|
||||
val player = entity is Player
|
||||
val regionId = ((entity.location.regionX shr 3) shl 8) or (entity.location.regionY shr 3)
|
||||
val viewport = entity.viewport
|
||||
val current = forId(regionId)
|
||||
val z = entity.location.z
|
||||
val plane = current.planes[z]
|
||||
viewport.updateViewport(entity)
|
||||
if (plane == viewport.currentPlane) {
|
||||
entity.zoneMonitor.updateLocation(entity.walkingQueue.footPrint)
|
||||
return
|
||||
}
|
||||
viewport.remove(entity)
|
||||
if (player) {
|
||||
current.add(entity as Player)
|
||||
} else {
|
||||
current.add(entity as NPC)
|
||||
}
|
||||
viewport.region = current
|
||||
viewport.currentPlane = plane
|
||||
val view: MutableList<RegionPlane> = LinkedList()
|
||||
for (regionX in ((entity.location.regionX shr 3) - 1)..((entity.location.regionX shr 3) + 1)) {
|
||||
for (regionY in ((entity.location.regionY shr 3) - 1)..((entity.location.regionY shr 3) + 1)) {
|
||||
if (regionX < 0 || regionY < 0) {
|
||||
continue
|
||||
}
|
||||
val region = forId((regionX shl 8) or regionY)
|
||||
val p = region.planes[z]
|
||||
if (player) {
|
||||
region.incrementViewAmount()
|
||||
region.flagActive()
|
||||
}
|
||||
view.add(p)
|
||||
}
|
||||
}
|
||||
viewport.viewingPlanes = view
|
||||
entity.zoneMonitor.updateLocation(entity.walkingQueue.footPrint)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the list of local NPCs with a maximum distance of 16.
|
||||
* @param n The entity.
|
||||
* @return The list of local NPCs.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getLocalNpcs(n: Entity): List<NPC> {
|
||||
return getLocalNpcs(n, MapDistance.RENDERING.distance)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the location entitys.
|
||||
* @param location the location.
|
||||
* @param distance the distance.
|
||||
* @return the list.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getLocalEntitys(location: Location, distance: Int): List<Entity> {
|
||||
val entitys: MutableList<Entity> = ArrayList(20)
|
||||
entitys.addAll(getLocalNpcs(location, distance))
|
||||
entitys.addAll(getLocalPlayers(location, distance))
|
||||
return entitys
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the location entitys.
|
||||
* @param entity the entity.
|
||||
* @param distance the distance.
|
||||
* @return the list.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getLocalEntitys(entity: Entity, distance: Int): List<Entity> {
|
||||
return getLocalEntitys(entity.location, distance)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the local entitys.
|
||||
* @param entity the entity.
|
||||
* @return the entitys.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getLocalEntitys(entity: Entity): List<Entity> {
|
||||
return getLocalEntitys(entity.location, MapDistance.RENDERING.distance)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the list of local NPCs.
|
||||
* @param n The entity.
|
||||
* @param distance The distance to the entity.
|
||||
* @return The list of local NPCs.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getLocalNpcs(n: Entity, distance: Int): List<NPC> {
|
||||
val npcs: MutableList<NPC> = LinkedList()
|
||||
for (r in n.viewport.viewingPlanes) {
|
||||
for (npc in r.npcs) {
|
||||
if (npc.location.withinDistance(n.location, distance)) {
|
||||
npcs.add(npc)
|
||||
}
|
||||
}
|
||||
}
|
||||
return npcs
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the list of local players with a maximum distance of 15.
|
||||
* @param n The entity.
|
||||
* @return The list of local players.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getLocalPlayers(n: Entity): List<Player> {
|
||||
return getLocalPlayers(n, MapDistance.RENDERING.distance)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the list of local players.
|
||||
* @param n The entity.
|
||||
* @param distance The distance to the entity.
|
||||
* @return The list of local players.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getLocalPlayers(n: Entity, distance: Int): List<Player> {
|
||||
val players: MutableList<Player> = LinkedList()
|
||||
for (r in n.viewport.viewingPlanes) {
|
||||
for (p in r.players) {
|
||||
if (p.location.withinDistance(n.location, distance)) {
|
||||
players.add(p)
|
||||
}
|
||||
}
|
||||
}
|
||||
return players
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the surrounding players.
|
||||
* @param n The node the players should be surrounding.
|
||||
* @param ignore The nodes not to add to the list.
|
||||
* @return The list of players.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getSurroundingPlayers(n: Node, vararg ignore: Node): List<Player> {
|
||||
return getSurroundingPlayers(n, 9, *ignore)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the surrounding players.
|
||||
* @param n The node the players should be surrounding.
|
||||
* @param ignore The nodes not to add to the list.
|
||||
* @return The list of players.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getSurroundingPlayers(n: Node, maximum: Int, vararg ignore: Node): List<Player> {
|
||||
val players = getLocalPlayers(n.location, 1)
|
||||
var count = 0
|
||||
val it = players.iterator()
|
||||
while (it.hasNext()) {
|
||||
val p = it.next()
|
||||
if (++count >= maximum) {
|
||||
it.remove()
|
||||
continue
|
||||
}
|
||||
for (node in ignore) {
|
||||
if (p === node) {
|
||||
count--
|
||||
it.remove()
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return players
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the surrounding players.
|
||||
* @param n The node the players should be surrounding.
|
||||
* @param ignore The nodes not to add to the list.
|
||||
* @return The list of players.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getSurroundingNPCs(n: Node, vararg ignore: Node): List<NPC> {
|
||||
return getSurroundingNPCs(n, 9, *ignore)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the surrounding players.
|
||||
* @param n The node the npcs should be surrounding.
|
||||
* @param ignore The nodes not to add to the list.
|
||||
* @return The list of npcs.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getSurroundingNPCs(n: Node, maximum: Int, vararg ignore: Node): List<NPC> {
|
||||
val npcs = getLocalNpcs(n.location, 1)
|
||||
var count = 0
|
||||
val it = npcs.iterator()
|
||||
while (it.hasNext()) {
|
||||
val p = it.next()
|
||||
if (++count > maximum) {
|
||||
it.remove()
|
||||
continue
|
||||
}
|
||||
for (node in ignore) {
|
||||
if (p === node) {
|
||||
count--
|
||||
it.remove()
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return npcs
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a random teleport location in the radius around the given location.
|
||||
* @param location The centre location.
|
||||
* @param radius The radius.
|
||||
* @return A random teleport location.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getTeleportLocation(location: Location, radius: Int): Location {
|
||||
var radius = radius
|
||||
var mod = radius shr 1
|
||||
if (mod == 0) {
|
||||
mod++
|
||||
radius--
|
||||
}
|
||||
return getTeleportLocation(location.transform(-mod, -mod, 0), mod + radius, mod + radius)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a random teleport location in the radius around the given location.
|
||||
* @param location The centre location.
|
||||
* @return A random teleport location.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getTeleportLocation(location: Location, areaX: Int, areaY: Int): Location {
|
||||
var destination = location
|
||||
var x: Int = RandomFunction.random(1 + areaX)
|
||||
var y: Int = RandomFunction.random(1 + areaY)
|
||||
var count = 0
|
||||
while (!isTeleportPermitted(location.transform(x, y, 0).also { destination = it })) {
|
||||
x = RandomFunction.random(1 + areaX)
|
||||
y = RandomFunction.random(1 + areaY)
|
||||
if (count++ >= areaX * 2) {
|
||||
//This would be able to keep looping for several seconds otherwise (this actually happens).
|
||||
x = 0
|
||||
while (x < areaX + 1) {
|
||||
y = 0
|
||||
while (y < areaY + 1) {
|
||||
if (isTeleportPermitted(location.transform(x, y, 0).also { destination = it })) {
|
||||
return destination
|
||||
}
|
||||
y++
|
||||
}
|
||||
x++
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
return destination
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current viewport for the location.
|
||||
* @param l The location.
|
||||
* @return The viewport.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getViewportPlayers(l: Location): List<Player> {
|
||||
var l = l
|
||||
val players: MutableList<Player> = LinkedList()
|
||||
l = l.chunkBase.transform(-8, -8, 0)
|
||||
val b = ZoneBorders(l.x, l.y, l.x + 24, l.y + 24)
|
||||
for (regionX in ((l.regionX - 6) shr 3)..((l.regionX + 6) shr 3)) {
|
||||
for (regionY in ((l.regionY - 6) shr 3)..((l.regionY + 6) shr 3)) {
|
||||
for (player in forId(regionX shl 8 or regionY).planes[l.z].players) {
|
||||
l = player.location
|
||||
if (b.insideBorder(l.x, l.y)) {
|
||||
players.add(player)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return players
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of players in the given region.
|
||||
* @param regionId The region id.
|
||||
* @return The list of players in this region.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getRegionPlayers(regionId: Int): List<Player> {
|
||||
val r = forId(regionId)
|
||||
val players: MutableList<Player> = ArrayList(20)
|
||||
for (plane in r.planes) {
|
||||
players.addAll(plane.players)
|
||||
}
|
||||
return players
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of local players within rendering distance of the location.
|
||||
* @param l The location.
|
||||
* @return The list of players.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getLocalPlayers(l: Location): List<Player> {
|
||||
return getLocalPlayers(l, MapDistance.RENDERING.distance)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of local players.
|
||||
* @param l The location.
|
||||
* @param distance The distance to that location.
|
||||
* @return The list of players.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getLocalPlayers(l: Location, distance: Int): MutableList<Player> {
|
||||
val players: MutableList<Player> = LinkedList()
|
||||
for (regionX in ((l.regionX - 6) shr 3)..((l.regionX + 6) shr 3)) {
|
||||
for (regionY in ((l.regionY - 6) shr 3)..((l.regionY + 6) shr 3)) {
|
||||
for (player in forId((regionX shl 8) or regionY).planes[l.z].players) {
|
||||
if (player.location.withinDistance(l, distance)) {
|
||||
players.add(player)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return players
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of local players within 16 tile distance of the location.
|
||||
* @param l The location.
|
||||
* @return The list of players.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getLocalNpcs(l: Location): List<NPC> {
|
||||
return getLocalNpcs(l, MapDistance.RENDERING.distance)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the npc.
|
||||
* @param entity the entity.
|
||||
* @param id the id.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getNpc(entity: Entity, id: Int): NPC? {
|
||||
return getNpc(entity, id, 16)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the npc.
|
||||
* @param entity the entity.
|
||||
* @param id the id.
|
||||
* @param distance the distance.
|
||||
* @return the npc.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getNpc(entity: Entity, id: Int, distance: Int): NPC? {
|
||||
return getNpc(entity.location, id, distance)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an npc near the entity.
|
||||
* @param id the id,
|
||||
* @param distance the dinstance.
|
||||
* @return the npc.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getNpc(location: Location, id: Int, distance: Int): NPC? {
|
||||
val npcs: List<NPC> = getLocalNpcs(location, distance)
|
||||
for (n in npcs) {
|
||||
if (n.id == id) {
|
||||
return n
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of local players.
|
||||
* @param l The location.
|
||||
* @param distance The distance to that location.
|
||||
* @return The list of players.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getLocalNpcs(l: Location, distance: Int): MutableList<NPC> {
|
||||
val npcs: MutableList<NPC> = LinkedList()
|
||||
for (regionX in ((l.regionX - 6) shr 3)..((l.regionX + 6) shr 3)) {
|
||||
for (regionY in ((l.regionY - 6) shr 3)..((l.regionY + 6) shr 3)) {
|
||||
for (n in forId(regionX shl 8 or regionY).planes[l.z].npcs) {
|
||||
if (n.location.withinDistance(l, (n.size() shr 1) + distance)) {
|
||||
npcs.add(n)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return npcs
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun addRegion(id: Int, region: Region){
|
||||
LOCK.tryLock(10000, TimeUnit.MILLISECONDS)
|
||||
REGION_CACHE[id] = region
|
||||
LOCK.unlock()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the regionCache.
|
||||
* @return The regionCache.
|
||||
*/
|
||||
val regionCache: Map<Int, Region>
|
||||
@JvmStatic get(){
|
||||
return REGION_CACHE
|
||||
}
|
||||
|
||||
val lock: ReentrantLock
|
||||
@JvmStatic get() = LOCK
|
||||
}
|
||||
@@ -122,14 +122,14 @@ public final class DynamicRegion extends Region {
|
||||
Location loc = l.transform((x - baseX) << 6, (y - baseY) << 6, 0);
|
||||
DynamicRegion region = copy(regionId, loc);
|
||||
region.setBorders(border);
|
||||
Region r = RegionManager.getRegionCache().get(region.getId());
|
||||
Region r = RegionManager.forId(region.getId());
|
||||
if (r != null) {
|
||||
for (int z = 0; z < 4; z++) {
|
||||
region.getPlanes()[z].getPlayers().addAll(r.getPlanes()[z].getPlayers());
|
||||
region.getPlanes()[z].getNpcs().addAll(r.getPlanes()[z].getNpcs());
|
||||
}
|
||||
}
|
||||
RegionManager.getRegionCache().put(region.getId(), region);
|
||||
RegionManager.addRegion(region.getId(), region);
|
||||
regions.add(region);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -247,7 +247,7 @@ class ScriptAPI(private val bot: Player) {
|
||||
* @return an Array of the nearest NPCs with matching name, or null.
|
||||
* @author Ceikry
|
||||
*/
|
||||
private fun findTargets(entity: Entity?, radius: Int, name: String? = null): List<Entity>? {
|
||||
private fun findTargets(entity: Entity, radius: Int, name: String? = null): List<Entity>? {
|
||||
val targets: MutableList<Entity> = ArrayList()
|
||||
val localNPCs: Array<Any> = RegionManager.getLocalNpcs(entity, radius).toTypedArray()
|
||||
var length = localNPCs.size
|
||||
|
||||
@@ -4,29 +4,20 @@ import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class ConfigParser {
|
||||
fun prePlugin() = GlobalScope.launch{
|
||||
launch {
|
||||
fun prePlugin() {
|
||||
NPCConfigParser().load()
|
||||
ItemConfigParser().load()
|
||||
}
|
||||
launch {
|
||||
ObjectConfigParser().load()
|
||||
XteaParser().load()
|
||||
}
|
||||
InterfaceConfigParser().load()
|
||||
InterfaceConfigParser().load()
|
||||
}
|
||||
|
||||
fun postPlugin() = GlobalScope.launch{
|
||||
launch {
|
||||
fun postPlugin() {
|
||||
ShopParser().load()
|
||||
DropTableParser().load()
|
||||
NPCSpawner().load()
|
||||
}
|
||||
launch {
|
||||
DoorConfigLoader().load()
|
||||
GroundSpawnLoader().load()
|
||||
MusicConfigLoader().load()
|
||||
}
|
||||
RangedConfigLoader().load()
|
||||
RangedConfigLoader().load()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user