@rpgjs/server 4.1.2 → 4.2.0

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.
@@ -1,135 +1,6 @@
1
- import { Utils as Utils$1, EventEmitter as EventEmitter$1, Direction as Direction$1, LiteralDirection, PrebuiltGui, RpgCommonPlayer, RpgCommonMap, RpgPlugin, RpgCommonWorldMaps, HookServer, Scheduler, DefaultInput, RpgCommonGame, GameSide, loadModules } from "@rpgjs/common";
1
+ import { Utils as Utils$1, EventEmitter as EventEmitter$1, Direction as Direction$1, LiteralDirection, PrebuiltGui, RpgCommonPlayer, RpgCommonGame, RpgCommonMap, RpgPlugin, RpgCommonWorldMaps, HookServer, Scheduler, DefaultInput, InjectContext, GameSide, loadModules } from "@rpgjs/common";
2
2
  import { AbstractObject, Control, Direction, HookClient, HookServer as HookServer2, Input, RpgModule, RpgPlugin as RpgPlugin2, RpgShape, ShapePositioning } from "@rpgjs/common";
3
3
  import { Effect, ClassHooks, Actor, State, Class, Skill, Armor, Weapon, Item as Item$1 } from "@rpgjs/database";
4
- var commonjsGlobal = typeof globalThis !== "undefined" ? globalThis : typeof window !== "undefined" ? window : typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : {};
5
- function getAugmentedNamespace(n) {
6
- if (n.__esModule)
7
- return n;
8
- var f = n.default;
9
- if (typeof f == "function") {
10
- var a = function a2() {
11
- if (this instanceof a2) {
12
- var args = [null];
13
- args.push.apply(args, arguments);
14
- var Ctor = Function.bind.apply(f, args);
15
- return new Ctor();
16
- }
17
- return f.apply(this, arguments);
18
- };
19
- a.prototype = f.prototype;
20
- } else
21
- a = {};
22
- Object.defineProperty(a, "__esModule", {
23
- value: true
24
- });
25
- Object.keys(n).forEach(function(k) {
26
- var d = Object.getOwnPropertyDescriptor(n, k);
27
- Object.defineProperty(a, k, d.get ? d : {
28
- enumerable: true,
29
- get: function() {
30
- return n[k];
31
- }
32
- });
33
- });
34
- return a;
35
- }
36
- /*!
37
- * isobject <https://github.com/jonschlinkert/isobject>
38
- *
39
- * Copyright (c) 2014-2017, Jon Schlinkert.
40
- * Released under the MIT License.
41
- */
42
- var isobject = function isObject(val) {
43
- return val != null && typeof val === "object" && Array.isArray(val) === false;
44
- };
45
- /*!
46
- * get-value <https://github.com/jonschlinkert/get-value>
47
- *
48
- * Copyright (c) 2014-2018, Jon Schlinkert.
49
- * Released under the MIT License.
50
- */
51
- const isObject$3 = isobject;
52
- var getValue = function(target, path2, options2) {
53
- if (!isObject$3(options2)) {
54
- options2 = { default: options2 };
55
- }
56
- if (!isValidObject(target)) {
57
- return typeof options2.default !== "undefined" ? options2.default : target;
58
- }
59
- if (typeof path2 === "number") {
60
- path2 = String(path2);
61
- }
62
- const isArray2 = Array.isArray(path2);
63
- const isString2 = typeof path2 === "string";
64
- const splitChar = options2.separator || ".";
65
- const joinChar = options2.joinChar || (typeof splitChar === "string" ? splitChar : ".");
66
- if (!isString2 && !isArray2) {
67
- return target;
68
- }
69
- if (isString2 && path2 in target) {
70
- return isValid(path2, target, options2) ? target[path2] : options2.default;
71
- }
72
- let segs = isArray2 ? path2 : split(path2, splitChar, options2);
73
- let len = segs.length;
74
- let idx = 0;
75
- do {
76
- let prop = segs[idx];
77
- if (typeof prop === "number") {
78
- prop = String(prop);
79
- }
80
- while (prop && prop.slice(-1) === "\\") {
81
- prop = join$2([prop.slice(0, -1), segs[++idx] || ""], joinChar, options2);
82
- }
83
- if (prop in target) {
84
- if (!isValid(prop, target, options2)) {
85
- return options2.default;
86
- }
87
- target = target[prop];
88
- } else {
89
- let hasProp = false;
90
- let n = idx + 1;
91
- while (n < len) {
92
- prop = join$2([prop, segs[n++]], joinChar, options2);
93
- if (hasProp = prop in target) {
94
- if (!isValid(prop, target, options2)) {
95
- return options2.default;
96
- }
97
- target = target[prop];
98
- idx = n - 1;
99
- break;
100
- }
101
- }
102
- if (!hasProp) {
103
- return options2.default;
104
- }
105
- }
106
- } while (++idx < len && isValidObject(target));
107
- if (idx === len) {
108
- return target;
109
- }
110
- return options2.default;
111
- };
112
- function join$2(segs, joinChar, options2) {
113
- if (typeof options2.join === "function") {
114
- return options2.join(segs);
115
- }
116
- return segs[0] + joinChar + segs[1];
117
- }
118
- function split(path2, splitChar, options2) {
119
- if (typeof options2.split === "function") {
120
- return options2.split(path2);
121
- }
122
- return path2.split(splitChar);
123
- }
124
- function isValid(key, target, options2) {
125
- if (typeof options2.isValid === "function") {
126
- return options2.isValid(key, target);
127
- }
128
- return true;
129
- }
130
- function isValidObject(val) {
131
- return isObject$3(val) || Array.isArray(val) || typeof val === "function";
132
- }
133
4
  const GENERIC_KEY_SCHEMA = "@";
134
5
  class Utils {
135
6
  static isObject(val) {
@@ -160,25 +31,90 @@ class Utils {
160
31
  };
161
32
  return paths(obj);
162
33
  }
163
- static generateId() {
164
- return "$" + (Date.now().toString(36) + Math.random().toString(36).substr(2, 5));
34
+ static generateId(n = 5) {
35
+ return Math.random().toString(36).substring(n);
36
+ }
37
+ static async resolveValue(value) {
38
+ if (value instanceof Promise) {
39
+ return await value;
40
+ }
41
+ return value;
165
42
  }
166
- // https://stackoverflow.com/questions/54733539/javascript-implementation-of-lodash-set-method
167
43
  static set(obj, path2, value, onlyPlainObject = false) {
168
44
  if (Object(obj) !== obj)
169
45
  return obj;
170
- if (!Array.isArray(path2))
171
- path2 = path2.toString().match(/[^.[\]]+/g) || [];
172
- path2.slice(0, -1).reduce(
173
- (a, c2, i) => (
174
- // Iterate all of them except the last one
175
- Object(a[c2]) === a[c2] ? a[c2] : a[c2] = Math.abs(path2[i + 1]) >> 0 === +path2[i + 1] ? onlyPlainObject ? {} : [] : {}
176
- ),
177
- // No: assign a new plain object
178
- obj
179
- )[path2[path2.length - 1]] = value;
46
+ if (typeof path2 === "string") {
47
+ path2 = path2.split(".");
48
+ }
49
+ let len = path2.length;
50
+ if (!len)
51
+ return obj;
52
+ let current = obj;
53
+ for (let i = 0; i < len - 1; i++) {
54
+ let segment = path2[i];
55
+ let nextSegment = path2[i + 1];
56
+ let isNextNumeric = !isNaN(nextSegment) && isFinite(nextSegment);
57
+ if (!current[segment] || typeof current[segment] !== "object") {
58
+ current[segment] = isNextNumeric && !onlyPlainObject ? [] : {};
59
+ }
60
+ current = current[segment];
61
+ }
62
+ current[path2[len - 1]] = value;
180
63
  return obj;
181
64
  }
65
+ static get(obj, path2) {
66
+ const keys2 = path2.split(".");
67
+ let current = obj;
68
+ for (let key of keys2) {
69
+ if (current[key] === void 0) {
70
+ return void 0;
71
+ }
72
+ current = current[key];
73
+ }
74
+ return current;
75
+ }
76
+ static bufferFrom(input) {
77
+ if (typeof input === "string") {
78
+ let encoder2 = new TextEncoder();
79
+ return encoder2.encode(input);
80
+ } else if (input instanceof ArrayBuffer || ArrayBuffer.isView(input)) {
81
+ return new Uint8Array(input);
82
+ } else {
83
+ throw new Error("Input type not supported");
84
+ }
85
+ }
86
+ }
87
+ var commonjsGlobal = typeof globalThis !== "undefined" ? globalThis : typeof window !== "undefined" ? window : typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : {};
88
+ function getAugmentedNamespace(n) {
89
+ if (n.__esModule)
90
+ return n;
91
+ var f = n.default;
92
+ if (typeof f == "function") {
93
+ var a = function a2() {
94
+ if (this instanceof a2) {
95
+ var args = [null];
96
+ args.push.apply(args, arguments);
97
+ var Ctor = Function.bind.apply(f, args);
98
+ return new Ctor();
99
+ }
100
+ return f.apply(this, arguments);
101
+ };
102
+ a.prototype = f.prototype;
103
+ } else
104
+ a = {};
105
+ Object.defineProperty(a, "__esModule", {
106
+ value: true
107
+ });
108
+ Object.keys(n).forEach(function(k) {
109
+ var d = Object.getOwnPropertyDescriptor(n, k);
110
+ Object.defineProperty(a, k, d.get ? d : {
111
+ enumerable: true,
112
+ get: function() {
113
+ return n[k];
114
+ }
115
+ });
116
+ });
117
+ return a;
182
118
  }
183
119
  var browser$2 = {};
184
120
  var encode$4 = {};
@@ -3754,16 +3690,17 @@ class Packet {
3754
3690
  get body() {
3755
3691
  return this.data;
3756
3692
  }
3757
- message(otherData = {}) {
3758
- return [this.roomId, Date.now(), { ...this.data, ...otherData }];
3693
+ message(otherData) {
3694
+ return [this.roomId, Date.now(), otherData ?? this.data];
3759
3695
  }
3760
3696
  clone(data) {
3761
3697
  return new Packet(data, this.roomId);
3762
3698
  }
3763
- encode(otherData = {}) {
3699
+ encode(otherData) {
3764
3700
  return browser$2.encode(this.message(otherData));
3765
3701
  }
3766
3702
  }
3703
+ const { get: get$1, set: set$1 } = Utils;
3767
3704
  class TransmitterClass {
3768
3705
  constructor() {
3769
3706
  this.encode = true;
@@ -3794,104 +3731,183 @@ class TransmitterClass {
3794
3731
  this.packets = {};
3795
3732
  }
3796
3733
  }
3797
- emit(user, packet, room) {
3798
- const send = (packet2) => {
3799
- const lastFramePositions = user["_lastFramePositions"];
3800
- let pos;
3801
- let lastFrame;
3802
- if (lastFramePositions) {
3803
- pos = lastFramePositions.position;
3804
- lastFrame = lastFramePositions.frame;
3805
- }
3806
- const data = { frame: lastFrame, pos };
3807
- user._socket.emit("w", this.encode ? packet2.encode(data) : packet2.message(data));
3808
- };
3809
- if (room.filterEmit) {
3810
- const objectPacket = room.filterEmit(user, packet);
3811
- const promiseObjectPacket = objectPacket;
3812
- if (promiseObjectPacket.then) {
3813
- promiseObjectPacket.then(send);
3814
- } else {
3815
- send(objectPacket);
3734
+ error(user, error) {
3735
+ const err = error instanceof Error ? error.toObject ? error.toObject() : error.message : error;
3736
+ user._socket.emit("error", err);
3737
+ }
3738
+ async emit(user, packet, room) {
3739
+ let data = packet.body;
3740
+ if (room.$additionalEmitProperties) {
3741
+ let additionalData = await Utils.resolveValue(room.$additionalEmitProperties(user, packet.body));
3742
+ if (additionalData !== void 0) {
3743
+ if (typeof additionalData === "string") {
3744
+ additionalData = [additionalData];
3745
+ }
3746
+ if (Array.isArray(additionalData)) {
3747
+ const newData = structuredClone(data);
3748
+ for (let path2 of additionalData) {
3749
+ set$1(newData, path2, get$1(room, path2));
3750
+ }
3751
+ data = newData;
3752
+ } else {
3753
+ data = { ...data, ...additionalData };
3754
+ }
3816
3755
  }
3817
- return;
3818
3756
  }
3819
- send(packet);
3757
+ user._socket.emit("w", this.encode ? packet.encode(data) : packet.message(data));
3820
3758
  }
3821
3759
  }
3822
3760
  const Transmitter = new TransmitterClass();
3823
- const { set } = Utils;
3824
- class Room {
3761
+ var UserState;
3762
+ (function(UserState2) {
3763
+ UserState2["Connected"] = "C";
3764
+ UserState2["Disconnected"] = "D";
3765
+ })(UserState || (UserState = {}));
3766
+ class User {
3825
3767
  constructor() {
3826
- this.memoryTotalObject = {};
3827
- this.memoryObject = {};
3828
- this.permanentObject = [];
3768
+ this.$state = UserState.Connected;
3769
+ this._secretSessionId = "";
3770
+ this._rooms = [];
3771
+ }
3772
+ }
3773
+ User.schema = {
3774
+ $state: String
3775
+ };
3776
+ class CustomError extends Error {
3777
+ constructor(customMessage) {
3778
+ super(customMessage);
3779
+ this.customMessage = customMessage;
3780
+ this.status = 500;
3781
+ this.code = "INTERNAL_SERVER_ERROR";
3782
+ this.message = "Internal Server error";
3783
+ }
3784
+ toObject() {
3785
+ return {
3786
+ message: this.customMessage || this.message,
3787
+ status: this.status,
3788
+ code: this.code
3789
+ };
3790
+ }
3791
+ }
3792
+ class NotAuthorized extends CustomError {
3793
+ constructor(customMessage) {
3794
+ super(customMessage);
3795
+ this.status = 401;
3796
+ this.code = "NOT_AUTHORIZED";
3797
+ this.message = "Not authorized";
3829
3798
  }
3799
+ }
3800
+ const { set, get } = Utils;
3801
+ class Room {
3830
3802
  static hasExtraProp(obj) {
3831
- return obj.$default !== void 0 || obj.$syncWithClient !== void 0 || obj.$permanent !== void 0 || obj.$validate !== void 0 || obj.$effects !== void 0;
3803
+ 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;
3832
3804
  }
3833
- static toDict(schema, room) {
3805
+ static compileSchema(schema, room) {
3834
3806
  const dict = {};
3807
+ const masks = {};
3835
3808
  const permanentObject = [];
3836
- function toDict(obj, path2 = "") {
3837
- for (let prop in obj) {
3838
- const val = obj[prop];
3809
+ function specialObject(val, p) {
3810
+ if (Room.hasExtraProp(val)) {
3811
+ if (val.$permanent ?? true)
3812
+ permanentObject.push(p);
3813
+ if (room && val.$default !== void 0)
3814
+ ;
3815
+ if (val.$syncWithClient === false) {
3816
+ return;
3817
+ }
3818
+ dict[p] = {
3819
+ ...val
3820
+ };
3821
+ } else {
3822
+ dict[p] = val;
3823
+ masks[p] = Utils.propertiesToArray(val);
3824
+ compile(val, p);
3825
+ }
3826
+ }
3827
+ function compile(schema2, path2 = "") {
3828
+ for (let prop in schema2) {
3829
+ const val = schema2[prop];
3839
3830
  let p = (path2 ? path2 + "." : "") + prop;
3840
3831
  if (Array.isArray(val)) {
3841
3832
  dict[p] = GENERIC_KEY_SCHEMA;
3842
3833
  p += "." + GENERIC_KEY_SCHEMA;
3843
- dict[p] = val[0];
3844
- toDict(val[0], p);
3845
- } else if (Utils.isObject(val)) {
3846
- if (Room.hasExtraProp(val)) {
3847
- if (val.$permanent ?? true)
3848
- permanentObject.push(p);
3849
- if (room && val.$default !== void 0)
3850
- ;
3851
- if (val.$syncWithClient === false) {
3852
- continue;
3853
- }
3854
- dict[p] = {
3855
- ...val
3856
- };
3834
+ if (val[0] === void 0)
3835
+ val[0] = {};
3836
+ if (Utils.isObject(val[0])) {
3837
+ specialObject(val[0], p);
3857
3838
  } else {
3858
- dict[p] = val;
3859
- toDict(val, p);
3839
+ dict[p] = val[0];
3840
+ compile(val[0], p);
3860
3841
  }
3842
+ } else if (Utils.isObject(val)) {
3843
+ specialObject(val, p);
3861
3844
  } else {
3862
3845
  permanentObject.push(p);
3863
3846
  dict[p] = val;
3864
3847
  }
3865
3848
  }
3866
3849
  }
3867
- toDict(schema);
3850
+ compile(schema);
3868
3851
  return {
3852
+ masks,
3869
3853
  dict,
3870
3854
  permanentObject
3871
3855
  };
3872
3856
  }
3873
- join(user, room) {
3874
- if (!user._rooms)
3875
- user._rooms = [];
3876
- user._rooms.push(room.id);
3877
- if (!user.id)
3878
- user.id = Utils.generateId();
3879
- if (room["onJoin"])
3880
- room["onJoin"](user);
3857
+ constructor(options2) {
3858
+ this.options = options2;
3859
+ this.memoryTotalObject = {};
3860
+ this.memoryObject = {};
3861
+ this.permanentObject = [];
3862
+ this.propagateOldRoom = true;
3863
+ if (options2.propagateOldRoom) {
3864
+ this.propagateOldRoom = options2.propagateOldRoom;
3865
+ }
3866
+ }
3867
+ async join(user, room) {
3868
+ if (room["canJoin"]) {
3869
+ const authBool = await Utils.resolveValue(room["canJoin"](user, user._socket));
3870
+ if (authBool === false || typeof authBool == "string") {
3871
+ Transmitter.error(user, new NotAuthorized(authBool));
3872
+ return false;
3873
+ }
3874
+ }
3875
+ if (World.agonesSDK) {
3876
+ await World.agonesSDK.allocate();
3877
+ }
3878
+ let firstJoin = !room.users[user.id];
3879
+ room.users[user.id] = user;
3880
+ const userProxy = World.users[user.id]["proxy"];
3881
+ userProxy.$state = UserState.Connected;
3882
+ if (firstJoin) {
3883
+ if (room["onJoin"])
3884
+ await Utils.resolveValue(room["onJoin"](userProxy));
3885
+ }
3881
3886
  if (this.getUsersLength(room) == 1) {
3882
3887
  this.memoryTotalObject = Room.extractObjectOfRoom(room, room.$schema);
3883
3888
  }
3884
3889
  const packet = new Packet({
3885
3890
  ...this.memoryTotalObject,
3886
- join: true
3891
+ join: firstJoin
3887
3892
  }, room.id);
3888
- Transmitter.emit(user, packet, room);
3893
+ await Transmitter.emit(userProxy, packet, room);
3894
+ return true;
3889
3895
  }
3890
- leave(user, room) {
3891
- const index2 = user._rooms.findIndex((id) => room.id == id);
3892
- user._rooms.splice(index2, 1);
3896
+ async leave(user, room) {
3893
3897
  if (room["onLeave"])
3894
3898
  room["onLeave"](user);
3899
+ const index2 = user._rooms.findIndex((id) => room.id == id);
3900
+ user._rooms.splice(index2, 1);
3901
+ delete room.users[user.id];
3902
+ delete World.users[user.id]["proxy"];
3903
+ if (World.nbUsers == 0 && World.agonesSDK) {
3904
+ const { onBeforeShutdown, shutdownIfNotPlayers } = World.agonesOptions;
3905
+ if (shutdownIfNotPlayers) {
3906
+ if (onBeforeShutdown)
3907
+ await onBeforeShutdown();
3908
+ await World.agonesSDK.shutdown();
3909
+ }
3910
+ }
3895
3911
  }
3896
3912
  getUsersLength(room) {
3897
3913
  return Object.keys(room.users).length;
@@ -3914,7 +3930,8 @@ class Room {
3914
3930
  }
3915
3931
  setProxy(room) {
3916
3932
  const self2 = this;
3917
- const { dict, permanentObject } = Room.toDict(room.$schema, room);
3933
+ const { dict, permanentObject, masks } = Room.compileSchema(room.$schema, room);
3934
+ const proxifiedObjects = /* @__PURE__ */ new WeakSet();
3918
3935
  this.permanentObject = permanentObject;
3919
3936
  room.$dict = dict;
3920
3937
  const getInfoDict = (path2, key, dictPath) => {
@@ -3924,19 +3941,31 @@ class Room {
3924
3941
  return {
3925
3942
  fullPath: p,
3926
3943
  genericPath,
3927
- infoDict: dict[genericPath]
3944
+ infoDict: dict[genericPath],
3945
+ mask: masks[genericPath]
3928
3946
  };
3929
3947
  };
3930
3948
  function deepProxy(object, path2 = "", dictPath = "") {
3949
+ if (proxifiedObjects.has(object)) {
3950
+ return object;
3951
+ }
3931
3952
  return new Proxy(object, {
3932
3953
  set(target, key, val, receiver) {
3933
- const { fullPath: p, infoDict, genericPath } = getInfoDict(path2, key, dictPath);
3954
+ const { fullPath: p, infoDict, genericPath, mask } = getInfoDict(path2, key, dictPath);
3934
3955
  if (typeof val == "object" && infoDict && val != null) {
3935
3956
  const valProxy = deepProxy(val, p, genericPath);
3957
+ proxifiedObjects.add(valProxy);
3936
3958
  if (path2 == "users") {
3959
+ if (!room.users[key]) {
3960
+ if (!valProxy._rooms)
3961
+ valProxy._rooms = [];
3962
+ valProxy._rooms.push(room.id);
3963
+ if (!valProxy.id)
3964
+ valProxy.id = Utils.generateId();
3965
+ }
3937
3966
  World.users[key]["proxy"] = valProxy;
3938
3967
  }
3939
- Reflect.set(target, key, valProxy, receiver);
3968
+ Reflect.set(target, key, val, receiver);
3940
3969
  val = target[key];
3941
3970
  } else {
3942
3971
  if (infoDict == null ? void 0 : infoDict.$validate) {
@@ -3970,7 +3999,7 @@ class Room {
3970
3999
  }
3971
4000
  let newObj;
3972
4001
  if (Utils.isObject(infoDict) && val != null && !Room.hasExtraProp(infoDict)) {
3973
- newObj = Room.extractObjectOfRoom(val, infoDict);
4002
+ newObj = Room.extractObjectOfRoom(val, mask);
3974
4003
  } else if (infoDict == GENERIC_KEY_SCHEMA) {
3975
4004
  newObj = {};
3976
4005
  if (Object.keys(val).length == 0) {
@@ -4002,6 +4031,7 @@ class Room {
4002
4031
  const { fullPath: p, infoDict, genericPath } = getInfoDict(path3, key, dictPath);
4003
4032
  if (typeof val2 == "object" && infoDict) {
4004
4033
  val2 = deepProxy(val2, p, genericPath);
4034
+ proxifiedObjects.add(val2);
4005
4035
  }
4006
4036
  return val2;
4007
4037
  };
@@ -4026,7 +4056,7 @@ class Room {
4026
4056
  if (!room.$schema)
4027
4057
  room.$schema = {};
4028
4058
  if (!room.$schema.users)
4029
- room.$schema.users = [{ id: String }];
4059
+ room.$schema.users = [User.schema];
4030
4060
  if (!room.$inputs)
4031
4061
  room.$inputs = {};
4032
4062
  if (!room.users)
@@ -4052,16 +4082,20 @@ class Room {
4052
4082
  room.$snapshotUser = (userId) => {
4053
4083
  return this.snapshotUser(room, userId);
4054
4084
  };
4055
- room.$join = (user) => {
4085
+ room.$join = async (user) => {
4086
+ if (typeof user == "string") {
4087
+ user = World.users[user];
4088
+ }
4056
4089
  if (user) {
4057
- room.users[user.id] = user;
4058
- this.join(room.users[user.id], room);
4090
+ return this.join(user, room);
4059
4091
  }
4092
+ return false;
4060
4093
  };
4061
- room.$leave = (user) => {
4062
- this.leave(user, room);
4063
- delete room.users[user.id];
4064
- delete World.users[user.id]["proxy"];
4094
+ room.$leave = async (user) => {
4095
+ if (typeof user == "string") {
4096
+ user = World.users[user]["proxy"];
4097
+ }
4098
+ await this.leave(user, room);
4065
4099
  };
4066
4100
  room.$currentState = () => this.memoryObject;
4067
4101
  room.$setCurrentState = (path2, value) => {
@@ -4070,6 +4104,7 @@ class Room {
4070
4104
  room.$clearCurrentState = () => {
4071
4105
  this.memoryObject = {};
4072
4106
  };
4107
+ room.$parent = this;
4073
4108
  this.proxyRoom = room = this.setProxy(room);
4074
4109
  if (this.proxyRoom["onInit"])
4075
4110
  this.proxyRoom["onInit"]();
@@ -4077,52 +4112,59 @@ class Room {
4077
4112
  }
4078
4113
  static extractObjectOfRoom(room, schema) {
4079
4114
  const newObj = {};
4080
- const schemas = [];
4081
4115
  const _schema = Array.isArray(schema) ? schema : Utils.propertiesToArray(schema);
4082
- function extract(path2) {
4083
- const match = new RegExp("^(.*?)\\.\\" + GENERIC_KEY_SCHEMA).exec(path2);
4116
+ const regex = new RegExp("^(.*?)\\.\\" + GENERIC_KEY_SCHEMA);
4117
+ function extractAndSet(obj, path2) {
4118
+ if (path2.endsWith("@")) {
4119
+ return;
4120
+ }
4121
+ const match = regex.exec(path2);
4084
4122
  if (match) {
4085
- const generic = getValue(room, match[1]);
4086
- if (generic) {
4087
- const keys2 = Object.keys(generic);
4088
- for (let key of keys2) {
4089
- extract(path2.replace(GENERIC_KEY_SCHEMA, key));
4123
+ const generic = get(room, match[1]);
4124
+ if (generic && typeof generic === "object") {
4125
+ for (let key in generic) {
4126
+ if (generic.hasOwnProperty(key)) {
4127
+ extractAndSet(obj, path2.replace(GENERIC_KEY_SCHEMA, key));
4128
+ }
4090
4129
  }
4091
4130
  }
4092
4131
  } else {
4093
- schemas.push(path2);
4132
+ set(obj, path2, get(room, path2));
4094
4133
  }
4095
4134
  }
4096
4135
  for (let path2 of _schema) {
4097
- extract(path2);
4098
- }
4099
- for (let sheme of schemas) {
4100
- set(newObj, sheme, getValue(room, sheme));
4136
+ extractAndSet(newObj, path2);
4101
4137
  }
4102
4138
  return newObj;
4103
4139
  }
4104
4140
  detectChanges(room, obj, path2) {
4141
+ const change = (room2) => {
4142
+ const roomInstance = room2.$parent;
4143
+ roomInstance.editMemoryObject(path2, obj);
4144
+ set(roomInstance.memoryTotalObject, path2, obj);
4145
+ if (roomInstance.proxyRoom["onChanges"])
4146
+ roomInstance.proxyRoom["onChanges"](roomInstance.memoryObject);
4147
+ const id = room2.id;
4148
+ World.changes.next({
4149
+ ...World.changes.value,
4150
+ [id]: room2
4151
+ });
4152
+ };
4105
4153
  if (obj != null) {
4106
4154
  const [prop, userId] = path2.split(".");
4107
4155
  if (prop == "users") {
4108
- if (!room.users[userId]) {
4156
+ if (!this.propagateOldRoom && !room.users[userId]) {
4109
4157
  return;
4110
4158
  }
4159
+ World.forEachUserRooms(userId, change);
4160
+ return;
4111
4161
  }
4112
4162
  }
4113
- this.editMemoryObject(path2, obj);
4114
- set(this.memoryTotalObject, path2, obj);
4115
- if (this.proxyRoom["onChanges"])
4116
- this.proxyRoom["onChanges"](this.memoryObject);
4117
- const id = room.id;
4118
- World.changes.next({
4119
- ...World.changes.value,
4120
- [id]: room
4121
- });
4163
+ change(room);
4122
4164
  }
4123
4165
  editMemoryObject(path2, roomOrValue) {
4124
4166
  if (roomOrValue && typeof roomOrValue == "object" && "$currentState" in roomOrValue) {
4125
- set(this.memoryObject, path2, getValue(roomOrValue, path2), true);
4167
+ set(this.memoryObject, path2, get(roomOrValue, path2), true);
4126
4168
  } else {
4127
4169
  set(this.memoryObject, path2, roomOrValue, true);
4128
4170
  }
@@ -4146,28 +4188,6 @@ class TransportCommon {
4146
4188
  this.onDisconnectedCb = cb;
4147
4189
  }
4148
4190
  }
4149
- class Transport extends TransportCommon {
4150
- constructor(io) {
4151
- super();
4152
- this.io = io;
4153
- io.on("connection", (socket) => {
4154
- const id = socket.client.id;
4155
- this.onConnectedCb(socket, id);
4156
- socket.on(":input", ({ prop, value }) => this.onInputCb(id, prop, value));
4157
- socket.on(":action", ({ name, value }) => this.onActionCb(id, name, value));
4158
- socket.on(":join", (roomId) => this.onJoinCb(roomId, id));
4159
- socket.on("disconnect", () => this.onDisconnectedCb(id));
4160
- });
4161
- }
4162
- }
4163
- class User {
4164
- constructor() {
4165
- this._rooms = [];
4166
- }
4167
- }
4168
- User.schema = {
4169
- id: String
4170
- };
4171
4191
  var extendStatics = function(d, b) {
4172
4192
  extendStatics = Object.setPrototypeOf || { __proto__: [] } instanceof Array && function(d2, b2) {
4173
4193
  d2.__proto__ = b2;
@@ -5056,12 +5076,132 @@ var BehaviorSubject = function(_super) {
5056
5076
  };
5057
5077
  return BehaviorSubject2;
5058
5078
  }(Subject);
5079
+ class Transport extends TransportCommon {
5080
+ constructor(io, options2 = {}) {
5081
+ super();
5082
+ this.io = io;
5083
+ this.options = options2;
5084
+ this.bandwidthData = {};
5085
+ this.WINDOW_SECONDS = 10;
5086
+ io.on("connection", (socket) => {
5087
+ const id = socket.playerId;
5088
+ this.bandwidthData[id] = new BehaviorSubject({
5089
+ incoming: [],
5090
+ outgoing: []
5091
+ });
5092
+ this.handleConnection(socket, id);
5093
+ socket.on(":input", ({ prop, value }) => this.onInputCb(id, prop, value));
5094
+ socket.on(":action", ({ name, value }) => this.onActionCb(id, name, value));
5095
+ if (options2.clientCanJoinRoom)
5096
+ socket.on(":join", (roomId) => this.onJoinCb(roomId, id));
5097
+ socket.on("disconnect", () => {
5098
+ var _a;
5099
+ (_a = this.bandwidthData[id]) == null ? void 0 : _a.unsubscribe();
5100
+ delete this.bandwidthData[id];
5101
+ this.onDisconnectedCb(id);
5102
+ });
5103
+ });
5104
+ this.use();
5105
+ }
5106
+ handleConnection(socket, id) {
5107
+ this.onConnectedCb(socket, id);
5108
+ }
5109
+ use() {
5110
+ var _a, _b;
5111
+ const { maxKbpsIncoming, maxKbpsOutgoing, auth } = this.options;
5112
+ (_b = (_a = this.io).use) == null ? void 0 : _b.call(_a, async (socket, next) => {
5113
+ let playerId;
5114
+ if (auth) {
5115
+ try {
5116
+ playerId = await Utils.resolveValue(auth(socket));
5117
+ } catch (err) {
5118
+ socket.disconnect();
5119
+ next(new NotAuthorized(err).toObject());
5120
+ return;
5121
+ }
5122
+ }
5123
+ if (!playerId)
5124
+ playerId = Utils.generateId(5);
5125
+ socket.playerId = playerId;
5126
+ socket.use((packet, nextMiddleware) => {
5127
+ var _a2, _b2;
5128
+ if (packet && packet[1]) {
5129
+ const packetSize = Utils.bufferFrom(JSON.stringify(packet)).length - 2;
5130
+ const data = { size: packetSize, timestamp: Date.now() };
5131
+ this.updateBandwidthData(playerId, { incoming: data });
5132
+ const kbps = this.calculateKbps(((_a2 = this.bandwidthData[playerId]) == null ? void 0 : _a2.value.incoming) || []);
5133
+ if (maxKbpsIncoming && kbps > maxKbpsIncoming) {
5134
+ socket.disconnect();
5135
+ return;
5136
+ }
5137
+ this.cleanOldData(((_b2 = this.bandwidthData[playerId]) == null ? void 0 : _b2.value.incoming) || []);
5138
+ }
5139
+ nextMiddleware();
5140
+ });
5141
+ const originalEmit = socket.emit;
5142
+ socket.emit = (...args) => {
5143
+ var _a2, _b2;
5144
+ const packetSize = Utils.bufferFrom(JSON.stringify(args)).length - 2;
5145
+ const data = { size: packetSize, timestamp: Date.now() };
5146
+ this.updateBandwidthData(playerId, { outgoing: data });
5147
+ const kbps = this.calculateKbps(((_a2 = this.bandwidthData[playerId]) == null ? void 0 : _a2.value.outgoing) || []);
5148
+ if (maxKbpsOutgoing && kbps > maxKbpsOutgoing) {
5149
+ socket.disconnect();
5150
+ return;
5151
+ }
5152
+ this.cleanOldData(((_b2 = this.bandwidthData[playerId]) == null ? void 0 : _b2.value.outgoing) || []);
5153
+ originalEmit.apply(socket, args);
5154
+ };
5155
+ next();
5156
+ });
5157
+ }
5158
+ updateBandwidthData(socketId, data) {
5159
+ var _a, _b;
5160
+ const currentData = ((_a = this.bandwidthData[socketId]) == null ? void 0 : _a.value) || { incoming: [], outgoing: [] };
5161
+ if (data.incoming) {
5162
+ currentData.incoming.push(data.incoming);
5163
+ }
5164
+ if (data.outgoing) {
5165
+ currentData.outgoing.push(data.outgoing);
5166
+ }
5167
+ (_b = this.bandwidthData[socketId]) == null ? void 0 : _b.next(currentData);
5168
+ }
5169
+ cleanOldData(dataArray) {
5170
+ const cutOff = Date.now() - this.WINDOW_SECONDS * 1e3;
5171
+ while (dataArray.length > 0 && dataArray[0].timestamp < cutOff) {
5172
+ dataArray.shift();
5173
+ }
5174
+ }
5175
+ calculateKbps(dataArray) {
5176
+ const totalBytes = dataArray.reduce((acc, entry) => acc + entry.size, 0);
5177
+ return totalBytes * 8 / (this.WINDOW_SECONDS * 1e3);
5178
+ }
5179
+ getTelemetry() {
5180
+ const socketsData = {};
5181
+ let totalKbps = 0;
5182
+ for (const [socketId, bandwidth] of Object.entries(this.bandwidthData)) {
5183
+ const socketData = bandwidth.value;
5184
+ const incomingKbps = this.calculateKbps(socketData.incoming);
5185
+ const outgoingKbps = this.calculateKbps(socketData.outgoing);
5186
+ socketsData[socketId] = { incomingKbps, outgoingKbps };
5187
+ totalKbps += incomingKbps + outgoingKbps;
5188
+ }
5189
+ return {
5190
+ sockets: socketsData,
5191
+ totalKbps
5192
+ };
5193
+ }
5194
+ }
5059
5195
  class WorldClass {
5060
5196
  constructor() {
5061
5197
  this.rooms = /* @__PURE__ */ new Map();
5062
5198
  this.users = {};
5063
5199
  this.userClass = User;
5200
+ this.timeoutDisconnect = 0;
5064
5201
  this.changes = new BehaviorSubject({});
5202
+ this._transport = null;
5203
+ this.agonesSDK = null;
5204
+ this.agonesOptions = {};
5065
5205
  }
5066
5206
  /**
5067
5207
  * Define user class
@@ -5072,32 +5212,48 @@ class WorldClass {
5072
5212
  setUserClass(userClass) {
5073
5213
  this.userClass = userClass;
5074
5214
  }
5215
+ setAgones(agones, options2 = {}) {
5216
+ this.agonesSDK = agones;
5217
+ this.agonesOptions = options2;
5218
+ }
5075
5219
  /**
5076
5220
  * Define transportation. You can set socket.io as default
5077
5221
  *
5078
5222
  * @method transport()
5079
5223
  * @param {object} io
5080
- * @returns {void}
5224
+ * @returns {Transport}
5081
5225
  */
5082
- transport(io) {
5083
- const transport = new Transport(io);
5226
+ transport(io, options2 = {}) {
5227
+ if (options2.timeoutDisconnect) {
5228
+ this.timeoutDisconnect = options2.timeoutDisconnect;
5229
+ }
5230
+ const transport = new Transport(io, options2);
5084
5231
  transport.onConnected(this.connectUser.bind(this));
5085
5232
  transport.onDisconnected(this.disconnectUser.bind(this));
5086
5233
  transport.onJoin(this.joinRoom.bind(this));
5087
5234
  transport.onInput((id, prop, value) => {
5088
5235
  this.forEachUserRooms(id, (room, user) => {
5089
- if (room.$inputs && room.$inputs[prop]) {
5090
- room[prop] = value;
5236
+ try {
5237
+ if (room.$inputs && room.$inputs[prop]) {
5238
+ room[prop] = value;
5239
+ }
5240
+ } catch (err) {
5241
+ Transmitter.error(user, err);
5091
5242
  }
5092
5243
  });
5093
5244
  });
5094
5245
  transport.onAction((id, name, value) => {
5095
5246
  this.forEachUserRooms(id, async (room, user) => {
5096
5247
  if (room.$actions && room.$actions[name]) {
5097
- room[name](user, value);
5248
+ try {
5249
+ room[name](user, value);
5250
+ } catch (err) {
5251
+ Transmitter.error(user, err);
5252
+ }
5098
5253
  }
5099
5254
  });
5100
5255
  });
5256
+ return this._transport = transport;
5101
5257
  }
5102
5258
  /**
5103
5259
  * Loop over all rooms of a user
@@ -5116,7 +5272,7 @@ class WorldClass {
5116
5272
  * @returns {void}
5117
5273
  */
5118
5274
  forEachUserRooms(userId, cb) {
5119
- const user = this.getUser(userId);
5275
+ const user = this.getUser(userId, true);
5120
5276
  if (!user)
5121
5277
  return;
5122
5278
  for (let roomId of user._rooms) {
@@ -5155,29 +5311,32 @@ class WorldClass {
5155
5311
  this.users[user.id] = user;
5156
5312
  return this.users[user.id];
5157
5313
  }
5314
+ get nbUsers() {
5315
+ return Object.keys(this.users).length;
5316
+ }
5158
5317
  /**
5159
5318
  * Send the packages to the rooms.
5160
5319
  *
5161
5320
  * @method send()
5162
5321
  */
5163
- send() {
5164
- this.rooms.forEach((room, id) => {
5322
+ async send() {
5323
+ for (let [_, room] of this.rooms) {
5165
5324
  const obj = room.$currentState();
5166
5325
  if (Object.keys(obj).length == 0) {
5167
5326
  return;
5168
5327
  }
5169
5328
  Transmitter.addPacket(room, obj);
5170
- for (let id2 in room.users) {
5171
- const user = room.users[id2];
5329
+ for (let id in room.users) {
5330
+ const user = room.users[id];
5172
5331
  const packets = Transmitter.getPackets(room);
5173
5332
  if (packets) {
5174
5333
  for (let packet of packets) {
5175
- Transmitter.emit(user, packet, room);
5334
+ await Transmitter.emit(user, packet, room);
5176
5335
  }
5177
5336
  }
5178
5337
  }
5179
5338
  room.$clearCurrentState();
5180
- });
5339
+ }
5181
5340
  Transmitter.clear();
5182
5341
  }
5183
5342
  /**
@@ -5186,10 +5345,23 @@ class WorldClass {
5186
5345
  * @method connectUser()
5187
5346
  * @param {object} socket
5188
5347
  * @param {id} userId
5348
+ * @param {object} options
5349
+ * - getUserInstance: function that returns a new instance of the user
5189
5350
  * @returns {User}
5190
5351
  */
5191
- connectUser(socket, id) {
5192
- const user = new this.userClass();
5352
+ connectUser(socket, id, options2 = {}) {
5353
+ var _a;
5354
+ const existingUser = this.getUser(id, false);
5355
+ if (existingUser) {
5356
+ if (existingUser._timeoutDisconnect) {
5357
+ clearTimeout(existingUser._timeoutDisconnect);
5358
+ delete existingUser._timeoutDisconnect;
5359
+ }
5360
+ existingUser._socket = socket;
5361
+ existingUser.$state = UserState.Connected;
5362
+ return existingUser;
5363
+ }
5364
+ const user = ((_a = options2.getUserInstance) == null ? void 0 : _a.call(options2, socket)) ?? new this.userClass();
5193
5365
  user.id = id;
5194
5366
  socket.emit("uid", id);
5195
5367
  this.setUser(user, socket);
@@ -5203,18 +5375,52 @@ class WorldClass {
5203
5375
  * @returns {void}
5204
5376
  */
5205
5377
  disconnectUser(userId) {
5206
- this.forEachUserRooms(userId, (room, user) => {
5207
- if (room.$leave)
5208
- room.$leave(user);
5378
+ return new Promise((resolve2, reject) => {
5379
+ const user = this.getUser(userId);
5380
+ if (!user)
5381
+ return resolve2();
5382
+ user.$state = UserState.Disconnected;
5383
+ const leave = () => {
5384
+ const leaveAllPromises = [];
5385
+ this.forEachUserRooms(userId, async (room, user2) => {
5386
+ if (room.$leave)
5387
+ leaveAllPromises.push(room.$leave(user2));
5388
+ });
5389
+ delete this.users[userId];
5390
+ Promise.all(leaveAllPromises).then(resolve2).catch((err) => {
5391
+ Transmitter.error(user, err);
5392
+ reject(err);
5393
+ });
5394
+ };
5395
+ if (!this.timeoutDisconnect) {
5396
+ leave();
5397
+ return;
5398
+ }
5399
+ user._timeoutDisconnect = setTimeout(leave, this.timeoutDisconnect);
5400
+ });
5401
+ }
5402
+ httpUpgrade(httpServer, io) {
5403
+ httpServer.removeAllListeners("upgrade");
5404
+ httpServer.on("upgrade", (req, socket, head) => {
5405
+ if (req.url.startsWith("/socket.io/")) {
5406
+ io.engine.handleUpgrade(req, socket, head);
5407
+ } else {
5408
+ socket.destroy();
5409
+ }
5209
5410
  });
5210
- delete this.users[userId];
5211
5411
  }
5212
- joinOrLeaveRoom(type, roomId, userId) {
5412
+ async joinOrLeaveRoom(type, roomId, userId) {
5213
5413
  const room = this.getRoom(roomId);
5214
5414
  if (!room)
5215
5415
  return;
5216
- if (room[type])
5217
- room[type](this.getUser(userId, false));
5416
+ if (room[type]) {
5417
+ try {
5418
+ await room[type](this.getUser(userId, false));
5419
+ } catch (err) {
5420
+ Transmitter.error(this.getUser(userId, false), err);
5421
+ throw err;
5422
+ }
5423
+ }
5218
5424
  return room;
5219
5425
  }
5220
5426
  /**
@@ -5224,7 +5430,7 @@ class WorldClass {
5224
5430
  * @param {string} userId
5225
5431
  * @returns {RoomClass | undefined}
5226
5432
  */
5227
- leaveRoom(roomId, userId) {
5433
+ async leaveRoom(roomId, userId) {
5228
5434
  return this.joinOrLeaveRoom("$leave", roomId, userId);
5229
5435
  }
5230
5436
  /**
@@ -5234,7 +5440,7 @@ class WorldClass {
5234
5440
  * @param {string} userId
5235
5441
  * @returns {RoomClass | undefined}
5236
5442
  */
5237
- joinRoom(roomId, userId) {
5443
+ async joinRoom(roomId, userId) {
5238
5444
  return this.joinOrLeaveRoom("$join", roomId, userId);
5239
5445
  }
5240
5446
  /**
@@ -5264,12 +5470,15 @@ class WorldClass {
5264
5470
  * @param {Class or instance of Class} roomClass
5265
5471
  * @returns instance of Class
5266
5472
  */
5267
- addRoom(id, roomClass) {
5473
+ addRoom(id, roomClass, options2 = {}) {
5268
5474
  if (roomClass.constructor.name == "Function") {
5269
5475
  roomClass = new roomClass();
5270
5476
  }
5271
- const room = new Room().add(id, roomClass);
5477
+ const room = new Room(options2).add(id, roomClass);
5272
5478
  this.rooms.set(id, room);
5479
+ if (this.agonesSDK) {
5480
+ this.agonesSDK.setLabel("room.id", id);
5481
+ }
5273
5482
  return room;
5274
5483
  }
5275
5484
  /**
@@ -5303,11 +5512,132 @@ class WorldClass {
5303
5512
  * Remove all rooms and users
5304
5513
  */
5305
5514
  clear() {
5515
+ var _a, _b;
5306
5516
  this.rooms.clear();
5517
+ this.changes.next({});
5307
5518
  this.users = {};
5519
+ if (this._transport) {
5520
+ (_b = (_a = this._transport.io) == null ? void 0 : _a.clear) == null ? void 0 : _b.call(_a);
5521
+ }
5308
5522
  }
5309
5523
  }
5310
5524
  const World = new WorldClass();
5525
+ class MiddlewareHandler {
5526
+ constructor() {
5527
+ this.middlewares = [];
5528
+ }
5529
+ use(middleware) {
5530
+ this.middlewares.push(middleware);
5531
+ }
5532
+ run(socket, finalCallback = (err) => {
5533
+ }) {
5534
+ let index2 = 0;
5535
+ const next = (err) => {
5536
+ if (err) {
5537
+ finalCallback(err);
5538
+ return;
5539
+ }
5540
+ if (index2 >= this.middlewares.length) {
5541
+ finalCallback();
5542
+ return;
5543
+ }
5544
+ const middleware = this.middlewares[index2];
5545
+ index2 += 1;
5546
+ middleware(socket, next);
5547
+ };
5548
+ next();
5549
+ }
5550
+ clear() {
5551
+ this.middlewares = [];
5552
+ }
5553
+ }
5554
+ class MockIo {
5555
+ constructor() {
5556
+ this.events = /* @__PURE__ */ new Map();
5557
+ this.eventsOnce = /* @__PURE__ */ new Map();
5558
+ }
5559
+ on(name, value) {
5560
+ this.events.set(name, [...this.events.get(name) || [], value]);
5561
+ }
5562
+ off(name) {
5563
+ if (this.eventsOnce.has(name)) {
5564
+ this.eventsOnce.delete(name);
5565
+ return;
5566
+ }
5567
+ this.events.delete(name);
5568
+ }
5569
+ once(name, value) {
5570
+ this.eventsOnce.set(name, value);
5571
+ }
5572
+ _trigger(name, data, client) {
5573
+ const events = this.events.get(name) || [];
5574
+ for (const event of events) {
5575
+ event(data, client);
5576
+ }
5577
+ const eventOnce = this.eventsOnce.get(name);
5578
+ if (eventOnce) {
5579
+ eventOnce(data, client);
5580
+ this.eventsOnce.delete(name);
5581
+ }
5582
+ }
5583
+ }
5584
+ class MockSocket extends MockIo {
5585
+ constructor(handshake, client) {
5586
+ super();
5587
+ this.handshake = handshake;
5588
+ this.client = client;
5589
+ this.middlewares = new MiddlewareHandler();
5590
+ this.id = client.fakeId ?? "" + Math.random();
5591
+ this.client.id = this.id;
5592
+ }
5593
+ emit(name, data) {
5594
+ this.client._trigger(name, data);
5595
+ }
5596
+ removeAllListeners(name) {
5597
+ return this.off(name);
5598
+ }
5599
+ use(cb) {
5600
+ this.middlewares.use(cb);
5601
+ }
5602
+ disconnect() {
5603
+ }
5604
+ }
5605
+ class MockServerIo extends MockIo {
5606
+ constructor() {
5607
+ super(...arguments);
5608
+ this.clients = /* @__PURE__ */ new Map();
5609
+ this.middlewares = new MiddlewareHandler();
5610
+ }
5611
+ connection(client, handshake) {
5612
+ return new Promise((resolve2, reject) => {
5613
+ const socket = new MockSocket(handshake, client);
5614
+ this.clients.set(socket.id, socket);
5615
+ client.id = socket.id;
5616
+ this.middlewares.run(socket, (err) => {
5617
+ if (err) {
5618
+ client._trigger("error", err);
5619
+ return;
5620
+ }
5621
+ this._trigger("connection", socket);
5622
+ resolve2(socket);
5623
+ });
5624
+ });
5625
+ }
5626
+ emit(name, data, id) {
5627
+ var _a;
5628
+ (_a = this.clients.get(id)) == null ? void 0 : _a._trigger(name, data);
5629
+ }
5630
+ use(cb) {
5631
+ this.middlewares.use(cb);
5632
+ }
5633
+ clear() {
5634
+ this.events.clear();
5635
+ this.eventsOnce.clear();
5636
+ this.clients.clear();
5637
+ this.middlewares.clear();
5638
+ }
5639
+ }
5640
+ new MockServerIo();
5311
5641
  var TiledLayerType;
5312
5642
  (function(TiledLayerType2) {
5313
5643
  TiledLayerType2["Tile"] = "tilelayer";
@@ -12446,7 +12776,7 @@ var lodash_merge = {
12446
12776
  return func(value);
12447
12777
  };
12448
12778
  }
12449
- function getValue2(object, key) {
12779
+ function getValue(object, key) {
12450
12780
  return object == null ? void 0 : object[key];
12451
12781
  }
12452
12782
  function overArg(func, transform) {
@@ -12482,7 +12812,7 @@ var lodash_merge = {
12482
12812
  function object() {
12483
12813
  }
12484
12814
  return function(proto) {
12485
- if (!isObject3(proto)) {
12815
+ if (!isObject2(proto)) {
12486
12816
  return {};
12487
12817
  }
12488
12818
  if (objectCreate) {
@@ -12715,7 +13045,7 @@ var lodash_merge = {
12715
13045
  return isObjectLike(value) && baseGetTag(value) == argsTag;
12716
13046
  }
12717
13047
  function baseIsNative(value) {
12718
- if (!isObject3(value) || isMasked(value)) {
13048
+ if (!isObject2(value) || isMasked(value)) {
12719
13049
  return false;
12720
13050
  }
12721
13051
  var pattern = isFunction2(value) ? reIsNative : reIsHostCtor;
@@ -12725,7 +13055,7 @@ var lodash_merge = {
12725
13055
  return isObjectLike(value) && isLength(value.length) && !!typedArrayTags[baseGetTag(value)];
12726
13056
  }
12727
13057
  function baseKeysIn(object) {
12728
- if (!isObject3(object)) {
13058
+ if (!isObject2(object)) {
12729
13059
  return nativeKeysIn(object);
12730
13060
  }
12731
13061
  var isProto = isPrototype(object), result = [];
@@ -12742,7 +13072,7 @@ var lodash_merge = {
12742
13072
  }
12743
13073
  baseFor(source, function(srcValue, key) {
12744
13074
  stack || (stack = new Stack());
12745
- if (isObject3(srcValue)) {
13075
+ if (isObject2(srcValue)) {
12746
13076
  baseMergeDeep(object, source, key, srcIndex, baseMerge, customizer, stack);
12747
13077
  } else {
12748
13078
  var newValue = customizer ? customizer(safeGet(object, key), srcValue, key + "", object, source, stack) : void 0;
@@ -12782,7 +13112,7 @@ var lodash_merge = {
12782
13112
  newValue = objValue;
12783
13113
  if (isArguments(objValue)) {
12784
13114
  newValue = toPlainObject(objValue);
12785
- } else if (!isObject3(objValue) || isFunction2(objValue)) {
13115
+ } else if (!isObject2(objValue) || isFunction2(objValue)) {
12786
13116
  newValue = initCloneObject(srcValue);
12787
13117
  }
12788
13118
  } else {
@@ -12885,7 +13215,7 @@ var lodash_merge = {
12885
13215
  return isKeyable(key) ? data[typeof key == "string" ? "string" : "hash"] : data.map;
12886
13216
  }
12887
13217
  function getNative(object, key) {
12888
- var value = getValue2(object, key);
13218
+ var value = getValue(object, key);
12889
13219
  return baseIsNative(value) ? value : void 0;
12890
13220
  }
12891
13221
  function getRawTag(value) {
@@ -12914,7 +13244,7 @@ var lodash_merge = {
12914
13244
  return !!length && (type == "number" || type != "symbol" && reIsUint.test(value)) && (value > -1 && value % 1 == 0 && value < length);
12915
13245
  }
12916
13246
  function isIterateeCall(value, index2, object) {
12917
- if (!isObject3(object)) {
13247
+ if (!isObject2(object)) {
12918
13248
  return false;
12919
13249
  }
12920
13250
  var type = typeof index2;
@@ -13017,7 +13347,7 @@ var lodash_merge = {
13017
13347
  }
13018
13348
  var isBuffer2 = nativeIsBuffer || stubFalse;
13019
13349
  function isFunction2(value) {
13020
- if (!isObject3(value)) {
13350
+ if (!isObject2(value)) {
13021
13351
  return false;
13022
13352
  }
13023
13353
  var tag = baseGetTag(value);
@@ -13026,7 +13356,7 @@ var lodash_merge = {
13026
13356
  function isLength(value) {
13027
13357
  return typeof value == "number" && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;
13028
13358
  }
13029
- function isObject3(value) {
13359
+ function isObject2(value) {
13030
13360
  var type = typeof value;
13031
13361
  return value != null && (type == "object" || type == "function");
13032
13362
  }
@@ -17593,7 +17923,6 @@ class EventManager {
17593
17923
  }
17594
17924
  // @internal
17595
17925
  removeObject(object, mode = "shared") {
17596
- var _a;
17597
17926
  const map = this.getCurrentMap();
17598
17927
  if (!map)
17599
17928
  return;
@@ -17612,7 +17941,7 @@ class EventManager {
17612
17941
  if (object.id == playerId)
17613
17942
  continue;
17614
17943
  const otherPlayer = map.players[playerId];
17615
- if (((_a = otherPlayer.following) == null ? void 0 : _a.id) == object.id) {
17944
+ if (otherPlayer.followingId == object.id) {
17616
17945
  otherPlayer.cameraFollow(otherPlayer);
17617
17946
  }
17618
17947
  }
@@ -17621,6 +17950,13 @@ class EventManager {
17621
17950
  }
17622
17951
  }
17623
17952
  }
17953
+ let instanceContext = null;
17954
+ function inject(service, args = []) {
17955
+ return instanceContext.inject(service, args);
17956
+ }
17957
+ function setInject(context) {
17958
+ instanceContext = context;
17959
+ }
17624
17960
  const {
17625
17961
  isPromise,
17626
17962
  applyMixins,
@@ -17680,7 +18016,7 @@ const playerSchemas = {
17680
18016
  sp: Number,
17681
18017
  gold: Number,
17682
18018
  level: {
17683
- $effects: ["$this.expForNextlevel"]
18019
+ $effects: ["$this.expForNextlevel", "$this.param"]
17684
18020
  },
17685
18021
  expForNextlevel: {
17686
18022
  $permanent: false
@@ -17742,8 +18078,9 @@ const layoutObject = {
17742
18078
  lines: []
17743
18079
  };
17744
18080
  const _RpgPlayer = class extends RpgCommonPlayer {
17745
- constructor(gameEngine, playerId) {
17746
- super(gameEngine, playerId);
18081
+ constructor(playerId) {
18082
+ super(inject(RpgCommonGame), playerId);
18083
+ this.playerId = playerId;
17747
18084
  this.type = "player";
17748
18085
  this.layout = {
17749
18086
  top: layoutObject,
@@ -17759,8 +18096,9 @@ const _RpgPlayer = class extends RpgCommonPlayer {
17759
18096
  this.touchSide = false;
17760
18097
  this.tmpPositions = null;
17761
18098
  this.otherPossessedPlayer = null;
17762
- this.following = null;
18099
+ this.followingId = null;
17763
18100
  this._dataLoading = false;
18101
+ this.gameEngine = inject(RpgCommonGame);
17764
18102
  this.teleported = 0;
17765
18103
  this.deleted = false;
17766
18104
  this.initialize();
@@ -17775,6 +18113,7 @@ const _RpgPlayer = class extends RpgCommonPlayer {
17775
18113
  }
17776
18114
  /** @internal */
17777
18115
  initialize() {
18116
+ this.server = inject(RpgServerEngine);
17778
18117
  this.expCurve = {
17779
18118
  basis: 30,
17780
18119
  extra: 20,
@@ -18127,7 +18466,7 @@ const _RpgPlayer = class extends RpgCommonPlayer {
18127
18466
  toJSON() {
18128
18467
  const {
18129
18468
  permanentObject
18130
- } = Room.toDict(this.schema);
18469
+ } = Room.compileSchema(this.schema);
18131
18470
  const snapshot = Room.extractObjectOfRoom(this, permanentObject);
18132
18471
  snapshot.variables = [...this.variables];
18133
18472
  return snapshot;
@@ -18292,9 +18631,9 @@ const _RpgPlayer = class extends RpgCommonPlayer {
18292
18631
  */
18293
18632
  cameraFollow(otherPlayer, options2 = {}) {
18294
18633
  if (otherPlayer.id == this.id) {
18295
- this.following = null;
18634
+ this.followingId = null;
18296
18635
  } else {
18297
- this.following = otherPlayer;
18636
+ this.followingId = otherPlayer.id;
18298
18637
  }
18299
18638
  this.emit(SocketEvents.CallMethod, {
18300
18639
  objectId: this.playerId,
@@ -18478,8 +18817,8 @@ RpgPlayer.schemas = {
18478
18817
  };
18479
18818
  applyMixins(RpgPlayer, [EventManager, ItemManager, GoldManager, StateManager, SkillManager, ParameterManager, EffectManager, ClassManager, ElementManager, GuiManager, VariableManager, MoveManager, BattleManager, ComponentManager]);
18480
18819
  class RpgEvent extends RpgPlayer {
18481
- constructor(gameEngine, playerId) {
18482
- super(gameEngine, playerId);
18820
+ constructor(playerId) {
18821
+ super(playerId);
18483
18822
  this.type = "event";
18484
18823
  this.properties = {};
18485
18824
  this.playerRelated = null;
@@ -18632,6 +18971,20 @@ class RpgMap extends RpgCommonMap {
18632
18971
  get nbPlayers() {
18633
18972
  return Object.keys(this.players).length;
18634
18973
  }
18974
+ $additionalEmitProperties(player) {
18975
+ const lastFramePositions = player["_lastFramePositions"];
18976
+ let pos;
18977
+ let lastFrame;
18978
+ if (lastFramePositions) {
18979
+ pos = lastFramePositions.position;
18980
+ lastFrame = lastFramePositions.frame;
18981
+ }
18982
+ const data = {
18983
+ frame: lastFrame,
18984
+ pos
18985
+ };
18986
+ return data;
18987
+ }
18635
18988
  async load() {
18636
18989
  var _a;
18637
18990
  if (RpgCommonMap.buffer.has(this.id)) {
@@ -18916,7 +19269,6 @@ class RpgMap extends RpgCommonMap {
18916
19269
  const ev = this.game.addEvent(event);
18917
19270
  const _shape = shape || this.getEventShape(ev.name);
18918
19271
  ev.map = this.id;
18919
- ev.server = this._server;
18920
19272
  ev.width = event.width || this.tileWidth;
18921
19273
  ev.height = event.height || this.tileHeight;
18922
19274
  if (_shape && _shape.properties)
@@ -19018,11 +19370,11 @@ var __decorateClass$1 = (decorators, target, key, kind) => {
19018
19370
  return result;
19019
19371
  };
19020
19372
  class SceneMap {
19021
- constructor(sceneMapObject, server) {
19022
- this.server = server;
19373
+ constructor(sceneMapObject) {
19023
19374
  this.maps = [];
19024
19375
  this.mapsById = {};
19025
19376
  this.worldMaps = /* @__PURE__ */ new Map();
19377
+ this.server = inject(RpgServerEngine);
19026
19378
  const {
19027
19379
  maps,
19028
19380
  worldMaps,
@@ -19229,7 +19581,9 @@ class SceneMap {
19229
19581
  await player.teleport(positions || "start");
19230
19582
  return null;
19231
19583
  }
19232
- player.emit("preLoadScene", mapId);
19584
+ player.emit("preLoadScene", {
19585
+ id: mapId
19586
+ });
19233
19587
  player.prevMap = player.map;
19234
19588
  if (player.prevMap) {
19235
19589
  await player.execMethod("onLeaveMap", [player.getCurrentMap()]);
@@ -19440,16 +19794,7 @@ var __decorateClass = (decorators, target, key, kind) => {
19440
19794
  return result;
19441
19795
  };
19442
19796
  class RpgServerEngine {
19443
- /**
19444
- * Combat formulas
19445
- *
19446
- * @prop {Socket Io Server} [io]
19447
- * @memberof RpgServerEngine
19448
- */
19449
- constructor(io, gameEngine, inputOptions) {
19450
- this.io = io;
19451
- this.gameEngine = gameEngine;
19452
- this.inputOptions = inputOptions;
19797
+ constructor() {
19453
19798
  this.database = {};
19454
19799
  this.globalConfig = {};
19455
19800
  this.damageFormulas = {};
@@ -19457,8 +19802,20 @@ class RpgServerEngine {
19457
19802
  this.scenes = /* @__PURE__ */ new Map();
19458
19803
  this.totalConnected = 0;
19459
19804
  this.scheduler = new Scheduler();
19805
+ this.gameEngine = inject(RpgCommonGame);
19460
19806
  this.world = World;
19461
19807
  this.envs = {};
19808
+ this.inputOptions = {};
19809
+ }
19810
+ /**
19811
+ * Combat formulas
19812
+ *
19813
+ * @prop {Socket Io Server} [io]
19814
+ * @memberof RpgServerEngine
19815
+ */
19816
+ initialize(io, inputOptions) {
19817
+ this.io = io;
19818
+ this.inputOptions = inputOptions;
19462
19819
  this.envs = inputOptions.envs || {};
19463
19820
  if (this.inputOptions.workers) {
19464
19821
  console.log("workers enabled");
@@ -19492,15 +19849,16 @@ class RpgServerEngine {
19492
19849
  if (!this.inputOptions.database)
19493
19850
  this.inputOptions.database = {};
19494
19851
  const datas = await RpgPlugin.emit(HookServer.AddDatabase, this.inputOptions.database) || [];
19495
- for (let plug of datas) {
19496
- this.inputOptions.database = {
19497
- ...plug,
19498
- ...this.inputOptions.database
19499
- };
19500
- }
19501
- for (let key in this.inputOptions.database) {
19502
- const data = this.inputOptions.database[key];
19503
- this.addInDatabase(data.id, data);
19852
+ for (let element of datas) {
19853
+ if (Array.isArray(element)) {
19854
+ for (let data of element) {
19855
+ this.addInDatabase(data.id, data);
19856
+ }
19857
+ } else {
19858
+ for (let id in element) {
19859
+ this.addInDatabase(element[id].id ?? id, element[id]);
19860
+ }
19861
+ }
19504
19862
  }
19505
19863
  this.loadScenes();
19506
19864
  }
@@ -19631,9 +19989,27 @@ class RpgServerEngine {
19631
19989
  return Query._getShapesOfMap(map);
19632
19990
  }
19633
19991
  });
19634
- this.io.on("connection", this.onPlayerConnected.bind(this));
19992
+ this.transport(this.io);
19635
19993
  await RpgPlugin.emit(HookServer.Start, this);
19636
19994
  }
19995
+ transport(io) {
19996
+ const timeoutDisconnect = this.globalConfig.timeoutDisconnect ?? 0;
19997
+ const auth = this.globalConfig.disableAuth ? () => Utils$1.generateUID() : async (socket) => {
19998
+ const val = await RpgPlugin.emit(HookServer.Auth, [this, socket], true);
19999
+ if (val.length == 0) {
20000
+ return Utils$1.generateUID();
20001
+ }
20002
+ return val[val.length - 1];
20003
+ };
20004
+ const transport = new Transport(io, {
20005
+ timeoutDisconnect,
20006
+ auth
20007
+ });
20008
+ this.world.timeoutDisconnect = timeoutDisconnect;
20009
+ transport.onConnected(this.onPlayerConnected.bind(this));
20010
+ transport.onDisconnected(this.onPlayerDisconnected.bind(this));
20011
+ return transport;
20012
+ }
19637
20013
  get tick() {
19638
20014
  return this.scheduler.tick;
19639
20015
  }
@@ -19646,7 +20022,7 @@ class RpgServerEngine {
19646
20022
  * @memberof RpgServerEngine
19647
20023
  */
19648
20024
  send() {
19649
- this.world.send();
20025
+ return this.world.send();
19650
20026
  }
19651
20027
  async updatePlayersMove(deltaTimeInt) {
19652
20028
  const players = this.world.getUsers();
@@ -19710,7 +20086,7 @@ class RpgServerEngine {
19710
20086
  maps: this.inputOptions.maps,
19711
20087
  events: this.inputOptions.events,
19712
20088
  worldMaps: this.inputOptions.worldMaps
19713
- }, this));
20089
+ }));
19714
20090
  }
19715
20091
  getScene(name) {
19716
20092
  return this.scenes.get(name);
@@ -19734,13 +20110,52 @@ class RpgServerEngine {
19734
20110
  sendToPlayer(currentPlayer, eventName, data) {
19735
20111
  currentPlayer._socket.emit(eventName, data);
19736
20112
  }
19737
- onPlayerConnected(socket) {
19738
- const {
19739
- token
19740
- } = socket.handshake.auth;
19741
- const playerId = Utils$1.generateUID();
19742
- const player = new RpgPlayer(this.gameEngine, playerId);
19743
- player.session = token;
20113
+ getPlayerBySession(session) {
20114
+ const users = this.world.getUsers();
20115
+ for (let userId in users) {
20116
+ const user = users[userId];
20117
+ if (user.session === session) {
20118
+ return user;
20119
+ }
20120
+ }
20121
+ return null;
20122
+ }
20123
+ onPlayerConnected(socket, playerId) {
20124
+ const existingUser = this.world.getUser(playerId, false);
20125
+ this.world.connectUser(socket, playerId);
20126
+ let player;
20127
+ if (!existingUser) {
20128
+ const {
20129
+ token
20130
+ } = socket.handshake.auth;
20131
+ player = new RpgPlayer(playerId);
20132
+ player.session = token;
20133
+ this.world.setUser(player, socket);
20134
+ player._init();
20135
+ if (!token) {
20136
+ const newToken = Utils$1.generateUID() + "-" + Utils$1.generateUID() + "-" + Utils$1.generateUID();
20137
+ player.session = newToken;
20138
+ }
20139
+ if (!token) {
20140
+ player.execMethod("onConnected");
20141
+ } else {
20142
+ RpgPlugin.emit(HookServer.ScalabilityPlayerConnected, player);
20143
+ }
20144
+ } else {
20145
+ player = existingUser;
20146
+ if (player.map) {
20147
+ player.emit("preLoadScene", {
20148
+ reconnect: true,
20149
+ id: player.map
20150
+ });
20151
+ player.emitSceneMap();
20152
+ this.world.joinRoom(player.map, playerId);
20153
+ }
20154
+ }
20155
+ socket.emit("playerJoined", {
20156
+ playerId,
20157
+ session: player.session
20158
+ });
19744
20159
  socket.on("move", (data) => {
19745
20160
  if (!(data == null ? void 0 : data.input))
19746
20161
  return;
@@ -19757,25 +20172,6 @@ class RpgServerEngine {
19757
20172
  });
19758
20173
  }
19759
20174
  });
19760
- socket.on("disconnect", () => {
19761
- this.onPlayerDisconnected(playerId);
19762
- });
19763
- this.world.setUser(player, socket);
19764
- player.server = this;
19765
- player._init();
19766
- if (!token) {
19767
- const newToken = Utils$1.generateUID() + "-" + Utils$1.generateUID() + "-" + Utils$1.generateUID();
19768
- player.session = newToken;
19769
- }
19770
- socket.emit("playerJoined", {
19771
- playerId,
19772
- session: player.session
19773
- });
19774
- if (!token) {
19775
- player.execMethod("onConnected");
19776
- } else {
19777
- RpgPlugin.emit(HookServer.ScalabilityPlayerConnected, player);
19778
- }
19779
20175
  }
19780
20176
  onPlayerDisconnected(playerId) {
19781
20177
  const player = World.getUser(playerId);
@@ -19821,7 +20217,7 @@ function isArrayBufferView(val) {
19821
20217
  const isString = typeOfTest("string");
19822
20218
  const isFunction = typeOfTest("function");
19823
20219
  const isNumber = typeOfTest("number");
19824
- const isObject2 = (thing) => thing !== null && typeof thing === "object";
20220
+ const isObject = (thing) => thing !== null && typeof thing === "object";
19825
20221
  const isBoolean = (thing) => thing === true || thing === false;
19826
20222
  const isPlainObject = (val) => {
19827
20223
  if (kindOf(val) !== "object") {
@@ -19834,7 +20230,7 @@ const isDate = kindOfTest("Date");
19834
20230
  const isFile = kindOfTest("File");
19835
20231
  const isBlob = kindOfTest("Blob");
19836
20232
  const isFileList = kindOfTest("FileList");
19837
- const isStream = (val) => isObject2(val) && isFunction(val.pipe);
20233
+ const isStream = (val) => isObject(val) && isFunction(val.pipe);
19838
20234
  const isFormData = (thing) => {
19839
20235
  let kind;
19840
20236
  return thing && (typeof FormData === "function" && thing instanceof FormData || isFunction(thing.append) && ((kind = kindOf(thing)) === "formdata" || // detect form-data instance
@@ -20073,7 +20469,7 @@ function isSpecCompliantForm(thing) {
20073
20469
  const toJSONObject = (obj) => {
20074
20470
  const stack = new Array(10);
20075
20471
  const visit = (source, i) => {
20076
- if (isObject2(source)) {
20472
+ if (isObject(source)) {
20077
20473
  if (stack.indexOf(source) >= 0) {
20078
20474
  return;
20079
20475
  }
@@ -20101,7 +20497,7 @@ const utils = {
20101
20497
  isString,
20102
20498
  isNumber,
20103
20499
  isBoolean,
20104
- isObject: isObject2,
20500
+ isObject,
20105
20501
  isPlainObject,
20106
20502
  isUndefined,
20107
20503
  isDate,
@@ -21786,7 +22182,7 @@ class RpgMatchMaker {
21786
22182
  this.callback = options2.callback;
21787
22183
  }
21788
22184
  async getServer(player) {
21789
- const currentServerId = player.server.serverId;
22185
+ const currentServerId = inject(RpgServerEngine).serverId;
21790
22186
  const payload = {
21791
22187
  playerId: player.id,
21792
22188
  mapName: player.map
@@ -21815,7 +22211,9 @@ class RpgMatchMaker {
21815
22211
  }
21816
22212
  }
21817
22213
  async function entryPoint(modules, options2) {
21818
- const gameEngine = new RpgCommonGame(GameSide.Server);
22214
+ const context = new InjectContext();
22215
+ setInject(context);
22216
+ inject(RpgCommonGame, [GameSide.Server]);
21819
22217
  if (!options2.globalConfig)
21820
22218
  options2.globalConfig = {};
21821
22219
  const relations = {
@@ -21833,7 +22231,8 @@ async function entryPoint(modules, options2) {
21833
22231
  };
21834
22232
  const relationsEngine = {
21835
22233
  onStart: HookServer.Start,
21836
- onStep: HookServer.Step
22234
+ onStep: HookServer.Step,
22235
+ auth: HookServer.Auth
21837
22236
  };
21838
22237
  const {
21839
22238
  playerProps
@@ -21871,7 +22270,7 @@ async function entryPoint(modules, options2) {
21871
22270
  }
21872
22271
  return mod;
21873
22272
  });
21874
- const serverEngine = new RpgServerEngine(options2.io, gameEngine, {
22273
+ const serverEngine = inject(RpgServerEngine, [options2.io, {
21875
22274
  debug: {},
21876
22275
  updateRate: 10,
21877
22276
  stepRate: 60,
@@ -21879,7 +22278,7 @@ async function entryPoint(modules, options2) {
21879
22278
  countConnections: false,
21880
22279
  playerProps,
21881
22280
  ...options2
21882
- });
22281
+ }]);
21883
22282
  return serverEngine;
21884
22283
  }
21885
22284
  function EventData(options2) {
@@ -21965,5 +22364,6 @@ export {
21965
22364
  RpgWorldMaps,
21966
22365
  ShapePositioning,
21967
22366
  Speed,
21968
- entryPoint
22367
+ entryPoint,
22368
+ inject
21969
22369
  };