rsmod/
lib.rs

1#![allow(non_snake_case)]
2#![allow(non_upper_case_globals)]
3#![allow(unused_must_use)]
4#![warn(static_mut_refs)]
5
6use std::ptr::addr_of;
7
8use once_cell::sync::Lazy;
9use wasm_bindgen::prelude::wasm_bindgen;
10
11use crate::rsmod::{
12    Blocked, can_travel, CollisionStrategies, CollisionType, find_naive_path, has_line_of_sight,
13    has_line_of_walk, Indoors, line_of_sight, line_of_walk, LineOfSight, LocAngle, LocLayer,
14    LocShape, Normal, Outdoors, PathFinder,
15};
16use crate::rsmod::collision::collision::CollisionFlagMap;
17use crate::rsmod::collision_flag::CollisionFlag;
18use crate::rsmod::reach_strategy::ReachStrategy;
19
20pub mod rsmod;
21
22// alloc on the heap for the wasm module globally.
23static mut COLLISION_FLAGS: Lazy<CollisionFlagMap> = Lazy::new(CollisionFlagMap::new);
24static mut PATHFINDER: Lazy<PathFinder> = Lazy::new(PathFinder::new);
25
26#[wasm_bindgen]
27pub unsafe fn findPath(
28    y: i32,
29    srcX: i32,
30    srcZ: i32,
31    destX: i32,
32    destZ: i32,
33    srcSize: u8,
34    destWidth: u8,
35    destHeight: u8,
36    angle: u8,
37    shape: i8,
38    moveNear: bool,
39    blockAccessFlags: u8,
40    maxWaypoints: u8,
41    collision: CollisionType,
42) -> Vec<u32> {
43    return PATHFINDER.find_path(
44        &**addr_of!(COLLISION_FLAGS),
45        y,
46        srcX,
47        srcZ,
48        destX,
49        destZ,
50        srcSize,
51        destWidth,
52        destHeight,
53        angle,
54        shape,
55        moveNear,
56        blockAccessFlags,
57        maxWaypoints,
58        &get_collision_strategy(collision),
59    );
60}
61
62#[wasm_bindgen]
63pub unsafe fn findNaivePath(
64    y: i32,
65    srcX: i32,
66    srcZ: i32,
67    destX: i32,
68    destZ: i32,
69    srcWidth: u8,
70    srcHeight: u8,
71    destWidth: u8,
72    destHeight: u8,
73    extraFlag: u32,
74    collision: CollisionType,
75) -> Vec<u32> {
76    return find_naive_path(
77        &**addr_of!(COLLISION_FLAGS),
78        y,
79        srcX,
80        srcZ,
81        destX,
82        destZ,
83        srcWidth,
84        srcHeight,
85        destWidth,
86        destHeight,
87        extraFlag,
88        &get_collision_strategy(collision),
89    );
90}
91
92#[wasm_bindgen]
93pub unsafe fn changeFloor(x: i32, z: i32, y: i32, add: bool) {
94    if add {
95        COLLISION_FLAGS.add(x, z, y, CollisionFlag::FLOOR as u32);
96    } else {
97        COLLISION_FLAGS.remove(x, z, y, CollisionFlag::FLOOR as u32);
98    }
99}
100
101#[wasm_bindgen]
102pub unsafe fn changeLoc(
103    x: i32,
104    z: i32,
105    y: i32,
106    width: i32,
107    length: i32,
108    blockrange: bool,
109    breakroutefinding: bool,
110    add: bool,
111) {
112    let mut mask: u32 = CollisionFlag::LOC as u32;
113    if blockrange {
114        mask |= CollisionFlag::LOC_PROJ_BLOCKER as u32;
115    }
116    if breakroutefinding {
117        mask |= CollisionFlag::LOC_ROUTE_BLOCKER as u32;
118    }
119    let area: i32 = width * length;
120    if add {
121        for index in 0..area {
122            let dx: i32 = x + (index % width);
123            let dz: i32 = z + (index / width);
124            COLLISION_FLAGS.add(dx, dz, y, mask);
125        }
126    } else {
127        for index in 0..area {
128            let dx: i32 = x + (index % width);
129            let dz: i32 = z + (index / width);
130            COLLISION_FLAGS.remove(dx, dz, y, mask);
131        }
132    }
133}
134
135#[wasm_bindgen]
136pub unsafe fn changeNpc(x: i32, z: i32, y: i32, size: i32, add: bool) {
137    let mask: u32 = CollisionFlag::NPC as u32;
138    let area: i32 = size * size;
139    if add {
140        for index in 0..area {
141            let dx: i32 = x + (index % size);
142            let dz: i32 = z + (index / size);
143            COLLISION_FLAGS.add(dx, dz, y, mask);
144        }
145    } else {
146        for index in 0..area {
147            let dx: i32 = x + (index % size);
148            let dz: i32 = z + (index / size);
149            COLLISION_FLAGS.remove(dx, dz, y, mask);
150        }
151    }
152}
153
154#[wasm_bindgen]
155pub unsafe fn changePlayer(x: i32, z: i32, y: i32, size: i32, add: bool) {
156    let mask: u32 = CollisionFlag::PLAYER as u32;
157    let area: i32 = size * size;
158    if add {
159        for index in 0..area {
160            let dx: i32 = x + (index % size);
161            let dz: i32 = z + (index / size);
162            COLLISION_FLAGS.add(dx, dz, y, mask);
163        }
164    } else {
165        for index in 0..area {
166            let dx: i32 = x + (index % size);
167            let dz: i32 = z + (index / size);
168            COLLISION_FLAGS.remove(dx, dz, y, mask);
169        }
170    }
171}
172
173#[wasm_bindgen]
174pub unsafe fn changeRoof(x: i32, z: i32, y: i32, add: bool) {
175    if add {
176        COLLISION_FLAGS.add(x, z, y, CollisionFlag::ROOF as u32);
177    } else {
178        COLLISION_FLAGS.remove(x, z, y, CollisionFlag::ROOF as u32);
179    }
180}
181
182#[wasm_bindgen]
183pub unsafe fn changeWall(
184    x: i32,
185    z: i32,
186    y: i32,
187    angle: u8,
188    shape: i8,
189    blockrange: bool,
190    breakroutefinding: bool,
191    add: bool,
192) {
193    match LocShape::from(shape) {
194        LocShape::WALL_STRAIGHT => {
195            changeWallStraight(x, z, y, angle, blockrange, breakroutefinding, add)
196        }
197        LocShape::WALL_DIAGONAL_CORNER | LocShape::WALL_SQUARE_CORNER => {
198            changeWallCorner(x, z, y, angle, blockrange, breakroutefinding, add)
199        }
200        LocShape::WALL_L => changeWallL(x, z, y, angle, blockrange, breakroutefinding, add),
201        _ => {}
202    }
203}
204
205#[inline(always)]
206unsafe fn changeWallStraight(
207    x: i32,
208    z: i32,
209    y: i32,
210    angle: u8,
211    blockrange: bool,
212    breakroutefinding: bool,
213    add: bool,
214) {
215    let west: u32 = if breakroutefinding {
216        CollisionFlag::WALL_WEST_ROUTE_BLOCKER
217    } else if blockrange {
218        CollisionFlag::WALL_WEST_PROJ_BLOCKER
219    } else {
220        CollisionFlag::WALL_WEST
221    } as u32;
222    let east: u32 = if breakroutefinding {
223        CollisionFlag::WALL_EAST_ROUTE_BLOCKER
224    } else if blockrange {
225        CollisionFlag::WALL_EAST_PROJ_BLOCKER
226    } else {
227        CollisionFlag::WALL_EAST
228    } as u32;
229    let north: u32 = if breakroutefinding {
230        CollisionFlag::WALL_NORTH_ROUTE_BLOCKER
231    } else if blockrange {
232        CollisionFlag::WALL_NORTH_PROJ_BLOCKER
233    } else {
234        CollisionFlag::WALL_NORTH
235    } as u32;
236    let south: u32 = if breakroutefinding {
237        CollisionFlag::WALL_SOUTH_ROUTE_BLOCKER
238    } else if blockrange {
239        CollisionFlag::WALL_SOUTH_PROJ_BLOCKER
240    } else {
241        CollisionFlag::WALL_SOUTH
242    } as u32;
243
244    match LocAngle::from(angle) {
245        LocAngle::WEST => {
246            if add {
247                COLLISION_FLAGS.add(x, z, y, west);
248                COLLISION_FLAGS.add(x - 1, z, y, east);
249            } else {
250                COLLISION_FLAGS.remove(x, z, y, west);
251                COLLISION_FLAGS.remove(x - 1, z, y, east);
252            }
253        }
254        LocAngle::NORTH => {
255            if add {
256                COLLISION_FLAGS.add(x, z, y, north);
257                COLLISION_FLAGS.add(x, z + 1, y, south);
258            } else {
259                COLLISION_FLAGS.remove(x, z, y, north);
260                COLLISION_FLAGS.remove(x, z + 1, y, south);
261            }
262        }
263        LocAngle::EAST => {
264            if add {
265                COLLISION_FLAGS.add(x, z, y, east);
266                COLLISION_FLAGS.add(x + 1, z, y, west);
267            } else {
268                COLLISION_FLAGS.remove(x, z, y, east);
269                COLLISION_FLAGS.remove(x + 1, z, y, west);
270            }
271        }
272        LocAngle::SOUTH => {
273            if add {
274                COLLISION_FLAGS.add(x, z, y, south);
275                COLLISION_FLAGS.add(x, z - 1, y, north);
276            } else {
277                COLLISION_FLAGS.remove(x, z, y, south);
278                COLLISION_FLAGS.remove(x, z - 1, y, north);
279            }
280        }
281    }
282    if breakroutefinding {
283        return changeWallStraight(x, z, y, angle, blockrange, false, add);
284    }
285    if blockrange {
286        return changeWallStraight(x, z, y, angle, false, false, add);
287    }
288}
289
290#[inline(always)]
291unsafe fn changeWallCorner(
292    x: i32,
293    z: i32,
294    y: i32,
295    angle: u8,
296    blockrange: bool,
297    breakroutefinding: bool,
298    add: bool,
299) {
300    let north_west: u32 = if breakroutefinding {
301        CollisionFlag::WALL_NORTH_WEST_ROUTE_BLOCKER
302    } else if blockrange {
303        CollisionFlag::WALL_NORTH_WEST_PROJ_BLOCKER
304    } else {
305        CollisionFlag::WALL_NORTH_WEST
306    } as u32;
307    let south_east: u32 = if breakroutefinding {
308        CollisionFlag::WALL_SOUTH_EAST_ROUTE_BLOCKER
309    } else if blockrange {
310        CollisionFlag::WALL_SOUTH_EAST_PROJ_BLOCKER
311    } else {
312        CollisionFlag::WALL_SOUTH_EAST
313    } as u32;
314    let north_east: u32 = if breakroutefinding {
315        CollisionFlag::WALL_NORTH_EAST_ROUTE_BLOCKER
316    } else if blockrange {
317        CollisionFlag::WALL_NORTH_EAST_PROJ_BLOCKER
318    } else {
319        CollisionFlag::WALL_NORTH_EAST
320    } as u32;
321    let south_west: u32 = if breakroutefinding {
322        CollisionFlag::WALL_SOUTH_WEST_ROUTE_BLOCKER
323    } else if blockrange {
324        CollisionFlag::WALL_SOUTH_WEST_PROJ_BLOCKER
325    } else {
326        CollisionFlag::WALL_SOUTH_WEST
327    } as u32;
328
329    match LocAngle::from(angle) {
330        LocAngle::WEST => {
331            if add {
332                COLLISION_FLAGS.add(x, z, y, north_west);
333                COLLISION_FLAGS.add(x - 1, z + 1, y, south_east);
334            } else {
335                COLLISION_FLAGS.remove(x, z, y, north_west);
336                COLLISION_FLAGS.remove(x - 1, z + 1, y, south_east);
337            }
338        }
339        LocAngle::NORTH => {
340            if add {
341                COLLISION_FLAGS.add(x, z, y, north_east);
342                COLLISION_FLAGS.add(x + 1, z + 1, y, south_west);
343            } else {
344                COLLISION_FLAGS.remove(x, z, y, north_east);
345                COLLISION_FLAGS.remove(x + 1, z + 1, y, south_west);
346            }
347        }
348        LocAngle::EAST => {
349            if add {
350                COLLISION_FLAGS.add(x, z, y, south_east);
351                COLLISION_FLAGS.add(x + 1, z - 1, y, north_west);
352            } else {
353                COLLISION_FLAGS.remove(x, z, y, south_east);
354                COLLISION_FLAGS.remove(x + 1, z - 1, y, north_west);
355            }
356        }
357        LocAngle::SOUTH => {
358            if add {
359                COLLISION_FLAGS.add(x, z, y, south_west);
360                COLLISION_FLAGS.add(x - 1, z - 1, y, north_east);
361            } else {
362                COLLISION_FLAGS.remove(x, z, y, south_west);
363                COLLISION_FLAGS.remove(x - 1, z - 1, y, north_east);
364            }
365        }
366    }
367    if breakroutefinding {
368        return changeWallCorner(x, z, y, angle, blockrange, false, add);
369    }
370    if blockrange {
371        return changeWallCorner(x, z, y, angle, false, false, add);
372    }
373}
374
375#[inline(always)]
376unsafe fn changeWallL(
377    x: i32,
378    z: i32,
379    y: i32,
380    angle: u8,
381    blockrange: bool,
382    breakroutefinding: bool,
383    add: bool,
384) {
385    let west: u32 = if breakroutefinding {
386        CollisionFlag::WALL_WEST_ROUTE_BLOCKER
387    } else if blockrange {
388        CollisionFlag::WALL_WEST_PROJ_BLOCKER
389    } else {
390        CollisionFlag::WALL_WEST
391    } as u32;
392    let east: u32 = if breakroutefinding {
393        CollisionFlag::WALL_EAST_ROUTE_BLOCKER
394    } else if blockrange {
395        CollisionFlag::WALL_EAST_PROJ_BLOCKER
396    } else {
397        CollisionFlag::WALL_EAST
398    } as u32;
399    let north: u32 = if breakroutefinding {
400        CollisionFlag::WALL_NORTH_ROUTE_BLOCKER
401    } else if blockrange {
402        CollisionFlag::WALL_NORTH_PROJ_BLOCKER
403    } else {
404        CollisionFlag::WALL_NORTH
405    } as u32;
406    let south: u32 = if breakroutefinding {
407        CollisionFlag::WALL_SOUTH_ROUTE_BLOCKER
408    } else if blockrange {
409        CollisionFlag::WALL_SOUTH_PROJ_BLOCKER
410    } else {
411        CollisionFlag::WALL_SOUTH
412    } as u32;
413
414    match LocAngle::from(angle) {
415        LocAngle::WEST => {
416            if add {
417                COLLISION_FLAGS.add(x, z, y, north | west);
418                COLLISION_FLAGS.add(x - 1, z, y, east);
419                COLLISION_FLAGS.add(x, z + 1, y, south);
420            } else {
421                COLLISION_FLAGS.remove(x, z, y, north | west);
422                COLLISION_FLAGS.remove(x - 1, z, y, east);
423                COLLISION_FLAGS.remove(x, z + 1, y, south);
424            }
425        }
426        LocAngle::NORTH => {
427            if add {
428                COLLISION_FLAGS.add(x, z, y, north | east);
429                COLLISION_FLAGS.add(x, z + 1, y, south);
430                COLLISION_FLAGS.add(x + 1, z, y, west);
431            } else {
432                COLLISION_FLAGS.remove(x, z, y, north | east);
433                COLLISION_FLAGS.remove(x, z + 1, y, south);
434                COLLISION_FLAGS.remove(x + 1, z, y, west);
435            }
436        }
437        LocAngle::EAST => {
438            if add {
439                COLLISION_FLAGS.add(x, z, y, south | east);
440                COLLISION_FLAGS.add(x + 1, z, y, west);
441                COLLISION_FLAGS.add(x, z - 1, y, north);
442            } else {
443                COLLISION_FLAGS.remove(x, z, y, south | east);
444                COLLISION_FLAGS.remove(x + 1, z, y, west);
445                COLLISION_FLAGS.remove(x, z - 1, y, north);
446            }
447        }
448        LocAngle::SOUTH => {
449            if add {
450                COLLISION_FLAGS.add(x, z, y, south | west);
451                COLLISION_FLAGS.add(x, z - 1, y, north);
452                COLLISION_FLAGS.add(x - 1, z, y, east);
453            } else {
454                COLLISION_FLAGS.remove(x, z, y, south | west);
455                COLLISION_FLAGS.remove(x, z - 1, y, north);
456                COLLISION_FLAGS.remove(x - 1, z, y, east);
457            }
458        }
459    }
460    if breakroutefinding {
461        return changeWallL(x, z, y, angle, blockrange, false, add);
462    }
463    if blockrange {
464        return changeWallL(x, z, y, angle, false, false, add);
465    }
466}
467
468#[wasm_bindgen]
469pub unsafe fn allocateIfAbsent(x: i32, z: i32, y: i32) {
470    COLLISION_FLAGS.allocate_if_absent(x, z, y);
471}
472
473#[wasm_bindgen]
474pub unsafe fn deallocateIfPresent(x: i32, z: i32, y: i32) {
475    COLLISION_FLAGS.deallocate_if_present(x, z, y);
476}
477
478#[wasm_bindgen]
479pub unsafe fn isZoneAllocated(x: i32, z: i32, y: i32) -> bool {
480    return COLLISION_FLAGS.is_zone_allocated(x, z, y);
481}
482
483#[wasm_bindgen]
484pub unsafe fn isFlagged(x: i32, z: i32, y: i32, masks: u32) -> bool {
485    return COLLISION_FLAGS.is_flagged(x, z, y, masks);
486}
487
488#[wasm_bindgen]
489pub unsafe fn canTravel(
490    y: i32,
491    x: i32,
492    z: i32,
493    offsetX: i8,
494    offsetZ: i8,
495    size: u8,
496    extraFlag: u32,
497    collision: CollisionType,
498) -> bool {
499    return can_travel(
500        &**addr_of!(COLLISION_FLAGS),
501        y,
502        x,
503        z,
504        offsetX,
505        offsetZ,
506        size,
507        extraFlag,
508        &get_collision_strategy(collision),
509    );
510}
511
512#[wasm_bindgen]
513pub unsafe fn hasLineOfSight(
514    y: i32,
515    srcX: i32,
516    srcZ: i32,
517    destX: i32,
518    destZ: i32,
519    srcWidth: u8,
520    srcHeight: u8,
521    destWidth: u8,
522    destHeight: u8,
523    extraFlag: u32,
524) -> bool {
525    return has_line_of_sight(
526        &**addr_of!(COLLISION_FLAGS),
527        y,
528        srcX,
529        srcZ,
530        destX,
531        destZ,
532        srcWidth,
533        srcHeight,
534        destWidth,
535        destHeight,
536        extraFlag,
537    );
538}
539
540#[wasm_bindgen]
541pub unsafe fn hasLineOfWalk(
542    y: i32,
543    srcX: i32,
544    srcZ: i32,
545    destX: i32,
546    destZ: i32,
547    srcWidth: u8,
548    srcHeight: u8,
549    destWidth: u8,
550    destHeight: u8,
551    extraFlag: u32,
552) -> bool {
553    return has_line_of_walk(
554        &**addr_of!(COLLISION_FLAGS),
555        y,
556        srcX,
557        srcZ,
558        destX,
559        destZ,
560        srcWidth,
561        srcHeight,
562        destWidth,
563        destHeight,
564        extraFlag,
565    );
566}
567
568#[wasm_bindgen]
569pub unsafe fn lineOfSight(
570    y: i32,
571    srcX: i32,
572    srcZ: i32,
573    destX: i32,
574    destZ: i32,
575    srcWidth: u8,
576    srcHeight: u8,
577    destWidth: u8,
578    destHeight: u8,
579    extraFlag: u32,
580) -> Vec<u32> {
581    return line_of_sight(
582        &**addr_of!(COLLISION_FLAGS),
583        y,
584        srcX,
585        srcZ,
586        destX,
587        destZ,
588        srcWidth,
589        srcHeight,
590        destWidth,
591        destHeight,
592        extraFlag,
593    );
594}
595
596#[wasm_bindgen]
597pub unsafe fn lineOfWalk(
598    y: i32,
599    srcX: i32,
600    srcZ: i32,
601    destX: i32,
602    destZ: i32,
603    srcWidth: u8,
604    srcHeight: u8,
605    destWidth: u8,
606    destHeight: u8,
607    extraFlag: u32,
608) -> Vec<u32> {
609    return line_of_walk(
610        &**addr_of!(COLLISION_FLAGS),
611        y,
612        srcX,
613        srcZ,
614        destX,
615        destZ,
616        srcWidth,
617        srcHeight,
618        destWidth,
619        destHeight,
620        extraFlag,
621    );
622}
623
624#[wasm_bindgen]
625pub unsafe fn reached(
626    y: i32,
627    srcX: i32,
628    srcZ: i32,
629    destX: i32,
630    destZ: i32,
631    destWidth: u8,
632    destHeight: u8,
633    srcSize: u8,
634    angle: u8,
635    shape: i8,
636    blockAccessFlags: u8,
637) -> bool {
638    return ReachStrategy::reached(
639        &**addr_of!(COLLISION_FLAGS),
640        y,
641        srcX,
642        srcZ,
643        destX,
644        destZ,
645        destWidth,
646        destHeight,
647        srcSize,
648        angle,
649        shape,
650        blockAccessFlags,
651    );
652}
653
654#[wasm_bindgen]
655pub fn locShapeLayer(shape: LocShape) -> LocLayer {
656    return match shape {
657        LocShape::WALL_STRAIGHT
658        | LocShape::WALL_DIAGONAL_CORNER
659        | LocShape::WALL_L
660        | LocShape::WALL_SQUARE_CORNER => LocLayer::WALL,
661
662        LocShape::WALLDECOR_STRAIGHT_NOOFFSET
663        | LocShape::WALLDECOR_STRAIGHT_OFFSET
664        | LocShape::WALLDECOR_DIAGONAL_OFFSET
665        | LocShape::WALLDECOR_DIAGONAL_NOOFFSET
666        | LocShape::WALLDECOR_DIAGONAL_BOTH => LocLayer::WALL_DECOR,
667
668        LocShape::WALL_DIAGONAL
669        | LocShape::CENTREPIECE_STRAIGHT
670        | LocShape::CENTREPIECE_DIAGONAL
671        | LocShape::ROOF_STRAIGHT
672        | LocShape::ROOF_DIAGONAL_WITH_ROOFEDGE
673        | LocShape::ROOF_DIAGONAL
674        | LocShape::ROOF_L_CONCAVE
675        | LocShape::ROOF_L_CONVEX
676        | LocShape::ROOF_FLAT
677        | LocShape::ROOFEDGE_STRAIGHT
678        | LocShape::ROOFEDGE_DIAGONAL_CORNER
679        | LocShape::ROOFEDGE_L
680        | LocShape::ROOFEDGE_SQUARE_CORNER => LocLayer::GROUND,
681
682        LocShape::GROUND_DECOR => LocLayer::GROUND_DECOR,
683    };
684}
685
686// this is only to test benchmarking lumbridge.
687#[wasm_bindgen]
688pub unsafe fn __set(x: i32, z: i32, y: i32, mask: u32) {
689    COLLISION_FLAGS.set(x, z, y, mask);
690}
691
692#[inline(always)]
693fn get_collision_strategy(collision: CollisionType) -> CollisionStrategies {
694    return match collision {
695        CollisionType::NORMAL => CollisionStrategies::Normal(Normal),
696        CollisionType::BLOCKED => CollisionStrategies::Blocked(Blocked),
697        CollisionType::INDOORS => CollisionStrategies::Indoors(Indoors),
698        CollisionType::OUTDOORS => CollisionStrategies::Outdoors(Outdoors),
699        CollisionType::LINE_OF_SIGHT => CollisionStrategies::LineOfSight(LineOfSight),
700    };
701}