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
22static 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#[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}