@rpgjs/server 5.0.0-alpha.32 → 5.0.0-alpha.35

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.
package/dist/index.js CHANGED
@@ -5284,171 +5284,6 @@ var BehaviorSubject = (function (_super) {
5284
5284
  return BehaviorSubject;
5285
5285
  }(Subject));
5286
5286
 
5287
- var dateTimestampProvider = {
5288
- now: function () {
5289
- return (Date).now();
5290
- }};
5291
-
5292
- var Action$1 = (function (_super) {
5293
- __extends(Action, _super);
5294
- function Action(scheduler, work) {
5295
- return _super.call(this) || this;
5296
- }
5297
- Action.prototype.schedule = function (state, delay) {
5298
- return this;
5299
- };
5300
- return Action;
5301
- }(Subscription));
5302
-
5303
- var intervalProvider = {
5304
- setInterval: function (handler, timeout) {
5305
- var args = [];
5306
- for (var _i = 2; _i < arguments.length; _i++) {
5307
- args[_i - 2] = arguments[_i];
5308
- }
5309
- return setInterval.apply(void 0, __spreadArray([handler, timeout], __read(args)));
5310
- },
5311
- clearInterval: function (handle) {
5312
- return (clearInterval)(handle);
5313
- },
5314
- delegate: undefined,
5315
- };
5316
-
5317
- var AsyncAction = (function (_super) {
5318
- __extends(AsyncAction, _super);
5319
- function AsyncAction(scheduler, work) {
5320
- var _this = _super.call(this, scheduler, work) || this;
5321
- _this.scheduler = scheduler;
5322
- _this.work = work;
5323
- _this.pending = false;
5324
- return _this;
5325
- }
5326
- AsyncAction.prototype.schedule = function (state, delay) {
5327
- var _a;
5328
- if (delay === void 0) { delay = 0; }
5329
- if (this.closed) {
5330
- return this;
5331
- }
5332
- this.state = state;
5333
- var id = this.id;
5334
- var scheduler = this.scheduler;
5335
- if (id != null) {
5336
- this.id = this.recycleAsyncId(scheduler, id, delay);
5337
- }
5338
- this.pending = true;
5339
- this.delay = delay;
5340
- this.id = (_a = this.id) !== null && _a !== void 0 ? _a : this.requestAsyncId(scheduler, this.id, delay);
5341
- return this;
5342
- };
5343
- AsyncAction.prototype.requestAsyncId = function (scheduler, _id, delay) {
5344
- if (delay === void 0) { delay = 0; }
5345
- return intervalProvider.setInterval(scheduler.flush.bind(scheduler, this), delay);
5346
- };
5347
- AsyncAction.prototype.recycleAsyncId = function (_scheduler, id, delay) {
5348
- if (delay === void 0) { delay = 0; }
5349
- if (delay != null && this.delay === delay && this.pending === false) {
5350
- return id;
5351
- }
5352
- if (id != null) {
5353
- intervalProvider.clearInterval(id);
5354
- }
5355
- return undefined;
5356
- };
5357
- AsyncAction.prototype.execute = function (state, delay) {
5358
- if (this.closed) {
5359
- return new Error('executing a cancelled action');
5360
- }
5361
- this.pending = false;
5362
- var error = this._execute(state, delay);
5363
- if (error) {
5364
- return error;
5365
- }
5366
- else if (this.pending === false && this.id != null) {
5367
- this.id = this.recycleAsyncId(this.scheduler, this.id, null);
5368
- }
5369
- };
5370
- AsyncAction.prototype._execute = function (state, _delay) {
5371
- var errored = false;
5372
- var errorValue;
5373
- try {
5374
- this.work(state);
5375
- }
5376
- catch (e) {
5377
- errored = true;
5378
- errorValue = e ? e : new Error('Scheduled action threw falsy error');
5379
- }
5380
- if (errored) {
5381
- this.unsubscribe();
5382
- return errorValue;
5383
- }
5384
- };
5385
- AsyncAction.prototype.unsubscribe = function () {
5386
- if (!this.closed) {
5387
- var _a = this, id = _a.id, scheduler = _a.scheduler;
5388
- var actions = scheduler.actions;
5389
- this.work = this.state = this.scheduler = null;
5390
- this.pending = false;
5391
- arrRemove(actions, this);
5392
- if (id != null) {
5393
- this.id = this.recycleAsyncId(scheduler, id, null);
5394
- }
5395
- this.delay = null;
5396
- _super.prototype.unsubscribe.call(this);
5397
- }
5398
- };
5399
- return AsyncAction;
5400
- }(Action$1));
5401
-
5402
- var Scheduler = (function () {
5403
- function Scheduler(schedulerActionCtor, now) {
5404
- if (now === void 0) { now = Scheduler.now; }
5405
- this.schedulerActionCtor = schedulerActionCtor;
5406
- this.now = now;
5407
- }
5408
- Scheduler.prototype.schedule = function (work, delay, state) {
5409
- if (delay === void 0) { delay = 0; }
5410
- return new this.schedulerActionCtor(this, work).schedule(state, delay);
5411
- };
5412
- Scheduler.now = dateTimestampProvider.now;
5413
- return Scheduler;
5414
- }());
5415
-
5416
- var AsyncScheduler = (function (_super) {
5417
- __extends(AsyncScheduler, _super);
5418
- function AsyncScheduler(SchedulerAction, now) {
5419
- if (now === void 0) { now = Scheduler.now; }
5420
- var _this = _super.call(this, SchedulerAction, now) || this;
5421
- _this.actions = [];
5422
- _this._active = false;
5423
- return _this;
5424
- }
5425
- AsyncScheduler.prototype.flush = function (action) {
5426
- var actions = this.actions;
5427
- if (this._active) {
5428
- actions.push(action);
5429
- return;
5430
- }
5431
- var error;
5432
- this._active = true;
5433
- do {
5434
- if ((error = action.execute(action.state, action.delay))) {
5435
- break;
5436
- }
5437
- } while ((action = actions.shift()));
5438
- this._active = false;
5439
- if (error) {
5440
- while ((action = actions.shift())) {
5441
- action.unsubscribe();
5442
- }
5443
- throw error;
5444
- }
5445
- };
5446
- return AsyncScheduler;
5447
- }(Scheduler));
5448
-
5449
- var asyncScheduler = new AsyncScheduler(AsyncAction);
5450
- var async = asyncScheduler;
5451
-
5452
5287
  function isScheduler(value) {
5453
5288
  return value && isFunction$2(value.schedule);
5454
5289
  }
@@ -5828,10 +5663,6 @@ function lastValueFrom(source, config) {
5828
5663
  });
5829
5664
  }
5830
5665
 
5831
- function isValidDate(value) {
5832
- return value instanceof Date && !isNaN(value);
5833
- }
5834
-
5835
5666
  function map(project, thisArg) {
5836
5667
  return operate(function (source, subscriber) {
5837
5668
  var index = 0;
@@ -5997,37 +5828,6 @@ function mergeMap(project, resultSelector, concurrent) {
5997
5828
  return operate(function (source, subscriber) { return mergeInternals(source, subscriber, project, concurrent); });
5998
5829
  }
5999
5830
 
6000
- function timer(dueTime, intervalOrScheduler, scheduler) {
6001
- if (scheduler === void 0) { scheduler = async; }
6002
- var intervalDuration = -1;
6003
- if (intervalOrScheduler != null) {
6004
- if (isScheduler(intervalOrScheduler)) {
6005
- scheduler = intervalOrScheduler;
6006
- }
6007
- else {
6008
- intervalDuration = intervalOrScheduler;
6009
- }
6010
- }
6011
- return new Observable(function (subscriber) {
6012
- var due = isValidDate(dueTime) ? +dueTime - scheduler.now() : dueTime;
6013
- if (due < 0) {
6014
- due = 0;
6015
- }
6016
- var n = 0;
6017
- return scheduler.schedule(function () {
6018
- if (!subscriber.closed) {
6019
- subscriber.next(n++);
6020
- if (0 <= intervalDuration) {
6021
- this.schedule(undefined, intervalDuration);
6022
- }
6023
- else {
6024
- subscriber.complete();
6025
- }
6026
- }
6027
- }, due);
6028
- });
6029
- }
6030
-
6031
5831
  function filter(predicate, thisArg) {
6032
5832
  return operate(function (source, subscriber) {
6033
5833
  var index = 0;
@@ -6156,54 +5956,6 @@ function handleReset(reset, on) {
6156
5956
  return innerFrom(on.apply(void 0, __spreadArray([], __read(args)))).subscribe(onSubscriber);
6157
5957
  }
6158
5958
 
6159
- function throttle$1(durationSelector, config) {
6160
- return operate(function (source, subscriber) {
6161
- var _a = config !== null && config !== void 0 ? config : {}, _b = _a.leading, leading = _b === void 0 ? true : _b, _c = _a.trailing, trailing = _c === void 0 ? false : _c;
6162
- var hasValue = false;
6163
- var sendValue = null;
6164
- var throttled = null;
6165
- var isComplete = false;
6166
- var endThrottling = function () {
6167
- throttled === null || throttled === void 0 ? void 0 : throttled.unsubscribe();
6168
- throttled = null;
6169
- if (trailing) {
6170
- send();
6171
- isComplete && subscriber.complete();
6172
- }
6173
- };
6174
- var cleanupThrottling = function () {
6175
- throttled = null;
6176
- isComplete && subscriber.complete();
6177
- };
6178
- var startThrottle = function (value) {
6179
- return (throttled = innerFrom(durationSelector(value)).subscribe(createOperatorSubscriber(subscriber, endThrottling, cleanupThrottling)));
6180
- };
6181
- var send = function () {
6182
- if (hasValue) {
6183
- hasValue = false;
6184
- var value = sendValue;
6185
- sendValue = null;
6186
- subscriber.next(value);
6187
- !isComplete && startThrottle(value);
6188
- }
6189
- };
6190
- source.subscribe(createOperatorSubscriber(subscriber, function (value) {
6191
- hasValue = true;
6192
- sendValue = value;
6193
- !(throttled && !throttled.closed) && (leading ? send() : startThrottle(value));
6194
- }, function () {
6195
- isComplete = true;
6196
- !(trailing && hasValue && throttled && !throttled.closed) && subscriber.complete();
6197
- }));
6198
- });
6199
- }
6200
-
6201
- function throttleTime(duration, scheduler, config) {
6202
- if (scheduler === void 0) { scheduler = asyncScheduler; }
6203
- var duration$ = timer(duration, scheduler);
6204
- return throttle$1(function () { return duration$; }, config);
6205
- }
6206
-
6207
5959
  var __defProp$9 = Object.defineProperty;
6208
5960
  var __name$2 = (target, value) => __defProp$9(target, "name", { value, configurable: true });
6209
5961
  var ArraySubject = class extends BehaviorSubject {
@@ -6749,7 +6501,7 @@ function isClass$1(obj) {
6749
6501
  return typeof obj === "function" && obj.prototype && obj.prototype.constructor === obj;
6750
6502
  }
6751
6503
  __name$3(isClass$1, "isClass");
6752
- var isObject$1 = /* @__PURE__ */ __name$3((item) => item && typeof item === "object" && !Array.isArray(item) && item !== null, "isObject");
6504
+ var isObject$2 = /* @__PURE__ */ __name$3((item) => item && typeof item === "object" && !Array.isArray(item) && item !== null, "isObject");
6753
6505
  function isInstanceOfClass(value) {
6754
6506
  if (value === null || typeof value !== "object" || value === void 0 || Array.isArray(value)) {
6755
6507
  return false;
@@ -6799,7 +6551,7 @@ function createStatesSnapshot(instance) {
6799
6551
  const signal = instance.$snapshot.get(key);
6800
6552
  const persist2 = signal.options.persist ?? true;
6801
6553
  let value = signal();
6802
- if (isObject$1(value) || Array.isArray(value)) {
6554
+ if (isObject$2(value) || Array.isArray(value)) {
6803
6555
  continue;
6804
6556
  }
6805
6557
  if (persist2) {
@@ -6904,7 +6656,7 @@ var createSyncClass = /* @__PURE__ */ __name$3((currentClass, parentKey = null,
6904
6656
  if (transform) {
6905
6657
  signalValue = transform(signalValue);
6906
6658
  }
6907
- if (isObject$1(signalValue) || Array.isArray(signalValue)) {
6659
+ if (isObject$2(signalValue) || Array.isArray(signalValue)) {
6908
6660
  signalValue = {
6909
6661
  ...signalValue
6910
6662
  };
@@ -6940,7 +6692,7 @@ var type = /* @__PURE__ */ __name$3((_signal, path, options = {}, currentInstanc
6940
6692
  ].includes(value.type)) {
6941
6693
  if (isInstanceOfClass(value.value)) {
6942
6694
  createSyncClass(value.value, value.key, currentInstance, newPath);
6943
- } else if (value.type === "update" && (isObject$1(value.value) || Array.isArray(value.value))) {
6695
+ } else if (value.type === "update" && (isObject$2(value.value) || Array.isArray(value.value))) {
6944
6696
  createSyncClass(value.value, value.key, currentInstance, newPath);
6945
6697
  } else {
6946
6698
  savePath(newPath, value.value);
@@ -6969,7 +6721,7 @@ var type = /* @__PURE__ */ __name$3((_signal, path, options = {}, currentInstanc
6969
6721
  ].includes(value.type) && firstItem !== void 0) {
6970
6722
  if (isInstanceOfClass(firstItem)) {
6971
6723
  createSyncClass(firstItem, value.key, currentInstance, newPath);
6972
- } else if (value.type === "update" && (isObject$1(firstItem) || Array.isArray(firstItem))) {
6724
+ } else if (value.type === "update" && (isObject$2(firstItem) || Array.isArray(firstItem))) {
6973
6725
  createSyncClass(firstItem, value.key, currentInstance, newPath);
6974
6726
  } else {
6975
6727
  savePath(newPath, firstItem);
@@ -8543,9 +8295,9 @@ var Server = class {
8543
8295
  sessionState,
8544
8296
  room: this.room
8545
8297
  })) ?? userSnapshot;
8546
- load(user, hydratedSnapshot, true);
8547
8298
  signal2()[publicId] = user;
8548
- await this.room.storage.put(`${usersPropName}.${publicId}`, hydratedSnapshot);
8299
+ load(user, hydratedSnapshot, true);
8300
+ await this.room.storage.put(`${usersPropName}.${publicId}`, userSnapshot);
8549
8301
  }
8550
8302
  }
8551
8303
  const transferToken = generateShortUUID$1();
@@ -9898,6 +9650,7 @@ class Item {
9898
9650
  this.atk = signal(0);
9899
9651
  this.pdef = signal(0);
9900
9652
  this.sdef = signal(0);
9653
+ this.icon = signal("");
9901
9654
  this.quantity = signal(1);
9902
9655
  this.onAdd = () => {
9903
9656
  };
@@ -9907,6 +9660,7 @@ class Item {
9907
9660
  this.atk.set(data?.atk ?? 0);
9908
9661
  this.pdef.set(data?.pdef ?? 0);
9909
9662
  this.sdef.set(data?.sdef ?? 0);
9663
+ this.icon.set(data?.icon ?? "");
9910
9664
  this.onAdd = data?.onAdd?.bind(this) ?? (() => {
9911
9665
  });
9912
9666
  }
@@ -9914,6 +9668,12 @@ class Item {
9914
9668
  __decorateClass$6([
9915
9669
  id()
9916
9670
  ], Item.prototype, "id");
9671
+ __decorateClass$6([
9672
+ sync()
9673
+ ], Item.prototype, "name");
9674
+ __decorateClass$6([
9675
+ sync()
9676
+ ], Item.prototype, "icon");
9917
9677
  __decorateClass$6([
9918
9678
  sync()
9919
9679
  ], Item.prototype, "quantity");
@@ -9933,6 +9693,7 @@ class Skill {
9933
9693
  this.name = signal("");
9934
9694
  this.description = signal("");
9935
9695
  this.spCost = signal(0);
9696
+ this.icon = signal("");
9936
9697
  this.hitRate = signal(0);
9937
9698
  this.power = signal(0);
9938
9699
  this.coefficient = signal({});
@@ -9943,11 +9704,21 @@ class Skill {
9943
9704
  this.hitRate.set(data?.hitRate ?? 0);
9944
9705
  this.power.set(data?.power ?? 0);
9945
9706
  this.coefficient.set(data?.coefficient ?? {});
9707
+ this.icon.set(data?.icon ?? "");
9946
9708
  }
9947
9709
  }
9948
9710
  __decorateClass$5([
9949
9711
  id()
9950
9712
  ], Skill.prototype, "id");
9713
+ __decorateClass$5([
9714
+ sync()
9715
+ ], Skill.prototype, "name");
9716
+ __decorateClass$5([
9717
+ sync()
9718
+ ], Skill.prototype, "spCost");
9719
+ __decorateClass$5([
9720
+ sync()
9721
+ ], Skill.prototype, "icon");
9951
9722
 
9952
9723
  var __defProp$5 = Object.defineProperty;
9953
9724
  var __decorateClass$4 = (decorators, target, key, kind) => {
@@ -16372,12 +16143,17 @@ class RpgCommonMap {
16372
16143
  }
16373
16144
  loadPhysic() {
16374
16145
  this.clearPhysic();
16375
- const hitboxes = this.data()?.hitboxes ?? [];
16376
- const gap = 100;
16377
- this.addStaticHitbox("map-width-left", -gap, 0, gap, this.data().height);
16378
- this.addStaticHitbox("map-width-right", this.data().width, 0, gap, this.data().height);
16379
- this.addStaticHitbox("map-height-top", 0, -gap, this.data().width, gap);
16380
- this.addStaticHitbox("map-height-bottom", 0, this.data().height, this.data().width, gap);
16146
+ const mapData = this.data?.();
16147
+ const mapWidth = typeof mapData?.width === "number" ? mapData.width : 0;
16148
+ const mapHeight = typeof mapData?.height === "number" ? mapData.height : 0;
16149
+ const hitboxes = Array.isArray(mapData?.hitboxes) ? mapData.hitboxes : [];
16150
+ if (mapWidth > 0 && mapHeight > 0) {
16151
+ const gap = 100;
16152
+ this.addStaticHitbox("map-width-left", -gap, 0, gap, mapHeight);
16153
+ this.addStaticHitbox("map-width-right", mapWidth, 0, gap, mapHeight);
16154
+ this.addStaticHitbox("map-height-top", 0, -gap, mapWidth, gap);
16155
+ this.addStaticHitbox("map-height-bottom", 0, mapHeight, mapWidth, gap);
16156
+ }
16381
16157
  for (let staticHitbox of hitboxes) {
16382
16158
  if ("x" in staticHitbox) {
16383
16159
  this.addStaticHitbox(staticHitbox.id ?? generateShortUUID$1(), staticHitbox.x, staticHitbox.y, staticHitbox.width, staticHitbox.height);
@@ -16387,13 +16163,29 @@ class RpgCommonMap {
16387
16163
  }
16388
16164
  this.playersSubscription = this.players.observable.subscribe(
16389
16165
  ({ value: player, type, key }) => {
16166
+ if (type === "remove") {
16167
+ this.removeHitbox(key);
16168
+ return;
16169
+ }
16170
+ if (type == "reset") {
16171
+ if (!player) return;
16172
+ for (let id in player) {
16173
+ const _player = player[id];
16174
+ _player.id = _player.id ?? id;
16175
+ this.createCharacterHitbox(_player, "hero");
16176
+ }
16177
+ return;
16178
+ }
16390
16179
  if (!player) return;
16391
16180
  if (type === "add") {
16392
16181
  player.id = key;
16393
16182
  this.createCharacterHitbox(player, "hero");
16394
- } else if (type === "remove") {
16395
- this.removeHitbox(key);
16396
16183
  } else if (type === "update") {
16184
+ player.id = player.id ?? key;
16185
+ if (!this.getBody(key)) {
16186
+ this.createCharacterHitbox(player, "hero");
16187
+ return;
16188
+ }
16397
16189
  if (this.isPhysicsSyncingSignals) {
16398
16190
  return;
16399
16191
  }
@@ -16414,9 +16206,41 @@ class RpgCommonMap {
16414
16206
  }
16415
16207
  this.removeHitbox(key);
16416
16208
  } else if (type === "update") {
16209
+ event.id = event.id ?? key;
16210
+ if (!this.getBody(key)) {
16211
+ this.createCharacterHitbox(event, "npc", {
16212
+ mass: 100
16213
+ });
16214
+ return;
16215
+ }
16417
16216
  this.updateCharacterHitbox(event);
16217
+ } else if (type === "reset") {
16218
+ for (const id in event) {
16219
+ const _event = event[id];
16220
+ if (!_event) continue;
16221
+ _event.id = _event.id ?? id;
16222
+ this.createCharacterHitbox(_event, "npc", {
16223
+ mass: 100
16224
+ });
16225
+ }
16418
16226
  }
16419
16227
  });
16228
+ const players = this.players();
16229
+ for (const id in players) {
16230
+ const player = players[id];
16231
+ if (!player) continue;
16232
+ player.id = player.id ?? id;
16233
+ this.createCharacterHitbox(player, "hero");
16234
+ }
16235
+ const events = this.events();
16236
+ for (const id in events) {
16237
+ const event = events[id];
16238
+ if (!event) continue;
16239
+ event.id = event.id ?? id;
16240
+ this.createCharacterHitbox(event, "npc", {
16241
+ mass: 100
16242
+ });
16243
+ }
16420
16244
  if (this.autoTickEnabled) {
16421
16245
  this.tickSubscription = this.tick$.subscribe(({ delta }) => {
16422
16246
  this.runFixedTicks(delta);
@@ -16614,6 +16438,12 @@ class RpgCommonMap {
16614
16438
  if (!owner?.id) {
16615
16439
  return;
16616
16440
  }
16441
+ const existingEntity = this.physic.getEntityByUUID(owner.id);
16442
+ if (existingEntity) {
16443
+ existingEntity.owner = owner;
16444
+ this.updateCharacterHitbox(owner);
16445
+ return;
16446
+ }
16617
16447
  const hitbox = typeof owner.hitbox === "function" ? owner.hitbox() : owner.hitbox;
16618
16448
  const width = hitbox?.w ?? 32;
16619
16449
  const height = hitbox?.h ?? 32;
@@ -16630,6 +16460,9 @@ class RpgCommonMap {
16630
16460
  }
16631
16461
  updateCharacterHitbox(owner) {
16632
16462
  if (!owner?.id) return;
16463
+ const entity = this.physic.getEntityByUUID(owner.id);
16464
+ if (!entity) return;
16465
+ entity.owner = owner;
16633
16466
  const hitbox = typeof owner.hitbox === "function" ? owner.hitbox() : owner.hitbox;
16634
16467
  const width = hitbox?.w ?? 32;
16635
16468
  const height = hitbox?.h ?? 32;
@@ -17017,22 +16850,26 @@ class RpgCommonMap {
17017
16850
  }
17018
16851
  }
17019
16852
  });
17020
- const entityWidth = width;
17021
- const entityHeight = height;
17022
16853
  entity.onPositionChange(({ x, y }) => {
16854
+ const currentOwner = entity.owner;
16855
+ if (!currentOwner) {
16856
+ return;
16857
+ }
16858
+ const entityWidth = entity.width || width;
16859
+ const entityHeight = entity.height || height;
17023
16860
  const topLeftX2 = x - entityWidth / 2;
17024
16861
  const topLeftY2 = y - entityHeight / 2;
17025
16862
  let changed = false;
17026
- if (typeof owner.x === "function" && typeof owner.x.set === "function") {
17027
- owner.x.set(Math.round(topLeftX2));
16863
+ if (typeof currentOwner.x === "function" && typeof currentOwner.x.set === "function") {
16864
+ currentOwner.x.set(Math.round(topLeftX2));
17028
16865
  changed = true;
17029
16866
  }
17030
- if (typeof owner.y === "function" && typeof owner.y.set === "function") {
17031
- owner.y.set(Math.round(topLeftY2));
16867
+ if (typeof currentOwner.y === "function" && typeof currentOwner.y.set === "function") {
16868
+ currentOwner.y.set(Math.round(topLeftY2));
17032
16869
  changed = true;
17033
16870
  }
17034
16871
  if (changed) {
17035
- owner.applyFrames?.();
16872
+ currentOwner.applyFrames?.();
17036
16873
  }
17037
16874
  });
17038
16875
  entity.addResolutionFilter((self, other) => {
@@ -20669,6 +20506,27 @@ function WithVariableManager(Base) {
20669
20506
  };
20670
20507
  }
20671
20508
 
20509
+ const DEFAULT_EXP_CURVE = {
20510
+ basis: 30,
20511
+ extra: 20,
20512
+ accelerationA: 30,
20513
+ accelerationB: 30
20514
+ };
20515
+ function isObject$1(value) {
20516
+ return typeof value === "object" && value !== null;
20517
+ }
20518
+ function toValidNumber(value, fallback) {
20519
+ return typeof value === "number" && Number.isFinite(value) ? value : fallback;
20520
+ }
20521
+ function normalizeExpCurve(value) {
20522
+ if (!isObject$1(value)) return DEFAULT_EXP_CURVE;
20523
+ return {
20524
+ basis: toValidNumber(value.basis, DEFAULT_EXP_CURVE.basis),
20525
+ extra: toValidNumber(value.extra, DEFAULT_EXP_CURVE.extra),
20526
+ accelerationA: toValidNumber(value.accelerationA, DEFAULT_EXP_CURVE.accelerationA),
20527
+ accelerationB: toValidNumber(value.accelerationB, DEFAULT_EXP_CURVE.accelerationB)
20528
+ };
20529
+ }
20672
20530
  function WithParameterManager(Base) {
20673
20531
  return class extends Base {
20674
20532
  constructor() {
@@ -20771,7 +20629,7 @@ function WithParameterManager(Base) {
20771
20629
  * ```
20772
20630
  * @memberof ParameterManager
20773
20631
  * */
20774
- this._expCurveSignal = type(signal(""), "_expCurveSignal", { persist: true }, this);
20632
+ this._expCurveSignal = type(signal(JSON.stringify(DEFAULT_EXP_CURVE)), "_expCurveSignal", { persist: true }, this);
20775
20633
  }
20776
20634
  /**
20777
20635
  * Aggregates parameter modifiers from all sources (direct modifiers, states, equipment)
@@ -20820,7 +20678,13 @@ function WithParameterManager(Base) {
20820
20678
  return params;
20821
20679
  }
20822
20680
  get expCurve() {
20823
- return JSON.parse(this._expCurveSignal());
20681
+ const raw = this._expCurveSignal();
20682
+ if (!raw) return DEFAULT_EXP_CURVE;
20683
+ try {
20684
+ return normalizeExpCurve(JSON.parse(raw));
20685
+ } catch {
20686
+ return DEFAULT_EXP_CURVE;
20687
+ }
20824
20688
  }
20825
20689
  set expCurve(val) {
20826
20690
  this._expCurveSignal.set(JSON.stringify(val));
@@ -21169,10 +21033,12 @@ function WithItemFixture(Base) {
21169
21033
  };
21170
21034
  }
21171
21035
 
21172
- class Log {
21036
+ class Log extends Error {
21173
21037
  constructor(id, msg) {
21038
+ super(`[${id}] ${msg}`);
21039
+ this.name = "RpgLog";
21174
21040
  this.id = id;
21175
- this.msg = msg;
21041
+ Object.setPrototypeOf(this, new.target.prototype);
21176
21042
  }
21177
21043
  }
21178
21044
 
@@ -21549,13 +21415,17 @@ function WithItemManager(Base) {
21549
21415
  this.removeItem(itemClass);
21550
21416
  return inventory;
21551
21417
  }
21552
- equip(itemClass, equip = true) {
21553
- const itemId = isString(itemClass) ? itemClass : itemClass.name;
21554
- const inventory = this.getItem(itemClass);
21418
+ equip(itemId, equip = true) {
21419
+ const autoAdd = equip === "auto";
21420
+ const equipState = equip === "auto" ? true : equip;
21421
+ const data = this.databaseById(itemId);
21422
+ let inventory = this.getItem(itemId);
21423
+ if (!inventory && autoAdd) {
21424
+ inventory = this.addItem(itemId, 1);
21425
+ }
21555
21426
  if (!inventory) {
21556
21427
  throw ItemLog.notInInventory(itemId);
21557
21428
  }
21558
- const data = this.databaseById(itemId);
21559
21429
  if (data._type == "item") {
21560
21430
  throw ItemLog.invalidToEquiped(itemId);
21561
21431
  }
@@ -21570,18 +21440,18 @@ function WithItemManager(Base) {
21570
21440
  }
21571
21441
  }
21572
21442
  const item = inventory;
21573
- if (item.equipped && equip) {
21443
+ if (item.equipped && equipState) {
21574
21444
  throw ItemLog.isAlreadyEquiped(itemId);
21575
21445
  }
21576
- item.equipped = equip;
21577
- if (!equip) {
21446
+ item.equipped = equipState;
21447
+ if (!equipState) {
21578
21448
  const index = this.equipments().findIndex((it) => it.id() == item.id());
21579
21449
  this.equipments().splice(index, 1);
21580
21450
  } else {
21581
21451
  this.equipments().push(item);
21582
21452
  }
21583
21453
  const hookTarget = item._itemInstance || item;
21584
- this["execMethod"]("onEquip", [this, equip], hookTarget);
21454
+ this["execMethod"]("onEquip", [this, equipState], hookTarget);
21585
21455
  }
21586
21456
  };
21587
21457
  }
@@ -22180,8 +22050,11 @@ function WithClassManager(Base) {
22180
22050
  this.addParameter(param, actor.parameters[param]);
22181
22051
  }
22182
22052
  for (let item of actor.startingEquipment) {
22183
- this.addItem(item);
22184
- this.equip(item, true);
22053
+ const inventory = this.addItem(item);
22054
+ const itemId = inventory?.id?.();
22055
+ if (itemId) {
22056
+ this.equip(itemId, true);
22057
+ }
22185
22058
  }
22186
22059
  if (actor.class) this.setClass(actor.class);
22187
22060
  this["execMethod"]("onSet", [this], actor);
@@ -22365,7 +22238,9 @@ const _RpgPlayer = class _RpgPlayer extends BasicPlayerMixins(RpgCommonPlayer) {
22365
22238
  this._lastFramePositions = null;
22366
22239
  this.frames = [];
22367
22240
  this.events = signal([]);
22368
- let lastEmitted = null;
22241
+ const initialX = typeof this.x === "function" ? Number(this.x()) || 0 : 0;
22242
+ const initialY = typeof this.y === "function" ? Number(this.y()) || 0 : 0;
22243
+ let lastEmitted = { x: initialX, y: initialY };
22369
22244
  let pendingUpdate = null;
22370
22245
  let updateScheduled = false;
22371
22246
  combineLatest([this.x.observable, this.y.observable]).subscribe(([x, y]) => {
@@ -22467,6 +22342,7 @@ const _RpgPlayer = class _RpgPlayer extends BasicPlayerMixins(RpgCommonPlayer) {
22467
22342
  }
22468
22343
  setMap(map2) {
22469
22344
  this.map = map2;
22345
+ this.touchSide = true;
22470
22346
  }
22471
22347
  applyFrames() {
22472
22348
  this._frames.set(this.frames);
@@ -22508,12 +22384,13 @@ const _RpgPlayer = class _RpgPlayer extends BasicPlayerMixins(RpgCommonPlayer) {
22508
22384
  }));
22509
22385
  if (canChange.some((v) => v === false)) return false;
22510
22386
  if (positions && typeof positions === "object") {
22511
- this.teleport(positions);
22387
+ await this.teleport(positions);
22512
22388
  }
22513
- await room?.$sessionTransfer(this.conn, realMapId);
22389
+ const transferToken = await room?.$sessionTransfer(this.conn, realMapId);
22514
22390
  this.emit("changeMap", {
22515
22391
  mapId: realMapId,
22516
- positions
22392
+ positions,
22393
+ transferToken: typeof transferToken === "string" ? transferToken : void 0
22517
22394
  });
22518
22395
  return true;
22519
22396
  }
@@ -22525,16 +22402,28 @@ const _RpgPlayer = class _RpgPlayer extends BasicPlayerMixins(RpgCommonPlayer) {
22525
22402
  const direction = this.getDirection();
22526
22403
  const marginLeftRight = map2.tileWidth / 2;
22527
22404
  const marginTopDown = map2.tileHeight / 2;
22528
- const changeMap = async (adjacent, to) => {
22529
- if (this.touchSide) {
22405
+ const hitbox = this.hitbox();
22406
+ const currentX = this.x();
22407
+ const currentY = this.y();
22408
+ const nearBorder = currentX < marginLeftRight || currentX > map2.widthPx - hitbox.w - marginLeftRight || currentY < marginTopDown || currentY > map2.heightPx - hitbox.h - marginTopDown;
22409
+ if (this.touchSide) {
22410
+ if (nearBorder) {
22530
22411
  return false;
22531
22412
  }
22532
- this.touchSide = true;
22413
+ this.touchSide = false;
22414
+ }
22415
+ const changeMap = async (adjacent, to) => {
22533
22416
  const [nextMap] = worldMaps.getAdjacentMaps(map2, adjacent);
22534
- if (!nextMap) return false;
22417
+ if (!nextMap) {
22418
+ return false;
22419
+ }
22535
22420
  const id = nextMap.id;
22536
22421
  const nextMapInfo = worldMaps.getMapInfo(id);
22537
- return !!await this.changeMap(id, to(nextMapInfo));
22422
+ const changed = !!await this.changeMap(id, to(nextMapInfo));
22423
+ if (changed) {
22424
+ this.touchSide = true;
22425
+ }
22426
+ return changed;
22538
22427
  };
22539
22428
  if (nextPosition.x < marginLeftRight && direction == Direction.Left) {
22540
22429
  ret = await changeMap({
@@ -24517,7 +24406,7 @@ class Doc {
24517
24406
  const version = {
24518
24407
  major: 4,
24519
24408
  minor: 3,
24520
- patch: 5,
24409
+ patch: 6,
24521
24410
  };
24522
24411
 
24523
24412
  const $ZodType = /*@__PURE__*/ $constructor("$ZodType", (inst, def) => {
@@ -26574,7 +26463,7 @@ function finalize(ctx, schema) {
26574
26463
  }
26575
26464
  }
26576
26465
  // When ref was extracted to $defs, remove properties that match the definition
26577
- if (refSchema.$ref) {
26466
+ if (refSchema.$ref && refSeen.def) {
26578
26467
  for (const key in schema) {
26579
26468
  if (key === "$ref" || key === "allOf")
26580
26469
  continue;
@@ -27935,6 +27824,9 @@ var __decorateClass$1 = (decorators, target, key, kind) => {
27935
27824
  if (kind && result) __defProp$1(target, key, result);
27936
27825
  return result;
27937
27826
  };
27827
+ function isRpgLog(error) {
27828
+ return error instanceof Log || typeof error === "object" && error !== null && "id" in error && error.name === "RpgLog";
27829
+ }
27938
27830
  const MapUpdateSchema = object({
27939
27831
  /** Configuration object for the map (optional) */
27940
27832
  config: any().optional(),
@@ -27947,6 +27839,8 @@ const MapUpdateSchema = object({
27947
27839
  /** Height of the map in pixels (required) */
27948
27840
  height: number()
27949
27841
  });
27842
+ const SAFE_MAP_WIDTH = 1e3;
27843
+ const SAFE_MAP_HEIGHT = 1e3;
27950
27844
  let RpgMap = class extends RpgCommonMap {
27951
27845
  constructor(room) {
27952
27846
  super();
@@ -28019,6 +27913,7 @@ let RpgMap = class extends RpgCommonMap {
28019
27913
  * with custom formulas when the map is loaded.
28020
27914
  */
28021
27915
  this.damageFormulas = {};
27916
+ this._weatherState = null;
28022
27917
  /** Internal: Map of shapes by name */
28023
27918
  this._shapes = /* @__PURE__ */ new Map();
28024
27919
  /** Internal: Map of shape entity UUIDs to RpgShape instances */
@@ -28047,6 +27942,19 @@ let RpgMap = class extends RpgCommonMap {
28047
27942
  onStart() {
28048
27943
  return BaseRoom.prototype.onStart.call(this);
28049
27944
  }
27945
+ isPositiveNumber(value) {
27946
+ return typeof value === "number" && Number.isFinite(value) && value > 0;
27947
+ }
27948
+ resolveTrustedMapDimensions(map) {
27949
+ const normalizedId = typeof map?.id === "string" ? map.id.replace(/^map-/, "") : "";
27950
+ const worldMapInfo = normalizedId ? this.worldMapsManager?.getMapInfo(normalizedId) : null;
27951
+ if (!this.isPositiveNumber(map?.width)) {
27952
+ map.width = this.isPositiveNumber(worldMapInfo?.width) ? worldMapInfo.width : SAFE_MAP_WIDTH;
27953
+ }
27954
+ if (!this.isPositiveNumber(map?.height)) {
27955
+ map.height = this.isPositiveNumber(worldMapInfo?.height) ? worldMapInfo.height : SAFE_MAP_HEIGHT;
27956
+ }
27957
+ }
28050
27958
  /**
28051
27959
  * Setup collision detection between players, events, and shapes
28052
27960
  *
@@ -28090,8 +27998,8 @@ let RpgMap = class extends RpgCommonMap {
28090
27998
  const activeCollisions = /* @__PURE__ */ new Set();
28091
27999
  const activeShapeCollisions = /* @__PURE__ */ new Set();
28092
28000
  const hasDifferentZ = (entityA, entityB) => {
28093
- const zA = entityA.owner.z();
28094
- const zB = entityB.owner.z();
28001
+ const zA = entityA.owner?.z();
28002
+ const zB = entityB.owner?.z();
28095
28003
  return zA !== zB;
28096
28004
  };
28097
28005
  this.physic.getEvents().onCollisionEnter((collision) => {
@@ -28200,12 +28108,19 @@ let RpgMap = class extends RpgCommonMap {
28200
28108
  if (packet && typeof packet === "object") {
28201
28109
  obj.timestamp = Date.now();
28202
28110
  if (player) {
28111
+ const value = packet.value && typeof packet.value === "object" ? packet.value : void 0;
28112
+ const packetPlayers = value?.players && typeof value.players === "object" ? value.players : void 0;
28113
+ const playerSnapshot = packetPlayers?.[player.id];
28114
+ const bodyPos = this.getBodyPosition(player.id, "top-left");
28115
+ const ackX = typeof playerSnapshot?.x === "number" ? playerSnapshot.x : bodyPos?.x ?? player.x();
28116
+ const ackY = typeof playerSnapshot?.y === "number" ? playerSnapshot.y : bodyPos?.y ?? player.y();
28203
28117
  const lastFramePositions = player._lastFramePositions;
28204
28118
  obj.ack = {
28205
- frame: lastFramePositions?.frame ?? player.pendingInputs.length,
28206
- x: lastFramePositions?.position?.x ?? player.x(),
28207
- y: lastFramePositions?.position?.y ?? player.y(),
28208
- direction: lastFramePositions?.position?.direction ?? player.direction()
28119
+ frame: lastFramePositions?.frame ?? 0,
28120
+ serverTick: this.getTick(),
28121
+ x: Math.round(ackX),
28122
+ y: Math.round(ackY),
28123
+ direction: playerSnapshot?.direction ?? player.direction()
28209
28124
  };
28210
28125
  }
28211
28126
  }
@@ -28255,18 +28170,40 @@ let RpgMap = class extends RpgCommonMap {
28255
28170
  }
28256
28171
  player.context = context;
28257
28172
  player.conn = conn;
28173
+ player.pendingInputs = [];
28174
+ player.lastProcessedInputTs = 0;
28175
+ player._lastFramePositions = null;
28258
28176
  player._onInit();
28259
28177
  this.dataIsReady$.pipe(
28260
- finalize$1(async () => {
28261
- if (this.stopAllSoundsBeforeJoin) {
28262
- player.stopAllSounds();
28263
- }
28264
- this.sounds.forEach((sound) => player.playSound(sound, { loop: true }));
28265
- await lastValueFrom(this.hooks.callHooks("server-map-onJoin", player, this));
28266
- if (typeof this._onJoin === "function") {
28267
- await this._onJoin(player);
28268
- }
28269
- await lastValueFrom(this.hooks.callHooks("server-player-onJoinMap", player, this));
28178
+ finalize$1(() => {
28179
+ void (async () => {
28180
+ try {
28181
+ const hitbox = typeof player.hitbox === "function" ? player.hitbox() : player.hitbox;
28182
+ const width = hitbox?.w ?? 32;
28183
+ const height = hitbox?.h ?? 32;
28184
+ const body = this.getBody(player.id);
28185
+ if (body) {
28186
+ body.owner = player;
28187
+ }
28188
+ this.updateHitbox(player.id, player.x(), player.y(), width, height);
28189
+ if (this.stopAllSoundsBeforeJoin) {
28190
+ player.stopAllSounds();
28191
+ }
28192
+ this.sounds.forEach((sound) => player.playSound(sound, { loop: true }));
28193
+ player.emit("weatherState", this.getWeather());
28194
+ await lastValueFrom(this.hooks.callHooks("server-map-onJoin", player, this));
28195
+ if (typeof this._onJoin === "function") {
28196
+ await this._onJoin(player);
28197
+ }
28198
+ await lastValueFrom(this.hooks.callHooks("server-player-onJoinMap", player, this));
28199
+ } catch (error) {
28200
+ if (isRpgLog(error)) {
28201
+ console.warn(`[RpgLog:${error.id}] ${error.message}`);
28202
+ return;
28203
+ }
28204
+ console.error("[RPGJS] Error during map onJoin hooks:", error);
28205
+ }
28206
+ })();
28270
28207
  })
28271
28208
  ).subscribe();
28272
28209
  }
@@ -28300,6 +28237,8 @@ let RpgMap = class extends RpgCommonMap {
28300
28237
  }
28301
28238
  await lastValueFrom(this.hooks.callHooks("server-player-onLeaveMap", player, this));
28302
28239
  player.pendingInputs = [];
28240
+ player.lastProcessedInputTs = 0;
28241
+ player._lastFramePositions = null;
28303
28242
  }
28304
28243
  /**
28305
28244
  * Get the hooks system for this map
@@ -28342,18 +28281,60 @@ let RpgMap = class extends RpgCommonMap {
28342
28281
  player.execMethod("onInput", [action]);
28343
28282
  }
28344
28283
  async onInput(player, input) {
28345
- if (typeof input?.frame === "number") {
28346
- const existingInput = player.pendingInputs.find((pending) => pending.frame === input.frame);
28347
- if (existingInput) {
28284
+ const lastAckedFrame = player._lastFramePositions?.frame ?? 0;
28285
+ const now = Date.now();
28286
+ const candidates = [];
28287
+ const enqueueCandidate = (entry) => {
28288
+ if (typeof entry?.frame !== "number") {
28348
28289
  return;
28349
28290
  }
28350
- player.pendingInputs.push({
28351
- input: input.input,
28352
- frame: input.frame,
28353
- timestamp: input.timestamp || Date.now()
28354
- });
28291
+ if (!entry?.input) {
28292
+ return;
28293
+ }
28294
+ const candidate = {
28295
+ input: entry.input,
28296
+ frame: entry.frame,
28297
+ tick: typeof entry.tick === "number" ? entry.tick : void 0,
28298
+ timestamp: typeof entry.timestamp === "number" ? entry.timestamp : now
28299
+ };
28300
+ if (typeof entry.x === "number" && typeof entry.y === "number") {
28301
+ candidate.clientState = {
28302
+ x: entry.x,
28303
+ y: entry.y,
28304
+ direction: entry.direction
28305
+ };
28306
+ }
28307
+ candidates.push(candidate);
28308
+ };
28309
+ for (const trajectoryEntry of Array.isArray(input?.trajectory) ? input.trajectory : []) {
28310
+ enqueueCandidate(trajectoryEntry);
28311
+ }
28312
+ enqueueCandidate(input);
28313
+ if (candidates.length === 0) {
28314
+ return;
28315
+ }
28316
+ candidates.sort((a, b) => a.frame - b.frame);
28317
+ const existingFrames = new Set(
28318
+ player.pendingInputs.map((pending) => pending?.frame).filter((frame) => typeof frame === "number")
28319
+ );
28320
+ for (const candidate of candidates) {
28321
+ if (candidate.frame <= lastAckedFrame) {
28322
+ continue;
28323
+ }
28324
+ if (existingFrames.has(candidate.frame)) {
28325
+ continue;
28326
+ }
28327
+ player.pendingInputs.push(candidate);
28328
+ existingFrames.add(candidate.frame);
28355
28329
  }
28356
28330
  }
28331
+ onPing(player, payload) {
28332
+ player.emit("pong", {
28333
+ serverTick: this.getTick(),
28334
+ clientTime: typeof payload?.clientTime === "number" ? payload.clientTime : Date.now(),
28335
+ clientFrame: typeof payload?.clientFrame === "number" ? payload.clientFrame : 0
28336
+ });
28337
+ }
28357
28338
  async saveSlot(player, value) {
28358
28339
  BaseRoom.prototype.saveSlot(player, value);
28359
28340
  }
@@ -28378,9 +28359,15 @@ let RpgMap = class extends RpgCommonMap {
28378
28359
  await lastValueFrom(this.hooks.callHooks("server-maps-load", this));
28379
28360
  await lastValueFrom(this.hooks.callHooks("server-worldMaps-load", this));
28380
28361
  await lastValueFrom(this.hooks.callHooks("server-databaseHooks-load", this));
28362
+ this.resolveTrustedMapDimensions(map);
28363
+ this.data.set(map);
28381
28364
  map.events = map.events ?? [];
28365
+ let initialWeather = this.globalConfig?.weather;
28382
28366
  if (map.id) {
28383
28367
  const mapFound = this.maps.find((m) => m.id === map.id);
28368
+ if (typeof mapFound?.weather !== "undefined") {
28369
+ initialWeather = mapFound.weather;
28370
+ }
28384
28371
  if (mapFound?.events) {
28385
28372
  map.events = [
28386
28373
  ...mapFound.events,
@@ -28408,6 +28395,11 @@ let RpgMap = class extends RpgCommonMap {
28408
28395
  this.stopAllSoundsBeforeJoin = mapFound.stopAllSoundsBeforeJoin;
28409
28396
  }
28410
28397
  }
28398
+ if (typeof initialWeather !== "undefined") {
28399
+ this.setWeather(initialWeather);
28400
+ } else {
28401
+ this.clearWeather();
28402
+ }
28411
28403
  await lastValueFrom(this.hooks.callHooks("server-map-onBeforeUpdate", map, this));
28412
28404
  this.loadPhysic();
28413
28405
  for (let event of map.events ?? []) {
@@ -28447,10 +28439,11 @@ let RpgMap = class extends RpgCommonMap {
28447
28439
  /**
28448
28440
  * Process pending inputs for a player with anti-cheat validation
28449
28441
  *
28450
- * This method processes all pending inputs for a player while performing
28442
+ * This method processes pending inputs for a player while performing
28451
28443
  * anti-cheat validation to prevent time manipulation and frame skipping.
28452
28444
  * It validates the time deltas between inputs and ensures they are within
28453
- * acceptable ranges.
28445
+ * acceptable ranges. To preserve movement itinerary under network bursts,
28446
+ * the number of inputs processed per call is capped.
28454
28447
  *
28455
28448
  * ## Architecture
28456
28449
  *
@@ -28500,14 +28493,16 @@ let RpgMap = class extends RpgCommonMap {
28500
28493
  // Max 10 frames skipped
28501
28494
  minTimeBetweenInputs: 16,
28502
28495
  // ~60fps minimum
28503
- enableAntiCheat: false
28496
+ enableAntiCheat: false,
28497
+ maxInputsPerTick: 1
28504
28498
  };
28505
28499
  const config = { ...defaultControls, ...controls };
28506
28500
  let lastProcessedTime = player.lastProcessedInputTs || 0;
28507
- let lastProcessedFrame = 0;
28501
+ let lastProcessedFrame = player._lastFramePositions?.frame ?? 0;
28508
28502
  player.pendingInputs.sort((a, b) => (a.frame || 0) - (b.frame || 0));
28509
28503
  let hasProcessedInputs = false;
28510
- while (player.pendingInputs.length > 0) {
28504
+ let processedThisTick = 0;
28505
+ while (player.pendingInputs.length > 0 && processedThisTick < config.maxInputsPerTick) {
28511
28506
  const input = player.pendingInputs.shift();
28512
28507
  if (!input || typeof input.frame !== "number") {
28513
28508
  continue;
@@ -28537,6 +28532,19 @@ let RpgMap = class extends RpgCommonMap {
28537
28532
  processedInputs.push(input.input);
28538
28533
  hasProcessedInputs = true;
28539
28534
  lastProcessedTime = input.timestamp || Date.now();
28535
+ processedThisTick += 1;
28536
+ const bodyPos = this.getBodyPosition(player.id, "top-left");
28537
+ const ackX = typeof input.clientState?.x === "number" ? input.clientState.x : bodyPos?.x ?? player.x();
28538
+ const ackY = typeof input.clientState?.y === "number" ? input.clientState.y : bodyPos?.y ?? player.y();
28539
+ player._lastFramePositions = {
28540
+ frame: input.frame,
28541
+ position: {
28542
+ x: Math.round(ackX),
28543
+ y: Math.round(ackY),
28544
+ direction: input.clientState?.direction ?? player.direction()
28545
+ },
28546
+ serverTick: this.getTick()
28547
+ };
28540
28548
  }
28541
28549
  lastProcessedFrame = input.frame;
28542
28550
  }
@@ -28579,20 +28587,17 @@ let RpgMap = class extends RpgCommonMap {
28579
28587
  if (this._inputLoopSubscription) {
28580
28588
  this._inputLoopSubscription.unsubscribe();
28581
28589
  }
28582
- this._inputLoopSubscription = this.tick$.pipe(
28583
- throttleTime(50)
28584
- // Throttle to 50ms for input processing
28585
- ).subscribe(async ({ timestamp }) => {
28590
+ this._inputLoopSubscription = this.tick$.subscribe(() => {
28586
28591
  for (const player of this.getPlayers()) {
28587
- if (player.pendingInputs.length > 0) {
28588
- const anyPlayer = player;
28589
- if (!anyPlayer._isProcessingInputs) {
28590
- anyPlayer._isProcessingInputs = true;
28591
- await this.processInput(player.id).finally(() => {
28592
- anyPlayer._isProcessingInputs = false;
28593
- });
28594
- }
28592
+ const anyPlayer = player;
28593
+ const shouldProcess = player.pendingInputs.length > 0 || (player.lastProcessedInputTs || 0) > 0;
28594
+ if (!shouldProcess || anyPlayer._isProcessingInputs) {
28595
+ continue;
28595
28596
  }
28597
+ anyPlayer._isProcessingInputs = true;
28598
+ void this.processInput(player.id).finally(() => {
28599
+ anyPlayer._isProcessingInputs = false;
28600
+ });
28596
28601
  }
28597
28602
  });
28598
28603
  }
@@ -29090,6 +29095,66 @@ let RpgMap = class extends RpgCommonMap {
29090
29095
  animationName
29091
29096
  });
29092
29097
  }
29098
+ cloneWeatherState(weather) {
29099
+ if (!weather) {
29100
+ return null;
29101
+ }
29102
+ return {
29103
+ ...weather,
29104
+ params: weather.params ? { ...weather.params } : void 0
29105
+ };
29106
+ }
29107
+ /**
29108
+ * Get the current map weather state.
29109
+ */
29110
+ getWeather() {
29111
+ return this.cloneWeatherState(this._weatherState);
29112
+ }
29113
+ /**
29114
+ * Set the full weather state for this map.
29115
+ *
29116
+ * When `sync` is true (default), all connected clients receive the new weather.
29117
+ */
29118
+ setWeather(next, options = {}) {
29119
+ const sync2 = options.sync !== false;
29120
+ if (next && !next.effect) {
29121
+ throw new Error("setWeather: 'effect' is required when weather is not null.");
29122
+ }
29123
+ this._weatherState = this.cloneWeatherState(next);
29124
+ if (sync2) {
29125
+ this.$broadcast({
29126
+ type: "weatherState",
29127
+ value: this._weatherState
29128
+ });
29129
+ }
29130
+ return this.getWeather();
29131
+ }
29132
+ /**
29133
+ * Patch the current weather state.
29134
+ *
29135
+ * Nested `params` values are merged.
29136
+ */
29137
+ patchWeather(patch, options = {}) {
29138
+ const current = this._weatherState ?? null;
29139
+ if (!current && !patch.effect) {
29140
+ throw new Error("patchWeather: 'effect' is required when no weather is currently set.");
29141
+ }
29142
+ const next = {
29143
+ ...current ?? {},
29144
+ ...patch,
29145
+ params: {
29146
+ ...current?.params ?? {},
29147
+ ...patch.params ?? {}
29148
+ }
29149
+ };
29150
+ return this.setWeather(next, options);
29151
+ }
29152
+ /**
29153
+ * Clear weather for this map.
29154
+ */
29155
+ clearWeather(options = {}) {
29156
+ this.setWeather(null, options);
29157
+ }
29093
29158
  /**
29094
29159
  * Configure runtime synchronized properties on the map
29095
29160
  *
@@ -29530,6 +29595,9 @@ __decorateClass$1([
29530
29595
  __decorateClass$1([
29531
29596
  Action("move")
29532
29597
  ], RpgMap.prototype, "onInput", 1);
29598
+ __decorateClass$1([
29599
+ Action("ping")
29600
+ ], RpgMap.prototype, "onPing", 1);
29533
29601
  __decorateClass$1([
29534
29602
  Action("save.save")
29535
29603
  ], RpgMap.prototype, "saveSlot", 1);
@@ -29894,6 +29962,7 @@ function provideServerModules(modules) {
29894
29962
  type: MapClass.type,
29895
29963
  name: MapClass.prototype?.name,
29896
29964
  sounds: MapClass.prototype?.sounds,
29965
+ weather: MapClass.prototype?.weather,
29897
29966
  lowMemory: MapClass.prototype?.lowMemory,
29898
29967
  stopAllSoundsBeforeJoin: MapClass.prototype?.stopAllSoundsBeforeJoin,
29899
29968
  events: MapClass.prototype?._events,
@@ -30027,6 +30096,7 @@ function MapData(options) {
30027
30096
  target.prototype.file = options.file;
30028
30097
  target.prototype.id = options.id;
30029
30098
  target.prototype.sounds = options.sounds;
30099
+ target.prototype.weather = options.weather;
30030
30100
  target.prototype.lowMemory = options.lowMemory;
30031
30101
  target.prototype.stopAllSoundsBeforeJoin = options.stopAllSoundsBeforeJoin;
30032
30102
  target.prototype.$schema = {};