Skip to content

Commit bf0593d

Browse files
Working on pathfinding stuff.
1 parent 06b3a07 commit bf0593d

File tree

3 files changed

+144
-135
lines changed

3 files changed

+144
-135
lines changed

src/world/actor/actor.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { Item } from '@server/world/items/item';
88
import { Position } from '@server/world/position';
99
import { DirectionData, directionFromIndex } from '@server/world/direction';
1010
import { CombatAction } from '@server/world/actor/player/action/combat-action';
11+
import { Pathfinding } from '@server/world/actor/pathfinding';
1112

1213
/**
1314
* Handles an actor within the game world.
@@ -25,6 +26,7 @@ export abstract class Actor extends Entity {
2526
private _busy: boolean;
2627
public readonly metadata: { [key: string]: any } = {};
2728
private _combatActions: CombatAction[];
29+
public readonly pathfinding: Pathfinding;
2830

2931
protected constructor() {
3032
super();
@@ -37,6 +39,7 @@ export abstract class Actor extends Entity {
3739
this.skills = new Skills(this);
3840
this._busy = false;
3941
this._combatActions = [];
42+
this.pathfinding = new Pathfinding(this);
4043
}
4144

4245
public face(face: Position | Actor, clearWalkingQueue: boolean = true, autoClear: boolean = true): void {

src/world/actor/pathfinding.ts

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
import { world } from '@server/game-server';
2+
import { Actor } from '@server/world/actor/actor';
3+
import { Position } from '../position';
4+
import { Chunk } from '@server/world/map/chunk';
5+
import { Tile } from '@runejs/cache-parser';
6+
7+
export class Pathfinding {
8+
9+
public constructor(private actor: Actor) {
10+
}
11+
12+
public pathTo(destinationX: number, destinationY: number): void {
13+
const path: Position[][] = new Array(16).fill(new Array(16));
14+
}
15+
16+
public canMoveTo(origin: Position, destination: Position): boolean {
17+
let destinationChunk: Chunk = world.chunkManager.getChunkForWorldPosition(destination);
18+
const positionAbove: Position = new Position(destination.x, destination.y, destination.level + 1);
19+
const chunkAbove: Chunk = world.chunkManager.getChunkForWorldPosition(positionAbove);
20+
let tile: Tile = chunkAbove.getTile(positionAbove);
21+
22+
if(!tile || !tile.bridge) {
23+
tile = destinationChunk.getTile(destination);
24+
} else {
25+
// Destination is a bridge, so we need to check the chunk above to get the bridge tiles instead of the level we're currently on
26+
destinationChunk = chunkAbove;
27+
}
28+
29+
if(tile) {
30+
if(tile.nonWalkable) {
31+
return false;
32+
}
33+
}
34+
35+
const initialX: number = origin.x;
36+
const initialY: number = origin.y;
37+
const destinationAdjacency: number[][] = destinationChunk.collisionMap.adjacency;
38+
const destinationLocalX: number = destination.x - destinationChunk.collisionMap.insetX;
39+
const destinationLocalY: number = destination.y - destinationChunk.collisionMap.insetY;
40+
41+
// @TODO check objects moving from bridge tile to non bridge tile
42+
// ^ currently possible to clip through some bridge walls thanks to this issue
43+
// not the most important thing since you still can't walk on water or anything
44+
45+
// West
46+
if(destination.x < initialX && destination.y == initialY) {
47+
if((destinationAdjacency[destinationLocalX][destinationLocalY] & 0x1280108) != 0) {
48+
return false;
49+
}
50+
}
51+
52+
// East
53+
if(destination.x > initialX && destination.y == initialY) {
54+
if((destinationAdjacency[destinationLocalX][destinationLocalY] & 0x1280180) != 0) {
55+
return false;
56+
}
57+
}
58+
59+
// South
60+
if(destination.y < initialY && destination.x == initialX) {
61+
if((destinationAdjacency[destinationLocalX][destinationLocalY] & 0x1280102) != 0) {
62+
return false;
63+
}
64+
}
65+
66+
// North
67+
if(destination.y > initialY && destination.x == initialX) {
68+
if((destinationAdjacency[destinationLocalX][destinationLocalY] & 0x1280120) != 0) {
69+
return false;
70+
}
71+
}
72+
73+
// South-West
74+
if(destination.x < initialX && destination.y < initialY) {
75+
if(!Pathfinding.canMoveDiagonally(origin, destinationAdjacency, destinationLocalX, destinationLocalY, initialX, initialY, -1, -1,
76+
0x128010e, 0x1280108, 0x1280102)) {
77+
return false;
78+
}
79+
}
80+
81+
// South-East
82+
if(destination.x > initialX && destination.y < initialY) {
83+
if(!Pathfinding.canMoveDiagonally(origin, destinationAdjacency, destinationLocalX, destinationLocalY, initialX, initialY, 1, -1,
84+
0x1280183, 0x1280180, 0x1280102)) {
85+
return false;
86+
}
87+
}
88+
89+
// North-West
90+
if(destination.x < initialX && destination.y > initialY) {
91+
if(!Pathfinding.canMoveDiagonally(origin, destinationAdjacency, destinationLocalX, destinationLocalY, initialX, initialY, -1, 1,
92+
0x1280138, 0x1280108, 0x1280120)) {
93+
return false;
94+
}
95+
}
96+
97+
// North-East
98+
if(destination.x > initialX && destination.y > initialY) {
99+
if(!Pathfinding.canMoveDiagonally(origin, destinationAdjacency, destinationLocalX, destinationLocalY, initialX, initialY, 1, 1,
100+
0x12801e0, 0x1280180, 0x1280120)) {
101+
return false;
102+
}
103+
}
104+
105+
return true;
106+
}
107+
108+
public static canMoveDiagonally(origin: Position, destinationAdjacency: number[][], destinationLocalX: number, destinationLocalY: number,
109+
initialX: number, initialY: number, offsetX: number, offsetY: number, destMask: number, cornerMask1: number, cornerMask2: number): boolean {
110+
const cornerX1: number = initialX + offsetX;
111+
const cornerY1: number = initialY;
112+
const cornerX2: number = initialX;
113+
const cornerY2: number = initialY + offsetY;
114+
const corner1 = Pathfinding.calculateLocalCornerPosition(cornerX1, cornerY1, origin);
115+
const corner2 = Pathfinding.calculateLocalCornerPosition(cornerX2, cornerY2, origin);
116+
117+
return ((destinationAdjacency[destinationLocalX][destinationLocalY] & destMask) == 0 &&
118+
(corner1.chunk.collisionMap.adjacency[corner1.localX][corner1.localY] & cornerMask1) == 0 &&
119+
(corner2.chunk.collisionMap.adjacency[corner2.localX][corner2.localY] & cornerMask2) == 0);
120+
}
121+
122+
private static calculateLocalCornerPosition(cornerX: number, cornerY: number, origin: Position): { localX: number, localY: number, chunk: Chunk } {
123+
const cornerPosition: Position = new Position(cornerX, cornerY, origin.level + 1);
124+
let cornerChunk: Chunk = world.chunkManager.getChunkForWorldPosition(cornerPosition);
125+
const tileAbove: Tile = cornerChunk.getTile(cornerPosition);
126+
if(!tileAbove || !tileAbove.bridge) {
127+
cornerPosition.level = cornerPosition.level - 1;
128+
cornerChunk = world.chunkManager.getChunkForWorldPosition(cornerPosition);
129+
}
130+
const localX: number = cornerX - cornerChunk.collisionMap.insetX;
131+
const localY: number = cornerY - cornerChunk.collisionMap.insetY;
132+
133+
return { localX, localY, chunk: cornerChunk };
134+
}
135+
136+
}

src/world/actor/walking-queue.ts

Lines changed: 5 additions & 135 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@ import { Actor } from './actor';
22
import { Position } from '../position';
33
import { Player } from './player/player';
44
import { world } from '@server/game-server';
5-
import { Chunk } from '../map/chunk';
6-
import { Tile } from '@runejs/cache-parser';
75
import { Npc } from './npc/npc';
86

97
/**
@@ -59,7 +57,7 @@ export class WalkingQueue {
5957

6058
const newPosition = new Position(lastX, lastY, this.actor.position.level);
6159

62-
if(this.canMoveTo(lastPosition, newPosition)) {
60+
if(this.actor.pathfinding.canMoveTo(lastPosition, newPosition)) {
6361
lastPosition = newPosition;
6462
newPosition.metadata = positionMetadata;
6563
this.queue.push(newPosition);
@@ -72,7 +70,7 @@ export class WalkingQueue {
7270
if(lastX !== x || lastY !== y && this.valid) {
7371
const newPosition = new Position(x, y, this.actor.position.level);
7472

75-
if(this.canMoveTo(lastPosition, newPosition)) {
73+
if(this.actor.pathfinding.canMoveTo(lastPosition, newPosition)) {
7674
newPosition.metadata = positionMetadata;
7775
this.queue.push(newPosition);
7876
} else {
@@ -85,7 +83,7 @@ export class WalkingQueue {
8583
const position = this.actor.position;
8684
const newPosition = new Position(position.x + xDiff, position.y + yDiff, position.level);
8785

88-
if(this.canMoveTo(position, newPosition)) {
86+
if(this.actor.pathfinding.canMoveTo(position, newPosition)) {
8987
this.clear();
9088
this.valid = true;
9189
this.add(newPosition.x, newPosition.y, { ignoreWidgets: true });
@@ -95,134 +93,6 @@ export class WalkingQueue {
9593
return false;
9694
}
9795

98-
public canMoveTo(origin: Position, destination: Position): boolean {
99-
let destinationChunk: Chunk = world.chunkManager.getChunkForWorldPosition(destination);
100-
const positionAbove: Position = new Position(destination.x, destination.y, destination.level + 1);
101-
const chunkAbove: Chunk = world.chunkManager.getChunkForWorldPosition(positionAbove);
102-
let tile: Tile = chunkAbove.getTile(positionAbove);
103-
104-
if(!tile || !tile.bridge) {
105-
tile = destinationChunk.getTile(destination);
106-
} else {
107-
// Destination is a bridge, so we need to check the chunk above to get the bridge tiles instead of the level we're currently on
108-
destinationChunk = chunkAbove;
109-
}
110-
111-
if(tile) {
112-
if(tile.nonWalkable) {
113-
return false;
114-
}
115-
}
116-
117-
const initialX: number = origin.x;
118-
const initialY: number = origin.y;
119-
const destinationAdjacency: number[][] = destinationChunk.collisionMap.adjacency;
120-
const destinationLocalX: number = destination.x - destinationChunk.collisionMap.insetX;
121-
const destinationLocalY: number = destination.y - destinationChunk.collisionMap.insetY;
122-
123-
// @TODO check objects moving from bridge tile to non bridge tile
124-
// ^ currently possible to clip through some bridge walls thanks to this issue
125-
// not the most important thing since you still can't walk on water or anything
126-
127-
// West
128-
if(destination.x < initialX && destination.y == initialY) {
129-
if((destinationAdjacency[destinationLocalX][destinationLocalY] & 0x1280108) != 0) {
130-
// logger.warn(`${this.actor instanceof Player ? this.actor.username + ' c' : 'C'}an not move west.`);
131-
return false;
132-
}
133-
}
134-
135-
// East
136-
if(destination.x > initialX && destination.y == initialY) {
137-
if((destinationAdjacency[destinationLocalX][destinationLocalY] & 0x1280180) != 0) {
138-
// logger.warn(`${this.actor instanceof Player ? this.actor.username + ' c' : 'C'}an not move east.`);
139-
return false;
140-
}
141-
}
142-
143-
// South
144-
if(destination.y < initialY && destination.x == initialX) {
145-
if((destinationAdjacency[destinationLocalX][destinationLocalY] & 0x1280102) != 0) {
146-
// logger.warn(`${this.actor instanceof Player ? this.actor.username + ' c' : 'C'}an not move south.`);
147-
return false;
148-
}
149-
}
150-
151-
// North
152-
if(destination.y > initialY && destination.x == initialX) {
153-
if((destinationAdjacency[destinationLocalX][destinationLocalY] & 0x1280120) != 0) {
154-
// logger.warn(`${this.actor instanceof Player ? this.actor.username + ' c' : 'C'}an not move north.`);
155-
return false;
156-
}
157-
}
158-
159-
// South-West
160-
if(destination.x < initialX && destination.y < initialY) {
161-
if(!this.canMoveDiagonally(origin, destinationAdjacency, destinationLocalX, destinationLocalY, initialX, initialY, -1, -1,
162-
0x128010e, 0x1280108, 0x1280102)) {
163-
// logger.warn(`${this.actor instanceof Player ? this.actor.username + ' c' : 'C'}an not move south-west.`);
164-
return false;
165-
}
166-
}
167-
168-
// South-East
169-
if(destination.x > initialX && destination.y < initialY) {
170-
if(!this.canMoveDiagonally(origin, destinationAdjacency, destinationLocalX, destinationLocalY, initialX, initialY, 1, -1,
171-
0x1280183, 0x1280180, 0x1280102)) {
172-
// logger.warn(`${this.actor instanceof Player ? this.actor.username + ' c' : 'C'}an not move south-east.`);
173-
return false;
174-
}
175-
}
176-
177-
// North-West
178-
if(destination.x < initialX && destination.y > initialY) {
179-
if(!this.canMoveDiagonally(origin, destinationAdjacency, destinationLocalX, destinationLocalY, initialX, initialY, -1, 1,
180-
0x1280138, 0x1280108, 0x1280120)) {
181-
// logger.warn(`${this.actor instanceof Player ? this.actor.username + ' c' : 'C'}an not move north-west.`);
182-
return false;
183-
}
184-
}
185-
186-
// North-East
187-
if(destination.x > initialX && destination.y > initialY) {
188-
if(!this.canMoveDiagonally(origin, destinationAdjacency, destinationLocalX, destinationLocalY, initialX, initialY, 1, 1,
189-
0x12801e0, 0x1280180, 0x1280120)) {
190-
// logger.warn(`${this.actor instanceof Player ? this.actor.username + ' c' : 'C'}an not move north-east.`);
191-
return false;
192-
}
193-
}
194-
195-
return true;
196-
}
197-
198-
private canMoveDiagonally(origin: Position, destinationAdjacency: number[][], destinationLocalX: number, destinationLocalY: number,
199-
initialX: number, initialY: number, offsetX: number, offsetY: number, destMask: number, cornerMask1: number, cornerMask2: number): boolean {
200-
const cornerX1: number = initialX + offsetX;
201-
const cornerY1: number = initialY;
202-
const cornerX2: number = initialX;
203-
const cornerY2: number = initialY + offsetY;
204-
const corner1 = this.calculateLocalCornerPosition(cornerX1, cornerY1, origin);
205-
const corner2 = this.calculateLocalCornerPosition(cornerX2, cornerY2, origin);
206-
207-
return ((destinationAdjacency[destinationLocalX][destinationLocalY] & destMask) == 0 &&
208-
(corner1.chunk.collisionMap.adjacency[corner1.localX][corner1.localY] & cornerMask1) == 0 &&
209-
(corner2.chunk.collisionMap.adjacency[corner2.localX][corner2.localY] & cornerMask2) == 0);
210-
}
211-
212-
private calculateLocalCornerPosition(cornerX: number, cornerY: number, origin: Position): { localX: number, localY: number, chunk: Chunk } {
213-
const cornerPosition: Position = new Position(cornerX, cornerY, origin.level + 1);
214-
let cornerChunk: Chunk = world.chunkManager.getChunkForWorldPosition(cornerPosition);
215-
const tileAbove: Tile = cornerChunk.getTile(cornerPosition);
216-
if(!tileAbove || !tileAbove.bridge) {
217-
cornerPosition.level = cornerPosition.level - 1;
218-
cornerChunk = world.chunkManager.getChunkForWorldPosition(cornerPosition);
219-
}
220-
const localX: number = cornerX - cornerChunk.collisionMap.insetX;
221-
const localY: number = cornerY - cornerChunk.collisionMap.insetY;
222-
223-
return { localX, localY, chunk: cornerChunk };
224-
}
225-
22696
public resetDirections(): void {
22797
this.actor.walkDirection = -1;
22898
this.actor.runDirection = -1;
@@ -286,7 +156,7 @@ export class WalkingQueue {
286156

287157
const currentPosition = this.actor.position;
288158

289-
if(this.canMoveTo(currentPosition, walkPosition)) {
159+
if(this.actor.pathfinding.canMoveTo(currentPosition, walkPosition)) {
290160
const oldChunk = world.chunkManager.getChunkForWorldPosition(currentPosition);
291161
const lastMapRegionUpdatePosition = this.actor.lastMapRegionUpdatePosition;
292162

@@ -308,7 +178,7 @@ export class WalkingQueue {
308178
if(this.actor.settings.runEnabled && this.queue.length !== 0) {
309179
const runPosition = this.queue.shift();
310180

311-
if(this.canMoveTo(walkPosition, runPosition)) {
181+
if(this.actor.pathfinding.canMoveTo(walkPosition, runPosition)) {
312182
const runDiffX = runPosition.x - walkPosition.x;
313183
const runDiffY = runPosition.y - walkPosition.y;
314184
runDir = this.calculateDirection(runDiffX, runDiffY);

0 commit comments

Comments
 (0)