New l2j geoengine rework.
This commit is contained in:
parent
fb5a0626cd
commit
061bc41de8
@ -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.
|
||||
|
@ -295,7 +295,7 @@ public class FourSepulchers extends AbstractNpcAI implements IXmlReader
|
||||
{
|
||||
if ((npc != null) && !npc.isDead())
|
||||
{
|
||||
final Location destination = GeoEngine.getInstance().canMoveToTargetLoc(npc.getX(), npc.getY(), npc.getZ(), npc.getSpawn().getLocation().getX() + getRandom(-400, 400), npc.getSpawn().getLocation().getY() + getRandom(-400, 400), npc.getZ(), npc.getInstanceWorld());
|
||||
final Location destination = GeoEngine.getInstance().getValidLocation(npc.getX(), npc.getY(), npc.getZ(), npc.getSpawn().getLocation().getX() + getRandom(-400, 400), npc.getSpawn().getLocation().getY() + getRandom(-400, 400), npc.getZ(), npc.getInstanceWorld());
|
||||
if (Util.calculateDistance(npc, npc.getSpawn().getLocation(), false, false) < 600)
|
||||
{
|
||||
npc.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, destination);
|
||||
|
@ -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.getInstanceWorld());
|
||||
final Location loc = GeoEngine.getInstance().getValidLocation(npc.getX(), npc.getY(), npc.getZ(), newX, newY, npc.getZ(), npc.getInstanceWorld());
|
||||
npc.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, loc, 0);
|
||||
}
|
||||
else if (ag_type == 1)
|
||||
|
@ -78,7 +78,7 @@ public class BoyAndGirl extends AbstractNpcAI
|
||||
startQuestTimer("NPC_SHOUT", 10000 + (getRandom(5) * 1000), npc, null);
|
||||
npc.setRunning();
|
||||
final Location randomLoc = Util.getRandomPosition(npc.getSpawn().getLocation(), 200, 600);
|
||||
addMoveToDesire(npc, GeoEngine.getInstance().canMoveToTargetLoc(npc.getLocation().getX(), npc.getLocation().getY(), npc.getLocation().getZ(), randomLoc.getX(), randomLoc.getY(), randomLoc.getZ(), npc.getInstanceWorld()), 23);
|
||||
addMoveToDesire(npc, GeoEngine.getInstance().getValidLocation(npc.getLocation().getX(), npc.getLocation().getY(), npc.getLocation().getZ(), randomLoc.getX(), randomLoc.getY(), randomLoc.getZ(), npc.getInstanceWorld()), 23);
|
||||
return super.onSpawn(npc);
|
||||
}
|
||||
|
||||
@ -86,7 +86,7 @@ public class BoyAndGirl extends AbstractNpcAI
|
||||
public void onMoveFinished(Npc npc)
|
||||
{
|
||||
final Location randomLoc = Util.getRandomPosition(npc.getSpawn().getLocation(), 200, 600);
|
||||
addMoveToDesire(npc, GeoEngine.getInstance().canMoveToTargetLoc(npc.getLocation().getX(), npc.getLocation().getY(), npc.getLocation().getZ(), randomLoc.getX(), randomLoc.getY(), randomLoc.getZ(), npc.getInstanceWorld()), 23);
|
||||
addMoveToDesire(npc, GeoEngine.getInstance().getValidLocation(npc.getLocation().getX(), npc.getLocation().getY(), npc.getLocation().getZ(), randomLoc.getX(), randomLoc.getY(), randomLoc.getZ(), npc.getInstanceWorld()), 23);
|
||||
super.onMoveFinished(npc);
|
||||
}
|
||||
|
||||
|
@ -48,7 +48,7 @@ public class Devno extends AbstractNpcAI
|
||||
if (getRandomBoolean())
|
||||
{
|
||||
final Location randomLoc = Util.getRandomPosition(npc.getSpawn().getLocation(), 0, 500);
|
||||
addMoveToDesire(npc, GeoEngine.getInstance().canMoveToTargetLoc(npc.getLocation().getX(), npc.getLocation().getY(), npc.getLocation().getZ(), randomLoc.getX(), randomLoc.getY(), randomLoc.getZ(), npc.getInstanceWorld()), 23);
|
||||
addMoveToDesire(npc, GeoEngine.getInstance().getValidLocation(npc.getLocation().getX(), npc.getLocation().getY(), npc.getLocation().getZ(), randomLoc.getX(), randomLoc.getY(), randomLoc.getZ(), npc.getInstanceWorld()), 23);
|
||||
}
|
||||
startQuestTimer("NPC_MOVE", (10 + getRandom(5)) * 1000, npc, null);
|
||||
}
|
||||
|
@ -48,7 +48,7 @@ public class Eleve extends AbstractNpcAI
|
||||
if (getRandomBoolean())
|
||||
{
|
||||
final Location randomLoc = Util.getRandomPosition(npc.getSpawn().getLocation(), 0, 500);
|
||||
addMoveToDesire(npc, GeoEngine.getInstance().canMoveToTargetLoc(npc.getLocation().getX(), npc.getLocation().getY(), npc.getLocation().getZ(), randomLoc.getX(), randomLoc.getY(), randomLoc.getZ(), npc.getInstanceWorld()), 23);
|
||||
addMoveToDesire(npc, GeoEngine.getInstance().getValidLocation(npc.getLocation().getX(), npc.getLocation().getY(), npc.getLocation().getZ(), randomLoc.getX(), randomLoc.getY(), randomLoc.getZ(), npc.getInstanceWorld()), 23);
|
||||
}
|
||||
startQuestTimer("NPC_MOVE", (10 + getRandom(5)) * 1000, npc, null);
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ public class Handermonkey extends AbstractNpcAI
|
||||
{
|
||||
final int x = npc.getSpawn().getX() + (getRandom(-100, 100));
|
||||
final int y = npc.getSpawn().getY() + (getRandom(-100, 100));
|
||||
final Location loc = GeoEngine.getInstance().canMoveToTargetLoc(npc.getX(), npc.getY(), npc.getZ(), x, y, npc.getZ(), npc.getInstanceWorld());
|
||||
final Location loc = GeoEngine.getInstance().getValidLocation(npc.getX(), npc.getY(), npc.getZ(), x, y, npc.getZ(), npc.getInstanceWorld());
|
||||
addMoveToDesire(npc, loc, 0);
|
||||
}
|
||||
else
|
||||
|
@ -48,7 +48,7 @@ public class Karonf extends AbstractNpcAI
|
||||
if (getRandomBoolean())
|
||||
{
|
||||
final Location randomLoc = Util.getRandomPosition(npc.getSpawn().getLocation(), 0, 500);
|
||||
addMoveToDesire(npc, GeoEngine.getInstance().canMoveToTargetLoc(npc.getLocation().getX(), npc.getLocation().getY(), npc.getLocation().getZ(), randomLoc.getX(), randomLoc.getY(), randomLoc.getZ(), npc.getInstanceWorld()), 23);
|
||||
addMoveToDesire(npc, GeoEngine.getInstance().getValidLocation(npc.getLocation().getX(), npc.getLocation().getY(), npc.getLocation().getZ(), randomLoc.getX(), randomLoc.getY(), randomLoc.getZ(), npc.getInstanceWorld()), 23);
|
||||
}
|
||||
startQuestTimer("NPC_MOVE", (10 + getRandom(5)) * 1000, npc, null);
|
||||
}
|
||||
|
@ -48,7 +48,7 @@ public class Marsha extends AbstractNpcAI
|
||||
if (getRandomBoolean())
|
||||
{
|
||||
final Location randomLoc = Util.getRandomPosition(npc.getSpawn().getLocation(), 0, 500);
|
||||
addMoveToDesire(npc, GeoEngine.getInstance().canMoveToTargetLoc(npc.getLocation().getX(), npc.getLocation().getY(), npc.getLocation().getZ(), randomLoc.getX(), randomLoc.getY(), randomLoc.getZ(), npc.getInstanceWorld()), 23);
|
||||
addMoveToDesire(npc, GeoEngine.getInstance().getValidLocation(npc.getLocation().getX(), npc.getLocation().getY(), npc.getLocation().getZ(), randomLoc.getX(), randomLoc.getY(), randomLoc.getZ(), npc.getInstanceWorld()), 23);
|
||||
}
|
||||
startQuestTimer("NPC_MOVE", (10 + getRandom(5)) * 1000, npc, null);
|
||||
}
|
||||
|
@ -48,7 +48,7 @@ public class Morgan extends AbstractNpcAI
|
||||
if (getRandomBoolean())
|
||||
{
|
||||
final Location randomLoc = Util.getRandomPosition(npc.getSpawn().getLocation(), 0, 500);
|
||||
addMoveToDesire(npc, GeoEngine.getInstance().canMoveToTargetLoc(npc.getLocation().getX(), npc.getLocation().getY(), npc.getLocation().getZ(), randomLoc.getX(), randomLoc.getY(), randomLoc.getZ(), npc.getInstanceWorld()), 23);
|
||||
addMoveToDesire(npc, GeoEngine.getInstance().getValidLocation(npc.getLocation().getX(), npc.getLocation().getY(), npc.getLocation().getZ(), randomLoc.getX(), randomLoc.getY(), randomLoc.getZ(), npc.getInstanceWorld()), 23);
|
||||
}
|
||||
startQuestTimer("NPC_MOVE", (10 + getRandom(5)) * 1000, npc, null);
|
||||
}
|
||||
|
@ -48,7 +48,7 @@ public class Rubentis extends AbstractNpcAI
|
||||
if (getRandomBoolean())
|
||||
{
|
||||
final Location randomLoc = Util.getRandomPosition(npc.getSpawn().getLocation(), 0, 500);
|
||||
addMoveToDesire(npc, GeoEngine.getInstance().canMoveToTargetLoc(npc.getLocation().getX(), npc.getLocation().getY(), npc.getLocation().getZ(), randomLoc.getX(), randomLoc.getY(), randomLoc.getZ(), npc.getInstanceWorld()), 23);
|
||||
addMoveToDesire(npc, GeoEngine.getInstance().getValidLocation(npc.getLocation().getX(), npc.getLocation().getY(), npc.getLocation().getZ(), randomLoc.getX(), randomLoc.getY(), randomLoc.getZ(), npc.getInstanceWorld()), 23);
|
||||
}
|
||||
startQuestTimer("NPC_MOVE", 10000 + (getRandom(5) * 1000), npc, null);
|
||||
}
|
||||
|
@ -63,7 +63,7 @@ public class Vortex extends AbstractNpcAI
|
||||
final int x = (int) (attackers.getX() + (600 * Math.cos(radians)));
|
||||
final int y = (int) (attackers.getY() + (600 * Math.sin(radians)));
|
||||
final int z = attackers.getZ();
|
||||
final Location loc = GeoEngine.getInstance().canMoveToTargetLoc(attackers.getX(), attackers.getY(), attackers.getZ(), x, y, z, attackers.getInstanceWorld());
|
||||
final Location loc = GeoEngine.getInstance().getValidLocation(attackers.getX(), attackers.getY(), attackers.getZ(), x, y, z, attackers.getInstanceWorld());
|
||||
attackers.broadcastPacket(new FlyToLocation(attackers, x, y, z, FlyToLocation.FlyType.THROW_UP, 800, 800, 800));
|
||||
attackers.setXYZ(loc);
|
||||
attackers.broadcastPacket(new ValidateLocation(attackers));
|
||||
|
@ -68,7 +68,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.getInstanceWorld());
|
||||
final Location destination = GeoEngine.getInstance().getValidLocation(npc.getX(), npc.getY(), npc.getZ(), posX, posY, posZ, npc.getInstanceWorld());
|
||||
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;
|
||||
}
|
||||
|
@ -57,8 +57,8 @@ public class AdminMissingHtmls implements IAdminCommandHandler
|
||||
{
|
||||
case "admin_geomap_missing_htmls":
|
||||
{
|
||||
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;
|
||||
final int topLeftX = (x - World.TILE_ZERO_COORD_X) * World.TILE_SIZE;
|
||||
final int topLeftY = (y - World.TILE_ZERO_COORD_Y) * World.TILE_SIZE;
|
||||
final int bottomRightX = (((x - World.TILE_ZERO_COORD_X) * World.TILE_SIZE) + World.TILE_SIZE) - 1;
|
||||
|
@ -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.getInstanceWorld());
|
||||
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.getInstanceWorld());
|
||||
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());
|
||||
}
|
||||
|
@ -88,7 +88,7 @@ public class Blink extends AbstractEffect
|
||||
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.getInstanceWorld());
|
||||
final Location destination = GeoEngine.getInstance().getValidLocation(effected.getX(), effected.getY(), effected.getZ(), x, y, z, effected.getInstanceWorld());
|
||||
|
||||
effected.getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
|
||||
effected.broadcastPacket(new FlyToLocation(effected, destination, _flyType, _flySpeed, _flyDelay, _animationSpeed));
|
||||
|
@ -100,7 +100,7 @@ public class Fear extends AbstractEffect
|
||||
final int posY = (int) (effected.getY() + (FEAR_RANGE * Math.sin(radians)));
|
||||
final int posZ = effected.getZ();
|
||||
|
||||
final Location destination = GeoEngine.getInstance().canMoveToTargetLoc(effected.getX(), effected.getY(), effected.getZ(), posX, posY, posZ, effected.getInstanceWorld());
|
||||
final Location destination = GeoEngine.getInstance().getValidLocation(effected.getX(), effected.getY(), effected.getZ(), posX, posY, posZ, effected.getInstanceWorld());
|
||||
effected.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, destination);
|
||||
}
|
||||
}
|
||||
|
@ -57,7 +57,7 @@ public class FlyAway extends AbstractEffect
|
||||
final int y = (int) (effector.getY() - (nRadius * (dy / distance)));
|
||||
final int z = effector.getZ();
|
||||
|
||||
final Location destination = GeoEngine.getInstance().canMoveToTargetLoc(effected.getX(), effected.getY(), effected.getZ(), x, y, z, effected.getInstanceWorld());
|
||||
final Location destination = GeoEngine.getInstance().getValidLocation(effected.getX(), effected.getY(), effected.getZ(), x, y, z, effected.getInstanceWorld());
|
||||
|
||||
effected.broadcastPacket(new FlyToLocation(effected, destination, FlyType.THROW_UP));
|
||||
effected.setXYZ(destination);
|
||||
|
@ -179,7 +179,7 @@ public class KnockBack extends AbstractEffect
|
||||
final int x = (int) (effected.getX() + (_distance * Math.cos(radians)));
|
||||
final int y = (int) (effected.getY() + (_distance * Math.sin(radians)));
|
||||
final int z = effected.getZ();
|
||||
final Location loc = GeoEngine.getInstance().canMoveToTargetLoc(effected.getX(), effected.getY(), effected.getZ(), x, y, z, effected.getInstanceWorld());
|
||||
final Location loc = GeoEngine.getInstance().getValidLocation(effected.getX(), effected.getY(), effected.getZ(), x, y, z, effected.getInstanceWorld());
|
||||
|
||||
effected.getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
|
||||
effected.broadcastPacket(new FlyToLocation(effected, loc, _type, _speed, _delay, _animationSpeed));
|
||||
|
@ -73,7 +73,7 @@ public class PullBack extends AbstractEffect
|
||||
}
|
||||
|
||||
// In retail, you get debuff, but you are not even moved if there is obstacle. You are still disabled from using skills and moving though.
|
||||
if (GeoEngine.getInstance().canMoveToTarget(effected.getX(), effected.getY(), effected.getZ(), effector.getX(), effector.getY(), effector.getZ(), effector.getInstanceWorld()))
|
||||
if (GeoEngine.getInstance().canMoveToTarget(effected.getX(), effected.getY(), effected.getZ(), effector.getX(), effector.getY(), effector.getZ(), effected.getInstanceWorld()))
|
||||
{
|
||||
effected.broadcastPacket(new FlyToLocation(effected, effector, _type, _speed, _delay, _animationSpeed));
|
||||
effected.setXYZ(effector.getX(), effector.getY(), GeoEngine.getInstance().getHeight(effector.getX(), effector.getY(), effector.getZ()) + 10);
|
||||
|
@ -87,7 +87,7 @@ public class TeleportToSummon extends AbstractEffect
|
||||
final int y = (int) (py + (25 * Math.sin(ph)));
|
||||
final int z = summon.getZ();
|
||||
|
||||
final Location loc = GeoEngine.getInstance().canMoveToTargetLoc(effector.getX(), effector.getY(), effector.getZ(), x, y, z, effector.getInstanceWorld());
|
||||
final Location loc = GeoEngine.getInstance().getValidLocation(effector.getX(), effector.getY(), effector.getZ(), x, y, z,effector.getInstanceWorld());
|
||||
|
||||
effector.getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
|
||||
effector.broadcastPacket(new FlyToLocation(effector, loc.getX(), loc.getY(), loc.getZ(), FlyType.DUMMY));
|
||||
|
@ -76,7 +76,7 @@ public class TeleportToTarget extends AbstractEffect
|
||||
final int y = (int) (py + (25 * Math.sin(ph)));
|
||||
final int z = effected.getZ();
|
||||
|
||||
final Location loc = GeoEngine.getInstance().canMoveToTargetLoc(effector.getX(), effector.getY(), effector.getZ(), x, y, z, effector.getInstanceWorld());
|
||||
final Location loc = GeoEngine.getInstance().getValidLocation(effector.getX(), effector.getY(), effector.getZ(), x, y, z,effector.getInstanceWorld());
|
||||
|
||||
effector.getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
|
||||
effector.broadcastPacket(new FlyToLocation(effector, loc.getX(), loc.getY(), loc.getZ(), FlyType.DUMMY));
|
||||
|
@ -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.getInstanceWorld());
|
||||
final Location destination = GeoEngine.getInstance().getValidLocation(player.getX(), player.getY(), player.getZ(), x, y, z, player.getInstanceWorld());
|
||||
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);
|
||||
|
@ -52,7 +52,7 @@ public class Ground implements ITargetTypeHandler
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!GeoEngine.getInstance().canSeeTarget(creature, worldPosition))
|
||||
if (!GeoEngine.getInstance().canSeeLocation(creature, worldPosition))
|
||||
{
|
||||
if (sendMessage)
|
||||
{
|
||||
|
@ -61,6 +61,7 @@ import org.l2jmobius.commons.util.PropertiesParser;
|
||||
import org.l2jmobius.commons.util.StringUtil;
|
||||
import org.l2jmobius.gameserver.enums.ChatType;
|
||||
import org.l2jmobius.gameserver.enums.ClassId;
|
||||
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;
|
||||
@ -932,12 +933,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;
|
||||
|
||||
/** Attribute System */
|
||||
public static int S_WEAPON_STONE;
|
||||
@ -2469,12 +2475,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);
|
||||
|
@ -584,4 +584,15 @@ public class CommonUtil
|
||||
final DecimalFormat formatter = new DecimalFormat(format, new DecimalFormatSymbols(Locale.ENGLISH));
|
||||
return formatter.format(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @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;
|
||||
}
|
||||
}
|
@ -578,7 +578,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.getInstanceWorld());
|
||||
final Location moveLoc = _actor.isFlying() ? new Location(x1, y1, z1) : GeoEngine.getInstance().getValidLocation(npc.getX(), npc.getY(), npc.getZ(), x1, y1, z1, npc.getInstanceWorld());
|
||||
moveTo(moveLoc.getX(), moveLoc.getY(), moveLoc.getZ());
|
||||
}
|
||||
}
|
||||
@ -801,7 +801,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.getInstanceWorld()));
|
||||
moveTo(GeoEngine.getInstance().getValidLocation(npc.getX(), npc.getY(), npc.getZ(), newX, newY, newZ, npc.getInstanceWorld()));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -114,8 +114,8 @@ public class SpawnTable
|
||||
}
|
||||
|
||||
// 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
|
||||
@ -192,8 +192,8 @@ public class SpawnTable
|
||||
|
||||
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 File spawnFile = spawn.getNpcSpawnTemplate() != null ? spawn.getNpcSpawnTemplate().getSpawnTemplate().getFile() : new File(OTHER_XML_FOLDER + "/" + x + "_" + y + ".xml");
|
||||
final File tempFile = new File(spawnFile.getAbsolutePath().substring(Config.DATAPACK_ROOT.getAbsolutePath().length() + 1).replace('\\', '/') + ".tmp");
|
||||
try
|
||||
|
@ -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,301 +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;
|
||||
import org.l2jmobius.gameserver.model.instancezone.Instance;
|
||||
|
||||
/**
|
||||
* @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, Instance instance)
|
||||
{
|
||||
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(), instance))
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
@ -93,15 +93,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, SpawnTerritory> _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.
|
||||
|
@ -16,30 +16,30 @@
|
||||
*/
|
||||
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) 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;
|
||||
protected volatile int _z;
|
||||
protected volatile int _heading;
|
||||
|
||||
public Location(int x, int y, int z)
|
||||
{
|
||||
this(x, y, z, 0);
|
||||
super(x, y);
|
||||
_z = z;
|
||||
_heading = 0;
|
||||
}
|
||||
|
||||
public Location(int x, int y, int z, int heading)
|
||||
{
|
||||
_x = x;
|
||||
_y = y;
|
||||
super(x, y);
|
||||
_z = z;
|
||||
_heading = heading;
|
||||
}
|
||||
@ -51,9 +51,8 @@ public class Location implements IPositionable
|
||||
|
||||
public Location(StatSet set)
|
||||
{
|
||||
_x = set.getInt("x");
|
||||
_y = set.getInt("y");
|
||||
_z = set.getInt("z");
|
||||
super(set.getInt("x", 0), set.getInt("y", 0));
|
||||
_z = set.getInt("z", 0);
|
||||
_heading = set.getInt("heading", 0);
|
||||
}
|
||||
|
||||
@ -146,6 +145,25 @@ public class Location implements IPositionable
|
||||
_heading = loc.getHeading();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clean()
|
||||
{
|
||||
super.clean();
|
||||
_z = 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)
|
||||
{
|
||||
|
@ -66,19 +66,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<>();
|
||||
@ -817,9 +817,6 @@ public class World
|
||||
return _memberInPartyNumber.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the current instance of World
|
||||
*/
|
||||
public static World getInstance()
|
||||
{
|
||||
return SingletonHolder.INSTANCE;
|
||||
|
@ -188,23 +188,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.
|
||||
@ -518,23 +518,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);
|
||||
|
@ -65,8 +65,6 @@ import org.l2jmobius.gameserver.enums.Team;
|
||||
import org.l2jmobius.gameserver.enums.TeleportWhereType;
|
||||
import org.l2jmobius.gameserver.enums.UserInfoType;
|
||||
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.MapRegionManager;
|
||||
import org.l2jmobius.gameserver.instancemanager.QuestManager;
|
||||
@ -2585,7 +2583,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;
|
||||
@ -3406,8 +3404,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
|
||||
@ -3430,7 +3428,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, getInstanceWorld());
|
||||
final Location destiny = GeoEngine.getInstance().getValidLocation(curX, curY, curZ, x, y, z, getInstanceWorld());
|
||||
x = destiny.getX();
|
||||
y = destiny.getY();
|
||||
z = destiny.getZ();
|
||||
@ -3444,7 +3442,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe
|
||||
if (((originalDistance - distance) > 30) && !isControlBlocked() && !isInVehicle)
|
||||
{
|
||||
// Path calculation -- overrides previous movement check
|
||||
m.geoPath = GeoEnginePathfinding.getInstance().findPath(curX, curY, curZ, originalX, originalY, originalZ, getInstanceWorld());
|
||||
m.geoPath = GeoEngine.getInstance().findPath(curX, curY, curZ, originalX, originalY, originalZ, getInstanceWorld());
|
||||
if ((m.geoPath == null) || (m.geoPath.size() < 2)) // No path found
|
||||
{
|
||||
if (isPlayer() && !_isFlying && !isInWater)
|
||||
|
@ -106,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.getInstanceWorld());
|
||||
final Location location = GeoEngine.getInstance().getValidLocation(x, y, z, x + Rnd.get(-100, 100), y + Rnd.get(-100, 100), z, getInstanceWorld());
|
||||
setXYZInvisible(location.getX(), location.getY(), location.getZ());
|
||||
}
|
||||
|
||||
|
@ -1502,7 +1502,7 @@ public class ItemInstance extends WorldObject
|
||||
if (dropper != null)
|
||||
{
|
||||
final Instance instance = dropper.getInstanceWorld();
|
||||
final Location dropDest = GeoEngine.getInstance().canMoveToTargetLoc(dropper.getX(), dropper.getY(), dropper.getZ(), x, y, z, instance);
|
||||
final Location dropDest = GeoEngine.getInstance().getValidLocation(dropper.getX(), dropper.getY(), dropper.getZ(), x, y, z, instance);
|
||||
x = dropDest.getX();
|
||||
y = dropDest.getY();
|
||||
z = dropDest.getZ();
|
||||
|
@ -1179,7 +1179,7 @@ public class SkillCaster implements Runnable
|
||||
}
|
||||
}
|
||||
|
||||
final Location destination = creature.isFlying() ? new Location(x, y, z) : GeoEngine.getInstance().canMoveToTargetLoc(creature.getX(), creature.getY(), creature.getZ(), x, y, z, creature.getInstanceWorld());
|
||||
final Location destination = creature.isFlying() ? new Location(x, y, z) : GeoEngine.getInstance().getValidLocation(creature.getX(), creature.getY(), creature.getZ(), x, y, z, creature.getInstanceWorld());
|
||||
creature.getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
|
||||
creature.broadcastPacket(new FlyToLocation(creature, destination, flyType, 0, 0, 333));
|
||||
creature.setXYZ(destination);
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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.
|
||||
|
@ -295,7 +295,7 @@ public class FourSepulchers extends AbstractNpcAI implements IXmlReader
|
||||
{
|
||||
if ((npc != null) && !npc.isDead())
|
||||
{
|
||||
final Location destination = GeoEngine.getInstance().canMoveToTargetLoc(npc.getX(), npc.getY(), npc.getZ(), npc.getSpawn().getLocation().getX() + getRandom(-400, 400), npc.getSpawn().getLocation().getY() + getRandom(-400, 400), npc.getZ(), npc.getInstanceWorld());
|
||||
final Location destination = GeoEngine.getInstance().getValidLocation(npc.getX(), npc.getY(), npc.getZ(), npc.getSpawn().getLocation().getX() + getRandom(-400, 400), npc.getSpawn().getLocation().getY() + getRandom(-400, 400), npc.getZ(), npc.getInstanceWorld());
|
||||
if (Util.calculateDistance(npc, npc.getSpawn().getLocation(), false, false) < 600)
|
||||
{
|
||||
npc.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, destination);
|
||||
|
@ -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.getInstanceWorld());
|
||||
final Location loc = GeoEngine.getInstance().getValidLocation(npc.getX(), npc.getY(), npc.getZ(), newX, newY, npc.getZ(), npc.getInstanceWorld());
|
||||
npc.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, loc, 0);
|
||||
}
|
||||
else if (ag_type == 1)
|
||||
|
@ -78,7 +78,7 @@ public class BoyAndGirl extends AbstractNpcAI
|
||||
startQuestTimer("NPC_SHOUT", 10000 + (getRandom(5) * 1000), npc, null);
|
||||
npc.setRunning();
|
||||
final Location randomLoc = Util.getRandomPosition(npc.getSpawn().getLocation(), 200, 600);
|
||||
addMoveToDesire(npc, GeoEngine.getInstance().canMoveToTargetLoc(npc.getLocation().getX(), npc.getLocation().getY(), npc.getLocation().getZ(), randomLoc.getX(), randomLoc.getY(), randomLoc.getZ(), npc.getInstanceWorld()), 23);
|
||||
addMoveToDesire(npc, GeoEngine.getInstance().getValidLocation(npc.getLocation().getX(), npc.getLocation().getY(), npc.getLocation().getZ(), randomLoc.getX(), randomLoc.getY(), randomLoc.getZ(), npc.getInstanceWorld()), 23);
|
||||
return super.onSpawn(npc);
|
||||
}
|
||||
|
||||
@ -86,7 +86,7 @@ public class BoyAndGirl extends AbstractNpcAI
|
||||
public void onMoveFinished(Npc npc)
|
||||
{
|
||||
final Location randomLoc = Util.getRandomPosition(npc.getSpawn().getLocation(), 200, 600);
|
||||
addMoveToDesire(npc, GeoEngine.getInstance().canMoveToTargetLoc(npc.getLocation().getX(), npc.getLocation().getY(), npc.getLocation().getZ(), randomLoc.getX(), randomLoc.getY(), randomLoc.getZ(), npc.getInstanceWorld()), 23);
|
||||
addMoveToDesire(npc, GeoEngine.getInstance().getValidLocation(npc.getLocation().getX(), npc.getLocation().getY(), npc.getLocation().getZ(), randomLoc.getX(), randomLoc.getY(), randomLoc.getZ(), npc.getInstanceWorld()), 23);
|
||||
super.onMoveFinished(npc);
|
||||
}
|
||||
|
||||
|
@ -48,7 +48,7 @@ public class Devno extends AbstractNpcAI
|
||||
if (getRandomBoolean())
|
||||
{
|
||||
final Location randomLoc = Util.getRandomPosition(npc.getSpawn().getLocation(), 0, 500);
|
||||
addMoveToDesire(npc, GeoEngine.getInstance().canMoveToTargetLoc(npc.getLocation().getX(), npc.getLocation().getY(), npc.getLocation().getZ(), randomLoc.getX(), randomLoc.getY(), randomLoc.getZ(), npc.getInstanceWorld()), 23);
|
||||
addMoveToDesire(npc, GeoEngine.getInstance().getValidLocation(npc.getLocation().getX(), npc.getLocation().getY(), npc.getLocation().getZ(), randomLoc.getX(), randomLoc.getY(), randomLoc.getZ(), npc.getInstanceWorld()), 23);
|
||||
}
|
||||
startQuestTimer("NPC_MOVE", (10 + getRandom(5)) * 1000, npc, null);
|
||||
}
|
||||
|
@ -48,7 +48,7 @@ public class Eleve extends AbstractNpcAI
|
||||
if (getRandomBoolean())
|
||||
{
|
||||
final Location randomLoc = Util.getRandomPosition(npc.getSpawn().getLocation(), 0, 500);
|
||||
addMoveToDesire(npc, GeoEngine.getInstance().canMoveToTargetLoc(npc.getLocation().getX(), npc.getLocation().getY(), npc.getLocation().getZ(), randomLoc.getX(), randomLoc.getY(), randomLoc.getZ(), npc.getInstanceWorld()), 23);
|
||||
addMoveToDesire(npc, GeoEngine.getInstance().getValidLocation(npc.getLocation().getX(), npc.getLocation().getY(), npc.getLocation().getZ(), randomLoc.getX(), randomLoc.getY(), randomLoc.getZ(), npc.getInstanceWorld()), 23);
|
||||
}
|
||||
startQuestTimer("NPC_MOVE", (10 + getRandom(5)) * 1000, npc, null);
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ public class Handermonkey extends AbstractNpcAI
|
||||
{
|
||||
final int x = npc.getSpawn().getX() + (getRandom(-100, 100));
|
||||
final int y = npc.getSpawn().getY() + (getRandom(-100, 100));
|
||||
final Location loc = GeoEngine.getInstance().canMoveToTargetLoc(npc.getX(), npc.getY(), npc.getZ(), x, y, npc.getZ(), npc.getInstanceWorld());
|
||||
final Location loc = GeoEngine.getInstance().getValidLocation(npc.getX(), npc.getY(), npc.getZ(), x, y, npc.getZ(), npc.getInstanceWorld());
|
||||
addMoveToDesire(npc, loc, 0);
|
||||
}
|
||||
else
|
||||
|
@ -48,7 +48,7 @@ public class Karonf extends AbstractNpcAI
|
||||
if (getRandomBoolean())
|
||||
{
|
||||
final Location randomLoc = Util.getRandomPosition(npc.getSpawn().getLocation(), 0, 500);
|
||||
addMoveToDesire(npc, GeoEngine.getInstance().canMoveToTargetLoc(npc.getLocation().getX(), npc.getLocation().getY(), npc.getLocation().getZ(), randomLoc.getX(), randomLoc.getY(), randomLoc.getZ(), npc.getInstanceWorld()), 23);
|
||||
addMoveToDesire(npc, GeoEngine.getInstance().getValidLocation(npc.getLocation().getX(), npc.getLocation().getY(), npc.getLocation().getZ(), randomLoc.getX(), randomLoc.getY(), randomLoc.getZ(), npc.getInstanceWorld()), 23);
|
||||
}
|
||||
startQuestTimer("NPC_MOVE", (10 + getRandom(5)) * 1000, npc, null);
|
||||
}
|
||||
|
@ -48,7 +48,7 @@ public class Marsha extends AbstractNpcAI
|
||||
if (getRandomBoolean())
|
||||
{
|
||||
final Location randomLoc = Util.getRandomPosition(npc.getSpawn().getLocation(), 0, 500);
|
||||
addMoveToDesire(npc, GeoEngine.getInstance().canMoveToTargetLoc(npc.getLocation().getX(), npc.getLocation().getY(), npc.getLocation().getZ(), randomLoc.getX(), randomLoc.getY(), randomLoc.getZ(), npc.getInstanceWorld()), 23);
|
||||
addMoveToDesire(npc, GeoEngine.getInstance().getValidLocation(npc.getLocation().getX(), npc.getLocation().getY(), npc.getLocation().getZ(), randomLoc.getX(), randomLoc.getY(), randomLoc.getZ(), npc.getInstanceWorld()), 23);
|
||||
}
|
||||
startQuestTimer("NPC_MOVE", (10 + getRandom(5)) * 1000, npc, null);
|
||||
}
|
||||
|
@ -48,7 +48,7 @@ public class Morgan extends AbstractNpcAI
|
||||
if (getRandomBoolean())
|
||||
{
|
||||
final Location randomLoc = Util.getRandomPosition(npc.getSpawn().getLocation(), 0, 500);
|
||||
addMoveToDesire(npc, GeoEngine.getInstance().canMoveToTargetLoc(npc.getLocation().getX(), npc.getLocation().getY(), npc.getLocation().getZ(), randomLoc.getX(), randomLoc.getY(), randomLoc.getZ(), npc.getInstanceWorld()), 23);
|
||||
addMoveToDesire(npc, GeoEngine.getInstance().getValidLocation(npc.getLocation().getX(), npc.getLocation().getY(), npc.getLocation().getZ(), randomLoc.getX(), randomLoc.getY(), randomLoc.getZ(), npc.getInstanceWorld()), 23);
|
||||
}
|
||||
startQuestTimer("NPC_MOVE", (10 + getRandom(5)) * 1000, npc, null);
|
||||
}
|
||||
|
@ -48,7 +48,7 @@ public class Rubentis extends AbstractNpcAI
|
||||
if (getRandomBoolean())
|
||||
{
|
||||
final Location randomLoc = Util.getRandomPosition(npc.getSpawn().getLocation(), 0, 500);
|
||||
addMoveToDesire(npc, GeoEngine.getInstance().canMoveToTargetLoc(npc.getLocation().getX(), npc.getLocation().getY(), npc.getLocation().getZ(), randomLoc.getX(), randomLoc.getY(), randomLoc.getZ(), npc.getInstanceWorld()), 23);
|
||||
addMoveToDesire(npc, GeoEngine.getInstance().getValidLocation(npc.getLocation().getX(), npc.getLocation().getY(), npc.getLocation().getZ(), randomLoc.getX(), randomLoc.getY(), randomLoc.getZ(), npc.getInstanceWorld()), 23);
|
||||
}
|
||||
startQuestTimer("NPC_MOVE", 10000 + (getRandom(5) * 1000), npc, null);
|
||||
}
|
||||
|
@ -63,7 +63,7 @@ public class Vortex extends AbstractNpcAI
|
||||
final int x = (int) (attackers.getX() + (600 * Math.cos(radians)));
|
||||
final int y = (int) (attackers.getY() + (600 * Math.sin(radians)));
|
||||
final int z = attackers.getZ();
|
||||
final Location loc = GeoEngine.getInstance().canMoveToTargetLoc(attackers.getX(), attackers.getY(), attackers.getZ(), x, y, z, attackers.getInstanceWorld());
|
||||
final Location loc = GeoEngine.getInstance().getValidLocation(attackers.getX(), attackers.getY(), attackers.getZ(), x, y, z, attackers.getInstanceWorld());
|
||||
attackers.broadcastPacket(new FlyToLocation(attackers, x, y, z, FlyToLocation.FlyType.THROW_UP, 800, 800, 800));
|
||||
attackers.setXYZ(loc);
|
||||
attackers.broadcastPacket(new ValidateLocation(attackers));
|
||||
|
@ -68,7 +68,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.getInstanceWorld());
|
||||
final Location destination = GeoEngine.getInstance().getValidLocation(npc.getX(), npc.getY(), npc.getZ(), posX, posY, posZ, npc.getInstanceWorld());
|
||||
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;
|
||||
}
|
||||
|
@ -57,8 +57,8 @@ public class AdminMissingHtmls implements IAdminCommandHandler
|
||||
{
|
||||
case "admin_geomap_missing_htmls":
|
||||
{
|
||||
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;
|
||||
final int topLeftX = (x - World.TILE_ZERO_COORD_X) * World.TILE_SIZE;
|
||||
final int topLeftY = (y - World.TILE_ZERO_COORD_Y) * World.TILE_SIZE;
|
||||
final int bottomRightX = (((x - World.TILE_ZERO_COORD_X) * World.TILE_SIZE) + World.TILE_SIZE) - 1;
|
||||
|
@ -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.getInstanceWorld());
|
||||
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.getInstanceWorld());
|
||||
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());
|
||||
}
|
||||
|
@ -88,7 +88,7 @@ public class Blink extends AbstractEffect
|
||||
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.getInstanceWorld());
|
||||
final Location destination = GeoEngine.getInstance().getValidLocation(effected.getX(), effected.getY(), effected.getZ(), x, y, z, effected.getInstanceWorld());
|
||||
|
||||
effected.getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
|
||||
effected.broadcastPacket(new FlyToLocation(effected, destination, _flyType, _flySpeed, _flyDelay, _animationSpeed));
|
||||
|
@ -100,7 +100,7 @@ public class Fear extends AbstractEffect
|
||||
final int posY = (int) (effected.getY() + (FEAR_RANGE * Math.sin(radians)));
|
||||
final int posZ = effected.getZ();
|
||||
|
||||
final Location destination = GeoEngine.getInstance().canMoveToTargetLoc(effected.getX(), effected.getY(), effected.getZ(), posX, posY, posZ, effected.getInstanceWorld());
|
||||
final Location destination = GeoEngine.getInstance().getValidLocation(effected.getX(), effected.getY(), effected.getZ(), posX, posY, posZ, effected.getInstanceWorld());
|
||||
effected.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, destination);
|
||||
}
|
||||
}
|
||||
|
@ -57,7 +57,7 @@ public class FlyAway extends AbstractEffect
|
||||
final int y = (int) (effector.getY() - (nRadius * (dy / distance)));
|
||||
final int z = effector.getZ();
|
||||
|
||||
final Location destination = GeoEngine.getInstance().canMoveToTargetLoc(effected.getX(), effected.getY(), effected.getZ(), x, y, z, effected.getInstanceWorld());
|
||||
final Location destination = GeoEngine.getInstance().getValidLocation(effected.getX(), effected.getY(), effected.getZ(), x, y, z, effected.getInstanceWorld());
|
||||
|
||||
effected.broadcastPacket(new FlyToLocation(effected, destination, FlyType.THROW_UP));
|
||||
effected.setXYZ(destination);
|
||||
|
@ -179,7 +179,7 @@ public class KnockBack extends AbstractEffect
|
||||
final int x = (int) (effected.getX() + (_distance * Math.cos(radians)));
|
||||
final int y = (int) (effected.getY() + (_distance * Math.sin(radians)));
|
||||
final int z = effected.getZ();
|
||||
final Location loc = GeoEngine.getInstance().canMoveToTargetLoc(effected.getX(), effected.getY(), effected.getZ(), x, y, z, effected.getInstanceWorld());
|
||||
final Location loc = GeoEngine.getInstance().getValidLocation(effected.getX(), effected.getY(), effected.getZ(), x, y, z, effected.getInstanceWorld());
|
||||
|
||||
effected.getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
|
||||
effected.broadcastPacket(new FlyToLocation(effected, loc, _type, _speed, _delay, _animationSpeed));
|
||||
|
@ -73,7 +73,7 @@ public class PullBack extends AbstractEffect
|
||||
}
|
||||
|
||||
// In retail, you get debuff, but you are not even moved if there is obstacle. You are still disabled from using skills and moving though.
|
||||
if (GeoEngine.getInstance().canMoveToTarget(effected.getX(), effected.getY(), effected.getZ(), effector.getX(), effector.getY(), effector.getZ(), effector.getInstanceWorld()))
|
||||
if (GeoEngine.getInstance().canMoveToTarget(effected.getX(), effected.getY(), effected.getZ(), effector.getX(), effector.getY(), effector.getZ(), effected.getInstanceWorld()))
|
||||
{
|
||||
effected.broadcastPacket(new FlyToLocation(effected, effector, _type, _speed, _delay, _animationSpeed));
|
||||
effected.setXYZ(effector.getX(), effector.getY(), GeoEngine.getInstance().getHeight(effector.getX(), effector.getY(), effector.getZ()) + 10);
|
||||
|
@ -87,7 +87,7 @@ public class TeleportToSummon extends AbstractEffect
|
||||
final int y = (int) (py + (25 * Math.sin(ph)));
|
||||
final int z = summon.getZ();
|
||||
|
||||
final Location loc = GeoEngine.getInstance().canMoveToTargetLoc(effector.getX(), effector.getY(), effector.getZ(), x, y, z, effector.getInstanceWorld());
|
||||
final Location loc = GeoEngine.getInstance().getValidLocation(effector.getX(), effector.getY(), effector.getZ(), x, y, z,effector.getInstanceWorld());
|
||||
|
||||
effector.getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
|
||||
effector.broadcastPacket(new FlyToLocation(effector, loc.getX(), loc.getY(), loc.getZ(), FlyType.DUMMY));
|
||||
|
@ -76,7 +76,7 @@ public class TeleportToTarget extends AbstractEffect
|
||||
final int y = (int) (py + (25 * Math.sin(ph)));
|
||||
final int z = effected.getZ();
|
||||
|
||||
final Location loc = GeoEngine.getInstance().canMoveToTargetLoc(effector.getX(), effector.getY(), effector.getZ(), x, y, z, effector.getInstanceWorld());
|
||||
final Location loc = GeoEngine.getInstance().getValidLocation(effector.getX(), effector.getY(), effector.getZ(), x, y, z,effector.getInstanceWorld());
|
||||
|
||||
effector.getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
|
||||
effector.broadcastPacket(new FlyToLocation(effector, loc.getX(), loc.getY(), loc.getZ(), FlyType.DUMMY));
|
||||
|
@ -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.getInstanceWorld());
|
||||
final Location destination = GeoEngine.getInstance().getValidLocation(player.getX(), player.getY(), player.getZ(), x, y, z, player.getInstanceWorld());
|
||||
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);
|
||||
|
@ -52,7 +52,7 @@ public class Ground implements ITargetTypeHandler
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!GeoEngine.getInstance().canSeeTarget(creature, worldPosition))
|
||||
if (!GeoEngine.getInstance().canSeeLocation(creature, worldPosition))
|
||||
{
|
||||
if (sendMessage)
|
||||
{
|
||||
|
@ -61,6 +61,7 @@ import org.l2jmobius.commons.util.PropertiesParser;
|
||||
import org.l2jmobius.commons.util.StringUtil;
|
||||
import org.l2jmobius.gameserver.enums.ChatType;
|
||||
import org.l2jmobius.gameserver.enums.ClassId;
|
||||
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;
|
||||
@ -942,12 +943,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;
|
||||
|
||||
/** Attribute System */
|
||||
public static int S_WEAPON_STONE;
|
||||
@ -2491,12 +2497,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);
|
||||
|
@ -584,4 +584,15 @@ public class CommonUtil
|
||||
final DecimalFormat formatter = new DecimalFormat(format, new DecimalFormatSymbols(Locale.ENGLISH));
|
||||
return formatter.format(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @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;
|
||||
}
|
||||
}
|
@ -578,7 +578,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.getInstanceWorld());
|
||||
final Location moveLoc = _actor.isFlying() ? new Location(x1, y1, z1) : GeoEngine.getInstance().getValidLocation(npc.getX(), npc.getY(), npc.getZ(), x1, y1, z1, npc.getInstanceWorld());
|
||||
moveTo(moveLoc.getX(), moveLoc.getY(), moveLoc.getZ());
|
||||
}
|
||||
}
|
||||
@ -801,7 +801,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.getInstanceWorld()));
|
||||
moveTo(GeoEngine.getInstance().getValidLocation(npc.getX(), npc.getY(), npc.getZ(), newX, newY, newZ, npc.getInstanceWorld()));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -114,8 +114,8 @@ public class SpawnTable
|
||||
}
|
||||
|
||||
// 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
|
||||
@ -192,8 +192,8 @@ public class SpawnTable
|
||||
|
||||
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 File spawnFile = spawn.getNpcSpawnTemplate() != null ? spawn.getNpcSpawnTemplate().getSpawnTemplate().getFile() : new File(OTHER_XML_FOLDER + "/" + x + "_" + y + ".xml");
|
||||
final File tempFile = new File(spawnFile.getAbsolutePath().substring(Config.DATAPACK_ROOT.getAbsolutePath().length() + 1).replace('\\', '/') + ".tmp");
|
||||
try
|
||||
|
@ -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
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user