@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 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.5.0",
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/promise": "^6.5.0",
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": "3306212248c310731931ad45d8b86dc7247f2a5d"
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