Several GeoEngine improvements/fixes.

This commit is contained in:
MobiusDev
2017-08-27 14:58:10 +00:00
parent 8703a52cf6
commit a5ab4d03d4
15 changed files with 220 additions and 575 deletions

View File

@@ -22,7 +22,6 @@ import java.util.List;
import java.util.ListIterator; import java.util.ListIterator;
import com.l2jmobius.Config; import com.l2jmobius.Config;
import com.l2jmobius.commons.util.StringUtil;
import com.l2jmobius.gameserver.geoengine.geodata.GeoLocation; import com.l2jmobius.gameserver.geoengine.geodata.GeoLocation;
import com.l2jmobius.gameserver.geoengine.pathfinding.Node; import com.l2jmobius.gameserver.geoengine.pathfinding.Node;
import com.l2jmobius.gameserver.geoengine.pathfinding.NodeBuffer; import com.l2jmobius.gameserver.geoengine.pathfinding.NodeBuffer;
@@ -212,7 +211,7 @@ final class GeoEnginePathfinding extends GeoEngine
} }
/** /**
* Provides optimize selection of the buffer. When all pre-initialized buffer are locked, creates new buffer and log this situation. * Provides optimize selection of the buffer. When all pre-initialized buffer are locked, creates new buffer.
* @param size : pre-calculated minimal required size * @param size : pre-calculated minimal required size
* @param playable : moving object is playable? * @param playable : moving object is playable?
* @return NodeBuffer : buffer * @return NodeBuffer : buffer
@@ -236,25 +235,12 @@ final class GeoEnginePathfinding extends GeoEngine
continue; continue;
} }
holder._uses++;
if (playable)
{
holder._playableUses++;
}
holder._elapsed += buffer.getElapsedTime();
return buffer; return buffer;
} }
// NodeBuffer not found, allocate temporary buffer // NodeBuffer not found, allocate temporary buffer
current = new NodeBuffer(holder._size); current = new NodeBuffer(holder._size);
current.isLocked(); current.isLocked();
holder._overflows++;
if (playable)
{
holder._playableOverflows++;
}
} }
return current; return current;
@@ -266,20 +252,11 @@ final class GeoEnginePathfinding extends GeoEngine
private static final class BufferHolder private static final class BufferHolder
{ {
final int _size; final int _size;
final int _count; List<NodeBuffer> _buffer;
ArrayList<NodeBuffer> _buffer;
// statistics
int _playableUses = 0;
int _uses = 0;
int _playableOverflows = 0;
int _overflows = 0;
long _elapsed = 0;
public BufferHolder(int size, int count) public BufferHolder(int size, int count)
{ {
_size = size; _size = size;
_count = count;
_buffer = new ArrayList<>(count); _buffer = new ArrayList<>(count);
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
@@ -287,22 +264,5 @@ final class GeoEnginePathfinding extends GeoEngine
_buffer.add(new NodeBuffer(size)); _buffer.add(new NodeBuffer(size));
} }
} }
@Override
public String toString()
{
final StringBuilder sb = new StringBuilder(100);
StringUtil.append(sb, "Buffer ", String.valueOf(_size), "x", String.valueOf(_size), ": count=", String.valueOf(_count), " uses=", String.valueOf(_playableUses), "/", String.valueOf(_uses));
if (_uses > 0)
{
StringUtil.append(sb, " total/avg(ms)=", String.valueOf(_elapsed), "/", String.format("%1.2f", (double) _elapsed / _uses));
}
StringUtil.append(sb, " ovf=", String.valueOf(_playableOverflows), "/", String.valueOf(_overflows));
return sb.toString();
}
} }
} }

View File

@@ -51,7 +51,6 @@ import com.l2jmobius.gameserver.ai.CtrlIntention;
import com.l2jmobius.gameserver.ai.L2AttackableAI; import com.l2jmobius.gameserver.ai.L2AttackableAI;
import com.l2jmobius.gameserver.ai.L2CharacterAI; import com.l2jmobius.gameserver.ai.L2CharacterAI;
import com.l2jmobius.gameserver.data.xml.impl.CategoryData; import com.l2jmobius.gameserver.data.xml.impl.CategoryData;
import com.l2jmobius.gameserver.data.xml.impl.DoorData;
import com.l2jmobius.gameserver.data.xml.impl.TransformData; import com.l2jmobius.gameserver.data.xml.impl.TransformData;
import com.l2jmobius.gameserver.enums.AttributeType; import com.l2jmobius.gameserver.enums.AttributeType;
import com.l2jmobius.gameserver.enums.BasicProperty; import com.l2jmobius.gameserver.enums.BasicProperty;
@@ -67,7 +66,6 @@ import com.l2jmobius.gameserver.geoengine.GeoEngine;
import com.l2jmobius.gameserver.idfactory.IdFactory; import com.l2jmobius.gameserver.idfactory.IdFactory;
import com.l2jmobius.gameserver.instancemanager.MapRegionManager; import com.l2jmobius.gameserver.instancemanager.MapRegionManager;
import com.l2jmobius.gameserver.instancemanager.TimersManager; import com.l2jmobius.gameserver.instancemanager.TimersManager;
import com.l2jmobius.gameserver.instancemanager.WarpedSpaceManager;
import com.l2jmobius.gameserver.instancemanager.ZoneManager; import com.l2jmobius.gameserver.instancemanager.ZoneManager;
import com.l2jmobius.gameserver.model.CharEffectList; import com.l2jmobius.gameserver.model.CharEffectList;
import com.l2jmobius.gameserver.model.CreatureContainer; import com.l2jmobius.gameserver.model.CreatureContainer;
@@ -3579,7 +3577,7 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
m.onGeodataPathIndex = -1; // Initialize not on geodata path m.onGeodataPathIndex = -1; // Initialize not on geodata path
m.disregardingGeodata = false; m.disregardingGeodata = false;
if (!isFlying() && !isInsideZone(ZoneId.WATER) && !isWalker()) if (!isFlying() && !isInsideZone(ZoneId.WATER) && !isWalker() && !isVehicle())
{ {
final boolean isInVehicle = isPlayer() && (getActingPlayer().getVehicle() != null); final boolean isInVehicle = isPlayer() && (getActingPlayer().getVehicle() != null);
if (isInVehicle) if (isInVehicle)
@@ -3598,7 +3596,7 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
// when geodata == 2, for all characters except mobs returning home (could be changed later to teleport if pathfinding fails) // when geodata == 2, for all characters except mobs returning home (could be changed later to teleport if pathfinding fails)
// when geodata == 1, for l2playableinstance // when geodata == 1, for l2playableinstance
// assuming intention_follow only when following owner // assuming intention_follow only when following owner
if ((Config.PATHFINDING && !(isAttackable() && ((L2Attackable) this).isReturningToSpawnPoint())) || (isPlayer() && !(isInVehicle && (distance > 1500))) || (isSummon() && !(getAI().getIntention() == CtrlIntention.AI_INTENTION_FOLLOW))) if (Config.PATHFINDING && (!(isAttackable() && ((L2Attackable) this).isReturningToSpawnPoint()) || (isSummon() && !(getAI().getIntention() == CtrlIntention.AI_INTENTION_FOLLOW))))
{ {
if (isOnGeodataPath()) if (isOnGeodataPath())
{ {
@@ -3636,7 +3634,7 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
return; return;
} }
// location different if destination wasn't reached (or just z coord is different) // location different if destination wasn't reached (or just z coord is different)
Location destiny = GeoEngine.getInstance().canMoveToTargetLoc(curX, curY, curZ, x, y, z, getInstanceWorld()); final Location destiny = GeoEngine.getInstance().canMoveToTargetLoc(curX, curY, curZ, x, y, z, getInstanceWorld());
x = destiny.getX(); x = destiny.getX();
y = destiny.getY(); y = destiny.getY();
z = destiny.getZ(); z = destiny.getZ();
@@ -3647,84 +3645,51 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
} }
// Pathfinding checks. Only when geodata setting is 2, the LoS check gives shorter result than the original movement was and the LoS gives a shorter distance than 2000 // Pathfinding checks. Only when geodata setting is 2, the LoS check gives shorter result than the original movement was and the LoS gives a shorter distance than 2000
// This way of detecting need for pathfinding could be changed. // This way of detecting need for pathfinding could be changed.
if (Config.PATHFINDING && ((originalDistance - distance) > 30) && (distance < 2000) && !isControlBlocked() && !isInVehicle) if (Config.PATHFINDING && ((originalDistance - distance) > 30) && !isControlBlocked() && !isInVehicle)
{ {
// Path calculation -- overrides previous movement check // Path calculation -- overrides previous movement check
if (isPlayable() || isMinion() || isInCombat()) m.geoPath = GeoEngine.getInstance().findPath(curX, curY, curZ, originalX, originalY, originalZ, getInstanceWorld(), isPlayable());
if ((m.geoPath == null) || (m.geoPath.size() < 2))
{ {
m.geoPath = GeoEngine.getInstance().findPath(curX, curY, curZ, originalX, originalY, originalZ, getInstanceWorld(), isPlayable()); // No path found
if ((m.geoPath == null) || (m.geoPath.size() < 2)) // Even though there's no path found (remember geonodes aren't perfect), the mob is attacking and right now we set it so that the mob will go after target anyway, is dz is small enough.
// With cellpathfinding this approach could be changed but would require taking off the geonodes and some more checks.
// Summons will follow their masters no matter what.
// Currently minions also must move freely since L2AttackableAI commands them to move along with their leader
if (isPlayer() || (!isPlayable() && !isMinion() && (Math.abs(z - curZ) > 140)) || (isSummon() && !((L2Summon) this).getFollowStatus()))
{ {
// No path found getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
// Even though there's no path found (remember geonodes aren't perfect), the mob is attacking and right now we set it so that the mob will go after target anyway, is dz is small enough. return;
// With cellpathfinding this approach could be changed but would require taking off the geonodes and some more checks.
// Summons will follow their masters no matter what.
// Currently minions also must move freely since L2AttackableAI commands them to move along with their leader
if (isPlayer() || (!isPlayable() && !isMinion() && (Math.abs(z - curZ) > 140)) || (isSummon() && !((L2Summon) this).getFollowStatus()))
{
getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
return;
}
m.disregardingGeodata = true;
x = originalX;
y = originalY;
z = originalZ;
distance = originalDistance;
} }
else
{
m.onGeodataPathIndex = 0; // on first segment
m.geoPathGtx = gtx;
m.geoPathGty = gty;
m.geoPathAccurateTx = originalX;
m.geoPathAccurateTy = originalY;
x = m.geoPath.get(m.onGeodataPathIndex).getX(); m.disregardingGeodata = true;
y = m.geoPath.get(m.onGeodataPathIndex).getY(); x = originalX;
z = m.geoPath.get(m.onGeodataPathIndex).getZ(); y = originalY;
z = originalZ;
distance = originalDistance;
}
else
{
m.onGeodataPathIndex = 0; // on first segment
m.geoPathGtx = gtx;
m.geoPathGty = gty;
m.geoPathAccurateTx = originalX;
m.geoPathAccurateTy = originalY;
// check for doors in the route x = m.geoPath.get(m.onGeodataPathIndex).getX();
if (DoorData.getInstance().checkIfDoorsBetween(curX, curY, curZ, x, y, z, getInstanceWorld())) y = m.geoPath.get(m.onGeodataPathIndex).getY();
{ z = m.geoPath.get(m.onGeodataPathIndex).getZ();
m.geoPath = null;
getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
return;
}
if (WarpedSpaceManager.getInstance().checkForWarpedSpace(new Location(curX, curY, curZ), new Location(x, y, z), getInstanceWorld()))
{
m.geoPath = null;
getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
return;
}
for (int i = 0; i < (m.geoPath.size() - 1); i++)
{
if (DoorData.getInstance().checkIfDoorsBetween(m.geoPath.get(i), m.geoPath.get(i + 1), getInstanceWorld()))
{
m.geoPath = null;
getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
return;
}
if (WarpedSpaceManager.getInstance().checkForWarpedSpace(m.geoPath.get(i), m.geoPath.get(i + 1), getInstanceWorld()))
{
m.geoPath = null;
getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
return;
}
}
dx = x - curX; dx = x - curX;
dy = y - curY; dy = y - curY;
dz = z - curZ; dz = z - curZ;
distance = verticalMovementOnly ? Math.pow(dz, 2) : Math.hypot(dx, dy); distance = verticalMovementOnly ? Math.pow(dz, 2) : Math.hypot(dx, dy);
sin = dy / distance; sin = dy / distance;
cos = dx / distance; cos = dx / distance;
}
} }
} }
// If no distance to go through, the movement is canceled // If no distance to go through, the movement is canceled
if ((distance < 1) && (Config.PATHFINDING || isPlayable() || isControlBlocked())) if ((distance < 1) && (Config.PATHFINDING || isPlayable()))
{ {
if (isSummon()) if (isSummon())
{ {
@@ -3746,7 +3711,7 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
final int ticksToMove = 1 + (int) ((GameTimeController.TICKS_PER_SECOND * distance) / speed); final int ticksToMove = 1 + (int) ((GameTimeController.TICKS_PER_SECOND * distance) / speed);
m._xDestination = x; m._xDestination = x;
m._yDestination = y; m._yDestination = y;
m._zDestination = z; m._zDestination = z; // this is what was requested from client
// Calculate and set the heading of the L2Character // Calculate and set the heading of the L2Character
m._heading = 0; // initial value for coordinate sync m._heading = 0; // initial value for coordinate sync

View File

@@ -133,6 +133,7 @@ public class L2AirShipInstance extends L2Vehicle
player.broadcastPacket(new ExGetOnAirShip(player, this)); player.broadcastPacket(new ExGetOnAirShip(player, this));
player.setXYZ(getX(), getY(), getZ()); player.setXYZ(getX(), getY(), getZ());
player.revalidateZone(true); player.revalidateZone(true);
player.stopMove(null);
return true; return true;
} }

View File

@@ -22,7 +22,6 @@ import java.util.List;
import java.util.ListIterator; import java.util.ListIterator;
import com.l2jmobius.Config; import com.l2jmobius.Config;
import com.l2jmobius.commons.util.StringUtil;
import com.l2jmobius.gameserver.geoengine.geodata.GeoLocation; import com.l2jmobius.gameserver.geoengine.geodata.GeoLocation;
import com.l2jmobius.gameserver.geoengine.pathfinding.Node; import com.l2jmobius.gameserver.geoengine.pathfinding.Node;
import com.l2jmobius.gameserver.geoengine.pathfinding.NodeBuffer; import com.l2jmobius.gameserver.geoengine.pathfinding.NodeBuffer;
@@ -212,7 +211,7 @@ final class GeoEnginePathfinding extends GeoEngine
} }
/** /**
* Provides optimize selection of the buffer. When all pre-initialized buffer are locked, creates new buffer and log this situation. * Provides optimize selection of the buffer. When all pre-initialized buffer are locked, creates new buffer.
* @param size : pre-calculated minimal required size * @param size : pre-calculated minimal required size
* @param playable : moving object is playable? * @param playable : moving object is playable?
* @return NodeBuffer : buffer * @return NodeBuffer : buffer
@@ -236,25 +235,12 @@ final class GeoEnginePathfinding extends GeoEngine
continue; continue;
} }
holder._uses++;
if (playable)
{
holder._playableUses++;
}
holder._elapsed += buffer.getElapsedTime();
return buffer; return buffer;
} }
// NodeBuffer not found, allocate temporary buffer // NodeBuffer not found, allocate temporary buffer
current = new NodeBuffer(holder._size); current = new NodeBuffer(holder._size);
current.isLocked(); current.isLocked();
holder._overflows++;
if (playable)
{
holder._playableOverflows++;
}
} }
return current; return current;
@@ -266,20 +252,11 @@ final class GeoEnginePathfinding extends GeoEngine
private static final class BufferHolder private static final class BufferHolder
{ {
final int _size; final int _size;
final int _count; List<NodeBuffer> _buffer;
ArrayList<NodeBuffer> _buffer;
// statistics
int _playableUses = 0;
int _uses = 0;
int _playableOverflows = 0;
int _overflows = 0;
long _elapsed = 0;
public BufferHolder(int size, int count) public BufferHolder(int size, int count)
{ {
_size = size; _size = size;
_count = count;
_buffer = new ArrayList<>(count); _buffer = new ArrayList<>(count);
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
@@ -287,22 +264,5 @@ final class GeoEnginePathfinding extends GeoEngine
_buffer.add(new NodeBuffer(size)); _buffer.add(new NodeBuffer(size));
} }
} }
@Override
public String toString()
{
final StringBuilder sb = new StringBuilder(100);
StringUtil.append(sb, "Buffer ", String.valueOf(_size), "x", String.valueOf(_size), ": count=", String.valueOf(_count), " uses=", String.valueOf(_playableUses), "/", String.valueOf(_uses));
if (_uses > 0)
{
StringUtil.append(sb, " total/avg(ms)=", String.valueOf(_elapsed), "/", String.format("%1.2f", (double) _elapsed / _uses));
}
StringUtil.append(sb, " ovf=", String.valueOf(_playableOverflows), "/", String.valueOf(_overflows));
return sb.toString();
}
} }
} }

View File

@@ -51,7 +51,6 @@ import com.l2jmobius.gameserver.ai.CtrlIntention;
import com.l2jmobius.gameserver.ai.L2AttackableAI; import com.l2jmobius.gameserver.ai.L2AttackableAI;
import com.l2jmobius.gameserver.ai.L2CharacterAI; import com.l2jmobius.gameserver.ai.L2CharacterAI;
import com.l2jmobius.gameserver.data.xml.impl.CategoryData; import com.l2jmobius.gameserver.data.xml.impl.CategoryData;
import com.l2jmobius.gameserver.data.xml.impl.DoorData;
import com.l2jmobius.gameserver.data.xml.impl.TransformData; import com.l2jmobius.gameserver.data.xml.impl.TransformData;
import com.l2jmobius.gameserver.enums.AttributeType; import com.l2jmobius.gameserver.enums.AttributeType;
import com.l2jmobius.gameserver.enums.BasicProperty; import com.l2jmobius.gameserver.enums.BasicProperty;
@@ -67,7 +66,6 @@ import com.l2jmobius.gameserver.geoengine.GeoEngine;
import com.l2jmobius.gameserver.idfactory.IdFactory; import com.l2jmobius.gameserver.idfactory.IdFactory;
import com.l2jmobius.gameserver.instancemanager.MapRegionManager; import com.l2jmobius.gameserver.instancemanager.MapRegionManager;
import com.l2jmobius.gameserver.instancemanager.TimersManager; import com.l2jmobius.gameserver.instancemanager.TimersManager;
import com.l2jmobius.gameserver.instancemanager.WarpedSpaceManager;
import com.l2jmobius.gameserver.instancemanager.ZoneManager; import com.l2jmobius.gameserver.instancemanager.ZoneManager;
import com.l2jmobius.gameserver.model.CharEffectList; import com.l2jmobius.gameserver.model.CharEffectList;
import com.l2jmobius.gameserver.model.CreatureContainer; import com.l2jmobius.gameserver.model.CreatureContainer;
@@ -3579,7 +3577,7 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
m.onGeodataPathIndex = -1; // Initialize not on geodata path m.onGeodataPathIndex = -1; // Initialize not on geodata path
m.disregardingGeodata = false; m.disregardingGeodata = false;
if (!isFlying() && !isInsideZone(ZoneId.WATER) && !isWalker()) if (!isFlying() && !isInsideZone(ZoneId.WATER) && !isWalker() && !isVehicle())
{ {
final boolean isInVehicle = isPlayer() && (getActingPlayer().getVehicle() != null); final boolean isInVehicle = isPlayer() && (getActingPlayer().getVehicle() != null);
if (isInVehicle) if (isInVehicle)
@@ -3598,7 +3596,7 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
// when geodata == 2, for all characters except mobs returning home (could be changed later to teleport if pathfinding fails) // when geodata == 2, for all characters except mobs returning home (could be changed later to teleport if pathfinding fails)
// when geodata == 1, for l2playableinstance // when geodata == 1, for l2playableinstance
// assuming intention_follow only when following owner // assuming intention_follow only when following owner
if ((Config.PATHFINDING && !(isAttackable() && ((L2Attackable) this).isReturningToSpawnPoint())) || (isPlayer() && !(isInVehicle && (distance > 1500))) || (isSummon() && !(getAI().getIntention() == CtrlIntention.AI_INTENTION_FOLLOW))) if (Config.PATHFINDING && (!(isAttackable() && ((L2Attackable) this).isReturningToSpawnPoint()) || (isSummon() && !(getAI().getIntention() == CtrlIntention.AI_INTENTION_FOLLOW))))
{ {
if (isOnGeodataPath()) if (isOnGeodataPath())
{ {
@@ -3636,7 +3634,7 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
return; return;
} }
// location different if destination wasn't reached (or just z coord is different) // location different if destination wasn't reached (or just z coord is different)
Location destiny = GeoEngine.getInstance().canMoveToTargetLoc(curX, curY, curZ, x, y, z, getInstanceWorld()); final Location destiny = GeoEngine.getInstance().canMoveToTargetLoc(curX, curY, curZ, x, y, z, getInstanceWorld());
x = destiny.getX(); x = destiny.getX();
y = destiny.getY(); y = destiny.getY();
z = destiny.getZ(); z = destiny.getZ();
@@ -3647,84 +3645,51 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
} }
// Pathfinding checks. Only when geodata setting is 2, the LoS check gives shorter result than the original movement was and the LoS gives a shorter distance than 2000 // Pathfinding checks. Only when geodata setting is 2, the LoS check gives shorter result than the original movement was and the LoS gives a shorter distance than 2000
// This way of detecting need for pathfinding could be changed. // This way of detecting need for pathfinding could be changed.
if (Config.PATHFINDING && ((originalDistance - distance) > 30) && (distance < 2000) && !isControlBlocked() && !isInVehicle) if (Config.PATHFINDING && ((originalDistance - distance) > 30) && !isControlBlocked() && !isInVehicle)
{ {
// Path calculation -- overrides previous movement check // Path calculation -- overrides previous movement check
if (isPlayable() || isMinion() || isInCombat()) m.geoPath = GeoEngine.getInstance().findPath(curX, curY, curZ, originalX, originalY, originalZ, getInstanceWorld(), isPlayable());
if ((m.geoPath == null) || (m.geoPath.size() < 2))
{ {
m.geoPath = GeoEngine.getInstance().findPath(curX, curY, curZ, originalX, originalY, originalZ, getInstanceWorld(), isPlayable()); // No path found
if ((m.geoPath == null) || (m.geoPath.size() < 2)) // Even though there's no path found (remember geonodes aren't perfect), the mob is attacking and right now we set it so that the mob will go after target anyway, is dz is small enough.
// With cellpathfinding this approach could be changed but would require taking off the geonodes and some more checks.
// Summons will follow their masters no matter what.
// Currently minions also must move freely since L2AttackableAI commands them to move along with their leader
if (isPlayer() || (!isPlayable() && !isMinion() && (Math.abs(z - curZ) > 140)) || (isSummon() && !((L2Summon) this).getFollowStatus()))
{ {
// No path found getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
// Even though there's no path found (remember geonodes aren't perfect), the mob is attacking and right now we set it so that the mob will go after target anyway, is dz is small enough. return;
// With cellpathfinding this approach could be changed but would require taking off the geonodes and some more checks.
// Summons will follow their masters no matter what.
// Currently minions also must move freely since L2AttackableAI commands them to move along with their leader
if (isPlayer() || (!isPlayable() && !isMinion() && (Math.abs(z - curZ) > 140)) || (isSummon() && !((L2Summon) this).getFollowStatus()))
{
getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
return;
}
m.disregardingGeodata = true;
x = originalX;
y = originalY;
z = originalZ;
distance = originalDistance;
} }
else
{
m.onGeodataPathIndex = 0; // on first segment
m.geoPathGtx = gtx;
m.geoPathGty = gty;
m.geoPathAccurateTx = originalX;
m.geoPathAccurateTy = originalY;
x = m.geoPath.get(m.onGeodataPathIndex).getX(); m.disregardingGeodata = true;
y = m.geoPath.get(m.onGeodataPathIndex).getY(); x = originalX;
z = m.geoPath.get(m.onGeodataPathIndex).getZ(); y = originalY;
z = originalZ;
distance = originalDistance;
}
else
{
m.onGeodataPathIndex = 0; // on first segment
m.geoPathGtx = gtx;
m.geoPathGty = gty;
m.geoPathAccurateTx = originalX;
m.geoPathAccurateTy = originalY;
// check for doors in the route x = m.geoPath.get(m.onGeodataPathIndex).getX();
if (DoorData.getInstance().checkIfDoorsBetween(curX, curY, curZ, x, y, z, getInstanceWorld())) y = m.geoPath.get(m.onGeodataPathIndex).getY();
{ z = m.geoPath.get(m.onGeodataPathIndex).getZ();
m.geoPath = null;
getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
return;
}
if (WarpedSpaceManager.getInstance().checkForWarpedSpace(new Location(curX, curY, curZ), new Location(x, y, z), getInstanceWorld()))
{
m.geoPath = null;
getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
return;
}
for (int i = 0; i < (m.geoPath.size() - 1); i++)
{
if (DoorData.getInstance().checkIfDoorsBetween(m.geoPath.get(i), m.geoPath.get(i + 1), getInstanceWorld()))
{
m.geoPath = null;
getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
return;
}
if (WarpedSpaceManager.getInstance().checkForWarpedSpace(m.geoPath.get(i), m.geoPath.get(i + 1), getInstanceWorld()))
{
m.geoPath = null;
getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
return;
}
}
dx = x - curX; dx = x - curX;
dy = y - curY; dy = y - curY;
dz = z - curZ; dz = z - curZ;
distance = verticalMovementOnly ? Math.pow(dz, 2) : Math.hypot(dx, dy); distance = verticalMovementOnly ? Math.pow(dz, 2) : Math.hypot(dx, dy);
sin = dy / distance; sin = dy / distance;
cos = dx / distance; cos = dx / distance;
}
} }
} }
// If no distance to go through, the movement is canceled // If no distance to go through, the movement is canceled
if ((distance < 1) && (Config.PATHFINDING || isPlayable() || isControlBlocked())) if ((distance < 1) && (Config.PATHFINDING || isPlayable()))
{ {
if (isSummon()) if (isSummon())
{ {
@@ -3746,7 +3711,7 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
final int ticksToMove = 1 + (int) ((GameTimeController.TICKS_PER_SECOND * distance) / speed); final int ticksToMove = 1 + (int) ((GameTimeController.TICKS_PER_SECOND * distance) / speed);
m._xDestination = x; m._xDestination = x;
m._yDestination = y; m._yDestination = y;
m._zDestination = z; m._zDestination = z; // this is what was requested from client
// Calculate and set the heading of the L2Character // Calculate and set the heading of the L2Character
m._heading = 0; // initial value for coordinate sync m._heading = 0; // initial value for coordinate sync

View File

@@ -133,6 +133,7 @@ public class L2AirShipInstance extends L2Vehicle
player.broadcastPacket(new ExGetOnAirShip(player, this)); player.broadcastPacket(new ExGetOnAirShip(player, this));
player.setXYZ(getX(), getY(), getZ()); player.setXYZ(getX(), getY(), getZ());
player.revalidateZone(true); player.revalidateZone(true);
player.stopMove(null);
return true; return true;
} }

View File

@@ -22,7 +22,6 @@ import java.util.List;
import java.util.ListIterator; import java.util.ListIterator;
import com.l2jmobius.Config; import com.l2jmobius.Config;
import com.l2jmobius.commons.util.StringUtil;
import com.l2jmobius.gameserver.geoengine.geodata.GeoLocation; import com.l2jmobius.gameserver.geoengine.geodata.GeoLocation;
import com.l2jmobius.gameserver.geoengine.pathfinding.Node; import com.l2jmobius.gameserver.geoengine.pathfinding.Node;
import com.l2jmobius.gameserver.geoengine.pathfinding.NodeBuffer; import com.l2jmobius.gameserver.geoengine.pathfinding.NodeBuffer;
@@ -212,7 +211,7 @@ final class GeoEnginePathfinding extends GeoEngine
} }
/** /**
* Provides optimize selection of the buffer. When all pre-initialized buffer are locked, creates new buffer and log this situation. * Provides optimize selection of the buffer. When all pre-initialized buffer are locked, creates new buffer.
* @param size : pre-calculated minimal required size * @param size : pre-calculated minimal required size
* @param playable : moving object is playable? * @param playable : moving object is playable?
* @return NodeBuffer : buffer * @return NodeBuffer : buffer
@@ -236,25 +235,12 @@ final class GeoEnginePathfinding extends GeoEngine
continue; continue;
} }
holder._uses++;
if (playable)
{
holder._playableUses++;
}
holder._elapsed += buffer.getElapsedTime();
return buffer; return buffer;
} }
// NodeBuffer not found, allocate temporary buffer // NodeBuffer not found, allocate temporary buffer
current = new NodeBuffer(holder._size); current = new NodeBuffer(holder._size);
current.isLocked(); current.isLocked();
holder._overflows++;
if (playable)
{
holder._playableOverflows++;
}
} }
return current; return current;
@@ -266,20 +252,11 @@ final class GeoEnginePathfinding extends GeoEngine
private static final class BufferHolder private static final class BufferHolder
{ {
final int _size; final int _size;
final int _count; List<NodeBuffer> _buffer;
ArrayList<NodeBuffer> _buffer;
// statistics
int _playableUses = 0;
int _uses = 0;
int _playableOverflows = 0;
int _overflows = 0;
long _elapsed = 0;
public BufferHolder(int size, int count) public BufferHolder(int size, int count)
{ {
_size = size; _size = size;
_count = count;
_buffer = new ArrayList<>(count); _buffer = new ArrayList<>(count);
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
@@ -287,22 +264,5 @@ final class GeoEnginePathfinding extends GeoEngine
_buffer.add(new NodeBuffer(size)); _buffer.add(new NodeBuffer(size));
} }
} }
@Override
public String toString()
{
final StringBuilder sb = new StringBuilder(100);
StringUtil.append(sb, "Buffer ", String.valueOf(_size), "x", String.valueOf(_size), ": count=", String.valueOf(_count), " uses=", String.valueOf(_playableUses), "/", String.valueOf(_uses));
if (_uses > 0)
{
StringUtil.append(sb, " total/avg(ms)=", String.valueOf(_elapsed), "/", String.format("%1.2f", (double) _elapsed / _uses));
}
StringUtil.append(sb, " ovf=", String.valueOf(_playableOverflows), "/", String.valueOf(_overflows));
return sb.toString();
}
} }
} }

View File

@@ -51,7 +51,6 @@ import com.l2jmobius.gameserver.ai.CtrlIntention;
import com.l2jmobius.gameserver.ai.L2AttackableAI; import com.l2jmobius.gameserver.ai.L2AttackableAI;
import com.l2jmobius.gameserver.ai.L2CharacterAI; import com.l2jmobius.gameserver.ai.L2CharacterAI;
import com.l2jmobius.gameserver.data.xml.impl.CategoryData; import com.l2jmobius.gameserver.data.xml.impl.CategoryData;
import com.l2jmobius.gameserver.data.xml.impl.DoorData;
import com.l2jmobius.gameserver.data.xml.impl.TransformData; import com.l2jmobius.gameserver.data.xml.impl.TransformData;
import com.l2jmobius.gameserver.enums.AttributeType; import com.l2jmobius.gameserver.enums.AttributeType;
import com.l2jmobius.gameserver.enums.BasicProperty; import com.l2jmobius.gameserver.enums.BasicProperty;
@@ -67,7 +66,6 @@ import com.l2jmobius.gameserver.geoengine.GeoEngine;
import com.l2jmobius.gameserver.idfactory.IdFactory; import com.l2jmobius.gameserver.idfactory.IdFactory;
import com.l2jmobius.gameserver.instancemanager.MapRegionManager; import com.l2jmobius.gameserver.instancemanager.MapRegionManager;
import com.l2jmobius.gameserver.instancemanager.TimersManager; import com.l2jmobius.gameserver.instancemanager.TimersManager;
import com.l2jmobius.gameserver.instancemanager.WarpedSpaceManager;
import com.l2jmobius.gameserver.instancemanager.ZoneManager; import com.l2jmobius.gameserver.instancemanager.ZoneManager;
import com.l2jmobius.gameserver.model.CharEffectList; import com.l2jmobius.gameserver.model.CharEffectList;
import com.l2jmobius.gameserver.model.CreatureContainer; import com.l2jmobius.gameserver.model.CreatureContainer;
@@ -3579,7 +3577,7 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
m.onGeodataPathIndex = -1; // Initialize not on geodata path m.onGeodataPathIndex = -1; // Initialize not on geodata path
m.disregardingGeodata = false; m.disregardingGeodata = false;
if (!isFlying() && !isInsideZone(ZoneId.WATER) && !isWalker()) if (!isFlying() && !isInsideZone(ZoneId.WATER) && !isWalker() && !isVehicle())
{ {
final boolean isInVehicle = isPlayer() && (getActingPlayer().getVehicle() != null); final boolean isInVehicle = isPlayer() && (getActingPlayer().getVehicle() != null);
if (isInVehicle) if (isInVehicle)
@@ -3598,7 +3596,7 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
// when geodata == 2, for all characters except mobs returning home (could be changed later to teleport if pathfinding fails) // when geodata == 2, for all characters except mobs returning home (could be changed later to teleport if pathfinding fails)
// when geodata == 1, for l2playableinstance // when geodata == 1, for l2playableinstance
// assuming intention_follow only when following owner // assuming intention_follow only when following owner
if ((Config.PATHFINDING && !(isAttackable() && ((L2Attackable) this).isReturningToSpawnPoint())) || (isPlayer() && !(isInVehicle && (distance > 1500))) || (isSummon() && !(getAI().getIntention() == CtrlIntention.AI_INTENTION_FOLLOW))) if (Config.PATHFINDING && (!(isAttackable() && ((L2Attackable) this).isReturningToSpawnPoint()) || (isSummon() && !(getAI().getIntention() == CtrlIntention.AI_INTENTION_FOLLOW))))
{ {
if (isOnGeodataPath()) if (isOnGeodataPath())
{ {
@@ -3636,7 +3634,7 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
return; return;
} }
// location different if destination wasn't reached (or just z coord is different) // location different if destination wasn't reached (or just z coord is different)
Location destiny = GeoEngine.getInstance().canMoveToTargetLoc(curX, curY, curZ, x, y, z, getInstanceWorld()); final Location destiny = GeoEngine.getInstance().canMoveToTargetLoc(curX, curY, curZ, x, y, z, getInstanceWorld());
x = destiny.getX(); x = destiny.getX();
y = destiny.getY(); y = destiny.getY();
z = destiny.getZ(); z = destiny.getZ();
@@ -3647,84 +3645,51 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
} }
// Pathfinding checks. Only when geodata setting is 2, the LoS check gives shorter result than the original movement was and the LoS gives a shorter distance than 2000 // Pathfinding checks. Only when geodata setting is 2, the LoS check gives shorter result than the original movement was and the LoS gives a shorter distance than 2000
// This way of detecting need for pathfinding could be changed. // This way of detecting need for pathfinding could be changed.
if (Config.PATHFINDING && ((originalDistance - distance) > 30) && (distance < 2000) && !isControlBlocked() && !isInVehicle) if (Config.PATHFINDING && ((originalDistance - distance) > 30) && !isControlBlocked() && !isInVehicle)
{ {
// Path calculation -- overrides previous movement check // Path calculation -- overrides previous movement check
if (isPlayable() || isMinion() || isInCombat()) m.geoPath = GeoEngine.getInstance().findPath(curX, curY, curZ, originalX, originalY, originalZ, getInstanceWorld(), isPlayable());
if ((m.geoPath == null) || (m.geoPath.size() < 2))
{ {
m.geoPath = GeoEngine.getInstance().findPath(curX, curY, curZ, originalX, originalY, originalZ, getInstanceWorld(), isPlayable()); // No path found
if ((m.geoPath == null) || (m.geoPath.size() < 2)) // Even though there's no path found (remember geonodes aren't perfect), the mob is attacking and right now we set it so that the mob will go after target anyway, is dz is small enough.
// With cellpathfinding this approach could be changed but would require taking off the geonodes and some more checks.
// Summons will follow their masters no matter what.
// Currently minions also must move freely since L2AttackableAI commands them to move along with their leader
if (isPlayer() || (!isPlayable() && !isMinion() && (Math.abs(z - curZ) > 140)) || (isSummon() && !((L2Summon) this).getFollowStatus()))
{ {
// No path found getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
// Even though there's no path found (remember geonodes aren't perfect), the mob is attacking and right now we set it so that the mob will go after target anyway, is dz is small enough. return;
// With cellpathfinding this approach could be changed but would require taking off the geonodes and some more checks.
// Summons will follow their masters no matter what.
// Currently minions also must move freely since L2AttackableAI commands them to move along with their leader
if (isPlayer() || (!isPlayable() && !isMinion() && (Math.abs(z - curZ) > 140)) || (isSummon() && !((L2Summon) this).getFollowStatus()))
{
getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
return;
}
m.disregardingGeodata = true;
x = originalX;
y = originalY;
z = originalZ;
distance = originalDistance;
} }
else
{
m.onGeodataPathIndex = 0; // on first segment
m.geoPathGtx = gtx;
m.geoPathGty = gty;
m.geoPathAccurateTx = originalX;
m.geoPathAccurateTy = originalY;
x = m.geoPath.get(m.onGeodataPathIndex).getX(); m.disregardingGeodata = true;
y = m.geoPath.get(m.onGeodataPathIndex).getY(); x = originalX;
z = m.geoPath.get(m.onGeodataPathIndex).getZ(); y = originalY;
z = originalZ;
distance = originalDistance;
}
else
{
m.onGeodataPathIndex = 0; // on first segment
m.geoPathGtx = gtx;
m.geoPathGty = gty;
m.geoPathAccurateTx = originalX;
m.geoPathAccurateTy = originalY;
// check for doors in the route x = m.geoPath.get(m.onGeodataPathIndex).getX();
if (DoorData.getInstance().checkIfDoorsBetween(curX, curY, curZ, x, y, z, getInstanceWorld())) y = m.geoPath.get(m.onGeodataPathIndex).getY();
{ z = m.geoPath.get(m.onGeodataPathIndex).getZ();
m.geoPath = null;
getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
return;
}
if (WarpedSpaceManager.getInstance().checkForWarpedSpace(new Location(curX, curY, curZ), new Location(x, y, z), getInstanceWorld()))
{
m.geoPath = null;
getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
return;
}
for (int i = 0; i < (m.geoPath.size() - 1); i++)
{
if (DoorData.getInstance().checkIfDoorsBetween(m.geoPath.get(i), m.geoPath.get(i + 1), getInstanceWorld()))
{
m.geoPath = null;
getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
return;
}
if (WarpedSpaceManager.getInstance().checkForWarpedSpace(m.geoPath.get(i), m.geoPath.get(i + 1), getInstanceWorld()))
{
m.geoPath = null;
getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
return;
}
}
dx = x - curX; dx = x - curX;
dy = y - curY; dy = y - curY;
dz = z - curZ; dz = z - curZ;
distance = verticalMovementOnly ? Math.pow(dz, 2) : Math.hypot(dx, dy); distance = verticalMovementOnly ? Math.pow(dz, 2) : Math.hypot(dx, dy);
sin = dy / distance; sin = dy / distance;
cos = dx / distance; cos = dx / distance;
}
} }
} }
// If no distance to go through, the movement is canceled // If no distance to go through, the movement is canceled
if ((distance < 1) && (Config.PATHFINDING || isPlayable() || isControlBlocked())) if ((distance < 1) && (Config.PATHFINDING || isPlayable()))
{ {
if (isSummon()) if (isSummon())
{ {
@@ -3746,7 +3711,7 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
final int ticksToMove = 1 + (int) ((GameTimeController.TICKS_PER_SECOND * distance) / speed); final int ticksToMove = 1 + (int) ((GameTimeController.TICKS_PER_SECOND * distance) / speed);
m._xDestination = x; m._xDestination = x;
m._yDestination = y; m._yDestination = y;
m._zDestination = z; m._zDestination = z; // this is what was requested from client
// Calculate and set the heading of the L2Character // Calculate and set the heading of the L2Character
m._heading = 0; // initial value for coordinate sync m._heading = 0; // initial value for coordinate sync

View File

@@ -133,6 +133,7 @@ public class L2AirShipInstance extends L2Vehicle
player.broadcastPacket(new ExGetOnAirShip(player, this)); player.broadcastPacket(new ExGetOnAirShip(player, this));
player.setXYZ(getX(), getY(), getZ()); player.setXYZ(getX(), getY(), getZ());
player.revalidateZone(true); player.revalidateZone(true);
player.stopMove(null);
return true; return true;
} }

View File

@@ -26,7 +26,6 @@ import com.l2jmobius.gameserver.geoengine.geodata.GeoLocation;
import com.l2jmobius.gameserver.geoengine.pathfinding.Node; import com.l2jmobius.gameserver.geoengine.pathfinding.Node;
import com.l2jmobius.gameserver.geoengine.pathfinding.NodeBuffer; import com.l2jmobius.gameserver.geoengine.pathfinding.NodeBuffer;
import com.l2jmobius.gameserver.model.Location; import com.l2jmobius.gameserver.model.Location;
import com.l2jmobius.gameserver.util.StringUtil;
/** /**
* @author Hasha * @author Hasha
@@ -211,7 +210,7 @@ final class GeoEnginePathfinding extends GeoEngine
} }
/** /**
* Provides optimize selection of the buffer. When all pre-initialized buffer are locked, creates new buffer and log this situation. * Provides optimize selection of the buffer. When all pre-initialized buffer are locked, creates new buffer.
* @param size : pre-calculated minimal required size * @param size : pre-calculated minimal required size
* @param playable : moving object is playable? * @param playable : moving object is playable?
* @return NodeBuffer : buffer * @return NodeBuffer : buffer
@@ -235,25 +234,12 @@ final class GeoEnginePathfinding extends GeoEngine
continue; continue;
} }
holder._uses++;
if (playable)
{
holder._playableUses++;
}
holder._elapsed += buffer.getElapsedTime();
return buffer; return buffer;
} }
// NodeBuffer not found, allocate temporary buffer // NodeBuffer not found, allocate temporary buffer
current = new NodeBuffer(holder._size); current = new NodeBuffer(holder._size);
current.isLocked(); current.isLocked();
holder._overflows++;
if (playable)
{
holder._playableOverflows++;
}
} }
return current; return current;
@@ -265,20 +251,11 @@ final class GeoEnginePathfinding extends GeoEngine
private static final class BufferHolder private static final class BufferHolder
{ {
final int _size; final int _size;
final int _count; List<NodeBuffer> _buffer;
ArrayList<NodeBuffer> _buffer;
// statistics
int _playableUses = 0;
int _uses = 0;
int _playableOverflows = 0;
int _overflows = 0;
long _elapsed = 0;
public BufferHolder(int size, int count) public BufferHolder(int size, int count)
{ {
_size = size; _size = size;
_count = count;
_buffer = new ArrayList<>(count); _buffer = new ArrayList<>(count);
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
@@ -286,22 +263,5 @@ final class GeoEnginePathfinding extends GeoEngine
_buffer.add(new NodeBuffer(size)); _buffer.add(new NodeBuffer(size));
} }
} }
@Override
public String toString()
{
final StringBuilder sb = new StringBuilder(100);
StringUtil.append(sb, "Buffer ", String.valueOf(_size), "x", String.valueOf(_size), ": count=", String.valueOf(_count), " uses=", String.valueOf(_playableUses), "/", String.valueOf(_uses));
if (_uses > 0)
{
StringUtil.append(sb, " total/avg(ms)=", String.valueOf(_elapsed), "/", String.format("%1.2f", (double) _elapsed / _uses));
}
StringUtil.append(sb, " ovf=", String.valueOf(_playableOverflows), "/", String.valueOf(_overflows));
return sb.toString();
}
} }
} }

View File

@@ -42,7 +42,6 @@ import com.l2jmobius.gameserver.ai.CtrlIntention;
import com.l2jmobius.gameserver.ai.L2AttackableAI; import com.l2jmobius.gameserver.ai.L2AttackableAI;
import com.l2jmobius.gameserver.ai.L2CharacterAI; import com.l2jmobius.gameserver.ai.L2CharacterAI;
import com.l2jmobius.gameserver.data.xml.impl.CategoryData; import com.l2jmobius.gameserver.data.xml.impl.CategoryData;
import com.l2jmobius.gameserver.data.xml.impl.DoorData;
import com.l2jmobius.gameserver.datatables.ItemTable; import com.l2jmobius.gameserver.datatables.ItemTable;
import com.l2jmobius.gameserver.enums.CategoryType; import com.l2jmobius.gameserver.enums.CategoryType;
import com.l2jmobius.gameserver.enums.InstanceType; import com.l2jmobius.gameserver.enums.InstanceType;
@@ -4373,7 +4372,8 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
m.disregardingGeodata = false; m.disregardingGeodata = false;
if (!isFlying() // flying chars not checked - even canSeeTarget doesn't work yet if (!isFlying() // flying chars not checked - even canSeeTarget doesn't work yet
&& (!isInsideZone(ZoneId.WATER) || isInsideZone(ZoneId.SIEGE))) // swimming also not checked unless in siege zone - but distance is limited && (!isInsideZone(ZoneId.WATER) || isInsideZone(ZoneId.SIEGE)) // swimming also not checked unless in siege zone - but distance is limited
&& !isWalker() && !isVehicle())
{ {
final boolean isInVehicle = isPlayer() && (getActingPlayer().getVehicle() != null); final boolean isInVehicle = isPlayer() && (getActingPlayer().getVehicle() != null);
if (isInVehicle) if (isInVehicle)
@@ -4429,8 +4429,8 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
} }
return; return;
} }
final Location destiny = GeoEngine.getInstance().canMoveToTargetLoc(curX, curY, curZ, x, y, z, getInstanceId());
// location different if destination wasn't reached (or just z coord is different) // location different if destination wasn't reached (or just z coord is different)
final Location destiny = GeoEngine.getInstance().canMoveToTargetLoc(curX, curY, curZ, x, y, z, getInstanceId());
x = destiny.getX(); x = destiny.getX();
y = destiny.getY(); y = destiny.getY();
z = destiny.getZ(); z = destiny.getZ();
@@ -4442,70 +4442,50 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
// Pathfinding checks. Only when geodata setting is 2, the LoS check gives shorter result // Pathfinding checks. Only when geodata setting is 2, the LoS check gives shorter result
// than the original movement was and the LoS gives a shorter distance than 2000 // than the original movement was and the LoS gives a shorter distance than 2000
// This way of detecting need for pathfinding could be changed. // This way of detecting need for pathfinding could be changed.
if (Config.PATHFINDING && ((originalDistance - distance) > 30) && (distance < 2000)) if (Config.PATHFINDING && ((originalDistance - distance) > 30))
{ {
// Path calculation // Path calculation
// Overrides previous movement check // Overrides previous movement check
if ((isPlayable() && !isInVehicle) || isMinion() || isInCombat()) m.geoPath = GeoEngine.getInstance().findPath(curX, curY, curZ, originalX, originalY, originalZ, getInstanceId(), isPlayable());
if ((m.geoPath == null) || (m.geoPath.size() < 2)) // No path found
{ {
m.geoPath = GeoEngine.getInstance().findPath(curX, curY, curZ, originalX, originalY, originalZ, getInstanceId(), isPlayable()); // Even though there's no path found (remember geonodes aren't perfect),
if ((m.geoPath == null) || (m.geoPath.size() < 2)) // No path found // the mob is attacking and right now we set it so that the mob will go
// after target anyway, is dz is small enough.
// With cellpathfinding this approach could be changed but would require taking
// off the geonodes and some more checks.
// Summons will follow their masters no matter what.
// Currently minions also must move freely since L2AttackableAI commands them to move along with their leader
if (isPlayer() || (!isPlayable() && !isMinion() && (Math.abs(z - curZ) > 140)) || (isSummon() && !((L2Summon) this).getFollowStatus()))
{ {
// Even though there's no path found (remember geonodes aren't perfect), getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
// the mob is attacking and right now we set it so that the mob will go return;
// after target anyway, is dz is small enough.
// With cellpathfinding this approach could be changed but would require taking
// off the geonodes and some more checks.
// Summons will follow their masters no matter what.
// Currently minions also must move freely since L2AttackableAI commands them to move along with their leader
if (isPlayer() || (!isPlayable() && !isMinion() && (Math.abs(z - curZ) > 140)) || (isSummon() && !((L2Summon) this).getFollowStatus()))
{
getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
return;
}
m.disregardingGeodata = true;
x = originalX;
y = originalY;
z = originalZ;
distance = originalDistance;
} }
else
{
m.onGeodataPathIndex = 0; // on first segment
m.geoPathGtx = gtx;
m.geoPathGty = gty;
m.geoPathAccurateTx = originalX;
m.geoPathAccurateTy = originalY;
x = m.geoPath.get(m.onGeodataPathIndex).getX(); m.disregardingGeodata = true;
y = m.geoPath.get(m.onGeodataPathIndex).getY(); x = originalX;
z = m.geoPath.get(m.onGeodataPathIndex).getZ(); y = originalY;
z = originalZ;
distance = originalDistance;
}
else
{
m.onGeodataPathIndex = 0; // on first segment
m.geoPathGtx = gtx;
m.geoPathGty = gty;
m.geoPathAccurateTx = originalX;
m.geoPathAccurateTy = originalY;
// check for doors in the route x = m.geoPath.get(m.onGeodataPathIndex).getX();
if (DoorData.getInstance().checkIfDoorsBetween(curX, curY, curZ, x, y, z, getInstanceId())) y = m.geoPath.get(m.onGeodataPathIndex).getY();
{ z = m.geoPath.get(m.onGeodataPathIndex).getZ();
m.geoPath = null;
getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
return;
}
for (int i = 0; i < (m.geoPath.size() - 1); i++)
{
if (DoorData.getInstance().checkIfDoorsBetween(m.geoPath.get(i), m.geoPath.get(i + 1), getInstanceId()))
{
m.geoPath = null;
getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
return;
}
}
dx = x - curX; dx = x - curX;
dy = y - curY; dy = y - curY;
dz = z - curZ; dz = z - curZ;
distance = verticalMovementOnly ? Math.pow(dz, 2) : Math.hypot(dx, dy); distance = verticalMovementOnly ? Math.pow(dz, 2) : Math.hypot(dx, dy);
sin = dy / distance; sin = dy / distance;
cos = dx / distance; cos = dx / distance;
}
} }
} }
// If no distance to go through, the movement is canceled // If no distance to go through, the movement is canceled

View File

@@ -134,6 +134,7 @@ public class L2AirShipInstance extends L2Vehicle
player.getKnownList().removeAllKnownObjects(); player.getKnownList().removeAllKnownObjects();
player.setXYZ(getX(), getY(), getZ()); player.setXYZ(getX(), getY(), getZ());
player.revalidateZone(true); player.revalidateZone(true);
player.stopMove(null);
return true; return true;
} }

View File

@@ -22,7 +22,6 @@ import java.util.List;
import java.util.ListIterator; import java.util.ListIterator;
import com.l2jmobius.Config; import com.l2jmobius.Config;
import com.l2jmobius.commons.util.StringUtil;
import com.l2jmobius.gameserver.geoengine.geodata.GeoLocation; import com.l2jmobius.gameserver.geoengine.geodata.GeoLocation;
import com.l2jmobius.gameserver.geoengine.pathfinding.Node; import com.l2jmobius.gameserver.geoengine.pathfinding.Node;
import com.l2jmobius.gameserver.geoengine.pathfinding.NodeBuffer; import com.l2jmobius.gameserver.geoengine.pathfinding.NodeBuffer;
@@ -212,7 +211,7 @@ final class GeoEnginePathfinding extends GeoEngine
} }
/** /**
* Provides optimize selection of the buffer. When all pre-initialized buffer are locked, creates new buffer and log this situation. * Provides optimize selection of the buffer. When all pre-initialized buffer are locked, creates new buffer.
* @param size : pre-calculated minimal required size * @param size : pre-calculated minimal required size
* @param playable : moving object is playable? * @param playable : moving object is playable?
* @return NodeBuffer : buffer * @return NodeBuffer : buffer
@@ -236,25 +235,12 @@ final class GeoEnginePathfinding extends GeoEngine
continue; continue;
} }
holder._uses++;
if (playable)
{
holder._playableUses++;
}
holder._elapsed += buffer.getElapsedTime();
return buffer; return buffer;
} }
// NodeBuffer not found, allocate temporary buffer // NodeBuffer not found, allocate temporary buffer
current = new NodeBuffer(holder._size); current = new NodeBuffer(holder._size);
current.isLocked(); current.isLocked();
holder._overflows++;
if (playable)
{
holder._playableOverflows++;
}
} }
return current; return current;
@@ -266,20 +252,11 @@ final class GeoEnginePathfinding extends GeoEngine
private static final class BufferHolder private static final class BufferHolder
{ {
final int _size; final int _size;
final int _count; List<NodeBuffer> _buffer;
ArrayList<NodeBuffer> _buffer;
// statistics
int _playableUses = 0;
int _uses = 0;
int _playableOverflows = 0;
int _overflows = 0;
long _elapsed = 0;
public BufferHolder(int size, int count) public BufferHolder(int size, int count)
{ {
_size = size; _size = size;
_count = count;
_buffer = new ArrayList<>(count); _buffer = new ArrayList<>(count);
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
@@ -287,22 +264,5 @@ final class GeoEnginePathfinding extends GeoEngine
_buffer.add(new NodeBuffer(size)); _buffer.add(new NodeBuffer(size));
} }
} }
@Override
public String toString()
{
final StringBuilder sb = new StringBuilder(100);
StringUtil.append(sb, "Buffer ", String.valueOf(_size), "x", String.valueOf(_size), ": count=", String.valueOf(_count), " uses=", String.valueOf(_playableUses), "/", String.valueOf(_uses));
if (_uses > 0)
{
StringUtil.append(sb, " total/avg(ms)=", String.valueOf(_elapsed), "/", String.format("%1.2f", (double) _elapsed / _uses));
}
StringUtil.append(sb, " ovf=", String.valueOf(_playableOverflows), "/", String.valueOf(_overflows));
return sb.toString();
}
} }
} }

View File

@@ -51,7 +51,6 @@ import com.l2jmobius.gameserver.ai.CtrlIntention;
import com.l2jmobius.gameserver.ai.L2AttackableAI; import com.l2jmobius.gameserver.ai.L2AttackableAI;
import com.l2jmobius.gameserver.ai.L2CharacterAI; import com.l2jmobius.gameserver.ai.L2CharacterAI;
import com.l2jmobius.gameserver.data.xml.impl.CategoryData; import com.l2jmobius.gameserver.data.xml.impl.CategoryData;
import com.l2jmobius.gameserver.data.xml.impl.DoorData;
import com.l2jmobius.gameserver.data.xml.impl.TransformData; import com.l2jmobius.gameserver.data.xml.impl.TransformData;
import com.l2jmobius.gameserver.enums.AttributeType; import com.l2jmobius.gameserver.enums.AttributeType;
import com.l2jmobius.gameserver.enums.BasicProperty; import com.l2jmobius.gameserver.enums.BasicProperty;
@@ -67,7 +66,6 @@ import com.l2jmobius.gameserver.geoengine.GeoEngine;
import com.l2jmobius.gameserver.idfactory.IdFactory; import com.l2jmobius.gameserver.idfactory.IdFactory;
import com.l2jmobius.gameserver.instancemanager.MapRegionManager; import com.l2jmobius.gameserver.instancemanager.MapRegionManager;
import com.l2jmobius.gameserver.instancemanager.TimersManager; import com.l2jmobius.gameserver.instancemanager.TimersManager;
import com.l2jmobius.gameserver.instancemanager.WarpedSpaceManager;
import com.l2jmobius.gameserver.instancemanager.ZoneManager; import com.l2jmobius.gameserver.instancemanager.ZoneManager;
import com.l2jmobius.gameserver.model.CharEffectList; import com.l2jmobius.gameserver.model.CharEffectList;
import com.l2jmobius.gameserver.model.CreatureContainer; import com.l2jmobius.gameserver.model.CreatureContainer;
@@ -3579,7 +3577,7 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
m.onGeodataPathIndex = -1; // Initialize not on geodata path m.onGeodataPathIndex = -1; // Initialize not on geodata path
m.disregardingGeodata = false; m.disregardingGeodata = false;
if (!isFlying() && !isInsideZone(ZoneId.WATER) && !isWalker()) if (!isFlying() && !isInsideZone(ZoneId.WATER) && !isWalker() && !isVehicle())
{ {
final boolean isInVehicle = isPlayer() && (getActingPlayer().getVehicle() != null); final boolean isInVehicle = isPlayer() && (getActingPlayer().getVehicle() != null);
if (isInVehicle) if (isInVehicle)
@@ -3598,7 +3596,7 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
// when geodata == 2, for all characters except mobs returning home (could be changed later to teleport if pathfinding fails) // when geodata == 2, for all characters except mobs returning home (could be changed later to teleport if pathfinding fails)
// when geodata == 1, for l2playableinstance // when geodata == 1, for l2playableinstance
// assuming intention_follow only when following owner // assuming intention_follow only when following owner
if ((Config.PATHFINDING && !(isAttackable() && ((L2Attackable) this).isReturningToSpawnPoint())) || (isPlayer() && !(isInVehicle && (distance > 1500))) || (isSummon() && !(getAI().getIntention() == CtrlIntention.AI_INTENTION_FOLLOW))) if (Config.PATHFINDING && (!(isAttackable() && ((L2Attackable) this).isReturningToSpawnPoint()) || (isSummon() && !(getAI().getIntention() == CtrlIntention.AI_INTENTION_FOLLOW))))
{ {
if (isOnGeodataPath()) if (isOnGeodataPath())
{ {
@@ -3636,7 +3634,7 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
return; return;
} }
// location different if destination wasn't reached (or just z coord is different) // location different if destination wasn't reached (or just z coord is different)
Location destiny = GeoEngine.getInstance().canMoveToTargetLoc(curX, curY, curZ, x, y, z, getInstanceWorld()); final Location destiny = GeoEngine.getInstance().canMoveToTargetLoc(curX, curY, curZ, x, y, z, getInstanceWorld());
x = destiny.getX(); x = destiny.getX();
y = destiny.getY(); y = destiny.getY();
z = destiny.getZ(); z = destiny.getZ();
@@ -3647,84 +3645,51 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
} }
// Pathfinding checks. Only when geodata setting is 2, the LoS check gives shorter result than the original movement was and the LoS gives a shorter distance than 2000 // Pathfinding checks. Only when geodata setting is 2, the LoS check gives shorter result than the original movement was and the LoS gives a shorter distance than 2000
// This way of detecting need for pathfinding could be changed. // This way of detecting need for pathfinding could be changed.
if (Config.PATHFINDING && ((originalDistance - distance) > 30) && (distance < 2000) && !isControlBlocked() && !isInVehicle) if (Config.PATHFINDING && ((originalDistance - distance) > 30) && !isControlBlocked() && !isInVehicle)
{ {
// Path calculation -- overrides previous movement check // Path calculation -- overrides previous movement check
if (isPlayable() || isMinion() || isInCombat()) m.geoPath = GeoEngine.getInstance().findPath(curX, curY, curZ, originalX, originalY, originalZ, getInstanceWorld(), isPlayable());
if ((m.geoPath == null) || (m.geoPath.size() < 2))
{ {
m.geoPath = GeoEngine.getInstance().findPath(curX, curY, curZ, originalX, originalY, originalZ, getInstanceWorld(), isPlayable()); // No path found
if ((m.geoPath == null) || (m.geoPath.size() < 2)) // Even though there's no path found (remember geonodes aren't perfect), the mob is attacking and right now we set it so that the mob will go after target anyway, is dz is small enough.
// With cellpathfinding this approach could be changed but would require taking off the geonodes and some more checks.
// Summons will follow their masters no matter what.
// Currently minions also must move freely since L2AttackableAI commands them to move along with their leader
if (isPlayer() || (!isPlayable() && !isMinion() && (Math.abs(z - curZ) > 140)) || (isSummon() && !((L2Summon) this).getFollowStatus()))
{ {
// No path found getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
// Even though there's no path found (remember geonodes aren't perfect), the mob is attacking and right now we set it so that the mob will go after target anyway, is dz is small enough. return;
// With cellpathfinding this approach could be changed but would require taking off the geonodes and some more checks.
// Summons will follow their masters no matter what.
// Currently minions also must move freely since L2AttackableAI commands them to move along with their leader
if (isPlayer() || (!isPlayable() && !isMinion() && (Math.abs(z - curZ) > 140)) || (isSummon() && !((L2Summon) this).getFollowStatus()))
{
getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
return;
}
m.disregardingGeodata = true;
x = originalX;
y = originalY;
z = originalZ;
distance = originalDistance;
} }
else
{
m.onGeodataPathIndex = 0; // on first segment
m.geoPathGtx = gtx;
m.geoPathGty = gty;
m.geoPathAccurateTx = originalX;
m.geoPathAccurateTy = originalY;
x = m.geoPath.get(m.onGeodataPathIndex).getX(); m.disregardingGeodata = true;
y = m.geoPath.get(m.onGeodataPathIndex).getY(); x = originalX;
z = m.geoPath.get(m.onGeodataPathIndex).getZ(); y = originalY;
z = originalZ;
distance = originalDistance;
}
else
{
m.onGeodataPathIndex = 0; // on first segment
m.geoPathGtx = gtx;
m.geoPathGty = gty;
m.geoPathAccurateTx = originalX;
m.geoPathAccurateTy = originalY;
// check for doors in the route x = m.geoPath.get(m.onGeodataPathIndex).getX();
if (DoorData.getInstance().checkIfDoorsBetween(curX, curY, curZ, x, y, z, getInstanceWorld())) y = m.geoPath.get(m.onGeodataPathIndex).getY();
{ z = m.geoPath.get(m.onGeodataPathIndex).getZ();
m.geoPath = null;
getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
return;
}
if (WarpedSpaceManager.getInstance().checkForWarpedSpace(new Location(curX, curY, curZ), new Location(x, y, z), getInstanceWorld()))
{
m.geoPath = null;
getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
return;
}
for (int i = 0; i < (m.geoPath.size() - 1); i++)
{
if (DoorData.getInstance().checkIfDoorsBetween(m.geoPath.get(i), m.geoPath.get(i + 1), getInstanceWorld()))
{
m.geoPath = null;
getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
return;
}
if (WarpedSpaceManager.getInstance().checkForWarpedSpace(m.geoPath.get(i), m.geoPath.get(i + 1), getInstanceWorld()))
{
m.geoPath = null;
getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
return;
}
}
dx = x - curX; dx = x - curX;
dy = y - curY; dy = y - curY;
dz = z - curZ; dz = z - curZ;
distance = verticalMovementOnly ? Math.pow(dz, 2) : Math.hypot(dx, dy); distance = verticalMovementOnly ? Math.pow(dz, 2) : Math.hypot(dx, dy);
sin = dy / distance; sin = dy / distance;
cos = dx / distance; cos = dx / distance;
}
} }
} }
// If no distance to go through, the movement is canceled // If no distance to go through, the movement is canceled
if ((distance < 1) && (Config.PATHFINDING || isPlayable() || isControlBlocked())) if ((distance < 1) && (Config.PATHFINDING || isPlayable()))
{ {
if (isSummon()) if (isSummon())
{ {
@@ -3746,7 +3711,7 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
final int ticksToMove = 1 + (int) ((GameTimeController.TICKS_PER_SECOND * distance) / speed); final int ticksToMove = 1 + (int) ((GameTimeController.TICKS_PER_SECOND * distance) / speed);
m._xDestination = x; m._xDestination = x;
m._yDestination = y; m._yDestination = y;
m._zDestination = z; m._zDestination = z; // this is what was requested from client
// Calculate and set the heading of the L2Character // Calculate and set the heading of the L2Character
m._heading = 0; // initial value for coordinate sync m._heading = 0; // initial value for coordinate sync

View File

@@ -133,6 +133,7 @@ public class L2AirShipInstance extends L2Vehicle
player.broadcastPacket(new ExGetOnAirShip(player, this)); player.broadcastPacket(new ExGetOnAirShip(player, this));
player.setXYZ(getX(), getY(), getZ()); player.setXYZ(getX(), getY(), getZ());
player.revalidateZone(true); player.revalidateZone(true);
player.stopMove(null);
return true; return true;
} }