New l2j geoengine rework.
This commit is contained in:
@@ -6,33 +6,44 @@
|
||||
# at different folder/harddrive ("C:/Program Files/Lineage II/system/geodata/"), default: ./data/geodata/
|
||||
GeoDataPath = ./data/geodata/
|
||||
|
||||
# Specifies the geodata files type. Default: L2J
|
||||
# L2J: Using L2J geodata files (filename e.g. 22_16.l2j)
|
||||
# L2OFF: Using L2OFF geodata files (filename e.g. 22_16_conv.dat)
|
||||
GeoDataType = L2J
|
||||
|
||||
# =================================================================
|
||||
# Path finding
|
||||
# Pathfinding
|
||||
# =================================================================
|
||||
|
||||
# When line of movement check fails, the pathfinding algoritm is performed to look for
|
||||
# an alternative path (e.g. walk around obstacle), default: true
|
||||
PathFinding = true
|
||||
# an alternative path (e.g. walk around obstacle), default: True
|
||||
PathFinding = True
|
||||
|
||||
# Pathfinding array buffers configuration, default: 100x6;128x6;192x6;256x4;320x4;384x4;500x2
|
||||
PathFindBuffers = 100x6;128x6;192x6;256x4;320x4;384x4;500x2
|
||||
# Pathfinding array buffers configuration, default: 500x10;1000x10;3000x5;5000x3;10000x3
|
||||
PathFindBuffers = 500x10;1000x10;3000x5;5000x3;10000x3
|
||||
|
||||
# Weight for nodes without obstacles far from walls
|
||||
LowWeight = 0.5
|
||||
# Movement weight, when moving from one to another axially and diagonally, default: 10 and 14
|
||||
MoveWeight = 10
|
||||
MoveWeightDiag = 14
|
||||
|
||||
# Weight for nodes near walls
|
||||
MediumWeight = 2
|
||||
# When movement flags of target node is blocked to any direction, use this weight instead of MoveWeight or MoveWeightDiag.
|
||||
# This causes pathfinding algorithm to avoid path construction exactly near an obstacle, default: 30
|
||||
ObstacleWeight = 30
|
||||
|
||||
# Weight for nodes with obstacles
|
||||
HighWeight = 3
|
||||
# Weight of the heuristic algorithm, which is giving estimated cost from node to target, default: 12 and 18
|
||||
# For proper function must be higher than MoveWeight.
|
||||
HeuristicWeight = 12
|
||||
HeuristicWeightDiag = 18
|
||||
|
||||
# Weight for diagonal movement.
|
||||
# Default: LowWeight * sqrt(2)
|
||||
DiagonalWeight = 0.707
|
||||
# Maximum number of generated nodes per one path-finding process, default 3500
|
||||
MaxIterations = 3500
|
||||
|
||||
# =================================================================
|
||||
# Other
|
||||
# Line of Sight
|
||||
# =================================================================
|
||||
|
||||
# Correct player Z after falling through the ground.
|
||||
CorrectPlayerZ = False
|
||||
# Line of sight start at X percent of the character height, default: 75
|
||||
PartOfCharacterHeight = 75
|
||||
|
||||
# Maximum height of an obstacle, which can exceed the line of sight, default: 32
|
||||
MaxObstacleHeight = 32
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -23,8 +23,8 @@ a - Prerequisites
|
||||
b - Make it work
|
||||
----------------------------------------------
|
||||
|
||||
To make geodata working:
|
||||
* unpack your geodata files into "/data/geodata" folder
|
||||
* open "/config/GeoEngine.ini" with your favorite text editor and then edit following config:
|
||||
- CoordSynchronize = 2
|
||||
* If you do not use any geodata files, the server will automatically change this setting to -1.
|
||||
To make geodata work:
|
||||
* unpack your geodata files into "/data/geodata" folder (or any other folder)
|
||||
* open "/config/GeoEngine.ini" with your favorite text editor and then edit following configs:
|
||||
- GeoDataPath = set path to your geodata, if elsewhere than "./data/geodata/"
|
||||
- GeoDataType = set the geodata format, which you are using.
|
||||
|
@@ -270,7 +270,7 @@ public class PrimevalIsle extends AbstractNpcAI
|
||||
final double cos = Math.cos(radian);
|
||||
final int newX = (int) (npc.getX() + (cos * distance));
|
||||
final int newY = (int) (npc.getY() + (sin * distance));
|
||||
final Location loc = GeoEngine.getInstance().canMoveToTargetLoc(npc.getX(), npc.getY(), npc.getZ(), newX, newY, npc.getZ(), npc.getInstanceId());
|
||||
final Location loc = GeoEngine.getInstance().getValidLocation(npc.getX(), npc.getY(), npc.getZ(), newX, newY, npc.getZ(), npc.getInstanceId());
|
||||
npc.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, loc, 0);
|
||||
}
|
||||
else if (ag_type == 1)
|
||||
|
@@ -69,7 +69,7 @@ public class FleeMonsters extends AbstractNpcAI
|
||||
final int posX = (int) (npc.getX() + (FLEE_DISTANCE * Math.cos(radians)));
|
||||
final int posY = (int) (npc.getY() + (FLEE_DISTANCE * Math.sin(radians)));
|
||||
final int posZ = npc.getZ();
|
||||
final Location destination = GeoEngine.getInstance().canMoveToTargetLoc(npc.getX(), npc.getY(), npc.getZ(), posX, posY, posZ, attacker.getInstanceId());
|
||||
final Location destination = GeoEngine.getInstance().getValidLocation(npc.getX(), npc.getY(), npc.getZ(), posX, posY, posZ, npc.getInstanceId());
|
||||
npc.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, destination);
|
||||
return super.onAttack(npc, attacker, damage, isSummon);
|
||||
}
|
||||
|
@@ -55,8 +55,8 @@ public class AdminGeodata implements IAdminCommandHandler
|
||||
final int worldX = activeChar.getX();
|
||||
final int worldY = activeChar.getY();
|
||||
final int worldZ = activeChar.getZ();
|
||||
final int geoX = GeoEngine.getInstance().getGeoX(worldX);
|
||||
final int geoY = GeoEngine.getInstance().getGeoY(worldY);
|
||||
final int geoX = GeoEngine.getGeoX(worldX);
|
||||
final int geoY = GeoEngine.getGeoY(worldY);
|
||||
|
||||
if (GeoEngine.getInstance().hasGeoPos(geoX, geoY))
|
||||
{
|
||||
@@ -73,8 +73,8 @@ public class AdminGeodata implements IAdminCommandHandler
|
||||
final int worldX = activeChar.getX();
|
||||
final int worldY = activeChar.getY();
|
||||
final int worldZ = activeChar.getZ();
|
||||
final int geoX = GeoEngine.getInstance().getGeoX(worldX);
|
||||
final int geoY = GeoEngine.getInstance().getGeoY(worldY);
|
||||
final int geoX = GeoEngine.getGeoX(worldX);
|
||||
final int geoY = GeoEngine.getGeoY(worldY);
|
||||
|
||||
if (GeoEngine.getInstance().hasGeoPos(geoX, geoY))
|
||||
{
|
||||
@@ -133,8 +133,8 @@ public class AdminGeodata implements IAdminCommandHandler
|
||||
}
|
||||
case "admin_geomap":
|
||||
{
|
||||
final int x = ((activeChar.getX() - World.MAP_MIN_X) >> 15) + World.TILE_X_MIN;
|
||||
final int y = ((activeChar.getY() - World.MAP_MIN_Y) >> 15) + World.TILE_Y_MIN;
|
||||
final int x = ((activeChar.getX() - World.WORLD_X_MIN) >> 15) + World.TILE_X_MIN;
|
||||
final int y = ((activeChar.getY() - World.WORLD_Y_MIN) >> 15) + World.TILE_Y_MIN;
|
||||
BuilderUtil.sendSysMessage(activeChar, "GeoMap: " + x + "_" + y + " (" + ((x - World.TILE_ZERO_COORD_X) * World.TILE_SIZE) + "," + ((y - World.TILE_ZERO_COORD_Y) * World.TILE_SIZE) + " to " + ((((x - World.TILE_ZERO_COORD_X) * World.TILE_SIZE) + World.TILE_SIZE) - 1) + "," + ((((y - World.TILE_ZERO_COORD_Y) * World.TILE_SIZE) + World.TILE_SIZE) - 1) + ")");
|
||||
break;
|
||||
}
|
||||
|
@@ -19,9 +19,9 @@ package handlers.admincommandhandlers;
|
||||
import java.util.List;
|
||||
|
||||
import org.l2jmobius.Config;
|
||||
import org.l2jmobius.gameserver.geoengine.GeoEnginePathfinding;
|
||||
import org.l2jmobius.gameserver.geoengine.pathfinding.AbstractNodeLoc;
|
||||
import org.l2jmobius.gameserver.geoengine.GeoEngine;
|
||||
import org.l2jmobius.gameserver.handler.IAdminCommandHandler;
|
||||
import org.l2jmobius.gameserver.model.Location;
|
||||
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
|
||||
import org.l2jmobius.gameserver.util.BuilderUtil;
|
||||
|
||||
@@ -44,13 +44,13 @@ public class AdminPathNode implements IAdminCommandHandler
|
||||
}
|
||||
if (activeChar.getTarget() != null)
|
||||
{
|
||||
final List<AbstractNodeLoc> path = GeoEnginePathfinding.getInstance().findPath(activeChar.getX(), activeChar.getY(), (short) activeChar.getZ(), activeChar.getTarget().getX(), activeChar.getTarget().getY(), (short) activeChar.getTarget().getZ(), activeChar.getInstanceId());
|
||||
final List<Location> path = GeoEngine.getInstance().findPath(activeChar.getX(), activeChar.getY(), (short) activeChar.getZ(), activeChar.getTarget().getX(), activeChar.getTarget().getY(), (short) activeChar.getTarget().getZ(), activeChar.getInstanceId());
|
||||
if (path == null)
|
||||
{
|
||||
BuilderUtil.sendSysMessage(activeChar, "No Route!");
|
||||
return true;
|
||||
}
|
||||
for (AbstractNodeLoc a : path)
|
||||
for (Location a : path)
|
||||
{
|
||||
BuilderUtil.sendSysMessage(activeChar, "x:" + a.getX() + " y:" + a.getY() + " z:" + a.getZ());
|
||||
}
|
||||
|
@@ -68,7 +68,7 @@ public class Blink extends AbstractEffect
|
||||
final int x = effected.getX() + x1;
|
||||
final int y = effected.getY() + y1;
|
||||
final int z = effected.getZ();
|
||||
final Location destination = GeoEngine.getInstance().canMoveToTargetLoc(effected.getX(), effected.getY(), effected.getZ(), x, y, z, effected.getInstanceId());
|
||||
final Location destination = GeoEngine.getInstance().getValidLocation(effected.getX(), effected.getY(), effected.getZ(), x, y, z, effected.getInstanceId());
|
||||
effected.getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
|
||||
effected.broadcastPacket(new FlyToLocation(effected, destination, FlyType.DUMMY));
|
||||
effected.abortAttack();
|
||||
|
@@ -90,7 +90,7 @@ public class EnemyCharge extends AbstractEffect
|
||||
final int x = curX + (int) ((distance - offset) * cos);
|
||||
final int y = curY + (int) ((distance - offset) * sin);
|
||||
final int z = info.getEffected().getZ();
|
||||
final Location destination = GeoEngine.getInstance().canMoveToTargetLoc(info.getEffector().getX(), info.getEffector().getY(), info.getEffector().getZ(), x, y, z, info.getEffector().getInstanceId());
|
||||
final Location destination = GeoEngine.getInstance().getValidLocation(info.getEffector().getX(), info.getEffector().getY(), info.getEffector().getZ(), x, y, z, info.getEffector().getInstanceId());
|
||||
info.getEffector().broadcastPacket(new FlyToLocation(info.getEffector(), destination, FlyType.CHARGE));
|
||||
|
||||
// maybe is need force set X,Y,Z
|
||||
|
@@ -236,7 +236,7 @@ public class Fishing extends AbstractEffect
|
||||
|
||||
// always use water zone, fishing zone high z is high in the air...
|
||||
final int baitZ = waterZone.getWaterZ();
|
||||
if (!GeoEngine.getInstance().canSeeTarget(player, new Location(baitX, baitY, baitZ)))
|
||||
if (!GeoEngine.getInstance().canSeeLocation(player, new Location(baitX, baitY, baitZ)))
|
||||
{
|
||||
return Integer.MIN_VALUE;
|
||||
}
|
||||
|
@@ -82,7 +82,7 @@ public class TeleportToTarget extends AbstractEffect
|
||||
final int x = (int) (px + (25 * Math.cos(ph)));
|
||||
final int y = (int) (py + (25 * Math.sin(ph)));
|
||||
final int z = target.getZ();
|
||||
final Location loc = GeoEngine.getInstance().canMoveToTargetLoc(creature.getX(), creature.getY(), creature.getZ(), x, y, z, creature.getInstanceId());
|
||||
final Location loc = GeoEngine.getInstance().getValidLocation(creature.getX(), creature.getY(), creature.getZ(), x, y, z, creature.getInstanceId());
|
||||
creature.getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
|
||||
creature.broadcastPacket(new FlyToLocation(creature, loc.getX(), loc.getY(), loc.getZ(), FlyType.DUMMY));
|
||||
creature.abortAttack();
|
||||
|
@@ -93,7 +93,7 @@ public class ThrowUp extends AbstractEffect
|
||||
final int x = info.getEffector().getX() - (int) (offset * cos);
|
||||
final int y = info.getEffector().getY() - (int) (offset * sin);
|
||||
final int z = info.getEffected().getZ();
|
||||
final Location destination = GeoEngine.getInstance().canMoveToTargetLoc(info.getEffected().getX(), info.getEffected().getY(), info.getEffected().getZ(), x, y, z, info.getEffected().getInstanceId());
|
||||
final Location destination = GeoEngine.getInstance().getValidLocation(info.getEffected().getX(), info.getEffected().getY(), info.getEffected().getZ(), x, y, z, info.getEffected().getInstanceId());
|
||||
info.getEffected().broadcastPacket(new FlyToLocation(info.getEffected(), destination, FlyType.THROW_UP));
|
||||
// TODO: Review.
|
||||
info.getEffected().setXYZ(destination);
|
||||
|
@@ -65,7 +65,7 @@ public class RollingDice implements IItemHandler
|
||||
final int x = player.getX() + x1;
|
||||
final int y = player.getY() + y1;
|
||||
final int z = player.getZ();
|
||||
final Location destination = GeoEngine.getInstance().canMoveToTargetLoc(player.getX(), player.getY(), player.getZ(), x, y, z, player.getInstanceId());
|
||||
final Location destination = GeoEngine.getInstance().getValidLocation(player.getX(), player.getY(), player.getZ(), x, y, z, player.getInstanceId());
|
||||
Broadcast.toSelfAndKnownPlayers(player, new Dice(player.getObjectId(), itemId, number, destination.getX(), destination.getY(), destination.getZ()));
|
||||
|
||||
final SystemMessage sm = new SystemMessage(SystemMessageId.C1_HAS_ROLLED_A_S2);
|
||||
|
@@ -677,7 +677,7 @@ public class CrystalCaverns extends AbstractInstance
|
||||
final int _x = effector.getX() - (int) (offset * cos);
|
||||
final int _y = effector.getY() - (int) (offset * sin);
|
||||
final int _z = effected.getZ();
|
||||
final Location destination = GeoEngine.getInstance().canMoveToTargetLoc(effected.getX(), effected.getY(), effected.getZ(), _x, _y, _z, effected.getInstanceId());
|
||||
final Location destination = GeoEngine.getInstance().getValidLocation(effected.getX(), effected.getY(), effected.getZ(), _x, _y, _z, effected.getInstanceId());
|
||||
effected.broadcastPacket(new FlyToLocation(effected, destination, FlyType.THROW_UP));
|
||||
|
||||
// maybe is need force set X,Y,Z
|
||||
|
@@ -59,6 +59,7 @@ import org.l2jmobius.commons.enums.ServerMode;
|
||||
import org.l2jmobius.commons.util.IXmlReader;
|
||||
import org.l2jmobius.commons.util.PropertiesParser;
|
||||
import org.l2jmobius.gameserver.enums.ChatType;
|
||||
import org.l2jmobius.gameserver.enums.GeoType;
|
||||
import org.l2jmobius.gameserver.enums.IllegalActionPunishmentType;
|
||||
import org.l2jmobius.gameserver.model.Location;
|
||||
import org.l2jmobius.gameserver.model.holders.ItemHolder;
|
||||
@@ -1060,12 +1061,17 @@ public class Config
|
||||
// GeoEngine
|
||||
// --------------------------------------------------
|
||||
public static Path GEODATA_PATH;
|
||||
public static GeoType GEODATA_TYPE;
|
||||
public static boolean PATHFINDING;
|
||||
public static String PATHFIND_BUFFERS;
|
||||
public static float LOW_WEIGHT;
|
||||
public static float MEDIUM_WEIGHT;
|
||||
public static float HIGH_WEIGHT;
|
||||
public static float DIAGONAL_WEIGHT;
|
||||
public static int MOVE_WEIGHT;
|
||||
public static int MOVE_WEIGHT_DIAG;
|
||||
public static int OBSTACLE_WEIGHT;
|
||||
public static int HEURISTIC_WEIGHT;
|
||||
public static int HEURISTIC_WEIGHT_DIAG;
|
||||
public static int MAX_ITERATIONS;
|
||||
public static int PART_OF_CHARACTER_HEIGHT;
|
||||
public static int MAX_OBSTACLE_HEIGHT;
|
||||
|
||||
// --------------------------------------------------
|
||||
// Custom Settings
|
||||
@@ -2594,12 +2600,17 @@ public class Config
|
||||
// Load GeoEngine config file (if exists)
|
||||
final PropertiesParser GeoEngine = new PropertiesParser(GEOENGINE_CONFIG_FILE);
|
||||
GEODATA_PATH = Paths.get(GeoEngine.getString("GeoDataPath", "./data/geodata"));
|
||||
GEODATA_TYPE = Enum.valueOf(GeoType.class, GeoEngine.getString("GeoDataType", "L2J"));
|
||||
PATHFINDING = GeoEngine.getBoolean("PathFinding", true);
|
||||
PATHFIND_BUFFERS = GeoEngine.getString("PathFindBuffers", "100x6;128x6;192x6;256x4;320x4;384x4;500x2");
|
||||
LOW_WEIGHT = GeoEngine.getFloat("LowWeight", 0.5f);
|
||||
MEDIUM_WEIGHT = GeoEngine.getFloat("MediumWeight", 2);
|
||||
HIGH_WEIGHT = GeoEngine.getFloat("HighWeight", 3);
|
||||
DIAGONAL_WEIGHT = GeoEngine.getFloat("DiagonalWeight", 0.707f);
|
||||
PATHFIND_BUFFERS = GeoEngine.getString("PathFindBuffers", "500x10;1000x10;3000x5;5000x3;10000x3");
|
||||
MOVE_WEIGHT = GeoEngine.getInt("MoveWeight", 10);
|
||||
MOVE_WEIGHT_DIAG = GeoEngine.getInt("MoveWeightDiag", 14);
|
||||
OBSTACLE_WEIGHT = GeoEngine.getInt("ObstacleWeight", 30);
|
||||
HEURISTIC_WEIGHT = GeoEngine.getInt("HeuristicWeight", 12);
|
||||
HEURISTIC_WEIGHT_DIAG = GeoEngine.getInt("HeuristicWeightDiag", 18);
|
||||
MAX_ITERATIONS = GeoEngine.getInt("MaxIterations", 3500);
|
||||
PART_OF_CHARACTER_HEIGHT = GeoEngine.getInt("PartOfCharacterHeight", 75);
|
||||
MAX_OBSTACLE_HEIGHT = GeoEngine.getInt("MaxObstacleHeight", 32);
|
||||
|
||||
// Load AllowedPlayerRaces config file (if exists)
|
||||
final PropertiesParser AllowedPlayerRaces = new PropertiesParser(CUSTOM_ALLOWED_PLAYER_RACES_CONFIG_FILE);
|
||||
|
@@ -266,4 +266,15 @@ public class CommonUtil
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param numToTest : The number to test.
|
||||
* @param min : The minimum limit.
|
||||
* @param max : The maximum limit.
|
||||
* @return the number or one of the limit (mininum / maximum).
|
||||
*/
|
||||
public static int limit(int numToTest, int min, int max)
|
||||
{
|
||||
return (numToTest > max) ? max : ((numToTest < min) ? min : numToTest);
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.l2jmobius.commons.util;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* A datatype used to retain a 2D (x/y) point. It got the capability to be set and cleaned.
|
||||
*/
|
||||
public class Point2D
|
||||
{
|
||||
protected volatile int _x;
|
||||
protected volatile int _y;
|
||||
|
||||
public Point2D(int x, int y)
|
||||
{
|
||||
_x = x;
|
||||
_y = y;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Point2D clone()
|
||||
{
|
||||
return new Point2D(_x, _y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return _x + ", " + _y;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return Objects.hash(_x, _y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if (this == obj)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (obj == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (getClass() != obj.getClass())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
final Point2D other = (Point2D) obj;
|
||||
return (_x == other._x) && (_y == other._y);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param x : The X coord to test.
|
||||
* @param y : The Y coord to test.
|
||||
* @return True if all coordinates equals this {@link Point2D} coordinates.
|
||||
*/
|
||||
public boolean equals(int x, int y)
|
||||
{
|
||||
return (_x == x) && (_y == y);
|
||||
}
|
||||
|
||||
public int getX()
|
||||
{
|
||||
return _x;
|
||||
}
|
||||
|
||||
public void setX(int x)
|
||||
{
|
||||
_x = x;
|
||||
}
|
||||
|
||||
public int getY()
|
||||
{
|
||||
return _y;
|
||||
}
|
||||
|
||||
public void setY(int y)
|
||||
{
|
||||
_y = y;
|
||||
}
|
||||
|
||||
public void set(int x, int y)
|
||||
{
|
||||
_x = x;
|
||||
_y = y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh the current {@link Point2D} using a reference {@link Point2D} and a distance. The new destination is calculated to go in opposite side of the {@link Point2D} reference.<br>
|
||||
* <br>
|
||||
* This method is perfect to calculate fleeing characters position.
|
||||
* @param referenceLoc : The Point2D used as position.
|
||||
* @param distance : The distance to be set between current and new position.
|
||||
*/
|
||||
public void setFleeing(Point2D referenceLoc, int distance)
|
||||
{
|
||||
final double xDiff = referenceLoc.getX() - _x;
|
||||
final double yDiff = referenceLoc.getY() - _y;
|
||||
|
||||
final double yxRation = Math.abs(xDiff / yDiff);
|
||||
|
||||
final int y = (int) (distance / (yxRation + 1));
|
||||
final int x = (int) (y * yxRation);
|
||||
|
||||
_x += (xDiff < 0 ? x : -x);
|
||||
_y += (yDiff < 0 ? y : -y);
|
||||
}
|
||||
|
||||
public void clean()
|
||||
{
|
||||
_x = 0;
|
||||
_y = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param x : The X position to test.
|
||||
* @param y : The Y position to test.
|
||||
* @return The distance between this {@Point2D} and some given coordinates.
|
||||
*/
|
||||
public double distance2D(int x, int y)
|
||||
{
|
||||
final double dx = (double) _x - x;
|
||||
final double dy = (double) _y - y;
|
||||
|
||||
return Math.sqrt((dx * dx) + (dy * dy));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param point : The {@link Point2D} to test.
|
||||
* @return The distance between this {@Point2D} and the {@link Point2D} set as parameter.
|
||||
*/
|
||||
public double distance2D(Point2D point)
|
||||
{
|
||||
return distance2D(point.getX(), point.getY());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param x : The X position to test.
|
||||
* @param y : The Y position to test.
|
||||
* @param radius : The radius to check.
|
||||
* @return True if this {@link Point2D} is in the radius of some given coordinates.
|
||||
*/
|
||||
public boolean isIn2DRadius(int x, int y, int radius)
|
||||
{
|
||||
return distance2D(x, y) < radius;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param point : The Point2D to test.
|
||||
* @param radius : The radius to check.
|
||||
* @return True if this {@link Point2D} is in the radius of the {@link Point2D} set as parameter.
|
||||
*/
|
||||
public boolean isIn2DRadius(Point2D point, int radius)
|
||||
{
|
||||
return distance2D(point) < radius;
|
||||
}
|
||||
}
|
@@ -710,7 +710,7 @@ public class AttackableAI extends CreatureAI
|
||||
}
|
||||
|
||||
// Move the actor to Location (x,y,z) server side AND client side by sending Server->Client packet CharMoveToLocation (broadcast)
|
||||
final Location moveLoc = _actor.isFlying() ? new Location(x1, y1, z1) : GeoEngine.getInstance().canMoveToTargetLoc(npc.getX(), npc.getY(), npc.getZ(), x1, y1, z1, npc.getInstanceId());
|
||||
final Location moveLoc = _actor.isFlying() ? new Location(x1, y1, z1) : GeoEngine.getInstance().getValidLocation(npc.getX(), npc.getY(), npc.getZ(), x1, y1, z1, npc.getInstanceId());
|
||||
moveTo(moveLoc.getX(), moveLoc.getY(), moveLoc.getZ());
|
||||
}
|
||||
}
|
||||
@@ -941,7 +941,7 @@ public class AttackableAI extends CreatureAI
|
||||
final int newZ = npc.getZ() + 30;
|
||||
|
||||
// Mobius: Verify destination. Prevents wall collision issues and fixes monsters not avoiding obstacles.
|
||||
moveTo(GeoEngine.getInstance().canMoveToTargetLoc(npc.getX(), npc.getY(), npc.getZ(), newX, newY, newZ, npc.getInstanceId()));
|
||||
moveTo(GeoEngine.getInstance().getValidLocation(npc.getX(), npc.getY(), npc.getZ(), newX, newY, newZ, npc.getInstanceId()));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@@ -925,7 +925,7 @@ public class CreatureAI extends AbstractAI
|
||||
}
|
||||
|
||||
// If pathfinding enabled the creature will go to the destination or it will go to the nearest obstacle.
|
||||
setIntention(AI_INTENTION_MOVE_TO, Config.PATHFINDING ? GeoEngine.getInstance().canMoveToTargetLoc(_actor.getX(), _actor.getY(), _actor.getZ(), posX, posY, posZ, _actor.getInstanceId()) : new Location(posX, posY, posZ));
|
||||
setIntention(AI_INTENTION_MOVE_TO, Config.PATHFINDING ? GeoEngine.getInstance().getValidLocation(_actor.getX(), _actor.getY(), _actor.getZ(), posX, posY, posZ, _actor.getInstanceId()) : new Location(posX, posY, posZ));
|
||||
}
|
||||
|
||||
protected boolean maybeMoveToPosition(ILocational worldPosition, int offset)
|
||||
|
@@ -26,7 +26,6 @@ import org.l2jmobius.Config;
|
||||
import org.l2jmobius.commons.concurrent.ThreadPool;
|
||||
import org.l2jmobius.commons.util.Rnd;
|
||||
import org.l2jmobius.gameserver.geoengine.GeoEngine;
|
||||
import org.l2jmobius.gameserver.geoengine.GeoEnginePathfinding;
|
||||
import org.l2jmobius.gameserver.model.WorldObject;
|
||||
import org.l2jmobius.gameserver.model.actor.Creature;
|
||||
import org.l2jmobius.gameserver.model.actor.Summon;
|
||||
@@ -51,7 +50,7 @@ public class SummonAI extends PlayableAI implements Runnable
|
||||
@Override
|
||||
protected void onIntentionAttack(Creature target)
|
||||
{
|
||||
if (Config.PATHFINDING && (GeoEnginePathfinding.getInstance().findPath(_actor.getX(), _actor.getY(), _actor.getZ(), target.getX(), target.getY(), target.getZ(), _actor.getInstanceId()) == null))
|
||||
if (Config.PATHFINDING && (GeoEngine.getInstance().findPath(_actor.getX(), _actor.getY(), _actor.getZ(), target.getX(), target.getY(), target.getZ(), _actor.getInstanceId()) == null))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@@ -400,8 +400,8 @@ public class SpawnTable implements IXmlReader
|
||||
}
|
||||
|
||||
// XML file for spawn
|
||||
final int x = ((spawn.getX() - World.MAP_MIN_X) >> 15) + World.TILE_X_MIN;
|
||||
final int y = ((spawn.getY() - World.MAP_MIN_Y) >> 15) + World.TILE_Y_MIN;
|
||||
final int x = ((spawn.getX() - World.WORLD_X_MIN) >> 15) + World.TILE_X_MIN;
|
||||
final int y = ((spawn.getY() - World.WORLD_Y_MIN) >> 15) + World.TILE_Y_MIN;
|
||||
final File spawnFile = new File(OTHER_XML_FOLDER + "/" + x + "_" + y + ".xml");
|
||||
|
||||
// Write info to XML
|
||||
@@ -476,8 +476,8 @@ public class SpawnTable implements IXmlReader
|
||||
|
||||
if (update)
|
||||
{
|
||||
final int x = ((spawn.getX() - World.MAP_MIN_X) >> 15) + World.TILE_X_MIN;
|
||||
final int y = ((spawn.getY() - World.MAP_MIN_Y) >> 15) + World.TILE_Y_MIN;
|
||||
final int x = ((spawn.getX() - World.WORLD_X_MIN) >> 15) + World.TILE_X_MIN;
|
||||
final int y = ((spawn.getY() - World.WORLD_Y_MIN) >> 15) + World.TILE_Y_MIN;
|
||||
final int npcSpawnTemplateId = spawn.getNpcSpawnTemplateId();
|
||||
final File spawnFile = npcSpawnTemplateId > 0 ? new File(_spawnTemplates.get(npcSpawnTemplateId)) : new File(OTHER_XML_FOLDER + "/" + x + "_" + y + ".xml");
|
||||
final File tempFile = new File(spawnFile.getAbsolutePath().substring(Config.DATAPACK_ROOT.getAbsolutePath().length() + 1).replace('\\', '/') + ".tmp");
|
||||
|
@@ -14,20 +14,22 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.l2jmobius.gameserver.geoengine.pathfinding;
|
||||
package org.l2jmobius.gameserver.enums;
|
||||
|
||||
/**
|
||||
* @author -Nemesiss-
|
||||
*/
|
||||
public abstract class AbstractNodeLoc
|
||||
public enum GeoType
|
||||
{
|
||||
public abstract int getX();
|
||||
L2J("%d_%d.l2j"),
|
||||
L2OFF("%d_%d_conv.dat");
|
||||
|
||||
public abstract int getY();
|
||||
private final String _filename;
|
||||
|
||||
public abstract int getZ();
|
||||
private GeoType(String filename)
|
||||
{
|
||||
_filename = filename;
|
||||
}
|
||||
|
||||
public abstract int getNodeX();
|
||||
|
||||
public abstract int getNodeY();
|
||||
}
|
||||
public String getFilename()
|
||||
{
|
||||
return _filename;
|
||||
}
|
||||
}
|
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.l2jmobius.gameserver.enums;
|
||||
|
||||
import org.l2jmobius.gameserver.geoengine.geodata.GeoStructure;
|
||||
|
||||
/**
|
||||
* Container of movement constants used for various geodata and movement checks.
|
||||
*/
|
||||
public enum MoveDirectionType
|
||||
{
|
||||
N(0, -1),
|
||||
S(0, 1),
|
||||
W(-1, 0),
|
||||
E(1, 0),
|
||||
NW(-1, -1),
|
||||
SW(-1, 1),
|
||||
NE(1, -1),
|
||||
SE(1, 1);
|
||||
|
||||
// Step and signum.
|
||||
private final int _stepX;
|
||||
private final int _stepY;
|
||||
private final int _signumX;
|
||||
private final int _signumY;
|
||||
|
||||
// Cell offset.
|
||||
private final int _offsetX;
|
||||
private final int _offsetY;
|
||||
|
||||
// Direction flags.
|
||||
private final byte _directionX;
|
||||
private final byte _directionY;
|
||||
private final String _symbolX;
|
||||
private final String _symbolY;
|
||||
|
||||
private MoveDirectionType(int signumX, int signumY)
|
||||
{
|
||||
// Get step (world -16, 0, 16) and signum (geodata -1, 0, 1) coordinates.
|
||||
_stepX = signumX * GeoStructure.CELL_SIZE;
|
||||
_stepY = signumY * GeoStructure.CELL_SIZE;
|
||||
_signumX = signumX;
|
||||
_signumY = signumY;
|
||||
|
||||
// Get border offsets in a direction of iteration.
|
||||
_offsetX = signumX >= 0 ? GeoStructure.CELL_SIZE - 1 : 0;
|
||||
_offsetY = signumY >= 0 ? GeoStructure.CELL_SIZE - 1 : 0;
|
||||
|
||||
// Get direction NSWE flag and symbol.
|
||||
_directionX = signumX < 0 ? GeoStructure.CELL_FLAG_W : signumX == 0 ? 0 : GeoStructure.CELL_FLAG_E;
|
||||
_directionY = signumY < 0 ? GeoStructure.CELL_FLAG_N : signumY == 0 ? 0 : GeoStructure.CELL_FLAG_S;
|
||||
_symbolX = signumX < 0 ? "W" : signumX == 0 ? "-" : "E";
|
||||
_symbolY = signumY < 0 ? "N" : signumY == 0 ? "-" : "S";
|
||||
}
|
||||
|
||||
public int getStepX()
|
||||
{
|
||||
return _stepX;
|
||||
}
|
||||
|
||||
public int getStepY()
|
||||
{
|
||||
return _stepY;
|
||||
}
|
||||
|
||||
public int getSignumX()
|
||||
{
|
||||
return _signumX;
|
||||
}
|
||||
|
||||
public int getSignumY()
|
||||
{
|
||||
return _signumY;
|
||||
}
|
||||
|
||||
public int getOffsetX()
|
||||
{
|
||||
return _offsetX;
|
||||
}
|
||||
|
||||
public int getOffsetY()
|
||||
{
|
||||
return _offsetY;
|
||||
}
|
||||
|
||||
public byte getDirectionX()
|
||||
{
|
||||
return _directionX;
|
||||
}
|
||||
|
||||
public byte getDirectionY()
|
||||
{
|
||||
return _directionY;
|
||||
}
|
||||
|
||||
public String getSymbolX()
|
||||
{
|
||||
return _symbolX;
|
||||
}
|
||||
|
||||
public String getSymbolY()
|
||||
{
|
||||
return _symbolY;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param gdx : Geodata X delta coordinate.
|
||||
* @param gdy : Geodata Y delta coordinate.
|
||||
* @return {@link MoveDirectionType} based on given geodata dx and dy delta coordinates.
|
||||
*/
|
||||
public static MoveDirectionType getDirection(int gdx, int gdy)
|
||||
{
|
||||
if (gdx == 0)
|
||||
{
|
||||
return (gdy < 0) ? MoveDirectionType.N : MoveDirectionType.S;
|
||||
}
|
||||
|
||||
if (gdy == 0)
|
||||
{
|
||||
return (gdx < 0) ? MoveDirectionType.W : MoveDirectionType.E;
|
||||
}
|
||||
|
||||
if (gdx > 0)
|
||||
{
|
||||
return (gdy < 0) ? MoveDirectionType.NE : MoveDirectionType.SE;
|
||||
}
|
||||
|
||||
return (gdy < 0) ? MoveDirectionType.NW : MoveDirectionType.SW;
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@@ -1,300 +0,0 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.l2jmobius.gameserver.geoengine;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.l2jmobius.Config;
|
||||
import org.l2jmobius.gameserver.geoengine.pathfinding.AbstractNode;
|
||||
import org.l2jmobius.gameserver.geoengine.pathfinding.AbstractNodeLoc;
|
||||
import org.l2jmobius.gameserver.geoengine.pathfinding.CellNode;
|
||||
import org.l2jmobius.gameserver.geoengine.pathfinding.CellNodeBuffer;
|
||||
import org.l2jmobius.gameserver.geoengine.pathfinding.NodeLoc;
|
||||
import org.l2jmobius.gameserver.model.World;
|
||||
|
||||
/**
|
||||
* @author -Nemesiss-
|
||||
*/
|
||||
public class GeoEnginePathfinding
|
||||
{
|
||||
private static final Logger LOGGER = Logger.getLogger(GeoEnginePathfinding.class.getName());
|
||||
|
||||
private BufferInfo[] _buffers;
|
||||
|
||||
protected GeoEnginePathfinding()
|
||||
{
|
||||
try
|
||||
{
|
||||
final String[] array = Config.PATHFIND_BUFFERS.split(";");
|
||||
|
||||
_buffers = new BufferInfo[array.length];
|
||||
|
||||
String buf;
|
||||
String[] args;
|
||||
for (int i = 0; i < array.length; i++)
|
||||
{
|
||||
buf = array[i];
|
||||
args = buf.split("x");
|
||||
if (args.length != 2)
|
||||
{
|
||||
throw new Exception("Invalid buffer definition: " + buf);
|
||||
}
|
||||
|
||||
_buffers[i] = new BufferInfo(Integer.parseInt(args[0]), Integer.parseInt(args[1]));
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOGGER.log(Level.WARNING, "CellPathFinding: Problem during buffer init: " + e.getMessage(), e);
|
||||
throw new Error("CellPathFinding: load aborted");
|
||||
}
|
||||
}
|
||||
|
||||
public boolean pathNodesExist(short regionoffset)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public List<AbstractNodeLoc> findPath(int x, int y, int z, int tx, int ty, int tz, int instanceId)
|
||||
{
|
||||
final int gx = GeoEngine.getInstance().getGeoX(x);
|
||||
final int gy = GeoEngine.getInstance().getGeoY(y);
|
||||
if (!GeoEngine.getInstance().hasGeo(x, y))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
final int gz = GeoEngine.getInstance().getHeight(x, y, z);
|
||||
final int gtx = GeoEngine.getInstance().getGeoX(tx);
|
||||
final int gty = GeoEngine.getInstance().getGeoY(ty);
|
||||
if (!GeoEngine.getInstance().hasGeo(tx, ty))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
final int gtz = GeoEngine.getInstance().getHeight(tx, ty, tz);
|
||||
final CellNodeBuffer buffer = alloc(64 + (2 * Math.max(Math.abs(gx - gtx), Math.abs(gy - gty))));
|
||||
if (buffer == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
List<AbstractNodeLoc> path = null;
|
||||
try
|
||||
{
|
||||
final CellNode result = buffer.findPath(gx, gy, gz, gtx, gty, gtz);
|
||||
|
||||
if (result == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
path = constructPath(result);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOGGER.warning(e.getMessage());
|
||||
return null;
|
||||
}
|
||||
finally
|
||||
{
|
||||
buffer.free();
|
||||
}
|
||||
|
||||
// check path
|
||||
if (path.size() < 3)
|
||||
{
|
||||
return path;
|
||||
}
|
||||
|
||||
int currentX, currentY, currentZ;
|
||||
ListIterator<AbstractNodeLoc> middlePoint;
|
||||
|
||||
middlePoint = path.listIterator();
|
||||
currentX = x;
|
||||
currentY = y;
|
||||
currentZ = z;
|
||||
|
||||
while (middlePoint.hasNext())
|
||||
{
|
||||
final AbstractNodeLoc locMiddle = middlePoint.next();
|
||||
if (!middlePoint.hasNext())
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
final AbstractNodeLoc locEnd = path.get(middlePoint.nextIndex());
|
||||
if (GeoEngine.getInstance().canMoveToTarget(currentX, currentY, currentZ, locEnd.getX(), locEnd.getY(), locEnd.getZ(), instanceId))
|
||||
{
|
||||
middlePoint.remove();
|
||||
}
|
||||
else
|
||||
{
|
||||
currentX = locMiddle.getX();
|
||||
currentY = locMiddle.getY();
|
||||
currentZ = locMiddle.getZ();
|
||||
}
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert geodata position to pathnode position
|
||||
* @param geo_pos
|
||||
* @return pathnode position
|
||||
*/
|
||||
public short getNodePos(int geo_pos)
|
||||
{
|
||||
return (short) (geo_pos >> 3); // OK?
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert node position to pathnode block position
|
||||
* @param node_pos
|
||||
* @return pathnode block position (0...255)
|
||||
*/
|
||||
public short getNodeBlock(int node_pos)
|
||||
{
|
||||
return (short) (node_pos % 256);
|
||||
}
|
||||
|
||||
public byte getRegionX(int node_pos)
|
||||
{
|
||||
return (byte) ((node_pos >> 8) + World.TILE_X_MIN);
|
||||
}
|
||||
|
||||
public byte getRegionY(int node_pos)
|
||||
{
|
||||
return (byte) ((node_pos >> 8) + World.TILE_Y_MIN);
|
||||
}
|
||||
|
||||
public short getRegionOffset(byte rx, byte ry)
|
||||
{
|
||||
return (short) ((rx << 5) + ry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert pathnode x to World x position
|
||||
* @param node_x rx
|
||||
* @return
|
||||
*/
|
||||
public int calculateWorldX(short node_x)
|
||||
{
|
||||
return World.MAP_MIN_X + (node_x * 128) + 48;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert pathnode y to World y position
|
||||
* @param node_y
|
||||
* @return
|
||||
*/
|
||||
public int calculateWorldY(short node_y)
|
||||
{
|
||||
return World.MAP_MIN_Y + (node_y * 128) + 48;
|
||||
}
|
||||
|
||||
private List<AbstractNodeLoc> constructPath(AbstractNode<NodeLoc> nodeValue)
|
||||
{
|
||||
final LinkedList<AbstractNodeLoc> path = new LinkedList<>();
|
||||
int previousDirectionX = Integer.MIN_VALUE;
|
||||
int previousDirectionY = Integer.MIN_VALUE;
|
||||
int directionX, directionY;
|
||||
|
||||
AbstractNode<NodeLoc> node = nodeValue;
|
||||
while (node.getParent() != null)
|
||||
{
|
||||
directionX = node.getLoc().getNodeX() - node.getParent().getLoc().getNodeX();
|
||||
directionY = node.getLoc().getNodeY() - node.getParent().getLoc().getNodeY();
|
||||
|
||||
// only add a new route point if moving direction changes
|
||||
if ((directionX != previousDirectionX) || (directionY != previousDirectionY))
|
||||
{
|
||||
previousDirectionX = directionX;
|
||||
previousDirectionY = directionY;
|
||||
|
||||
path.addFirst(node.getLoc());
|
||||
node.setLoc(null);
|
||||
}
|
||||
|
||||
node = node.getParent();
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
private CellNodeBuffer alloc(int size)
|
||||
{
|
||||
CellNodeBuffer current = null;
|
||||
for (BufferInfo i : _buffers)
|
||||
{
|
||||
if (i.mapSize >= size)
|
||||
{
|
||||
for (CellNodeBuffer buf : i.buffer)
|
||||
{
|
||||
if (buf.lock())
|
||||
{
|
||||
current = buf;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (current != null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// not found, allocate temporary buffer
|
||||
current = new CellNodeBuffer(i.mapSize);
|
||||
current.lock();
|
||||
if (i.buffer.size() < i.count)
|
||||
{
|
||||
i.buffer.add(current);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return current;
|
||||
}
|
||||
|
||||
private static final class BufferInfo
|
||||
{
|
||||
final int mapSize;
|
||||
final int count;
|
||||
ArrayList<CellNodeBuffer> buffer;
|
||||
|
||||
public BufferInfo(int size, int cnt)
|
||||
{
|
||||
mapSize = size;
|
||||
count = cnt;
|
||||
buffer = new ArrayList<>(count);
|
||||
}
|
||||
}
|
||||
|
||||
public static GeoEnginePathfinding getInstance()
|
||||
{
|
||||
return SingletonHolder.INSTANCE;
|
||||
}
|
||||
|
||||
private static class SingletonHolder
|
||||
{
|
||||
protected static final GeoEnginePathfinding INSTANCE = new GeoEnginePathfinding();
|
||||
}
|
||||
}
|
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.l2jmobius.gameserver.geoengine.geodata;
|
||||
|
||||
public abstract class ABlock
|
||||
{
|
||||
/**
|
||||
* Checks the block for having geodata.
|
||||
* @return boolean : True, when block has geodata (Flat, Complex, Multilayer).
|
||||
*/
|
||||
public abstract boolean hasGeoPos();
|
||||
|
||||
/**
|
||||
* Returns the height of cell, which is closest to given coordinates.<br>
|
||||
* @param geoX : Cell geodata X coordinate.
|
||||
* @param geoY : Cell geodata Y coordinate.
|
||||
* @param worldZ : Cell world Z coordinate.
|
||||
* @return short : Cell geodata Z coordinate, nearest to given coordinates.
|
||||
*/
|
||||
public abstract short getHeightNearest(int geoX, int geoY, int worldZ);
|
||||
|
||||
/**
|
||||
* Returns the NSWE flag byte of cell, which is closest to given coordinates.<br>
|
||||
* @param geoX : Cell geodata X coordinate.
|
||||
* @param geoY : Cell geodata Y coordinate.
|
||||
* @param worldZ : Cell world Z coordinate.
|
||||
* @return short : Cell NSWE flag byte, nearest to given coordinates.
|
||||
*/
|
||||
public abstract byte getNsweNearest(int geoX, int geoY, int worldZ);
|
||||
|
||||
/**
|
||||
* Returns index to data of the cell, which is closes layer to given coordinates.<br>
|
||||
* @param geoX : Cell geodata X coordinate.
|
||||
* @param geoY : Cell geodata Y coordinate.
|
||||
* @param worldZ : Cell world Z coordinate.
|
||||
* @return {@code int} : Cell index.
|
||||
*/
|
||||
public abstract int getIndexNearest(int geoX, int geoY, int worldZ);
|
||||
|
||||
/**
|
||||
* Returns index to data of the cell, which is first layer above given coordinates.<br>
|
||||
* @param geoX : Cell geodata X coordinate.
|
||||
* @param geoY : Cell geodata Y coordinate.
|
||||
* @param worldZ : Cell world Z coordinate.
|
||||
* @return {@code int} : Cell index. -1..when no layer available below given Z coordinate.
|
||||
*/
|
||||
public abstract int getIndexAbove(int geoX, int geoY, int worldZ);
|
||||
|
||||
/**
|
||||
* Returns index to data of the cell, which is first layer below given coordinates.<br>
|
||||
* @param geoX : Cell geodata X coordinate.
|
||||
* @param geoY : Cell geodata Y coordinate.
|
||||
* @param worldZ : Cell world Z coordinate.
|
||||
* @return {@code int} : Cell index. -1..when no layer available below given Z coordinate.
|
||||
*/
|
||||
public abstract int getIndexBelow(int geoX, int geoY, int worldZ);
|
||||
|
||||
/**
|
||||
* Returns the height of cell given by cell index.<br>
|
||||
* @param index : Index of the cell.
|
||||
* @return short : Cell geodata Z coordinate, below given coordinates.
|
||||
*/
|
||||
public abstract short getHeight(int index);
|
||||
|
||||
/**
|
||||
* Returns the NSWE flag byte of cell given by cell index.<br>
|
||||
* @param index : Index of the cell.
|
||||
* @return short : Cell geodata Z coordinate, below given coordinates.
|
||||
*/
|
||||
public abstract byte getNswe(int index);
|
||||
}
|
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.l2jmobius.gameserver.geoengine.geodata;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
public class BlockComplex extends ABlock
|
||||
{
|
||||
protected byte[] _buffer;
|
||||
|
||||
/**
|
||||
* Implicit constructor for children class.
|
||||
*/
|
||||
protected BlockComplex()
|
||||
{
|
||||
// Buffer is initialized in children class.
|
||||
_buffer = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates ComplexBlock.
|
||||
* @param bb : Input byte buffer.
|
||||
*/
|
||||
public BlockComplex(ByteBuffer bb)
|
||||
{
|
||||
// Initialize buffer.
|
||||
_buffer = new byte[GeoStructure.BLOCK_CELLS * 3];
|
||||
|
||||
// Load data.
|
||||
for (int i = 0; i < GeoStructure.BLOCK_CELLS; i++)
|
||||
{
|
||||
// Get data.
|
||||
short data = bb.getShort();
|
||||
|
||||
// Get nswe.
|
||||
_buffer[i * 3] = (byte) (data & 0x000F);
|
||||
|
||||
// Get height.
|
||||
data = (short) ((short) (data & 0xFFF0) >> 1);
|
||||
_buffer[(i * 3) + 1] = (byte) (data & 0x00FF);
|
||||
_buffer[(i * 3) + 2] = (byte) (data >> 8);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasGeoPos()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getHeightNearest(int geoX, int geoY, int worldZ)
|
||||
{
|
||||
// Get cell index.
|
||||
final int index = (((geoX % GeoStructure.BLOCK_CELLS_X) * GeoStructure.BLOCK_CELLS_Y) + (geoY % GeoStructure.BLOCK_CELLS_Y)) * 3;
|
||||
|
||||
// Get height.
|
||||
return (short) ((_buffer[index + 1] & 0x00FF) | (_buffer[index + 2] << 8));
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getNsweNearest(int geoX, int geoY, int worldZ)
|
||||
{
|
||||
// Get cell index.
|
||||
final int index = (((geoX % GeoStructure.BLOCK_CELLS_X) * GeoStructure.BLOCK_CELLS_Y) + (geoY % GeoStructure.BLOCK_CELLS_Y)) * 3;
|
||||
|
||||
// Get nswe.
|
||||
return _buffer[index];
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int getIndexNearest(int geoX, int geoY, int worldZ)
|
||||
{
|
||||
return (((geoX % GeoStructure.BLOCK_CELLS_X) * GeoStructure.BLOCK_CELLS_Y) + (geoY % GeoStructure.BLOCK_CELLS_Y)) * 3;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIndexAbove(int geoX, int geoY, int worldZ)
|
||||
{
|
||||
// Get cell index.
|
||||
final int index = (((geoX % GeoStructure.BLOCK_CELLS_X) * GeoStructure.BLOCK_CELLS_Y) + (geoY % GeoStructure.BLOCK_CELLS_Y)) * 3;
|
||||
|
||||
// Get height.
|
||||
final int height = (_buffer[index + 1] & 0x00FF) | (_buffer[index + 2] << 8);
|
||||
|
||||
// Check height and return nswe.
|
||||
return height > worldZ ? index : -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIndexBelow(int geoX, int geoY, int worldZ)
|
||||
{
|
||||
// Get cell index.
|
||||
final int index = (((geoX % GeoStructure.BLOCK_CELLS_X) * GeoStructure.BLOCK_CELLS_Y) + (geoY % GeoStructure.BLOCK_CELLS_Y)) * 3;
|
||||
|
||||
// Get height.
|
||||
final int height = (_buffer[index + 1] & 0x00FF) | (_buffer[index + 2] << 8);
|
||||
|
||||
// Check height and return nswe.
|
||||
return height < worldZ ? index : -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getHeight(int index)
|
||||
{
|
||||
// Get height.
|
||||
return (short) ((_buffer[index + 1] & 0x00FF) | (_buffer[index + 2] << 8));
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getNswe(int index)
|
||||
{
|
||||
// Get nswe.
|
||||
return _buffer[index];
|
||||
}
|
||||
}
|
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.l2jmobius.gameserver.geoengine.geodata;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.l2jmobius.gameserver.enums.GeoType;
|
||||
|
||||
public class BlockFlat extends ABlock
|
||||
{
|
||||
protected final short _height;
|
||||
protected byte _nswe;
|
||||
|
||||
/**
|
||||
* Creates FlatBlock.
|
||||
* @param bb : Input byte buffer.
|
||||
* @param type : The type of loaded geodata.
|
||||
*/
|
||||
public BlockFlat(ByteBuffer bb, GeoType type)
|
||||
{
|
||||
// Get height and nswe.
|
||||
_height = bb.getShort();
|
||||
_nswe = GeoStructure.CELL_FLAG_ALL;
|
||||
|
||||
// Read dummy data.
|
||||
if (type == GeoType.L2OFF)
|
||||
{
|
||||
bb.getShort();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasGeoPos()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getHeightNearest(int geoX, int geoY, int worldZ)
|
||||
{
|
||||
return _height;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getNsweNearest(int geoX, int geoY, int worldZ)
|
||||
{
|
||||
return _nswe;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIndexNearest(int geoX, int geoY, int worldZ)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIndexAbove(int geoX, int geoY, int worldZ)
|
||||
{
|
||||
// Check height and return index.
|
||||
return _height > worldZ ? 0 : -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIndexBelow(int geoX, int geoY, int worldZ)
|
||||
{
|
||||
// Check height and return index.
|
||||
return _height < worldZ ? 0 : -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getHeight(int index)
|
||||
{
|
||||
return _height;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getNswe(int index)
|
||||
{
|
||||
return _nswe;
|
||||
}
|
||||
}
|
@@ -0,0 +1,248 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.l2jmobius.gameserver.geoengine.geodata;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.l2jmobius.gameserver.enums.GeoType;
|
||||
|
||||
public class BlockMultilayer extends ABlock
|
||||
{
|
||||
private static final int MAX_LAYERS = Byte.MAX_VALUE;
|
||||
|
||||
private static ByteBuffer _temp;
|
||||
|
||||
/**
|
||||
* Initializes the temporary buffer.
|
||||
*/
|
||||
public static final void initialize()
|
||||
{
|
||||
// Initialize temporary buffer and sorting mechanism.
|
||||
_temp = ByteBuffer.allocate(GeoStructure.BLOCK_CELLS * MAX_LAYERS * 3);
|
||||
_temp.order(ByteOrder.LITTLE_ENDIAN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases temporary buffer.
|
||||
*/
|
||||
public static final void release()
|
||||
{
|
||||
_temp = null;
|
||||
}
|
||||
|
||||
protected byte[] _buffer;
|
||||
|
||||
/**
|
||||
* Implicit constructor for children class.
|
||||
*/
|
||||
protected BlockMultilayer()
|
||||
{
|
||||
// Buffer is initialized in children class.
|
||||
_buffer = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates MultilayerBlock.
|
||||
* @param bb : Input byte buffer.
|
||||
* @param type : The type of loaded geodata.
|
||||
*/
|
||||
public BlockMultilayer(ByteBuffer bb, GeoType type)
|
||||
{
|
||||
// Move buffer pointer to end of MultilayerBlock.
|
||||
for (int cell = 0; cell < GeoStructure.BLOCK_CELLS; cell++)
|
||||
{
|
||||
// Get layer count for this cell.
|
||||
final byte layers = type != GeoType.L2OFF ? bb.get() : (byte) bb.getShort();
|
||||
|
||||
if ((layers <= 0) || (layers > MAX_LAYERS))
|
||||
{
|
||||
throw new RuntimeException("Invalid layer count for MultilayerBlock");
|
||||
}
|
||||
|
||||
// Add layers count.
|
||||
_temp.put(layers);
|
||||
|
||||
// Loop over layers.
|
||||
for (byte layer = 0; layer < layers; layer++)
|
||||
{
|
||||
// Get data.
|
||||
final short data = bb.getShort();
|
||||
|
||||
// Add nswe and height.
|
||||
_temp.put((byte) (data & 0x000F));
|
||||
_temp.putShort((short) ((short) (data & 0xFFF0) >> 1));
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize buffer.
|
||||
_buffer = Arrays.copyOf(_temp.array(), _temp.position());
|
||||
|
||||
// Clear temp buffer.
|
||||
_temp.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasGeoPos()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getHeightNearest(int geoX, int geoY, int worldZ)
|
||||
{
|
||||
// Get cell index.
|
||||
final int index = getIndexNearest(geoX, geoY, worldZ);
|
||||
|
||||
// Get height.
|
||||
return (short) ((_buffer[index + 1] & 0x00FF) | (_buffer[index + 2] << 8));
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getNsweNearest(int geoX, int geoY, int worldZ)
|
||||
{
|
||||
// Get cell index.
|
||||
final int index = getIndexNearest(geoX, geoY, worldZ);
|
||||
|
||||
// Get nswe.
|
||||
return _buffer[index];
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIndexNearest(int geoX, int geoY, int worldZ)
|
||||
{
|
||||
// Move index to the cell given by coordinates.
|
||||
int index = 0;
|
||||
for (int i = 0; i < (((geoX % GeoStructure.BLOCK_CELLS_X) * GeoStructure.BLOCK_CELLS_Y) + (geoY % GeoStructure.BLOCK_CELLS_Y)); i++)
|
||||
{
|
||||
// Move index by amount of layers for this cell.
|
||||
index += (_buffer[index] * 3) + 1;
|
||||
}
|
||||
|
||||
// Get layers count and shift to last layer data (first from bottom).
|
||||
byte layers = _buffer[index++];
|
||||
|
||||
// Loop though all cell layers, find closest layer to given worldZ.
|
||||
int limit = Integer.MAX_VALUE;
|
||||
while (layers-- > 0)
|
||||
{
|
||||
// Get layer height.
|
||||
final int height = (_buffer[index + 1] & 0x00FF) | (_buffer[index + 2] << 8);
|
||||
|
||||
// Get Z distance and compare with limit.
|
||||
// Note: When 2 layers have same distance to worldZ (worldZ is in the middle of them):
|
||||
// > Returns bottom layer.
|
||||
// >= Returns upper layer.
|
||||
final int distance = Math.abs(height - worldZ);
|
||||
if (distance > limit)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// Update limit and move to next layer.
|
||||
limit = distance;
|
||||
index += 3;
|
||||
}
|
||||
|
||||
// Return layer index.
|
||||
return index - 3;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIndexAbove(int geoX, int geoY, int worldZ)
|
||||
{
|
||||
// Move index to the cell given by coordinates.
|
||||
int index = 0;
|
||||
for (int i = 0; i < (((geoX % GeoStructure.BLOCK_CELLS_X) * GeoStructure.BLOCK_CELLS_Y) + (geoY % GeoStructure.BLOCK_CELLS_Y)); i++)
|
||||
{
|
||||
// Move index by amount of layers for this cell.
|
||||
index += (_buffer[index] * 3) + 1;
|
||||
}
|
||||
|
||||
// Get layers count and shift to last layer data (first from bottom).
|
||||
byte layers = _buffer[index++];
|
||||
index += (layers - 1) * 3;
|
||||
|
||||
// Loop though all layers, find first layer above worldZ.
|
||||
while (layers-- > 0)
|
||||
{
|
||||
// Get layer height.
|
||||
final int height = (_buffer[index + 1] & 0x00FF) | (_buffer[index + 2] << 8);
|
||||
|
||||
// Layer height is higher than worldZ, return layer index.
|
||||
if (height > worldZ)
|
||||
{
|
||||
return index;
|
||||
}
|
||||
|
||||
// Move index to next layer.
|
||||
index -= 3;
|
||||
}
|
||||
|
||||
// No layer found.
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIndexBelow(int geoX, int geoY, int worldZ)
|
||||
{
|
||||
// Move index to the cell given by coordinates.
|
||||
int index = 0;
|
||||
for (int i = 0; i < (((geoX % GeoStructure.BLOCK_CELLS_X) * GeoStructure.BLOCK_CELLS_Y) + (geoY % GeoStructure.BLOCK_CELLS_Y)); i++)
|
||||
{
|
||||
// Move index by amount of layers for this cell.
|
||||
index += (_buffer[index] * 3) + 1;
|
||||
}
|
||||
|
||||
// Get layers count and shift to first layer data (first from top).
|
||||
byte layers = _buffer[index++];
|
||||
|
||||
// Loop though all layers, find first layer below worldZ.
|
||||
while (layers-- > 0)
|
||||
{
|
||||
// Get layer height.
|
||||
final int height = (_buffer[index + 1] & 0x00FF) | (_buffer[index + 2] << 8);
|
||||
|
||||
// Layer height is lower than worldZ, return layer index.
|
||||
if (height < worldZ)
|
||||
{
|
||||
return index;
|
||||
}
|
||||
|
||||
// Move index to next layer.
|
||||
index += 3;
|
||||
}
|
||||
|
||||
// No layer found.
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getHeight(int index)
|
||||
{
|
||||
// Get height.
|
||||
return (short) ((_buffer[index + 1] & 0x00FF) | (_buffer[index + 2] << 8));
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getNswe(int index)
|
||||
{
|
||||
// Get nswe.
|
||||
return _buffer[index];
|
||||
}
|
||||
}
|
@@ -16,40 +16,53 @@
|
||||
*/
|
||||
package org.l2jmobius.gameserver.geoengine.geodata;
|
||||
|
||||
/**
|
||||
* @author HorridoJoho
|
||||
*/
|
||||
public final class NullRegion implements IRegion
|
||||
public class BlockNull extends ABlock
|
||||
{
|
||||
public static final NullRegion INSTANCE = new NullRegion();
|
||||
|
||||
@Override
|
||||
public boolean checkNearestNswe(int geoX, int geoY, int worldZ, int nswe)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNearestZ(int geoX, int geoY, int worldZ)
|
||||
{
|
||||
return worldZ;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNextLowerZ(int geoX, int geoY, int worldZ)
|
||||
{
|
||||
return worldZ;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNextHigherZ(int geoX, int geoY, int worldZ)
|
||||
{
|
||||
return worldZ;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasGeo()
|
||||
public boolean hasGeoPos()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getHeightNearest(int geoX, int geoY, int worldZ)
|
||||
{
|
||||
return (short) worldZ;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getNsweNearest(int geoX, int geoY, int worldZ)
|
||||
{
|
||||
return GeoStructure.CELL_FLAG_ALL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIndexNearest(int geoX, int geoY, int worldZ)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIndexAbove(int geoX, int geoY, int worldZ)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIndexBelow(int geoX, int geoY, int worldZ)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getHeight(int index)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getNswe(int index)
|
||||
{
|
||||
return GeoStructure.CELL_FLAG_ALL;
|
||||
}
|
||||
}
|
@@ -1,48 +0,0 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.l2jmobius.gameserver.geoengine.geodata;
|
||||
|
||||
/**
|
||||
* @author HorridoJoho
|
||||
*/
|
||||
public final class Cell
|
||||
{
|
||||
/** East NSWE flag */
|
||||
public static final byte NSWE_EAST = 1 << 0;
|
||||
/** West NSWE flag */
|
||||
public static final byte NSWE_WEST = 1 << 1;
|
||||
/** South NSWE flag */
|
||||
public static final byte NSWE_SOUTH = 1 << 2;
|
||||
/** North NSWE flag */
|
||||
public static final byte NSWE_NORTH = 1 << 3;
|
||||
|
||||
/** North-East NSWE flags */
|
||||
public static final byte NSWE_NORTH_EAST = NSWE_NORTH | NSWE_EAST;
|
||||
/** North-West NSWE flags */
|
||||
public static final byte NSWE_NORTH_WEST = NSWE_NORTH | NSWE_WEST;
|
||||
/** South-East NSWE flags */
|
||||
public static final byte NSWE_SOUTH_EAST = NSWE_SOUTH | NSWE_EAST;
|
||||
/** South-West NSWE flags */
|
||||
public static final byte NSWE_SOUTH_WEST = NSWE_SOUTH | NSWE_WEST;
|
||||
|
||||
/** All directions NSWE flags */
|
||||
public static final byte NSWE_ALL = NSWE_EAST | NSWE_WEST | NSWE_SOUTH | NSWE_NORTH;
|
||||
|
||||
private Cell()
|
||||
{
|
||||
}
|
||||
}
|
@@ -1,77 +0,0 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.l2jmobius.gameserver.geoengine.geodata;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* @author HorridoJoho
|
||||
*/
|
||||
public final class ComplexBlock implements IBlock
|
||||
{
|
||||
private final short[] _data;
|
||||
|
||||
public ComplexBlock(ByteBuffer bb)
|
||||
{
|
||||
_data = new short[IBlock.BLOCK_CELLS];
|
||||
for (int cellOffset = 0; cellOffset < IBlock.BLOCK_CELLS; cellOffset++)
|
||||
{
|
||||
_data[cellOffset] = bb.getShort();
|
||||
}
|
||||
}
|
||||
|
||||
private short _getCellData(int geoX, int geoY)
|
||||
{
|
||||
return _data[((geoX % IBlock.BLOCK_CELLS_X) * IBlock.BLOCK_CELLS_Y) + (geoY % IBlock.BLOCK_CELLS_Y)];
|
||||
}
|
||||
|
||||
private byte _getCellNSWE(int geoX, int geoY)
|
||||
{
|
||||
return (byte) (_getCellData(geoX, geoY) & 0x000F);
|
||||
}
|
||||
|
||||
private int _getCellHeight(int geoX, int geoY)
|
||||
{
|
||||
return (short) (_getCellData(geoX, geoY) & 0x0FFF0) >> 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkNearestNswe(int geoX, int geoY, int worldZ, int nswe)
|
||||
{
|
||||
return (_getCellNSWE(geoX, geoY) & nswe) == nswe;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNearestZ(int geoX, int geoY, int worldZ)
|
||||
{
|
||||
return _getCellHeight(geoX, geoY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNextLowerZ(int geoX, int geoY, int worldZ)
|
||||
{
|
||||
final int cellHeight = _getCellHeight(geoX, geoY);
|
||||
return cellHeight <= worldZ ? cellHeight : worldZ;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNextHigherZ(int geoX, int geoY, int worldZ)
|
||||
{
|
||||
final int cellHeight = _getCellHeight(geoX, geoY);
|
||||
return cellHeight >= worldZ ? cellHeight : worldZ;
|
||||
}
|
||||
}
|
@@ -1,56 +0,0 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.l2jmobius.gameserver.geoengine.geodata;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* @author HorridoJoho
|
||||
*/
|
||||
public class FlatBlock implements IBlock
|
||||
{
|
||||
private final short _height;
|
||||
|
||||
public FlatBlock(ByteBuffer bb)
|
||||
{
|
||||
_height = bb.getShort();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkNearestNswe(int geoX, int geoY, int worldZ, int nswe)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNearestZ(int geoX, int geoY, int worldZ)
|
||||
{
|
||||
return _height;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNextLowerZ(int geoX, int geoY, int worldZ)
|
||||
{
|
||||
return _height <= worldZ ? _height : worldZ;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNextHigherZ(int geoX, int geoY, int worldZ)
|
||||
{
|
||||
return _height >= worldZ ? _height : worldZ;
|
||||
}
|
||||
}
|
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.l2jmobius.gameserver.geoengine.geodata;
|
||||
|
||||
import org.l2jmobius.gameserver.model.World;
|
||||
|
||||
public final class GeoStructure
|
||||
{
|
||||
// Geo cell direction (nswe) flags.
|
||||
public static final byte CELL_FLAG_NONE = 0x00;
|
||||
public static final byte CELL_FLAG_E = 0x01;
|
||||
public static final byte CELL_FLAG_W = 0x02;
|
||||
public static final byte CELL_FLAG_S = 0x04;
|
||||
public static final byte CELL_FLAG_N = 0x08;
|
||||
public static final byte CELL_FLAG_ALL = 0x0F;
|
||||
|
||||
// Geo cell height constants.
|
||||
public static final int CELL_SIZE = 16;
|
||||
public static final int CELL_HEIGHT = 8;
|
||||
public static final int CELL_IGNORE_HEIGHT = CELL_HEIGHT * 6;
|
||||
|
||||
// Geo block type identification.
|
||||
public static final byte TYPE_FLAT_L2J_L2OFF = 0;
|
||||
public static final byte TYPE_COMPLEX_L2J = 1;
|
||||
public static final byte TYPE_COMPLEX_L2OFF = 0x40;
|
||||
public static final byte TYPE_MULTILAYER_L2J = 2;
|
||||
// public static final byte TYPE_MULTILAYER_L2OFF = 0x41; // officially not does exist, is anything above complex block (0x41 - 0xFFFF)
|
||||
|
||||
// Geo block dimensions.
|
||||
public static final int BLOCK_CELLS_X = 8;
|
||||
public static final int BLOCK_CELLS_Y = 8;
|
||||
public static final int BLOCK_CELLS = BLOCK_CELLS_X * BLOCK_CELLS_Y;
|
||||
|
||||
// Geo region dimensions.
|
||||
public static final int REGION_BLOCKS_X = 256;
|
||||
public static final int REGION_BLOCKS_Y = 256;
|
||||
public static final int REGION_BLOCKS = REGION_BLOCKS_X * REGION_BLOCKS_Y;
|
||||
|
||||
public static final int REGION_CELLS_X = REGION_BLOCKS_X * BLOCK_CELLS_X;
|
||||
public static final int REGION_CELLS_Y = REGION_BLOCKS_Y * BLOCK_CELLS_Y;
|
||||
|
||||
// Geo world dimensions.
|
||||
public static final int GEO_REGIONS_X = ((World.TILE_X_MAX - World.TILE_X_MIN) + 1);
|
||||
public static final int GEO_REGIONS_Y = ((World.TILE_Y_MAX - World.TILE_Y_MIN) + 1);
|
||||
|
||||
public static final int GEO_BLOCKS_X = GEO_REGIONS_X * REGION_BLOCKS_X;
|
||||
public static final int GEO_BLOCKS_Y = GEO_REGIONS_Y * REGION_BLOCKS_Y;
|
||||
|
||||
public static final int GEO_CELLS_X = GEO_BLOCKS_X * BLOCK_CELLS_X;
|
||||
public static final int GEO_CELLS_Y = GEO_BLOCKS_Y * BLOCK_CELLS_Y;
|
||||
}
|
@@ -1,42 +0,0 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.l2jmobius.gameserver.geoengine.geodata;
|
||||
|
||||
/**
|
||||
* @author HorridoJoho
|
||||
*/
|
||||
public interface IBlock
|
||||
{
|
||||
int TYPE_FLAT = 0;
|
||||
int TYPE_COMPLEX = 1;
|
||||
int TYPE_MULTILAYER = 2;
|
||||
|
||||
/** Cells in a block on the x axis */
|
||||
int BLOCK_CELLS_X = 8;
|
||||
/** Cells in a block on the y axis */
|
||||
int BLOCK_CELLS_Y = 8;
|
||||
/** Cells in a block */
|
||||
int BLOCK_CELLS = BLOCK_CELLS_X * BLOCK_CELLS_Y;
|
||||
|
||||
boolean checkNearestNswe(int geoX, int geoY, int worldZ, int nswe);
|
||||
|
||||
int getNearestZ(int geoX, int geoY, int worldZ);
|
||||
|
||||
int getNextLowerZ(int geoX, int geoY, int worldZ);
|
||||
|
||||
int getNextHigherZ(int geoX, int geoY, int worldZ);
|
||||
}
|
@@ -1,47 +0,0 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.l2jmobius.gameserver.geoengine.geodata;
|
||||
|
||||
/**
|
||||
* @author HorridoJoho
|
||||
*/
|
||||
public interface IRegion
|
||||
{
|
||||
/** Blocks in a region on the x axis. */
|
||||
int REGION_BLOCKS_X = 256;
|
||||
/** Blocks in a region on the y axis. */
|
||||
int REGION_BLOCKS_Y = 256;
|
||||
/** Blocks in a region. */
|
||||
int REGION_BLOCKS = REGION_BLOCKS_X * REGION_BLOCKS_Y;
|
||||
|
||||
/** Cells in a region on the x axis. */
|
||||
int REGION_CELLS_X = REGION_BLOCKS_X * IBlock.BLOCK_CELLS_X;
|
||||
/** Cells in a regioin on the y axis. */
|
||||
int REGION_CELLS_Y = REGION_BLOCKS_Y * IBlock.BLOCK_CELLS_Y;
|
||||
/** Cells in a region. */
|
||||
int REGION_CELLS = REGION_CELLS_X * REGION_CELLS_Y;
|
||||
|
||||
boolean checkNearestNswe(int geoX, int geoY, int worldZ, int nswe);
|
||||
|
||||
int getNearestZ(int geoX, int geoY, int worldZ);
|
||||
|
||||
int getNextLowerZ(int geoX, int geoY, int worldZ);
|
||||
|
||||
int getNextHigherZ(int geoX, int geoY, int worldZ);
|
||||
|
||||
boolean hasGeo();
|
||||
}
|
@@ -1,183 +0,0 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.l2jmobius.gameserver.geoengine.geodata;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* @author HorridoJoho
|
||||
*/
|
||||
public class MultilayerBlock implements IBlock
|
||||
{
|
||||
private final byte[] _data;
|
||||
|
||||
/**
|
||||
* Initializes a new instance of this block reading the specified buffer.
|
||||
* @param bb the buffer
|
||||
*/
|
||||
public MultilayerBlock(ByteBuffer bb)
|
||||
{
|
||||
final int start = bb.position();
|
||||
|
||||
for (int blockCellOffset = 0; blockCellOffset < IBlock.BLOCK_CELLS; blockCellOffset++)
|
||||
{
|
||||
final byte nLayers = bb.get();
|
||||
if ((nLayers <= 0) || (nLayers > 125))
|
||||
{
|
||||
throw new RuntimeException("L2JGeoDriver: Geo file corrupted! Invalid layers count!");
|
||||
}
|
||||
|
||||
bb.position(bb.position() + (nLayers * 2));
|
||||
}
|
||||
|
||||
_data = new byte[bb.position() - start];
|
||||
bb.position(start);
|
||||
bb.get(_data);
|
||||
}
|
||||
|
||||
private short _getNearestLayer(int geoX, int geoY, int worldZ)
|
||||
{
|
||||
final int startOffset = _getCellDataOffset(geoX, geoY);
|
||||
final byte nLayers = _data[startOffset];
|
||||
final int endOffset = startOffset + 1 + (nLayers * 2);
|
||||
|
||||
// 1 layer at least was required on loading so this is set at least once on the loop below
|
||||
int nearestDZ = 0;
|
||||
short nearestData = 0;
|
||||
for (int offset = startOffset + 1; offset < endOffset; offset += 2)
|
||||
{
|
||||
final short layerData = _extractLayerData(offset);
|
||||
final int layerZ = _extractLayerHeight(layerData);
|
||||
if (layerZ == worldZ)
|
||||
{
|
||||
// exact z
|
||||
return layerData;
|
||||
}
|
||||
|
||||
final int layerDZ = Math.abs(layerZ - worldZ);
|
||||
if ((offset == (startOffset + 1)) || (layerDZ < nearestDZ))
|
||||
{
|
||||
nearestDZ = layerDZ;
|
||||
nearestData = layerData;
|
||||
}
|
||||
}
|
||||
|
||||
return nearestData;
|
||||
}
|
||||
|
||||
private int _getCellDataOffset(int geoX, int geoY)
|
||||
{
|
||||
final int cellLocalOffset = ((geoX % IBlock.BLOCK_CELLS_X) * IBlock.BLOCK_CELLS_Y) + (geoY % IBlock.BLOCK_CELLS_Y);
|
||||
int cellDataOffset = 0;
|
||||
// move index to cell, we need to parse on each request, OR we parse on creation and save indexes
|
||||
for (int i = 0; i < cellLocalOffset; i++)
|
||||
{
|
||||
cellDataOffset += 1 + (_data[cellDataOffset] * 2);
|
||||
}
|
||||
// now the index points to the cell we need
|
||||
|
||||
return cellDataOffset;
|
||||
}
|
||||
|
||||
private short _extractLayerData(int dataOffset)
|
||||
{
|
||||
return (short) ((_data[dataOffset] & 0xFF) | (_data[dataOffset + 1] << 8));
|
||||
}
|
||||
|
||||
private int _getNearestNSWE(int geoX, int geoY, int worldZ)
|
||||
{
|
||||
return _extractLayerNswe(_getNearestLayer(geoX, geoY, worldZ));
|
||||
}
|
||||
|
||||
private int _extractLayerNswe(short layer)
|
||||
{
|
||||
return (byte) (layer & 0x000F);
|
||||
}
|
||||
|
||||
private int _extractLayerHeight(short layer)
|
||||
{
|
||||
return ((short) (layer & 0x0fff0)) >> 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkNearestNswe(int geoX, int geoY, int worldZ, int nswe)
|
||||
{
|
||||
return (_getNearestNSWE(geoX, geoY, worldZ) & nswe) == nswe;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNearestZ(int geoX, int geoY, int worldZ)
|
||||
{
|
||||
return _extractLayerHeight(_getNearestLayer(geoX, geoY, worldZ));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNextLowerZ(int geoX, int geoY, int worldZ)
|
||||
{
|
||||
final int startOffset = _getCellDataOffset(geoX, geoY);
|
||||
final byte nLayers = _data[startOffset];
|
||||
final int endOffset = startOffset + 1 + (nLayers * 2);
|
||||
|
||||
int lowerZ = Integer.MIN_VALUE;
|
||||
for (int offset = startOffset + 1; offset < endOffset; offset += 2)
|
||||
{
|
||||
final short layerData = _extractLayerData(offset);
|
||||
|
||||
final int layerZ = _extractLayerHeight(layerData);
|
||||
if (layerZ == worldZ)
|
||||
{
|
||||
// exact z
|
||||
return layerZ;
|
||||
}
|
||||
|
||||
if ((layerZ < worldZ) && (layerZ > lowerZ))
|
||||
{
|
||||
lowerZ = layerZ;
|
||||
}
|
||||
}
|
||||
|
||||
return lowerZ == Integer.MIN_VALUE ? worldZ : lowerZ;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNextHigherZ(int geoX, int geoY, int worldZ)
|
||||
{
|
||||
final int startOffset = _getCellDataOffset(geoX, geoY);
|
||||
final byte nLayers = _data[startOffset];
|
||||
final int endOffset = startOffset + 1 + (nLayers * 2);
|
||||
|
||||
int higherZ = Integer.MAX_VALUE;
|
||||
for (int offset = startOffset + 1; offset < endOffset; offset += 2)
|
||||
{
|
||||
final short layerData = _extractLayerData(offset);
|
||||
|
||||
final int layerZ = _extractLayerHeight(layerData);
|
||||
if (layerZ == worldZ)
|
||||
{
|
||||
// exact z
|
||||
return layerZ;
|
||||
}
|
||||
|
||||
if ((layerZ > worldZ) && (layerZ < higherZ))
|
||||
{
|
||||
higherZ = layerZ;
|
||||
}
|
||||
}
|
||||
|
||||
return higherZ == Integer.MAX_VALUE ? worldZ : higherZ;
|
||||
}
|
||||
}
|
@@ -1,92 +0,0 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.l2jmobius.gameserver.geoengine.geodata;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* @author HorridoJoho
|
||||
*/
|
||||
public final class Region implements IRegion
|
||||
{
|
||||
private final IBlock[] _blocks = new IBlock[IRegion.REGION_BLOCKS];
|
||||
|
||||
public Region(ByteBuffer bb)
|
||||
{
|
||||
for (int blockOffset = 0; blockOffset < IRegion.REGION_BLOCKS; blockOffset++)
|
||||
{
|
||||
final int blockType = bb.get();
|
||||
switch (blockType)
|
||||
{
|
||||
case IBlock.TYPE_FLAT:
|
||||
{
|
||||
_blocks[blockOffset] = new FlatBlock(bb);
|
||||
break;
|
||||
}
|
||||
case IBlock.TYPE_COMPLEX:
|
||||
{
|
||||
_blocks[blockOffset] = new ComplexBlock(bb);
|
||||
break;
|
||||
}
|
||||
case IBlock.TYPE_MULTILAYER:
|
||||
{
|
||||
_blocks[blockOffset] = new MultilayerBlock(bb);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw new RuntimeException("Invalid block type " + blockType + "!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private IBlock getBlock(int geoX, int geoY)
|
||||
{
|
||||
return _blocks[(((geoX / IBlock.BLOCK_CELLS_X) % IRegion.REGION_BLOCKS_X) * IRegion.REGION_BLOCKS_Y) + ((geoY / IBlock.BLOCK_CELLS_Y) % IRegion.REGION_BLOCKS_Y)];
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkNearestNswe(int geoX, int geoY, int worldZ, int nswe)
|
||||
{
|
||||
return getBlock(geoX, geoY).checkNearestNswe(geoX, geoY, worldZ, nswe);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNearestZ(int geoX, int geoY, int worldZ)
|
||||
{
|
||||
return getBlock(geoX, geoY).getNearestZ(geoX, geoY, worldZ);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNextLowerZ(int geoX, int geoY, int worldZ)
|
||||
{
|
||||
return getBlock(geoX, geoY).getNextLowerZ(geoX, geoY, worldZ);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNextHigherZ(int geoX, int geoY, int worldZ)
|
||||
{
|
||||
return getBlock(geoX, geoY).getNextHigherZ(geoX, geoY, worldZ);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasGeo()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
@@ -1,87 +0,0 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.l2jmobius.gameserver.geoengine.pathfinding;
|
||||
|
||||
public abstract class AbstractNode<T extends AbstractNodeLoc>
|
||||
{
|
||||
private T _loc;
|
||||
private AbstractNode<T> _parent;
|
||||
|
||||
public AbstractNode(T loc)
|
||||
{
|
||||
_loc = loc;
|
||||
}
|
||||
|
||||
public void setParent(AbstractNode<T> p)
|
||||
{
|
||||
_parent = p;
|
||||
}
|
||||
|
||||
public AbstractNode<T> getParent()
|
||||
{
|
||||
return _parent;
|
||||
}
|
||||
|
||||
public T getLoc()
|
||||
{
|
||||
return _loc;
|
||||
}
|
||||
|
||||
public void setLoc(T l)
|
||||
{
|
||||
_loc = l;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = (prime * result) + ((_loc == null) ? 0 : _loc.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if (this == obj)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (obj == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!(obj instanceof AbstractNode))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
final AbstractNode<?> other = (AbstractNode<?>) obj;
|
||||
if (_loc == null)
|
||||
{
|
||||
if (other._loc != null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (!_loc.equals(other._loc))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
@@ -1,67 +0,0 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.l2jmobius.gameserver.geoengine.pathfinding;
|
||||
|
||||
public class CellNode extends AbstractNode<NodeLoc>
|
||||
{
|
||||
private CellNode _next = null;
|
||||
private boolean _isInUse = true;
|
||||
private float _cost = -1000;
|
||||
|
||||
public CellNode(NodeLoc loc)
|
||||
{
|
||||
super(loc);
|
||||
}
|
||||
|
||||
public boolean isInUse()
|
||||
{
|
||||
return _isInUse;
|
||||
}
|
||||
|
||||
public void setInUse()
|
||||
{
|
||||
_isInUse = true;
|
||||
}
|
||||
|
||||
public CellNode getNext()
|
||||
{
|
||||
return _next;
|
||||
}
|
||||
|
||||
public void setNext(CellNode next)
|
||||
{
|
||||
_next = next;
|
||||
}
|
||||
|
||||
public float getCost()
|
||||
{
|
||||
return _cost;
|
||||
}
|
||||
|
||||
public void setCost(double cost)
|
||||
{
|
||||
_cost = (float) cost;
|
||||
}
|
||||
|
||||
public void free()
|
||||
{
|
||||
setParent(null);
|
||||
_cost = -1000;
|
||||
_isInUse = false;
|
||||
_next = null;
|
||||
}
|
||||
}
|
@@ -1,348 +0,0 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.l2jmobius.gameserver.geoengine.pathfinding;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import org.l2jmobius.Config;
|
||||
|
||||
/**
|
||||
* @author DS Credits to Diamond
|
||||
*/
|
||||
public class CellNodeBuffer
|
||||
{
|
||||
private static final int MAX_ITERATIONS = 3500;
|
||||
|
||||
private final ReentrantLock _lock = new ReentrantLock();
|
||||
private final int _mapSize;
|
||||
private final CellNode[][] _buffer;
|
||||
|
||||
private int _baseX = 0;
|
||||
private int _baseY = 0;
|
||||
|
||||
private int _targetX = 0;
|
||||
private int _targetY = 0;
|
||||
private int _targetZ = 0;
|
||||
|
||||
private CellNode _current = null;
|
||||
|
||||
public CellNodeBuffer(int size)
|
||||
{
|
||||
_mapSize = size;
|
||||
_buffer = new CellNode[_mapSize][_mapSize];
|
||||
}
|
||||
|
||||
public final boolean lock()
|
||||
{
|
||||
return _lock.tryLock();
|
||||
}
|
||||
|
||||
public final CellNode findPath(int x, int y, int z, int tx, int ty, int tz)
|
||||
{
|
||||
_baseX = x + ((tx - x - _mapSize) / 2); // middle of the line (x,y) - (tx,ty)
|
||||
_baseY = y + ((ty - y - _mapSize) / 2); // will be in the center of the buffer
|
||||
_targetX = tx;
|
||||
_targetY = ty;
|
||||
_targetZ = tz;
|
||||
_current = getNode(x, y, z);
|
||||
_current.setCost(getCost(x, y, z, Config.HIGH_WEIGHT));
|
||||
|
||||
for (int count = 0; count < MAX_ITERATIONS; count++)
|
||||
{
|
||||
if ((_current.getLoc().getNodeX() == _targetX) && (_current.getLoc().getNodeY() == _targetY) && (Math.abs(_current.getLoc().getZ() - _targetZ) < 64))
|
||||
{
|
||||
return _current; // found
|
||||
}
|
||||
|
||||
getNeighbors();
|
||||
if (_current.getNext() == null)
|
||||
{
|
||||
return null; // no more ways
|
||||
}
|
||||
|
||||
_current = _current.getNext();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public final void free()
|
||||
{
|
||||
_current = null;
|
||||
|
||||
CellNode node;
|
||||
for (int i = 0; i < _mapSize; i++)
|
||||
{
|
||||
for (int j = 0; j < _mapSize; j++)
|
||||
{
|
||||
node = _buffer[i][j];
|
||||
if (node != null)
|
||||
{
|
||||
node.free();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_lock.unlock();
|
||||
}
|
||||
|
||||
public final List<CellNode> debugPath()
|
||||
{
|
||||
final List<CellNode> result = new LinkedList<>();
|
||||
|
||||
for (CellNode n = _current; n.getParent() != null; n = (CellNode) n.getParent())
|
||||
{
|
||||
result.add(n);
|
||||
n.setCost(-n.getCost());
|
||||
}
|
||||
|
||||
for (int i = 0; i < _mapSize; i++)
|
||||
{
|
||||
for (int j = 0; j < _mapSize; j++)
|
||||
{
|
||||
final CellNode n = _buffer[i][j];
|
||||
if ((n == null) || !n.isInUse() || (n.getCost() <= 0))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
result.add(n);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private void getNeighbors()
|
||||
{
|
||||
if (!_current.getLoc().canGoAll())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
final int x = _current.getLoc().getNodeX();
|
||||
final int y = _current.getLoc().getNodeY();
|
||||
final int z = _current.getLoc().getZ();
|
||||
|
||||
CellNode nodeE = null;
|
||||
CellNode nodeS = null;
|
||||
CellNode nodeW = null;
|
||||
CellNode nodeN = null;
|
||||
|
||||
// East
|
||||
if (_current.getLoc().canGoEast())
|
||||
{
|
||||
nodeE = addNode(x + 1, y, z, false);
|
||||
}
|
||||
|
||||
// South
|
||||
if (_current.getLoc().canGoSouth())
|
||||
{
|
||||
nodeS = addNode(x, y + 1, z, false);
|
||||
}
|
||||
|
||||
// West
|
||||
if (_current.getLoc().canGoWest())
|
||||
{
|
||||
nodeW = addNode(x - 1, y, z, false);
|
||||
}
|
||||
|
||||
// North
|
||||
if (_current.getLoc().canGoNorth())
|
||||
{
|
||||
nodeN = addNode(x, y - 1, z, false);
|
||||
}
|
||||
|
||||
// SouthEast
|
||||
if ((nodeE != null) && (nodeS != null))
|
||||
{
|
||||
if (nodeE.getLoc().canGoSouth() && nodeS.getLoc().canGoEast())
|
||||
{
|
||||
addNode(x + 1, y + 1, z, true);
|
||||
}
|
||||
}
|
||||
|
||||
// SouthWest
|
||||
if ((nodeS != null) && (nodeW != null))
|
||||
{
|
||||
if (nodeW.getLoc().canGoSouth() && nodeS.getLoc().canGoWest())
|
||||
{
|
||||
addNode(x - 1, y + 1, z, true);
|
||||
}
|
||||
}
|
||||
|
||||
// NorthEast
|
||||
if ((nodeN != null) && (nodeE != null))
|
||||
{
|
||||
if (nodeE.getLoc().canGoNorth() && nodeN.getLoc().canGoEast())
|
||||
{
|
||||
addNode(x + 1, y - 1, z, true);
|
||||
}
|
||||
}
|
||||
|
||||
// NorthWest
|
||||
if ((nodeN != null) && (nodeW != null))
|
||||
{
|
||||
if (nodeW.getLoc().canGoNorth() && nodeN.getLoc().canGoWest())
|
||||
{
|
||||
addNode(x - 1, y - 1, z, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private CellNode getNode(int x, int y, int z)
|
||||
{
|
||||
final int aX = x - _baseX;
|
||||
if ((aX < 0) || (aX >= _mapSize))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
final int aY = y - _baseY;
|
||||
if ((aY < 0) || (aY >= _mapSize))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
CellNode result = _buffer[aX][aY];
|
||||
if (result == null)
|
||||
{
|
||||
result = new CellNode(new NodeLoc(x, y, z));
|
||||
_buffer[aX][aY] = result;
|
||||
}
|
||||
else if (!result.isInUse())
|
||||
{
|
||||
result.setInUse();
|
||||
// reinit node if needed
|
||||
if (result.getLoc() != null)
|
||||
{
|
||||
result.getLoc().set(x, y, z);
|
||||
}
|
||||
else
|
||||
{
|
||||
result.setLoc(new NodeLoc(x, y, z));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private CellNode addNode(int x, int y, int z, boolean diagonal)
|
||||
{
|
||||
final CellNode newNode = getNode(x, y, z);
|
||||
if (newNode == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (newNode.getCost() >= 0)
|
||||
{
|
||||
return newNode;
|
||||
}
|
||||
|
||||
final int geoZ = newNode.getLoc().getZ();
|
||||
|
||||
final int stepZ = Math.abs(geoZ - _current.getLoc().getZ());
|
||||
float weight = diagonal ? Config.DIAGONAL_WEIGHT : Config.LOW_WEIGHT;
|
||||
|
||||
if (!newNode.getLoc().canGoAll() || (stepZ > 16))
|
||||
{
|
||||
weight = Config.HIGH_WEIGHT;
|
||||
}
|
||||
else if (isHighWeight(x + 1, y, geoZ))
|
||||
{
|
||||
weight = Config.MEDIUM_WEIGHT;
|
||||
}
|
||||
else if (isHighWeight(x - 1, y, geoZ))
|
||||
{
|
||||
weight = Config.MEDIUM_WEIGHT;
|
||||
}
|
||||
else if (isHighWeight(x, y + 1, geoZ))
|
||||
{
|
||||
weight = Config.MEDIUM_WEIGHT;
|
||||
}
|
||||
else if (isHighWeight(x, y - 1, geoZ))
|
||||
{
|
||||
weight = Config.MEDIUM_WEIGHT;
|
||||
}
|
||||
|
||||
newNode.setParent(_current);
|
||||
newNode.setCost(getCost(x, y, geoZ, weight));
|
||||
|
||||
CellNode node = _current;
|
||||
int count = 0;
|
||||
while ((node.getNext() != null) && (count < (MAX_ITERATIONS * 4)))
|
||||
{
|
||||
count++;
|
||||
if (node.getNext().getCost() > newNode.getCost())
|
||||
{
|
||||
// insert node into a chain
|
||||
newNode.setNext(node.getNext());
|
||||
break;
|
||||
}
|
||||
node = node.getNext();
|
||||
}
|
||||
if (count == (MAX_ITERATIONS * 4))
|
||||
{
|
||||
System.err.println("Pathfinding: too long loop detected, cost:" + newNode.getCost());
|
||||
}
|
||||
|
||||
node.setNext(newNode); // add last
|
||||
|
||||
return newNode;
|
||||
}
|
||||
|
||||
private boolean isHighWeight(int x, int y, int z)
|
||||
{
|
||||
final CellNode result = getNode(x, y, z);
|
||||
if (result == null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!result.getLoc().canGoAll())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (Math.abs(result.getLoc().getZ() - z) > 16)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private double getCost(int x, int y, int z, float weight)
|
||||
{
|
||||
final int dX = x - _targetX;
|
||||
final int dY = y - _targetY;
|
||||
final int dZ = z - _targetZ;
|
||||
// Math.abs(dx) + Math.abs(dy) + Math.abs(dz) / 16
|
||||
double result = Math.sqrt((dX * dX) + (dY * dY) + ((dZ * dZ) / 256.0));
|
||||
if (result > weight)
|
||||
{
|
||||
result += weight;
|
||||
}
|
||||
|
||||
if (result > Float.MAX_VALUE)
|
||||
{
|
||||
result = Float.MAX_VALUE;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.l2jmobius.gameserver.geoengine.pathfinding;
|
||||
|
||||
import org.l2jmobius.gameserver.geoengine.GeoEngine;
|
||||
import org.l2jmobius.gameserver.geoengine.geodata.GeoStructure;
|
||||
import org.l2jmobius.gameserver.model.Location;
|
||||
|
||||
public class Node extends Location implements Comparable<Node>
|
||||
{
|
||||
// Node geodata values.
|
||||
private int _geoX;
|
||||
private int _geoY;
|
||||
private byte _nswe;
|
||||
|
||||
// The cost G (movement cost done) and cost H (estimated cost to target).
|
||||
private int _costG;
|
||||
private int _costH;
|
||||
private int _costF;
|
||||
|
||||
// Node parent (reverse path construction).
|
||||
private Node _parent;
|
||||
|
||||
public Node()
|
||||
{
|
||||
super(0, 0, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clean()
|
||||
{
|
||||
super.clean();
|
||||
|
||||
_geoX = 0;
|
||||
_geoY = 0;
|
||||
_nswe = GeoStructure.CELL_FLAG_NONE;
|
||||
|
||||
_costG = 0;
|
||||
_costH = 0;
|
||||
_costF = 0;
|
||||
|
||||
_parent = null;
|
||||
}
|
||||
|
||||
public void setGeo(int gx, int gy, int gz, byte nswe)
|
||||
{
|
||||
super.setXYZ(GeoEngine.getWorldX(gx), GeoEngine.getWorldY(gy), gz);
|
||||
|
||||
_geoX = gx;
|
||||
_geoY = gy;
|
||||
_nswe = nswe;
|
||||
}
|
||||
|
||||
public void setCost(Node parent, int weight, int costH)
|
||||
{
|
||||
_costG = weight;
|
||||
if (parent != null)
|
||||
{
|
||||
_costG += parent._costG;
|
||||
}
|
||||
_costH = costH;
|
||||
_costF = _costG + _costH;
|
||||
|
||||
_parent = parent;
|
||||
}
|
||||
|
||||
public int getGeoX()
|
||||
{
|
||||
return _geoX;
|
||||
}
|
||||
|
||||
public int getGeoY()
|
||||
{
|
||||
return _geoY;
|
||||
}
|
||||
|
||||
public byte getNSWE()
|
||||
{
|
||||
return _nswe;
|
||||
}
|
||||
|
||||
public int getCostF()
|
||||
{
|
||||
return _costF;
|
||||
}
|
||||
|
||||
public Node getParent()
|
||||
{
|
||||
return _parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Node o)
|
||||
{
|
||||
return _costF - o._costF;
|
||||
}
|
||||
}
|
@@ -0,0 +1,368 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.l2jmobius.gameserver.geoengine.pathfinding;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.PriorityQueue;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import org.l2jmobius.Config;
|
||||
import org.l2jmobius.gameserver.geoengine.GeoEngine;
|
||||
import org.l2jmobius.gameserver.geoengine.geodata.ABlock;
|
||||
import org.l2jmobius.gameserver.geoengine.geodata.GeoStructure;
|
||||
import org.l2jmobius.gameserver.model.Location;
|
||||
import org.l2jmobius.gameserver.network.serverpackets.ExServerPrimitive;
|
||||
|
||||
public class NodeBuffer
|
||||
{
|
||||
// Locking NodeBuffer to ensure thread-safe operations.
|
||||
private final ReentrantLock _lock = new ReentrantLock();
|
||||
|
||||
// Container holding all available Nodes to be used.
|
||||
private final Node[] _buffer;
|
||||
private int _bufferIndex;
|
||||
// Container (binary-heap) holding Nodes to be explored.
|
||||
private final PriorityQueue<Node> _opened;
|
||||
// Container holding Nodes already explored.
|
||||
private final List<Node> _closed;
|
||||
|
||||
// Target coordinates.
|
||||
private int _gtx;
|
||||
private int _gty;
|
||||
private int _gtz;
|
||||
|
||||
// Pathfinding statistics.
|
||||
private long _timeStamp;
|
||||
private long _lastElapsedTime;
|
||||
|
||||
private Node _current;
|
||||
|
||||
/**
|
||||
* Constructor of NodeBuffer.
|
||||
* @param size : The total size buffer. Determines the amount of {@link Node}s to be used for pathfinding.
|
||||
*/
|
||||
public NodeBuffer(int size)
|
||||
{
|
||||
// Create buffers based on given size.
|
||||
_buffer = new Node[size];
|
||||
_opened = new PriorityQueue<>(size);
|
||||
_closed = new ArrayList<>(size);
|
||||
|
||||
// Create Nodes.
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
_buffer[i] = new Node();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find path consisting of Nodes. Starts at origin coordinates, ends in target coordinates.
|
||||
* @param gox : origin point x
|
||||
* @param goy : origin point y
|
||||
* @param goz : origin point z
|
||||
* @param gtx : target point x
|
||||
* @param gty : target point y
|
||||
* @param gtz : target point z
|
||||
* @return The list of {@link Location} for the path. Empty, if path not found.
|
||||
*/
|
||||
public List<Location> findPath(int gox, int goy, int goz, int gtx, int gty, int gtz)
|
||||
{
|
||||
// Set start timestamp.
|
||||
_timeStamp = System.currentTimeMillis();
|
||||
|
||||
// Set target coordinates.
|
||||
_gtx = gtx;
|
||||
_gty = gty;
|
||||
_gtz = gtz;
|
||||
|
||||
// Get node from buffer.
|
||||
_current = _buffer[_bufferIndex++];
|
||||
|
||||
// Set node geodata coordinates and movement cost.
|
||||
_current.setGeo(gox, goy, goz, GeoEngine.getInstance().getNsweNearest(gox, goy, goz));
|
||||
_current.setCost(null, 0, getCostH(gox, goy, goz));
|
||||
|
||||
int count = 0;
|
||||
do
|
||||
{
|
||||
// Move node to closed list.
|
||||
_closed.add(_current);
|
||||
|
||||
// Target reached, calculate path and return.
|
||||
if ((_current.getGeoX() == _gtx) && (_current.getGeoY() == _gty) && (_current.getZ() == _gtz))
|
||||
{
|
||||
return constructPath();
|
||||
}
|
||||
|
||||
// Expand current node.
|
||||
expand();
|
||||
|
||||
// Get next node to expand.
|
||||
_current = _opened.poll();
|
||||
}
|
||||
while ((_current != null) && (_bufferIndex < _buffer.length) && (++count < Config.MAX_ITERATIONS));
|
||||
|
||||
// Iteration failed, return empty path.
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the path from subsequent nodes. Skip nodes in straight directions, keep only corner nodes.
|
||||
* @return List of {@link Node}s representing the path.
|
||||
*/
|
||||
private List<Location> constructPath()
|
||||
{
|
||||
// Create result.
|
||||
final LinkedList<Location> path = new LinkedList<>();
|
||||
|
||||
// Clear X/Y direction.
|
||||
int dx = 0;
|
||||
int dy = 0;
|
||||
|
||||
// Get parent node.
|
||||
Node parent = _current.getParent();
|
||||
|
||||
// While parent exists.
|
||||
while (parent != null)
|
||||
{
|
||||
// Get parent node to current node X/Y direction.
|
||||
final int nx = parent.getGeoX() - _current.getGeoX();
|
||||
final int ny = parent.getGeoY() - _current.getGeoY();
|
||||
|
||||
// Direction has changed?
|
||||
if ((dx != nx) || (dy != ny))
|
||||
{
|
||||
// Add current node to the beginning of the path (Node must be cloned, as NodeBuffer reuses them).
|
||||
path.addFirst(_current.clone());
|
||||
|
||||
// Update X/Y direction.
|
||||
dx = nx;
|
||||
dy = ny;
|
||||
}
|
||||
|
||||
// Move current node and update its parent.
|
||||
_current = parent;
|
||||
parent = _current.getParent();
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates list of Nodes to show debug path.
|
||||
* @param debug : The debug packet to add debug informations in.
|
||||
*/
|
||||
public void debugPath(ExServerPrimitive debug)
|
||||
{
|
||||
// Add all opened node as yellow points.
|
||||
for (Node n : _opened)
|
||||
{
|
||||
debug.addPoint(String.valueOf(n.getCostF()), Color.YELLOW, true, n.getX(), n.getY(), n.getZ() - 16);
|
||||
}
|
||||
|
||||
// Add all opened node as blue points.
|
||||
for (Node n : _closed)
|
||||
{
|
||||
debug.addPoint(String.valueOf(n.getCostF()), Color.BLUE, true, n.getX(), n.getY(), n.getZ() - 16);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isLocked()
|
||||
{
|
||||
return _lock.tryLock();
|
||||
}
|
||||
|
||||
public void free()
|
||||
{
|
||||
_opened.clear();
|
||||
_closed.clear();
|
||||
|
||||
for (int i = 0; i < (_bufferIndex - 1); i++)
|
||||
{
|
||||
_buffer[i].clean();
|
||||
}
|
||||
_bufferIndex = 0;
|
||||
|
||||
_current = null;
|
||||
|
||||
_lastElapsedTime = System.currentTimeMillis() - _timeStamp;
|
||||
_lock.unlock();
|
||||
}
|
||||
|
||||
public long getElapsedTime()
|
||||
{
|
||||
return _lastElapsedTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Expand the current {@link Node} by exploring its neighbors (axially and diagonally).
|
||||
*/
|
||||
private void expand()
|
||||
{
|
||||
// Movement is blocked, skip.
|
||||
final byte nswe = _current.getNSWE();
|
||||
if (nswe == GeoStructure.CELL_FLAG_NONE)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Get geo coordinates of the node to be expanded.
|
||||
// Note: Z coord shifted up to avoid dual-layer issues.
|
||||
final int x = _current.getGeoX();
|
||||
final int y = _current.getGeoY();
|
||||
final int z = _current.getZ() + GeoStructure.CELL_IGNORE_HEIGHT;
|
||||
|
||||
byte nsweN = GeoStructure.CELL_FLAG_NONE;
|
||||
byte nsweS = GeoStructure.CELL_FLAG_NONE;
|
||||
byte nsweW = GeoStructure.CELL_FLAG_NONE;
|
||||
byte nsweE = GeoStructure.CELL_FLAG_NONE;
|
||||
|
||||
// Can move north, expand.
|
||||
if ((nswe & GeoStructure.CELL_FLAG_N) != 0)
|
||||
{
|
||||
nsweN = addNode(x, y - 1, z, Config.MOVE_WEIGHT);
|
||||
}
|
||||
|
||||
// Can move south, expand.
|
||||
if ((nswe & GeoStructure.CELL_FLAG_S) != 0)
|
||||
{
|
||||
nsweS = addNode(x, y + 1, z, Config.MOVE_WEIGHT);
|
||||
}
|
||||
|
||||
// Can move west, expand.
|
||||
if ((nswe & GeoStructure.CELL_FLAG_W) != 0)
|
||||
{
|
||||
nsweW = addNode(x - 1, y, z, Config.MOVE_WEIGHT);
|
||||
}
|
||||
|
||||
// Can move east, expand.
|
||||
if ((nswe & GeoStructure.CELL_FLAG_E) != 0)
|
||||
{
|
||||
nsweE = addNode(x + 1, y, z, Config.MOVE_WEIGHT);
|
||||
}
|
||||
|
||||
// Can move north-west, expand.
|
||||
if (((nsweW & GeoStructure.CELL_FLAG_N) != 0) && ((nsweN & GeoStructure.CELL_FLAG_W) != 0))
|
||||
{
|
||||
addNode(x - 1, y - 1, z, Config.MOVE_WEIGHT_DIAG);
|
||||
}
|
||||
|
||||
// Can move north-east, expand.
|
||||
if (((nsweE & GeoStructure.CELL_FLAG_N) != 0) && ((nsweN & GeoStructure.CELL_FLAG_E) != 0))
|
||||
{
|
||||
addNode(x + 1, y - 1, z, Config.MOVE_WEIGHT_DIAG);
|
||||
}
|
||||
|
||||
// Can move south-west, expand.
|
||||
if (((nsweW & GeoStructure.CELL_FLAG_S) != 0) && ((nsweS & GeoStructure.CELL_FLAG_W) != 0))
|
||||
{
|
||||
addNode(x - 1, y + 1, z, Config.MOVE_WEIGHT_DIAG);
|
||||
}
|
||||
|
||||
// Can move south-east, expand.
|
||||
if (((nsweE & GeoStructure.CELL_FLAG_S) != 0) && ((nsweS & GeoStructure.CELL_FLAG_E) != 0))
|
||||
{
|
||||
addNode(x + 1, y + 1, z, Config.MOVE_WEIGHT_DIAG);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Take {@link Node} from buffer, validate it and add to opened list.
|
||||
* @param gx : The new node X geodata coordinate.
|
||||
* @param gy : The new node Y geodata coordinate.
|
||||
* @param gzValue : The new node Z geodata coordinate.
|
||||
* @param weight : The weight of movement to the new node.
|
||||
* @return The nswe of the added node. Blank, if not added.
|
||||
*/
|
||||
private byte addNode(int gx, int gy, int gzValue, int weight)
|
||||
{
|
||||
// Check new node is out of geodata grid (world coordinates).
|
||||
if ((gx < 0) || (gx >= GeoStructure.GEO_CELLS_X) || (gy < 0) || (gy >= GeoStructure.GEO_CELLS_Y))
|
||||
{
|
||||
return GeoStructure.CELL_FLAG_NONE;
|
||||
}
|
||||
|
||||
// Check buffer has reached capacity.
|
||||
if (_bufferIndex >= _buffer.length)
|
||||
{
|
||||
return GeoStructure.CELL_FLAG_NONE;
|
||||
}
|
||||
|
||||
// Get geodata block and check if there is a layer at given coordinates.
|
||||
final ABlock block = GeoEngine.getInstance().getBlock(gx, gy);
|
||||
final int index = block.getIndexBelow(gx, gy, gzValue);
|
||||
if (index < 0)
|
||||
{
|
||||
return GeoStructure.CELL_FLAG_NONE;
|
||||
}
|
||||
|
||||
// Get node geodata Z and nswe.
|
||||
final int gz = block.getHeight(index);
|
||||
final byte nswe = block.getNswe(index);
|
||||
|
||||
// Get node from current index (don't move index yet).
|
||||
Node node = _buffer[_bufferIndex];
|
||||
|
||||
// Set node geodata coordinates.
|
||||
node.setGeo(gx, gy, gz, nswe);
|
||||
|
||||
// Node is already added to opened list, return.
|
||||
if (_opened.contains(node))
|
||||
{
|
||||
return nswe;
|
||||
}
|
||||
|
||||
// Node was already expanded, return.
|
||||
if (_closed.contains(node))
|
||||
{
|
||||
return nswe;
|
||||
}
|
||||
|
||||
// The node is to be used. Set node movement cost and add it to opened list. Move the buffer index.
|
||||
node.setCost(_current, nswe != GeoStructure.CELL_FLAG_ALL ? Config.OBSTACLE_WEIGHT : weight, getCostH(gx, gy, gz));
|
||||
_opened.add(node);
|
||||
_bufferIndex++;
|
||||
return nswe;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate cost H value, calculated using diagonal distance method.<br>
|
||||
* Note: Manhattan distance is too simple, causing to explore more unwanted cells.
|
||||
* @param gx : The node geodata X coordinate.
|
||||
* @param gy : The node geodata Y coordinate.
|
||||
* @param gz : The node geodata Z coordinate.
|
||||
* @return The cost H value (estimated cost to reach the target).
|
||||
*/
|
||||
private int getCostH(int gx, int gy, int gz)
|
||||
{
|
||||
// Get differences to the target.
|
||||
final int dx = Math.abs(gx - _gtx);
|
||||
final int dy = Math.abs(gy - _gty);
|
||||
final int dz = Math.abs(gz - _gtz) / GeoStructure.CELL_HEIGHT;
|
||||
|
||||
// Get diagonal and axial differences to the target.
|
||||
final int dd = Math.min(dx, dy);
|
||||
final int da = Math.max(dx, dy) - dd;
|
||||
|
||||
// Calculate the diagonal distance of the node to the target.
|
||||
return (dd * Config.HEURISTIC_WEIGHT_DIAG) + ((da + dz) * Config.HEURISTIC_WEIGHT);
|
||||
}
|
||||
}
|
@@ -1,183 +0,0 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.l2jmobius.gameserver.geoengine.pathfinding;
|
||||
|
||||
import org.l2jmobius.gameserver.geoengine.GeoEngine;
|
||||
import org.l2jmobius.gameserver.geoengine.geodata.Cell;
|
||||
|
||||
/**
|
||||
* @author -Nemesiss-, HorridoJoho
|
||||
*/
|
||||
public class NodeLoc extends AbstractNodeLoc
|
||||
{
|
||||
private int _x;
|
||||
private int _y;
|
||||
private boolean _goNorth;
|
||||
private boolean _goEast;
|
||||
private boolean _goSouth;
|
||||
private boolean _goWest;
|
||||
private int _geoHeight;
|
||||
|
||||
public NodeLoc(int x, int y, int z)
|
||||
{
|
||||
set(x, y, z);
|
||||
}
|
||||
|
||||
public void set(int x, int y, int z)
|
||||
{
|
||||
_x = x;
|
||||
_y = y;
|
||||
_goNorth = GeoEngine.getInstance().checkNearestNswe(x, y, z, Cell.NSWE_NORTH);
|
||||
_goEast = GeoEngine.getInstance().checkNearestNswe(x, y, z, Cell.NSWE_EAST);
|
||||
_goSouth = GeoEngine.getInstance().checkNearestNswe(x, y, z, Cell.NSWE_SOUTH);
|
||||
_goWest = GeoEngine.getInstance().checkNearestNswe(x, y, z, Cell.NSWE_WEST);
|
||||
_geoHeight = GeoEngine.getInstance().getNearestZ(x, y, z);
|
||||
}
|
||||
|
||||
public boolean canGoNorth()
|
||||
{
|
||||
return _goNorth;
|
||||
}
|
||||
|
||||
public boolean canGoEast()
|
||||
{
|
||||
return _goEast;
|
||||
}
|
||||
|
||||
public boolean canGoSouth()
|
||||
{
|
||||
return _goSouth;
|
||||
}
|
||||
|
||||
public boolean canGoWest()
|
||||
{
|
||||
return _goWest;
|
||||
}
|
||||
|
||||
public boolean canGoAll()
|
||||
{
|
||||
return canGoNorth() && canGoEast() && canGoSouth() && canGoWest();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getX()
|
||||
{
|
||||
return GeoEngine.getInstance().getWorldX(_x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getY()
|
||||
{
|
||||
return GeoEngine.getInstance().getWorldY(_y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getZ()
|
||||
{
|
||||
return _geoHeight;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNodeX()
|
||||
{
|
||||
return _x;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNodeY()
|
||||
{
|
||||
return _y;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = (prime * result) + _x;
|
||||
result = (prime * result) + _y;
|
||||
|
||||
int nswe = 0;
|
||||
if (canGoNorth())
|
||||
{
|
||||
nswe |= Cell.NSWE_NORTH;
|
||||
}
|
||||
if (canGoEast())
|
||||
{
|
||||
nswe |= Cell.NSWE_EAST;
|
||||
}
|
||||
if (canGoSouth())
|
||||
{
|
||||
nswe |= Cell.NSWE_SOUTH;
|
||||
}
|
||||
if (canGoWest())
|
||||
{
|
||||
nswe |= Cell.NSWE_WEST;
|
||||
}
|
||||
|
||||
result = (prime * result) + (((_geoHeight & 0xFFFF) << 1) | nswe);
|
||||
return result;
|
||||
// return super.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if (this == obj)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (obj == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!(obj instanceof NodeLoc))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
final NodeLoc other = (NodeLoc) obj;
|
||||
if (_x != other._x)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (_y != other._y)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (_goNorth != other._goNorth)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (_goEast != other._goEast)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (_goSouth != other._goSouth)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (_goWest != other._goWest)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (_geoHeight != other._geoHeight)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
@@ -91,15 +91,15 @@ public class ZoneManager implements IXmlReader
|
||||
private static final Map<String, AbstractZoneSettings> SETTINGS = new HashMap<>();
|
||||
|
||||
private static final int SHIFT_BY = 15;
|
||||
private static final int OFFSET_X = Math.abs(World.MAP_MIN_X >> SHIFT_BY);
|
||||
private static final int OFFSET_Y = Math.abs(World.MAP_MIN_Y >> SHIFT_BY);
|
||||
private static final int OFFSET_X = Math.abs(World.WORLD_X_MIN >> SHIFT_BY);
|
||||
private static final int OFFSET_Y = Math.abs(World.WORLD_Y_MIN >> SHIFT_BY);
|
||||
|
||||
private final Map<Class<? extends ZoneType>, ConcurrentHashMap<Integer, ? extends ZoneType>> _classZones = new ConcurrentHashMap<>();
|
||||
private final Map<String, NpcSpawnTerritory> _spawnTerritories = new ConcurrentHashMap<>();
|
||||
private final AtomicInteger _lastDynamicId = new AtomicInteger(300000);
|
||||
private List<ItemInstance> _debugItems;
|
||||
|
||||
private final ZoneRegion[][] _zoneRegions = new ZoneRegion[(World.MAP_MAX_X >> SHIFT_BY) + OFFSET_X + 1][(World.MAP_MAX_Y >> SHIFT_BY) + OFFSET_Y + 1];
|
||||
private final ZoneRegion[][] _zoneRegions = new ZoneRegion[(World.WORLD_X_MAX >> SHIFT_BY) + OFFSET_X + 1][(World.WORLD_Y_MAX >> SHIFT_BY) + OFFSET_Y + 1];
|
||||
|
||||
/**
|
||||
* Instantiates a new zone manager.
|
||||
@@ -178,7 +178,6 @@ public class ZoneManager implements IXmlReader
|
||||
String zoneType;
|
||||
String zoneShape;
|
||||
final List<int[]> rs = new ArrayList<>();
|
||||
|
||||
for (Node n = doc.getFirstChild(); n != null; n = n.getNextSibling())
|
||||
{
|
||||
if ("list".equalsIgnoreCase(n.getNodeName()))
|
||||
@@ -195,7 +194,6 @@ public class ZoneManager implements IXmlReader
|
||||
if ("zone".equalsIgnoreCase(d.getNodeName()))
|
||||
{
|
||||
attrs = d.getAttributes();
|
||||
|
||||
attribute = attrs.getNamedItem("type");
|
||||
if (attribute != null)
|
||||
{
|
||||
@@ -244,7 +242,6 @@ public class ZoneManager implements IXmlReader
|
||||
|
||||
minZ = parseInteger(attrs, "minZ");
|
||||
maxZ = parseInteger(attrs, "maxZ");
|
||||
|
||||
zoneType = parseString(attrs, "type");
|
||||
zoneShape = parseString(attrs, "shape");
|
||||
|
||||
@@ -366,7 +363,6 @@ public class ZoneManager implements IXmlReader
|
||||
attrs = cd.getAttributes();
|
||||
final String name = attrs.getNamedItem("name").getNodeValue();
|
||||
final String val = attrs.getNamedItem("val").getNodeValue();
|
||||
|
||||
temp.setParameter(name, val);
|
||||
}
|
||||
else if ("spawn".equalsIgnoreCase(cd.getNodeName()) && (temp instanceof ZoneRespawn))
|
||||
@@ -383,7 +379,6 @@ public class ZoneManager implements IXmlReader
|
||||
attrs = cd.getAttributes();
|
||||
final String race = attrs.getNamedItem("name").getNodeValue();
|
||||
final String point = attrs.getNamedItem("point").getNodeValue();
|
||||
|
||||
((RespawnZone) temp).addRaceRespawnPoint(race, point);
|
||||
}
|
||||
}
|
||||
@@ -410,7 +405,6 @@ public class ZoneManager implements IXmlReader
|
||||
final int bx = ((x + 1) - OFFSET_X) << SHIFT_BY;
|
||||
final int ay = (y - OFFSET_Y) << SHIFT_BY;
|
||||
final int by = ((y + 1) - OFFSET_Y) << SHIFT_BY;
|
||||
|
||||
if (temp.getZone().intersectsRectangle(ax, bx, ay, by))
|
||||
{
|
||||
_zoneRegions[x][y].getZones().put(temp.getId(), temp);
|
||||
@@ -463,7 +457,7 @@ public class ZoneManager implements IXmlReader
|
||||
LOGGER.info(getClass().getSimpleName() + ": Loaded " + _classZones.size() + " zone classes and " + getSize() + " zones.");
|
||||
LOGGER.info(getClass().getSimpleName() + ": Loaded " + _spawnTerritories.size() + " NPC spawn territoriers.");
|
||||
final OptionalInt maxId = _classZones.values().stream().flatMap(map -> map.keySet().stream()).mapToInt(Integer.class::cast).filter(value -> value < 300000).max();
|
||||
LOGGER.info(getClass().getSimpleName() + ": Last static id: " + maxId.getAsInt());
|
||||
LOGGER.info(getClass().getSimpleName() + ": Last static id " + maxId.getAsInt() + ".");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -16,30 +16,35 @@
|
||||
*/
|
||||
package org.l2jmobius.gameserver.model;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import org.l2jmobius.commons.util.Point2D;
|
||||
import org.l2jmobius.gameserver.model.interfaces.ILocational;
|
||||
import org.l2jmobius.gameserver.model.interfaces.IPositionable;
|
||||
|
||||
/**
|
||||
* Location data transfer object.<br>
|
||||
* Contains coordinates data, heading and instance Id.
|
||||
* @author Zoey76
|
||||
* A datatype used to retain a 3D (x/y/z/heading/instanceId) point. It got the capability to be set and cleaned.
|
||||
*/
|
||||
public class Location implements IPositionable
|
||||
public class Location extends Point2D implements IPositionable
|
||||
{
|
||||
protected int _x;
|
||||
protected int _y;
|
||||
protected int _z;
|
||||
private int _heading;
|
||||
private int _instanceId;
|
||||
protected volatile int _z;
|
||||
protected volatile int _heading;
|
||||
protected volatile int _instanceId;
|
||||
|
||||
public Location(int x, int y, int z)
|
||||
{
|
||||
this(x, y, z, 0, 0);
|
||||
super(x, y);
|
||||
_z = z;
|
||||
_heading = 0;
|
||||
_instanceId = 0;
|
||||
}
|
||||
|
||||
public Location(int x, int y, int z, int heading)
|
||||
{
|
||||
this(x, y, z, heading, 0);
|
||||
super(x, y);
|
||||
_z = z;
|
||||
_heading = heading;
|
||||
_instanceId = 0;
|
||||
}
|
||||
|
||||
public Location(WorldObject obj)
|
||||
@@ -49,13 +54,20 @@ public class Location implements IPositionable
|
||||
|
||||
public Location(int x, int y, int z, int heading, int instanceId)
|
||||
{
|
||||
_x = x;
|
||||
_y = y;
|
||||
super(x, y);
|
||||
_z = z;
|
||||
_heading = heading;
|
||||
_instanceId = instanceId;
|
||||
}
|
||||
|
||||
public Location(StatSet set)
|
||||
{
|
||||
super(set.getInt("x", 0), set.getInt("y", 0));
|
||||
_z = set.getInt("z", 0);
|
||||
_heading = set.getInt("heading", 0);
|
||||
_instanceId = set.getInt("instanceId", 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the x coordinate.
|
||||
* @return the x coordinate
|
||||
@@ -166,15 +178,35 @@ public class Location implements IPositionable
|
||||
_instanceId = loc.getInstanceId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clean()
|
||||
{
|
||||
super.clean();
|
||||
_z = 0;
|
||||
_instanceId = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Location clone()
|
||||
{
|
||||
return new Location(_x, _y, _z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return (31 * super.hashCode()) + Objects.hash(_z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if (!(obj instanceof Location))
|
||||
if (obj instanceof Location)
|
||||
{
|
||||
return false;
|
||||
final Location loc = (Location) obj;
|
||||
return (getX() == loc.getX()) && (getY() == loc.getY()) && (getZ() == loc.getZ()) && (getHeading() == loc.getHeading()) && (getInstanceId() == loc.getInstanceId());
|
||||
}
|
||||
final Location loc = (Location) obj;
|
||||
return (getX() == loc.getX()) && (getY() == loc.getY()) && (getZ() == loc.getZ()) && (getHeading() == loc.getHeading()) && (getInstanceId() == loc.getInstanceId());
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@@ -65,19 +65,19 @@ public class World
|
||||
public static final int TILE_Y_MAX = 26;
|
||||
public static final int TILE_ZERO_COORD_X = 20;
|
||||
public static final int TILE_ZERO_COORD_Y = 18;
|
||||
public static final int MAP_MIN_X = (TILE_X_MIN - TILE_ZERO_COORD_X) * TILE_SIZE;
|
||||
public static final int MAP_MIN_Y = (TILE_Y_MIN - TILE_ZERO_COORD_Y) * TILE_SIZE;
|
||||
public static final int WORLD_X_MIN = (TILE_X_MIN - TILE_ZERO_COORD_X) * TILE_SIZE;
|
||||
public static final int WORLD_Y_MIN = (TILE_Y_MIN - TILE_ZERO_COORD_Y) * TILE_SIZE;
|
||||
|
||||
public static final int MAP_MAX_X = ((TILE_X_MAX - TILE_ZERO_COORD_X) + 1) * TILE_SIZE;
|
||||
public static final int MAP_MAX_Y = ((TILE_Y_MAX - TILE_ZERO_COORD_Y) + 1) * TILE_SIZE;
|
||||
public static final int WORLD_X_MAX = ((TILE_X_MAX - TILE_ZERO_COORD_X) + 1) * TILE_SIZE;
|
||||
public static final int WORLD_Y_MAX = ((TILE_Y_MAX - TILE_ZERO_COORD_Y) + 1) * TILE_SIZE;
|
||||
|
||||
/** Calculated offset used so top left region is 0,0 */
|
||||
public static final int OFFSET_X = Math.abs(MAP_MIN_X >> SHIFT_BY);
|
||||
public static final int OFFSET_Y = Math.abs(MAP_MIN_Y >> SHIFT_BY);
|
||||
public static final int OFFSET_X = Math.abs(WORLD_X_MIN >> SHIFT_BY);
|
||||
public static final int OFFSET_Y = Math.abs(WORLD_Y_MIN >> SHIFT_BY);
|
||||
|
||||
/** Number of regions. */
|
||||
private static final int REGIONS_X = (MAP_MAX_X >> SHIFT_BY) + OFFSET_X;
|
||||
private static final int REGIONS_Y = (MAP_MAX_Y >> SHIFT_BY) + OFFSET_Y;
|
||||
private static final int REGIONS_X = (WORLD_X_MAX >> SHIFT_BY) + OFFSET_X;
|
||||
private static final int REGIONS_Y = (WORLD_Y_MAX >> SHIFT_BY) + OFFSET_Y;
|
||||
|
||||
/** Map containing all the players in game. */
|
||||
private static final Map<Integer, PlayerInstance> _allPlayers = new ConcurrentHashMap<>();
|
||||
@@ -783,9 +783,6 @@ public class World
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the current instance of World
|
||||
*/
|
||||
public static World getInstance()
|
||||
{
|
||||
return SingletonHolder.INSTANCE;
|
||||
|
@@ -191,23 +191,23 @@ public abstract class WorldObject extends ListenersContainer implements IIdentif
|
||||
synchronized (this)
|
||||
{
|
||||
int spawnX = x;
|
||||
if (spawnX > World.MAP_MAX_X)
|
||||
if (spawnX > World.WORLD_X_MAX)
|
||||
{
|
||||
spawnX = World.MAP_MAX_X - 5000;
|
||||
spawnX = World.WORLD_X_MAX - 5000;
|
||||
}
|
||||
if (spawnX < World.MAP_MIN_X)
|
||||
if (spawnX < World.WORLD_X_MIN)
|
||||
{
|
||||
spawnX = World.MAP_MIN_X + 5000;
|
||||
spawnX = World.WORLD_X_MIN + 5000;
|
||||
}
|
||||
|
||||
int spawnY = y;
|
||||
if (spawnY > World.MAP_MAX_Y)
|
||||
if (spawnY > World.WORLD_Y_MAX)
|
||||
{
|
||||
spawnY = World.MAP_MAX_Y - 5000;
|
||||
spawnY = World.WORLD_Y_MAX - 5000;
|
||||
}
|
||||
if (spawnY < World.MAP_MIN_Y)
|
||||
if (spawnY < World.WORLD_Y_MIN)
|
||||
{
|
||||
spawnY = World.MAP_MIN_Y + 5000;
|
||||
spawnY = World.WORLD_Y_MIN + 5000;
|
||||
}
|
||||
|
||||
// Set the x,y,z position of the WorldObject. If flagged with _isSpawned, setXYZ will automatically update world region, so avoid that.
|
||||
@@ -529,23 +529,23 @@ public abstract class WorldObject extends ListenersContainer implements IIdentif
|
||||
public void setXYZInvisible(int x, int y, int z)
|
||||
{
|
||||
int correctX = x;
|
||||
if (correctX > World.MAP_MAX_X)
|
||||
if (correctX > World.WORLD_X_MAX)
|
||||
{
|
||||
correctX = World.MAP_MAX_X - 5000;
|
||||
correctX = World.WORLD_X_MAX - 5000;
|
||||
}
|
||||
if (correctX < World.MAP_MIN_X)
|
||||
if (correctX < World.WORLD_X_MIN)
|
||||
{
|
||||
correctX = World.MAP_MIN_X + 5000;
|
||||
correctX = World.WORLD_X_MIN + 5000;
|
||||
}
|
||||
|
||||
int correctY = y;
|
||||
if (correctY > World.MAP_MAX_Y)
|
||||
if (correctY > World.WORLD_Y_MAX)
|
||||
{
|
||||
correctY = World.MAP_MAX_Y - 5000;
|
||||
correctY = World.WORLD_Y_MAX - 5000;
|
||||
}
|
||||
if (correctY < World.MAP_MIN_Y)
|
||||
if (correctY < World.WORLD_Y_MIN)
|
||||
{
|
||||
correctY = World.MAP_MIN_Y + 5000;
|
||||
correctY = World.WORLD_Y_MIN + 5000;
|
||||
}
|
||||
|
||||
setXYZ(correctX, correctY, z);
|
||||
|
@@ -57,8 +57,6 @@ import org.l2jmobius.gameserver.enums.ShotType;
|
||||
import org.l2jmobius.gameserver.enums.Team;
|
||||
import org.l2jmobius.gameserver.enums.TeleportWhereType;
|
||||
import org.l2jmobius.gameserver.geoengine.GeoEngine;
|
||||
import org.l2jmobius.gameserver.geoengine.GeoEnginePathfinding;
|
||||
import org.l2jmobius.gameserver.geoengine.pathfinding.AbstractNodeLoc;
|
||||
import org.l2jmobius.gameserver.instancemanager.IdManager;
|
||||
import org.l2jmobius.gameserver.instancemanager.InstanceManager;
|
||||
import org.l2jmobius.gameserver.instancemanager.MapRegionManager;
|
||||
@@ -3380,7 +3378,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe
|
||||
|
||||
public boolean disregardingGeodata;
|
||||
public int onGeodataPathIndex;
|
||||
public List<AbstractNodeLoc> geoPath;
|
||||
public List<Location> geoPath;
|
||||
public int geoPathAccurateTx;
|
||||
public int geoPathAccurateTy;
|
||||
public int geoPathGtx;
|
||||
@@ -4340,8 +4338,8 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe
|
||||
final int originalX = x;
|
||||
final int originalY = y;
|
||||
final int originalZ = z;
|
||||
final int gtx = (originalX - World.MAP_MIN_X) >> 4;
|
||||
final int gty = (originalY - World.MAP_MIN_Y) >> 4;
|
||||
final int gtx = (originalX - World.WORLD_X_MIN) >> 4;
|
||||
final int gty = (originalY - World.WORLD_Y_MIN) >> 4;
|
||||
if (isOnGeodataPath())
|
||||
{
|
||||
try
|
||||
@@ -4364,7 +4362,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe
|
||||
&& !(((curZ - z) > 300) && (distance < 300))) // Prohibit correcting destination if character wants to fall.
|
||||
{
|
||||
// location different if destination wasn't reached (or just z coord is different)
|
||||
final Location destiny = GeoEngine.getInstance().canMoveToTargetLoc(curX, curY, curZ, x, y, z, getInstanceId());
|
||||
final Location destiny = GeoEngine.getInstance().getValidLocation(curX, curY, curZ, x, y, z, getInstanceId());
|
||||
x = destiny.getX();
|
||||
y = destiny.getY();
|
||||
z = destiny.getZ();
|
||||
@@ -4378,7 +4376,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe
|
||||
if (((originalDistance - distance) > 30) && !isAfraid() && !isInVehicle)
|
||||
{
|
||||
// Path calculation -- overrides previous movement check
|
||||
m.geoPath = GeoEnginePathfinding.getInstance().findPath(curX, curY, curZ, originalX, originalY, originalZ, getInstanceId());
|
||||
m.geoPath = GeoEngine.getInstance().findPath(curX, curY, curZ, originalX, originalY, originalZ, getInstanceId());
|
||||
if ((m.geoPath == null) || (m.geoPath.size() < 2)) // No path found
|
||||
{
|
||||
if (isPlayer() && !_isFlying && !isInWater)
|
||||
|
@@ -29,7 +29,6 @@ import org.l2jmobius.gameserver.enums.Race;
|
||||
import org.l2jmobius.gameserver.enums.ShotType;
|
||||
import org.l2jmobius.gameserver.enums.Team;
|
||||
import org.l2jmobius.gameserver.geoengine.GeoEngine;
|
||||
import org.l2jmobius.gameserver.geoengine.GeoEnginePathfinding;
|
||||
import org.l2jmobius.gameserver.handler.IItemHandler;
|
||||
import org.l2jmobius.gameserver.handler.ItemHandler;
|
||||
import org.l2jmobius.gameserver.instancemanager.TerritoryWarManager;
|
||||
@@ -107,7 +106,7 @@ public abstract class Summon extends Playable
|
||||
final int x = owner.getX();
|
||||
final int y = owner.getY();
|
||||
final int z = owner.getZ();
|
||||
final Location location = GeoEngine.getInstance().canMoveToTargetLoc(x, y, z, x + Rnd.get(-100, 100), y + Rnd.get(-100, 100), z, owner.getInstanceId());
|
||||
final Location location = GeoEngine.getInstance().getValidLocation(x, y, z, x + Rnd.get(-100, 100), y + Rnd.get(-100, 100), z, owner.getInstanceId());
|
||||
setXYZInvisible(location.getX(), location.getY(), location.getZ());
|
||||
}
|
||||
|
||||
@@ -646,7 +645,7 @@ public abstract class Summon extends Playable
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((this != target) && skill.isPhysical() && Config.PATHFINDING && (GeoEnginePathfinding.getInstance().findPath(getX(), getY(), getZ(), target.getX(), target.getY(), target.getZ(), getInstanceId()) == null))
|
||||
if ((this != target) && skill.isPhysical() && Config.PATHFINDING && (GeoEngine.getInstance().findPath(getX(), getY(), getZ(), target.getX(), target.getY(), target.getZ(), getInstanceId()) == null))
|
||||
{
|
||||
sendPacket(SystemMessageId.CANNOT_SEE_TARGET);
|
||||
return false;
|
||||
|
@@ -8832,7 +8832,7 @@ public class PlayerInstance extends Playable
|
||||
{
|
||||
if (sklTargetType == TargetType.GROUND)
|
||||
{
|
||||
if (!GeoEngine.getInstance().canSeeTarget(this, _currentSkillWorldPosition))
|
||||
if (!GeoEngine.getInstance().canSeeLocation(this, _currentSkillWorldPosition))
|
||||
{
|
||||
sendPacket(SystemMessageId.CANNOT_SEE_TARGET);
|
||||
sendPacket(ActionFailed.STATIC_PACKET);
|
||||
|
@@ -1521,7 +1521,7 @@ public class ItemInstance extends WorldObject
|
||||
|
||||
if (dropper != null)
|
||||
{
|
||||
final Location dropDest = GeoEngine.getInstance().canMoveToTargetLoc(dropper.getX(), dropper.getY(), dropper.getZ(), x, y, z, dropper.getInstanceId());
|
||||
final Location dropDest = GeoEngine.getInstance().getValidLocation(dropper.getX(), dropper.getY(), dropper.getZ(), x, y, z, dropper.getInstanceId());
|
||||
x = dropDest.getX();
|
||||
y = dropDest.getY();
|
||||
z = dropDest.getZ();
|
||||
|
@@ -114,7 +114,7 @@ public class ValidatePosition implements IClientIncomingPacket
|
||||
{
|
||||
if (player.isFalling(_z))
|
||||
{
|
||||
final int nearestZ = GeoEngine.getInstance().getHigherHeight(_x, _y, _z);
|
||||
final int nearestZ = GeoEngine.getInstance().getHeight(_x, _y, _z);
|
||||
if (player.getZ() < nearestZ)
|
||||
{
|
||||
player.setXYZ(_x, _y, nearestZ);
|
||||
|
@@ -19,7 +19,7 @@ package org.l2jmobius.gameserver.util;
|
||||
import java.awt.Color;
|
||||
|
||||
import org.l2jmobius.gameserver.geoengine.GeoEngine;
|
||||
import org.l2jmobius.gameserver.geoengine.geodata.Cell;
|
||||
import org.l2jmobius.gameserver.geoengine.geodata.GeoStructure;
|
||||
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
|
||||
import org.l2jmobius.gameserver.network.serverpackets.ExServerPrimitive;
|
||||
|
||||
@@ -30,21 +30,21 @@ public final class GeoUtils
|
||||
{
|
||||
public static void debug2DLine(PlayerInstance player, int x, int y, int tx, int ty, int z)
|
||||
{
|
||||
final int gx = GeoEngine.getInstance().getGeoX(x);
|
||||
final int gy = GeoEngine.getInstance().getGeoY(y);
|
||||
final int gx = GeoEngine.getGeoX(x);
|
||||
final int gy = GeoEngine.getGeoY(y);
|
||||
|
||||
final int tgx = GeoEngine.getInstance().getGeoX(tx);
|
||||
final int tgy = GeoEngine.getInstance().getGeoY(ty);
|
||||
final int tgx = GeoEngine.getGeoX(tx);
|
||||
final int tgy = GeoEngine.getGeoY(ty);
|
||||
|
||||
final ExServerPrimitive prim = new ExServerPrimitive("Debug2DLine", x, y, z);
|
||||
prim.addLine(Color.BLUE, GeoEngine.getInstance().getWorldX(gx), GeoEngine.getInstance().getWorldY(gy), z, GeoEngine.getInstance().getWorldX(tgx), GeoEngine.getInstance().getWorldY(tgy), z);
|
||||
prim.addLine(Color.BLUE, GeoEngine.getWorldX(gx), GeoEngine.getWorldY(gy), z, GeoEngine.getWorldX(tgx), GeoEngine.getWorldY(tgy), z);
|
||||
|
||||
final LinePointIterator iter = new LinePointIterator(gx, gy, tgx, tgy);
|
||||
|
||||
while (iter.next())
|
||||
{
|
||||
final int wx = GeoEngine.getInstance().getWorldX(iter.x());
|
||||
final int wy = GeoEngine.getInstance().getWorldY(iter.y());
|
||||
final int wx = GeoEngine.getWorldX(iter.x());
|
||||
final int wy = GeoEngine.getWorldY(iter.y());
|
||||
|
||||
prim.addPoint(Color.RED, wx, wy, z);
|
||||
}
|
||||
@@ -53,21 +53,21 @@ public final class GeoUtils
|
||||
|
||||
public static void debug3DLine(PlayerInstance player, int x, int y, int z, int tx, int ty, int tz)
|
||||
{
|
||||
final int gx = GeoEngine.getInstance().getGeoX(x);
|
||||
final int gy = GeoEngine.getInstance().getGeoY(y);
|
||||
final int gx = GeoEngine.getGeoX(x);
|
||||
final int gy = GeoEngine.getGeoY(y);
|
||||
|
||||
final int tgx = GeoEngine.getInstance().getGeoX(tx);
|
||||
final int tgy = GeoEngine.getInstance().getGeoY(ty);
|
||||
final int tgx = GeoEngine.getGeoX(tx);
|
||||
final int tgy = GeoEngine.getGeoY(ty);
|
||||
|
||||
final ExServerPrimitive prim = new ExServerPrimitive("Debug3DLine", x, y, z);
|
||||
prim.addLine(Color.BLUE, GeoEngine.getInstance().getWorldX(gx), GeoEngine.getInstance().getWorldY(gy), z, GeoEngine.getInstance().getWorldX(tgx), GeoEngine.getInstance().getWorldY(tgy), tz);
|
||||
prim.addLine(Color.BLUE, GeoEngine.getWorldX(gx), GeoEngine.getWorldY(gy), z, GeoEngine.getWorldX(tgx), GeoEngine.getWorldY(tgy), tz);
|
||||
|
||||
final LinePointIterator3D iter = new LinePointIterator3D(gx, gy, z, tgx, tgy, tz);
|
||||
iter.next();
|
||||
int prevX = iter.x();
|
||||
int prevY = iter.y();
|
||||
int wx = GeoEngine.getInstance().getWorldX(prevX);
|
||||
int wy = GeoEngine.getInstance().getWorldY(prevY);
|
||||
int wx = GeoEngine.getWorldX(prevX);
|
||||
int wy = GeoEngine.getWorldY(prevY);
|
||||
int wz = iter.z();
|
||||
prim.addPoint(Color.RED, wx, wy, wz);
|
||||
|
||||
@@ -78,8 +78,8 @@ public final class GeoUtils
|
||||
|
||||
if ((curX != prevX) || (curY != prevY))
|
||||
{
|
||||
wx = GeoEngine.getInstance().getWorldX(curX);
|
||||
wy = GeoEngine.getInstance().getWorldY(curY);
|
||||
wx = GeoEngine.getWorldX(curX);
|
||||
wy = GeoEngine.getWorldY(curY);
|
||||
wz = iter.z();
|
||||
|
||||
prim.addPoint(Color.RED, wx, wy, wz);
|
||||
@@ -93,7 +93,7 @@ public final class GeoUtils
|
||||
|
||||
private static Color getDirectionColor(int x, int y, int z, int nswe)
|
||||
{
|
||||
if (GeoEngine.getInstance().checkNearestNswe(x, y, z, nswe))
|
||||
if ((GeoEngine.getInstance().getNsweNearest(x, y, z) & nswe) != 0)
|
||||
{
|
||||
return Color.GREEN;
|
||||
}
|
||||
@@ -109,9 +109,8 @@ public final class GeoUtils
|
||||
int iPacket = 0;
|
||||
|
||||
ExServerPrimitive exsp = null;
|
||||
final GeoEngine ge = GeoEngine.getInstance();
|
||||
final int playerGx = ge.getGeoX(player.getX());
|
||||
final int playerGy = ge.getGeoY(player.getY());
|
||||
final int playerGx = GeoEngine.getGeoX(player.getX());
|
||||
final int playerGy = GeoEngine.getGeoY(player.getY());
|
||||
for (int dx = -geoRadius; dx <= geoRadius; ++dx)
|
||||
{
|
||||
for (int dy = -geoRadius; dy <= geoRadius; ++dy)
|
||||
@@ -135,32 +134,32 @@ public final class GeoUtils
|
||||
final int gx = playerGx + dx;
|
||||
final int gy = playerGy + dy;
|
||||
|
||||
final int x = ge.getWorldX(gx);
|
||||
final int y = ge.getWorldY(gy);
|
||||
final int z = ge.getNearestZ(gx, gy, player.getZ());
|
||||
final int x = GeoEngine.getWorldX(gx);
|
||||
final int y = GeoEngine.getWorldY(gy);
|
||||
final int z = GeoEngine.getInstance().getHeightNearest(gx, gy, player.getZ());
|
||||
|
||||
// north arrow
|
||||
Color col = getDirectionColor(gx, gy, z, Cell.NSWE_NORTH);
|
||||
Color col = getDirectionColor(gx, gy, z, GeoStructure.CELL_FLAG_N);
|
||||
exsp.addLine(col, x - 1, y - 7, z, x + 1, y - 7, z);
|
||||
exsp.addLine(col, x - 2, y - 6, z, x + 2, y - 6, z);
|
||||
exsp.addLine(col, x - 3, y - 5, z, x + 3, y - 5, z);
|
||||
exsp.addLine(col, x - 4, y - 4, z, x + 4, y - 4, z);
|
||||
|
||||
// east arrow
|
||||
col = getDirectionColor(gx, gy, z, Cell.NSWE_EAST);
|
||||
col = getDirectionColor(gx, gy, z, GeoStructure.CELL_FLAG_E);
|
||||
exsp.addLine(col, x + 7, y - 1, z, x + 7, y + 1, z);
|
||||
exsp.addLine(col, x + 6, y - 2, z, x + 6, y + 2, z);
|
||||
exsp.addLine(col, x + 5, y - 3, z, x + 5, y + 3, z);
|
||||
exsp.addLine(col, x + 4, y - 4, z, x + 4, y + 4, z);
|
||||
|
||||
// south arrow
|
||||
col = getDirectionColor(gx, gy, z, Cell.NSWE_SOUTH);
|
||||
col = getDirectionColor(gx, gy, z, GeoStructure.CELL_FLAG_S);
|
||||
exsp.addLine(col, x - 1, y + 7, z, x + 1, y + 7, z);
|
||||
exsp.addLine(col, x - 2, y + 6, z, x + 2, y + 6, z);
|
||||
exsp.addLine(col, x - 3, y + 5, z, x + 3, y + 5, z);
|
||||
exsp.addLine(col, x - 4, y + 4, z, x + 4, y + 4, z);
|
||||
|
||||
col = getDirectionColor(gx, gy, z, Cell.NSWE_WEST);
|
||||
col = getDirectionColor(gx, gy, z, GeoStructure.CELL_FLAG_W);
|
||||
exsp.addLine(col, x - 7, y - 1, z, x - 7, y + 1, z);
|
||||
exsp.addLine(col, x - 6, y - 2, z, x - 6, y + 2, z);
|
||||
exsp.addLine(col, x - 5, y - 3, z, x - 5, y + 3, z);
|
||||
@@ -188,41 +187,41 @@ public final class GeoUtils
|
||||
{
|
||||
if (y > lastY)
|
||||
{
|
||||
return Cell.NSWE_SOUTH_EAST;
|
||||
return GeoStructure.CELL_FLAG_S & GeoStructure.CELL_FLAG_E;
|
||||
}
|
||||
else if (y < lastY)
|
||||
{
|
||||
return Cell.NSWE_NORTH_EAST;
|
||||
return GeoStructure.CELL_FLAG_N & GeoStructure.CELL_FLAG_E;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Cell.NSWE_EAST;
|
||||
return GeoStructure.CELL_FLAG_E;
|
||||
}
|
||||
}
|
||||
else if (x < lastX) // west
|
||||
{
|
||||
if (y > lastY)
|
||||
{
|
||||
return Cell.NSWE_SOUTH_WEST;
|
||||
return GeoStructure.CELL_FLAG_S & GeoStructure.CELL_FLAG_W;
|
||||
}
|
||||
else if (y < lastY)
|
||||
{
|
||||
return Cell.NSWE_NORTH_WEST;
|
||||
return GeoStructure.CELL_FLAG_N & GeoStructure.CELL_FLAG_W;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Cell.NSWE_WEST;
|
||||
return GeoStructure.CELL_FLAG_W;
|
||||
}
|
||||
}
|
||||
else // unchanged x
|
||||
{
|
||||
if (y > lastY)
|
||||
{
|
||||
return Cell.NSWE_SOUTH;
|
||||
return GeoStructure.CELL_FLAG_S;
|
||||
}
|
||||
else if (y < lastY)
|
||||
{
|
||||
return Cell.NSWE_NORTH;
|
||||
return GeoStructure.CELL_FLAG_N;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
Reference in New Issue
Block a user