@rbxts/replion 1.0.17 → 1.0.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/package.json +2 -2
- package/src/BaseReplion.lua +56 -0
- package/src/Client.lua +22 -39
- package/src/Server.lua +23 -44
package/README.md
CHANGED
package/package.json
CHANGED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
--!strict
|
|
2
|
+
export type GenericDataTable = { [string]: any };
|
|
3
|
+
|
|
4
|
+
local isTypeScriptEnv = script.Parent.Name == 'src';
|
|
5
|
+
local dependencies = if isTypeScriptEnv then script.Parent.Parent.Parent else script.Parent.Parent;
|
|
6
|
+
local Shared = require(script.Parent.Shared);
|
|
7
|
+
local Signal = require(isTypeScriptEnv and dependencies['sleitnick-signal'] or dependencies.Signal);
|
|
8
|
+
|
|
9
|
+
local BaseReplion = {};
|
|
10
|
+
BaseReplion.__index = BaseReplion;
|
|
11
|
+
|
|
12
|
+
function BaseReplion.new(data: GenericDataTable)
|
|
13
|
+
local self = setmetatable({}, BaseReplion);
|
|
14
|
+
|
|
15
|
+
self.data = data;
|
|
16
|
+
|
|
17
|
+
self._signals = {} :: { [string]: any };
|
|
18
|
+
self._allSignal = Signal.new();
|
|
19
|
+
|
|
20
|
+
return self;
|
|
21
|
+
end;
|
|
22
|
+
|
|
23
|
+
function BaseReplion:get(path: { string }?)
|
|
24
|
+
if not path then return self.data; end;
|
|
25
|
+
return Shared.getNestedValue(self.data, path);
|
|
26
|
+
end;
|
|
27
|
+
|
|
28
|
+
function BaseReplion:observe(path: { string }?, callback: (any, any) -> ())
|
|
29
|
+
if not path then
|
|
30
|
+
task.spawn(callback, self.data, nil);
|
|
31
|
+
return self._allSignal:Connect(callback);
|
|
32
|
+
end;
|
|
33
|
+
|
|
34
|
+
local signalKey = Shared.getSignalKey(path);
|
|
35
|
+
if not self._signals[signalKey] then
|
|
36
|
+
self._signals[signalKey] = Signal.new();
|
|
37
|
+
end;
|
|
38
|
+
|
|
39
|
+
local initialValue = Shared.getNestedValue(self.data, path);
|
|
40
|
+
|
|
41
|
+
task.spawn(callback, initialValue, nil);
|
|
42
|
+
local connection = self._signals[signalKey]:Connect(callback);
|
|
43
|
+
return function()
|
|
44
|
+
connection:Disconnect();
|
|
45
|
+
end;
|
|
46
|
+
end;
|
|
47
|
+
|
|
48
|
+
function BaseReplion:destroy()
|
|
49
|
+
self._allSignal:Destroy();
|
|
50
|
+
for _, signal in self._signals do
|
|
51
|
+
signal:Destroy();
|
|
52
|
+
end;
|
|
53
|
+
self._signals = {};
|
|
54
|
+
end;
|
|
55
|
+
|
|
56
|
+
return BaseReplion;
|
package/src/Client.lua
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
--!strict
|
|
2
2
|
local isTypeScriptEnv = script.Parent.Name == 'src';
|
|
3
3
|
local dependencies = if isTypeScriptEnv then script.Parent.Parent.Parent else script.Parent.Parent;
|
|
4
|
+
local BaseReplion = require(script.Parent.BaseReplion)
|
|
4
5
|
local Shared = require(script.Parent.Shared);
|
|
5
6
|
local Signal = require(isTypeScriptEnv and dependencies['sleitnick-signal'] or dependencies.Signal);
|
|
6
7
|
|
|
@@ -52,36 +53,18 @@ function Client.new(channel: string, data: Shared.GenericDataTable)
|
|
|
52
53
|
local self = setmetatable({}, Client);
|
|
53
54
|
|
|
54
55
|
self.channel = channel;
|
|
55
|
-
|
|
56
|
-
self.
|
|
57
|
-
self._allSignal = Signal.new();
|
|
56
|
+
|
|
57
|
+
self._base = BaseReplion.new(data);
|
|
58
58
|
|
|
59
59
|
return self;
|
|
60
60
|
end;
|
|
61
61
|
|
|
62
62
|
function Client:get(path: { string }?)
|
|
63
|
-
|
|
64
|
-
return Shared.getNestedValue(self.data, path);
|
|
63
|
+
return self._base:get(path);
|
|
65
64
|
end;
|
|
66
65
|
|
|
67
66
|
function Client:observe(path: { string }?, callback: Observer)
|
|
68
|
-
|
|
69
|
-
task.spawn(callback, self.data, nil);
|
|
70
|
-
return self._allSignal:Connect(callback);
|
|
71
|
-
end;
|
|
72
|
-
|
|
73
|
-
local signalKey = Shared.getSignalKey(path);
|
|
74
|
-
if not self._signals[signalKey] then
|
|
75
|
-
self._signals[signalKey] = Signal.new();
|
|
76
|
-
end;
|
|
77
|
-
|
|
78
|
-
local initialValue = Shared.getNestedValue(self.data, path);
|
|
79
|
-
|
|
80
|
-
task.spawn(callback, initialValue, nil);
|
|
81
|
-
local connection = self._signals[signalKey]:Connect(callback);
|
|
82
|
-
return function()
|
|
83
|
-
connection:Disconnect();
|
|
84
|
-
end;
|
|
67
|
+
return self._base:observe(path, callback);
|
|
85
68
|
end;
|
|
86
69
|
|
|
87
70
|
function Client:_collectDeletions(target: any, updates: any, path: { string }, out: { Deletion })
|
|
@@ -101,12 +84,14 @@ function Client:_collectDeletions(target: any, updates: any, path: { string }, o
|
|
|
101
84
|
end;
|
|
102
85
|
|
|
103
86
|
function Client:_notifyDeepDeletion(path: { string }, oldTable: any)
|
|
87
|
+
local signals = self._base._signals;
|
|
88
|
+
|
|
104
89
|
for k, v in oldTable do
|
|
105
90
|
local nextPath = table.clone(path);
|
|
106
91
|
table.insert(nextPath, k);
|
|
107
92
|
|
|
108
93
|
local signalKey = Shared.getSignalKey(nextPath);
|
|
109
|
-
local signal =
|
|
94
|
+
local signal = signals[signalKey];
|
|
110
95
|
if signal then
|
|
111
96
|
signal:Fire(nil, v);
|
|
112
97
|
end;
|
|
@@ -118,15 +103,17 @@ function Client:_notifyDeepDeletion(path: { string }, oldTable: any)
|
|
|
118
103
|
end;
|
|
119
104
|
|
|
120
105
|
function Client:_notifyRecursiveUpdates(currentPath: { string }, updateTree: any)
|
|
106
|
+
local signals = self._base._signals;
|
|
107
|
+
|
|
121
108
|
for k, v in updateTree do
|
|
122
109
|
local nextPath = table.clone(currentPath);
|
|
123
110
|
table.insert(nextPath, k);
|
|
124
111
|
|
|
125
112
|
local signalKey = Shared.getSignalKey(nextPath);
|
|
126
|
-
local signal =
|
|
113
|
+
local signal = signals[signalKey];
|
|
127
114
|
|
|
128
115
|
if signal then
|
|
129
|
-
local newValue = Shared.getNestedValue(self.data, nextPath);
|
|
116
|
+
local newValue = Shared.getNestedValue(self._base.data, nextPath);
|
|
130
117
|
signal:Fire(newValue, newValue); -- Warning: Sends improper 'old' argument due to shallow copy optimization.
|
|
131
118
|
end;
|
|
132
119
|
|
|
@@ -138,11 +125,11 @@ end;
|
|
|
138
125
|
|
|
139
126
|
function Client:_applyUpdates(updates: Shared.GenericDataTable)
|
|
140
127
|
local deletions: { Deletion } = {};
|
|
141
|
-
self:_collectDeletions(self.data, updates, {}, deletions);
|
|
128
|
+
self:_collectDeletions(self._base.data, updates, {}, deletions);
|
|
142
129
|
|
|
143
|
-
local oldData = table.clone(self.data); -- Note: Shallow copy instead of deep copy.
|
|
130
|
+
local oldData = table.clone(self._base.data); -- Note: Shallow copy instead of deep copy.
|
|
144
131
|
|
|
145
|
-
deepMergeAndApply(self.data, updates);
|
|
132
|
+
deepMergeAndApply(self._base.data, updates);
|
|
146
133
|
|
|
147
134
|
local anyChanged = false;
|
|
148
135
|
|
|
@@ -156,31 +143,27 @@ function Client:_applyUpdates(updates: Shared.GenericDataTable)
|
|
|
156
143
|
-- If it's a table, we assume it changed if it's in the updates list.
|
|
157
144
|
if typeof(newValue) == 'table' then
|
|
158
145
|
anyChanged = true;
|
|
159
|
-
local signal = self._signals[key];
|
|
146
|
+
local signal = self._base._signals[key];
|
|
160
147
|
if signal then
|
|
161
|
-
signal:Fire(self.data[key], self.data[key]); -- Warning: Sends improper 'old' argument due to shallow copy optimization.
|
|
148
|
+
signal:Fire(self._base.data[key], self._base.data[key]); -- Warning: Sends improper 'old' argument due to shallow copy optimization.
|
|
162
149
|
end;
|
|
163
150
|
self:_notifyRecursiveUpdates({key}, newValue);
|
|
164
|
-
elseif self.data[key] ~= oldValue then
|
|
151
|
+
elseif self._base.data[key] ~= oldValue then
|
|
165
152
|
anyChanged = true;
|
|
166
|
-
local signal = self._signals[key];
|
|
153
|
+
local signal = self._base._signals[key];
|
|
167
154
|
if signal then
|
|
168
|
-
signal:Fire(self.data[key], oldValue);
|
|
155
|
+
signal:Fire(self._base.data[key], oldValue);
|
|
169
156
|
end;
|
|
170
157
|
end;
|
|
171
158
|
end;
|
|
172
159
|
|
|
173
160
|
if anyChanged then
|
|
174
|
-
self._allSignal:Fire(self.data, updates);
|
|
161
|
+
self._base._allSignal:Fire(self._base.data, updates);
|
|
175
162
|
end;
|
|
176
163
|
end;
|
|
177
164
|
|
|
178
165
|
function Client:destroy()
|
|
179
|
-
self.
|
|
180
|
-
for _, signal in self._signals do
|
|
181
|
-
signal:Destroy();
|
|
182
|
-
end;
|
|
183
|
-
self._signals = {};
|
|
166
|
+
self._base:destroy();
|
|
184
167
|
end;
|
|
185
168
|
|
|
186
169
|
remote.OnClientEvent:Connect(function(type, channel, payload)
|
package/src/Server.lua
CHANGED
|
@@ -3,9 +3,9 @@ local Players = game:GetService('Players');
|
|
|
3
3
|
|
|
4
4
|
local isTypeScriptEnv = script.Parent.Name == 'src';
|
|
5
5
|
local dependencies = if isTypeScriptEnv then script.Parent.Parent.Parent else script.Parent.Parent;
|
|
6
|
+
local BaseReplion = require(script.Parent.BaseReplion)
|
|
6
7
|
local Shared = require(script.Parent.Shared);
|
|
7
8
|
local Sift = require(isTypeScriptEnv and dependencies.sift.out or dependencies.Sift);
|
|
8
|
-
local Signal = require(isTypeScriptEnv and dependencies['sleitnick-signal'] or dependencies.Signal);
|
|
9
9
|
|
|
10
10
|
type ServerConfig = {
|
|
11
11
|
channel: string;
|
|
@@ -76,10 +76,8 @@ function Server.new(config: ServerConfig)
|
|
|
76
76
|
|
|
77
77
|
self.player = config.replicateTo;
|
|
78
78
|
self.channel = config.channel;
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
self._signals = {} :: { [string]: any };
|
|
82
|
-
self._allSignal = Signal.new();
|
|
79
|
+
|
|
80
|
+
self._base = BaseReplion.new(Sift.Dictionary.copyDeep(config.data));
|
|
83
81
|
|
|
84
82
|
self._queuedUpdates = {} :: Shared.GenericDataTable;
|
|
85
83
|
self._isQueued = false;
|
|
@@ -100,26 +98,16 @@ function Server.new(config: ServerConfig)
|
|
|
100
98
|
end;
|
|
101
99
|
|
|
102
100
|
function Server:observe(path: { string }?, callback: Observer)
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
return self._allSignal:Connect(callback);
|
|
106
|
-
end;
|
|
107
|
-
|
|
108
|
-
local signalKey = Shared.getSignalKey(path);
|
|
109
|
-
if not self._signals[signalKey] then
|
|
110
|
-
self._signals[signalKey] = Signal.new();
|
|
111
|
-
end;
|
|
112
|
-
|
|
113
|
-
local initialValue = Shared.getNestedValue(self.data, path);
|
|
101
|
+
return self._base:observe(path, callback);
|
|
102
|
+
end;
|
|
114
103
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
return function()
|
|
118
|
-
connection:Disconnect();
|
|
119
|
-
end;
|
|
104
|
+
function Server:get(path: { string }?)
|
|
105
|
+
return self._base:get(path);
|
|
120
106
|
end;
|
|
121
107
|
|
|
122
108
|
function Server:_notifyDeep(currentPath: { string }, newValue: any, oldValue: any)
|
|
109
|
+
local signals = self._base._signals;
|
|
110
|
+
|
|
123
111
|
if typeof(newValue) == 'table' then
|
|
124
112
|
for k, v in newValue do
|
|
125
113
|
local nextPath = table.clone(currentPath);
|
|
@@ -128,7 +116,7 @@ function Server:_notifyDeep(currentPath: { string }, newValue: any, oldValue: an
|
|
|
128
116
|
local nextOld = if typeof(oldValue) == 'table' then oldValue[k] else nil;
|
|
129
117
|
|
|
130
118
|
local signalKey = Shared.getSignalKey(nextPath);
|
|
131
|
-
local signal =
|
|
119
|
+
local signal = signals[signalKey];
|
|
132
120
|
if signal then
|
|
133
121
|
signal:Fire(v, nextOld);
|
|
134
122
|
end;
|
|
@@ -145,7 +133,7 @@ function Server:_notifyDeep(currentPath: { string }, newValue: any, oldValue: an
|
|
|
145
133
|
table.insert(nextPath, k);
|
|
146
134
|
|
|
147
135
|
local signalKey = Shared.getSignalKey(nextPath);
|
|
148
|
-
local signal =
|
|
136
|
+
local signal = signals[signalKey];
|
|
149
137
|
if signal then
|
|
150
138
|
signal:Fire(nil, v);
|
|
151
139
|
end;
|
|
@@ -160,25 +148,26 @@ function Server:set(path: { string }, value: any)
|
|
|
160
148
|
|
|
161
149
|
local topKey = path[1];
|
|
162
150
|
|
|
163
|
-
local oldValue = Shared.getNestedValue(self.data, path);
|
|
151
|
+
local oldValue = Shared.getNestedValue(self._base.data, path);
|
|
164
152
|
local newValue = if typeof(value) == 'function' then value(oldValue) else value;
|
|
165
153
|
if oldValue == newValue then return; end;
|
|
166
154
|
|
|
167
|
-
local oldTop = self.data[topKey];
|
|
155
|
+
local oldTop = self._base.data[topKey];
|
|
168
156
|
|
|
169
|
-
setNestedValue(self.data, path, newValue);
|
|
157
|
+
setNestedValue(self._base.data, path, newValue);
|
|
170
158
|
queueNestedUpdate(self._queuedUpdates, path, newValue);
|
|
171
159
|
self:_scheduleUpdatesFlush();
|
|
172
160
|
|
|
173
161
|
do
|
|
174
|
-
local
|
|
162
|
+
local signals = self._base._signals;
|
|
163
|
+
local topSignal = signals[topKey];
|
|
175
164
|
if topSignal then
|
|
176
|
-
topSignal:Fire(self.data[topKey], oldTop);
|
|
165
|
+
topSignal:Fire(self._base.data[topKey], oldTop);
|
|
177
166
|
end;
|
|
178
167
|
|
|
179
168
|
local signalKey = Shared.getSignalKey(path);
|
|
180
169
|
if signalKey ~= topKey then
|
|
181
|
-
local pathSignal =
|
|
170
|
+
local pathSignal = signals[signalKey];
|
|
182
171
|
if pathSignal then
|
|
183
172
|
pathSignal:Fire(newValue, oldValue)
|
|
184
173
|
end;
|
|
@@ -188,26 +177,16 @@ function Server:set(path: { string }, value: any)
|
|
|
188
177
|
|
|
189
178
|
local thisUpdate = {};
|
|
190
179
|
setNestedValue(thisUpdate, path, newValue);
|
|
191
|
-
self._allSignal:Fire(self.data, thisUpdate);
|
|
180
|
+
self._base._allSignal:Fire(self._base.data, thisUpdate);
|
|
192
181
|
end;
|
|
193
182
|
end;
|
|
194
183
|
|
|
195
|
-
function Server:get(path: { string }?)
|
|
196
|
-
if not path then return self.data; end;
|
|
197
|
-
return Shared.getNestedValue(self.data, path);
|
|
198
|
-
end;
|
|
199
|
-
|
|
200
184
|
function Server:destroy()
|
|
201
185
|
self._destroyed = true;
|
|
202
|
-
self.data = {};
|
|
203
186
|
self._queuedUpdates = {};
|
|
204
|
-
|
|
205
|
-
self.
|
|
206
|
-
|
|
207
|
-
signal:Destroy();
|
|
208
|
-
end;
|
|
209
|
-
self._signals = {};
|
|
210
|
-
|
|
187
|
+
|
|
188
|
+
self._base:destroy();
|
|
189
|
+
|
|
211
190
|
if self.player then
|
|
212
191
|
local playerReplions = self._activeReplions[self.player];
|
|
213
192
|
if not playerReplions then return; end;
|
|
@@ -249,7 +228,7 @@ function Server:_sendInitial(player: Player?)
|
|
|
249
228
|
local receiver = player or self.player;
|
|
250
229
|
if not receiver then return; end;
|
|
251
230
|
|
|
252
|
-
remote:FireClient(receiver, 'I', self.channel, self.data);
|
|
231
|
+
remote:FireClient(receiver, 'I', self.channel, self._base.data);
|
|
253
232
|
end;
|
|
254
233
|
|
|
255
234
|
remote.OnServerEvent:Connect(function(player, action, ...)
|