@quenty/remoting 6.5.0 → 6.6.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.
- package/CHANGELOG.md +12 -0
- package/package.json +8 -3
- package/src/Shared/Interface/Remoting.lua +532 -0
- package/src/Shared/Interface/RemotingMember.lua +189 -0
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,18 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
# [6.6.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/remoting@6.5.0...@quenty/remoting@6.6.0) (2023-06-17)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
* Add forward declaration ([40bb41e](https://github.com/Quenty/NevermoreEngine/commit/40bb41ebabe889faefda9aac11f03834bb1d4286))
|
|
12
|
+
* Add Remoting class which accelerators remoting logic in Roblox ([50e3581](https://github.com/Quenty/NevermoreEngine/commit/50e358185e52fcc280d850d7f397264f8b31bff9))
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
|
|
6
18
|
# [6.5.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/remoting@6.4.1...@quenty/remoting@6.5.0) (2023-04-10)
|
|
7
19
|
|
|
8
20
|
**Note:** Version bump only for package @quenty/remoting
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quenty/remoting",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.6.0",
|
|
4
4
|
"description": "Global remoting retrieval system for Roblox (RemoteFunctions/RemoteEvents)",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Roblox",
|
|
@@ -26,12 +26,17 @@
|
|
|
26
26
|
"Quenty"
|
|
27
27
|
],
|
|
28
28
|
"dependencies": {
|
|
29
|
+
"@quenty/brio": "^8.14.0",
|
|
30
|
+
"@quenty/instanceutils": "^7.15.0",
|
|
29
31
|
"@quenty/loader": "^6.2.1",
|
|
30
|
-
"@quenty/
|
|
32
|
+
"@quenty/maid": "^2.5.0",
|
|
33
|
+
"@quenty/promise": "^6.6.0",
|
|
34
|
+
"@quenty/remotefunctionutils": "^6.7.0",
|
|
35
|
+
"@quenty/rx": "^7.12.0",
|
|
31
36
|
"@quenty/table": "^3.2.0"
|
|
32
37
|
},
|
|
33
38
|
"publishConfig": {
|
|
34
39
|
"access": "public"
|
|
35
40
|
},
|
|
36
|
-
"gitHead": "
|
|
41
|
+
"gitHead": "dc77d6de09e9eb9d3fd6dafd790c052d8393d38f"
|
|
37
42
|
}
|
|
@@ -0,0 +1,532 @@
|
|
|
1
|
+
--[=[
|
|
2
|
+
Offers a thin wrapper around Roblox remoting instances and events. Designed to reduce
|
|
3
|
+
the amount of code needed to construct a large set of RemoteFunction/RemoteEvent instances.
|
|
4
|
+
|
|
5
|
+
@class Remoting
|
|
6
|
+
]=]
|
|
7
|
+
|
|
8
|
+
local require = require(script.Parent.loader).load(script)
|
|
9
|
+
|
|
10
|
+
local RunService = game:GetService("RunService")
|
|
11
|
+
|
|
12
|
+
local Maid = require("Maid")
|
|
13
|
+
local Promise = require("Promise")
|
|
14
|
+
local promiseChild = require("promiseChild")
|
|
15
|
+
local PromiseUtils = require("PromiseUtils")
|
|
16
|
+
local RemoteFunctionUtils = require("RemoteFunctionUtils")
|
|
17
|
+
local RemotingMember = require("RemotingMember")
|
|
18
|
+
local RxBrioUtils = require("RxBrioUtils")
|
|
19
|
+
local RxInstanceUtils = require("RxInstanceUtils")
|
|
20
|
+
|
|
21
|
+
local RAW_MEMBERS = {
|
|
22
|
+
_name = true;
|
|
23
|
+
_maid = true;
|
|
24
|
+
_instance = true;
|
|
25
|
+
_remoteObjects = true;
|
|
26
|
+
_remoteFolder = true;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
local REMOTE_EVENT_SUFFIX = "Event"
|
|
30
|
+
local REMOTE_FUNCTION_SUFFIX = "Function"
|
|
31
|
+
|
|
32
|
+
local Remoting = {}
|
|
33
|
+
Remoting.ClassName = "Remoting"
|
|
34
|
+
Remoting.__index = Remoting
|
|
35
|
+
|
|
36
|
+
--[=[
|
|
37
|
+
Creates a new remoting instance
|
|
38
|
+
|
|
39
|
+
@param instance Instance
|
|
40
|
+
@param name string
|
|
41
|
+
@return Remoting
|
|
42
|
+
]=]
|
|
43
|
+
function Remoting.new(instance, name)
|
|
44
|
+
assert(typeof(instance) == "Instance", "Bad instance")
|
|
45
|
+
assert(type(name) == "string", "Bad name")
|
|
46
|
+
|
|
47
|
+
local self = setmetatable({}, Remoting)
|
|
48
|
+
|
|
49
|
+
self._maid = Maid.new()
|
|
50
|
+
|
|
51
|
+
self._instance = assert(instance, "No instance")
|
|
52
|
+
self._name = assert(name, "No name")
|
|
53
|
+
|
|
54
|
+
self._remoteFolderName = string.format("%sRemotes", self._name)
|
|
55
|
+
self._remoteObjects = {}
|
|
56
|
+
|
|
57
|
+
return self
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
function Remoting:__index(index)
|
|
61
|
+
if Remoting[index] then
|
|
62
|
+
return Remoting[index]
|
|
63
|
+
elseif RAW_MEMBERS[index] then
|
|
64
|
+
return rawget(self, index)
|
|
65
|
+
else
|
|
66
|
+
return RemotingMember.new(self, index)
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
--[=[
|
|
71
|
+
Connects to a given remote event.
|
|
72
|
+
|
|
73
|
+
@param memberName string
|
|
74
|
+
@param callback string
|
|
75
|
+
@return MaidTask
|
|
76
|
+
]=]
|
|
77
|
+
function Remoting:Connect(memberName, callback)
|
|
78
|
+
assert(type(memberName) == "string", "Bad memberName")
|
|
79
|
+
assert(type(callback) == "function", "Bad callback")
|
|
80
|
+
|
|
81
|
+
local connectMaid = Maid.new()
|
|
82
|
+
|
|
83
|
+
if RunService:IsServer() then
|
|
84
|
+
local remoteEvent = self:_getOrCreateRemoteEvent(memberName)
|
|
85
|
+
connectMaid:GiveTask(remoteEvent.OnServerEvent:Connect(callback))
|
|
86
|
+
|
|
87
|
+
-- TODO: Cleanup if nothing else is expecting this
|
|
88
|
+
elseif RunService:IsClient() then
|
|
89
|
+
connectMaid:GiveTask(self:_observeRemoteEventBrio(memberName):Subscribe(function(brio)
|
|
90
|
+
if brio:IsDead() then
|
|
91
|
+
return
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
local remoteEvent = brio:GetValue()
|
|
95
|
+
local maid = brio:ToMaid()
|
|
96
|
+
|
|
97
|
+
maid:GiveTask(remoteEvent.OnClientEvent:Connect(callback))
|
|
98
|
+
end))
|
|
99
|
+
|
|
100
|
+
-- TODO: Warn if remote event doesn't exist
|
|
101
|
+
else
|
|
102
|
+
error("[Remoting.Connect] - Unknown RunService state")
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
self._maid[connectMaid] = connectMaid
|
|
106
|
+
connectMaid:GiveTask(function()
|
|
107
|
+
self._maid[connectMaid] = nil
|
|
108
|
+
end)
|
|
109
|
+
|
|
110
|
+
return connectMaid
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
--[=[
|
|
114
|
+
If on the server, creates a new [RemoteFunction] with the name `memberName` and binds the
|
|
115
|
+
invoke. On the client, it waits for the event to exist and then binds to it.
|
|
116
|
+
|
|
117
|
+
@param memberName string
|
|
118
|
+
@param callback any
|
|
119
|
+
]=]
|
|
120
|
+
function Remoting:Bind(memberName, callback)
|
|
121
|
+
assert(type(memberName) == "string", "Bad memberName")
|
|
122
|
+
assert(type(callback) == "function", "Bad callback")
|
|
123
|
+
|
|
124
|
+
local bindMaid = Maid.new()
|
|
125
|
+
|
|
126
|
+
if RunService:IsServer() then
|
|
127
|
+
local remoteFunction = self:_getOrCreateRemoteFunction(memberName)
|
|
128
|
+
remoteFunction.OnServerInvoke = self:_translateCallback(bindMaid, memberName, callback)
|
|
129
|
+
|
|
130
|
+
-- TODO: Cleanup if nothing else is expecting this
|
|
131
|
+
elseif RunService:IsClient() then
|
|
132
|
+
bindMaid:GiveTask(self:_observeRemoteFunctionBrio():Subscribe(function(brio)
|
|
133
|
+
if brio:IsDead() then
|
|
134
|
+
return
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
local remoteFunction = brio:GetValue()
|
|
138
|
+
local maid = brio:ToMaid()
|
|
139
|
+
|
|
140
|
+
remoteFunction.OnClientInvoke = self:_translateCallback(maid, memberName, callback)
|
|
141
|
+
end))
|
|
142
|
+
|
|
143
|
+
-- TODO: Warn if remote function doesn't exist
|
|
144
|
+
else
|
|
145
|
+
error("[Remoting.Bind] - Unknown RunService state")
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
self._maid[bindMaid] = bindMaid
|
|
149
|
+
bindMaid:GiveTask(function()
|
|
150
|
+
self._maid[bindMaid] = nil
|
|
151
|
+
end)
|
|
152
|
+
|
|
153
|
+
return bindMaid
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
--[=[
|
|
157
|
+
Forward declares an event on the remoting object
|
|
158
|
+
|
|
159
|
+
@param memberName string
|
|
160
|
+
]=]
|
|
161
|
+
function Remoting:DeclareEvent(memberName)
|
|
162
|
+
assert(type(memberName) == "string", "Bad memberName")
|
|
163
|
+
|
|
164
|
+
if RunService:IsServer() then
|
|
165
|
+
self:_getOrCreateRemoteEvent(memberName)
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
--[=[
|
|
170
|
+
Forward declares an event on the remoting object
|
|
171
|
+
|
|
172
|
+
@param memberName string
|
|
173
|
+
]=]
|
|
174
|
+
function Remoting:DeclareMethod(memberName)
|
|
175
|
+
assert(type(memberName) == "string", "Bad memberName")
|
|
176
|
+
|
|
177
|
+
if RunService:IsServer() then
|
|
178
|
+
self:_getOrCreateRemoteFunction(memberName)
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
function Remoting:_translateCallback(maid, memberName, callback)
|
|
183
|
+
local alive = true
|
|
184
|
+
maid:GiveTask(function()
|
|
185
|
+
alive = false
|
|
186
|
+
end)
|
|
187
|
+
|
|
188
|
+
return function(...)
|
|
189
|
+
if not alive then
|
|
190
|
+
error(string.format("[Remoting] - Function for %s is disconnected and can't be called", memberName))
|
|
191
|
+
return
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
local results = table.pack(callback(...))
|
|
195
|
+
|
|
196
|
+
local hasPromise = false
|
|
197
|
+
for i=1, results.n do
|
|
198
|
+
if Promise.isPromise(results[i]) then
|
|
199
|
+
hasPromise = true
|
|
200
|
+
break
|
|
201
|
+
end
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
if hasPromise then
|
|
205
|
+
local promise
|
|
206
|
+
if results.n == 1 then
|
|
207
|
+
promise = results[1]
|
|
208
|
+
else
|
|
209
|
+
local data = {}
|
|
210
|
+
for i=1, results.n do
|
|
211
|
+
table.insert(data, results[i])
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
promise = PromiseUtils.combine(data)
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
promise = maid:GivePromise(promise)
|
|
218
|
+
|
|
219
|
+
local yielded = table.pack(promise:Wait())
|
|
220
|
+
return table.unpack(yielded, 1, yielded.n)
|
|
221
|
+
else
|
|
222
|
+
return ...
|
|
223
|
+
end
|
|
224
|
+
end
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
--[=[
|
|
228
|
+
Fires the client with the individual request. Should consider this syntax instead.
|
|
229
|
+
|
|
230
|
+
```lua
|
|
231
|
+
local remoting = Remoting.new(workspace, "Test")
|
|
232
|
+
remoting.Event:FireClient(otherPlayer, ...)
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
Equivalent of [RemoteFunction.FireClient].
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
@param memberName string
|
|
239
|
+
@param player Player
|
|
240
|
+
@param ... any
|
|
241
|
+
]=]
|
|
242
|
+
function Remoting:FireClient(memberName, player, ...)
|
|
243
|
+
assert(type(memberName) == "string", "Bad memberName")
|
|
244
|
+
assert(typeof(player) == "Instance" and player:IsA("Player"), "Bad player")
|
|
245
|
+
assert(RunService:IsServer(), "FireClient must be called on server")
|
|
246
|
+
|
|
247
|
+
local remoteEvent = self:_getOrCreateRemoteEvent(memberName)
|
|
248
|
+
remoteEvent:FireClient(player, ...)
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
--[=[
|
|
252
|
+
Invokes the client, yielding as needed
|
|
253
|
+
|
|
254
|
+
Equivalent of [RemoteFunction.InvokeClient].
|
|
255
|
+
|
|
256
|
+
@server
|
|
257
|
+
@param memberName string
|
|
258
|
+
@param player Player
|
|
259
|
+
@param ... any
|
|
260
|
+
]=]
|
|
261
|
+
function Remoting:InvokeClient(memberName, player, ...)
|
|
262
|
+
assert(type(memberName) == "string", "Bad memberName")
|
|
263
|
+
assert(typeof(player) == "Instance" and player:IsA("Player"), "Bad player")
|
|
264
|
+
assert(RunService:IsServer(), "InvokeClient must be called on server")
|
|
265
|
+
|
|
266
|
+
local remoteEvent = self:_getOrCreateRemoteFunction(memberName)
|
|
267
|
+
remoteEvent:InvokeClient(player, ...)
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
--[=[
|
|
271
|
+
Fires all clients with the event.
|
|
272
|
+
|
|
273
|
+
Equivalent of [RemoteEvent.FireAllClients].
|
|
274
|
+
|
|
275
|
+
@server
|
|
276
|
+
@param memberName string
|
|
277
|
+
@param ... any
|
|
278
|
+
]=]
|
|
279
|
+
function Remoting:FireAllClients(memberName, ...)
|
|
280
|
+
assert(type(memberName) == "string", "Bad memberName")
|
|
281
|
+
assert(RunService:IsServer(), "FireAllClients must be called on server")
|
|
282
|
+
|
|
283
|
+
local remoteEvent = self:_getOrCreateRemoteEvent(memberName)
|
|
284
|
+
remoteEvent:FireAllClients(memberName, ...)
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
--[=[
|
|
288
|
+
Fires the server
|
|
289
|
+
|
|
290
|
+
@client
|
|
291
|
+
@param memberName string
|
|
292
|
+
@param ... any
|
|
293
|
+
]=]
|
|
294
|
+
function Remoting:FireServer(memberName, ...)
|
|
295
|
+
assert(type(memberName) == "string", "Bad memberName")
|
|
296
|
+
assert(RunService:IsClient(), "FireServer must be called on server")
|
|
297
|
+
|
|
298
|
+
self:PromiseFireServer(memberName, ...)
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
--[=[
|
|
302
|
+
Fires the server, resolving the promise once it is fired.
|
|
303
|
+
|
|
304
|
+
@client
|
|
305
|
+
@param memberName string
|
|
306
|
+
@param ... any
|
|
307
|
+
@return Promise
|
|
308
|
+
]=]
|
|
309
|
+
function Remoting:PromiseFireServer(memberName, ...)
|
|
310
|
+
assert(type(memberName) == "string", "Bad memberName")
|
|
311
|
+
assert(RunService:IsClient(), "PromiseFireServer must be called on server")
|
|
312
|
+
|
|
313
|
+
local fireMaid = Maid.new()
|
|
314
|
+
local args = table.pack(...)
|
|
315
|
+
|
|
316
|
+
local promise = self:_promiseRemoteEvent(fireMaid, memberName)
|
|
317
|
+
:Then(function(remoteEvent)
|
|
318
|
+
remoteEvent:FireServer(table.unpack(args, 1, args.n))
|
|
319
|
+
end)
|
|
320
|
+
|
|
321
|
+
promise:Finally(function()
|
|
322
|
+
self._maid[fireMaid] = nil
|
|
323
|
+
end)
|
|
324
|
+
self._maid[fireMaid] = fireMaid
|
|
325
|
+
fireMaid:GiveTask(function()
|
|
326
|
+
self._maid[fireMaid] = nil
|
|
327
|
+
end)
|
|
328
|
+
|
|
329
|
+
-- TODO: Warn if remote event doesn't exist
|
|
330
|
+
|
|
331
|
+
return promise
|
|
332
|
+
end
|
|
333
|
+
|
|
334
|
+
--[=[
|
|
335
|
+
Invokes the server from the client
|
|
336
|
+
|
|
337
|
+
@client
|
|
338
|
+
@param memberName string
|
|
339
|
+
@param ... any
|
|
340
|
+
@return any
|
|
341
|
+
]=]
|
|
342
|
+
function Remoting:InvokeServer(memberName, ...)
|
|
343
|
+
assert(type(memberName) == "string", "Bad memberName")
|
|
344
|
+
|
|
345
|
+
return self:PromiseInvokeServer(memberName, ...):Wait()
|
|
346
|
+
end
|
|
347
|
+
|
|
348
|
+
--[=[
|
|
349
|
+
Invokes the server from the client
|
|
350
|
+
|
|
351
|
+
@client
|
|
352
|
+
@param memberName string
|
|
353
|
+
@param ... any
|
|
354
|
+
@return Promise<any>
|
|
355
|
+
]=]
|
|
356
|
+
function Remoting:PromiseInvokeServer(memberName, ...)
|
|
357
|
+
assert(type(memberName) == "string", "Bad memberName")
|
|
358
|
+
|
|
359
|
+
local invokeMaid = Maid.new()
|
|
360
|
+
local args = table.pack(...)
|
|
361
|
+
|
|
362
|
+
local promise = self:_promiseRemoteFunction(invokeMaid, memberName)
|
|
363
|
+
:Then(function(remoteFunction)
|
|
364
|
+
return invokeMaid:GivePromise(RemoteFunctionUtils.promiseInvokeServer(remoteFunction, table.unpack(args, 1, args.n)))
|
|
365
|
+
end)
|
|
366
|
+
|
|
367
|
+
promise:Finally(function()
|
|
368
|
+
self._maid[invokeMaid] = nil
|
|
369
|
+
end)
|
|
370
|
+
self._maid[invokeMaid] = invokeMaid
|
|
371
|
+
invokeMaid:GiveTask(function()
|
|
372
|
+
self._maid[invokeMaid] = nil
|
|
373
|
+
end)
|
|
374
|
+
|
|
375
|
+
-- TODO: Warn if remote function doesn't exist
|
|
376
|
+
|
|
377
|
+
return promise
|
|
378
|
+
end
|
|
379
|
+
|
|
380
|
+
--[=[
|
|
381
|
+
Invokes the client from the server
|
|
382
|
+
|
|
383
|
+
@server
|
|
384
|
+
@param memberName string
|
|
385
|
+
@param player Player
|
|
386
|
+
@param ... any
|
|
387
|
+
@return Promise<any>
|
|
388
|
+
]=]
|
|
389
|
+
function Remoting:PromiseInvokeClient(memberName, player, ...)
|
|
390
|
+
assert(type(memberName) == "string", "Bad memberName")
|
|
391
|
+
assert(typeof(player) == "Instance" and player:IsA("Player"), "Bad player")
|
|
392
|
+
|
|
393
|
+
local remoteFunction = self:_getOrCreateRemoteFunction(memberName)
|
|
394
|
+
|
|
395
|
+
local invokeMaid = Maid.new()
|
|
396
|
+
|
|
397
|
+
local promise = invokeMaid:GivePromise(RemoteFunctionUtils.promiseInvokeClient(remoteFunction, player, ...))
|
|
398
|
+
promise:Finally(function()
|
|
399
|
+
self._maid[invokeMaid] = nil
|
|
400
|
+
end)
|
|
401
|
+
|
|
402
|
+
self._maid[invokeMaid] = invokeMaid
|
|
403
|
+
invokeMaid:GiveTask(function()
|
|
404
|
+
self._maid[invokeMaid] = nil
|
|
405
|
+
end)
|
|
406
|
+
|
|
407
|
+
return promise
|
|
408
|
+
end
|
|
409
|
+
|
|
410
|
+
function Remoting:_ensureFolder()
|
|
411
|
+
assert(RunService:IsServer(), "Folder should only be created on server")
|
|
412
|
+
|
|
413
|
+
if self._remoteFolder then
|
|
414
|
+
return self._remoteFolder
|
|
415
|
+
end
|
|
416
|
+
|
|
417
|
+
self._remoteFolder = Instance.new("Folder")
|
|
418
|
+
self._remoteFolder.Name = self._remoteFolderName
|
|
419
|
+
self._remoteFolder.Archivable = false
|
|
420
|
+
self._remoteFolder.Parent = self._instance
|
|
421
|
+
|
|
422
|
+
return self._remoteFolder
|
|
423
|
+
end
|
|
424
|
+
|
|
425
|
+
function Remoting:_observeRemoteFunctionBrio(memberName)
|
|
426
|
+
assert(type(memberName) == "string", "Bad memberName")
|
|
427
|
+
|
|
428
|
+
local remoteFunctionName = self:_getMemberName(memberName, REMOTE_FUNCTION_SUFFIX)
|
|
429
|
+
|
|
430
|
+
return self:_observeFolderBrio():Pipe({
|
|
431
|
+
RxBrioUtils.switchMapBrio(function(item)
|
|
432
|
+
return RxInstanceUtils.observeLastNamedChildBrio(item, "RemoteFunction", remoteFunctionName)
|
|
433
|
+
end)
|
|
434
|
+
})
|
|
435
|
+
end
|
|
436
|
+
|
|
437
|
+
function Remoting:_observeRemoteEventBrio(memberName)
|
|
438
|
+
assert(type(memberName) == "string", "Bad memberName")
|
|
439
|
+
|
|
440
|
+
local remoteFunctionName = self:_getMemberName(memberName, REMOTE_EVENT_SUFFIX)
|
|
441
|
+
|
|
442
|
+
return self:_observeFolderBrio():Pipe({
|
|
443
|
+
RxBrioUtils.switchMapBrio(function(item)
|
|
444
|
+
return RxInstanceUtils.observeLastNamedChildBrio(item, "RemoteEvent", remoteFunctionName)
|
|
445
|
+
end)
|
|
446
|
+
})
|
|
447
|
+
end
|
|
448
|
+
|
|
449
|
+
function Remoting:_promiseFolder(maid)
|
|
450
|
+
return maid:GivePromise(promiseChild(self._instance, self._remoteFolderName, 5))
|
|
451
|
+
end
|
|
452
|
+
|
|
453
|
+
function Remoting:_promiseRemoteEvent(maid, memberName)
|
|
454
|
+
local remoteEventName = self:_getMemberName(memberName, REMOTE_EVENT_SUFFIX)
|
|
455
|
+
return self:_promiseFolder(maid)
|
|
456
|
+
:Then(function(folder)
|
|
457
|
+
return maid:GivePromise(promiseChild(folder, remoteEventName, 5))
|
|
458
|
+
end)
|
|
459
|
+
end
|
|
460
|
+
|
|
461
|
+
function Remoting:_promiseRemoteFunction(maid, memberName)
|
|
462
|
+
local remoteEventName = self:_getMemberName(memberName, REMOTE_FUNCTION_SUFFIX)
|
|
463
|
+
return self:_promiseFolder(maid)
|
|
464
|
+
:Then(function(folder)
|
|
465
|
+
return maid:GivePromise(promiseChild(folder, remoteEventName, 5))
|
|
466
|
+
end)
|
|
467
|
+
end
|
|
468
|
+
|
|
469
|
+
|
|
470
|
+
function Remoting:_observeFolderBrio()
|
|
471
|
+
assert(self._instance, "Not initialized")
|
|
472
|
+
|
|
473
|
+
return RxInstanceUtils.observeLastNamedChildBrio(self._instance, "Folder", self._remoteFolderName)
|
|
474
|
+
end
|
|
475
|
+
|
|
476
|
+
function Remoting:_getOrCreateRemoteFunction(memberName)
|
|
477
|
+
assert(type(memberName) == "string", "Bad memberName")
|
|
478
|
+
|
|
479
|
+
local remoteFunctionName = self:_getMemberName(memberName, REMOTE_FUNCTION_SUFFIX)
|
|
480
|
+
|
|
481
|
+
if self._remoteObjects[remoteFunctionName] then
|
|
482
|
+
return self._remoteObjects[remoteFunctionName]
|
|
483
|
+
end
|
|
484
|
+
|
|
485
|
+
local folder = self:_ensureFolder()
|
|
486
|
+
|
|
487
|
+
local remoteFunction = Instance.new("RemoteFunction")
|
|
488
|
+
remoteFunction.Name = remoteFunctionName
|
|
489
|
+
remoteFunction.Archivable = false
|
|
490
|
+
remoteFunction.Parent = folder
|
|
491
|
+
|
|
492
|
+
self._remoteObjects[remoteFunctionName] = remoteFunction
|
|
493
|
+
self._maid[remoteFunction] = remoteFunction
|
|
494
|
+
|
|
495
|
+
return remoteFunction
|
|
496
|
+
end
|
|
497
|
+
|
|
498
|
+
function Remoting:_getOrCreateRemoteEvent(memberName)
|
|
499
|
+
assert(type(memberName) == "string", "Bad memberName")
|
|
500
|
+
|
|
501
|
+
local remoteEventName = self:_getMemberName(memberName, REMOTE_EVENT_SUFFIX)
|
|
502
|
+
|
|
503
|
+
if self._remoteObjects[remoteEventName] then
|
|
504
|
+
return self._remoteObjects[remoteEventName]
|
|
505
|
+
end
|
|
506
|
+
|
|
507
|
+
local folder = self:_ensureFolder()
|
|
508
|
+
|
|
509
|
+
local remoteEvent = Instance.new("RemoteEvent")
|
|
510
|
+
remoteEvent.Name = remoteEventName
|
|
511
|
+
remoteEvent.Archivable = false
|
|
512
|
+
remoteEvent.Parent = folder
|
|
513
|
+
|
|
514
|
+
self._maid[remoteEvent] = remoteEvent
|
|
515
|
+
self._remoteObjects[remoteEventName] = remoteEvent
|
|
516
|
+
|
|
517
|
+
return remoteEvent
|
|
518
|
+
end
|
|
519
|
+
|
|
520
|
+
function Remoting:_getMemberName(memberName, objectType)
|
|
521
|
+
return memberName .. objectType
|
|
522
|
+
end
|
|
523
|
+
|
|
524
|
+
--[=[
|
|
525
|
+
Cleans up the remoting object
|
|
526
|
+
]=]
|
|
527
|
+
function Remoting:Destroy()
|
|
528
|
+
self._maid:DoCleaning()
|
|
529
|
+
setmetatable(self, nil)
|
|
530
|
+
end
|
|
531
|
+
|
|
532
|
+
return Remoting
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
--[=[
|
|
2
|
+
Helper class for the [Remoting] object which allows more natural syntax
|
|
3
|
+
to be used against the remoting API surface.
|
|
4
|
+
|
|
5
|
+
@class RemotingMember
|
|
6
|
+
]=]
|
|
7
|
+
|
|
8
|
+
local RunService = game:GetService("RunService")
|
|
9
|
+
|
|
10
|
+
local RemotingMember = {}
|
|
11
|
+
RemotingMember.ClassName = "RemotingMember"
|
|
12
|
+
RemotingMember.__index = RemotingMember
|
|
13
|
+
|
|
14
|
+
--[=[
|
|
15
|
+
Constructs a new RemotingMember
|
|
16
|
+
|
|
17
|
+
@param remoting Remoting
|
|
18
|
+
@param memberName string
|
|
19
|
+
@return RemotingMember
|
|
20
|
+
]=]
|
|
21
|
+
function RemotingMember.new(remoting, memberName)
|
|
22
|
+
local self = setmetatable({}, RemotingMember)
|
|
23
|
+
|
|
24
|
+
self._remoting = assert(remoting, "No remoting")
|
|
25
|
+
self._memberName = assert(memberName, "No memberName")
|
|
26
|
+
|
|
27
|
+
return self
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
--[=[
|
|
31
|
+
Binds to the member.
|
|
32
|
+
|
|
33
|
+
On the server this will create the remote function. On the client
|
|
34
|
+
this will connect to the remote event once it's created.
|
|
35
|
+
|
|
36
|
+
@param callback function
|
|
37
|
+
@return MaidTask
|
|
38
|
+
]=]
|
|
39
|
+
function RemotingMember:Bind(callback)
|
|
40
|
+
assert(type(callback) == "function", "Bad callback")
|
|
41
|
+
|
|
42
|
+
return self._remoting:Bind(self._memberName, callback)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
--[=[
|
|
46
|
+
Connects to the equivalent of a RemoteEvent for this member.
|
|
47
|
+
|
|
48
|
+
On the server this will create the remote event. On the client
|
|
49
|
+
this will connect to the remote event once it's created.
|
|
50
|
+
|
|
51
|
+
See [Remoting.Connect] for additional details.
|
|
52
|
+
|
|
53
|
+
@param callback function
|
|
54
|
+
@return MaidTask
|
|
55
|
+
]=]
|
|
56
|
+
function RemotingMember:Connect(callback)
|
|
57
|
+
assert(type(callback) == "function", "Bad callback")
|
|
58
|
+
|
|
59
|
+
return self._remoting:Connect(self._memberName, callback)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
--[=[
|
|
63
|
+
Forward declares an event on the remoting object
|
|
64
|
+
]=]
|
|
65
|
+
function RemotingMember:DeclareEvent()
|
|
66
|
+
return self._remoting:DeclareEvent(self._memberName)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
--[=[
|
|
70
|
+
Forward declares a method on the remoting object
|
|
71
|
+
]=]
|
|
72
|
+
function RemotingMember:DeclareMethod()
|
|
73
|
+
return self._remoting:DeclareMethod(self._memberName)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
--[=[
|
|
77
|
+
Fires the remote event on the server
|
|
78
|
+
|
|
79
|
+
@client
|
|
80
|
+
@param ... any
|
|
81
|
+
]=]
|
|
82
|
+
function RemotingMember:FireServer(...)
|
|
83
|
+
assert(RunService:IsClient(), "FireServer must be called on client")
|
|
84
|
+
self._remoting:FireServer(self._memberName, ...)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
--[=[
|
|
88
|
+
Invokes the server from the client
|
|
89
|
+
|
|
90
|
+
@client
|
|
91
|
+
@param ... any
|
|
92
|
+
]=]
|
|
93
|
+
function RemotingMember:InvokeServer(...)
|
|
94
|
+
assert(RunService:IsClient(), "InvokeServer must be called on client")
|
|
95
|
+
|
|
96
|
+
return self._remoting:InvokeServer(self._memberName, ...)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
--[=[
|
|
100
|
+
Invokes the client from the server.
|
|
101
|
+
|
|
102
|
+
@client
|
|
103
|
+
@param ... any
|
|
104
|
+
]=]
|
|
105
|
+
function RemotingMember:PromiseInvokeServer(...)
|
|
106
|
+
assert(RunService:IsClient(), "PromiseInvokeServer must be called on client")
|
|
107
|
+
|
|
108
|
+
return self._remoting:PromiseInvokeServer(self._memberName, ...)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
--[=[
|
|
112
|
+
Fires the server from the client. Promise resolves once the event is sent.
|
|
113
|
+
|
|
114
|
+
@client
|
|
115
|
+
@param ... any
|
|
116
|
+
@return Promise
|
|
117
|
+
]=]
|
|
118
|
+
function RemotingMember:PromiseFireServer(...)
|
|
119
|
+
assert(RunService:IsClient(), "PromiseInvokeServer must be called on client")
|
|
120
|
+
|
|
121
|
+
return self._remoting:PromiseFireServer(self._memberName, ...)
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
--[=[
|
|
126
|
+
Invokes the client from the server.
|
|
127
|
+
|
|
128
|
+
See [Remoting.PromiseInvokeClient].
|
|
129
|
+
|
|
130
|
+
@server
|
|
131
|
+
@param player Player
|
|
132
|
+
@param ... any
|
|
133
|
+
@return Promise<any>
|
|
134
|
+
]=]
|
|
135
|
+
function RemotingMember:PromiseInvokeClient(player, ...)
|
|
136
|
+
assert(typeof(player) == "Instance" and player:IsA("Player"), "Bad player")
|
|
137
|
+
assert(RunService:IsServer(), "PromiseInvokeClient must be called on client")
|
|
138
|
+
|
|
139
|
+
return self._remoting:PromiseInvokeClient(self._memberName, player, ...)
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
--[=[
|
|
143
|
+
Invokes the client from the server
|
|
144
|
+
|
|
145
|
+
See [Remoting.InvokeClient].
|
|
146
|
+
|
|
147
|
+
@server
|
|
148
|
+
@param player Player
|
|
149
|
+
@param ... any
|
|
150
|
+
@return ... any
|
|
151
|
+
]=]
|
|
152
|
+
function RemotingMember:InvokeClient(player, ...)
|
|
153
|
+
assert(typeof(player) == "Instance" and player:IsA("Player"), "Bad player")
|
|
154
|
+
assert(RunService:IsServer(), "InvokeClient must be called on client")
|
|
155
|
+
|
|
156
|
+
return self._remoting:InvokeClient(self._memberName, player, ...)
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
--[=[
|
|
160
|
+
Fires all clients.
|
|
161
|
+
|
|
162
|
+
See [Remoting.FireAllClients].
|
|
163
|
+
|
|
164
|
+
@server
|
|
165
|
+
@param ... any
|
|
166
|
+
]=]
|
|
167
|
+
function RemotingMember:FireAllClients(...)
|
|
168
|
+
assert(RunService:IsServer(), "FireAllClients must be called on client")
|
|
169
|
+
|
|
170
|
+
self._remoting:FireAllClients(self._memberName, ...)
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
--[=[
|
|
174
|
+
Fires the client with the data
|
|
175
|
+
|
|
176
|
+
See [Remoting.FireClient].
|
|
177
|
+
|
|
178
|
+
@server
|
|
179
|
+
@param player Instance
|
|
180
|
+
@param ... any
|
|
181
|
+
]=]
|
|
182
|
+
function RemotingMember:FireClient(player, ...)
|
|
183
|
+
assert(RunService:IsServer(), "FireClient must be called on client")
|
|
184
|
+
assert(typeof(player) == "Instance" and player:IsA("Player"), "Bad player")
|
|
185
|
+
|
|
186
|
+
self._remoting:FireClient(self._memberName, player, ...)
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
return RemotingMember
|