roblox-opencode 1.0.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/README.md +122 -0
- package/commands/setup-game.md +108 -0
- package/commands/sync-check.md +53 -0
- package/core/roblox-core.md +93 -0
- package/dist/server.js +167 -0
- package/package.json +35 -0
- package/skills/roblox-analytics/SKILL.md +277 -0
- package/skills/roblox-analytics/references/event-batcher.luau +75 -0
- package/skills/roblox-animation-vfx/SKILL.md +1325 -0
- package/skills/roblox-architecture/SKILL.md +863 -0
- package/skills/roblox-architecture/references/combat-systems.md +1381 -0
- package/skills/roblox-code-review/SKILL.md +687 -0
- package/skills/roblox-data/SKILL.md +889 -0
- package/skills/roblox-data/references/inventory-systems.md +1729 -0
- package/skills/roblox-debug/SKILL.md +99 -0
- package/skills/roblox-gui/SKILL.md +1103 -0
- package/skills/roblox-gui-fusion/SKILL.md +150 -0
- package/skills/roblox-gui-fusion/references/inventory.luau +427 -0
- package/skills/roblox-gui-fusion/references/settings-menu.luau +579 -0
- package/skills/roblox-gui-fusion/references/shop.luau +411 -0
- package/skills/roblox-luau-mastery/SKILL.md +1519 -0
- package/skills/roblox-monetization/SKILL.md +1084 -0
- package/skills/roblox-monetization/references/process-receipt.luau +131 -0
- package/skills/roblox-networking/SKILL.md +669 -0
- package/skills/roblox-networking/references/remote-validator.luau +193 -0
- package/skills/roblox-publish-checklist/SKILL.md +128 -0
- package/skills/roblox-runtime/SKILL.md +753 -0
- package/skills/roblox-sharp-edges/SKILL.md +295 -0
- package/skills/roblox-sync/SKILL.md +126 -0
- package/skills/roblox-testing/SKILL.md +943 -0
- package/skills/roblox-tooling/SKILL.md +150 -0
- package/vendor/LICENSES/ProfileStore-LICENSE +201 -0
- package/vendor/LICENSES/RbxUtil-LICENSE +7 -0
- package/vendor/LICENSES/promise-LICENSE +21 -0
- package/vendor/LICENSES/t-LICENSE +21 -0
- package/vendor/LICENSES/testez-LICENSE +201 -0
- package/vendor/README.md +84 -0
- package/vendor/fusion/Animation/ExternalTime.luau +84 -0
- package/vendor/fusion/Animation/Spring.luau +322 -0
- package/vendor/fusion/Animation/Stopwatch.luau +128 -0
- package/vendor/fusion/Animation/Tween.luau +187 -0
- package/vendor/fusion/Animation/getTweenDuration.luau +27 -0
- package/vendor/fusion/Animation/getTweenRatio.luau +47 -0
- package/vendor/fusion/Animation/lerpType.luau +164 -0
- package/vendor/fusion/Animation/packType.luau +100 -0
- package/vendor/fusion/Animation/springCoefficients.luau +80 -0
- package/vendor/fusion/Animation/unpackType.luau +103 -0
- package/vendor/fusion/Colour/Oklab.luau +70 -0
- package/vendor/fusion/Colour/sRGB.luau +55 -0
- package/vendor/fusion/External.luau +168 -0
- package/vendor/fusion/ExternalDebug.luau +70 -0
- package/vendor/fusion/Graph/Observer.luau +114 -0
- package/vendor/fusion/Graph/castToGraph.luau +29 -0
- package/vendor/fusion/Graph/change.luau +81 -0
- package/vendor/fusion/Graph/depend.luau +33 -0
- package/vendor/fusion/Graph/evaluate.luau +56 -0
- package/vendor/fusion/Instances/Attribute.luau +58 -0
- package/vendor/fusion/Instances/AttributeChange.luau +47 -0
- package/vendor/fusion/Instances/AttributeOut.luau +63 -0
- package/vendor/fusion/Instances/Child.luau +21 -0
- package/vendor/fusion/Instances/Children.luau +148 -0
- package/vendor/fusion/Instances/Hydrate.luau +33 -0
- package/vendor/fusion/Instances/New.luau +53 -0
- package/vendor/fusion/Instances/OnChange.luau +50 -0
- package/vendor/fusion/Instances/OnEvent.luau +54 -0
- package/vendor/fusion/Instances/Out.luau +69 -0
- package/vendor/fusion/Instances/applyInstanceProps.luau +149 -0
- package/vendor/fusion/Instances/defaultProps.luau +194 -0
- package/vendor/fusion/LICENSE +21 -0
- package/vendor/fusion/Logging/formatError.luau +49 -0
- package/vendor/fusion/Logging/messages.luau +52 -0
- package/vendor/fusion/Logging/parseError.luau +25 -0
- package/vendor/fusion/Memory/checkLifetime.luau +134 -0
- package/vendor/fusion/Memory/deriveScope.luau +24 -0
- package/vendor/fusion/Memory/deriveScopeImpl.luau +45 -0
- package/vendor/fusion/Memory/doCleanup.luau +79 -0
- package/vendor/fusion/Memory/innerScope.luau +34 -0
- package/vendor/fusion/Memory/legacyCleanup.luau +18 -0
- package/vendor/fusion/Memory/needsDestruction.luau +17 -0
- package/vendor/fusion/Memory/poisonScope.luau +34 -0
- package/vendor/fusion/Memory/scopePool.luau +55 -0
- package/vendor/fusion/Memory/scoped.luau +27 -0
- package/vendor/fusion/Memory/whichLivesLonger.luau +75 -0
- package/vendor/fusion/RobloxExternal.luau +98 -0
- package/vendor/fusion/State/Computed.luau +139 -0
- package/vendor/fusion/State/For/Disassembly.luau +211 -0
- package/vendor/fusion/State/For/ForTypes.luau +30 -0
- package/vendor/fusion/State/For/init.luau +110 -0
- package/vendor/fusion/State/ForKeys.luau +94 -0
- package/vendor/fusion/State/ForPairs.luau +97 -0
- package/vendor/fusion/State/ForValues.luau +94 -0
- package/vendor/fusion/State/Value.luau +88 -0
- package/vendor/fusion/State/castToState.luau +26 -0
- package/vendor/fusion/State/peek.luau +31 -0
- package/vendor/fusion/State/updateAll.luau +1 -0
- package/vendor/fusion/Types.luau +314 -0
- package/vendor/fusion/Utility/Contextual.luau +91 -0
- package/vendor/fusion/Utility/Safe.luau +23 -0
- package/vendor/fusion/Utility/isSimilar.luau +29 -0
- package/vendor/fusion/Utility/merge.luau +35 -0
- package/vendor/fusion/Utility/nameOf.luau +35 -0
- package/vendor/fusion/Utility/never.luau +14 -0
- package/vendor/fusion/Utility/nicknames.luau +11 -0
- package/vendor/fusion/Utility/xtypeof.luau +27 -0
- package/vendor/fusion/init.luau +82 -0
- package/vendor/profilestore/init.luau +2243 -0
- package/vendor/promise/init.luau +1982 -0
- package/vendor/rbxutil/buffer-util/Buffer.test.luau +25 -0
- package/vendor/rbxutil/buffer-util/BufferReader.luau +228 -0
- package/vendor/rbxutil/buffer-util/BufferWriter.luau +269 -0
- package/vendor/rbxutil/buffer-util/DataTypeBuffer.luau +223 -0
- package/vendor/rbxutil/buffer-util/Types.luau +60 -0
- package/vendor/rbxutil/buffer-util/index.d.ts +153 -0
- package/vendor/rbxutil/buffer-util/init.luau +41 -0
- package/vendor/rbxutil/buffer-util/package.json +16 -0
- package/vendor/rbxutil/buffer-util/wally.toml +9 -0
- package/vendor/rbxutil/comm/Client/ClientComm.luau +232 -0
- package/vendor/rbxutil/comm/Client/ClientRemoteProperty.luau +156 -0
- package/vendor/rbxutil/comm/Client/ClientRemoteSignal.luau +109 -0
- package/vendor/rbxutil/comm/Client/init.luau +135 -0
- package/vendor/rbxutil/comm/Server/RemoteProperty.luau +295 -0
- package/vendor/rbxutil/comm/Server/RemoteSignal.luau +211 -0
- package/vendor/rbxutil/comm/Server/ServerComm.luau +211 -0
- package/vendor/rbxutil/comm/Server/init.luau +140 -0
- package/vendor/rbxutil/comm/Types.luau +18 -0
- package/vendor/rbxutil/comm/Util.luau +27 -0
- package/vendor/rbxutil/comm/init.luau +35 -0
- package/vendor/rbxutil/comm/wally.toml +13 -0
- package/vendor/rbxutil/component/init.luau +759 -0
- package/vendor/rbxutil/component/init.test.luau +311 -0
- package/vendor/rbxutil/component/wally.toml +14 -0
- package/vendor/rbxutil/concur/init.luau +542 -0
- package/vendor/rbxutil/concur/init.test.luau +364 -0
- package/vendor/rbxutil/concur/wally.toml +8 -0
- package/vendor/rbxutil/enum-list/init.luau +101 -0
- package/vendor/rbxutil/enum-list/init.test.luau +91 -0
- package/vendor/rbxutil/enum-list/wally.toml +8 -0
- package/vendor/rbxutil/find/index.d.ts +20 -0
- package/vendor/rbxutil/find/init.luau +44 -0
- package/vendor/rbxutil/find/package.json +17 -0
- package/vendor/rbxutil/find/wally.toml +8 -0
- package/vendor/rbxutil/input/Gamepad.luau +559 -0
- package/vendor/rbxutil/input/Keyboard.luau +124 -0
- package/vendor/rbxutil/input/Mouse.luau +278 -0
- package/vendor/rbxutil/input/PreferredInput.luau +91 -0
- package/vendor/rbxutil/input/Touch.luau +120 -0
- package/vendor/rbxutil/input/init.luau +33 -0
- package/vendor/rbxutil/input/wally.toml +12 -0
- package/vendor/rbxutil/loader/index.d.ts +15 -0
- package/vendor/rbxutil/loader/init.luau +137 -0
- package/vendor/rbxutil/loader/wally.toml +8 -0
- package/vendor/rbxutil/log/index.d.ts +38 -0
- package/vendor/rbxutil/log/init.luau +746 -0
- package/vendor/rbxutil/log/wally.toml +8 -0
- package/vendor/rbxutil/net/init.luau +190 -0
- package/vendor/rbxutil/net/wally.toml +8 -0
- package/vendor/rbxutil/option/index.d.ts +44 -0
- package/vendor/rbxutil/option/init.luau +489 -0
- package/vendor/rbxutil/option/init.test.luau +342 -0
- package/vendor/rbxutil/option/wally.toml +8 -0
- package/vendor/rbxutil/pid/index.d.ts +53 -0
- package/vendor/rbxutil/pid/init.luau +195 -0
- package/vendor/rbxutil/pid/package.json +16 -0
- package/vendor/rbxutil/pid/wally.toml +9 -0
- package/vendor/rbxutil/quaternion/index.d.ts +117 -0
- package/vendor/rbxutil/quaternion/init.luau +570 -0
- package/vendor/rbxutil/quaternion/package.json +16 -0
- package/vendor/rbxutil/quaternion/wally.toml +9 -0
- package/vendor/rbxutil/query/index.d.ts +43 -0
- package/vendor/rbxutil/query/init.luau +117 -0
- package/vendor/rbxutil/query/package.json +18 -0
- package/vendor/rbxutil/query/wally.toml +9 -0
- package/vendor/rbxutil/sequent/index.d.ts +28 -0
- package/vendor/rbxutil/sequent/init.luau +340 -0
- package/vendor/rbxutil/sequent/package.json +16 -0
- package/vendor/rbxutil/sequent/wally.toml +9 -0
- package/vendor/rbxutil/ser/init.luau +175 -0
- package/vendor/rbxutil/ser/init.test.luau +50 -0
- package/vendor/rbxutil/ser/wally.toml +11 -0
- package/vendor/rbxutil/shake/index.d.ts +36 -0
- package/vendor/rbxutil/shake/init.luau +532 -0
- package/vendor/rbxutil/shake/init.test.luau +267 -0
- package/vendor/rbxutil/shake/package.json +16 -0
- package/vendor/rbxutil/shake/wally.toml +9 -0
- package/vendor/rbxutil/signal/index.d.ts +100 -0
- package/vendor/rbxutil/signal/init.luau +432 -0
- package/vendor/rbxutil/signal/init.test.luau +190 -0
- package/vendor/rbxutil/signal/package.json +17 -0
- package/vendor/rbxutil/signal/wally.toml +9 -0
- package/vendor/rbxutil/silo/TableWatcher.luau +65 -0
- package/vendor/rbxutil/silo/Util.luau +55 -0
- package/vendor/rbxutil/silo/init.luau +338 -0
- package/vendor/rbxutil/silo/init.test.luau +215 -0
- package/vendor/rbxutil/silo/wally.toml +8 -0
- package/vendor/rbxutil/spring/index.d.ts +40 -0
- package/vendor/rbxutil/spring/init.luau +97 -0
- package/vendor/rbxutil/spring/package.json +17 -0
- package/vendor/rbxutil/spring/wally.toml +8 -0
- package/vendor/rbxutil/stream/index.d.ts +88 -0
- package/vendor/rbxutil/stream/init.luau +597 -0
- package/vendor/rbxutil/stream/package.json +18 -0
- package/vendor/rbxutil/stream/wally.toml +9 -0
- package/vendor/rbxutil/streamable/Streamable.luau +202 -0
- package/vendor/rbxutil/streamable/StreamableUtil.luau +80 -0
- package/vendor/rbxutil/streamable/init.luau +8 -0
- package/vendor/rbxutil/streamable/wally.toml +12 -0
- package/vendor/rbxutil/symbol/init.luau +56 -0
- package/vendor/rbxutil/symbol/init.test.luau +37 -0
- package/vendor/rbxutil/symbol/wally.toml +8 -0
- package/vendor/rbxutil/table-util/init.luau +938 -0
- package/vendor/rbxutil/table-util/init.test.luau +439 -0
- package/vendor/rbxutil/table-util/wally.toml +8 -0
- package/vendor/rbxutil/task-queue/index.d.ts +27 -0
- package/vendor/rbxutil/task-queue/init.luau +97 -0
- package/vendor/rbxutil/task-queue/wally.toml +8 -0
- package/vendor/rbxutil/timer/index.d.ts +81 -0
- package/vendor/rbxutil/timer/init.luau +249 -0
- package/vendor/rbxutil/timer/init.test.luau +73 -0
- package/vendor/rbxutil/timer/wally.toml +11 -0
- package/vendor/rbxutil/tree/index.d.ts +15 -0
- package/vendor/rbxutil/tree/init.luau +137 -0
- package/vendor/rbxutil/tree/wally.toml +8 -0
- package/vendor/rbxutil/trove/index.d.ts +46 -0
- package/vendor/rbxutil/trove/init.luau +787 -0
- package/vendor/rbxutil/trove/init.test.luau +203 -0
- package/vendor/rbxutil/trove/wally.toml +8 -0
- package/vendor/rbxutil/typed-remote/init.luau +196 -0
- package/vendor/rbxutil/typed-remote/wally.toml +8 -0
- package/vendor/rbxutil/wait-for/index.d.ts +17 -0
- package/vendor/rbxutil/wait-for/init.luau +257 -0
- package/vendor/rbxutil/wait-for/init.test.luau +182 -0
- package/vendor/rbxutil/wait-for/wally.toml +11 -0
- package/vendor/t/t.lua +1350 -0
- package/vendor/testez/Context.lua +26 -0
- package/vendor/testez/Expectation.lua +311 -0
- package/vendor/testez/ExpectationContext.lua +38 -0
- package/vendor/testez/LifecycleHooks.lua +89 -0
- package/vendor/testez/Reporters/TeamCityReporter.lua +102 -0
- package/vendor/testez/Reporters/TextReporter.lua +106 -0
- package/vendor/testez/Reporters/TextReporterQuiet.lua +97 -0
- package/vendor/testez/TestBootstrap.lua +147 -0
- package/vendor/testez/TestEnum.lua +28 -0
- package/vendor/testez/TestPlan.lua +304 -0
- package/vendor/testez/TestPlanner.lua +40 -0
- package/vendor/testez/TestResults.lua +112 -0
- package/vendor/testez/TestRunner.lua +188 -0
- package/vendor/testez/TestSession.lua +243 -0
- package/vendor/testez/init.lua +40 -0
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
-- ClientComm
|
|
2
|
+
-- Stephen Leitnick
|
|
3
|
+
-- December 20, 2021
|
|
4
|
+
|
|
5
|
+
local Comm = require(script.Parent)
|
|
6
|
+
local Types = require(script.Parent.Parent.Types)
|
|
7
|
+
local Util = require(script.Parent.Parent.Util)
|
|
8
|
+
|
|
9
|
+
--[=[
|
|
10
|
+
@class ClientComm
|
|
11
|
+
@client
|
|
12
|
+
]=]
|
|
13
|
+
local ClientComm = {}
|
|
14
|
+
ClientComm.__index = ClientComm
|
|
15
|
+
|
|
16
|
+
--[=[
|
|
17
|
+
@within ClientComm
|
|
18
|
+
@type ClientMiddlewareFn (args: {any}) -> (shouldContinue: boolean, ...: any)
|
|
19
|
+
The middleware function takes the arguments (as a table array), and should
|
|
20
|
+
return `true|false` to indicate if the process should continue.
|
|
21
|
+
|
|
22
|
+
If returning `false`, the optional varargs after the `false` are used as the new return values
|
|
23
|
+
to whatever was calling the middleware.
|
|
24
|
+
]=]
|
|
25
|
+
--[=[
|
|
26
|
+
@within ClientComm
|
|
27
|
+
@type ClientMiddleware {ClientMiddlewareFn}
|
|
28
|
+
Array of middleware functions.
|
|
29
|
+
]=]
|
|
30
|
+
|
|
31
|
+
--[=[
|
|
32
|
+
@return ClientComm
|
|
33
|
+
Constructs a ClientComm object.
|
|
34
|
+
|
|
35
|
+
If `usePromise` is set to `true`, then `GetFunction` will generate a function that returns a Promise
|
|
36
|
+
that resolves with the server response. If set to `false`, the function will act like a normal
|
|
37
|
+
call to a RemoteFunction and yield until the function responds.
|
|
38
|
+
|
|
39
|
+
```lua
|
|
40
|
+
local clientComm = ClientComm.new(game:GetService("ReplicatedStorage"), true)
|
|
41
|
+
|
|
42
|
+
-- If using a unique namespace with ServerComm, include it as second argument:
|
|
43
|
+
local clientComm = ClientComm.new(game:GetService("ReplicatedStorage"), true, "MyNamespace")
|
|
44
|
+
```
|
|
45
|
+
]=]
|
|
46
|
+
function ClientComm.new(parent: Instance, usePromise: boolean, namespace: string?)
|
|
47
|
+
assert(not Util.IsServer, "ClientComm must be constructed from the client")
|
|
48
|
+
assert(typeof(parent) == "Instance", "Parent must be of type Instance")
|
|
49
|
+
local ns = Util.DefaultCommFolderName
|
|
50
|
+
if namespace then
|
|
51
|
+
ns = namespace
|
|
52
|
+
end
|
|
53
|
+
local folder: Instance? = parent:WaitForChild(ns, Util.WaitForChildTimeout)
|
|
54
|
+
assert(folder ~= nil, "Could not find namespace for ClientComm in parent: " .. ns)
|
|
55
|
+
local self = setmetatable({}, ClientComm)
|
|
56
|
+
self._instancesFolder = folder
|
|
57
|
+
self._usePromise = usePromise
|
|
58
|
+
return self
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
--[=[
|
|
62
|
+
@param name string
|
|
63
|
+
@param inboundMiddleware ClientMiddleware?
|
|
64
|
+
@param outboundMiddleware ClientMiddleware?
|
|
65
|
+
@return (...: any) -> any
|
|
66
|
+
|
|
67
|
+
Generates a function on the matching RemoteFunction generated with ServerComm. The function
|
|
68
|
+
can then be called to invoke the server. If this `ClientComm` object was created with
|
|
69
|
+
the `usePromise` parameter set to `true`, then this generated function will return
|
|
70
|
+
a Promise when called.
|
|
71
|
+
|
|
72
|
+
```lua
|
|
73
|
+
-- Server-side:
|
|
74
|
+
local serverComm = ServerComm.new(someParent)
|
|
75
|
+
serverComm:BindFunction("MyFunction", function(player, msg)
|
|
76
|
+
return msg:upper()
|
|
77
|
+
end)
|
|
78
|
+
|
|
79
|
+
-- Client-side:
|
|
80
|
+
local clientComm = ClientComm.new(someParent)
|
|
81
|
+
local myFunc = clientComm:GetFunction("MyFunction")
|
|
82
|
+
local uppercase = myFunc("hello world")
|
|
83
|
+
print(uppercase) --> HELLO WORLD
|
|
84
|
+
|
|
85
|
+
-- Client-side, using promises:
|
|
86
|
+
local clientComm = ClientComm.new(someParent, true)
|
|
87
|
+
local myFunc = clientComm:GetFunction("MyFunction")
|
|
88
|
+
myFunc("hi there"):andThen(function(msg)
|
|
89
|
+
print(msg) --> HI THERE
|
|
90
|
+
end):catch(function(err)
|
|
91
|
+
print("Error:", err)
|
|
92
|
+
end)
|
|
93
|
+
```
|
|
94
|
+
]=]
|
|
95
|
+
function ClientComm:GetFunction(
|
|
96
|
+
name: string,
|
|
97
|
+
inboundMiddleware: Types.ClientMiddleware?,
|
|
98
|
+
outboundMiddleware: Types.ClientMiddleware?
|
|
99
|
+
)
|
|
100
|
+
return Comm.GetFunction(self._instancesFolder, name, self._usePromise, inboundMiddleware, outboundMiddleware)
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
--[=[
|
|
104
|
+
@param name string
|
|
105
|
+
@param inboundMiddleware ClientMiddleware?
|
|
106
|
+
@param outboundMiddleware ClientMiddleware?
|
|
107
|
+
@return ClientRemoteSignal
|
|
108
|
+
Returns a new ClientRemoteSignal that mirrors the matching RemoteSignal created by
|
|
109
|
+
ServerComm with the same matching `name`.
|
|
110
|
+
|
|
111
|
+
```lua
|
|
112
|
+
local mySignal = clientComm:GetSignal("MySignal")
|
|
113
|
+
|
|
114
|
+
-- Listen for data from the server:
|
|
115
|
+
mySignal:Connect(function(message)
|
|
116
|
+
print("Received message from server:", message)
|
|
117
|
+
end)
|
|
118
|
+
|
|
119
|
+
-- Send data to the server:
|
|
120
|
+
mySignal:Fire("Hello!")
|
|
121
|
+
```
|
|
122
|
+
]=]
|
|
123
|
+
function ClientComm:GetSignal(
|
|
124
|
+
name: string,
|
|
125
|
+
inboundMiddleware: Types.ClientMiddleware?,
|
|
126
|
+
outboundMiddleware: Types.ClientMiddleware?
|
|
127
|
+
)
|
|
128
|
+
return Comm.GetSignal(self._instancesFolder, name, inboundMiddleware, outboundMiddleware)
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
--[=[
|
|
132
|
+
@param name string
|
|
133
|
+
@param inboundMiddleware ClientMiddleware?
|
|
134
|
+
@param outboundMiddleware ClientMiddleware?
|
|
135
|
+
@return ClientRemoteProperty
|
|
136
|
+
Returns a new ClientRemoteProperty that mirrors the matching RemoteProperty created by
|
|
137
|
+
ServerComm with the same matching `name`.
|
|
138
|
+
|
|
139
|
+
Take a look at the ClientRemoteProperty documentation for more info, such as
|
|
140
|
+
understanding how to wait for data to be ready.
|
|
141
|
+
|
|
142
|
+
```lua
|
|
143
|
+
local mapInfo = clientComm:GetProperty("MapInfo")
|
|
144
|
+
|
|
145
|
+
-- Observe the initial value of mapInfo, and all subsequent changes:
|
|
146
|
+
mapInfo:Observe(function(info)
|
|
147
|
+
print("Current map info", info)
|
|
148
|
+
end)
|
|
149
|
+
|
|
150
|
+
-- Check to see if data is initially ready:
|
|
151
|
+
if mapInfo:IsReady() then
|
|
152
|
+
-- Get the data:
|
|
153
|
+
local info = mapInfo:Get()
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
-- Get a promise that resolves once the data is ready (resolves immediately if already ready):
|
|
157
|
+
mapInfo:OnReady():andThen(function(info)
|
|
158
|
+
print("Map info is ready with info", info)
|
|
159
|
+
end)
|
|
160
|
+
|
|
161
|
+
-- Same as above, but yields thread:
|
|
162
|
+
local success, info = mapInfo:OnReady():await()
|
|
163
|
+
```
|
|
164
|
+
]=]
|
|
165
|
+
function ClientComm:GetProperty(
|
|
166
|
+
name: string,
|
|
167
|
+
inboundMiddleware: Types.ClientMiddleware?,
|
|
168
|
+
outboundMiddleware: Types.ClientMiddleware?
|
|
169
|
+
)
|
|
170
|
+
return Comm.GetProperty(self._instancesFolder, name, inboundMiddleware, outboundMiddleware)
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
--[=[
|
|
174
|
+
@param inboundMiddleware ClientMiddleware?
|
|
175
|
+
@param outboundMiddleware ClientMiddleware?
|
|
176
|
+
@return table
|
|
177
|
+
Returns an object which maps RemoteFunctions as methods
|
|
178
|
+
and RemoteEvents as fields.
|
|
179
|
+
```lua
|
|
180
|
+
-- Server-side:
|
|
181
|
+
serverComm:BindFunction("Test", function(player) end)
|
|
182
|
+
serverComm:CreateSignal("MySignal")
|
|
183
|
+
serverComm:CreateProperty("MyProperty", 10)
|
|
184
|
+
|
|
185
|
+
-- Client-side
|
|
186
|
+
local obj = clientComm:BuildObject()
|
|
187
|
+
obj:Test()
|
|
188
|
+
obj.MySignal:Connect(function(data) end)
|
|
189
|
+
obj.MyProperty:Observe(function(value) end)
|
|
190
|
+
```
|
|
191
|
+
]=]
|
|
192
|
+
function ClientComm:BuildObject(inboundMiddleware: Types.ClientMiddleware?, outboundMiddleware: Types.ClientMiddleware?)
|
|
193
|
+
local obj = {}
|
|
194
|
+
local rfFolder = self._instancesFolder:FindFirstChild("RF")
|
|
195
|
+
local reFolder = self._instancesFolder:FindFirstChild("RE")
|
|
196
|
+
local rpFolder = self._instancesFolder:FindFirstChild("RP")
|
|
197
|
+
if rfFolder then
|
|
198
|
+
for _, rf in rfFolder:GetChildren() do
|
|
199
|
+
if not rf:IsA("RemoteFunction") then
|
|
200
|
+
continue
|
|
201
|
+
end
|
|
202
|
+
local f = self:GetFunction(rf.Name, inboundMiddleware, outboundMiddleware)
|
|
203
|
+
obj[rf.Name] = function(_self, ...)
|
|
204
|
+
return f(...)
|
|
205
|
+
end
|
|
206
|
+
end
|
|
207
|
+
end
|
|
208
|
+
if reFolder then
|
|
209
|
+
for _, re in reFolder:GetChildren() do
|
|
210
|
+
if (not re:IsA("RemoteEvent")) and (not re:IsA("UnreliableRemoteEvent")) then
|
|
211
|
+
continue
|
|
212
|
+
end
|
|
213
|
+
obj[re.Name] = self:GetSignal(re.Name, inboundMiddleware, outboundMiddleware)
|
|
214
|
+
end
|
|
215
|
+
end
|
|
216
|
+
if rpFolder then
|
|
217
|
+
for _, re in rpFolder:GetChildren() do
|
|
218
|
+
if not re:IsA("RemoteEvent") then
|
|
219
|
+
continue
|
|
220
|
+
end
|
|
221
|
+
obj[re.Name] = self:GetProperty(re.Name, inboundMiddleware, outboundMiddleware)
|
|
222
|
+
end
|
|
223
|
+
end
|
|
224
|
+
return obj
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
--[=[
|
|
228
|
+
Destroys the ClientComm object.
|
|
229
|
+
]=]
|
|
230
|
+
function ClientComm:Destroy() end
|
|
231
|
+
|
|
232
|
+
return ClientComm
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
-- ClientRemoteProperty
|
|
2
|
+
-- Stephen Leitnick
|
|
3
|
+
-- December 20, 2021
|
|
4
|
+
|
|
5
|
+
local Promise = require(script.Parent.Parent.Parent.Promise)
|
|
6
|
+
local Signal = require(script.Parent.Parent.Parent.Signal)
|
|
7
|
+
local ClientRemoteSignal = require(script.Parent.ClientRemoteSignal)
|
|
8
|
+
local Types = require(script.Parent.Parent.Types)
|
|
9
|
+
|
|
10
|
+
--[=[
|
|
11
|
+
@within ClientRemoteProperty
|
|
12
|
+
@prop Changed Signal<any>
|
|
13
|
+
|
|
14
|
+
Fires when the property receives an updated value
|
|
15
|
+
from the server.
|
|
16
|
+
|
|
17
|
+
```lua
|
|
18
|
+
clientRemoteProperty.Changed:Connect(function(value)
|
|
19
|
+
print("New value", value)
|
|
20
|
+
end)
|
|
21
|
+
```
|
|
22
|
+
]=]
|
|
23
|
+
|
|
24
|
+
--[=[
|
|
25
|
+
@class ClientRemoteProperty
|
|
26
|
+
@client
|
|
27
|
+
Created via `ClientComm:GetProperty()`.
|
|
28
|
+
]=]
|
|
29
|
+
local ClientRemoteProperty = {}
|
|
30
|
+
ClientRemoteProperty.__index = ClientRemoteProperty
|
|
31
|
+
|
|
32
|
+
function ClientRemoteProperty.new(
|
|
33
|
+
re: RemoteEvent,
|
|
34
|
+
inboundMiddleware: Types.ClientMiddleware?,
|
|
35
|
+
outboudMiddleware: Types.ClientMiddleware?
|
|
36
|
+
)
|
|
37
|
+
local self = setmetatable({}, ClientRemoteProperty)
|
|
38
|
+
self._rs = ClientRemoteSignal.new(re, inboundMiddleware, outboudMiddleware)
|
|
39
|
+
self._ready = false
|
|
40
|
+
self._value = nil
|
|
41
|
+
self.Changed = Signal.new()
|
|
42
|
+
self._rs:Fire()
|
|
43
|
+
|
|
44
|
+
local resolveOnReadyPromise
|
|
45
|
+
self._readyPromise = Promise.new(function(resolve)
|
|
46
|
+
resolveOnReadyPromise = resolve
|
|
47
|
+
end)
|
|
48
|
+
self._changed = self._rs:Connect(function(value)
|
|
49
|
+
local changed = value ~= self._value
|
|
50
|
+
self._value = value
|
|
51
|
+
if not self._ready then
|
|
52
|
+
self._ready = true
|
|
53
|
+
resolveOnReadyPromise(value)
|
|
54
|
+
end
|
|
55
|
+
if changed then
|
|
56
|
+
self.Changed:Fire(value)
|
|
57
|
+
end
|
|
58
|
+
end)
|
|
59
|
+
|
|
60
|
+
return self
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
--[=[
|
|
64
|
+
Gets the value of the property object.
|
|
65
|
+
|
|
66
|
+
:::caution
|
|
67
|
+
This value might not be ready right away. Use `OnReady()` or `IsReady()`
|
|
68
|
+
before calling `Get()`. If not ready, this value will return `nil`.
|
|
69
|
+
:::
|
|
70
|
+
]=]
|
|
71
|
+
function ClientRemoteProperty:Get(): any
|
|
72
|
+
return self._value
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
--[=[
|
|
76
|
+
@return Promise<any>
|
|
77
|
+
Returns a Promise which resolves once the property object is
|
|
78
|
+
ready to be used. The resolved promise will also contain the
|
|
79
|
+
value of the property.
|
|
80
|
+
|
|
81
|
+
```lua
|
|
82
|
+
-- Use andThen clause:
|
|
83
|
+
clientRemoteProperty:OnReady():andThen(function(initialValue)
|
|
84
|
+
print(initialValue)
|
|
85
|
+
end)
|
|
86
|
+
|
|
87
|
+
-- Use await:
|
|
88
|
+
local success, initialValue = clientRemoteProperty:OnReady():await()
|
|
89
|
+
if success then
|
|
90
|
+
print(initialValue)
|
|
91
|
+
end
|
|
92
|
+
```
|
|
93
|
+
]=]
|
|
94
|
+
function ClientRemoteProperty:OnReady()
|
|
95
|
+
return self._readyPromise
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
--[=[
|
|
99
|
+
Returns `true` if the property object is ready to be
|
|
100
|
+
used. In other words, it has successfully gained
|
|
101
|
+
connection to the server-side version and has synced
|
|
102
|
+
in the initial value.
|
|
103
|
+
|
|
104
|
+
```lua
|
|
105
|
+
if clientRemoteProperty:IsReady() then
|
|
106
|
+
local value = clientRemoteProperty:Get()
|
|
107
|
+
end
|
|
108
|
+
```
|
|
109
|
+
]=]
|
|
110
|
+
function ClientRemoteProperty:IsReady(): boolean
|
|
111
|
+
return self._ready
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
--[=[
|
|
115
|
+
@param observer (any) -> nil
|
|
116
|
+
@return Connection
|
|
117
|
+
Observes the value of the property. The observer will
|
|
118
|
+
be called right when the value is first ready, and
|
|
119
|
+
every time the value changes. This is safe to call
|
|
120
|
+
immediately (i.e. no need to use `IsReady` or `OnReady`
|
|
121
|
+
before using this method).
|
|
122
|
+
|
|
123
|
+
Observing is essentially listening to `Changed`, but
|
|
124
|
+
also sends the initial value right away (or at least
|
|
125
|
+
once `OnReady` is completed).
|
|
126
|
+
|
|
127
|
+
```lua
|
|
128
|
+
local function ObserveValue(value)
|
|
129
|
+
print(value)
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
clientRemoteProperty:Observe(ObserveValue)
|
|
133
|
+
```
|
|
134
|
+
]=]
|
|
135
|
+
function ClientRemoteProperty:Observe(observer: (any) -> ())
|
|
136
|
+
if self._ready then
|
|
137
|
+
task.defer(observer, self._value)
|
|
138
|
+
end
|
|
139
|
+
return self.Changed:Connect(observer)
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
--[=[
|
|
143
|
+
Destroys the ClientRemoteProperty object.
|
|
144
|
+
]=]
|
|
145
|
+
function ClientRemoteProperty:Destroy()
|
|
146
|
+
self._rs:Destroy()
|
|
147
|
+
if self._readyPromise then
|
|
148
|
+
self._readyPromise:cancel()
|
|
149
|
+
end
|
|
150
|
+
if self._changed then
|
|
151
|
+
self._changed:Disconnect()
|
|
152
|
+
end
|
|
153
|
+
self.Changed:Destroy()
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
return ClientRemoteProperty
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
-- ClientRemoteSignal
|
|
2
|
+
-- Stephen Leitnick
|
|
3
|
+
-- December 20, 2021
|
|
4
|
+
|
|
5
|
+
local Signal = require(script.Parent.Parent.Parent.Signal)
|
|
6
|
+
local Types = require(script.Parent.Parent.Types)
|
|
7
|
+
|
|
8
|
+
--[=[
|
|
9
|
+
@class ClientRemoteSignal
|
|
10
|
+
@client
|
|
11
|
+
Created via `ClientComm:GetSignal()`.
|
|
12
|
+
]=]
|
|
13
|
+
local ClientRemoteSignal = {}
|
|
14
|
+
ClientRemoteSignal.__index = ClientRemoteSignal
|
|
15
|
+
|
|
16
|
+
--[=[
|
|
17
|
+
@within ClientRemoteSignal
|
|
18
|
+
@interface Connection
|
|
19
|
+
.Disconnect () -> ()
|
|
20
|
+
|
|
21
|
+
Represents a connection.
|
|
22
|
+
]=]
|
|
23
|
+
|
|
24
|
+
function ClientRemoteSignal.new(
|
|
25
|
+
re: RemoteEvent | UnreliableRemoteEvent,
|
|
26
|
+
inboundMiddleware: Types.ClientMiddleware?,
|
|
27
|
+
outboudMiddleware: Types.ClientMiddleware?
|
|
28
|
+
)
|
|
29
|
+
local self = setmetatable({}, ClientRemoteSignal)
|
|
30
|
+
self._re = re
|
|
31
|
+
if outboudMiddleware and #outboudMiddleware > 0 then
|
|
32
|
+
self._hasOutbound = true
|
|
33
|
+
self._outbound = outboudMiddleware
|
|
34
|
+
else
|
|
35
|
+
self._hasOutbound = false
|
|
36
|
+
end
|
|
37
|
+
if inboundMiddleware and #inboundMiddleware > 0 then
|
|
38
|
+
self._directConnect = false
|
|
39
|
+
self._signal = Signal.new()
|
|
40
|
+
self._reConn = self._re.OnClientEvent:Connect(function(...)
|
|
41
|
+
local args = table.pack(...)
|
|
42
|
+
for _, middlewareFunc in inboundMiddleware do
|
|
43
|
+
local middlewareResult = table.pack(middlewareFunc(args))
|
|
44
|
+
if not middlewareResult[1] then
|
|
45
|
+
return
|
|
46
|
+
end
|
|
47
|
+
args.n = #args
|
|
48
|
+
end
|
|
49
|
+
self._signal:Fire(table.unpack(args, 1, args.n))
|
|
50
|
+
end)
|
|
51
|
+
else
|
|
52
|
+
self._directConnect = true
|
|
53
|
+
end
|
|
54
|
+
return self
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
function ClientRemoteSignal:_processOutboundMiddleware(...: any)
|
|
58
|
+
local args = table.pack(...)
|
|
59
|
+
for _, middlewareFunc in self._outbound do
|
|
60
|
+
local middlewareResult = table.pack(middlewareFunc(args))
|
|
61
|
+
if not middlewareResult[1] then
|
|
62
|
+
return table.unpack(middlewareResult, 2, middlewareResult.n)
|
|
63
|
+
end
|
|
64
|
+
args.n = #args
|
|
65
|
+
end
|
|
66
|
+
return table.unpack(args, 1, args.n)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
--[=[
|
|
70
|
+
@param fn (...: any) -> ()
|
|
71
|
+
@return Connection
|
|
72
|
+
Connects a function to the remote signal. The function will be
|
|
73
|
+
called anytime the equivalent server-side RemoteSignal is
|
|
74
|
+
fired at this specific client that created this client signal.
|
|
75
|
+
]=]
|
|
76
|
+
function ClientRemoteSignal:Connect(fn: (...any) -> ())
|
|
77
|
+
if self._directConnect then
|
|
78
|
+
return self._re.OnClientEvent:Connect(fn)
|
|
79
|
+
else
|
|
80
|
+
return self._signal:Connect(fn)
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
--[=[
|
|
85
|
+
Fires the equivalent server-side signal with the given arguments.
|
|
86
|
+
|
|
87
|
+
:::note Outbound Middleware
|
|
88
|
+
All arguments pass through any outbound middleware before being
|
|
89
|
+
sent to the server.
|
|
90
|
+
:::
|
|
91
|
+
]=]
|
|
92
|
+
function ClientRemoteSignal:Fire(...: any)
|
|
93
|
+
if self._hasOutbound then
|
|
94
|
+
self._re:FireServer(self:_processOutboundMiddleware(...))
|
|
95
|
+
else
|
|
96
|
+
self._re:FireServer(...)
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
--[=[
|
|
101
|
+
Destroys the ClientRemoteSignal object.
|
|
102
|
+
]=]
|
|
103
|
+
function ClientRemoteSignal:Destroy()
|
|
104
|
+
if self._signal then
|
|
105
|
+
self._signal:Destroy()
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
return ClientRemoteSignal
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
local Util = require(script.Parent.Util)
|
|
2
|
+
local Types = require(script.Parent.Types)
|
|
3
|
+
local Promise = require(script.Parent.Parent.Promise)
|
|
4
|
+
local ClientRemoteSignal = require(script.ClientRemoteSignal)
|
|
5
|
+
local ClientRemoteProperty = require(script.ClientRemoteProperty)
|
|
6
|
+
|
|
7
|
+
local Client = {}
|
|
8
|
+
|
|
9
|
+
function Client.GetFunction(
|
|
10
|
+
parent: Instance,
|
|
11
|
+
name: string,
|
|
12
|
+
usePromise: boolean,
|
|
13
|
+
inboundMiddleware: Types.ClientMiddleware?,
|
|
14
|
+
outboundMiddleware: Types.ClientMiddleware?
|
|
15
|
+
)
|
|
16
|
+
assert(not Util.IsServer, "GetFunction must be called from the client")
|
|
17
|
+
local folder = Util.GetCommSubFolder(parent, "RF"):Expect("Failed to get Comm RF folder")
|
|
18
|
+
local rf = folder:WaitForChild(name, Util.WaitForChildTimeout)
|
|
19
|
+
assert(rf ~= nil, "Failed to find RemoteFunction: " .. name)
|
|
20
|
+
local hasInbound = type(inboundMiddleware) == "table" and #inboundMiddleware > 0
|
|
21
|
+
local hasOutbound = type(outboundMiddleware) == "table" and #outboundMiddleware > 0
|
|
22
|
+
local function ProcessOutbound(args)
|
|
23
|
+
for _, middlewareFunc in ipairs(outboundMiddleware) do
|
|
24
|
+
local middlewareResult = table.pack(middlewareFunc(args))
|
|
25
|
+
if not middlewareResult[1] then
|
|
26
|
+
return table.unpack(middlewareResult, 2, middlewareResult.n)
|
|
27
|
+
end
|
|
28
|
+
args.n = #args
|
|
29
|
+
end
|
|
30
|
+
return table.unpack(args, 1, args.n)
|
|
31
|
+
end
|
|
32
|
+
if hasInbound then
|
|
33
|
+
if usePromise then
|
|
34
|
+
return function(...)
|
|
35
|
+
local args = table.pack(...)
|
|
36
|
+
return Promise.new(function(resolve, reject)
|
|
37
|
+
local success, res = pcall(function()
|
|
38
|
+
if hasOutbound then
|
|
39
|
+
return table.pack(rf:InvokeServer(ProcessOutbound(args)))
|
|
40
|
+
else
|
|
41
|
+
return table.pack(rf:InvokeServer(table.unpack(args, 1, args.n)))
|
|
42
|
+
end
|
|
43
|
+
end)
|
|
44
|
+
if success then
|
|
45
|
+
for _, middlewareFunc in ipairs(inboundMiddleware) do
|
|
46
|
+
local middlewareResult = table.pack(middlewareFunc(res))
|
|
47
|
+
if not middlewareResult[1] then
|
|
48
|
+
return table.unpack(middlewareResult, 2, middlewareResult.n)
|
|
49
|
+
end
|
|
50
|
+
res.n = #res
|
|
51
|
+
end
|
|
52
|
+
resolve(table.unpack(res, 1, res.n))
|
|
53
|
+
else
|
|
54
|
+
reject(res)
|
|
55
|
+
end
|
|
56
|
+
end)
|
|
57
|
+
end
|
|
58
|
+
else
|
|
59
|
+
return function(...)
|
|
60
|
+
local res
|
|
61
|
+
if hasOutbound then
|
|
62
|
+
res = table.pack(rf:InvokeServer(ProcessOutbound(table.pack(...))))
|
|
63
|
+
else
|
|
64
|
+
res = table.pack(rf:InvokeServer(...))
|
|
65
|
+
end
|
|
66
|
+
for _, middlewareFunc in ipairs(inboundMiddleware) do
|
|
67
|
+
local middlewareResult = table.pack(middlewareFunc(res))
|
|
68
|
+
if not middlewareResult[1] then
|
|
69
|
+
return table.unpack(middlewareResult, 2, middlewareResult.n)
|
|
70
|
+
end
|
|
71
|
+
res.n = #res
|
|
72
|
+
end
|
|
73
|
+
return table.unpack(res, 1, res.n)
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
else
|
|
77
|
+
if usePromise then
|
|
78
|
+
return function(...)
|
|
79
|
+
local args = table.pack(...)
|
|
80
|
+
return Promise.new(function(resolve, reject)
|
|
81
|
+
local success, res = pcall(function()
|
|
82
|
+
if hasOutbound then
|
|
83
|
+
return table.pack(rf:InvokeServer(ProcessOutbound(args)))
|
|
84
|
+
else
|
|
85
|
+
return table.pack(rf:InvokeServer(table.unpack(args, 1, args.n)))
|
|
86
|
+
end
|
|
87
|
+
end)
|
|
88
|
+
if success then
|
|
89
|
+
resolve(table.unpack(res, 1, res.n))
|
|
90
|
+
else
|
|
91
|
+
reject(res)
|
|
92
|
+
end
|
|
93
|
+
end)
|
|
94
|
+
end
|
|
95
|
+
else
|
|
96
|
+
if hasOutbound then
|
|
97
|
+
return function(...)
|
|
98
|
+
return rf:InvokeServer(ProcessOutbound(table.pack(...)))
|
|
99
|
+
end
|
|
100
|
+
else
|
|
101
|
+
return function(...)
|
|
102
|
+
return rf:InvokeServer(...)
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
function Client.GetSignal(
|
|
110
|
+
parent: Instance,
|
|
111
|
+
name: string,
|
|
112
|
+
inboundMiddleware: Types.ClientMiddleware?,
|
|
113
|
+
outboundMiddleware: Types.ClientMiddleware?
|
|
114
|
+
)
|
|
115
|
+
assert(not Util.IsServer, "GetSignal must be called from the client")
|
|
116
|
+
local folder = Util.GetCommSubFolder(parent, "RE"):Expect("Failed to get Comm RE folder")
|
|
117
|
+
local re = folder:WaitForChild(name, Util.WaitForChildTimeout)
|
|
118
|
+
assert(re ~= nil, "Failed to find RemoteEvent: " .. name)
|
|
119
|
+
return ClientRemoteSignal.new(re, inboundMiddleware, outboundMiddleware)
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
function Client.GetProperty(
|
|
123
|
+
parent: Instance,
|
|
124
|
+
name: string,
|
|
125
|
+
inboundMiddleware: Types.ClientMiddleware?,
|
|
126
|
+
outboundMiddleware: Types.ClientMiddleware?
|
|
127
|
+
)
|
|
128
|
+
assert(not Util.IsServer, "GetProperty must be called from the client")
|
|
129
|
+
local folder = Util.GetCommSubFolder(parent, "RP"):Expect("Failed to get Comm RP folder")
|
|
130
|
+
local re = folder:WaitForChild(name, Util.WaitForChildTimeout)
|
|
131
|
+
assert(re ~= nil, "Failed to find RemoteEvent for RemoteProperty: " .. name)
|
|
132
|
+
return ClientRemoteProperty.new(re, inboundMiddleware, outboundMiddleware)
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
return Client
|