Project update.

This commit is contained in:
MobiusDev
2015-12-31 23:53:41 +00:00
parent e0d681a17e
commit ad2bcd79be
4084 changed files with 83696 additions and 86998 deletions

View File

@ -0,0 +1,87 @@
/*
* 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 com.l2jmobius.gameserver.pathfinding;
public abstract class AbstractNode<Loc extends AbstractNodeLoc>
{
private Loc _loc;
private AbstractNode<Loc> _parent;
public AbstractNode(Loc loc)
{
_loc = loc;
}
public void setParent(AbstractNode<Loc> p)
{
_parent = p;
}
public AbstractNode<Loc> getParent()
{
return _parent;
}
public Loc getLoc()
{
return _loc;
}
public void setLoc(Loc 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;
}
}

View File

@ -0,0 +1,35 @@
/*
* 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 com.l2jmobius.gameserver.pathfinding;
/**
* @author -Nemesiss-
*/
public abstract class AbstractNodeLoc
{
public abstract int getX();
public abstract int getY();
public abstract int getZ();
public abstract void setZ(short z);
public abstract int getNodeX();
public abstract int getNodeY();
}

View File

@ -0,0 +1,210 @@
/*
* 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 com.l2jmobius.gameserver.pathfinding;
import java.util.List;
import com.l2jmobius.Config;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.pathfinding.cellnodes.CellPathFinding;
import com.l2jmobius.gameserver.pathfinding.geonodes.GeoPathFinding;
/**
* @author -Nemesiss-
*/
public abstract class PathFinding
{
public static PathFinding getInstance()
{
if (Config.PATHFINDING == 1)
{
// Higher Memory Usage, Smaller Cpu Usage
return GeoPathFinding.getInstance();
}
// Cell pathfinding, calculated directly from geodata files
return CellPathFinding.getInstance();
}
public abstract boolean pathNodesExist(short regionoffset);
public abstract List<AbstractNodeLoc> findPath(int x, int y, int z, int tx, int ty, int tz, int instanceId, boolean playable);
// @formatter:off
/*
public List<AbstractNodeLoc> search(AbstractNode start, AbstractNode end, int instanceId)
{
// The simplest grid-based pathfinding.
// Drawback is not having higher cost for diagonal movement (means funny routes)
// Could be optimized e.g. not to calculate backwards as far as forwards.
// List of Visited Nodes
LinkedList<AbstractNode> visited = new LinkedList<AbstractNode>();
// List of Nodes to Visit
LinkedList<AbstractNode> to_visit = new LinkedList<AbstractNode>();
to_visit.add(start);
int i = 0;
while (i < 800)
{
AbstractNode node;
try
{
node = to_visit.removeFirst();
}
catch (Exception e)
{
// No Path found
return null;
}
if (node.equals(end)) //path found!
return constructPath(node, instanceId);
else
{
i++;
visited.add(node);
node.attachNeighbors();
Node[] neighbors = node.getNeighbors();
if (neighbors == null)
continue;
for (Node n : neighbors)
{
if (!visited.contains(n) && !to_visit.contains(n))
{
n.setParent(node);
to_visit.add(n);
}
}
}
}
//No Path found
return null;
}
*/
/*
public List<AbstractNodeLoc> searchAStar(Node start, Node end, int instanceId)
{
// Not operational yet?
int start_x = start.getLoc().getX();
int start_y = start.getLoc().getY();
int end_x = end.getLoc().getX();
int end_y = end.getLoc().getY();
//List of Visited Nodes
FastNodeList visited = new FastNodeList(800);//TODO! Add limit to cfg
// List of Nodes to Visit
BinaryNodeHeap to_visit = new BinaryNodeHeap(800);
to_visit.add(start);
int i = 0;
while (i < 800)//TODO! Add limit to cfg
{
AbstractNode node;
try
{
node = to_visit.removeFirst();
}
catch (Exception e)
{
// No Path found
return null;
}
if (node.equals(end)) //path found!
return constructPath(node, instanceId);
else
{
visited.add(node);
node.attachNeighbors();
for (Node n : node.getNeighbors())
{
if (!visited.contains(n) && !to_visit.contains(n))
{
i++;
n.setParent(node);
n.setCost(Math.abs(start_x - n.getLoc().getNodeX()) + Math.abs(start_y - n.getLoc().getNodeY())
+ Math.abs(end_x - n.getLoc().getNodeX()) + Math.abs(end_y - n.getLoc().getNodeY()));
to_visit.add(n);
}
}
}
}
//No Path found
return null;
}
*/
// @formatter:on
/**
* 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) + L2World.TILE_X_MIN);
}
public byte getRegionY(int node_pos)
{
return (byte) ((node_pos >> 8) + L2World.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 L2World.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 L2World.MAP_MIN_Y + (node_y * 128) + 48;
}
public String[] getStat()
{
return null;
}
}

View File

@ -0,0 +1,69 @@
/*
* 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 com.l2jmobius.gameserver.pathfinding.cellnodes;
import com.l2jmobius.gameserver.pathfinding.AbstractNode;
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;
}
}

View File

@ -0,0 +1,362 @@
/*
* 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 com.l2jmobius.gameserver.pathfinding.cellnodes;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;
import com.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 long _timeStamp = 0;
private long _lastElapsedTime = 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)
{
_timeStamp = System.currentTimeMillis();
_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();
_lastElapsedTime = System.currentTimeMillis() - _timeStamp;
}
public final long getElapsedTime()
{
return _lastElapsedTime;
}
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 final void getNeighbors()
{
if (_current.getLoc().canGoNone())
{
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);
}
if (Config.ADVANCED_DIAGONAL_STRATEGY)
{
// 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 final 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 final 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 final 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 final 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;
}
}

View File

@ -0,0 +1,400 @@
/*
* 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 com.l2jmobius.gameserver.pathfinding.cellnodes;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.gameserver.GeoData;
import com.l2jmobius.gameserver.idfactory.IdFactory;
import com.l2jmobius.gameserver.model.itemcontainer.Inventory;
import com.l2jmobius.gameserver.model.items.instance.L2ItemInstance;
import com.l2jmobius.gameserver.pathfinding.AbstractNode;
import com.l2jmobius.gameserver.pathfinding.AbstractNodeLoc;
import com.l2jmobius.gameserver.pathfinding.PathFinding;
import com.l2jmobius.util.StringUtil;
/**
* @author Sami, DS Credits to Diamond
*/
public class CellPathFinding extends PathFinding
{
private static final Logger _log = Logger.getLogger(CellPathFinding.class.getName());
private BufferInfo[] _allBuffers;
private int _findSuccess = 0;
private int _findFails = 0;
private int _postFilterUses = 0;
private int _postFilterPlayableUses = 0;
private int _postFilterPasses = 0;
private long _postFilterElapsed = 0;
private List<L2ItemInstance> _debugItems = null;
public static CellPathFinding getInstance()
{
return SingletonHolder._instance;
}
protected CellPathFinding()
{
try
{
final String[] array = Config.PATHFIND_BUFFERS.split(";");
_allBuffers = 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);
}
_allBuffers[i] = new BufferInfo(Integer.parseInt(args[0]), Integer.parseInt(args[1]));
}
}
catch (Exception e)
{
_log.log(Level.WARNING, "CellPathFinding: Problem during buffer init: " + e.getMessage(), e);
throw new Error("CellPathFinding: load aborted");
}
}
@Override
public boolean pathNodesExist(short regionoffset)
{
return false;
}
@Override
public List<AbstractNodeLoc> findPath(int x, int y, int z, int tx, int ty, int tz, int instanceId, boolean playable)
{
final int gx = GeoData.getInstance().getGeoX(x);
final int gy = GeoData.getInstance().getGeoY(y);
if (!GeoData.getInstance().hasGeo(x, y))
{
return null;
}
final int gz = GeoData.getInstance().getHeight(x, y, z);
final int gtx = GeoData.getInstance().getGeoX(tx);
final int gty = GeoData.getInstance().getGeoY(ty);
if (!GeoData.getInstance().hasGeo(tx, ty))
{
return null;
}
final int gtz = GeoData.getInstance().getHeight(tx, ty, tz);
final CellNodeBuffer buffer = alloc(64 + (2 * Math.max(Math.abs(gx - gtx), Math.abs(gy - gty))), playable);
if (buffer == null)
{
return null;
}
final boolean debug = playable && Config.DEBUG_PATH;
if (debug)
{
if (_debugItems == null)
{
_debugItems = new CopyOnWriteArrayList<>();
}
else
{
for (L2ItemInstance item : _debugItems)
{
item.decayMe();
}
_debugItems.clear();
}
}
List<AbstractNodeLoc> path = null;
try
{
final CellNode result = buffer.findPath(gx, gy, gz, gtx, gty, gtz);
if (debug)
{
for (CellNode n : buffer.debugPath())
{
if (n.getCost() < 0)
{
dropDebugItem(1831, (int) (-n.getCost() * 10), n.getLoc());
}
else
{
// known nodes
dropDebugItem(Inventory.ADENA_ID, (int) (n.getCost() * 10), n.getLoc());
}
}
}
if (result == null)
{
_findFails++;
return null;
}
path = constructPath(result);
}
catch (Exception e)
{
_log.log(Level.WARNING, "", e);
return null;
}
finally
{
buffer.free();
}
if ((path.size() < 3) || (Config.MAX_POSTFILTER_PASSES <= 0))
{
_findSuccess++;
return path;
}
final long timeStamp = System.currentTimeMillis();
_postFilterUses++;
if (playable)
{
_postFilterPlayableUses++;
}
boolean remove;
int pass = 0;
do
{
pass++;
_postFilterPasses++;
remove = false;
final Iterator<AbstractNodeLoc> endPoint = path.iterator();
endPoint.next();
int currentX = x;
int currentY = y;
int currentZ = z;
int midPoint = 0;
while (endPoint.hasNext())
{
final AbstractNodeLoc locMiddle = path.get(midPoint);
final AbstractNodeLoc locEnd = endPoint.next();
if (GeoData.getInstance().canMove(currentX, currentY, currentZ, locEnd.getX(), locEnd.getY(), locEnd.getZ(), instanceId))
{
path.remove(midPoint);
remove = true;
if (debug)
{
dropDebugItem(735, 1, locMiddle);
}
}
else
{
currentX = locMiddle.getX();
currentY = locMiddle.getY();
currentZ = locMiddle.getZ();
midPoint++;
}
}
}
// only one postfilter pass for AI
while (playable && remove && (path.size() > 2) && (pass < Config.MAX_POSTFILTER_PASSES));
if (debug)
{
path.forEach(n -> dropDebugItem(65, 1, n));
}
_findSuccess++;
_postFilterElapsed += System.currentTimeMillis() - timeStamp;
return path;
}
private List<AbstractNodeLoc> constructPath(AbstractNode<NodeLoc> node)
{
final List<AbstractNodeLoc> path = new CopyOnWriteArrayList<>();
int previousDirectionX = Integer.MIN_VALUE;
int previousDirectionY = Integer.MIN_VALUE;
int directionX, directionY;
while (node.getParent() != null)
{
if (!Config.ADVANCED_DIAGONAL_STRATEGY && (node.getParent().getParent() != null))
{
final int tmpX = node.getLoc().getNodeX() - node.getParent().getParent().getLoc().getNodeX();
final int tmpY = node.getLoc().getNodeY() - node.getParent().getParent().getLoc().getNodeY();
if (Math.abs(tmpX) == Math.abs(tmpY))
{
directionX = tmpX;
directionY = tmpY;
}
else
{
directionX = node.getLoc().getNodeX() - node.getParent().getLoc().getNodeX();
directionY = node.getLoc().getNodeY() - node.getParent().getLoc().getNodeY();
}
}
else
{
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.add(0, node.getLoc());
node.setLoc(null);
}
node = node.getParent();
}
return path;
}
private final CellNodeBuffer alloc(int size, boolean playable)
{
CellNodeBuffer current = null;
for (BufferInfo i : _allBuffers)
{
if (i.mapSize >= size)
{
for (CellNodeBuffer buf : i.bufs)
{
if (buf.lock())
{
i.uses++;
if (playable)
{
i.playableUses++;
}
i.elapsed += buf.getElapsedTime();
current = buf;
break;
}
}
if (current != null)
{
break;
}
// not found, allocate temporary buffer
current = new CellNodeBuffer(i.mapSize);
current.lock();
if (i.bufs.size() < i.count)
{
i.bufs.add(current);
i.uses++;
if (playable)
{
i.playableUses++;
}
break;
}
i.overflows++;
if (playable)
{
i.playableOverflows++;
// System.err.println("Overflow, size requested: " + size + " playable:"+playable);
}
}
}
return current;
}
private final void dropDebugItem(int itemId, int num, AbstractNodeLoc loc)
{
final L2ItemInstance item = new L2ItemInstance(IdFactory.getInstance().getNextId(), itemId);
item.setCount(num);
item.spawnMe(loc.getX(), loc.getY(), loc.getZ());
_debugItems.add(item);
}
private static final class BufferInfo
{
final int mapSize;
final int count;
List<CellNodeBuffer> bufs;
int uses = 0;
int playableUses = 0;
int overflows = 0;
int playableOverflows = 0;
long elapsed = 0;
public BufferInfo(int size, int cnt)
{
mapSize = size;
count = cnt;
bufs = new ArrayList<>(count);
}
@Override
public String toString()
{
final StringBuilder stat = new StringBuilder(100);
StringUtil.append(stat, String.valueOf(mapSize), "x", String.valueOf(mapSize), " num:", String.valueOf(bufs.size()), "/", String.valueOf(count), " uses:", String.valueOf(uses), "/", String.valueOf(playableUses));
if (uses > 0)
{
StringUtil.append(stat, " total/avg(ms):", String.valueOf(elapsed), "/", String.format("%1.2f", (double) elapsed / uses));
}
StringUtil.append(stat, " ovf:", String.valueOf(overflows), "/", String.valueOf(playableOverflows));
return stat.toString();
}
}
@Override
public String[] getStat()
{
final String[] result = new String[_allBuffers.length + 1];
for (int i = 0; i < _allBuffers.length; i++)
{
result[i] = _allBuffers[i].toString();
}
final StringBuilder stat = new StringBuilder(100);
StringUtil.append(stat, "LOS postfilter uses:", String.valueOf(_postFilterUses), "/", String.valueOf(_postFilterPlayableUses));
if (_postFilterUses > 0)
{
StringUtil.append(stat, " total/avg(ms):", String.valueOf(_postFilterElapsed), "/", String.format("%1.2f", (double) _postFilterElapsed / _postFilterUses), " passes total/avg:", String.valueOf(_postFilterPasses), "/", String.format("%1.1f", (double) _postFilterPasses / _postFilterUses), Config.EOL);
}
StringUtil.append(stat, "Pathfind success/fail:", String.valueOf(_findSuccess), "/", String.valueOf(_findFails));
result[result.length - 1] = stat.toString();
return result;
}
private static class SingletonHolder
{
protected static final CellPathFinding _instance = new CellPathFinding();
}
}

View File

@ -0,0 +1,195 @@
/*
* 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 com.l2jmobius.gameserver.pathfinding.cellnodes;
import com.l2jmobius.commons.geodriver.Cell;
import com.l2jmobius.gameserver.GeoData;
import com.l2jmobius.gameserver.pathfinding.AbstractNodeLoc;
/**
* @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 = GeoData.getInstance().checkNearestNswe(x, y, z, Cell.NSWE_NORTH);
_goEast = GeoData.getInstance().checkNearestNswe(x, y, z, Cell.NSWE_EAST);
_goSouth = GeoData.getInstance().checkNearestNswe(x, y, z, Cell.NSWE_SOUTH);
_goWest = GeoData.getInstance().checkNearestNswe(x, y, z, Cell.NSWE_WEST);
_geoHeight = GeoData.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 canGoNone()
{
return !canGoNorth() && !canGoEast() && !canGoSouth() && !canGoWest();
}
public boolean canGoAll()
{
return canGoNorth() && canGoEast() && canGoSouth() && canGoWest();
}
@Override
public int getX()
{
return GeoData.getInstance().getWorldX(_x);
}
@Override
public int getY()
{
return GeoData.getInstance().getWorldY(_y);
}
@Override
public int getZ()
{
return _geoHeight;
}
@Override
public void setZ(short z)
{
//
}
@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;
}
}

View File

@ -0,0 +1,60 @@
/*
* 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 com.l2jmobius.gameserver.pathfinding.geonodes;
import com.l2jmobius.gameserver.pathfinding.AbstractNode;
/**
* @author -Nemesiss-
*/
public class GeoNode extends AbstractNode<GeoNodeLoc>
{
private final int _neighborsIdx;
private short _cost;
private GeoNode[] _neighbors;
public GeoNode(GeoNodeLoc Loc, int Neighbors_idx)
{
super(Loc);
_neighborsIdx = Neighbors_idx;
}
public short getCost()
{
return _cost;
}
public void setCost(int cost)
{
_cost = (short) cost;
}
public GeoNode[] getNeighbors()
{
return _neighbors;
}
public void attachNeighbors(GeoNode[] neighbors)
{
_neighbors = neighbors;
}
public int getNeighborsIdx()
{
return _neighborsIdx;
}
}

View File

@ -0,0 +1,115 @@
/*
* 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 com.l2jmobius.gameserver.pathfinding.geonodes;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.pathfinding.AbstractNodeLoc;
/**
* @author -Nemesiss-
*/
public class GeoNodeLoc extends AbstractNodeLoc
{
private final short _x;
private final short _y;
private final short _z;
public GeoNodeLoc(short x, short y, short z)
{
_x = x;
_y = y;
_z = z;
}
@Override
public int getX()
{
return L2World.MAP_MIN_X + (_x * 128) + 48;
}
@Override
public int getY()
{
return L2World.MAP_MIN_Y + (_y * 128) + 48;
}
@Override
public int getZ()
{
return _z;
}
@Override
public void setZ(short z)
{
//
}
@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;
result = (prime * result) + _z;
return result;
}
@Override
public boolean equals(Object obj)
{
if (this == obj)
{
return true;
}
if (obj == null)
{
return false;
}
if (!(obj instanceof GeoNodeLoc))
{
return false;
}
final GeoNodeLoc other = (GeoNodeLoc) obj;
if (_x != other._x)
{
return false;
}
if (_y != other._y)
{
return false;
}
if (_z != other._z)
{
return false;
}
return true;
}
}

View File

@ -0,0 +1,476 @@
/*
* 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 com.l2jmobius.gameserver.pathfinding.geonodes;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.gameserver.GeoData;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.Location;
import com.l2jmobius.gameserver.pathfinding.AbstractNode;
import com.l2jmobius.gameserver.pathfinding.AbstractNodeLoc;
import com.l2jmobius.gameserver.pathfinding.PathFinding;
import com.l2jmobius.gameserver.pathfinding.utils.FastNodeList;
import com.l2jmobius.gameserver.util.Util;
/**
* @author -Nemesiss-
*/
public class GeoPathFinding extends PathFinding
{
private static Logger _log = Logger.getLogger(GeoPathFinding.class.getName());
private static Map<Short, ByteBuffer> _pathNodes = new HashMap<>();
private static Map<Short, IntBuffer> _pathNodesIndex = new HashMap<>();
public static GeoPathFinding getInstance()
{
return SingletonHolder._instance;
}
@Override
public boolean pathNodesExist(short regionoffset)
{
return _pathNodesIndex.containsKey(regionoffset);
}
@Override
public List<AbstractNodeLoc> findPath(int x, int y, int z, int tx, int ty, int tz, int instanceId, boolean playable)
{
final int gx = (x - L2World.MAP_MIN_X) >> 4;
final int gy = (y - L2World.MAP_MIN_Y) >> 4;
final short gz = (short) z;
final int gtx = (tx - L2World.MAP_MIN_X) >> 4;
final int gty = (ty - L2World.MAP_MIN_Y) >> 4;
final short gtz = (short) tz;
final GeoNode start = readNode(gx, gy, gz);
final GeoNode end = readNode(gtx, gty, gtz);
if ((start == null) || (end == null))
{
return null;
}
if (Math.abs(start.getLoc().getZ() - z) > 55)
{
return null; // not correct layer
}
if (Math.abs(end.getLoc().getZ() - tz) > 55)
{
return null; // not correct layer
}
if (start == end)
{
return null;
}
// TODO: Find closest path node we CAN access. Now only checks if we can not reach the closest
Location temp = GeoData.getInstance().moveCheck(x, y, z, start.getLoc().getX(), start.getLoc().getY(), start.getLoc().getZ(), instanceId);
if ((temp.getX() != start.getLoc().getX()) || (temp.getY() != start.getLoc().getY()))
{
return null; // cannot reach closest...
}
// TODO: Find closest path node around target, now only checks if final location can be reached
temp = GeoData.getInstance().moveCheck(tx, ty, tz, end.getLoc().getX(), end.getLoc().getY(), end.getLoc().getZ(), instanceId);
if ((temp.getX() != end.getLoc().getX()) || (temp.getY() != end.getLoc().getY()))
{
return null; // cannot reach closest...
}
// return searchAStar(start, end);
return searchByClosest2(start, end);
}
public List<AbstractNodeLoc> searchByClosest2(GeoNode start, GeoNode end)
{
// Always continues checking from the closest to target non-blocked
// node from to_visit list. There's extra length in path if needed
// to go backwards/sideways but when moving generally forwards, this is extra fast
// and accurate. And can reach insane distances (try it with 800 nodes..).
// Minimum required node count would be around 300-400.
// Generally returns a bit (only a bit) more intelligent looking routes than
// the basic version. Not a true distance image (which would increase CPU
// load) level of intelligence though.
// List of Visited Nodes
final FastNodeList visited = new FastNodeList(550);
// List of Nodes to Visit
final LinkedList<GeoNode> to_visit = new LinkedList<>();
to_visit.add(start);
final int targetX = end.getLoc().getNodeX();
final int targetY = end.getLoc().getNodeY();
int dx, dy;
boolean added;
int i = 0;
while (i < 550)
{
GeoNode node;
try
{
node = to_visit.removeFirst();
}
catch (Exception e)
{
// No Path found
return null;
}
if (node.equals(end))
{
return constructPath2(node);
}
i++;
visited.add(node);
node.attachNeighbors(readNeighbors(node));
final GeoNode[] neighbors = node.getNeighbors();
if (neighbors == null)
{
continue;
}
for (GeoNode n : neighbors)
{
if (!visited.containsRev(n) && !to_visit.contains(n))
{
added = false;
n.setParent(node);
dx = targetX - n.getLoc().getNodeX();
dy = targetY - n.getLoc().getNodeY();
n.setCost((dx * dx) + (dy * dy));
for (int index = 0; index < to_visit.size(); index++)
{
// supposed to find it quite early..
if (to_visit.get(index).getCost() > n.getCost())
{
to_visit.add(index, n);
added = true;
break;
}
}
if (!added)
{
to_visit.addLast(n);
}
}
}
}
// No Path found
return null;
}
public List<AbstractNodeLoc> constructPath2(AbstractNode<GeoNodeLoc> node)
{
final LinkedList<AbstractNodeLoc> path = new LinkedList<>();
int previousDirectionX = -1000;
int previousDirectionY = -1000;
int directionX;
int directionY;
while (node.getParent() != null)
{
// only add a new route point if moving direction changes
directionX = node.getLoc().getNodeX() - node.getParent().getLoc().getNodeX();
directionY = node.getLoc().getNodeY() - node.getParent().getLoc().getNodeY();
if ((directionX != previousDirectionX) || (directionY != previousDirectionY))
{
previousDirectionX = directionX;
previousDirectionY = directionY;
path.addFirst(node.getLoc());
}
node = node.getParent();
}
return path;
}
private GeoNode[] readNeighbors(GeoNode n)
{
if (n.getLoc() == null)
{
return null;
}
int idx = n.getNeighborsIdx();
final int node_x = n.getLoc().getNodeX();
final int node_y = n.getLoc().getNodeY();
// short node_z = n.getLoc().getZ();
final short regoffset = getRegionOffset(getRegionX(node_x), getRegionY(node_y));
final ByteBuffer pn = _pathNodes.get(regoffset);
final List<AbstractNode<GeoNodeLoc>> neighbors = new ArrayList<>(8);
GeoNode newNode;
short new_node_x, new_node_y;
// Region for sure will change, we must read from correct file
byte neighbor = pn.get(idx++); // N
if (neighbor > 0)
{
neighbor--;
new_node_x = (short) node_x;
new_node_y = (short) (node_y - 1);
newNode = readNode(new_node_x, new_node_y, neighbor);
if (newNode != null)
{
neighbors.add(newNode);
}
}
neighbor = pn.get(idx++); // NE
if (neighbor > 0)
{
neighbor--;
new_node_x = (short) (node_x + 1);
new_node_y = (short) (node_y - 1);
newNode = readNode(new_node_x, new_node_y, neighbor);
if (newNode != null)
{
neighbors.add(newNode);
}
}
neighbor = pn.get(idx++); // E
if (neighbor > 0)
{
neighbor--;
new_node_x = (short) (node_x + 1);
new_node_y = (short) node_y;
newNode = readNode(new_node_x, new_node_y, neighbor);
if (newNode != null)
{
neighbors.add(newNode);
}
}
neighbor = pn.get(idx++); // SE
if (neighbor > 0)
{
neighbor--;
new_node_x = (short) (node_x + 1);
new_node_y = (short) (node_y + 1);
newNode = readNode(new_node_x, new_node_y, neighbor);
if (newNode != null)
{
neighbors.add(newNode);
}
}
neighbor = pn.get(idx++); // S
if (neighbor > 0)
{
neighbor--;
new_node_x = (short) node_x;
new_node_y = (short) (node_y + 1);
newNode = readNode(new_node_x, new_node_y, neighbor);
if (newNode != null)
{
neighbors.add(newNode);
}
}
neighbor = pn.get(idx++); // SW
if (neighbor > 0)
{
neighbor--;
new_node_x = (short) (node_x - 1);
new_node_y = (short) (node_y + 1);
newNode = readNode(new_node_x, new_node_y, neighbor);
if (newNode != null)
{
neighbors.add(newNode);
}
}
neighbor = pn.get(idx++); // W
if (neighbor > 0)
{
neighbor--;
new_node_x = (short) (node_x - 1);
new_node_y = (short) node_y;
newNode = readNode(new_node_x, new_node_y, neighbor);
if (newNode != null)
{
neighbors.add(newNode);
}
}
neighbor = pn.get(idx++); // NW
if (neighbor > 0)
{
neighbor--;
new_node_x = (short) (node_x - 1);
new_node_y = (short) (node_y - 1);
newNode = readNode(new_node_x, new_node_y, neighbor);
if (newNode != null)
{
neighbors.add(newNode);
}
}
final GeoNode[] result = new GeoNode[neighbors.size()];
return neighbors.toArray(result);
}
// Private
private GeoNode readNode(short node_x, short node_y, byte layer)
{
final short regoffset = getRegionOffset(getRegionX(node_x), getRegionY(node_y));
if (!pathNodesExist(regoffset))
{
return null;
}
final short nbx = getNodeBlock(node_x);
final short nby = getNodeBlock(node_y);
int idx = _pathNodesIndex.get(regoffset).get((nby << 8) + nbx);
final ByteBuffer pn = _pathNodes.get(regoffset);
// reading
final byte nodes = pn.get(idx);
idx += (layer * 10) + 1;// byte + layer*10byte
if (nodes < layer)
{
_log.warning("SmthWrong!");
}
final short node_z = pn.getShort(idx);
idx += 2;
return new GeoNode(new GeoNodeLoc(node_x, node_y, node_z), idx);
}
private GeoNode readNode(int gx, int gy, short z)
{
final short node_x = getNodePos(gx);
final short node_y = getNodePos(gy);
final short regoffset = getRegionOffset(getRegionX(node_x), getRegionY(node_y));
if (!pathNodesExist(regoffset))
{
return null;
}
final short nbx = getNodeBlock(node_x);
final short nby = getNodeBlock(node_y);
int idx = _pathNodesIndex.get(regoffset).get((nby << 8) + nbx);
final ByteBuffer pn = _pathNodes.get(regoffset);
// reading
byte nodes = pn.get(idx++);
int idx2 = 0; // create index to nearlest node by z
short last_z = Short.MIN_VALUE;
while (nodes > 0)
{
final short node_z = pn.getShort(idx);
if (Math.abs(last_z - z) > Math.abs(node_z - z))
{
last_z = node_z;
idx2 = idx + 2;
}
idx += 10; // short + 8 byte
nodes--;
}
return new GeoNode(new GeoNodeLoc(node_x, node_y, last_z), idx2);
}
protected GeoPathFinding()
{
try
{
_log.info("Path Engine: - Loading Path Nodes...");
//@formatter:off
Files.lines(Config.PATHNODE_PATH.resolve("pn_index.txt"), StandardCharsets.UTF_8)
.map(String::trim)
.filter(l -> !l.isEmpty())
.forEach(line -> {
final String[] parts = line.split("_");
if ((parts.length < 2)
|| !Util.isDigit(parts[0])
|| !Util.isDigit(parts[1]))
{
_log.warning("Invalid pathnode entry: '" + line + "', must be in format 'XX_YY', where X and Y - integers");
return;
}
final byte rx = Byte.parseByte(parts[0]);
final byte ry = Byte.parseByte(parts[1]);
LoadPathNodeFile(rx, ry);
});
//@formatter:on
}
catch (IOException e)
{
_log.log(Level.WARNING, "", e);
throw new Error("Failed to read pn_index file.");
}
}
private void LoadPathNodeFile(byte rx, byte ry)
{
if ((rx < L2World.TILE_X_MIN) || (rx > L2World.TILE_X_MAX) || (ry < L2World.TILE_Y_MIN) || (ry > L2World.TILE_Y_MAX))
{
_log.warning("Failed to Load PathNode File: invalid region " + rx + "," + ry + Config.EOL);
return;
}
final short regionoffset = getRegionOffset(rx, ry);
final File file = new File(Config.PATHNODE_PATH.toString(), rx + "_" + ry + ".pn");
_log.info("Path Engine: - Loading: " + file.getName() + " -> region offset: " + regionoffset + " X: " + rx + " Y: " + ry);
int node = 0, size, index = 0;
// Create a read-only memory-mapped file
try (RandomAccessFile raf = new RandomAccessFile(file, "r");
FileChannel roChannel = raf.getChannel())
{
size = (int) roChannel.size();
MappedByteBuffer nodes;
if (Config.FORCE_GEODATA)
{
// it is not guarantee, because the underlying operating system may have paged out some of the buffer's data
nodes = roChannel.map(FileChannel.MapMode.READ_ONLY, 0, size).load();
}
else
{
nodes = roChannel.map(FileChannel.MapMode.READ_ONLY, 0, size);
}
// Indexing pathnode files, so we will know where each block starts
final IntBuffer indexs = IntBuffer.allocate(65536);
while (node < 65536)
{
final byte layer = nodes.get(index);
indexs.put(node++, index);
index += (layer * 10) + 1;
}
_pathNodesIndex.put(regionoffset, indexs);
_pathNodes.put(regionoffset, nodes);
}
catch (Exception e)
{
_log.log(Level.WARNING, "Failed to Load PathNode File: " + file.getAbsolutePath() + " : " + e.getMessage(), e);
}
}
private static class SingletonHolder
{
protected static final GeoPathFinding _instance = new GeoPathFinding();
}
}

View File

@ -0,0 +1,124 @@
/*
* 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 com.l2jmobius.gameserver.pathfinding.utils;
import com.l2jmobius.gameserver.pathfinding.geonodes.GeoNode;
/**
* @author -Nemesiss-
*/
public class BinaryNodeHeap
{
private final GeoNode[] _list;
private int _size;
public BinaryNodeHeap(int size)
{
_list = new GeoNode[size + 1];
_size = 0;
}
public void add(GeoNode n)
{
_size++;
int pos = _size;
_list[pos] = n;
while (pos != 1)
{
final int p2 = pos / 2;
if (_list[pos].getCost() <= _list[p2].getCost())
{
final GeoNode temp = _list[p2];
_list[p2] = _list[pos];
_list[pos] = temp;
pos = p2;
}
else
{
break;
}
}
}
public GeoNode removeFirst()
{
final GeoNode first = _list[1];
_list[1] = _list[_size];
_list[_size] = null;
_size--;
int pos = 1;
int cpos;
int dblcpos;
GeoNode temp;
while (true)
{
cpos = pos;
dblcpos = cpos * 2;
if ((dblcpos + 1) <= _size)
{
if (_list[cpos].getCost() >= _list[dblcpos].getCost())
{
pos = dblcpos;
}
if (_list[pos].getCost() >= _list[dblcpos + 1].getCost())
{
pos = dblcpos + 1;
}
}
else if (dblcpos <= _size)
{
if (_list[cpos].getCost() >= _list[dblcpos].getCost())
{
pos = dblcpos;
}
}
if (cpos != pos)
{
temp = _list[cpos];
_list[cpos] = _list[pos];
_list[pos] = temp;
}
else
{
break;
}
}
return first;
}
public boolean contains(GeoNode n)
{
if (_size == 0)
{
return false;
}
for (int i = 1; i <= _size; i++)
{
if (_list[i].equals(n))
{
return true;
}
}
return false;
}
public boolean isEmpty()
{
return _size == 0;
}
}

View File

@ -0,0 +1,49 @@
/*
* 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 com.l2jmobius.gameserver.pathfinding.utils;
import java.util.ArrayList;
import com.l2jmobius.gameserver.pathfinding.AbstractNode;
/**
* @author -Nemesiss-
*/
public class FastNodeList
{
private final ArrayList<AbstractNode<?>> _list;
public FastNodeList(int size)
{
_list = new ArrayList<>(size);
}
public void add(AbstractNode<?> n)
{
_list.add(n);
}
public boolean contains(AbstractNode<?> n)
{
return _list.contains(n);
}
public boolean containsRev(AbstractNode<?> n)
{
return _list.lastIndexOf(n) != -1;
}
}