@rpgjs/server 4.1.3 → 4.2.1

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.
Files changed (45) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/browser/rpg.server.js +768 -366
  3. package/browser/rpg.server.umd.cjs +754 -352
  4. package/lib/Game/EventManager.js +1 -1
  5. package/lib/Game/EventManager.js.map +1 -1
  6. package/lib/Game/Map.d.ts +4 -0
  7. package/lib/Game/Map.js +11 -1
  8. package/lib/Game/Map.js.map +1 -1
  9. package/lib/Gui/Gui.js +1 -0
  10. package/lib/Gui/Gui.js.map +1 -1
  11. package/lib/MatchMaker.js +3 -1
  12. package/lib/MatchMaker.js.map +1 -1
  13. package/lib/Player/Player.d.ts +9 -3
  14. package/lib/Player/Player.js +24 -16
  15. package/lib/Player/Player.js.map +1 -1
  16. package/lib/RpgServer.d.ts +29 -0
  17. package/lib/Scenes/Map.d.ts +2 -3
  18. package/lib/Scenes/Map.js +7 -3
  19. package/lib/Scenes/Map.js.map +1 -1
  20. package/lib/entry-point.js +18 -12
  21. package/lib/entry-point.js.map +1 -1
  22. package/lib/express/server.js +0 -10
  23. package/lib/express/server.js.map +1 -1
  24. package/lib/index.d.ts +1 -0
  25. package/lib/index.js +1 -0
  26. package/lib/index.js.map +1 -1
  27. package/lib/inject.d.ts +22 -0
  28. package/lib/inject.js +29 -0
  29. package/lib/inject.js.map +1 -0
  30. package/lib/server.d.ts +7 -5
  31. package/lib/server.js +82 -38
  32. package/lib/server.js.map +1 -1
  33. package/package.json +7 -8
  34. package/src/Game/EventManager.ts +1 -1
  35. package/src/Game/Map.ts +15 -1
  36. package/src/Gui/Gui.ts +1 -0
  37. package/src/MatchMaker.ts +3 -1
  38. package/src/Player/Player.ts +18 -10
  39. package/src/RpgServer.ts +30 -1
  40. package/src/Scenes/Map.ts +6 -2
  41. package/src/entry-point.ts +19 -12
  42. package/src/express/server.ts +0 -10
  43. package/src/index.ts +1 -0
  44. package/src/inject.ts +33 -0
  45. package/src/server.ts +86 -35
@@ -2,135 +2,6 @@
2
2
  typeof exports === "object" && typeof module !== "undefined" ? factory(exports, require("@rpgjs/common"), require("@rpgjs/database")) : typeof define === "function" && define.amd ? define(["exports", "@rpgjs/common", "@rpgjs/database"], factory) : (global2 = typeof globalThis !== "undefined" ? globalThis : global2 || self, factory(global2.RpgServer = {}, global2.common, global2.database));
3
3
  })(this, function(exports2, common, database) {
4
4
  "use strict";
5
- var commonjsGlobal = typeof globalThis !== "undefined" ? globalThis : typeof window !== "undefined" ? window : typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : {};
6
- function getAugmentedNamespace(n) {
7
- if (n.__esModule)
8
- return n;
9
- var f = n.default;
10
- if (typeof f == "function") {
11
- var a = function a2() {
12
- if (this instanceof a2) {
13
- var args = [null];
14
- args.push.apply(args, arguments);
15
- var Ctor = Function.bind.apply(f, args);
16
- return new Ctor();
17
- }
18
- return f.apply(this, arguments);
19
- };
20
- a.prototype = f.prototype;
21
- } else
22
- a = {};
23
- Object.defineProperty(a, "__esModule", {
24
- value: true
25
- });
26
- Object.keys(n).forEach(function(k) {
27
- var d = Object.getOwnPropertyDescriptor(n, k);
28
- Object.defineProperty(a, k, d.get ? d : {
29
- enumerable: true,
30
- get: function() {
31
- return n[k];
32
- }
33
- });
34
- });
35
- return a;
36
- }
37
- /*!
38
- * isobject <https://github.com/jonschlinkert/isobject>
39
- *
40
- * Copyright (c) 2014-2017, Jon Schlinkert.
41
- * Released under the MIT License.
42
- */
43
- var isobject = function isObject2(val) {
44
- return val != null && typeof val === "object" && Array.isArray(val) === false;
45
- };
46
- /*!
47
- * get-value <https://github.com/jonschlinkert/get-value>
48
- *
49
- * Copyright (c) 2014-2018, Jon Schlinkert.
50
- * Released under the MIT License.
51
- */
52
- const isObject$3 = isobject;
53
- var getValue = function(target, path2, options2) {
54
- if (!isObject$3(options2)) {
55
- options2 = { default: options2 };
56
- }
57
- if (!isValidObject(target)) {
58
- return typeof options2.default !== "undefined" ? options2.default : target;
59
- }
60
- if (typeof path2 === "number") {
61
- path2 = String(path2);
62
- }
63
- const isArray2 = Array.isArray(path2);
64
- const isString2 = typeof path2 === "string";
65
- const splitChar = options2.separator || ".";
66
- const joinChar = options2.joinChar || (typeof splitChar === "string" ? splitChar : ".");
67
- if (!isString2 && !isArray2) {
68
- return target;
69
- }
70
- if (isString2 && path2 in target) {
71
- return isValid(path2, target, options2) ? target[path2] : options2.default;
72
- }
73
- let segs = isArray2 ? path2 : split(path2, splitChar, options2);
74
- let len = segs.length;
75
- let idx = 0;
76
- do {
77
- let prop = segs[idx];
78
- if (typeof prop === "number") {
79
- prop = String(prop);
80
- }
81
- while (prop && prop.slice(-1) === "\\") {
82
- prop = join$2([prop.slice(0, -1), segs[++idx] || ""], joinChar, options2);
83
- }
84
- if (prop in target) {
85
- if (!isValid(prop, target, options2)) {
86
- return options2.default;
87
- }
88
- target = target[prop];
89
- } else {
90
- let hasProp = false;
91
- let n = idx + 1;
92
- while (n < len) {
93
- prop = join$2([prop, segs[n++]], joinChar, options2);
94
- if (hasProp = prop in target) {
95
- if (!isValid(prop, target, options2)) {
96
- return options2.default;
97
- }
98
- target = target[prop];
99
- idx = n - 1;
100
- break;
101
- }
102
- }
103
- if (!hasProp) {
104
- return options2.default;
105
- }
106
- }
107
- } while (++idx < len && isValidObject(target));
108
- if (idx === len) {
109
- return target;
110
- }
111
- return options2.default;
112
- };
113
- function join$2(segs, joinChar, options2) {
114
- if (typeof options2.join === "function") {
115
- return options2.join(segs);
116
- }
117
- return segs[0] + joinChar + segs[1];
118
- }
119
- function split(path2, splitChar, options2) {
120
- if (typeof options2.split === "function") {
121
- return options2.split(path2);
122
- }
123
- return path2.split(splitChar);
124
- }
125
- function isValid(key, target, options2) {
126
- if (typeof options2.isValid === "function") {
127
- return options2.isValid(key, target);
128
- }
129
- return true;
130
- }
131
- function isValidObject(val) {
132
- return isObject$3(val) || Array.isArray(val) || typeof val === "function";
133
- }
134
5
  const GENERIC_KEY_SCHEMA = "@";
135
6
  class Utils {
136
7
  static isObject(val) {
@@ -161,25 +32,90 @@
161
32
  };
162
33
  return paths(obj);
163
34
  }
164
- static generateId() {
165
- return "$" + (Date.now().toString(36) + Math.random().toString(36).substr(2, 5));
35
+ static generateId(n = 5) {
36
+ return Math.random().toString(36).substring(n);
37
+ }
38
+ static async resolveValue(value) {
39
+ if (value instanceof Promise) {
40
+ return await value;
41
+ }
42
+ return value;
166
43
  }
167
- // https://stackoverflow.com/questions/54733539/javascript-implementation-of-lodash-set-method
168
44
  static set(obj, path2, value, onlyPlainObject = false) {
169
45
  if (Object(obj) !== obj)
170
46
  return obj;
171
- if (!Array.isArray(path2))
172
- path2 = path2.toString().match(/[^.[\]]+/g) || [];
173
- path2.slice(0, -1).reduce(
174
- (a, c2, i2) => (
175
- // Iterate all of them except the last one
176
- Object(a[c2]) === a[c2] ? a[c2] : a[c2] = Math.abs(path2[i2 + 1]) >> 0 === +path2[i2 + 1] ? onlyPlainObject ? {} : [] : {}
177
- ),
178
- // No: assign a new plain object
179
- obj
180
- )[path2[path2.length - 1]] = value;
47
+ if (typeof path2 === "string") {
48
+ path2 = path2.split(".");
49
+ }
50
+ let len = path2.length;
51
+ if (!len)
52
+ return obj;
53
+ let current = obj;
54
+ for (let i2 = 0; i2 < len - 1; i2++) {
55
+ let segment = path2[i2];
56
+ let nextSegment = path2[i2 + 1];
57
+ let isNextNumeric = !isNaN(nextSegment) && isFinite(nextSegment);
58
+ if (!current[segment] || typeof current[segment] !== "object") {
59
+ current[segment] = isNextNumeric && !onlyPlainObject ? [] : {};
60
+ }
61
+ current = current[segment];
62
+ }
63
+ current[path2[len - 1]] = value;
181
64
  return obj;
182
65
  }
66
+ static get(obj, path2) {
67
+ const keys2 = path2.split(".");
68
+ let current = obj;
69
+ for (let key of keys2) {
70
+ if (current[key] === void 0) {
71
+ return void 0;
72
+ }
73
+ current = current[key];
74
+ }
75
+ return current;
76
+ }
77
+ static bufferFrom(input) {
78
+ if (typeof input === "string") {
79
+ let encoder2 = new TextEncoder();
80
+ return encoder2.encode(input);
81
+ } else if (input instanceof ArrayBuffer || ArrayBuffer.isView(input)) {
82
+ return new Uint8Array(input);
83
+ } else {
84
+ throw new Error("Input type not supported");
85
+ }
86
+ }
87
+ }
88
+ var commonjsGlobal = typeof globalThis !== "undefined" ? globalThis : typeof window !== "undefined" ? window : typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : {};
89
+ function getAugmentedNamespace(n) {
90
+ if (n.__esModule)
91
+ return n;
92
+ var f = n.default;
93
+ if (typeof f == "function") {
94
+ var a = function a2() {
95
+ if (this instanceof a2) {
96
+ var args = [null];
97
+ args.push.apply(args, arguments);
98
+ var Ctor = Function.bind.apply(f, args);
99
+ return new Ctor();
100
+ }
101
+ return f.apply(this, arguments);
102
+ };
103
+ a.prototype = f.prototype;
104
+ } else
105
+ a = {};
106
+ Object.defineProperty(a, "__esModule", {
107
+ value: true
108
+ });
109
+ Object.keys(n).forEach(function(k) {
110
+ var d = Object.getOwnPropertyDescriptor(n, k);
111
+ Object.defineProperty(a, k, d.get ? d : {
112
+ enumerable: true,
113
+ get: function() {
114
+ return n[k];
115
+ }
116
+ });
117
+ });
118
+ return a;
183
119
  }
184
120
  var browser$2 = {};
185
121
  var encode$4 = {};
@@ -3755,16 +3691,17 @@
3755
3691
  get body() {
3756
3692
  return this.data;
3757
3693
  }
3758
- message(otherData = {}) {
3759
- return [this.roomId, Date.now(), { ...this.data, ...otherData }];
3694
+ message(otherData) {
3695
+ return [this.roomId, Date.now(), otherData ?? this.data];
3760
3696
  }
3761
3697
  clone(data) {
3762
3698
  return new Packet(data, this.roomId);
3763
3699
  }
3764
- encode(otherData = {}) {
3700
+ encode(otherData) {
3765
3701
  return browser$2.encode(this.message(otherData));
3766
3702
  }
3767
3703
  }
3704
+ const { get: get$1, set: set$1 } = Utils;
3768
3705
  class TransmitterClass {
3769
3706
  constructor() {
3770
3707
  this.encode = true;
@@ -3795,104 +3732,183 @@
3795
3732
  this.packets = {};
3796
3733
  }
3797
3734
  }
3798
- emit(user, packet, room) {
3799
- const send = (packet2) => {
3800
- const lastFramePositions = user["_lastFramePositions"];
3801
- let pos;
3802
- let lastFrame;
3803
- if (lastFramePositions) {
3804
- pos = lastFramePositions.position;
3805
- lastFrame = lastFramePositions.frame;
3806
- }
3807
- const data = { frame: lastFrame, pos };
3808
- user._socket.emit("w", this.encode ? packet2.encode(data) : packet2.message(data));
3809
- };
3810
- if (room.filterEmit) {
3811
- const objectPacket = room.filterEmit(user, packet);
3812
- const promiseObjectPacket = objectPacket;
3813
- if (promiseObjectPacket.then) {
3814
- promiseObjectPacket.then(send);
3815
- } else {
3816
- send(objectPacket);
3735
+ error(user, error) {
3736
+ const err = error instanceof Error ? error.toObject ? error.toObject() : error.message : error;
3737
+ user._socket.emit("error", err);
3738
+ }
3739
+ async emit(user, packet, room) {
3740
+ let data = packet.body;
3741
+ if (room.$additionalEmitProperties) {
3742
+ let additionalData = await Utils.resolveValue(room.$additionalEmitProperties(user, packet.body));
3743
+ if (additionalData !== void 0) {
3744
+ if (typeof additionalData === "string") {
3745
+ additionalData = [additionalData];
3746
+ }
3747
+ if (Array.isArray(additionalData)) {
3748
+ const newData = structuredClone(data);
3749
+ for (let path2 of additionalData) {
3750
+ set$1(newData, path2, get$1(room, path2));
3751
+ }
3752
+ data = newData;
3753
+ } else {
3754
+ data = { ...data, ...additionalData };
3755
+ }
3817
3756
  }
3818
- return;
3819
3757
  }
3820
- send(packet);
3758
+ user._socket.emit("w", this.encode ? packet.encode(data) : packet.message(data));
3821
3759
  }
3822
3760
  }
3823
3761
  const Transmitter = new TransmitterClass();
3824
- const { set } = Utils;
3825
- class Room {
3762
+ var UserState;
3763
+ (function(UserState2) {
3764
+ UserState2["Connected"] = "C";
3765
+ UserState2["Disconnected"] = "D";
3766
+ })(UserState || (UserState = {}));
3767
+ class User {
3826
3768
  constructor() {
3827
- this.memoryTotalObject = {};
3828
- this.memoryObject = {};
3829
- this.permanentObject = [];
3769
+ this.$state = UserState.Connected;
3770
+ this._secretSessionId = "";
3771
+ this._rooms = [];
3772
+ }
3773
+ }
3774
+ User.schema = {
3775
+ $state: String
3776
+ };
3777
+ class CustomError extends Error {
3778
+ constructor(customMessage) {
3779
+ super(customMessage);
3780
+ this.customMessage = customMessage;
3781
+ this.status = 500;
3782
+ this.code = "INTERNAL_SERVER_ERROR";
3783
+ this.message = "Internal Server error";
3784
+ }
3785
+ toObject() {
3786
+ return {
3787
+ message: this.customMessage || this.message,
3788
+ status: this.status,
3789
+ code: this.code
3790
+ };
3830
3791
  }
3792
+ }
3793
+ class NotAuthorized extends CustomError {
3794
+ constructor(customMessage) {
3795
+ super(customMessage);
3796
+ this.status = 401;
3797
+ this.code = "NOT_AUTHORIZED";
3798
+ this.message = "Not authorized";
3799
+ }
3800
+ }
3801
+ const { set, get } = Utils;
3802
+ class Room {
3831
3803
  static hasExtraProp(obj) {
3832
- return obj.$default !== void 0 || obj.$syncWithClient !== void 0 || obj.$permanent !== void 0 || obj.$validate !== void 0 || obj.$effects !== void 0;
3804
+ return obj.$default !== void 0 || obj.$syncWithClient !== void 0 || obj.$permanent !== void 0 || obj.$validate !== void 0 || obj.$effects !== void 0 || obj.$type !== void 0;
3833
3805
  }
3834
- static toDict(schema, room) {
3806
+ static compileSchema(schema, room) {
3835
3807
  const dict = {};
3808
+ const masks = {};
3836
3809
  const permanentObject = [];
3837
- function toDict(obj, path2 = "") {
3838
- for (let prop in obj) {
3839
- const val = obj[prop];
3810
+ function specialObject(val, p) {
3811
+ if (Room.hasExtraProp(val)) {
3812
+ if (val.$permanent ?? true)
3813
+ permanentObject.push(p);
3814
+ if (room && val.$default !== void 0)
3815
+ ;
3816
+ if (val.$syncWithClient === false) {
3817
+ return;
3818
+ }
3819
+ dict[p] = {
3820
+ ...val
3821
+ };
3822
+ } else {
3823
+ dict[p] = val;
3824
+ masks[p] = Utils.propertiesToArray(val);
3825
+ compile(val, p);
3826
+ }
3827
+ }
3828
+ function compile(schema2, path2 = "") {
3829
+ for (let prop in schema2) {
3830
+ const val = schema2[prop];
3840
3831
  let p = (path2 ? path2 + "." : "") + prop;
3841
3832
  if (Array.isArray(val)) {
3842
3833
  dict[p] = GENERIC_KEY_SCHEMA;
3843
3834
  p += "." + GENERIC_KEY_SCHEMA;
3844
- dict[p] = val[0];
3845
- toDict(val[0], p);
3846
- } else if (Utils.isObject(val)) {
3847
- if (Room.hasExtraProp(val)) {
3848
- if (val.$permanent ?? true)
3849
- permanentObject.push(p);
3850
- if (room && val.$default !== void 0)
3851
- ;
3852
- if (val.$syncWithClient === false) {
3853
- continue;
3854
- }
3855
- dict[p] = {
3856
- ...val
3857
- };
3835
+ if (val[0] === void 0)
3836
+ val[0] = {};
3837
+ if (Utils.isObject(val[0])) {
3838
+ specialObject(val[0], p);
3858
3839
  } else {
3859
- dict[p] = val;
3860
- toDict(val, p);
3840
+ dict[p] = val[0];
3841
+ compile(val[0], p);
3861
3842
  }
3843
+ } else if (Utils.isObject(val)) {
3844
+ specialObject(val, p);
3862
3845
  } else {
3863
3846
  permanentObject.push(p);
3864
3847
  dict[p] = val;
3865
3848
  }
3866
3849
  }
3867
3850
  }
3868
- toDict(schema);
3851
+ compile(schema);
3869
3852
  return {
3853
+ masks,
3870
3854
  dict,
3871
3855
  permanentObject
3872
3856
  };
3873
3857
  }
3874
- join(user, room) {
3875
- if (!user._rooms)
3876
- user._rooms = [];
3877
- user._rooms.push(room.id);
3878
- if (!user.id)
3879
- user.id = Utils.generateId();
3880
- if (room["onJoin"])
3881
- room["onJoin"](user);
3858
+ constructor(options2) {
3859
+ this.options = options2;
3860
+ this.memoryTotalObject = {};
3861
+ this.memoryObject = {};
3862
+ this.permanentObject = [];
3863
+ this.propagateOldRoom = true;
3864
+ if (options2.propagateOldRoom) {
3865
+ this.propagateOldRoom = options2.propagateOldRoom;
3866
+ }
3867
+ }
3868
+ async join(user, room) {
3869
+ if (room["canJoin"]) {
3870
+ const authBool = await Utils.resolveValue(room["canJoin"](user, user._socket));
3871
+ if (authBool === false || typeof authBool == "string") {
3872
+ Transmitter.error(user, new NotAuthorized(authBool));
3873
+ return false;
3874
+ }
3875
+ }
3876
+ if (World.agonesSDK) {
3877
+ await World.agonesSDK.allocate();
3878
+ }
3879
+ let firstJoin = !room.users[user.id];
3880
+ room.users[user.id] = user;
3881
+ const userProxy = World.users[user.id]["proxy"];
3882
+ userProxy.$state = UserState.Connected;
3883
+ if (firstJoin) {
3884
+ if (room["onJoin"])
3885
+ await Utils.resolveValue(room["onJoin"](userProxy));
3886
+ }
3882
3887
  if (this.getUsersLength(room) == 1) {
3883
3888
  this.memoryTotalObject = Room.extractObjectOfRoom(room, room.$schema);
3884
3889
  }
3885
3890
  const packet = new Packet({
3886
3891
  ...this.memoryTotalObject,
3887
- join: true
3892
+ join: firstJoin
3888
3893
  }, room.id);
3889
- Transmitter.emit(user, packet, room);
3894
+ await Transmitter.emit(userProxy, packet, room);
3895
+ return true;
3890
3896
  }
3891
- leave(user, room) {
3892
- const index2 = user._rooms.findIndex((id) => room.id == id);
3893
- user._rooms.splice(index2, 1);
3897
+ async leave(user, room) {
3894
3898
  if (room["onLeave"])
3895
3899
  room["onLeave"](user);
3900
+ const index2 = user._rooms.findIndex((id) => room.id == id);
3901
+ user._rooms.splice(index2, 1);
3902
+ delete room.users[user.id];
3903
+ delete World.users[user.id]["proxy"];
3904
+ if (World.nbUsers == 0 && World.agonesSDK) {
3905
+ const { onBeforeShutdown, shutdownIfNotPlayers } = World.agonesOptions;
3906
+ if (shutdownIfNotPlayers) {
3907
+ if (onBeforeShutdown)
3908
+ await onBeforeShutdown();
3909
+ await World.agonesSDK.shutdown();
3910
+ }
3911
+ }
3896
3912
  }
3897
3913
  getUsersLength(room) {
3898
3914
  return Object.keys(room.users).length;
@@ -3915,7 +3931,8 @@
3915
3931
  }
3916
3932
  setProxy(room) {
3917
3933
  const self2 = this;
3918
- const { dict, permanentObject } = Room.toDict(room.$schema, room);
3934
+ const { dict, permanentObject, masks } = Room.compileSchema(room.$schema, room);
3935
+ const proxifiedObjects = /* @__PURE__ */ new WeakSet();
3919
3936
  this.permanentObject = permanentObject;
3920
3937
  room.$dict = dict;
3921
3938
  const getInfoDict = (path2, key, dictPath) => {
@@ -3925,19 +3942,31 @@
3925
3942
  return {
3926
3943
  fullPath: p,
3927
3944
  genericPath,
3928
- infoDict: dict[genericPath]
3945
+ infoDict: dict[genericPath],
3946
+ mask: masks[genericPath]
3929
3947
  };
3930
3948
  };
3931
3949
  function deepProxy(object, path2 = "", dictPath = "") {
3950
+ if (proxifiedObjects.has(object)) {
3951
+ return object;
3952
+ }
3932
3953
  return new Proxy(object, {
3933
3954
  set(target, key, val, receiver) {
3934
- const { fullPath: p, infoDict, genericPath } = getInfoDict(path2, key, dictPath);
3955
+ const { fullPath: p, infoDict, genericPath, mask } = getInfoDict(path2, key, dictPath);
3935
3956
  if (typeof val == "object" && infoDict && val != null) {
3936
3957
  const valProxy = deepProxy(val, p, genericPath);
3958
+ proxifiedObjects.add(valProxy);
3937
3959
  if (path2 == "users") {
3960
+ if (!room.users[key]) {
3961
+ if (!valProxy._rooms)
3962
+ valProxy._rooms = [];
3963
+ valProxy._rooms.push(room.id);
3964
+ if (!valProxy.id)
3965
+ valProxy.id = Utils.generateId();
3966
+ }
3938
3967
  World.users[key]["proxy"] = valProxy;
3939
3968
  }
3940
- Reflect.set(target, key, valProxy, receiver);
3969
+ Reflect.set(target, key, val, receiver);
3941
3970
  val = target[key];
3942
3971
  } else {
3943
3972
  if (infoDict == null ? void 0 : infoDict.$validate) {
@@ -3971,7 +4000,7 @@
3971
4000
  }
3972
4001
  let newObj;
3973
4002
  if (Utils.isObject(infoDict) && val != null && !Room.hasExtraProp(infoDict)) {
3974
- newObj = Room.extractObjectOfRoom(val, infoDict);
4003
+ newObj = Room.extractObjectOfRoom(val, mask);
3975
4004
  } else if (infoDict == GENERIC_KEY_SCHEMA) {
3976
4005
  newObj = {};
3977
4006
  if (Object.keys(val).length == 0) {
@@ -4003,6 +4032,7 @@
4003
4032
  const { fullPath: p, infoDict, genericPath } = getInfoDict(path3, key, dictPath);
4004
4033
  if (typeof val2 == "object" && infoDict) {
4005
4034
  val2 = deepProxy(val2, p, genericPath);
4035
+ proxifiedObjects.add(val2);
4006
4036
  }
4007
4037
  return val2;
4008
4038
  };
@@ -4027,7 +4057,7 @@
4027
4057
  if (!room.$schema)
4028
4058
  room.$schema = {};
4029
4059
  if (!room.$schema.users)
4030
- room.$schema.users = [{ id: String }];
4060
+ room.$schema.users = [User.schema];
4031
4061
  if (!room.$inputs)
4032
4062
  room.$inputs = {};
4033
4063
  if (!room.users)
@@ -4053,16 +4083,20 @@
4053
4083
  room.$snapshotUser = (userId) => {
4054
4084
  return this.snapshotUser(room, userId);
4055
4085
  };
4056
- room.$join = (user) => {
4086
+ room.$join = async (user) => {
4087
+ if (typeof user == "string") {
4088
+ user = World.users[user];
4089
+ }
4057
4090
  if (user) {
4058
- room.users[user.id] = user;
4059
- this.join(room.users[user.id], room);
4091
+ return this.join(user, room);
4060
4092
  }
4093
+ return false;
4061
4094
  };
4062
- room.$leave = (user) => {
4063
- this.leave(user, room);
4064
- delete room.users[user.id];
4065
- delete World.users[user.id]["proxy"];
4095
+ room.$leave = async (user) => {
4096
+ if (typeof user == "string") {
4097
+ user = World.users[user]["proxy"];
4098
+ }
4099
+ await this.leave(user, room);
4066
4100
  };
4067
4101
  room.$currentState = () => this.memoryObject;
4068
4102
  room.$setCurrentState = (path2, value) => {
@@ -4071,6 +4105,7 @@
4071
4105
  room.$clearCurrentState = () => {
4072
4106
  this.memoryObject = {};
4073
4107
  };
4108
+ room.$parent = this;
4074
4109
  this.proxyRoom = room = this.setProxy(room);
4075
4110
  if (this.proxyRoom["onInit"])
4076
4111
  this.proxyRoom["onInit"]();
@@ -4078,52 +4113,59 @@
4078
4113
  }
4079
4114
  static extractObjectOfRoom(room, schema) {
4080
4115
  const newObj = {};
4081
- const schemas = [];
4082
4116
  const _schema = Array.isArray(schema) ? schema : Utils.propertiesToArray(schema);
4083
- function extract(path2) {
4084
- const match = new RegExp("^(.*?)\\.\\" + GENERIC_KEY_SCHEMA).exec(path2);
4117
+ const regex = new RegExp("^(.*?)\\.\\" + GENERIC_KEY_SCHEMA);
4118
+ function extractAndSet(obj, path2) {
4119
+ if (path2.endsWith("@")) {
4120
+ return;
4121
+ }
4122
+ const match = regex.exec(path2);
4085
4123
  if (match) {
4086
- const generic = getValue(room, match[1]);
4087
- if (generic) {
4088
- const keys2 = Object.keys(generic);
4089
- for (let key of keys2) {
4090
- extract(path2.replace(GENERIC_KEY_SCHEMA, key));
4124
+ const generic = get(room, match[1]);
4125
+ if (generic && typeof generic === "object") {
4126
+ for (let key in generic) {
4127
+ if (generic.hasOwnProperty(key)) {
4128
+ extractAndSet(obj, path2.replace(GENERIC_KEY_SCHEMA, key));
4129
+ }
4091
4130
  }
4092
4131
  }
4093
4132
  } else {
4094
- schemas.push(path2);
4133
+ set(obj, path2, get(room, path2));
4095
4134
  }
4096
4135
  }
4097
4136
  for (let path2 of _schema) {
4098
- extract(path2);
4099
- }
4100
- for (let sheme of schemas) {
4101
- set(newObj, sheme, getValue(room, sheme));
4137
+ extractAndSet(newObj, path2);
4102
4138
  }
4103
4139
  return newObj;
4104
4140
  }
4105
4141
  detectChanges(room, obj, path2) {
4142
+ const change = (room2) => {
4143
+ const roomInstance = room2.$parent;
4144
+ roomInstance.editMemoryObject(path2, obj);
4145
+ set(roomInstance.memoryTotalObject, path2, obj);
4146
+ if (roomInstance.proxyRoom["onChanges"])
4147
+ roomInstance.proxyRoom["onChanges"](roomInstance.memoryObject);
4148
+ const id = room2.id;
4149
+ World.changes.next({
4150
+ ...World.changes.value,
4151
+ [id]: room2
4152
+ });
4153
+ };
4106
4154
  if (obj != null) {
4107
4155
  const [prop, userId] = path2.split(".");
4108
4156
  if (prop == "users") {
4109
- if (!room.users[userId]) {
4157
+ if (!this.propagateOldRoom && !room.users[userId]) {
4110
4158
  return;
4111
4159
  }
4160
+ World.forEachUserRooms(userId, change);
4161
+ return;
4112
4162
  }
4113
4163
  }
4114
- this.editMemoryObject(path2, obj);
4115
- set(this.memoryTotalObject, path2, obj);
4116
- if (this.proxyRoom["onChanges"])
4117
- this.proxyRoom["onChanges"](this.memoryObject);
4118
- const id = room.id;
4119
- World.changes.next({
4120
- ...World.changes.value,
4121
- [id]: room
4122
- });
4164
+ change(room);
4123
4165
  }
4124
4166
  editMemoryObject(path2, roomOrValue) {
4125
4167
  if (roomOrValue && typeof roomOrValue == "object" && "$currentState" in roomOrValue) {
4126
- set(this.memoryObject, path2, getValue(roomOrValue, path2), true);
4168
+ set(this.memoryObject, path2, get(roomOrValue, path2), true);
4127
4169
  } else {
4128
4170
  set(this.memoryObject, path2, roomOrValue, true);
4129
4171
  }
@@ -4147,28 +4189,6 @@
4147
4189
  this.onDisconnectedCb = cb;
4148
4190
  }
4149
4191
  }
4150
- class Transport extends TransportCommon {
4151
- constructor(io) {
4152
- super();
4153
- this.io = io;
4154
- io.on("connection", (socket) => {
4155
- const id = socket.client.id;
4156
- this.onConnectedCb(socket, id);
4157
- socket.on(":input", ({ prop, value }) => this.onInputCb(id, prop, value));
4158
- socket.on(":action", ({ name, value }) => this.onActionCb(id, name, value));
4159
- socket.on(":join", (roomId) => this.onJoinCb(roomId, id));
4160
- socket.on("disconnect", () => this.onDisconnectedCb(id));
4161
- });
4162
- }
4163
- }
4164
- class User {
4165
- constructor() {
4166
- this._rooms = [];
4167
- }
4168
- }
4169
- User.schema = {
4170
- id: String
4171
- };
4172
4192
  var extendStatics = function(d, b) {
4173
4193
  extendStatics = Object.setPrototypeOf || { __proto__: [] } instanceof Array && function(d2, b2) {
4174
4194
  d2.__proto__ = b2;
@@ -5057,12 +5077,132 @@
5057
5077
  };
5058
5078
  return BehaviorSubject2;
5059
5079
  }(Subject);
5080
+ class Transport extends TransportCommon {
5081
+ constructor(io, options2 = {}) {
5082
+ super();
5083
+ this.io = io;
5084
+ this.options = options2;
5085
+ this.bandwidthData = {};
5086
+ this.WINDOW_SECONDS = 10;
5087
+ io.on("connection", (socket) => {
5088
+ const id = socket.playerId;
5089
+ this.bandwidthData[id] = new BehaviorSubject({
5090
+ incoming: [],
5091
+ outgoing: []
5092
+ });
5093
+ this.handleConnection(socket, id);
5094
+ socket.on(":input", ({ prop, value }) => this.onInputCb(id, prop, value));
5095
+ socket.on(":action", ({ name, value }) => this.onActionCb(id, name, value));
5096
+ if (options2.clientCanJoinRoom)
5097
+ socket.on(":join", (roomId) => this.onJoinCb(roomId, id));
5098
+ socket.on("disconnect", () => {
5099
+ var _a;
5100
+ (_a = this.bandwidthData[id]) == null ? void 0 : _a.unsubscribe();
5101
+ delete this.bandwidthData[id];
5102
+ this.onDisconnectedCb(id);
5103
+ });
5104
+ });
5105
+ this.use();
5106
+ }
5107
+ handleConnection(socket, id) {
5108
+ this.onConnectedCb(socket, id);
5109
+ }
5110
+ use() {
5111
+ var _a, _b;
5112
+ const { maxKbpsIncoming, maxKbpsOutgoing, auth } = this.options;
5113
+ (_b = (_a = this.io).use) == null ? void 0 : _b.call(_a, async (socket, next) => {
5114
+ let playerId;
5115
+ if (auth) {
5116
+ try {
5117
+ playerId = await Utils.resolveValue(auth(socket));
5118
+ } catch (err) {
5119
+ socket.disconnect();
5120
+ next(new NotAuthorized(err).toObject());
5121
+ return;
5122
+ }
5123
+ }
5124
+ if (!playerId)
5125
+ playerId = Utils.generateId(5);
5126
+ socket.playerId = playerId;
5127
+ socket.use((packet, nextMiddleware) => {
5128
+ var _a2, _b2;
5129
+ if (packet && packet[1]) {
5130
+ const packetSize = Utils.bufferFrom(JSON.stringify(packet)).length - 2;
5131
+ const data = { size: packetSize, timestamp: Date.now() };
5132
+ this.updateBandwidthData(playerId, { incoming: data });
5133
+ const kbps = this.calculateKbps(((_a2 = this.bandwidthData[playerId]) == null ? void 0 : _a2.value.incoming) || []);
5134
+ if (maxKbpsIncoming && kbps > maxKbpsIncoming) {
5135
+ socket.disconnect();
5136
+ return;
5137
+ }
5138
+ this.cleanOldData(((_b2 = this.bandwidthData[playerId]) == null ? void 0 : _b2.value.incoming) || []);
5139
+ }
5140
+ nextMiddleware();
5141
+ });
5142
+ const originalEmit = socket.emit;
5143
+ socket.emit = (...args) => {
5144
+ var _a2, _b2;
5145
+ const packetSize = Utils.bufferFrom(JSON.stringify(args)).length - 2;
5146
+ const data = { size: packetSize, timestamp: Date.now() };
5147
+ this.updateBandwidthData(playerId, { outgoing: data });
5148
+ const kbps = this.calculateKbps(((_a2 = this.bandwidthData[playerId]) == null ? void 0 : _a2.value.outgoing) || []);
5149
+ if (maxKbpsOutgoing && kbps > maxKbpsOutgoing) {
5150
+ socket.disconnect();
5151
+ return;
5152
+ }
5153
+ this.cleanOldData(((_b2 = this.bandwidthData[playerId]) == null ? void 0 : _b2.value.outgoing) || []);
5154
+ originalEmit.apply(socket, args);
5155
+ };
5156
+ next();
5157
+ });
5158
+ }
5159
+ updateBandwidthData(socketId, data) {
5160
+ var _a, _b;
5161
+ const currentData = ((_a = this.bandwidthData[socketId]) == null ? void 0 : _a.value) || { incoming: [], outgoing: [] };
5162
+ if (data.incoming) {
5163
+ currentData.incoming.push(data.incoming);
5164
+ }
5165
+ if (data.outgoing) {
5166
+ currentData.outgoing.push(data.outgoing);
5167
+ }
5168
+ (_b = this.bandwidthData[socketId]) == null ? void 0 : _b.next(currentData);
5169
+ }
5170
+ cleanOldData(dataArray) {
5171
+ const cutOff = Date.now() - this.WINDOW_SECONDS * 1e3;
5172
+ while (dataArray.length > 0 && dataArray[0].timestamp < cutOff) {
5173
+ dataArray.shift();
5174
+ }
5175
+ }
5176
+ calculateKbps(dataArray) {
5177
+ const totalBytes = dataArray.reduce((acc, entry) => acc + entry.size, 0);
5178
+ return totalBytes * 8 / (this.WINDOW_SECONDS * 1e3);
5179
+ }
5180
+ getTelemetry() {
5181
+ const socketsData = {};
5182
+ let totalKbps = 0;
5183
+ for (const [socketId, bandwidth] of Object.entries(this.bandwidthData)) {
5184
+ const socketData = bandwidth.value;
5185
+ const incomingKbps = this.calculateKbps(socketData.incoming);
5186
+ const outgoingKbps = this.calculateKbps(socketData.outgoing);
5187
+ socketsData[socketId] = { incomingKbps, outgoingKbps };
5188
+ totalKbps += incomingKbps + outgoingKbps;
5189
+ }
5190
+ return {
5191
+ sockets: socketsData,
5192
+ totalKbps
5193
+ };
5194
+ }
5195
+ }
5060
5196
  class WorldClass {
5061
5197
  constructor() {
5062
5198
  this.rooms = /* @__PURE__ */ new Map();
5063
5199
  this.users = {};
5064
5200
  this.userClass = User;
5201
+ this.timeoutDisconnect = 0;
5065
5202
  this.changes = new BehaviorSubject({});
5203
+ this._transport = null;
5204
+ this.agonesSDK = null;
5205
+ this.agonesOptions = {};
5066
5206
  }
5067
5207
  /**
5068
5208
  * Define user class
@@ -5073,32 +5213,48 @@
5073
5213
  setUserClass(userClass) {
5074
5214
  this.userClass = userClass;
5075
5215
  }
5216
+ setAgones(agones, options2 = {}) {
5217
+ this.agonesSDK = agones;
5218
+ this.agonesOptions = options2;
5219
+ }
5076
5220
  /**
5077
5221
  * Define transportation. You can set socket.io as default
5078
5222
  *
5079
5223
  * @method transport()
5080
5224
  * @param {object} io
5081
- * @returns {void}
5225
+ * @returns {Transport}
5082
5226
  */
5083
- transport(io) {
5084
- const transport = new Transport(io);
5227
+ transport(io, options2 = {}) {
5228
+ if (options2.timeoutDisconnect) {
5229
+ this.timeoutDisconnect = options2.timeoutDisconnect;
5230
+ }
5231
+ const transport = new Transport(io, options2);
5085
5232
  transport.onConnected(this.connectUser.bind(this));
5086
5233
  transport.onDisconnected(this.disconnectUser.bind(this));
5087
5234
  transport.onJoin(this.joinRoom.bind(this));
5088
5235
  transport.onInput((id, prop, value) => {
5089
5236
  this.forEachUserRooms(id, (room, user) => {
5090
- if (room.$inputs && room.$inputs[prop]) {
5091
- room[prop] = value;
5237
+ try {
5238
+ if (room.$inputs && room.$inputs[prop]) {
5239
+ room[prop] = value;
5240
+ }
5241
+ } catch (err) {
5242
+ Transmitter.error(user, err);
5092
5243
  }
5093
5244
  });
5094
5245
  });
5095
5246
  transport.onAction((id, name, value) => {
5096
5247
  this.forEachUserRooms(id, async (room, user) => {
5097
5248
  if (room.$actions && room.$actions[name]) {
5098
- room[name](user, value);
5249
+ try {
5250
+ room[name](user, value);
5251
+ } catch (err) {
5252
+ Transmitter.error(user, err);
5253
+ }
5099
5254
  }
5100
5255
  });
5101
5256
  });
5257
+ return this._transport = transport;
5102
5258
  }
5103
5259
  /**
5104
5260
  * Loop over all rooms of a user
@@ -5117,7 +5273,7 @@
5117
5273
  * @returns {void}
5118
5274
  */
5119
5275
  forEachUserRooms(userId, cb) {
5120
- const user = this.getUser(userId);
5276
+ const user = this.getUser(userId, true);
5121
5277
  if (!user)
5122
5278
  return;
5123
5279
  for (let roomId of user._rooms) {
@@ -5156,29 +5312,32 @@
5156
5312
  this.users[user.id] = user;
5157
5313
  return this.users[user.id];
5158
5314
  }
5315
+ get nbUsers() {
5316
+ return Object.keys(this.users).length;
5317
+ }
5159
5318
  /**
5160
5319
  * Send the packages to the rooms.
5161
5320
  *
5162
5321
  * @method send()
5163
5322
  */
5164
- send() {
5165
- this.rooms.forEach((room, id) => {
5323
+ async send() {
5324
+ for (let [_, room] of this.rooms) {
5166
5325
  const obj = room.$currentState();
5167
5326
  if (Object.keys(obj).length == 0) {
5168
5327
  return;
5169
5328
  }
5170
5329
  Transmitter.addPacket(room, obj);
5171
- for (let id2 in room.users) {
5172
- const user = room.users[id2];
5330
+ for (let id in room.users) {
5331
+ const user = room.users[id];
5173
5332
  const packets = Transmitter.getPackets(room);
5174
5333
  if (packets) {
5175
5334
  for (let packet of packets) {
5176
- Transmitter.emit(user, packet, room);
5335
+ await Transmitter.emit(user, packet, room);
5177
5336
  }
5178
5337
  }
5179
5338
  }
5180
5339
  room.$clearCurrentState();
5181
- });
5340
+ }
5182
5341
  Transmitter.clear();
5183
5342
  }
5184
5343
  /**
@@ -5187,10 +5346,23 @@
5187
5346
  * @method connectUser()
5188
5347
  * @param {object} socket
5189
5348
  * @param {id} userId
5349
+ * @param {object} options
5350
+ * - getUserInstance: function that returns a new instance of the user
5190
5351
  * @returns {User}
5191
5352
  */
5192
- connectUser(socket, id) {
5193
- const user = new this.userClass();
5353
+ connectUser(socket, id, options2 = {}) {
5354
+ var _a;
5355
+ const existingUser = this.getUser(id, false);
5356
+ if (existingUser) {
5357
+ if (existingUser._timeoutDisconnect) {
5358
+ clearTimeout(existingUser._timeoutDisconnect);
5359
+ delete existingUser._timeoutDisconnect;
5360
+ }
5361
+ existingUser._socket = socket;
5362
+ existingUser.$state = UserState.Connected;
5363
+ return existingUser;
5364
+ }
5365
+ const user = ((_a = options2.getUserInstance) == null ? void 0 : _a.call(options2, socket)) ?? new this.userClass();
5194
5366
  user.id = id;
5195
5367
  socket.emit("uid", id);
5196
5368
  this.setUser(user, socket);
@@ -5204,18 +5376,52 @@
5204
5376
  * @returns {void}
5205
5377
  */
5206
5378
  disconnectUser(userId) {
5207
- this.forEachUserRooms(userId, (room, user) => {
5208
- if (room.$leave)
5209
- room.$leave(user);
5379
+ return new Promise((resolve2, reject) => {
5380
+ const user = this.getUser(userId);
5381
+ if (!user)
5382
+ return resolve2();
5383
+ user.$state = UserState.Disconnected;
5384
+ const leave = () => {
5385
+ const leaveAllPromises = [];
5386
+ this.forEachUserRooms(userId, async (room, user2) => {
5387
+ if (room.$leave)
5388
+ leaveAllPromises.push(room.$leave(user2));
5389
+ });
5390
+ delete this.users[userId];
5391
+ Promise.all(leaveAllPromises).then(resolve2).catch((err) => {
5392
+ Transmitter.error(user, err);
5393
+ reject(err);
5394
+ });
5395
+ };
5396
+ if (!this.timeoutDisconnect) {
5397
+ leave();
5398
+ return;
5399
+ }
5400
+ user._timeoutDisconnect = setTimeout(leave, this.timeoutDisconnect);
5210
5401
  });
5211
- delete this.users[userId];
5212
5402
  }
5213
- joinOrLeaveRoom(type, roomId, userId) {
5403
+ httpUpgrade(httpServer, io) {
5404
+ httpServer.removeAllListeners("upgrade");
5405
+ httpServer.on("upgrade", (req, socket, head) => {
5406
+ if (req.url.startsWith("/socket.io/")) {
5407
+ io.engine.handleUpgrade(req, socket, head);
5408
+ } else {
5409
+ socket.destroy();
5410
+ }
5411
+ });
5412
+ }
5413
+ async joinOrLeaveRoom(type, roomId, userId) {
5214
5414
  const room = this.getRoom(roomId);
5215
5415
  if (!room)
5216
5416
  return;
5217
- if (room[type])
5218
- room[type](this.getUser(userId, false));
5417
+ if (room[type]) {
5418
+ try {
5419
+ await room[type](this.getUser(userId, false));
5420
+ } catch (err) {
5421
+ Transmitter.error(this.getUser(userId, false), err);
5422
+ throw err;
5423
+ }
5424
+ }
5219
5425
  return room;
5220
5426
  }
5221
5427
  /**
@@ -5225,7 +5431,7 @@
5225
5431
  * @param {string} userId
5226
5432
  * @returns {RoomClass | undefined}
5227
5433
  */
5228
- leaveRoom(roomId, userId) {
5434
+ async leaveRoom(roomId, userId) {
5229
5435
  return this.joinOrLeaveRoom("$leave", roomId, userId);
5230
5436
  }
5231
5437
  /**
@@ -5235,7 +5441,7 @@
5235
5441
  * @param {string} userId
5236
5442
  * @returns {RoomClass | undefined}
5237
5443
  */
5238
- joinRoom(roomId, userId) {
5444
+ async joinRoom(roomId, userId) {
5239
5445
  return this.joinOrLeaveRoom("$join", roomId, userId);
5240
5446
  }
5241
5447
  /**
@@ -5265,12 +5471,15 @@
5265
5471
  * @param {Class or instance of Class} roomClass
5266
5472
  * @returns instance of Class
5267
5473
  */
5268
- addRoom(id, roomClass) {
5474
+ addRoom(id, roomClass, options2 = {}) {
5269
5475
  if (roomClass.constructor.name == "Function") {
5270
5476
  roomClass = new roomClass();
5271
5477
  }
5272
- const room = new Room().add(id, roomClass);
5478
+ const room = new Room(options2).add(id, roomClass);
5273
5479
  this.rooms.set(id, room);
5480
+ if (this.agonesSDK) {
5481
+ this.agonesSDK.setLabel("room.id", id);
5482
+ }
5274
5483
  return room;
5275
5484
  }
5276
5485
  /**
@@ -5304,11 +5513,132 @@
5304
5513
  * Remove all rooms and users
5305
5514
  */
5306
5515
  clear() {
5516
+ var _a, _b;
5307
5517
  this.rooms.clear();
5518
+ this.changes.next({});
5308
5519
  this.users = {};
5520
+ if (this._transport) {
5521
+ (_b = (_a = this._transport.io) == null ? void 0 : _a.clear) == null ? void 0 : _b.call(_a);
5522
+ }
5309
5523
  }
5310
5524
  }
5311
5525
  const World = new WorldClass();
5526
+ class MiddlewareHandler {
5527
+ constructor() {
5528
+ this.middlewares = [];
5529
+ }
5530
+ use(middleware) {
5531
+ this.middlewares.push(middleware);
5532
+ }
5533
+ run(socket, finalCallback = (err) => {
5534
+ }) {
5535
+ let index2 = 0;
5536
+ const next = (err) => {
5537
+ if (err) {
5538
+ finalCallback(err);
5539
+ return;
5540
+ }
5541
+ if (index2 >= this.middlewares.length) {
5542
+ finalCallback();
5543
+ return;
5544
+ }
5545
+ const middleware = this.middlewares[index2];
5546
+ index2 += 1;
5547
+ middleware(socket, next);
5548
+ };
5549
+ next();
5550
+ }
5551
+ clear() {
5552
+ this.middlewares = [];
5553
+ }
5554
+ }
5555
+ class MockIo {
5556
+ constructor() {
5557
+ this.events = /* @__PURE__ */ new Map();
5558
+ this.eventsOnce = /* @__PURE__ */ new Map();
5559
+ }
5560
+ on(name, value) {
5561
+ this.events.set(name, [...this.events.get(name) || [], value]);
5562
+ }
5563
+ off(name) {
5564
+ if (this.eventsOnce.has(name)) {
5565
+ this.eventsOnce.delete(name);
5566
+ return;
5567
+ }
5568
+ this.events.delete(name);
5569
+ }
5570
+ once(name, value) {
5571
+ this.eventsOnce.set(name, value);
5572
+ }
5573
+ _trigger(name, data, client) {
5574
+ const events = this.events.get(name) || [];
5575
+ for (const event of events) {
5576
+ event(data, client);
5577
+ }
5578
+ const eventOnce = this.eventsOnce.get(name);
5579
+ if (eventOnce) {
5580
+ eventOnce(data, client);
5581
+ this.eventsOnce.delete(name);
5582
+ }
5583
+ }
5584
+ }
5585
+ class MockSocket extends MockIo {
5586
+ constructor(handshake, client) {
5587
+ super();
5588
+ this.handshake = handshake;
5589
+ this.client = client;
5590
+ this.middlewares = new MiddlewareHandler();
5591
+ this.id = client.fakeId ?? "" + Math.random();
5592
+ this.client.id = this.id;
5593
+ }
5594
+ emit(name, data) {
5595
+ this.client._trigger(name, data);
5596
+ }
5597
+ removeAllListeners(name) {
5598
+ return this.off(name);
5599
+ }
5600
+ use(cb) {
5601
+ this.middlewares.use(cb);
5602
+ }
5603
+ disconnect() {
5604
+ }
5605
+ }
5606
+ class MockServerIo extends MockIo {
5607
+ constructor() {
5608
+ super(...arguments);
5609
+ this.clients = /* @__PURE__ */ new Map();
5610
+ this.middlewares = new MiddlewareHandler();
5611
+ }
5612
+ connection(client, handshake) {
5613
+ return new Promise((resolve2, reject) => {
5614
+ const socket = new MockSocket(handshake, client);
5615
+ this.clients.set(socket.id, socket);
5616
+ client.id = socket.id;
5617
+ this.middlewares.run(socket, (err) => {
5618
+ if (err) {
5619
+ client._trigger("error", err);
5620
+ return;
5621
+ }
5622
+ this._trigger("connection", socket);
5623
+ resolve2(socket);
5624
+ });
5625
+ });
5626
+ }
5627
+ emit(name, data, id) {
5628
+ var _a;
5629
+ (_a = this.clients.get(id)) == null ? void 0 : _a._trigger(name, data);
5630
+ }
5631
+ use(cb) {
5632
+ this.middlewares.use(cb);
5633
+ }
5634
+ clear() {
5635
+ this.events.clear();
5636
+ this.eventsOnce.clear();
5637
+ this.clients.clear();
5638
+ this.middlewares.clear();
5639
+ }
5640
+ }
5641
+ new MockServerIo();
5312
5642
  var TiledLayerType;
5313
5643
  (function(TiledLayerType2) {
5314
5644
  TiledLayerType2["Tile"] = "tilelayer";
@@ -10163,6 +10493,9 @@
10163
10493
  if (!type)
10164
10494
  return;
10165
10495
  TiledParser.toArray(type).forEach((val) => {
10496
+ if (this.layers.has(+val._attributes.id)) {
10497
+ throw new Error(`Tiled Parser Error: Layer with id ${val._attributes.id} already exists`);
10498
+ }
10166
10499
  this.layers.set(+val._attributes.id, val);
10167
10500
  });
10168
10501
  };
@@ -12447,7 +12780,7 @@
12447
12780
  return func(value);
12448
12781
  };
12449
12782
  }
12450
- function getValue2(object, key) {
12783
+ function getValue(object, key) {
12451
12784
  return object == null ? void 0 : object[key];
12452
12785
  }
12453
12786
  function overArg(func, transform) {
@@ -12886,7 +13219,7 @@
12886
13219
  return isKeyable(key) ? data[typeof key == "string" ? "string" : "hash"] : data.map;
12887
13220
  }
12888
13221
  function getNative(object, key) {
12889
- var value = getValue2(object, key);
13222
+ var value = getValue(object, key);
12890
13223
  return baseIsNative(value) ? value : void 0;
12891
13224
  }
12892
13225
  function getRawTag(value) {
@@ -14875,6 +15208,7 @@
14875
15208
  blockPlayerInput = false
14876
15209
  } = {}) {
14877
15210
  return new Promise((resolve2) => {
15211
+ this.player.moving = false;
14878
15212
  this.player.emit("gui.open", {
14879
15213
  guiId: this.id,
14880
15214
  data
@@ -17594,7 +17928,6 @@
17594
17928
  }
17595
17929
  // @internal
17596
17930
  removeObject(object, mode = "shared") {
17597
- var _a;
17598
17931
  const map = this.getCurrentMap();
17599
17932
  if (!map)
17600
17933
  return;
@@ -17613,7 +17946,7 @@
17613
17946
  if (object.id == playerId)
17614
17947
  continue;
17615
17948
  const otherPlayer = map.players[playerId];
17616
- if (((_a = otherPlayer.following) == null ? void 0 : _a.id) == object.id) {
17949
+ if (otherPlayer.followingId == object.id) {
17617
17950
  otherPlayer.cameraFollow(otherPlayer);
17618
17951
  }
17619
17952
  }
@@ -17622,6 +17955,13 @@
17622
17955
  }
17623
17956
  }
17624
17957
  }
17958
+ let instanceContext = null;
17959
+ function inject(service, args = []) {
17960
+ return instanceContext.inject(service, args);
17961
+ }
17962
+ function setInject(context) {
17963
+ instanceContext = context;
17964
+ }
17625
17965
  const {
17626
17966
  isPromise,
17627
17967
  applyMixins,
@@ -17743,8 +18083,9 @@
17743
18083
  lines: []
17744
18084
  };
17745
18085
  const _RpgPlayer = class extends common.RpgCommonPlayer {
17746
- constructor(gameEngine, playerId) {
17747
- super(gameEngine, playerId);
18086
+ constructor(playerId) {
18087
+ super(inject(common.RpgCommonGame), playerId);
18088
+ this.playerId = playerId;
17748
18089
  this.type = "player";
17749
18090
  this.layout = {
17750
18091
  top: layoutObject,
@@ -17760,8 +18101,9 @@
17760
18101
  this.touchSide = false;
17761
18102
  this.tmpPositions = null;
17762
18103
  this.otherPossessedPlayer = null;
17763
- this.following = null;
18104
+ this.followingId = null;
17764
18105
  this._dataLoading = false;
18106
+ this.gameEngine = inject(common.RpgCommonGame);
17765
18107
  this.teleported = 0;
17766
18108
  this.deleted = false;
17767
18109
  this.initialize();
@@ -17776,6 +18118,7 @@
17776
18118
  }
17777
18119
  /** @internal */
17778
18120
  initialize() {
18121
+ this.server = inject(RpgServerEngine);
17779
18122
  this.expCurve = {
17780
18123
  basis: 30,
17781
18124
  extra: 20,
@@ -18128,7 +18471,7 @@
18128
18471
  toJSON() {
18129
18472
  const {
18130
18473
  permanentObject
18131
- } = Room.toDict(this.schema);
18474
+ } = Room.compileSchema(this.schema);
18132
18475
  const snapshot = Room.extractObjectOfRoom(this, permanentObject);
18133
18476
  snapshot.variables = [...this.variables];
18134
18477
  return snapshot;
@@ -18293,9 +18636,9 @@
18293
18636
  */
18294
18637
  cameraFollow(otherPlayer, options2 = {}) {
18295
18638
  if (otherPlayer.id == this.id) {
18296
- this.following = null;
18639
+ this.followingId = null;
18297
18640
  } else {
18298
- this.following = otherPlayer;
18641
+ this.followingId = otherPlayer.id;
18299
18642
  }
18300
18643
  this.emit(SocketEvents.CallMethod, {
18301
18644
  objectId: this.playerId,
@@ -18479,8 +18822,8 @@
18479
18822
  };
18480
18823
  applyMixins(RpgPlayer, [EventManager, ItemManager, GoldManager, StateManager, SkillManager, ParameterManager, EffectManager, ClassManager, ElementManager, GuiManager, VariableManager, MoveManager, BattleManager, ComponentManager]);
18481
18824
  class RpgEvent extends RpgPlayer {
18482
- constructor(gameEngine, playerId) {
18483
- super(gameEngine, playerId);
18825
+ constructor(playerId) {
18826
+ super(playerId);
18484
18827
  this.type = "event";
18485
18828
  this.properties = {};
18486
18829
  this.playerRelated = null;
@@ -18633,6 +18976,20 @@
18633
18976
  get nbPlayers() {
18634
18977
  return Object.keys(this.players).length;
18635
18978
  }
18979
+ $additionalEmitProperties(player) {
18980
+ const lastFramePositions = player["_lastFramePositions"];
18981
+ let pos;
18982
+ let lastFrame;
18983
+ if (lastFramePositions) {
18984
+ pos = lastFramePositions.position;
18985
+ lastFrame = lastFramePositions.frame;
18986
+ }
18987
+ const data = {
18988
+ frame: lastFrame,
18989
+ pos
18990
+ };
18991
+ return data;
18992
+ }
18636
18993
  async load() {
18637
18994
  var _a;
18638
18995
  if (common.RpgCommonMap.buffer.has(this.id)) {
@@ -18917,7 +19274,6 @@
18917
19274
  const ev = this.game.addEvent(event);
18918
19275
  const _shape = shape || this.getEventShape(ev.name);
18919
19276
  ev.map = this.id;
18920
- ev.server = this._server;
18921
19277
  ev.width = event.width || this.tileWidth;
18922
19278
  ev.height = event.height || this.tileHeight;
18923
19279
  if (_shape && _shape.properties)
@@ -19019,11 +19375,11 @@
19019
19375
  return result;
19020
19376
  };
19021
19377
  class SceneMap {
19022
- constructor(sceneMapObject, server) {
19023
- this.server = server;
19378
+ constructor(sceneMapObject) {
19024
19379
  this.maps = [];
19025
19380
  this.mapsById = {};
19026
19381
  this.worldMaps = /* @__PURE__ */ new Map();
19382
+ this.server = inject(RpgServerEngine);
19027
19383
  const {
19028
19384
  maps,
19029
19385
  worldMaps,
@@ -19230,7 +19586,9 @@
19230
19586
  await player.teleport(positions || "start");
19231
19587
  return null;
19232
19588
  }
19233
- player.emit("preLoadScene", mapId);
19589
+ player.emit("preLoadScene", {
19590
+ id: mapId
19591
+ });
19234
19592
  player.prevMap = player.map;
19235
19593
  if (player.prevMap) {
19236
19594
  await player.execMethod("onLeaveMap", [player.getCurrentMap()]);
@@ -19441,16 +19799,7 @@
19441
19799
  return result;
19442
19800
  };
19443
19801
  class RpgServerEngine {
19444
- /**
19445
- * Combat formulas
19446
- *
19447
- * @prop {Socket Io Server} [io]
19448
- * @memberof RpgServerEngine
19449
- */
19450
- constructor(io, gameEngine, inputOptions) {
19451
- this.io = io;
19452
- this.gameEngine = gameEngine;
19453
- this.inputOptions = inputOptions;
19802
+ constructor() {
19454
19803
  this.database = {};
19455
19804
  this.globalConfig = {};
19456
19805
  this.damageFormulas = {};
@@ -19458,8 +19807,20 @@
19458
19807
  this.scenes = /* @__PURE__ */ new Map();
19459
19808
  this.totalConnected = 0;
19460
19809
  this.scheduler = new common.Scheduler();
19810
+ this.gameEngine = inject(common.RpgCommonGame);
19461
19811
  this.world = World;
19462
19812
  this.envs = {};
19813
+ this.inputOptions = {};
19814
+ }
19815
+ /**
19816
+ * Combat formulas
19817
+ *
19818
+ * @prop {Socket Io Server} [io]
19819
+ * @memberof RpgServerEngine
19820
+ */
19821
+ initialize(io, inputOptions) {
19822
+ this.io = io;
19823
+ this.inputOptions = inputOptions;
19463
19824
  this.envs = inputOptions.envs || {};
19464
19825
  if (this.inputOptions.workers) {
19465
19826
  console.log("workers enabled");
@@ -19633,9 +19994,27 @@
19633
19994
  return Query._getShapesOfMap(map);
19634
19995
  }
19635
19996
  });
19636
- this.io.on("connection", this.onPlayerConnected.bind(this));
19997
+ this.transport(this.io);
19637
19998
  await common.RpgPlugin.emit(common.HookServer.Start, this);
19638
19999
  }
20000
+ transport(io) {
20001
+ const timeoutDisconnect = this.globalConfig.timeoutDisconnect ?? 0;
20002
+ const auth = this.globalConfig.disableAuth ? () => common.Utils.generateUID() : async (socket) => {
20003
+ const val = await common.RpgPlugin.emit(common.HookServer.Auth, [this, socket], true);
20004
+ if (val.length == 0) {
20005
+ return common.Utils.generateUID();
20006
+ }
20007
+ return val[val.length - 1];
20008
+ };
20009
+ const transport = new Transport(io, {
20010
+ timeoutDisconnect,
20011
+ auth
20012
+ });
20013
+ this.world.timeoutDisconnect = timeoutDisconnect;
20014
+ transport.onConnected(this.onPlayerConnected.bind(this));
20015
+ transport.onDisconnected(this.onPlayerDisconnected.bind(this));
20016
+ return transport;
20017
+ }
19639
20018
  get tick() {
19640
20019
  return this.scheduler.tick;
19641
20020
  }
@@ -19648,7 +20027,7 @@
19648
20027
  * @memberof RpgServerEngine
19649
20028
  */
19650
20029
  send() {
19651
- this.world.send();
20030
+ return this.world.send();
19652
20031
  }
19653
20032
  async updatePlayersMove(deltaTimeInt) {
19654
20033
  const players = this.world.getUsers();
@@ -19660,7 +20039,6 @@
19660
20039
  continue;
19661
20040
  const player = playerInstance.otherPossessedPlayer ?? playerInstance;
19662
20041
  if (player.pendingMove.length > 0) {
19663
- player.moving = true;
19664
20042
  const lastFrame = player.pendingMove[player.pendingMove.length - 1];
19665
20043
  if (this.inputOptions.workers)
19666
20044
  obj.push(player.toObject());
@@ -19712,7 +20090,7 @@
19712
20090
  maps: this.inputOptions.maps,
19713
20091
  events: this.inputOptions.events,
19714
20092
  worldMaps: this.inputOptions.worldMaps
19715
- }, this));
20093
+ }));
19716
20094
  }
19717
20095
  getScene(name) {
19718
20096
  return this.scenes.get(name);
@@ -19736,13 +20114,52 @@
19736
20114
  sendToPlayer(currentPlayer, eventName, data) {
19737
20115
  currentPlayer._socket.emit(eventName, data);
19738
20116
  }
19739
- onPlayerConnected(socket) {
19740
- const {
19741
- token
19742
- } = socket.handshake.auth;
19743
- const playerId = common.Utils.generateUID();
19744
- const player = new RpgPlayer(this.gameEngine, playerId);
19745
- player.session = token;
20117
+ getPlayerBySession(session) {
20118
+ const users = this.world.getUsers();
20119
+ for (let userId in users) {
20120
+ const user = users[userId];
20121
+ if (user.session === session) {
20122
+ return user;
20123
+ }
20124
+ }
20125
+ return null;
20126
+ }
20127
+ onPlayerConnected(socket, playerId) {
20128
+ const existingUser = this.world.getUser(playerId, false);
20129
+ this.world.connectUser(socket, playerId);
20130
+ let player;
20131
+ if (!existingUser) {
20132
+ const {
20133
+ token
20134
+ } = socket.handshake.auth;
20135
+ player = new RpgPlayer(playerId);
20136
+ player.session = token;
20137
+ this.world.setUser(player, socket);
20138
+ player._init();
20139
+ if (!token) {
20140
+ const newToken = common.Utils.generateUID() + "-" + common.Utils.generateUID() + "-" + common.Utils.generateUID();
20141
+ player.session = newToken;
20142
+ }
20143
+ if (!token) {
20144
+ player.execMethod("onConnected");
20145
+ } else {
20146
+ common.RpgPlugin.emit(common.HookServer.ScalabilityPlayerConnected, player);
20147
+ }
20148
+ } else {
20149
+ player = existingUser;
20150
+ if (player.map) {
20151
+ player.emit("preLoadScene", {
20152
+ reconnect: true,
20153
+ id: player.map
20154
+ });
20155
+ player.emitSceneMap();
20156
+ this.world.joinRoom(player.map, playerId);
20157
+ }
20158
+ }
20159
+ socket.emit("playerJoined", {
20160
+ playerId,
20161
+ session: player.session
20162
+ });
19746
20163
  socket.on("move", (data) => {
19747
20164
  if (!(data == null ? void 0 : data.input))
19748
20165
  return;
@@ -19759,25 +20176,6 @@
19759
20176
  });
19760
20177
  }
19761
20178
  });
19762
- socket.on("disconnect", () => {
19763
- this.onPlayerDisconnected(playerId);
19764
- });
19765
- this.world.setUser(player, socket);
19766
- player.server = this;
19767
- player._init();
19768
- if (!token) {
19769
- const newToken = common.Utils.generateUID() + "-" + common.Utils.generateUID() + "-" + common.Utils.generateUID();
19770
- player.session = newToken;
19771
- }
19772
- socket.emit("playerJoined", {
19773
- playerId,
19774
- session: player.session
19775
- });
19776
- if (!token) {
19777
- player.execMethod("onConnected");
19778
- } else {
19779
- common.RpgPlugin.emit(common.HookServer.ScalabilityPlayerConnected, player);
19780
- }
19781
20179
  }
19782
20180
  onPlayerDisconnected(playerId) {
19783
20181
  const player = World.getUser(playerId);
@@ -21788,7 +22186,7 @@
21788
22186
  this.callback = options2.callback;
21789
22187
  }
21790
22188
  async getServer(player) {
21791
- const currentServerId = player.server.serverId;
22189
+ const currentServerId = inject(RpgServerEngine).serverId;
21792
22190
  const payload = {
21793
22191
  playerId: player.id,
21794
22192
  mapName: player.map
@@ -21817,7 +22215,9 @@
21817
22215
  }
21818
22216
  }
21819
22217
  async function entryPoint(modules, options2) {
21820
- const gameEngine = new common.RpgCommonGame(common.GameSide.Server);
22218
+ const context = new common.InjectContext();
22219
+ setInject(context);
22220
+ inject(common.RpgCommonGame, [common.GameSide.Server]);
21821
22221
  if (!options2.globalConfig)
21822
22222
  options2.globalConfig = {};
21823
22223
  const relations = {
@@ -21835,7 +22235,8 @@
21835
22235
  };
21836
22236
  const relationsEngine = {
21837
22237
  onStart: common.HookServer.Start,
21838
- onStep: common.HookServer.Step
22238
+ onStep: common.HookServer.Step,
22239
+ auth: common.HookServer.Auth
21839
22240
  };
21840
22241
  const {
21841
22242
  playerProps
@@ -21873,7 +22274,7 @@
21873
22274
  }
21874
22275
  return mod;
21875
22276
  });
21876
- const serverEngine = new RpgServerEngine(options2.io, gameEngine, {
22277
+ const serverEngine = inject(RpgServerEngine, [options2.io, {
21877
22278
  debug: {},
21878
22279
  updateRate: 10,
21879
22280
  stepRate: 60,
@@ -21881,7 +22282,7 @@
21881
22282
  countConnections: false,
21882
22283
  playerProps,
21883
22284
  ...options2
21884
- });
22285
+ }]);
21885
22286
  return serverEngine;
21886
22287
  }
21887
22288
  function EventData(options2) {
@@ -21997,5 +22398,6 @@
21997
22398
  exports2.RpgWorldMaps = RpgWorldMaps;
21998
22399
  exports2.Speed = Speed;
21999
22400
  exports2.entryPoint = entryPoint;
22401
+ exports2.inject = inject;
22000
22402
  Object.defineProperty(exports2, Symbol.toStringTag, { value: "Module" });
22001
22403
  });