@rpgjs/server 5.0.0-beta.5 → 5.0.0-beta.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2461,6 +2461,24 @@ __decorate([sync(), __decorateMetadata("design:type", Object)], Skill.prototype,
2461
2461
  __decorate([sync(), __decorateMetadata("design:type", Object)], Skill.prototype, "icon", void 0);
2462
2462
  //#endregion
2463
2463
  //#region ../common/src/Player.ts
2464
+ var readReactiveValue = (value) => {
2465
+ if (typeof value === "function" && value.observable) return value();
2466
+ return value;
2467
+ };
2468
+ var toCloneableSyncValue = (value, seen = /* @__PURE__ */ new WeakSet()) => {
2469
+ const resolved = readReactiveValue(value);
2470
+ if (resolved == null || typeof resolved !== "object") return typeof resolved === "function" ? void 0 : resolved;
2471
+ if (seen.has(resolved)) return;
2472
+ seen.add(resolved);
2473
+ if (Array.isArray(resolved)) return resolved.map((item) => toCloneableSyncValue(item, seen)).filter((item) => item !== void 0);
2474
+ const output = {};
2475
+ for (const [key, child] of Object.entries(resolved)) {
2476
+ if (key.startsWith("$") || key === "_itemInstance" || key === "_subject" || key === "observable" || key === "options") continue;
2477
+ const childValue = toCloneableSyncValue(child, seen);
2478
+ if (childValue !== void 0) output[key.startsWith("__") ? key.slice(2) : key] = childValue;
2479
+ }
2480
+ return output;
2481
+ };
2464
2482
  var Direction = /* @__PURE__ */ function(Direction) {
2465
2483
  Direction["Up"] = "up";
2466
2484
  Direction["Down"] = "down";
@@ -2644,8 +2662,11 @@ __decorate([sync(), __decorateMetadata("design:type", Object)], RpgCommonPlayer.
2644
2662
  __decorate([sync(), __decorateMetadata("design:type", Object)], RpgCommonPlayer.prototype, "_exp", void 0);
2645
2663
  __decorate([sync(), __decorateMetadata("design:type", Object)], RpgCommonPlayer.prototype, "_level", void 0);
2646
2664
  __decorate([sync(), __decorateMetadata("design:type", Object)], RpgCommonPlayer.prototype, "_class", void 0);
2647
- __decorate([sync(Item), __decorateMetadata("design:type", Object)], RpgCommonPlayer.prototype, "items", void 0);
2648
- __decorate([sync(), __decorateMetadata("design:type", Object)], RpgCommonPlayer.prototype, "equipments", void 0);
2665
+ __decorate([sync({
2666
+ classType: Item,
2667
+ transform: toCloneableSyncValue
2668
+ }), __decorateMetadata("design:type", Object)], RpgCommonPlayer.prototype, "items", void 0);
2669
+ __decorate([sync({ transform: toCloneableSyncValue }), __decorateMetadata("design:type", Object)], RpgCommonPlayer.prototype, "equipments", void 0);
2649
2670
  __decorate([sync(), __decorateMetadata("design:type", Object)], RpgCommonPlayer.prototype, "states", void 0);
2650
2671
  __decorate([sync(Skill), __decorateMetadata("design:type", Object)], RpgCommonPlayer.prototype, "skills", void 0);
2651
2672
  __decorate([sync(), __decorateMetadata("design:type", Object)], RpgCommonPlayer.prototype, "_effects", void 0);
@@ -4766,6 +4787,18 @@ var CapsuleCollider = class CapsuleCollider {
4766
4787
  }
4767
4788
  };
4768
4789
  //#endregion
4790
+ //#region ../physic/src/collision/collider-cache.ts
4791
+ var colliderCache = /* @__PURE__ */ new WeakMap();
4792
+ function getCachedCollider(entity) {
4793
+ return colliderCache.get(entity);
4794
+ }
4795
+ function setCachedCollider(entity, collider) {
4796
+ colliderCache.set(entity, collider);
4797
+ }
4798
+ function invalidateCollider(entity) {
4799
+ colliderCache.delete(entity);
4800
+ }
4801
+ //#endregion
4769
4802
  //#region ../physic/src/collision/PolygonCollider.ts
4770
4803
  /**
4771
4804
  * Weak registry to attach polygon configurations to entities
@@ -4785,6 +4818,7 @@ var entityToPolygonConfig = /* @__PURE__ */ new WeakMap();
4785
4818
  */
4786
4819
  function assignPolygonCollider(entity, config) {
4787
4820
  entityToPolygonConfig.set(entity, config);
4821
+ invalidateCollider(entity);
4788
4822
  }
4789
4823
  /**
4790
4824
  * Polygon collider implementation (convex via SAT; concave via convex parts)
@@ -5090,7 +5124,6 @@ function polygonCentroid(poly) {
5090
5124
  }
5091
5125
  //#endregion
5092
5126
  //#region ../physic/src/collision/detector.ts
5093
- var colliderCache = /* @__PURE__ */ new WeakMap();
5094
5127
  /**
5095
5128
  * Collision detector
5096
5129
  *
@@ -5104,14 +5137,14 @@ var colliderCache = /* @__PURE__ */ new WeakMap();
5104
5137
  * @returns Appropriate collider instance
5105
5138
  */
5106
5139
  function createCollider(entity) {
5107
- const cached = colliderCache.get(entity);
5140
+ const cached = getCachedCollider(entity);
5108
5141
  if (cached) return cached;
5109
5142
  let collider = null;
5110
5143
  if (entityToPolygonConfig.has(entity)) collider = new PolygonCollider(entity);
5111
5144
  else if (entity.capsule) collider = new CapsuleCollider(entity);
5112
5145
  else if (entity.radius > 0) collider = new CircleCollider(entity);
5113
5146
  else if (entity.width > 0 && entity.height > 0) collider = new AABBCollider(entity);
5114
- if (collider) colliderCache.set(entity, collider);
5147
+ if (collider) setCachedCollider(entity, collider);
5115
5148
  return collider;
5116
5149
  }
5117
5150
  /**
@@ -5127,7 +5160,24 @@ function testCollision(entityA, entityB) {
5127
5160
  const colliderA = createCollider(entityA);
5128
5161
  const colliderB = createCollider(entityB);
5129
5162
  if (!colliderA || !colliderB) return null;
5130
- return colliderA.testCollision(colliderB);
5163
+ const directCollision = colliderA.testCollision(colliderB);
5164
+ if (directCollision) return directCollision;
5165
+ const reverseCollision = colliderB.testCollision(colliderA);
5166
+ if (!reverseCollision) return null;
5167
+ return reverseCollisionInfo(reverseCollision);
5168
+ }
5169
+ function reverseCollisionInfo(collision) {
5170
+ return {
5171
+ entityA: collision.entityB,
5172
+ entityB: collision.entityA,
5173
+ contacts: collision.contacts.map((contact) => ({
5174
+ point: contact.point,
5175
+ normal: contact.normal.mul(-1),
5176
+ depth: contact.depth
5177
+ })),
5178
+ normal: collision.normal.mul(-1),
5179
+ depth: collision.depth
5180
+ };
5131
5181
  }
5132
5182
  //#endregion
5133
5183
  //#region ../physic/src/collision/spatial-hash.ts
@@ -5476,148 +5526,6 @@ var Ray = class {
5476
5526
  }
5477
5527
  };
5478
5528
  //#endregion
5479
- //#region ../physic/src/collision/raycast.ts
5480
- /**
5481
- * Casts a ray in the world using the spatial partition for broad-phase, then shape-specific narrow-phase.
5482
- * Direction will be normalized internally.
5483
- *
5484
- * @param partition - Spatial partition to query
5485
- * @param origin - Ray origin
5486
- * @param direction - Ray direction (any length)
5487
- * @param maxDistance - Maximum distance
5488
- * @param mask - Optional collision mask (layer)
5489
- * @param filter - Optional filter function (return true to include entity)
5490
- * @returns Nearest hit or null
5491
- *
5492
- * @example
5493
- * ```typescript
5494
- * const hit = raycast(worldPartition, new Vector2(0,0), new Vector2(1,0), 1000);
5495
- * if (hit) {
5496
- * // handle
5497
- * }
5498
- * ```
5499
- */
5500
- function raycast(partition, origin, direction, maxDistance, mask, filter) {
5501
- const dir = direction.length() > 0 ? direction.normalize() : new Vector2(1, 0);
5502
- const end = origin.add(dir.mul(maxDistance));
5503
- const candidates = partition.raycast(new Ray(origin, dir, maxDistance), mask, filter);
5504
- if (candidates) return candidates;
5505
- const bounds = new AABB(Math.min(origin.x, end.x), Math.min(origin.y, end.y), Math.max(origin.x, end.x), Math.max(origin.y, end.y));
5506
- const entities = partition.queryAABB(bounds);
5507
- let best = null;
5508
- for (const e of entities) {
5509
- if (mask !== void 0 && (e.collisionCategory & mask) === 0) continue;
5510
- if (filter && !filter(e)) continue;
5511
- const collider = createCollider(e);
5512
- if (!collider) continue;
5513
- const hit = raycastCollider(collider, origin, dir, maxDistance);
5514
- if (!hit) continue;
5515
- if (!best || hit.distance < best.distance) best = hit;
5516
- }
5517
- return best;
5518
- }
5519
- function raycastCollider(collider, origin, dir, maxDistance) {
5520
- if (collider instanceof CircleCollider) return raycastCircle(collider, origin, dir, maxDistance);
5521
- if (collider instanceof AABBCollider) return raycastAABB(collider, origin, dir, maxDistance);
5522
- if (collider instanceof PolygonCollider) return raycastPolygon(collider, origin, dir, maxDistance);
5523
- return null;
5524
- }
5525
- function raycastCircle(circle, origin, dir, maxDistance) {
5526
- const c = circle.getCenter();
5527
- const r = circle.getRadius();
5528
- const m = origin.sub(c);
5529
- const b = m.dot(dir);
5530
- const cval = m.dot(m) - r * r;
5531
- if (cval > 0 && b > 0) return null;
5532
- const discr = b * b - cval;
5533
- if (discr < 0) return null;
5534
- const t = -b - Math.sqrt(discr);
5535
- if (t < 0) return null;
5536
- if (t > maxDistance) return null;
5537
- const point = origin.add(dir.mul(t));
5538
- const normal = point.sub(c).normalize();
5539
- return {
5540
- entity: circle.getEntity(),
5541
- point,
5542
- normal,
5543
- distance: t
5544
- };
5545
- }
5546
- function raycastAABB(box, origin, dir, maxDistance) {
5547
- const b = box.getBounds();
5548
- let tmin = 0;
5549
- let tmax = maxDistance;
5550
- const invDx = 1 / (dir.x === 0 ? 1e-9 : dir.x);
5551
- const invDy = 1 / (dir.y === 0 ? 1e-9 : dir.y);
5552
- let tx1 = (b.minX - origin.x) * invDx;
5553
- let tx2 = (b.maxX - origin.x) * invDx;
5554
- let ty1 = (b.minY - origin.y) * invDy;
5555
- let ty2 = (b.maxY - origin.y) * invDy;
5556
- const tminX = Math.min(tx1, tx2);
5557
- const tmaxX = Math.max(tx1, tx2);
5558
- const tminY = Math.min(ty1, ty2);
5559
- const tmaxY = Math.max(ty1, ty2);
5560
- tmin = Math.max(tmin, Math.max(tminX, tminY));
5561
- tmax = Math.min(tmax, Math.min(tmaxX, tmaxY));
5562
- if (tmax < tmin || tmin < 0 || tmin > maxDistance) return null;
5563
- const point = origin.add(dir.mul(tmin));
5564
- let normal;
5565
- if (tmin === tminX) normal = new Vector2(dir.x > 0 ? -1 : 1, 0);
5566
- else normal = new Vector2(0, dir.y > 0 ? -1 : 1);
5567
- return {
5568
- entity: box.getEntity(),
5569
- point,
5570
- normal,
5571
- distance: tmin
5572
- };
5573
- }
5574
- function raycastPolygon(poly, origin, dir, maxDistance) {
5575
- const end = origin.add(dir.mul(maxDistance));
5576
- let bestT = Number.POSITIVE_INFINITY;
5577
- let bestPoint = null;
5578
- let bestNormal = null;
5579
- const any = poly;
5580
- const parts = any["getWorldParts"] ? any["getWorldParts"]() : [];
5581
- for (const part of parts) for (let i = 0; i < part.length; i++) {
5582
- const a = part[i];
5583
- const b = part[(i + 1) % part.length];
5584
- if (!a || !b) continue;
5585
- const hit = segmentRayIntersection(a, b, origin, end);
5586
- if (!hit) continue;
5587
- const t = hit.distance;
5588
- if (t >= 0 && t <= maxDistance && t < bestT) {
5589
- bestT = t;
5590
- bestPoint = hit.point;
5591
- const edge = b.sub(a);
5592
- bestNormal = new Vector2(-edge.y, edge.x).normalize();
5593
- }
5594
- }
5595
- if (!bestPoint || !bestNormal || bestT === Number.POSITIVE_INFINITY) return null;
5596
- return {
5597
- entity: poly.getEntity(),
5598
- point: bestPoint,
5599
- normal: bestNormal,
5600
- distance: bestT
5601
- };
5602
- }
5603
- function segmentRayIntersection(a, b, r0, r1) {
5604
- const v1 = r0.sub(a);
5605
- const v2 = b.sub(a);
5606
- const v3 = new Vector2(-(r1.y - r0.y), r1.x - r0.x);
5607
- const denom = v2.dot(v3);
5608
- if (Math.abs(denom) < 1e-9) return null;
5609
- const t1 = v2.cross(v1) / denom;
5610
- const t2 = v1.dot(v3) / denom;
5611
- if (t1 >= 0 && t1 <= 1 && t2 >= 0 && t2 <= 1) {
5612
- const hitPoint = new Vector2(r0.x + (r1.x - r0.x) * t1, r0.y + (r1.y - r0.y) * t1);
5613
- return {
5614
- point: hitPoint,
5615
- distance: hitPoint.sub(r0).length()
5616
- };
5617
- }
5618
- return null;
5619
- }
5620
- //#endregion
5621
5529
  //#region ../physic/src/collision/resolver.ts
5622
5530
  /**
5623
5531
  * Collision resolver
@@ -6077,13 +5985,41 @@ var World = class {
6077
5985
  */
6078
5986
  addEntity(entity) {
6079
5987
  this.entities.add(entity);
6080
- if (entity.isStatic()) this.staticEntities.add(entity);
6081
- else this.dynamicEntities.add(entity);
5988
+ this.syncEntityCollection(entity);
6082
5989
  this.spatialPartition.insert(entity);
6083
5990
  this.events.emitEntityAdded(entity);
6084
5991
  return entity;
6085
5992
  }
6086
5993
  /**
5994
+ * Synchronizes an entity with the world's broad-phase structures.
5995
+ *
5996
+ * Call this after manually changing an entity position, dimensions, or state
5997
+ * outside the normal physics step.
5998
+ *
5999
+ * @param entity - Entity to synchronize
6000
+ */
6001
+ updateEntity(entity) {
6002
+ if (!this.entities.has(entity)) return;
6003
+ invalidateCollider(entity);
6004
+ this.syncEntity(entity);
6005
+ }
6006
+ syncEntity(entity) {
6007
+ this.syncEntityCollection(entity);
6008
+ this.spatialPartition.update(entity);
6009
+ }
6010
+ /**
6011
+ * Queries entities in an AABB region.
6012
+ *
6013
+ * The returned array comes from the broad-phase partition and may contain
6014
+ * false positives from overlapping cells.
6015
+ *
6016
+ * @param bounds - AABB to query
6017
+ * @returns Array of entities in overlapping partition cells
6018
+ */
6019
+ queryAABB(bounds) {
6020
+ return Array.from(this.spatialPartition.queryAABB(bounds));
6021
+ }
6022
+ /**
6087
6023
  * Performs a raycast against all entities in the world.
6088
6024
  *
6089
6025
  * @param origin - Starting point of the ray
@@ -6143,13 +6079,14 @@ var World = class {
6143
6079
  * Updates all entities, detects and resolves collisions.
6144
6080
  */
6145
6081
  step() {
6146
- this.refreshDynamicEntitiesInPartition();
6082
+ this.refreshEntitiesInPartition();
6147
6083
  for (const entity of this.dynamicEntities) if (!entity.isSleeping()) {
6148
6084
  const startPos = entity.position.clone();
6149
6085
  this.integrator.integrate(entity);
6150
6086
  this.updateEntityTile(entity, startPos);
6151
6087
  if (entity.continuous) this.performCCD(entity);
6152
6088
  }
6089
+ this.refreshDynamicEntitiesInPartition();
6153
6090
  let firstPassCollisions = [];
6154
6091
  for (let iteration = 0; iteration < this.resolverIterations; iteration++) {
6155
6092
  const collisions = this.detectCollisions();
@@ -6157,9 +6094,12 @@ var World = class {
6157
6094
  if (collisions.length === 0) break;
6158
6095
  this.sortCollisionsForDeterminism(collisions);
6159
6096
  this.resolver.resolveAll(collisions);
6160
- if (iteration + 1 < this.resolverIterations) this.refreshDynamicEntitiesInPartition();
6097
+ this.refreshDynamicEntitiesInPartition();
6098
+ }
6099
+ if (this.positionQuantizationStep !== null || this.velocityQuantizationStep !== null) {
6100
+ this.quantizeEntities();
6101
+ this.refreshDynamicEntitiesInPartition();
6161
6102
  }
6162
- if (this.positionQuantizationStep !== null || this.velocityQuantizationStep !== null) this.quantizeEntities();
6163
6103
  this.handleCollisionEvents(firstPassCollisions);
6164
6104
  if (this.enableSleep) this.updateSleepState();
6165
6105
  }
@@ -6249,7 +6189,10 @@ var World = class {
6249
6189
  clear() {
6250
6190
  for (const entity of this.entities) this.events.emitEntityRemoved(entity);
6251
6191
  this.entities.clear();
6192
+ this.staticEntities.clear();
6193
+ this.dynamicEntities.clear();
6252
6194
  this.spatialPartition.clear();
6195
+ this.queryResults.clear();
6253
6196
  this.previousCollisions.clear();
6254
6197
  }
6255
6198
  quantizeEntities() {
@@ -6270,6 +6213,18 @@ var World = class {
6270
6213
  refreshDynamicEntitiesInPartition() {
6271
6214
  for (const entity of this.dynamicEntities) this.spatialPartition.update(entity);
6272
6215
  }
6216
+ refreshEntitiesInPartition() {
6217
+ for (const entity of this.entities) this.syncEntity(entity);
6218
+ }
6219
+ syncEntityCollection(entity) {
6220
+ if (entity.isStatic()) {
6221
+ this.dynamicEntities.delete(entity);
6222
+ this.staticEntities.add(entity);
6223
+ } else {
6224
+ this.staticEntities.delete(entity);
6225
+ this.dynamicEntities.add(entity);
6226
+ }
6227
+ }
6273
6228
  /**
6274
6229
  * Gets statistics about the world
6275
6230
  *
@@ -6358,6 +6313,10 @@ var World = class {
6358
6313
  *
6359
6314
  * Represents an independent simulation zone that can contain entities.
6360
6315
  * Regions can overlap to allow smooth entity transitions.
6316
+ *
6317
+ * @experimental Region simulation is not the recommended default path for
6318
+ * RPG-JS server physics yet. Prefer a single `PhysicsEngine` world until
6319
+ * region migration semantics are fully benchmarked and documented.
6361
6320
  *
6362
6321
  * @example
6363
6322
  * ```typescript
@@ -6509,6 +6468,11 @@ var Region = class {
6509
6468
  *
6510
6469
  * Manages multiple regions in a distributed physics world.
6511
6470
  * Handles entity migration between regions and region activation/deactivation.
6471
+ *
6472
+ * @experimental Region simulation is not the recommended default path for
6473
+ * RPG-JS server physics yet. Prefer `PhysicsEngine` without regions until
6474
+ * migration semantics, events, stats, and config propagation are fully
6475
+ * benchmarked and documented.
6512
6476
  *
6513
6477
  * @example
6514
6478
  * ```typescript
@@ -6617,6 +6581,37 @@ var RegionManager = class {
6617
6581
  }
6618
6582
  }
6619
6583
  /**
6584
+ * Synchronizes an entity with its current region, migrating it when needed.
6585
+ *
6586
+ * @param entity - Entity to synchronize
6587
+ */
6588
+ updateEntity(entity) {
6589
+ const currentRegion = this.entityRegionMap.get(entity);
6590
+ const newRegion = this.getRegionAt(entity.position);
6591
+ if (!newRegion) {
6592
+ if (currentRegion) {
6593
+ currentRegion.removeEntity(entity);
6594
+ this.entityRegionMap.delete(entity);
6595
+ }
6596
+ return;
6597
+ }
6598
+ if (!currentRegion) {
6599
+ newRegion.addEntity(entity);
6600
+ this.entityRegionMap.set(entity, newRegion);
6601
+ if (this.config.autoActivate) newRegion.activate();
6602
+ return;
6603
+ }
6604
+ if (newRegion !== currentRegion) {
6605
+ currentRegion.removeEntity(entity);
6606
+ newRegion.addEntity(entity);
6607
+ this.entityRegionMap.set(entity, newRegion);
6608
+ if (this.config.autoActivate) newRegion.activate();
6609
+ if (this.config.autoActivate && currentRegion.getEntities().length === 0) currentRegion.deactivate();
6610
+ return;
6611
+ }
6612
+ currentRegion.getWorld().updateEntity(entity);
6613
+ }
6614
+ /**
6620
6615
  * Updates entity positions and migrates them between regions if needed
6621
6616
  */
6622
6617
  updateEntities() {
@@ -6628,13 +6623,7 @@ var RegionManager = class {
6628
6623
  newRegion
6629
6624
  });
6630
6625
  }
6631
- for (const { entity, newRegion } of entitiesToMigrate) {
6632
- const oldRegion = this.entityRegionMap.get(entity);
6633
- if (oldRegion) oldRegion.removeEntity(entity);
6634
- newRegion.addEntity(entity);
6635
- this.entityRegionMap.set(entity, newRegion);
6636
- if (this.config.autoActivate) newRegion.activate();
6637
- }
6626
+ for (const { entity } of entitiesToMigrate) this.updateEntity(entity);
6638
6627
  }
6639
6628
  /**
6640
6629
  * Steps all active regions
@@ -7046,7 +7035,8 @@ var ZoneManager = class {
7046
7035
  * ```
7047
7036
  */
7048
7037
  createZone(config, callbacks) {
7049
- const id = generateUUID();
7038
+ const id = config.id ?? generateUUID();
7039
+ if (this.zones.has(id)) throw new Error(`Zone "${id}" already exists`);
7050
7040
  const radius = config.radius;
7051
7041
  if (typeof radius !== "number" || radius <= 0) throw new Error("Zone radius must be a positive number");
7052
7042
  const angle = config.angle ?? 360;
@@ -7370,6 +7360,7 @@ var PhysicsEngine = class {
7370
7360
  this.regionManager = null;
7371
7361
  this.movementManager = null;
7372
7362
  this.zoneManager = null;
7363
+ this.rpgSpeeds = /* @__PURE__ */ new Map();
7373
7364
  this.tick = 0;
7374
7365
  this.useRegions = config.enableRegions ?? false;
7375
7366
  if (this.useRegions) {
@@ -7460,6 +7451,19 @@ var PhysicsEngine = class {
7460
7451
  return this.tick;
7461
7452
  }
7462
7453
  /**
7454
+ * Applies a frame of RPG movement inputs, advances the simulation, and updates sensors.
7455
+ *
7456
+ * @param inputs - Map of entity id to direction input
7457
+ * @returns Current tick index after stepping
7458
+ */
7459
+ stepFrame(inputs = {}) {
7460
+ for (const [id, input] of Object.entries(inputs)) if (this.isFrameInputObject(input)) this.moveEntity(id, input.direction, input.speed);
7461
+ else this.moveEntity(id, input);
7462
+ this.step();
7463
+ if (this.zoneManager) this.zoneManager.update();
7464
+ return this.tick;
7465
+ }
7466
+ /**
7463
7467
  * Advances the simulation by a fixed number of ticks.
7464
7468
  *
7465
7469
  * @param ticks - Number of ticks to simulate (>= 1)
@@ -7494,6 +7498,93 @@ var PhysicsEngine = class {
7494
7498
  return entity;
7495
7499
  }
7496
7500
  /**
7501
+ * Creates a dynamic RPG character with a stable id, hitbox, and default movement speed.
7502
+ *
7503
+ * This is the recommended creation path for players and NPCs in server-side RPG
7504
+ * simulations because the entity is registered and ready for `moveEntity` and
7505
+ * `stepFrame` immediately.
7506
+ *
7507
+ * @param id - Stable entity identifier
7508
+ * @param options - Character configuration
7509
+ * @returns Created entity
7510
+ */
7511
+ createCharacter(id, options) {
7512
+ const { x, y, hitbox: hitboxOption, speed, velocity, maxLinearVelocity, ...entityOptions } = options;
7513
+ const hitbox = this.resolveHitbox(hitboxOption);
7514
+ const config = {
7515
+ ...entityOptions,
7516
+ ...hitbox,
7517
+ uuid: id,
7518
+ position: {
7519
+ x,
7520
+ y
7521
+ },
7522
+ mass: options.mass ?? 1,
7523
+ maxLinearVelocity: maxLinearVelocity ?? speed
7524
+ };
7525
+ if (velocity !== void 0) config.velocity = velocity;
7526
+ const entity = this.createEntity(config);
7527
+ this.rpgSpeeds.set(entity.uuid, speed);
7528
+ return entity;
7529
+ }
7530
+ /**
7531
+ * Creates a static rectangular obstacle for RPG maps.
7532
+ *
7533
+ * @param id - Stable entity identifier
7534
+ * @param options - Obstacle configuration
7535
+ * @returns Created static entity
7536
+ */
7537
+ createStaticObstacle(id, options) {
7538
+ return this.createEntity({
7539
+ ...options,
7540
+ uuid: id,
7541
+ position: {
7542
+ x: options.x,
7543
+ y: options.y
7544
+ },
7545
+ width: options.width,
7546
+ height: options.height,
7547
+ mass: 0
7548
+ });
7549
+ }
7550
+ /**
7551
+ * Creates a static or attached sensor zone with a stable id.
7552
+ *
7553
+ * Sensors detect entities through the `ZoneManager` and do not create physical
7554
+ * collision responses.
7555
+ *
7556
+ * @param id - Stable sensor identifier
7557
+ * @param options - Sensor configuration
7558
+ * @returns Sensor identifier
7559
+ */
7560
+ createSensor(id, options) {
7561
+ const { onEnter, onExit, entity, position, x, y, ...zoneOptions } = options;
7562
+ let callbacks;
7563
+ if (onEnter || onExit) {
7564
+ callbacks = {};
7565
+ if (onEnter) callbacks.onEnter = onEnter;
7566
+ if (onExit) callbacks.onExit = onExit;
7567
+ }
7568
+ if (entity) {
7569
+ const attachedEntity = this.resolveEntity(entity);
7570
+ if (!attachedEntity) throw new Error(`Cannot create sensor "${id}" for unknown entity`);
7571
+ return this.getZoneManager().createZone({
7572
+ ...zoneOptions,
7573
+ id,
7574
+ entity: attachedEntity
7575
+ }, callbacks);
7576
+ }
7577
+ const resolvedPosition = position ?? {
7578
+ x: x ?? 0,
7579
+ y: y ?? 0
7580
+ };
7581
+ return this.getZoneManager().createZone({
7582
+ ...zoneOptions,
7583
+ id,
7584
+ position: resolvedPosition
7585
+ }, callbacks);
7586
+ }
7587
+ /**
7497
7588
  * Adds an existing entity to the engine
7498
7589
  *
7499
7590
  * @param entity - Entity to add
@@ -7510,6 +7601,7 @@ var PhysicsEngine = class {
7510
7601
  * @param entity - Entity to remove
7511
7602
  */
7512
7603
  removeEntity(entity) {
7604
+ this.rpgSpeeds.delete(entity.uuid);
7513
7605
  if (this.useRegions && this.regionManager) this.regionManager.removeEntity(entity);
7514
7606
  else this.world.removeEntity(entity);
7515
7607
  }
@@ -7586,7 +7678,70 @@ var PhysicsEngine = class {
7586
7678
  */
7587
7679
  teleport(entity, position) {
7588
7680
  entity.teleport(position);
7589
- if (this.useRegions && this.regionManager) this.regionManager.updateEntities();
7681
+ this.updateEntity(entity);
7682
+ }
7683
+ /**
7684
+ * Teleports an entity by id or entity reference.
7685
+ *
7686
+ * @param entity - Entity or UUID to teleport
7687
+ * @param position - New position
7688
+ * @returns True when the entity was found
7689
+ */
7690
+ teleportEntity(entity, position) {
7691
+ const target = this.resolveEntity(entity);
7692
+ if (!target) return false;
7693
+ this.teleport(target, position);
7694
+ return true;
7695
+ }
7696
+ /**
7697
+ * Moves an entity in a cardinal or vector direction using its configured RPG speed.
7698
+ *
7699
+ * Pass `'idle'` or a zero vector to stop the entity.
7700
+ *
7701
+ * @param entity - Entity or UUID to move
7702
+ * @param direction - Cardinal direction or arbitrary vector
7703
+ * @param speed - Optional speed override for this command
7704
+ * @returns True when the entity was found
7705
+ */
7706
+ moveEntity(entity, direction, speed) {
7707
+ const target = this.resolveEntity(entity);
7708
+ if (!target) return false;
7709
+ const vector = this.resolveDirection(direction);
7710
+ const magnitude = vector.length();
7711
+ if (magnitude === 0) {
7712
+ target.setVelocity({
7713
+ x: 0,
7714
+ y: 0
7715
+ });
7716
+ return true;
7717
+ }
7718
+ const resolvedSpeed = speed ?? this.rpgSpeeds.get(target.uuid) ?? target.maxLinearVelocity;
7719
+ if (!Number.isFinite(resolvedSpeed) || resolvedSpeed <= 0) {
7720
+ target.setVelocity({
7721
+ x: 0,
7722
+ y: 0
7723
+ });
7724
+ return true;
7725
+ }
7726
+ target.setVelocity({
7727
+ x: vector.x / magnitude * resolvedSpeed,
7728
+ y: vector.y / magnitude * resolvedSpeed
7729
+ });
7730
+ return true;
7731
+ }
7732
+ /**
7733
+ * Synchronizes an entity after manual position, shape, or state changes.
7734
+ *
7735
+ * Direct mutations such as `entity.position.set(...)`, `entity.width = ...`,
7736
+ * or `entity.freeze()` bypass the world's broad-phase structures. Call this
7737
+ * helper after such mutations so spatial queries and collisions use the
7738
+ * current entity state immediately.
7739
+ *
7740
+ * @param entity - Entity to synchronize
7741
+ */
7742
+ updateEntity(entity) {
7743
+ if (this.useRegions && this.regionManager) this.regionManager.updateEntity(entity);
7744
+ else this.world.updateEntity(entity);
7590
7745
  }
7591
7746
  /**
7592
7747
  * Freezes an entity (makes it static)
@@ -7595,6 +7750,7 @@ var PhysicsEngine = class {
7595
7750
  */
7596
7751
  freeze(entity) {
7597
7752
  entity.freeze();
7753
+ this.updateEntity(entity);
7598
7754
  }
7599
7755
  /**
7600
7756
  * Unfreezes an entity (makes it dynamic)
@@ -7603,6 +7759,7 @@ var PhysicsEngine = class {
7603
7759
  */
7604
7760
  unfreeze(entity) {
7605
7761
  entity.unfreeze();
7762
+ this.updateEntity(entity);
7606
7763
  }
7607
7764
  /**
7608
7765
  * Queries entities in an AABB region
@@ -7620,9 +7777,7 @@ var PhysicsEngine = class {
7620
7777
  }
7621
7778
  return entities;
7622
7779
  }
7623
- const world = this.world;
7624
- if (world.spatialPartition) return Array.from(world.spatialPartition.queryAABB(bounds));
7625
- return this.world.getEntities().filter((e) => bounds.contains(e.position));
7780
+ return this.world.queryAABB(bounds);
7626
7781
  }
7627
7782
  /**
7628
7783
  * Clears all entities from the engine
@@ -7630,6 +7785,7 @@ var PhysicsEngine = class {
7630
7785
  clear() {
7631
7786
  if (this.useRegions && this.regionManager) this.regionManager.clear();
7632
7787
  else this.world.clear();
7788
+ this.rpgSpeeds.clear();
7633
7789
  this.tick = 0;
7634
7790
  }
7635
7791
  /**
@@ -7647,6 +7803,7 @@ var PhysicsEngine = class {
7647
7803
  */
7648
7804
  assignPolygonCollider(entity, config) {
7649
7805
  assignPolygonCollider(entity, config);
7806
+ this.updateEntity(entity);
7650
7807
  }
7651
7808
  /**
7652
7809
  * Casts a ray in the physics world and returns the nearest hit, if any.
@@ -7664,9 +7821,7 @@ var PhysicsEngine = class {
7664
7821
  * ```
7665
7822
  */
7666
7823
  raycast(origin, direction, maxDistance, mask, filter) {
7667
- const partition = this.world.spatialPartition;
7668
- if (!partition) return null;
7669
- return raycast(partition, origin, direction, maxDistance, mask, filter);
7824
+ return this.world.raycast(origin, direction, maxDistance, mask, filter);
7670
7825
  }
7671
7826
  /**
7672
7827
  * Computes continuous collision detection (sweep test) time-of-impact between two entities
@@ -7766,6 +7921,7 @@ var PhysicsEngine = class {
7766
7921
  entity.angularVelocity = state.angularVelocity;
7767
7922
  if (state.sleeping) entity.sleep();
7768
7923
  else entity.wakeUp();
7924
+ this.updateEntity(entity);
7769
7925
  }
7770
7926
  this.tick = snapshot.tick;
7771
7927
  }
@@ -7777,6 +7933,43 @@ var PhysicsEngine = class {
7777
7933
  getRegionManager() {
7778
7934
  return this.regionManager;
7779
7935
  }
7936
+ resolveEntity(entity) {
7937
+ if (entity instanceof Entity) return entity;
7938
+ return this.getEntityByUUID(entity);
7939
+ }
7940
+ resolveHitbox(hitbox) {
7941
+ if (typeof hitbox === "number") return { radius: hitbox };
7942
+ if ("type" in hitbox) {
7943
+ if (hitbox.type === "circle") return { radius: hitbox.radius };
7944
+ if (hitbox.type === "capsule") return { capsule: {
7945
+ radius: hitbox.radius,
7946
+ height: hitbox.height
7947
+ } };
7948
+ return {
7949
+ width: hitbox.width,
7950
+ height: hitbox.height
7951
+ };
7952
+ }
7953
+ if ("radius" in hitbox) return { radius: hitbox.radius };
7954
+ return {
7955
+ width: hitbox.width,
7956
+ height: hitbox.height
7957
+ };
7958
+ }
7959
+ resolveDirection(direction) {
7960
+ if (direction instanceof Vector2) return direction.clone();
7961
+ if (typeof direction === "string") switch (direction) {
7962
+ case "up": return new Vector2(0, -1);
7963
+ case "down": return new Vector2(0, 1);
7964
+ case "left": return new Vector2(-1, 0);
7965
+ case "right": return new Vector2(1, 0);
7966
+ default: return new Vector2(0, 0);
7967
+ }
7968
+ return new Vector2(direction.x, direction.y);
7969
+ }
7970
+ isFrameInputObject(input) {
7971
+ return typeof input === "object" && !(input instanceof Vector2) && "direction" in input;
7972
+ }
7780
7973
  };
7781
7974
  //#endregion
7782
7975
  //#region ../physic/src/movement/strategies/Dash.ts
@@ -8381,17 +8574,7 @@ var ProjectileMovement = class {
8381
8574
  const gravity = this.options.gravity ?? 30;
8382
8575
  this.verticalVelocity -= gravity * dt;
8383
8576
  this.currentHeight += this.verticalVelocity * dt;
8384
- if (this.options.onHeightUpdate) this.options.onHeightUpdate(this.currentHeight, body);
8385
- else {
8386
- const dispatcher = globalThis;
8387
- if (typeof dispatcher.dispatchEvent === "function" && typeof CustomEvent !== "undefined") {
8388
- const event = new CustomEvent("projectile:height", { detail: {
8389
- id: body.id,
8390
- height: this.currentHeight
8391
- } });
8392
- dispatcher.dispatchEvent(event);
8393
- }
8394
- }
8577
+ this.options.onHeightUpdate?.(this.currentHeight, body);
8395
8578
  if (this.currentHeight <= 0) {
8396
8579
  this.currentHeight = 0;
8397
8580
  if (this.type === ProjectileType.Bounce) if (this.bounceCount < (this.options.maxBounces ?? 0)) {
@@ -8572,6 +8755,9 @@ var MovementManager = class {
8572
8755
  };
8573
8756
  //#endregion
8574
8757
  //#region ../common/src/rooms/Map.ts
8758
+ var COLLISION_PROXIMITY_MARGIN = 1;
8759
+ var DEFAULT_INTERACTION_RANGE = 16;
8760
+ var INTERACTION_SIDE_PADDING = 4;
8575
8761
  var RpgCommonMap = class {
8576
8762
  constructor() {
8577
8763
  this.data = signal(null);
@@ -8924,9 +9110,8 @@ var RpgCommonMap = class {
8924
9110
  this.physicsAccumulatorMs -= fixedStepMs;
8925
9111
  hooks?.beforeStep?.();
8926
9112
  this.physic.updateMovements();
8927
- const tick = this.physic.stepOneTick();
9113
+ const tick = this.physic.stepFrame();
8928
9114
  executed += 1;
8929
- this.runPostTickUpdates();
8930
9115
  hooks?.afterStep?.(tick);
8931
9116
  }
8932
9117
  return executed;
@@ -9006,8 +9191,7 @@ var RpgCommonMap = class {
9006
9191
  forceSingleTick(hooks) {
9007
9192
  hooks?.beforeStep?.();
9008
9193
  this.physic.updateMovements();
9009
- const tick = this.physic.stepOneTick();
9010
- this.runPostTickUpdates();
9194
+ const tick = this.physic.stepFrame();
9011
9195
  hooks?.afterStep?.(tick);
9012
9196
  const fixedMs = this.physic.getWorld().getTimeStep() * 1e3;
9013
9197
  this.physicsAccumulatorMs = Math.max(0, this.physicsAccumulatorMs - fixedMs);
@@ -9023,12 +9207,10 @@ var RpgCommonMap = class {
9023
9207
  return;
9024
9208
  }
9025
9209
  const hitbox = typeof owner.hitbox === "function" ? owner.hitbox() : owner.hitbox;
9026
- const width = hitbox?.w ?? 32;
9027
- const height = hitbox?.h ?? 32;
9028
- const radius = Math.max(width, height) / 2;
9210
+ hitbox?.w;
9211
+ hitbox?.h;
9029
9212
  this.addCharacter({
9030
9213
  owner,
9031
- radius,
9032
9214
  kind,
9033
9215
  maxSpeed: owner.speed(),
9034
9216
  collidesWithCharacters: !this.shouldDisableCharacterCollisions(owner),
@@ -9350,19 +9532,13 @@ var RpgCommonMap = class {
9350
9532
  const centerY = y + height / 2;
9351
9533
  boxWidth = Math.max(width, 1);
9352
9534
  boxHeight = Math.max(height, 1);
9353
- entity = this.physic.createEntity({
9354
- uuid: id,
9355
- position: {
9356
- x: centerX,
9357
- y: centerY
9358
- },
9535
+ entity = this.physic.createStaticObstacle(id, {
9536
+ x: centerX,
9537
+ y: centerY,
9359
9538
  width: boxWidth,
9360
9539
  height: boxHeight,
9361
- mass: Infinity,
9362
- state: EntityState.Static,
9363
9540
  restitution: 0
9364
9541
  });
9365
- entity.freeze();
9366
9542
  }
9367
9543
  return id;
9368
9544
  }
@@ -9407,25 +9583,24 @@ var RpgCommonMap = class {
9407
9583
  const hitbox = typeof owner.hitbox === "function" ? owner.hitbox() : owner.hitbox;
9408
9584
  const width = hitbox?.w ?? 32;
9409
9585
  const height = hitbox?.h ?? 32;
9410
- const radius = Math.max(width, height) / 2;
9411
9586
  const topLeftX = owner.x();
9412
9587
  const topLeftY = owner.y();
9413
9588
  const centerX = topLeftX + width / 2;
9414
9589
  const centerY = topLeftY + height / 2;
9415
9590
  const isStatic = !!options.isStatic;
9416
- const entity = this.physic.createEntity({
9417
- uuid: id,
9418
- position: {
9419
- x: centerX,
9420
- y: centerY
9591
+ const speed = options.maxSpeed ? options.maxSpeed * this.speedScalar : 200;
9592
+ const entity = this.physic.createCharacter(id, {
9593
+ x: centerX,
9594
+ y: centerY,
9595
+ hitbox: {
9596
+ width,
9597
+ height
9421
9598
  },
9422
- radius: Math.max(radius, 1),
9423
- width,
9424
- height,
9599
+ speed,
9425
9600
  mass: options.mass ?? (isStatic ? Infinity : 1),
9426
9601
  friction: options.friction ?? .4,
9427
9602
  linearDamping: isStatic ? 1 : .2,
9428
- maxLinearVelocity: options.maxSpeed ? options.maxSpeed * this.speedScalar : 200,
9603
+ maxLinearVelocity: speed,
9429
9604
  restitution: 0
9430
9605
  });
9431
9606
  if (isStatic) entity.freeze();
@@ -9543,7 +9718,10 @@ var RpgCommonMap = class {
9543
9718
  const entityHeight = entity.height || entity.radius * 2 || 32;
9544
9719
  const centerX = x + entityWidth / 2;
9545
9720
  const centerY = y + entityHeight / 2;
9546
- entity.position.set(centerX, centerY);
9721
+ this.physic.teleportEntity(entity, {
9722
+ x: centerX,
9723
+ y: centerY
9724
+ });
9547
9725
  return true;
9548
9726
  }
9549
9727
  /**
@@ -9579,26 +9757,8 @@ var RpgCommonMap = class {
9579
9757
  moveBody(player, direction) {
9580
9758
  const entity = this.physic.getEntityByUUID(player.id);
9581
9759
  if (!entity) return false;
9582
- const speedValue = player.speed();
9583
- let vx = 0, vy = 0;
9584
- switch (direction) {
9585
- case Direction.Left:
9586
- vx = -speedValue * this.speedScalar;
9587
- break;
9588
- case Direction.Right:
9589
- vx = speedValue * this.speedScalar;
9590
- break;
9591
- case Direction.Up:
9592
- vy = -speedValue * this.speedScalar;
9593
- break;
9594
- case Direction.Down:
9595
- vy = speedValue * this.speedScalar;
9596
- break;
9597
- }
9598
- entity.setVelocity({
9599
- x: vx,
9600
- y: vy
9601
- });
9760
+ const speed = player.speed() * this.speedScalar;
9761
+ this.physic.moveEntity(entity, direction, speed);
9602
9762
  entity.wakeUp();
9603
9763
  return true;
9604
9764
  }
@@ -9667,8 +9827,7 @@ var RpgCommonMap = class {
9667
9827
  if (!entity) return [];
9668
9828
  const collider = createCollider(entity);
9669
9829
  if (!collider) return [];
9670
- const entityAABB = collider.getBounds();
9671
- const expandedAABB = entityAABB.expand(1);
9830
+ const expandedAABB = collider.getBounds().expand(1);
9672
9831
  const nearby = this.physic.queryAABB(expandedAABB);
9673
9832
  const collisions = [];
9674
9833
  for (const other of nearby) {
@@ -9676,10 +9835,46 @@ var RpgCommonMap = class {
9676
9835
  const otherCollider = createCollider(other);
9677
9836
  if (!otherCollider) continue;
9678
9837
  const otherAABB = otherCollider.getBounds();
9679
- if (entityAABB.intersects(otherAABB)) collisions.push(other.uuid);
9838
+ if (expandedAABB.intersects(otherAABB)) collisions.push(other.uuid);
9839
+ }
9840
+ return collisions;
9841
+ }
9842
+ /**
9843
+ * Get entities inside the action area directly in front of an entity.
9844
+ *
9845
+ * This is intentionally separate from physical collisions: a player often
9846
+ * presses the action key while blocked just before touching an NPC, so the
9847
+ * physics solver may leave a tiny gap even though gameplay expects an
9848
+ * interaction.
9849
+ */
9850
+ getInteractionCollisions(id, direction, range = DEFAULT_INTERACTION_RANGE) {
9851
+ const entity = this.physic.getEntityByUUID(id);
9852
+ if (!entity) return [];
9853
+ const collider = createCollider(entity);
9854
+ if (!collider) return [];
9855
+ const entityAABB = collider.getBounds();
9856
+ const interactionAABB = this.getInteractionAABB(entityAABB, direction, range);
9857
+ const nearby = this.physic.queryAABB(interactionAABB);
9858
+ const collisions = [];
9859
+ for (const other of nearby) {
9860
+ if (other.uuid === id) continue;
9861
+ const otherCollider = createCollider(other);
9862
+ if (!otherCollider) continue;
9863
+ if (interactionAABB.intersects(otherCollider.getBounds())) collisions.push(other.uuid);
9680
9864
  }
9681
9865
  return collisions;
9682
9866
  }
9867
+ getInteractionAABB(bounds, direction, range = DEFAULT_INTERACTION_RANGE) {
9868
+ const distance = Number.isFinite(range) ? Math.max(0, range) : DEFAULT_INTERACTION_RANGE;
9869
+ const sidePadding = distance > 0 ? Math.min(INTERACTION_SIDE_PADDING, distance / 2) : 0;
9870
+ switch (direction) {
9871
+ case Direction.Up: return new AABB(bounds.minX - sidePadding, bounds.minY - distance, bounds.maxX + sidePadding, bounds.minY + COLLISION_PROXIMITY_MARGIN);
9872
+ case Direction.Down: return new AABB(bounds.minX - sidePadding, bounds.maxY - COLLISION_PROXIMITY_MARGIN, bounds.maxX + sidePadding, bounds.maxY + distance);
9873
+ case Direction.Left: return new AABB(bounds.minX - distance, bounds.minY - sidePadding, bounds.minX + COLLISION_PROXIMITY_MARGIN, bounds.maxY + sidePadding);
9874
+ case Direction.Right: return new AABB(bounds.maxX - COLLISION_PROXIMITY_MARGIN, bounds.minY - sidePadding, bounds.maxX + distance, bounds.maxY + sidePadding);
9875
+ default: return bounds.expand(distance);
9876
+ }
9877
+ }
9683
9878
  /**
9684
9879
  * Get physics body (entity) for an id
9685
9880
  * @protected
@@ -9739,6 +9934,7 @@ var RpgCommonMap = class {
9739
9934
  }
9740
9935
  entity.position.set(centerX, centerY);
9741
9936
  entity.notifyPositionChange();
9937
+ this.physic.updateEntity(entity);
9742
9938
  return entity;
9743
9939
  }
9744
9940
  /**
@@ -9750,7 +9946,6 @@ var RpgCommonMap = class {
9750
9946
  * @private
9751
9947
  */
9752
9948
  addZone(id, options) {
9753
- const zoneManager = this.physic.getZoneManager();
9754
9949
  if (this.physic.getEntityByUUID(id)) throw new Error(`Zone with id ${id} already exists as entity`);
9755
9950
  const radius = options.radius;
9756
9951
  if (typeof radius !== "number" || radius <= 0) throw new Error("Zone radius must be a positive number");
@@ -9759,15 +9954,13 @@ var RpgCommonMap = class {
9759
9954
  attachedEntity = this.physic.getEntityByUUID(options.linkedTo);
9760
9955
  if (!attachedEntity) throw new Error(`Cannot link zone to unknown entity ${options.linkedTo}`);
9761
9956
  }
9762
- const callbacks = {};
9763
- callbacks._onEnterString = void 0;
9764
- callbacks._onExitString = void 0;
9765
- const zoneId = attachedEntity ? zoneManager.createAttachedZone(attachedEntity, {
9957
+ const zoneId = this.physic.createSensor(id, attachedEntity ? {
9958
+ entity: attachedEntity,
9766
9959
  radius,
9767
9960
  angle: options.angle ?? 360,
9768
9961
  direction: options.direction ?? "down",
9769
9962
  limitedByWalls: options.limitedByWalls ?? false
9770
- }, callbacks) : zoneManager.createZone({
9963
+ } : {
9771
9964
  position: {
9772
9965
  x: options.x ?? 0,
9773
9966
  y: options.y ?? 0
@@ -9776,7 +9969,7 @@ var RpgCommonMap = class {
9776
9969
  angle: options.angle ?? 360,
9777
9970
  direction: options.direction ?? "down",
9778
9971
  limitedByWalls: options.limitedByWalls ?? false
9779
- }, callbacks);
9972
+ });
9780
9973
  this._zoneIdMap = this._zoneIdMap || /* @__PURE__ */ new Map();
9781
9974
  this._zoneIdMap.set(id, zoneId);
9782
9975
  return id;
@@ -11041,6 +11234,6 @@ function provideServerModules(modules) {
11041
11234
  });
11042
11235
  }
11043
11236
  //#endregion
11044
- export { RpgCommonPlayer as $, isArray as A, createErrorClass as At, ProjectileMovement as B, SDEF as C, isSignal as Ct, arrayFlat as D, finalize as Dt, PrebuiltGui as E, untracked as Et, ModulesToken as F, Knockback as G, PathFollow as H, RpgModule as I, Entity as J, IceMovement as K, WorldMapsManager as L, isInstanceOf as M, isString as N, arrayUniq as O, combineLatest as Ot, random as P, Direction as Q, RpgCommonMap as R, PDEF as S, isObjectSubject as St, PerlinNoise2D as T, signal as Tt, Oscillate as U, ProjectileType as V, LinearRepulsion as W, Vector2 as X, EntityState as Y, RpgShape as Z, ATK as _, ObjectSubject as _t, isMapUpdateAuthorized as a, createStatesSnapshot as at, MAXHP as b, isArraySubject as bt, updateMap as c, getByPath as ct, context$1 as d, persist as dt, Skill as et, inject as f, sync as ft, AGI as g, ArraySubject as gt, injector as h, users as ht, createMapUpdateHeaders as i, DELETE_TOKEN as it, isFunction as j, capitalize as k, BehaviorSubject as kt, context as l, id as lt, inject$1 as m, type as mt, MAP_UPDATE_TOKEN_ENV as n, __decorate as nt, readMapUpdateToken as o, createStatesSnapshotDeep as ot, setInject as p, syncClass as pt, Dash as q, MAP_UPDATE_TOKEN_HEADER as r, __decorateMetadata as rt, resolveMapUpdateToken as s, generateShortUUID as st, provideServerModules as t, Item as tt, clearInject as u, load as ut, DEX as v, computed as vt, STR as w, linkedSignal as wt, MAXSP as x, isComputed as xt, INT as y, effect as yt, SeekAvoid as z };
11237
+ export { Skill as $, isArray as A, ProjectileMovement as B, SDEF as C, linkedSignal as Ct, arrayFlat as D, combineLatest as Dt, PrebuiltGui as E, finalize as Et, ModulesToken as F, Knockback as G, PathFollow as H, RpgModule as I, Entity as J, IceMovement as K, WorldMapsManager as L, isInstanceOf as M, isString as N, arrayUniq as O, BehaviorSubject as Ot, random as P, RpgCommonPlayer as Q, RpgCommonMap as R, PDEF as S, isSignal as St, PerlinNoise2D as T, untracked as Tt, Oscillate as U, ProjectileType as V, LinearRepulsion as W, RpgShape as X, Vector2 as Y, Direction as Z, ATK as _, computed as _t, isMapUpdateAuthorized as a, createStatesSnapshotDeep as at, MAXHP as b, isComputed as bt, updateMap as c, id as ct, context$1 as d, sync as dt, Item as et, inject as f, syncClass as ft, AGI as g, ObjectSubject as gt, injector as h, ArraySubject as ht, createMapUpdateHeaders as i, createStatesSnapshot as it, isFunction as j, capitalize as k, createErrorClass as kt, context as l, load as lt, inject$1 as m, users as mt, MAP_UPDATE_TOKEN_ENV as n, __decorateMetadata as nt, readMapUpdateToken as o, generateShortUUID as ot, setInject as p, type as pt, Dash as q, MAP_UPDATE_TOKEN_HEADER as r, DELETE_TOKEN as rt, resolveMapUpdateToken as s, getByPath as st, provideServerModules as t, __decorate as tt, clearInject as u, persist as ut, DEX as v, effect as vt, STR as w, signal as wt, MAXSP as x, isObjectSubject as xt, INT as y, isArraySubject as yt, SeekAvoid as z };
11045
11238
 
11046
- //# sourceMappingURL=module-BmvXIvlE.js.map
11239
+ //# sourceMappingURL=module-Dy124Jyk.js.map