@quenty/remoting 12.5.0 → 12.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
+ # [12.6.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/remoting@12.5.0...@quenty/remoting@12.6.0) (2024-09-12)
7
+
8
+
9
+ ### Features
10
+
11
+ * Add new remoting .Server and .Client methods ([89862e8](https://github.com/Quenty/NevermoreEngine/commit/89862e852456ada3a1b1eefde682229c4ca033fa))
12
+ * Declarative remoting realms allows for safer calls ([7264fd1](https://github.com/Quenty/NevermoreEngine/commit/7264fd1eb7b9d812a7383ec62db63ed90e78472a))
13
+
14
+
15
+
16
+
17
+
6
18
  # [12.5.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/remoting@12.4.0...@quenty/remoting@12.5.0) (2024-08-09)
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": "12.5.0",
3
+ "version": "12.6.0",
4
4
  "description": "Global remoting retrieval system for Roblox (RemoteFunctions/RemoteEvents)",
5
5
  "keywords": [
6
6
  "Roblox",
@@ -26,17 +26,18 @@
26
26
  "Quenty"
27
27
  ],
28
28
  "dependencies": {
29
- "@quenty/brio": "^14.4.0",
30
- "@quenty/instanceutils": "^13.4.0",
31
- "@quenty/loader": "^10.3.0",
32
- "@quenty/maid": "^3.2.0",
33
- "@quenty/promise": "^10.3.0",
34
- "@quenty/remotefunctionutils": "^10.3.0",
35
- "@quenty/rx": "^13.4.0",
29
+ "@quenty/brio": "^14.5.0",
30
+ "@quenty/instanceutils": "^13.5.0",
31
+ "@quenty/loader": "^10.4.0",
32
+ "@quenty/maid": "^3.3.0",
33
+ "@quenty/promise": "^10.4.0",
34
+ "@quenty/promisemaid": "^5.4.0",
35
+ "@quenty/remotefunctionutils": "^10.4.0",
36
+ "@quenty/rx": "^13.5.0",
36
37
  "@quenty/table": "^3.5.0"
37
38
  },
38
39
  "publishConfig": {
39
40
  "access": "public"
40
41
  },
41
- "gitHead": "ba466bdbc05c42fb607cf5e228c16339201d21d7"
42
+ "gitHead": "fb172906f3ee725269ec1e5f4daf9dca227e729d"
42
43
  }
@@ -7,8 +7,8 @@
7
7
 
8
8
  local require = require(script.Parent.loader).load(script)
9
9
 
10
- local RunService = game:GetService("RunService")
11
10
  local Players = game:GetService("Players")
11
+ local RunService = game:GetService("RunService")
12
12
 
13
13
  local Maid = require("Maid")
14
14
  local Promise = require("Promise")
@@ -16,6 +16,8 @@ local promiseChild = require("promiseChild")
16
16
  local PromiseUtils = require("PromiseUtils")
17
17
  local RemoteFunctionUtils = require("RemoteFunctionUtils")
18
18
  local RemotingMember = require("RemotingMember")
19
+ local RemotingRealms = require("RemotingRealms")
20
+ local RemotingRealmUtils = require("RemotingRealmUtils")
19
21
  local RxBrioUtils = require("RxBrioUtils")
20
22
  local RxInstanceUtils = require("RxInstanceUtils")
21
23
 
@@ -24,7 +26,8 @@ local RAW_MEMBERS = {
24
26
  _maid = true;
25
27
  _instance = true;
26
28
  _remoteObjects = true;
27
- _remoteFolder = true;
29
+ _container = true;
30
+ _defaultRemotingRealm = true;
28
31
  }
29
32
 
30
33
  local REMOTE_EVENT_SUFFIX = "Event"
@@ -34,16 +37,32 @@ local Remoting = {}
34
37
  Remoting.ClassName = "Remoting"
35
38
  Remoting.__index = Remoting
36
39
 
40
+ Remoting.Realms = RemotingRealms
41
+
42
+ Remoting.Server = {
43
+ new = function(instance, name)
44
+ return Remoting.new(instance, name, RemotingRealms.SERVER)
45
+ end;
46
+ }
47
+
48
+ Remoting.Client = {
49
+ new = function(instance, name)
50
+ return Remoting.new(instance, name, RemotingRealms.CLIENT)
51
+ end;
52
+ }
53
+
37
54
  --[=[
38
55
  Creates a new remoting instance
39
56
 
40
57
  @param instance Instance
41
58
  @param name string
59
+ @param remotingRealm RemotingRealm?
42
60
  @return Remoting
43
61
  ]=]
44
- function Remoting.new(instance, name)
62
+ function Remoting.new(instance, name, remotingRealm)
45
63
  assert(typeof(instance) == "Instance", "Bad instance")
46
64
  assert(type(name) == "string", "Bad name")
65
+ assert(RemotingRealmUtils.isRemotingRealm(remotingRealm) or remotingRealm == nil, "Bad remotingRealm")
47
66
 
48
67
  local self = setmetatable({}, Remoting)
49
68
 
@@ -51,6 +70,8 @@ function Remoting.new(instance, name)
51
70
 
52
71
  self._instance = assert(instance, "No instance")
53
72
  self._name = assert(name, "No name")
73
+ self._remotingRealm = remotingRealm or RemotingRealmUtils.inferRemotingRealm()
74
+ self._useDummyObject = not RunService:IsRunning()
54
75
 
55
76
  self._remoteFolderName = string.format("%sRemotes", self._name)
56
77
  self._remoteObjects = {}
@@ -64,7 +85,7 @@ function Remoting:__index(index)
64
85
  elseif RAW_MEMBERS[index] then
65
86
  return rawget(self, index)
66
87
  else
67
- return RemotingMember.new(self, index)
88
+ return RemotingMember.new(self, index, self._remotingRealm)
68
89
  end
69
90
  end
70
91
 
@@ -81,28 +102,47 @@ function Remoting:Connect(memberName, callback)
81
102
 
82
103
  local connectMaid = Maid.new()
83
104
 
84
- if RunService:IsServer() then
85
- local remoteEvent = self:_getOrCreateRemoteEvent(memberName)
86
- connectMaid:GiveTask(remoteEvent.OnServerEvent:Connect(callback))
105
+ if self._remotingRealm == RemotingRealms.SERVER then
106
+ if self._useDummyObject then
107
+ self:DeclareEvent(memberName)
108
+
109
+ self:_getOrCreateRemoteEvent(self:_getDummyMemberName(memberName, "OnClientEvent"))
110
+ local bindableEvent = self:_getOrCreateRemoteEvent(self:_getDummyMemberName(memberName, "OnServerEvent"))
111
+ connectMaid:GiveTask(bindableEvent.Event:Connect(callback))
112
+ else
113
+ local remoteEvent = self:_getOrCreateRemoteEvent(memberName)
114
+ connectMaid:GiveTask(remoteEvent.OnServerEvent:Connect(callback))
115
+ end
87
116
 
88
117
  -- TODO: Cleanup if nothing else is expecting this
89
- elseif RunService:IsClient() then
118
+ elseif self._remotingRealm == RemotingRealms.CLIENT then
90
119
  connectMaid._warning = task.delay(5, function()
91
120
  warn(string.format("[Remoting] - Failed to find RemoteEvent %q, event may never connect", self:_getDebugMemberName(memberName)))
92
121
  end)
93
122
 
94
- connectMaid:GiveTask(self:_observeRemoteEventBrio(memberName):Subscribe(function(brio)
95
- if brio:IsDead() then
96
- return
97
- end
123
+ if self._useDummyObject then
124
+ connectMaid:GiveTask(self:_observeRemoteEventBrio(self:_getDummyMemberName(memberName, "OnClientEvent")):Subscribe(function(brio)
125
+ if brio:IsDead() then
126
+ return
127
+ end
128
+
129
+ connectMaid._warning = nil
98
130
 
99
- connectMaid._warning = nil
131
+ local maid, remoteEvent = brio:ToMaidAndValue()
132
+ maid:GiveTask(remoteEvent.Event:Connect(callback))
133
+ end))
134
+ else
135
+ connectMaid:GiveTask(self:_observeRemoteEventBrio(memberName):Subscribe(function(brio)
136
+ if brio:IsDead() then
137
+ return
138
+ end
100
139
 
101
- local remoteEvent = brio:GetValue()
102
- local maid = brio:ToMaid()
140
+ connectMaid._warning = nil
103
141
 
104
- maid:GiveTask(remoteEvent.OnClientEvent:Connect(callback))
105
- end))
142
+ local maid, remoteEvent = brio:ToMaidAndValue()
143
+ maid:GiveTask(remoteEvent.OnClientEvent:Connect(callback))
144
+ end))
145
+ end
106
146
  else
107
147
  error("[Remoting.Connect] - Unknown RunService state")
108
148
  end
@@ -128,28 +168,47 @@ function Remoting:Bind(memberName, callback)
128
168
 
129
169
  local bindMaid = Maid.new()
130
170
 
131
- if RunService:IsServer() then
132
- local remoteFunction = self:_getOrCreateRemoteFunction(memberName)
133
- remoteFunction.OnServerInvoke = self:_translateCallback(bindMaid, memberName, callback)
171
+ if self._remotingRealm == RemotingRealms.SERVER then
172
+ if self._useDummyObject then
173
+ self:DeclareMethod(memberName)
174
+
175
+ local bindableFunction = self:_getOrCreateRemoteFunction(self:_getDummyMemberName(memberName, "OnServerInvoke"))
176
+ bindableFunction.OnInvoke = self:_translateCallback(bindMaid, memberName, callback)
177
+ else
178
+ local remoteFunction = self:_getOrCreateRemoteFunction(memberName)
179
+ remoteFunction.OnServerInvoke = self:_translateCallback(bindMaid, memberName, callback)
180
+ end
134
181
 
135
182
  -- TODO: Cleanup if nothing else is expecting this
136
- elseif RunService:IsClient() then
183
+ elseif self._remotingRealm == RemotingRealms.CLIENT then
137
184
  bindMaid._warning = task.delay(5, function()
138
185
  warn(string.format("[Remoting] - Failed to find RemoteEvent %q, event may never fire", self:_getDebugMemberName(memberName)))
139
186
  end)
140
187
 
141
- bindMaid:GiveTask(self:_observeRemoteFunctionBrio(memberName):Subscribe(function(brio)
142
- if brio:IsDead() then
143
- return
144
- end
188
+ if self._useDummyObject then
189
+ bindMaid:GiveTask(self:_observeRemoteFunctionBrio(self:_getDummyMemberName(memberName, "OnClientInvoke")):Subscribe(function(brio)
190
+ if brio:IsDead() then
191
+ return
192
+ end
145
193
 
146
- bindMaid._warning = nil
194
+ bindMaid._warning = nil
147
195
 
148
- local remoteFunction = brio:GetValue()
149
- local maid = brio:ToMaid()
196
+ local maid, remoteFunction = brio:ToMaidAndValue()
197
+ remoteFunction.OnInvoke = self:_translateCallback(maid, memberName, callback)
198
+ end))
199
+ else
200
+
201
+ bindMaid:GiveTask(self:_observeRemoteFunctionBrio(memberName):Subscribe(function(brio)
202
+ if brio:IsDead() then
203
+ return
204
+ end
150
205
 
151
- remoteFunction.OnClientInvoke = self:_translateCallback(maid, memberName, callback)
152
- end))
206
+ bindMaid._warning = nil
207
+
208
+ local maid, remoteFunction = brio:ToMaidAndValue()
209
+ remoteFunction.OnClientInvoke = self:_translateCallback(maid, memberName, callback)
210
+ end))
211
+ end
153
212
 
154
213
  -- TODO: Warn if remote function doesn't exist
155
214
  else
@@ -172,8 +231,13 @@ end
172
231
  function Remoting:DeclareEvent(memberName)
173
232
  assert(type(memberName) == "string", "Bad memberName")
174
233
 
175
- if RunService:IsServer() then
176
- self:_getOrCreateRemoteEvent(memberName)
234
+ if self._remotingRealm == RemotingRealms.SERVER then
235
+ if self._useDummyObject then
236
+ self:_getOrCreateRemoteEvent(self:_getDummyMemberName(memberName, "OnClientEvent"))
237
+ self:_getOrCreateRemoteEvent(self:_getDummyMemberName(memberName, "OnServerEvent"))
238
+ else
239
+ self:_getOrCreateRemoteEvent(memberName)
240
+ end
177
241
  end
178
242
  end
179
243
 
@@ -185,8 +249,13 @@ end
185
249
  function Remoting:DeclareMethod(memberName)
186
250
  assert(type(memberName) == "string", "Bad memberName")
187
251
 
188
- if RunService:IsServer() then
189
- self:_getOrCreateRemoteFunction(memberName)
252
+ if self._remotingRealm == RemotingRealms.SERVER then
253
+ if self._useDummyObject then
254
+ self:_getOrCreateRemoteFunction(self:_getDummyMemberName(memberName, "OnServerInvoke"))
255
+ self:_getOrCreateRemoteFunction(self:_getDummyMemberName(memberName, "OnClientInvoke"))
256
+ else
257
+ self:_getOrCreateRemoteFunction(memberName)
258
+ end
190
259
  end
191
260
  end
192
261
 
@@ -253,7 +322,13 @@ end
253
322
  function Remoting:FireClient(memberName, player, ...)
254
323
  assert(type(memberName) == "string", "Bad memberName")
255
324
  assert(typeof(player) == "Instance" and player:IsA("Player"), "Bad player")
256
- assert(RunService:IsServer(), "FireClient must be called on server")
325
+ assert(self._remotingRealm == RemotingRealms.SERVER, "FireClient must be called on server")
326
+
327
+ if self._useDummyObject then
328
+ local bindableEvent = self:_getOrCreateRemoteEvent(memberName)
329
+ bindableEvent:Fire(...)
330
+ return
331
+ end
257
332
 
258
333
  local remoteEvent = self:_getOrCreateRemoteEvent(memberName)
259
334
  remoteEvent:FireClient(player, ...)
@@ -272,10 +347,16 @@ end
272
347
  function Remoting:InvokeClient(memberName, player, ...)
273
348
  assert(type(memberName) == "string", "Bad memberName")
274
349
  assert(typeof(player) == "Instance" and player:IsA("Player"), "Bad player")
275
- assert(RunService:IsServer(), "InvokeClient must be called on server")
350
+ assert(self._remotingRealm == RemotingRealms.SERVER, "InvokeClient must be called on server")
351
+
352
+ if self._useDummyObject then
353
+ local bindableFunction = self:_getOrCreateRemoteFunction(self:_getDummyMemberName(memberName, "OnClientInvoke"))
354
+ bindableFunction:Invoke(...)
355
+ return
356
+ end
276
357
 
277
- local remoteEvent = self:_getOrCreateRemoteFunction(memberName)
278
- remoteEvent:InvokeClient(player, ...)
358
+ local remoteFunction = self:_getOrCreateRemoteFunction(memberName)
359
+ remoteFunction:InvokeClient(player, ...)
279
360
  end
280
361
 
281
362
  --[=[
@@ -289,7 +370,13 @@ end
289
370
  ]=]
290
371
  function Remoting:FireAllClients(memberName, ...)
291
372
  assert(type(memberName) == "string", "Bad memberName")
292
- assert(RunService:IsServer(), "FireAllClients must be called on server")
373
+ assert(self._remotingRealm == RemotingRealms.SERVER, "FireAllClients must be called on server")
374
+
375
+ if self._useDummyObject then
376
+ local bindableEvent = self:_getOrCreateRemoteEvent(self:_getDummyMemberName(memberName, "OnClientEvent"))
377
+ bindableEvent:Fire(...)
378
+ return
379
+ end
293
380
 
294
381
  local remoteEvent = self:_getOrCreateRemoteEvent(memberName)
295
382
  remoteEvent:FireAllClients(...)
@@ -307,7 +394,13 @@ end
307
394
  function Remoting:FireAllClientsExcept(memberName, excludePlayer, ...)
308
395
  assert(type(memberName) == "string", "Bad memberName")
309
396
  assert(typeof(excludePlayer) == "Instance" and excludePlayer:IsA("Player") or excludePlayer == nil, "Bad excludePlayer")
310
- assert(RunService:IsServer(), "FireAllClientsExcept must be called on server")
397
+ assert(self._remotingRealm == RemotingRealms.SERVER, "FireAllClientsExcept must be called on server")
398
+
399
+ if self._useDummyObject then
400
+ local bindableEvent = self:_getOrCreateRemoteEvent(self:_getDummyMemberName(memberName, "OnClientEvent"))
401
+ bindableEvent:Fire(...)
402
+ return
403
+ end
311
404
 
312
405
  local remoteEvent = self:_getOrCreateRemoteEvent(memberName)
313
406
  for _, player in pairs(Players:GetPlayers()) do
@@ -326,7 +419,7 @@ end
326
419
  ]=]
327
420
  function Remoting:FireServer(memberName, ...)
328
421
  assert(type(memberName) == "string", "Bad memberName")
329
- assert(RunService:IsClient(), "FireServer must be called on server")
422
+ assert(self._remotingRealm == RemotingRealms.CLIENT, "FireServer must be called on client")
330
423
 
331
424
  self:PromiseFireServer(memberName, ...)
332
425
  end
@@ -341,15 +434,23 @@ end
341
434
  ]=]
342
435
  function Remoting:PromiseFireServer(memberName, ...)
343
436
  assert(type(memberName) == "string", "Bad memberName")
344
- assert(RunService:IsClient(), "PromiseFireServer must be called on server")
437
+ assert(self._remotingRealm == RemotingRealms.CLIENT, "PromiseFireServer must be called on client")
345
438
 
346
439
  local fireMaid = Maid.new()
347
440
  local args = table.pack(...)
348
441
 
349
- local promise = self:_promiseRemoteEvent(fireMaid, memberName)
350
- :Then(function(remoteEvent)
351
- remoteEvent:FireServer(table.unpack(args, 1, args.n))
352
- end)
442
+ local promise
443
+ if self._useDummyObject then
444
+ promise = self:_promiseRemoteEvent(fireMaid, self:_getDummyMemberName(memberName, "OnServerEvent"))
445
+ :Then(function(bindableEvent)
446
+ bindableEvent:Fire(Players.LocalPlayer, table.unpack(args, 1, args.n))
447
+ end)
448
+ else
449
+ promise = self:_promiseRemoteEvent(fireMaid, memberName)
450
+ :Then(function(remoteEvent)
451
+ remoteEvent:FireServer(table.unpack(args, 1, args.n))
452
+ end)
453
+ end
353
454
 
354
455
  promise:Finally(function()
355
456
  self._maid[fireMaid] = nil
@@ -392,10 +493,18 @@ function Remoting:PromiseInvokeServer(memberName, ...)
392
493
  local invokeMaid = Maid.new()
393
494
  local args = table.pack(...)
394
495
 
395
- local promise = self:_promiseRemoteFunction(invokeMaid, memberName)
396
- :Then(function(remoteFunction)
397
- return invokeMaid:GivePromise(RemoteFunctionUtils.promiseInvokeServer(remoteFunction, table.unpack(args, 1, args.n)))
398
- end)
496
+ local promise
497
+ if self._useDummyObject then
498
+ promise = self:_promiseRemoteFunction(invokeMaid, self:_getDummyMemberName(memberName, "OnServerInvoke"))
499
+ :Then(function(remoteFunction)
500
+ return invokeMaid:GivePromise(RemoteFunctionUtils.promiseInvokeBindableFunction(remoteFunction, Players.LocalPlayer, table.unpack(args, 1, args.n)))
501
+ end)
502
+ else
503
+ promise = self:_promiseRemoteFunction(invokeMaid, memberName)
504
+ :Then(function(remoteFunction)
505
+ return invokeMaid:GivePromise(RemoteFunctionUtils.promiseInvokeServer(remoteFunction, table.unpack(args, 1, args.n)))
506
+ end)
507
+ end
399
508
 
400
509
  promise:Finally(function()
401
510
  self._maid[invokeMaid] = nil
@@ -423,11 +532,17 @@ function Remoting:PromiseInvokeClient(memberName, player, ...)
423
532
  assert(type(memberName) == "string", "Bad memberName")
424
533
  assert(typeof(player) == "Instance" and player:IsA("Player"), "Bad player")
425
534
 
426
- local remoteFunction = self:_getOrCreateRemoteFunction(memberName)
427
-
428
535
  local invokeMaid = Maid.new()
429
536
 
430
- local promise = invokeMaid:GivePromise(RemoteFunctionUtils.promiseInvokeClient(remoteFunction, player, ...))
537
+ local promise
538
+ if self._useDummyObject then
539
+ local bindableFunction = self:_getOrCreateRemoteFunction(self:_getDummyMemberName(memberName, "OnClientInvoke"))
540
+ promise = invokeMaid:GivePromise(RemoteFunctionUtils.promiseInvokeBindableFunction(bindableFunction, ...))
541
+ else
542
+ local remoteFunction = self:_getOrCreateRemoteFunction(memberName)
543
+ promise = invokeMaid:GivePromise(RemoteFunctionUtils.promiseInvokeClient(remoteFunction, player, ...))
544
+ end
545
+
431
546
  promise:Finally(function()
432
547
  self._maid[invokeMaid] = nil
433
548
  end)
@@ -440,21 +555,25 @@ function Remoting:PromiseInvokeClient(memberName, player, ...)
440
555
  return promise
441
556
  end
442
557
 
443
- function Remoting:_ensureFolder()
444
- assert(RunService:IsServer(), "Folder should only be created on server")
558
+ function Remoting:GetContainerClass()
559
+ return "Configuration"
560
+ end
561
+
562
+ function Remoting:_ensureContainer()
563
+ assert(self._remotingRealm == RemotingRealms.SERVER, "Folder should only be created on server")
445
564
 
446
- if self._remoteFolder then
447
- return self._remoteFolder
565
+ if self._container then
566
+ return self._container
448
567
  end
449
568
 
450
- self._remoteFolder = Instance.new("Folder")
451
- self._remoteFolder.Name = self._remoteFolderName
452
- self._remoteFolder.Archivable = false
453
- self._remoteFolder.Parent = self._instance
569
+ self._container = Instance.new(self:GetContainerClass())
570
+ self._container.Name = self._remoteFolderName
571
+ self._container.Archivable = false
572
+ self._container.Parent = self._instance
454
573
 
455
- self._maid:GiveTask(self._remoteFolder)
574
+ self._maid:GiveTask(self._container)
456
575
 
457
- return self._remoteFolder
576
+ return self._container
458
577
  end
459
578
 
460
579
  function Remoting:_observeRemoteFunctionBrio(memberName)
@@ -464,7 +583,11 @@ function Remoting:_observeRemoteFunctionBrio(memberName)
464
583
 
465
584
  return self:_observeFolderBrio():Pipe({
466
585
  RxBrioUtils.switchMapBrio(function(item)
467
- return RxInstanceUtils.observeLastNamedChildBrio(item, "RemoteFunction", remoteFunctionName)
586
+ if self._useDummyObject then
587
+ return RxInstanceUtils.observeLastNamedChildBrio(item, "BindableFunction", remoteFunctionName)
588
+ else
589
+ return RxInstanceUtils.observeLastNamedChildBrio(item, "RemoteFunction", remoteFunctionName)
590
+ end
468
591
  end)
469
592
  })
470
593
  end
@@ -476,36 +599,39 @@ function Remoting:_observeRemoteEventBrio(memberName)
476
599
 
477
600
  return self:_observeFolderBrio():Pipe({
478
601
  RxBrioUtils.switchMapBrio(function(item)
479
- return RxInstanceUtils.observeLastNamedChildBrio(item, "RemoteEvent", remoteFunctionName)
602
+ if self._useDummyObject then
603
+ return RxInstanceUtils.observeLastNamedChildBrio(item, "BindableEvent", remoteFunctionName)
604
+ else
605
+ return RxInstanceUtils.observeLastNamedChildBrio(item, "RemoteEvent", remoteFunctionName)
606
+ end
480
607
  end)
481
608
  })
482
609
  end
483
610
 
484
- function Remoting:_promiseFolder(maid)
611
+ function Remoting:_promiseContainer(maid)
485
612
  return maid:GivePromise(promiseChild(self._instance, self._remoteFolderName, 5))
486
613
  end
487
614
 
488
615
  function Remoting:_promiseRemoteEvent(maid, memberName)
489
616
  local remoteEventName = self:_getMemberName(memberName, REMOTE_EVENT_SUFFIX)
490
- return self:_promiseFolder(maid)
491
- :Then(function(folder)
492
- return maid:GivePromise(promiseChild(folder, remoteEventName, 5))
617
+ return self:_promiseContainer(maid)
618
+ :Then(function(container)
619
+ return maid:GivePromise(promiseChild(container, remoteEventName, 5))
493
620
  end)
494
621
  end
495
622
 
496
623
  function Remoting:_promiseRemoteFunction(maid, memberName)
497
624
  local remoteEventName = self:_getMemberName(memberName, REMOTE_FUNCTION_SUFFIX)
498
- return self:_promiseFolder(maid)
499
- :Then(function(folder)
500
- return maid:GivePromise(promiseChild(folder, remoteEventName, 5))
625
+ return self:_promiseContainer(maid)
626
+ :Then(function(container)
627
+ return maid:GivePromise(promiseChild(container, remoteEventName, 5))
501
628
  end)
502
629
  end
503
630
 
504
-
505
631
  function Remoting:_observeFolderBrio()
506
632
  assert(self._instance, "Not initialized")
507
633
 
508
- return RxInstanceUtils.observeLastNamedChildBrio(self._instance, "Folder", self._remoteFolderName)
634
+ return RxInstanceUtils.observeLastNamedChildBrio(self._instance, self:GetContainerClass(), self._remoteFolderName)
509
635
  end
510
636
 
511
637
  function Remoting:_getOrCreateRemoteFunction(memberName)
@@ -517,12 +643,18 @@ function Remoting:_getOrCreateRemoteFunction(memberName)
517
643
  return self._remoteObjects[remoteFunctionName]
518
644
  end
519
645
 
520
- local folder = self:_ensureFolder()
646
+ local container = self:_ensureContainer()
647
+
648
+ local remoteFunction
649
+ if self._useDummyObject then
650
+ remoteFunction = Instance.new("BindableFunction")
651
+ else
652
+ remoteFunction = Instance.new("RemoteFunction")
653
+ end
521
654
 
522
- local remoteFunction = Instance.new("RemoteFunction")
523
655
  remoteFunction.Name = remoteFunctionName
524
656
  remoteFunction.Archivable = false
525
- remoteFunction.Parent = folder
657
+ remoteFunction.Parent = container
526
658
 
527
659
  self._remoteObjects[remoteFunctionName] = remoteFunction
528
660
  self._maid[remoteFunction] = remoteFunction
@@ -539,12 +671,18 @@ function Remoting:_getOrCreateRemoteEvent(memberName)
539
671
  return self._remoteObjects[remoteEventName]
540
672
  end
541
673
 
542
- local folder = self:_ensureFolder()
674
+ local container = self:_ensureContainer()
675
+
676
+ local remoteEvent
677
+ if self._useDummyObject then
678
+ remoteEvent = Instance.new("BindableEvent")
679
+ else
680
+ remoteEvent = Instance.new("RemoteEvent")
681
+ end
543
682
 
544
- local remoteEvent = Instance.new("RemoteEvent")
545
683
  remoteEvent.Name = remoteEventName
546
684
  remoteEvent.Archivable = false
547
- remoteEvent.Parent = folder
685
+ remoteEvent.Parent = container
548
686
 
549
687
  self._maid[remoteEvent] = remoteEvent
550
688
  self._remoteObjects[remoteEventName] = remoteEvent
@@ -556,6 +694,12 @@ function Remoting:_getMemberName(memberName, objectType)
556
694
  return memberName .. objectType
557
695
  end
558
696
 
697
+ function Remoting:_getDummyMemberName(memberName, suffix)
698
+ assert(self._useDummyObject, "Not dummy mode")
699
+
700
+ return memberName .. "_" .. suffix .. "_"
701
+ end
702
+
559
703
  function Remoting:_getDebugMemberName(memberName)
560
704
  return string.format("%s.%s", self._name, memberName)
561
705
  end
@@ -5,7 +5,9 @@
5
5
  @class RemotingMember
6
6
  ]=]
7
7
 
8
- local RunService = game:GetService("RunService")
8
+ local require = require(script.Parent.loader).load(script)
9
+
10
+ local RemotingRealms = require("RemotingRealms")
9
11
 
10
12
  local RemotingMember = {}
11
13
  RemotingMember.ClassName = "RemotingMember"
@@ -16,13 +18,15 @@ RemotingMember.__index = RemotingMember
16
18
 
17
19
  @param remoting Remoting
18
20
  @param memberName string
21
+ @param remotingRealm RemotingRealms
19
22
  @return RemotingMember
20
23
  ]=]
21
- function RemotingMember.new(remoting, memberName)
24
+ function RemotingMember.new(remoting, memberName, remotingRealm)
22
25
  local self = setmetatable({}, RemotingMember)
23
26
 
24
27
  self._remoting = assert(remoting, "No remoting")
25
28
  self._memberName = assert(memberName, "No memberName")
29
+ self._remotingRealm = assert(remotingRealm, "Bad remotingRealm")
26
30
 
27
31
  return self
28
32
  end
@@ -80,7 +84,7 @@ end
80
84
  @param ... any
81
85
  ]=]
82
86
  function RemotingMember:FireServer(...)
83
- assert(RunService:IsClient(), "FireServer must be called on client")
87
+ assert(self._remotingRealm == RemotingRealms.CLIENT, "FireServer must be called on client")
84
88
  self._remoting:FireServer(self._memberName, ...)
85
89
  end
86
90
 
@@ -91,7 +95,7 @@ end
91
95
  @param ... any
92
96
  ]=]
93
97
  function RemotingMember:InvokeServer(...)
94
- assert(RunService:IsClient(), "InvokeServer must be called on client")
98
+ assert(self._remotingRealm == RemotingRealms.CLIENT, "InvokeServer must be called on client")
95
99
 
96
100
  return self._remoting:InvokeServer(self._memberName, ...)
97
101
  end
@@ -103,7 +107,7 @@ end
103
107
  @param ... any
104
108
  ]=]
105
109
  function RemotingMember:PromiseInvokeServer(...)
106
- assert(RunService:IsClient(), "PromiseInvokeServer must be called on client")
110
+ assert(self._remotingRealm == RemotingRealms.CLIENT, "PromiseInvokeServer must be called on client")
107
111
 
108
112
  return self._remoting:PromiseInvokeServer(self._memberName, ...)
109
113
  end
@@ -116,7 +120,7 @@ end
116
120
  @return Promise
117
121
  ]=]
118
122
  function RemotingMember:PromiseFireServer(...)
119
- assert(RunService:IsClient(), "PromiseInvokeServer must be called on client")
123
+ assert(self._remotingRealm == RemotingRealms.CLIENT, "PromiseInvokeServer must be called on client")
120
124
 
121
125
  return self._remoting:PromiseFireServer(self._memberName, ...)
122
126
  end
@@ -134,7 +138,7 @@ end
134
138
  ]=]
135
139
  function RemotingMember:PromiseInvokeClient(player, ...)
136
140
  assert(typeof(player) == "Instance" and player:IsA("Player"), "Bad player")
137
- assert(RunService:IsServer(), "PromiseInvokeClient must be called on client")
141
+ assert(self._remotingRealm == RemotingRealms.SERVER, "PromiseInvokeClient must be called on client")
138
142
 
139
143
  return self._remoting:PromiseInvokeClient(self._memberName, player, ...)
140
144
  end
@@ -151,7 +155,7 @@ end
151
155
  ]=]
152
156
  function RemotingMember:InvokeClient(player, ...)
153
157
  assert(typeof(player) == "Instance" and player:IsA("Player"), "Bad player")
154
- assert(RunService:IsServer(), "InvokeClient must be called on client")
158
+ assert(self._remotingRealm == RemotingRealms.SERVER, "InvokeClient must be called on client")
155
159
 
156
160
  return self._remoting:InvokeClient(self._memberName, player, ...)
157
161
  end
@@ -165,7 +169,7 @@ end
165
169
  @param ... any
166
170
  ]=]
167
171
  function RemotingMember:FireAllClients(...)
168
- assert(RunService:IsServer(), "FireAllClients must be called on client")
172
+ assert(self._remotingRealm == RemotingRealms.SERVER, "FireAllClients must be called on client")
169
173
 
170
174
  self._remoting:FireAllClients(self._memberName, ...)
171
175
  end
@@ -180,12 +184,11 @@ end
180
184
  ]=]
181
185
  function RemotingMember:FireAllClientsExcept(excludePlayer, ...)
182
186
  assert(typeof(excludePlayer) == "Instance" and excludePlayer:IsA("Player") or excludePlayer == nil, "Bad excludePlayer")
183
- assert(RunService:IsServer(), "FireAllClientsExcept must be called on server")
187
+ assert(self._remotingRealm == RemotingRealms.SERVER, "FireAllClientsExcept must be called on server")
184
188
 
185
189
  self._remoting:FireAllClientsExcept(self._memberName, excludePlayer, ...)
186
190
  end
187
191
 
188
-
189
192
  --[=[
190
193
  Fires the client with the data
191
194
 
@@ -196,7 +199,7 @@ end
196
199
  @param ... any
197
200
  ]=]
198
201
  function RemotingMember:FireClient(player, ...)
199
- assert(RunService:IsServer(), "FireClient must be called on client")
202
+ assert(self._remotingRealm == RemotingRealms.SERVER, "FireClient must be called on client")
200
203
  assert(typeof(player) == "Instance" and player:IsA("Player"), "Bad player")
201
204
 
202
205
  self._remoting:FireClient(self._memberName, player, ...)
@@ -0,0 +1,27 @@
1
+ --[=[
2
+ @class RemotingRealmUtils
3
+ ]=]
4
+
5
+ local require = require(script.Parent.loader).load(script)
6
+
7
+ local RunService = game:GetService("RunService")
8
+
9
+ local RemotingRealms = require("RemotingRealms")
10
+
11
+ local RemotingRealmUtils = {}
12
+
13
+ function RemotingRealmUtils.isRemotingRealm(realm)
14
+ return realm == RemotingRealms.SERVER or realm == RemotingRealms.CLIENT
15
+ end
16
+
17
+ function RemotingRealmUtils.inferRemotingRealm()
18
+ if RunService:IsServer() then
19
+ return RemotingRealms.SERVER
20
+ elseif RunService:IsClient() then
21
+ return RemotingRealms.CLIENT
22
+ else
23
+ error("[RemotingRealmUtils.inferRemotingRealm] - Unknown RunService state")
24
+ end
25
+ end
26
+
27
+ return RemotingRealmUtils
@@ -0,0 +1,12 @@
1
+ --[=[
2
+ @class RemotingRealms
3
+ ]=]
4
+
5
+ local require = require(script.Parent.loader).load(script)
6
+
7
+ local Table = require("Table")
8
+
9
+ return Table.readonly({
10
+ SERVER = "server";
11
+ CLIENT = "client";
12
+ })