Improved pathfinding to stationary targets to not unnecessarily recalculate the path
Fixed an issue where end-of-movement was not being considered properly Added admin command for drawing chunk boundaries ::drawchunks Added admin command for drawing region boundaries ::drawregions Added admin command for drawing the current route ::drawroute Fixed impling IndexOutOfBoundsException
This commit is contained in:
@@ -16,7 +16,7 @@ class ImplingController : TickListener, Commands {
|
|||||||
if (--nextCycle > getTicksBeforeNextCycleToDespawn())
|
if (--nextCycle > getTicksBeforeNextCycleToDespawn())
|
||||||
return
|
return
|
||||||
if (activeImplings.size > 0) {
|
if (activeImplings.size > 0) {
|
||||||
clearSomeImplings(implingsClearedPerTick)
|
clearSomeImplings(min(activeImplings.size, implingsClearedPerTick))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
generateSpawners()
|
generateSpawners()
|
||||||
|
|||||||
@@ -269,62 +269,65 @@ public abstract class MovementPulse extends Pulse {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Location ml = mover.getLocation();
|
if (destination instanceof Entity || interactLocation == null) {
|
||||||
Location dl = destination.getLocation();
|
Location ml = mover.getLocation();
|
||||||
// Lead the target if they're walking/running, unless they're already within interaction range
|
Location dl = destination.getLocation();
|
||||||
if(loc != null && destination instanceof Entity && Math.max(Math.abs(ml.getX() - dl.getX()), Math.abs(ml.getY() - dl.getY())) > 1) {
|
// Lead the target if they're walking/running, unless they're already within interaction range
|
||||||
WalkingQueue wq = ((Entity)destination).getWalkingQueue();
|
if(loc != null && destination instanceof Entity && Math.max(Math.abs(ml.getX() - dl.getX()), Math.abs(ml.getY() - dl.getY())) > 1) {
|
||||||
if(wq.hasPath()) {
|
WalkingQueue wq = ((Entity)destination).getWalkingQueue();
|
||||||
Point[] points = wq.getQueue().toArray(new Point[0]);
|
if(wq.hasPath()) {
|
||||||
if(points.length > 0) {
|
Point[] points = wq.getQueue().toArray(new Point[0]);
|
||||||
Point p = points[0];
|
if(points.length > 0) {
|
||||||
for(int i=0; i<points.length; i++) {
|
Point p = points[0];
|
||||||
// Target the farthest point along target's planned movement that's within 1 tick's running,
|
for(int i=0; i<points.length; i++) {
|
||||||
// this ensures the player will run to catch up to the target if able.
|
// Target the farthest point along target's planned movement that's within 1 tick's running,
|
||||||
if(Math.max(Math.abs(ml.getX() - points[i].getX()), Math.abs(ml.getY() - points[i].getY())) <= 2) {
|
// this ensures the player will run to catch up to the target if able.
|
||||||
p = points[i];
|
if(Math.max(Math.abs(ml.getX() - points[i].getX()), Math.abs(ml.getY() - points[i].getY())) <= 2) {
|
||||||
|
p = points[i];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
loc.setX(p.getX());
|
||||||
|
loc.setY(p.getY());
|
||||||
}
|
}
|
||||||
loc.setX(p.getX());
|
|
||||||
loc.setY(p.getY());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
Path path = Pathfinder.find(mover, loc != null ? loc : destination, true, pathfinder);
|
Path path = Pathfinder.find(mover, loc != null ? loc : destination, true, pathfinder);
|
||||||
near = !path.isSuccessful() || path.isMoveNear();
|
near = !path.isSuccessful() || path.isMoveNear();
|
||||||
interactLocation = mover.getLocation();
|
interactLocation = mover.getLocation();
|
||||||
boolean canMove = true;
|
boolean canMove = true;
|
||||||
if (destination instanceof NPC || destination instanceof Player) {
|
if (destination instanceof Entity) {
|
||||||
Entity e = (Entity) destination;
|
Entity e = (Entity) destination;
|
||||||
Location l = e.getLocation();
|
Location l = e.getLocation();
|
||||||
Deque<Point> npcPath = e.getWalkingQueue().getQueue();
|
Deque<Point> npcPath = e.getWalkingQueue().getQueue();
|
||||||
if (e.getWalkingQueue().hasPath() && e.getProperties().getCombatPulse().isRunning() && e.getProperties().getCombatPulse().getVictim() == mover)
|
if (e.getWalkingQueue().hasPath() && e.getProperties().getCombatPulse().isRunning() && e.getProperties().getCombatPulse().getVictim() == mover)
|
||||||
canMove = false;
|
canMove = false;
|
||||||
if (!canMove) { //If we normally shouldn't move, but the NPC's pathfinding is not letting them move, then move.
|
if (!canMove) { //If we normally shouldn't move, but the NPC's pathfinding is not letting them move, then move.
|
||||||
if (npcPath.size() == 1) {
|
if (npcPath.size() == 1) {
|
||||||
Point pathElement = npcPath.peek();
|
Point pathElement = npcPath.peek();
|
||||||
if (pathElement.getX() == l.getX() && pathElement.getY() == l.getY())
|
if (pathElement.getX() == l.getX() && pathElement.getY() == l.getY())
|
||||||
canMove = true;
|
canMove = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
if (!path.getPoints().isEmpty() && canMove) {
|
||||||
if (!path.getPoints().isEmpty() && canMove) {
|
Point point = path.getPoints().getLast();
|
||||||
Point point = path.getPoints().getLast();
|
interactLocation = Location.create(point.getX(), point.getY(), mover.getLocation().getZ());
|
||||||
interactLocation = Location.create(point.getX(), point.getY(), mover.getLocation().getZ());
|
if (forceRun) {
|
||||||
if (forceRun) {
|
mover.getWalkingQueue().reset(forceRun);
|
||||||
mover.getWalkingQueue().reset(forceRun);
|
|
||||||
} else {
|
|
||||||
mover.getWalkingQueue().reset();
|
|
||||||
}
|
|
||||||
int size = path.getPoints().toArray().length;
|
|
||||||
Deque points = path.getPoints();
|
|
||||||
for (int i = 0; i < size; i++) {
|
|
||||||
point = path.getPoints().pop();
|
|
||||||
mover.getWalkingQueue().addPath(point.getX(), point.getY());
|
|
||||||
if (destination instanceof Entity) {
|
|
||||||
mover.face((Entity) destination);
|
|
||||||
} else {
|
} else {
|
||||||
mover.face(null);
|
mover.getWalkingQueue().reset();
|
||||||
|
}
|
||||||
|
int size = path.getPoints().toArray().length;
|
||||||
|
Deque points = path.getPoints();
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
point = path.getPoints().pop();
|
||||||
|
mover.getWalkingQueue().addPath(point.getX(), point.getY());
|
||||||
|
if (destination instanceof Entity) {
|
||||||
|
mover.face((Entity) destination);
|
||||||
|
} else {
|
||||||
|
mover.face(null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ class ScriptProcessor(val entity: Entity) {
|
|||||||
|
|
||||||
fun postMovement(didMove: Boolean) {
|
fun postMovement(didMove: Boolean) {
|
||||||
if (didMove)
|
if (didMove)
|
||||||
entity.clocks[Clocks.MOVEMENT] = GameWorld.ticks + 1
|
entity.clocks[Clocks.MOVEMENT] = GameWorld.ticks + if (entity.walkingQueue.isRunning) 0 else 1
|
||||||
var canProcess = !entity.delayed()
|
var canProcess = !entity.delayed()
|
||||||
if (entity is Player)
|
if (entity is Player)
|
||||||
canProcess = canProcess && !entity.interfaceManager.isOpened && !entity.interfaceManager.hasChatbox()
|
canProcess = canProcess && !entity.interfaceManager.isOpened && !entity.interfaceManager.hasChatbox()
|
||||||
@@ -80,7 +80,7 @@ class ScriptProcessor(val entity: Entity) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (canProcess && (apScript != null || opScript != null)) {
|
if (canProcess && (apScript != null || opScript != null)) {
|
||||||
if (!interacted && !didMove) {
|
if (!interacted && !didMove && finishedMoving(entity)) {
|
||||||
sendMessage(entity, "I can't reach that!")
|
sendMessage(entity, "I can't reach that!")
|
||||||
reset()
|
reset()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,15 +4,19 @@ import content.global.skill.skillcapeperks.SkillcapePerks;
|
|||||||
import core.game.node.entity.Entity;
|
import core.game.node.entity.Entity;
|
||||||
import core.game.node.entity.player.Player;
|
import core.game.node.entity.player.Player;
|
||||||
import core.game.node.entity.skill.Skills;
|
import core.game.node.entity.skill.Skills;
|
||||||
|
import core.game.node.item.Item;
|
||||||
|
import core.game.node.item.GroundItem;
|
||||||
import core.game.world.map.Direction;
|
import core.game.world.map.Direction;
|
||||||
import core.game.world.map.Location;
|
import core.game.world.map.Location;
|
||||||
import core.game.world.map.Point;
|
import core.game.world.map.Point;
|
||||||
import core.game.world.map.RegionManager;
|
import core.game.world.map.RegionManager;
|
||||||
|
import core.game.world.update.flag.chunk.ItemUpdateFlag;
|
||||||
import core.tools.Log;
|
import core.tools.Log;
|
||||||
import core.tools.SystemLogger;
|
import core.tools.SystemLogger;
|
||||||
|
|
||||||
import java.util.Deque;
|
import java.util.Deque;
|
||||||
import java.util.ArrayDeque;
|
import java.util.ArrayDeque;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
import static core.api.ContentAPIKt.log;
|
import static core.api.ContentAPIKt.log;
|
||||||
|
|
||||||
@@ -58,6 +62,8 @@ public final class WalkingQueue {
|
|||||||
*/
|
*/
|
||||||
private Location footPrint;
|
private Location footPrint;
|
||||||
|
|
||||||
|
public ArrayList<GroundItem> routeItems = new ArrayList<GroundItem>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a new {@code WalkingQueue} {@code Object}.
|
* Constructs a new {@code WalkingQueue} {@code Object}.
|
||||||
* @param entity The entity.
|
* @param entity The entity.
|
||||||
@@ -84,8 +90,17 @@ public final class WalkingQueue {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Point point = walkingQueue.poll();
|
Point point = walkingQueue.poll();
|
||||||
|
boolean drawPath = entity.getAttribute("routedraw", false);
|
||||||
if (point == null) {
|
if (point == null) {
|
||||||
updateRunEnergy(false);
|
updateRunEnergy(false);
|
||||||
|
if (isPlayer && drawPath) {
|
||||||
|
for (GroundItem item : routeItems) {
|
||||||
|
if (item != null) {
|
||||||
|
RegionManager.getRegionPlane(item.getLocation()).remove(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
routeItems.clear();
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (isPlayer && ((Player) entity).getSettings().getRunEnergy() < 1.0) {
|
if (isPlayer && ((Player) entity).getSettings().getRunEnergy() < 1.0) {
|
||||||
@@ -300,6 +315,13 @@ public final class WalkingQueue {
|
|||||||
if (point == null) {
|
if (point == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
boolean drawRoute = entity.getAttribute("routedraw", false);
|
||||||
|
if (drawRoute && entity instanceof Player) {
|
||||||
|
Player p = (Player) entity;
|
||||||
|
GroundItem item = new GroundItem(new Item(13444), Location.create(x, y, p.getLocation().getZ()), p);
|
||||||
|
routeItems.add (item);
|
||||||
|
RegionManager.getRegionPlane(item.getLocation()).add(item);
|
||||||
|
}
|
||||||
int diffX = x - point.getX(), diffY = y - point.getY();
|
int diffX = x - point.getX(), diffY = y - point.getY();
|
||||||
int max = Math.max(Math.abs(diffX), Math.abs(diffY));
|
int max = Math.max(Math.abs(diffX), Math.abs(diffY));
|
||||||
for (int i = 0; i < max; i++) {
|
for (int i = 0; i < max; i++) {
|
||||||
|
|||||||
@@ -212,5 +212,17 @@ class DevelopmentCommandSet : CommandSet(Privilege.ADMIN) {
|
|||||||
addItem(player, item, 1000)
|
addItem(player, item, 1000)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
define("drawchunks", Privilege.ADMIN, "", "Draws the border of the chunk you're standing in") {player, _ ->
|
||||||
|
setAttribute (player, "chunkdraw", !getAttribute(player, "chunkdraw", false))
|
||||||
|
}
|
||||||
|
|
||||||
|
define("drawregions", Privilege.ADMIN, "", "DRaws the border of the region you're standing in") {player, _ ->
|
||||||
|
setAttribute (player, "regiondraw", !getAttribute(player, "regiondraw", false))
|
||||||
|
}
|
||||||
|
|
||||||
|
define("drawroute", Privilege.ADMIN, "", "Visualizes the path your player is taking") {player, _ ->
|
||||||
|
setAttribute (player, "routedraw", !getAttribute(player, "routedraw", false))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -149,8 +149,52 @@ public class RegionChunk {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (items != null) {
|
ArrayList<GroundItem> totalItems = items != null ? new ArrayList(items) : new ArrayList();
|
||||||
for (Item item : items) {
|
|
||||||
|
boolean drawChunks = player.getAttribute("chunkdraw", false);
|
||||||
|
boolean drawRegions = player.getAttribute("regiondraw", false);
|
||||||
|
|
||||||
|
if (drawChunks) {
|
||||||
|
Location l = currentBase;
|
||||||
|
for (int x = 0; x < SIZE; x++) {
|
||||||
|
for (int y = 0; y < SIZE; y++) {
|
||||||
|
boolean add = false;
|
||||||
|
if (y == 0 || y == SIZE - 1)
|
||||||
|
add = true;
|
||||||
|
else if (x == 0 || x == SIZE - 1)
|
||||||
|
add = true;
|
||||||
|
if (add)
|
||||||
|
totalItems.add(new GroundItem(new Item(13444), l.transform(x, y, 0), player));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (drawRegions) {
|
||||||
|
Location l = currentBase;
|
||||||
|
int localX = l.getLocalX();
|
||||||
|
int localY = l.getLocalY();
|
||||||
|
|
||||||
|
for (int x = 0; x < SIZE; x++)
|
||||||
|
for (int y = 0; y < SIZE; y++) {
|
||||||
|
boolean add = false;
|
||||||
|
if (localY == 0 || localY == 56)
|
||||||
|
if (localY == 0 && y == 0)
|
||||||
|
add = true;
|
||||||
|
else if (localY == 56 && y == SIZE - 1)
|
||||||
|
add = true;
|
||||||
|
if (localX == 0 || localX == 56)
|
||||||
|
if (localX == 0 && x == 0)
|
||||||
|
add = true;
|
||||||
|
else if (localX == 56 && x == SIZE - 1)
|
||||||
|
add = true;
|
||||||
|
|
||||||
|
if (add)
|
||||||
|
totalItems.add(new GroundItem(new Item(13444), l.transform(x,y,0), player));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (totalItems != null) {
|
||||||
|
for (Item item : totalItems) {
|
||||||
if (item != null && item.isActive() && item.getLocation() != null) {
|
if (item != null && item.isActive() && item.getLocation() != null) {
|
||||||
GroundItem g = (GroundItem) item;
|
GroundItem g = (GroundItem) item;
|
||||||
if (!g.isPrivate() || g.droppedBy(player)) {
|
if (!g.isPrivate() || g.droppedBy(player)) {
|
||||||
|
|||||||
Reference in New Issue
Block a user