roblox-opencode 1.0.0 → 1.0.1
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 +112 -122
- package/commands/setup-game.md +108 -108
- package/commands/sync-check.md +53 -53
- package/core/roblox-core.md +93 -93
- package/dist/server.js +189 -167
- package/package.json +35 -35
- package/skills/roblox-analytics/SKILL.md +277 -277
- package/skills/roblox-analytics/references/event-batcher.luau +75 -75
- package/skills/roblox-animation-vfx/SKILL.md +1325 -1325
- package/skills/roblox-architecture/SKILL.md +863 -863
- package/skills/roblox-architecture/references/combat-systems.md +1381 -1381
- package/skills/roblox-code-review/SKILL.md +686 -686
- package/skills/roblox-data/SKILL.md +889 -889
- package/skills/roblox-data/references/inventory-systems.md +1729 -1729
- package/skills/roblox-debug/SKILL.md +98 -98
- package/skills/roblox-gui/SKILL.md +1103 -1103
- package/skills/roblox-gui-fusion/SKILL.md +150 -150
- package/skills/roblox-gui-fusion/references/inventory.luau +427 -427
- package/skills/roblox-gui-fusion/references/settings-menu.luau +579 -579
- package/skills/roblox-gui-fusion/references/shop.luau +411 -411
- package/skills/roblox-luau-mastery/SKILL.md +1519 -1519
- package/skills/roblox-monetization/SKILL.md +1084 -1084
- package/skills/roblox-monetization/references/process-receipt.luau +131 -131
- package/skills/roblox-networking/SKILL.md +669 -669
- package/skills/roblox-networking/references/remote-validator.luau +193 -193
- package/skills/roblox-publish-checklist/SKILL.md +127 -127
- package/skills/roblox-runtime/SKILL.md +753 -753
- package/skills/roblox-sharp-edges/SKILL.md +294 -294
- package/skills/roblox-sync/SKILL.md +126 -126
- package/skills/roblox-testing/SKILL.md +943 -943
- package/skills/roblox-tooling/SKILL.md +149 -149
- package/vendor/LICENSES/ProfileStore-LICENSE +201 -201
- package/vendor/LICENSES/RbxUtil-LICENSE +7 -7
- package/vendor/LICENSES/promise-LICENSE +20 -20
- package/vendor/LICENSES/t-LICENSE +21 -21
- package/vendor/LICENSES/testez-LICENSE +200 -200
- package/vendor/README.md +83 -83
- package/vendor/fusion/Animation/ExternalTime.luau +83 -83
- package/vendor/fusion/Animation/Spring.luau +321 -321
- package/vendor/fusion/Animation/Stopwatch.luau +127 -127
- package/vendor/fusion/Animation/Tween.luau +187 -187
- package/vendor/fusion/Animation/getTweenDuration.luau +27 -27
- package/vendor/fusion/Animation/getTweenRatio.luau +47 -47
- package/vendor/fusion/Animation/lerpType.luau +163 -163
- package/vendor/fusion/Animation/packType.luau +99 -99
- package/vendor/fusion/Animation/springCoefficients.luau +80 -80
- package/vendor/fusion/Animation/unpackType.luau +102 -102
- package/vendor/fusion/Colour/Oklab.luau +70 -70
- package/vendor/fusion/Colour/sRGB.luau +54 -54
- package/vendor/fusion/External.luau +167 -167
- package/vendor/fusion/ExternalDebug.luau +69 -69
- package/vendor/fusion/Graph/Observer.luau +113 -113
- package/vendor/fusion/Graph/castToGraph.luau +28 -28
- package/vendor/fusion/Graph/change.luau +80 -80
- package/vendor/fusion/Graph/depend.luau +32 -32
- package/vendor/fusion/Graph/evaluate.luau +55 -55
- package/vendor/fusion/Instances/Attribute.luau +57 -57
- package/vendor/fusion/Instances/AttributeChange.luau +46 -46
- package/vendor/fusion/Instances/AttributeOut.luau +63 -63
- package/vendor/fusion/Instances/Child.luau +21 -21
- package/vendor/fusion/Instances/Children.luau +147 -147
- package/vendor/fusion/Instances/Hydrate.luau +32 -32
- package/vendor/fusion/Instances/New.luau +52 -52
- package/vendor/fusion/Instances/OnChange.luau +49 -49
- package/vendor/fusion/Instances/OnEvent.luau +53 -53
- package/vendor/fusion/Instances/Out.luau +69 -69
- package/vendor/fusion/Instances/applyInstanceProps.luau +148 -148
- package/vendor/fusion/Instances/defaultProps.luau +194 -194
- package/vendor/fusion/LICENSE +21 -21
- package/vendor/fusion/Logging/formatError.luau +48 -48
- package/vendor/fusion/Logging/messages.luau +51 -51
- package/vendor/fusion/Logging/parseError.luau +24 -24
- package/vendor/fusion/Memory/checkLifetime.luau +133 -133
- package/vendor/fusion/Memory/deriveScope.luau +23 -23
- package/vendor/fusion/Memory/deriveScopeImpl.luau +44 -44
- package/vendor/fusion/Memory/doCleanup.luau +78 -78
- package/vendor/fusion/Memory/innerScope.luau +33 -33
- package/vendor/fusion/Memory/legacyCleanup.luau +17 -17
- package/vendor/fusion/Memory/needsDestruction.luau +16 -16
- package/vendor/fusion/Memory/poisonScope.luau +33 -33
- package/vendor/fusion/Memory/scopePool.luau +54 -54
- package/vendor/fusion/Memory/scoped.luau +26 -26
- package/vendor/fusion/Memory/whichLivesLonger.luau +74 -74
- package/vendor/fusion/RobloxExternal.luau +97 -97
- package/vendor/fusion/State/Computed.luau +138 -138
- package/vendor/fusion/State/For/Disassembly.luau +210 -210
- package/vendor/fusion/State/For/ForTypes.luau +30 -30
- package/vendor/fusion/State/For/init.luau +109 -109
- package/vendor/fusion/State/ForKeys.luau +93 -93
- package/vendor/fusion/State/ForPairs.luau +96 -96
- package/vendor/fusion/State/ForValues.luau +93 -93
- package/vendor/fusion/State/Value.luau +87 -87
- package/vendor/fusion/State/castToState.luau +25 -25
- package/vendor/fusion/State/peek.luau +30 -30
- package/vendor/fusion/Types.luau +314 -314
- package/vendor/fusion/Utility/Contextual.luau +90 -90
- package/vendor/fusion/Utility/Safe.luau +22 -22
- package/vendor/fusion/Utility/isSimilar.luau +29 -29
- package/vendor/fusion/Utility/merge.luau +35 -35
- package/vendor/fusion/Utility/nameOf.luau +34 -34
- package/vendor/fusion/Utility/never.luau +13 -13
- package/vendor/fusion/Utility/nicknames.luau +10 -10
- package/vendor/fusion/Utility/xtypeof.luau +26 -26
- package/vendor/fusion/init.luau +82 -82
- package/vendor/profilestore/init.luau +2242 -2242
- package/vendor/promise/init.luau +1982 -1982
- package/vendor/rbxutil/buffer-util/Buffer.test.luau +25 -25
- package/vendor/rbxutil/buffer-util/BufferReader.luau +228 -228
- package/vendor/rbxutil/buffer-util/BufferWriter.luau +269 -269
- package/vendor/rbxutil/buffer-util/DataTypeBuffer.luau +223 -223
- package/vendor/rbxutil/buffer-util/Types.luau +60 -60
- package/vendor/rbxutil/buffer-util/index.d.ts +153 -153
- package/vendor/rbxutil/buffer-util/init.luau +41 -41
- package/vendor/rbxutil/buffer-util/package.json +16 -16
- package/vendor/rbxutil/buffer-util/wally.toml +9 -9
- package/vendor/rbxutil/comm/Client/ClientComm.luau +232 -232
- package/vendor/rbxutil/comm/Client/ClientRemoteProperty.luau +156 -156
- package/vendor/rbxutil/comm/Client/ClientRemoteSignal.luau +109 -109
- package/vendor/rbxutil/comm/Client/init.luau +135 -135
- package/vendor/rbxutil/comm/Server/RemoteProperty.luau +295 -295
- package/vendor/rbxutil/comm/Server/RemoteSignal.luau +211 -211
- package/vendor/rbxutil/comm/Server/ServerComm.luau +211 -211
- package/vendor/rbxutil/comm/Server/init.luau +140 -140
- package/vendor/rbxutil/comm/Types.luau +18 -18
- package/vendor/rbxutil/comm/Util.luau +27 -27
- package/vendor/rbxutil/comm/init.luau +35 -35
- package/vendor/rbxutil/comm/wally.toml +13 -13
- package/vendor/rbxutil/component/init.luau +759 -759
- package/vendor/rbxutil/component/init.test.luau +311 -311
- package/vendor/rbxutil/component/wally.toml +14 -14
- package/vendor/rbxutil/concur/init.luau +542 -542
- package/vendor/rbxutil/concur/init.test.luau +364 -364
- package/vendor/rbxutil/concur/wally.toml +8 -8
- package/vendor/rbxutil/enum-list/init.luau +101 -101
- package/vendor/rbxutil/enum-list/init.test.luau +91 -91
- package/vendor/rbxutil/enum-list/wally.toml +8 -8
- package/vendor/rbxutil/find/index.d.ts +20 -20
- package/vendor/rbxutil/find/init.luau +44 -44
- package/vendor/rbxutil/find/package.json +17 -17
- package/vendor/rbxutil/find/wally.toml +8 -8
- package/vendor/rbxutil/input/Gamepad.luau +559 -559
- package/vendor/rbxutil/input/Keyboard.luau +124 -124
- package/vendor/rbxutil/input/Mouse.luau +278 -278
- package/vendor/rbxutil/input/PreferredInput.luau +91 -91
- package/vendor/rbxutil/input/Touch.luau +120 -120
- package/vendor/rbxutil/input/init.luau +33 -33
- package/vendor/rbxutil/input/wally.toml +12 -12
- package/vendor/rbxutil/loader/index.d.ts +15 -15
- package/vendor/rbxutil/loader/init.luau +137 -137
- package/vendor/rbxutil/loader/wally.toml +8 -8
- package/vendor/rbxutil/log/index.d.ts +38 -38
- package/vendor/rbxutil/log/init.luau +746 -746
- package/vendor/rbxutil/log/wally.toml +8 -8
- package/vendor/rbxutil/net/init.luau +190 -190
- package/vendor/rbxutil/net/wally.toml +8 -8
- package/vendor/rbxutil/option/index.d.ts +44 -44
- package/vendor/rbxutil/option/init.luau +489 -489
- package/vendor/rbxutil/option/init.test.luau +342 -342
- package/vendor/rbxutil/option/wally.toml +8 -8
- package/vendor/rbxutil/pid/index.d.ts +53 -53
- package/vendor/rbxutil/pid/init.luau +195 -195
- package/vendor/rbxutil/pid/package.json +16 -16
- package/vendor/rbxutil/pid/wally.toml +9 -9
- package/vendor/rbxutil/quaternion/index.d.ts +117 -117
- package/vendor/rbxutil/quaternion/init.luau +570 -570
- package/vendor/rbxutil/quaternion/package.json +16 -16
- package/vendor/rbxutil/quaternion/wally.toml +9 -9
- package/vendor/rbxutil/query/index.d.ts +43 -43
- package/vendor/rbxutil/query/init.luau +117 -117
- package/vendor/rbxutil/query/package.json +18 -18
- package/vendor/rbxutil/query/wally.toml +9 -9
- package/vendor/rbxutil/sequent/index.d.ts +28 -28
- package/vendor/rbxutil/sequent/init.luau +340 -340
- package/vendor/rbxutil/sequent/package.json +16 -16
- package/vendor/rbxutil/sequent/wally.toml +9 -9
- package/vendor/rbxutil/ser/init.luau +175 -175
- package/vendor/rbxutil/ser/init.test.luau +50 -50
- package/vendor/rbxutil/ser/wally.toml +11 -11
- package/vendor/rbxutil/shake/index.d.ts +36 -36
- package/vendor/rbxutil/shake/init.luau +532 -532
- package/vendor/rbxutil/shake/init.test.luau +267 -267
- package/vendor/rbxutil/shake/package.json +16 -16
- package/vendor/rbxutil/shake/wally.toml +9 -9
- package/vendor/rbxutil/signal/index.d.ts +100 -100
- package/vendor/rbxutil/signal/init.luau +432 -432
- package/vendor/rbxutil/signal/init.test.luau +190 -190
- package/vendor/rbxutil/signal/package.json +17 -17
- package/vendor/rbxutil/signal/wally.toml +9 -9
- package/vendor/rbxutil/silo/TableWatcher.luau +65 -65
- package/vendor/rbxutil/silo/Util.luau +55 -55
- package/vendor/rbxutil/silo/init.luau +338 -338
- package/vendor/rbxutil/silo/init.test.luau +215 -215
- package/vendor/rbxutil/silo/wally.toml +8 -8
- package/vendor/rbxutil/spring/index.d.ts +40 -40
- package/vendor/rbxutil/spring/init.luau +97 -97
- package/vendor/rbxutil/spring/package.json +17 -17
- package/vendor/rbxutil/spring/wally.toml +8 -8
- package/vendor/rbxutil/stream/index.d.ts +88 -88
- package/vendor/rbxutil/stream/init.luau +597 -597
- package/vendor/rbxutil/stream/package.json +18 -18
- package/vendor/rbxutil/stream/wally.toml +9 -9
- package/vendor/rbxutil/streamable/Streamable.luau +202 -202
- package/vendor/rbxutil/streamable/StreamableUtil.luau +80 -80
- package/vendor/rbxutil/streamable/init.luau +8 -8
- package/vendor/rbxutil/streamable/wally.toml +12 -12
- package/vendor/rbxutil/symbol/init.luau +56 -56
- package/vendor/rbxutil/symbol/init.test.luau +37 -37
- package/vendor/rbxutil/symbol/wally.toml +8 -8
- package/vendor/rbxutil/table-util/init.luau +938 -938
- package/vendor/rbxutil/table-util/init.test.luau +439 -439
- package/vendor/rbxutil/task-queue/index.d.ts +27 -27
- package/vendor/rbxutil/task-queue/init.luau +97 -97
- package/vendor/rbxutil/task-queue/wally.toml +8 -8
- package/vendor/rbxutil/timer/index.d.ts +81 -81
- package/vendor/rbxutil/timer/init.luau +249 -249
- package/vendor/rbxutil/timer/init.test.luau +73 -73
- package/vendor/rbxutil/timer/wally.toml +11 -11
- package/vendor/rbxutil/tree/index.d.ts +15 -15
- package/vendor/rbxutil/tree/init.luau +137 -137
- package/vendor/rbxutil/tree/wally.toml +8 -8
- package/vendor/rbxutil/trove/index.d.ts +46 -46
- package/vendor/rbxutil/trove/init.luau +787 -787
- package/vendor/rbxutil/trove/init.test.luau +203 -203
- package/vendor/rbxutil/trove/wally.toml +8 -8
- package/vendor/rbxutil/typed-remote/init.luau +196 -196
- package/vendor/rbxutil/typed-remote/wally.toml +8 -8
- package/vendor/rbxutil/wait-for/index.d.ts +17 -17
- package/vendor/rbxutil/wait-for/init.luau +257 -257
- package/vendor/rbxutil/wait-for/init.test.luau +182 -182
- package/vendor/rbxutil/wait-for/wally.toml +11 -11
- package/vendor/t/t.lua +1350 -1350
- package/vendor/testez/Context.lua +26 -26
- package/vendor/testez/Expectation.lua +311 -311
- package/vendor/testez/ExpectationContext.lua +38 -38
- package/vendor/testez/LifecycleHooks.lua +89 -89
- package/vendor/testez/Reporters/TeamCityReporter.lua +101 -101
- package/vendor/testez/Reporters/TextReporter.lua +105 -105
- package/vendor/testez/Reporters/TextReporterQuiet.lua +96 -96
- package/vendor/testez/TestBootstrap.lua +146 -146
- package/vendor/testez/TestEnum.lua +27 -27
- package/vendor/testez/TestPlan.lua +304 -304
- package/vendor/testez/TestPlanner.lua +39 -39
- package/vendor/testez/TestResults.lua +111 -111
- package/vendor/testez/TestRunner.lua +188 -188
- package/vendor/testez/TestSession.lua +243 -243
- package/vendor/testez/init.lua +39 -39
|
@@ -1,257 +1,257 @@
|
|
|
1
|
-
-- WaitFor
|
|
2
|
-
-- Stephen Leitnick
|
|
3
|
-
-- January 17, 2022
|
|
4
|
-
|
|
5
|
-
local RunService = game:GetService("RunService")
|
|
6
|
-
|
|
7
|
-
local Promise = require(script.Parent.Promise)
|
|
8
|
-
|
|
9
|
-
local DEFAULT_TIMEOUT = 60
|
|
10
|
-
|
|
11
|
-
--[=[
|
|
12
|
-
@class WaitFor
|
|
13
|
-
Utility class for awaiting the existence of instances.
|
|
14
|
-
|
|
15
|
-
By default, all promises timeout after 60 seconds, unless the `timeout`
|
|
16
|
-
argument is specified.
|
|
17
|
-
|
|
18
|
-
:::note
|
|
19
|
-
Promises will be rejected if the parent (or any ancestor) is unparented
|
|
20
|
-
from the game.
|
|
21
|
-
:::
|
|
22
|
-
|
|
23
|
-
:::caution Set name before parent
|
|
24
|
-
When waiting for instances based on name (e.g. `WaitFor.Child`), the `WaitFor`
|
|
25
|
-
system is listening to events to capture these instances being added. This
|
|
26
|
-
means that the name must be set _before_ being parented into the object.
|
|
27
|
-
:::
|
|
28
|
-
]=]
|
|
29
|
-
local WaitFor = {}
|
|
30
|
-
|
|
31
|
-
--[=[
|
|
32
|
-
@within WaitFor
|
|
33
|
-
@prop Error {Unparented: string, ParentChanged: string}
|
|
34
|
-
]=]
|
|
35
|
-
WaitFor.Error = {
|
|
36
|
-
Unparented = "Unparented",
|
|
37
|
-
ParentChanged = "ParentChanged",
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
local function PromiseWatchAncestry(instance: Instance, promise)
|
|
41
|
-
return Promise.race({
|
|
42
|
-
promise,
|
|
43
|
-
Promise.fromEvent(instance.AncestryChanged, function(_, newParent)
|
|
44
|
-
return newParent == nil
|
|
45
|
-
end):andThen(function()
|
|
46
|
-
return Promise.reject(WaitFor.Error.Unparented)
|
|
47
|
-
end),
|
|
48
|
-
})
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
--[=[
|
|
52
|
-
@return Promise<Instance>
|
|
53
|
-
Wait for a child to exist within a given parent based on the child name.
|
|
54
|
-
|
|
55
|
-
```lua
|
|
56
|
-
WaitFor.Child(parent, "SomeObject"):andThen(function(someObject)
|
|
57
|
-
print(someObject, "now exists")
|
|
58
|
-
end):catch(warn)
|
|
59
|
-
```
|
|
60
|
-
]=]
|
|
61
|
-
function WaitFor.Child(parent: Instance, childName: string, timeout: number?)
|
|
62
|
-
local child = parent:FindFirstChild(childName)
|
|
63
|
-
if child then
|
|
64
|
-
return Promise.resolve(child)
|
|
65
|
-
end
|
|
66
|
-
return PromiseWatchAncestry(
|
|
67
|
-
parent,
|
|
68
|
-
Promise.fromEvent(parent.ChildAdded, function(c)
|
|
69
|
-
return c.Name == childName
|
|
70
|
-
end):timeout(timeout or DEFAULT_TIMEOUT)
|
|
71
|
-
)
|
|
72
|
-
end
|
|
73
|
-
|
|
74
|
-
--[=[
|
|
75
|
-
@return Promise<{Instance}>
|
|
76
|
-
Wait for all children to exist within the given parent.
|
|
77
|
-
|
|
78
|
-
```lua
|
|
79
|
-
WaitFor.Children(parent, {"SomeObject01", "SomeObject02"}):andThen(function(children)
|
|
80
|
-
local someObject01, someObject02 = table.unpack(children)
|
|
81
|
-
end)
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
:::note
|
|
85
|
-
Once all children are found, a second check is made to ensure that all children
|
|
86
|
-
are still directly parented to the given `parent` (since one child's parent
|
|
87
|
-
might have changed before another child was found). A rejected promise with the
|
|
88
|
-
`WaitFor.Error.ParentChanged` error will be thrown if any parents of the children
|
|
89
|
-
no longer match the given `parent`.
|
|
90
|
-
:::
|
|
91
|
-
]=]
|
|
92
|
-
function WaitFor.Children(parent: Instance, childrenNames: { string }, timeout: number?)
|
|
93
|
-
local all = table.create(#childrenNames)
|
|
94
|
-
for i, childName in ipairs(childrenNames) do
|
|
95
|
-
all[i] = WaitFor.Child(parent, childName, timeout)
|
|
96
|
-
end
|
|
97
|
-
return Promise.all(all):andThen(function(children)
|
|
98
|
-
-- Check that all are still parented
|
|
99
|
-
for _, child in ipairs(children) do
|
|
100
|
-
if child.Parent ~= parent then
|
|
101
|
-
return Promise.reject(WaitFor.Error.ParentChanged)
|
|
102
|
-
end
|
|
103
|
-
end
|
|
104
|
-
return children
|
|
105
|
-
end)
|
|
106
|
-
end
|
|
107
|
-
|
|
108
|
-
--[=[
|
|
109
|
-
@return Promise<Instance>
|
|
110
|
-
Wait for a descendant to exist within a given parent. This is similar to
|
|
111
|
-
`WaitFor.Child`, except it looks for all descendants instead of immediate
|
|
112
|
-
children.
|
|
113
|
-
|
|
114
|
-
```lua
|
|
115
|
-
WaitFor.Descendant(parent, "SomeDescendant"):andThen(function(someDescendant)
|
|
116
|
-
print("SomeDescendant now exists")
|
|
117
|
-
end)
|
|
118
|
-
```
|
|
119
|
-
]=]
|
|
120
|
-
function WaitFor.Descendant(parent: Instance, descendantName: string, timeout: number?)
|
|
121
|
-
local descendant = parent:FindFirstChild(descendantName, true)
|
|
122
|
-
if descendant then
|
|
123
|
-
return Promise.resolve(descendant)
|
|
124
|
-
end
|
|
125
|
-
return PromiseWatchAncestry(
|
|
126
|
-
parent,
|
|
127
|
-
Promise.fromEvent(parent.DescendantAdded, function(d)
|
|
128
|
-
return d.Name == descendantName
|
|
129
|
-
end):timeout(timeout or DEFAULT_TIMEOUT)
|
|
130
|
-
)
|
|
131
|
-
end
|
|
132
|
-
|
|
133
|
-
--[=[
|
|
134
|
-
@return Promise<{Instance}>
|
|
135
|
-
Wait for all descendants to exist within a given parent.
|
|
136
|
-
|
|
137
|
-
```lua
|
|
138
|
-
WaitFor.Descendants(parent, {"SomeDescendant01", "SomeDescendant02"}):andThen(function(descendants)
|
|
139
|
-
local someDescendant01, someDescendant02 = table.unpack(descendants)
|
|
140
|
-
end)
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
:::note
|
|
144
|
-
Once all descendants are found, a second check is made to ensure that none of the
|
|
145
|
-
instances have moved outside of the parent (since one instance might change before
|
|
146
|
-
another instance is found). A rejected promise with the `WaitFor.Error.ParentChanged`
|
|
147
|
-
error will be thrown if any of the instances are no longer descendants of the given
|
|
148
|
-
`parent`.
|
|
149
|
-
:::
|
|
150
|
-
]=]
|
|
151
|
-
function WaitFor.Descendants(parent: Instance, descendantNames: { string }, timeout: number?)
|
|
152
|
-
local all = table.create(#descendantNames)
|
|
153
|
-
for i, descendantName in ipairs(descendantNames) do
|
|
154
|
-
all[i] = WaitFor.Descendant(parent, descendantName, timeout)
|
|
155
|
-
end
|
|
156
|
-
return Promise.all(all):andThen(function(descendants)
|
|
157
|
-
-- Check that all are still parented
|
|
158
|
-
for _, descendant in ipairs(descendants) do
|
|
159
|
-
if not descendant:IsDescendantOf(parent) then
|
|
160
|
-
return Promise.reject(WaitFor.Error.ParentChanged)
|
|
161
|
-
end
|
|
162
|
-
end
|
|
163
|
-
return descendants
|
|
164
|
-
end)
|
|
165
|
-
end
|
|
166
|
-
|
|
167
|
-
--[=[
|
|
168
|
-
@return Promise<Instance>
|
|
169
|
-
Wait for the PrimaryPart of a model to exist.
|
|
170
|
-
|
|
171
|
-
```lua
|
|
172
|
-
WaitFor.PrimaryPart(model):andThen(function(primaryPart)
|
|
173
|
-
print(primaryPart == model.PrimaryPart)
|
|
174
|
-
end)
|
|
175
|
-
```
|
|
176
|
-
]=]
|
|
177
|
-
function WaitFor.PrimaryPart(model: Model, timeout: number?)
|
|
178
|
-
local primary = model.PrimaryPart
|
|
179
|
-
if primary then
|
|
180
|
-
return Promise.resolve(primary)
|
|
181
|
-
end
|
|
182
|
-
return PromiseWatchAncestry(
|
|
183
|
-
model,
|
|
184
|
-
Promise.fromEvent(model:GetPropertyChangedSignal("PrimaryPart"), function()
|
|
185
|
-
primary = model.PrimaryPart
|
|
186
|
-
return primary ~= nil
|
|
187
|
-
end)
|
|
188
|
-
:andThen(function()
|
|
189
|
-
return primary
|
|
190
|
-
end)
|
|
191
|
-
:timeout(timeout or DEFAULT_TIMEOUT)
|
|
192
|
-
)
|
|
193
|
-
end
|
|
194
|
-
|
|
195
|
-
--[=[
|
|
196
|
-
@return Promise<Instance>
|
|
197
|
-
Wait for the Value of an ObjectValue to exist.
|
|
198
|
-
|
|
199
|
-
```lua
|
|
200
|
-
WaitFor.ObjectValue(someObjectValue):andThen(function(value)
|
|
201
|
-
print("someObjectValue's value is", value)
|
|
202
|
-
end)
|
|
203
|
-
```
|
|
204
|
-
]=]
|
|
205
|
-
function WaitFor.ObjectValue(objectValue: ObjectValue, timeout: number?)
|
|
206
|
-
local value = objectValue.Value
|
|
207
|
-
if value then
|
|
208
|
-
return Promise.resolve(value)
|
|
209
|
-
end
|
|
210
|
-
return PromiseWatchAncestry(
|
|
211
|
-
objectValue,
|
|
212
|
-
Promise.fromEvent(objectValue.Changed, function(v)
|
|
213
|
-
value = v
|
|
214
|
-
return value ~= nil
|
|
215
|
-
end)
|
|
216
|
-
:andThen(function()
|
|
217
|
-
return value
|
|
218
|
-
end)
|
|
219
|
-
:timeout(timeout or DEFAULT_TIMEOUT)
|
|
220
|
-
)
|
|
221
|
-
end
|
|
222
|
-
|
|
223
|
-
--[=[
|
|
224
|
-
@return Promise<T>
|
|
225
|
-
Wait for the given predicate function to return a non-nil value of
|
|
226
|
-
of type `T`. The predicate is fired every RunService Heartbeat step.
|
|
227
|
-
|
|
228
|
-
```lua
|
|
229
|
-
-- Example, waiting for some property to be set:
|
|
230
|
-
WaitFor.Custom(function() return vectorForce.Attachment0 end):andThen(function(a0)
|
|
231
|
-
print(a0)
|
|
232
|
-
end)
|
|
233
|
-
```
|
|
234
|
-
]=]
|
|
235
|
-
function WaitFor.Custom<T>(predicate: () -> T?, timeout: number?)
|
|
236
|
-
local value = predicate()
|
|
237
|
-
if value ~= nil then
|
|
238
|
-
return Promise.resolve(value)
|
|
239
|
-
end
|
|
240
|
-
return Promise.new(function(resolve, _reject, onCancel)
|
|
241
|
-
local heartbeat
|
|
242
|
-
local function OnDone()
|
|
243
|
-
heartbeat:Disconnect()
|
|
244
|
-
end
|
|
245
|
-
local function Update()
|
|
246
|
-
local v = predicate()
|
|
247
|
-
if v ~= nil then
|
|
248
|
-
OnDone()
|
|
249
|
-
resolve(v)
|
|
250
|
-
end
|
|
251
|
-
end
|
|
252
|
-
heartbeat = RunService.Heartbeat:Connect(Update)
|
|
253
|
-
onCancel(OnDone)
|
|
254
|
-
end):timeout(timeout or DEFAULT_TIMEOUT)
|
|
255
|
-
end
|
|
256
|
-
|
|
257
|
-
return WaitFor
|
|
1
|
+
-- WaitFor
|
|
2
|
+
-- Stephen Leitnick
|
|
3
|
+
-- January 17, 2022
|
|
4
|
+
|
|
5
|
+
local RunService = game:GetService("RunService")
|
|
6
|
+
|
|
7
|
+
local Promise = require(script.Parent.Promise)
|
|
8
|
+
|
|
9
|
+
local DEFAULT_TIMEOUT = 60
|
|
10
|
+
|
|
11
|
+
--[=[
|
|
12
|
+
@class WaitFor
|
|
13
|
+
Utility class for awaiting the existence of instances.
|
|
14
|
+
|
|
15
|
+
By default, all promises timeout after 60 seconds, unless the `timeout`
|
|
16
|
+
argument is specified.
|
|
17
|
+
|
|
18
|
+
:::note
|
|
19
|
+
Promises will be rejected if the parent (or any ancestor) is unparented
|
|
20
|
+
from the game.
|
|
21
|
+
:::
|
|
22
|
+
|
|
23
|
+
:::caution Set name before parent
|
|
24
|
+
When waiting for instances based on name (e.g. `WaitFor.Child`), the `WaitFor`
|
|
25
|
+
system is listening to events to capture these instances being added. This
|
|
26
|
+
means that the name must be set _before_ being parented into the object.
|
|
27
|
+
:::
|
|
28
|
+
]=]
|
|
29
|
+
local WaitFor = {}
|
|
30
|
+
|
|
31
|
+
--[=[
|
|
32
|
+
@within WaitFor
|
|
33
|
+
@prop Error {Unparented: string, ParentChanged: string}
|
|
34
|
+
]=]
|
|
35
|
+
WaitFor.Error = {
|
|
36
|
+
Unparented = "Unparented",
|
|
37
|
+
ParentChanged = "ParentChanged",
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
local function PromiseWatchAncestry(instance: Instance, promise)
|
|
41
|
+
return Promise.race({
|
|
42
|
+
promise,
|
|
43
|
+
Promise.fromEvent(instance.AncestryChanged, function(_, newParent)
|
|
44
|
+
return newParent == nil
|
|
45
|
+
end):andThen(function()
|
|
46
|
+
return Promise.reject(WaitFor.Error.Unparented)
|
|
47
|
+
end),
|
|
48
|
+
})
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
--[=[
|
|
52
|
+
@return Promise<Instance>
|
|
53
|
+
Wait for a child to exist within a given parent based on the child name.
|
|
54
|
+
|
|
55
|
+
```lua
|
|
56
|
+
WaitFor.Child(parent, "SomeObject"):andThen(function(someObject)
|
|
57
|
+
print(someObject, "now exists")
|
|
58
|
+
end):catch(warn)
|
|
59
|
+
```
|
|
60
|
+
]=]
|
|
61
|
+
function WaitFor.Child(parent: Instance, childName: string, timeout: number?)
|
|
62
|
+
local child = parent:FindFirstChild(childName)
|
|
63
|
+
if child then
|
|
64
|
+
return Promise.resolve(child)
|
|
65
|
+
end
|
|
66
|
+
return PromiseWatchAncestry(
|
|
67
|
+
parent,
|
|
68
|
+
Promise.fromEvent(parent.ChildAdded, function(c)
|
|
69
|
+
return c.Name == childName
|
|
70
|
+
end):timeout(timeout or DEFAULT_TIMEOUT)
|
|
71
|
+
)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
--[=[
|
|
75
|
+
@return Promise<{Instance}>
|
|
76
|
+
Wait for all children to exist within the given parent.
|
|
77
|
+
|
|
78
|
+
```lua
|
|
79
|
+
WaitFor.Children(parent, {"SomeObject01", "SomeObject02"}):andThen(function(children)
|
|
80
|
+
local someObject01, someObject02 = table.unpack(children)
|
|
81
|
+
end)
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
:::note
|
|
85
|
+
Once all children are found, a second check is made to ensure that all children
|
|
86
|
+
are still directly parented to the given `parent` (since one child's parent
|
|
87
|
+
might have changed before another child was found). A rejected promise with the
|
|
88
|
+
`WaitFor.Error.ParentChanged` error will be thrown if any parents of the children
|
|
89
|
+
no longer match the given `parent`.
|
|
90
|
+
:::
|
|
91
|
+
]=]
|
|
92
|
+
function WaitFor.Children(parent: Instance, childrenNames: { string }, timeout: number?)
|
|
93
|
+
local all = table.create(#childrenNames)
|
|
94
|
+
for i, childName in ipairs(childrenNames) do
|
|
95
|
+
all[i] = WaitFor.Child(parent, childName, timeout)
|
|
96
|
+
end
|
|
97
|
+
return Promise.all(all):andThen(function(children)
|
|
98
|
+
-- Check that all are still parented
|
|
99
|
+
for _, child in ipairs(children) do
|
|
100
|
+
if child.Parent ~= parent then
|
|
101
|
+
return Promise.reject(WaitFor.Error.ParentChanged)
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
return children
|
|
105
|
+
end)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
--[=[
|
|
109
|
+
@return Promise<Instance>
|
|
110
|
+
Wait for a descendant to exist within a given parent. This is similar to
|
|
111
|
+
`WaitFor.Child`, except it looks for all descendants instead of immediate
|
|
112
|
+
children.
|
|
113
|
+
|
|
114
|
+
```lua
|
|
115
|
+
WaitFor.Descendant(parent, "SomeDescendant"):andThen(function(someDescendant)
|
|
116
|
+
print("SomeDescendant now exists")
|
|
117
|
+
end)
|
|
118
|
+
```
|
|
119
|
+
]=]
|
|
120
|
+
function WaitFor.Descendant(parent: Instance, descendantName: string, timeout: number?)
|
|
121
|
+
local descendant = parent:FindFirstChild(descendantName, true)
|
|
122
|
+
if descendant then
|
|
123
|
+
return Promise.resolve(descendant)
|
|
124
|
+
end
|
|
125
|
+
return PromiseWatchAncestry(
|
|
126
|
+
parent,
|
|
127
|
+
Promise.fromEvent(parent.DescendantAdded, function(d)
|
|
128
|
+
return d.Name == descendantName
|
|
129
|
+
end):timeout(timeout or DEFAULT_TIMEOUT)
|
|
130
|
+
)
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
--[=[
|
|
134
|
+
@return Promise<{Instance}>
|
|
135
|
+
Wait for all descendants to exist within a given parent.
|
|
136
|
+
|
|
137
|
+
```lua
|
|
138
|
+
WaitFor.Descendants(parent, {"SomeDescendant01", "SomeDescendant02"}):andThen(function(descendants)
|
|
139
|
+
local someDescendant01, someDescendant02 = table.unpack(descendants)
|
|
140
|
+
end)
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
:::note
|
|
144
|
+
Once all descendants are found, a second check is made to ensure that none of the
|
|
145
|
+
instances have moved outside of the parent (since one instance might change before
|
|
146
|
+
another instance is found). A rejected promise with the `WaitFor.Error.ParentChanged`
|
|
147
|
+
error will be thrown if any of the instances are no longer descendants of the given
|
|
148
|
+
`parent`.
|
|
149
|
+
:::
|
|
150
|
+
]=]
|
|
151
|
+
function WaitFor.Descendants(parent: Instance, descendantNames: { string }, timeout: number?)
|
|
152
|
+
local all = table.create(#descendantNames)
|
|
153
|
+
for i, descendantName in ipairs(descendantNames) do
|
|
154
|
+
all[i] = WaitFor.Descendant(parent, descendantName, timeout)
|
|
155
|
+
end
|
|
156
|
+
return Promise.all(all):andThen(function(descendants)
|
|
157
|
+
-- Check that all are still parented
|
|
158
|
+
for _, descendant in ipairs(descendants) do
|
|
159
|
+
if not descendant:IsDescendantOf(parent) then
|
|
160
|
+
return Promise.reject(WaitFor.Error.ParentChanged)
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
return descendants
|
|
164
|
+
end)
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
--[=[
|
|
168
|
+
@return Promise<Instance>
|
|
169
|
+
Wait for the PrimaryPart of a model to exist.
|
|
170
|
+
|
|
171
|
+
```lua
|
|
172
|
+
WaitFor.PrimaryPart(model):andThen(function(primaryPart)
|
|
173
|
+
print(primaryPart == model.PrimaryPart)
|
|
174
|
+
end)
|
|
175
|
+
```
|
|
176
|
+
]=]
|
|
177
|
+
function WaitFor.PrimaryPart(model: Model, timeout: number?)
|
|
178
|
+
local primary = model.PrimaryPart
|
|
179
|
+
if primary then
|
|
180
|
+
return Promise.resolve(primary)
|
|
181
|
+
end
|
|
182
|
+
return PromiseWatchAncestry(
|
|
183
|
+
model,
|
|
184
|
+
Promise.fromEvent(model:GetPropertyChangedSignal("PrimaryPart"), function()
|
|
185
|
+
primary = model.PrimaryPart
|
|
186
|
+
return primary ~= nil
|
|
187
|
+
end)
|
|
188
|
+
:andThen(function()
|
|
189
|
+
return primary
|
|
190
|
+
end)
|
|
191
|
+
:timeout(timeout or DEFAULT_TIMEOUT)
|
|
192
|
+
)
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
--[=[
|
|
196
|
+
@return Promise<Instance>
|
|
197
|
+
Wait for the Value of an ObjectValue to exist.
|
|
198
|
+
|
|
199
|
+
```lua
|
|
200
|
+
WaitFor.ObjectValue(someObjectValue):andThen(function(value)
|
|
201
|
+
print("someObjectValue's value is", value)
|
|
202
|
+
end)
|
|
203
|
+
```
|
|
204
|
+
]=]
|
|
205
|
+
function WaitFor.ObjectValue(objectValue: ObjectValue, timeout: number?)
|
|
206
|
+
local value = objectValue.Value
|
|
207
|
+
if value then
|
|
208
|
+
return Promise.resolve(value)
|
|
209
|
+
end
|
|
210
|
+
return PromiseWatchAncestry(
|
|
211
|
+
objectValue,
|
|
212
|
+
Promise.fromEvent(objectValue.Changed, function(v)
|
|
213
|
+
value = v
|
|
214
|
+
return value ~= nil
|
|
215
|
+
end)
|
|
216
|
+
:andThen(function()
|
|
217
|
+
return value
|
|
218
|
+
end)
|
|
219
|
+
:timeout(timeout or DEFAULT_TIMEOUT)
|
|
220
|
+
)
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
--[=[
|
|
224
|
+
@return Promise<T>
|
|
225
|
+
Wait for the given predicate function to return a non-nil value of
|
|
226
|
+
of type `T`. The predicate is fired every RunService Heartbeat step.
|
|
227
|
+
|
|
228
|
+
```lua
|
|
229
|
+
-- Example, waiting for some property to be set:
|
|
230
|
+
WaitFor.Custom(function() return vectorForce.Attachment0 end):andThen(function(a0)
|
|
231
|
+
print(a0)
|
|
232
|
+
end)
|
|
233
|
+
```
|
|
234
|
+
]=]
|
|
235
|
+
function WaitFor.Custom<T>(predicate: () -> T?, timeout: number?)
|
|
236
|
+
local value = predicate()
|
|
237
|
+
if value ~= nil then
|
|
238
|
+
return Promise.resolve(value)
|
|
239
|
+
end
|
|
240
|
+
return Promise.new(function(resolve, _reject, onCancel)
|
|
241
|
+
local heartbeat
|
|
242
|
+
local function OnDone()
|
|
243
|
+
heartbeat:Disconnect()
|
|
244
|
+
end
|
|
245
|
+
local function Update()
|
|
246
|
+
local v = predicate()
|
|
247
|
+
if v ~= nil then
|
|
248
|
+
OnDone()
|
|
249
|
+
resolve(v)
|
|
250
|
+
end
|
|
251
|
+
end
|
|
252
|
+
heartbeat = RunService.Heartbeat:Connect(Update)
|
|
253
|
+
onCancel(OnDone)
|
|
254
|
+
end):timeout(timeout or DEFAULT_TIMEOUT)
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
return WaitFor
|