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,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Adds helpful functions that wrap
|
|
3
|
+
* [`Instance:QueryDescendants()`](https://create.roblox.com/docs/reference/engine/classes/Instance#QueryDescendants).
|
|
4
|
+
*/
|
|
5
|
+
interface Query {
|
|
6
|
+
/**
|
|
7
|
+
* Equivalent to [`parent.QueryDescendants(selector)`](https://create.roblox.com/docs/reference/engine/classes/Instance#QueryDescendants).
|
|
8
|
+
*/
|
|
9
|
+
all: (parent: Instance, selector: string) => Instance[];
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Returns the query result, filtered by the `filter` function. Ideally, most of
|
|
13
|
+
* the filtering should be done with the selector itself. However, if the selector
|
|
14
|
+
* is not enough, this function can be used to further filter the results.
|
|
15
|
+
*/
|
|
16
|
+
filter: (parent: Instance, selector: string, filter: (instance: Instance) => boolean) => Instance[];
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Returns the query result mapped by the `map` function.
|
|
20
|
+
*/
|
|
21
|
+
map: <T>(parent: Instance, selector: string, map: (instance: Instance) => T) => Instance[];
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Returns the first item from the query. Might be `nil` if the query returns
|
|
25
|
+
* nothing.
|
|
26
|
+
*
|
|
27
|
+
* This is equivalent to `parent.QueryDescendants(selector)[1]`.
|
|
28
|
+
*/
|
|
29
|
+
first: (parent: Instance, selector: string) => Instance | undefined;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Asserts that the query returns exactly one instance. The instance is returned.
|
|
33
|
+
* This is useful when attempting to find an exact match of an instance that
|
|
34
|
+
* must exist.
|
|
35
|
+
*
|
|
36
|
+
* If the result returns zero or more than one result, an error is thrown.
|
|
37
|
+
*/
|
|
38
|
+
one: (parent: Instance, selector: string) => Instance;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
declare const Query: Query;
|
|
42
|
+
|
|
43
|
+
export = Query;
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
--!strict
|
|
2
|
+
|
|
3
|
+
--[=[
|
|
4
|
+
@class Query
|
|
5
|
+
|
|
6
|
+
Adds helpful functions that wrap
|
|
7
|
+
[`Instance:QueryDescendants()`](https://create.roblox.com/docs/reference/engine/classes/Instance#QueryDescendants).
|
|
8
|
+
]=]
|
|
9
|
+
|
|
10
|
+
local Query = {}
|
|
11
|
+
|
|
12
|
+
--[=[
|
|
13
|
+
@within Query
|
|
14
|
+
|
|
15
|
+
Equivalent to [`parent:QueryDescendants(selector)`](https://create.roblox.com/docs/reference/engine/classes/Instance#QueryDescendants).
|
|
16
|
+
]=]
|
|
17
|
+
function Query.all(parent: Instance, selector: string): { Instance }
|
|
18
|
+
return parent:QueryDescendants(selector)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
--[=[
|
|
22
|
+
@within Query
|
|
23
|
+
|
|
24
|
+
Returns the query result, filtered by the `filter` function. Ideally, most of
|
|
25
|
+
the filtering should be done with the selector itself. However, if the selector
|
|
26
|
+
is not enough, this function can be used to further filter the results.
|
|
27
|
+
|
|
28
|
+
```lua
|
|
29
|
+
local buttons = Query.filter(workspace, ".Button", function(instance)
|
|
30
|
+
return instance.Transparency > 0.25
|
|
31
|
+
end)
|
|
32
|
+
```
|
|
33
|
+
]=]
|
|
34
|
+
function Query.filter(parent: Instance, selector: string, filter: (Instance) -> boolean): { Instance }
|
|
35
|
+
local instances = parent:QueryDescendants(selector)
|
|
36
|
+
for i = #instances, 1, -1 do
|
|
37
|
+
if not filter(instances[i]) then
|
|
38
|
+
table.remove(instances, i)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
return instances
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
--[=[
|
|
45
|
+
@within Query
|
|
46
|
+
|
|
47
|
+
Returns the query result mapped by the `map` function.
|
|
48
|
+
|
|
49
|
+
```lua
|
|
50
|
+
local Button = {}
|
|
51
|
+
|
|
52
|
+
function Button.new(btn: BasePart)
|
|
53
|
+
...
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
----
|
|
57
|
+
|
|
58
|
+
local buttons = Query.map(workspace, ".Button", function(instance)
|
|
59
|
+
return Button.new(instance)
|
|
60
|
+
end)
|
|
61
|
+
```
|
|
62
|
+
]=]
|
|
63
|
+
function Query.map<T>(parent: Instance, selector: string, map: (Instance) -> T): { T }
|
|
64
|
+
local instances = parent:QueryDescendants(selector)
|
|
65
|
+
local mapped = table.create(#instances)
|
|
66
|
+
for i, instance in instances do
|
|
67
|
+
mapped[i] = map(instance)
|
|
68
|
+
end
|
|
69
|
+
return mapped
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
--[=[
|
|
73
|
+
@within Query
|
|
74
|
+
|
|
75
|
+
Returns the first item from the query. Might be `nil` if the query returns
|
|
76
|
+
nothing.
|
|
77
|
+
|
|
78
|
+
This is equivalent to `parent:QueryDescendants(selector)[1]`.
|
|
79
|
+
|
|
80
|
+
```lua
|
|
81
|
+
-- Find an instance tagged with 'Tycoon' that has
|
|
82
|
+
-- the OwnerId attribute matching the player's UserId:
|
|
83
|
+
local tycoon = Query.first(workspace, `.Tycoon[$OwnerId = {player.UserId}]`)
|
|
84
|
+
|
|
85
|
+
if tycoon then
|
|
86
|
+
...
|
|
87
|
+
end
|
|
88
|
+
```
|
|
89
|
+
]=]
|
|
90
|
+
function Query.first(parent: Instance, selector: string): Instance?
|
|
91
|
+
return parent:QueryDescendants(selector)[1]
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
--[=[
|
|
95
|
+
@within Query
|
|
96
|
+
|
|
97
|
+
Asserts that the query returns exactly one instance. The instance is returned.
|
|
98
|
+
This is useful when attempting to find an exact match of an instance that
|
|
99
|
+
must exist.
|
|
100
|
+
|
|
101
|
+
If the result returns zero or more than one result, an error is thrown.
|
|
102
|
+
|
|
103
|
+
```lua
|
|
104
|
+
-- Find a SpawnLocation that has the MainSpawn attribute set to true:
|
|
105
|
+
local spawnPoint = Query.one(workspace, "SpawnLocation[$MainSpawn = true]")
|
|
106
|
+
```
|
|
107
|
+
]=]
|
|
108
|
+
function Query.one(parent: Instance, selector: string): Instance
|
|
109
|
+
local instances = parent:QueryDescendants(selector)
|
|
110
|
+
if #instances ~= 1 then
|
|
111
|
+
error(`expected 1 instance from query; got {#instances} instances (selector: {selector})`, 2)
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
return instances[1]
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
return Query
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@rbxutil/query",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"main": "init.luau",
|
|
5
|
+
"repository": {
|
|
6
|
+
"url": "git+https://github.com/Sleitnick/RbxUtil.git"
|
|
7
|
+
},
|
|
8
|
+
"license": "MIT",
|
|
9
|
+
"types": "index.d.ts",
|
|
10
|
+
"files": [
|
|
11
|
+
"./*",
|
|
12
|
+
"!*.toml",
|
|
13
|
+
"!*.json"
|
|
14
|
+
],
|
|
15
|
+
"publishConfig": {
|
|
16
|
+
"access": "public"
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
[package]
|
|
2
|
+
name = "sleitnick/query"
|
|
3
|
+
description = "Query instances"
|
|
4
|
+
version = "0.2.0"
|
|
5
|
+
license = "MIT"
|
|
6
|
+
authors = ["Stephen Leitnick"]
|
|
7
|
+
registry = "https://github.com/UpliftGames/wally-index"
|
|
8
|
+
realm = "shared"
|
|
9
|
+
exclude = ["node_modules", "package.json", "**/*.ts"]
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
declare namespace Sequent {
|
|
2
|
+
interface Constructor {
|
|
3
|
+
new <T>(cancellable?: boolean): Sequent<T>;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
interface SequentEvent<T> {
|
|
7
|
+
readonly Value: T;
|
|
8
|
+
readonly Cancellable: boolean;
|
|
9
|
+
Cancel(): void;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
interface SequentConnection {
|
|
13
|
+
readonly Connected: boolean;
|
|
14
|
+
Disconnect(): void;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
interface Sequent<T> {
|
|
19
|
+
Fire(value: T): void;
|
|
20
|
+
Connect(callback: (event: Sequent.SequentEvent<T>) => void): Sequent.SequentConnection;
|
|
21
|
+
Once(callback: (event: Sequent.SequentEvent<T>) => void): Sequent.SequentConnection;
|
|
22
|
+
Cancel(): void;
|
|
23
|
+
Destroy(): void;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
declare const Sequent: Sequent.Constructor;
|
|
27
|
+
|
|
28
|
+
export = Sequent;
|
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
export type Sequent<T> = {
|
|
2
|
+
Fire: (self: Sequent<T>, T) -> (),
|
|
3
|
+
Connect: (self: Sequent<T>, callback: (SequentEvent<T>) -> ()) -> SequentConnection,
|
|
4
|
+
Once: (self: Sequent<T>, callback: (SequentEvent<T>) -> ()) -> SequentConnection,
|
|
5
|
+
Cancel: (self: Sequent<T>) -> (),
|
|
6
|
+
Destroy: (self: Sequent<T>) -> (),
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
--[=[
|
|
10
|
+
@interface SequentConnection
|
|
11
|
+
@within Sequent
|
|
12
|
+
.Connected boolean
|
|
13
|
+
.Disconnect (self: SequentConnection) -> ()
|
|
14
|
+
|
|
15
|
+
```lua
|
|
16
|
+
print(sequent.Connected)
|
|
17
|
+
sequent:Disconnect()
|
|
18
|
+
```
|
|
19
|
+
]=]
|
|
20
|
+
export type SequentConnection = {
|
|
21
|
+
Connected: boolean,
|
|
22
|
+
Disconnect: (self: SequentConnection) -> (),
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
--[=[
|
|
26
|
+
@interface SequentEvent<T>
|
|
27
|
+
@within Sequent
|
|
28
|
+
.Value T
|
|
29
|
+
.Cancellable boolean
|
|
30
|
+
.Cancel (self: SequentEvent<T>) -> ()
|
|
31
|
+
|
|
32
|
+
Events are passed to connected callbacks when sequents are fired. Events
|
|
33
|
+
can be cancelled as well, which prevents the event from propagating to
|
|
34
|
+
other connected callbacks during the same firing. This can be used to
|
|
35
|
+
sink events if desired.
|
|
36
|
+
|
|
37
|
+
```lua
|
|
38
|
+
sequent:Connect(function(event)
|
|
39
|
+
print(event.Value)
|
|
40
|
+
event:Cancel()
|
|
41
|
+
end, 0)
|
|
42
|
+
```
|
|
43
|
+
]=]
|
|
44
|
+
export type SequentEvent<T> = {
|
|
45
|
+
Value: T,
|
|
46
|
+
Cancellable: boolean,
|
|
47
|
+
Cancel: (self: SequentEvent<T>) -> (),
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
type InternalSequentConnection = SequentConnection & {
|
|
51
|
+
_priority: number,
|
|
52
|
+
_sequent: Sequent<unknown>,
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
-----------------------------------------------------------------------------
|
|
56
|
+
-- Connection
|
|
57
|
+
local SequentConnection = {}
|
|
58
|
+
SequentConnection.__index = SequentConnection
|
|
59
|
+
|
|
60
|
+
function SequentConnection:Disconnect()
|
|
61
|
+
self._sequent:_disconnect(self)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
-----------------------------------------------------------------------------
|
|
65
|
+
-- Sequent
|
|
66
|
+
|
|
67
|
+
--[=[
|
|
68
|
+
@interface Priority
|
|
69
|
+
@within Sequent
|
|
70
|
+
.Highest math.huge
|
|
71
|
+
.High 1000
|
|
72
|
+
.Normal 0
|
|
73
|
+
.Low -1000
|
|
74
|
+
.Lowest -math.huge
|
|
75
|
+
|
|
76
|
+
```lua
|
|
77
|
+
sequent:Connect(fn, Sequent.Priority.Highest)
|
|
78
|
+
```
|
|
79
|
+
]=]
|
|
80
|
+
local Priority = {
|
|
81
|
+
Highest = math.huge,
|
|
82
|
+
High = 1000,
|
|
83
|
+
Normal = 0,
|
|
84
|
+
Low = -1000,
|
|
85
|
+
Lowest = -math.huge,
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
--[=[
|
|
89
|
+
@class Sequent
|
|
90
|
+
|
|
91
|
+
Sequent is a signal-like structure that executes connections in a serial nature. Each
|
|
92
|
+
connection must fully complete before the next is run. Connections can be prioritized
|
|
93
|
+
and cancelled.
|
|
94
|
+
|
|
95
|
+
```lua
|
|
96
|
+
local sequent = Sequent.new()
|
|
97
|
+
|
|
98
|
+
sequent:Connect(
|
|
99
|
+
function(event)
|
|
100
|
+
print("Got value", event.Value)
|
|
101
|
+
event:Cancel()
|
|
102
|
+
end,
|
|
103
|
+
Sequent.Priority.Highest,
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
sequent:Connect(
|
|
107
|
+
function(event)
|
|
108
|
+
print("This won't print!")
|
|
109
|
+
end,
|
|
110
|
+
Sequent.Priority.Lowest,
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
sequent:Fire("Test")
|
|
114
|
+
```
|
|
115
|
+
]=]
|
|
116
|
+
local Sequent = {}
|
|
117
|
+
Sequent.__index = Sequent
|
|
118
|
+
|
|
119
|
+
--[=[
|
|
120
|
+
Constructs a new Sequent. If `cancellable` is `true`, then
|
|
121
|
+
connected handlers can cancel event propagation.
|
|
122
|
+
]=]
|
|
123
|
+
function Sequent.new<T>(cancellable: boolean?): Sequent<T>
|
|
124
|
+
local self = setmetatable({
|
|
125
|
+
_connections = {},
|
|
126
|
+
_firing = false,
|
|
127
|
+
_queuedDisconnect = false,
|
|
128
|
+
|
|
129
|
+
_firingThread = nil,
|
|
130
|
+
_taskThread = nil,
|
|
131
|
+
|
|
132
|
+
_cancellable = not not cancellable,
|
|
133
|
+
}, Sequent)
|
|
134
|
+
|
|
135
|
+
return self
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
--[=[
|
|
139
|
+
@yields
|
|
140
|
+
Fires the Sequent with the given value.
|
|
141
|
+
|
|
142
|
+
This method will yield until all connections complete. Errors will
|
|
143
|
+
bubble up if they occur within a connection.
|
|
144
|
+
]=]
|
|
145
|
+
function Sequent:Fire<T>(value: T)
|
|
146
|
+
assert(not self._firing, "cannot fire while already firing")
|
|
147
|
+
self._firing = true
|
|
148
|
+
|
|
149
|
+
local cancelled = false
|
|
150
|
+
local event: SequentEvent<T> = table.freeze({
|
|
151
|
+
Value = value,
|
|
152
|
+
Cancellable = self._cancellable,
|
|
153
|
+
Cancel = function(_evt)
|
|
154
|
+
if not self._cancellable then
|
|
155
|
+
warn("attempted to cancel non-cancellable event")
|
|
156
|
+
return
|
|
157
|
+
end
|
|
158
|
+
cancelled = true
|
|
159
|
+
end,
|
|
160
|
+
})
|
|
161
|
+
|
|
162
|
+
local thread = coroutine.running()
|
|
163
|
+
self._firingThread = thread
|
|
164
|
+
for _, connection in self._connections do
|
|
165
|
+
if not connection.Connected then
|
|
166
|
+
continue
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
-- Run the task:
|
|
170
|
+
local success, err = nil, nil
|
|
171
|
+
local taskThread = task.spawn(function()
|
|
172
|
+
self._taskThread = coroutine.running()
|
|
173
|
+
|
|
174
|
+
local s, e = pcall(function()
|
|
175
|
+
connection._callback(event)
|
|
176
|
+
end)
|
|
177
|
+
|
|
178
|
+
self._taskThread = nil
|
|
179
|
+
|
|
180
|
+
-- Resume the parent thread if it yielded:
|
|
181
|
+
if coroutine.status(thread) == "suspended" then
|
|
182
|
+
task.spawn(thread, s, e)
|
|
183
|
+
else
|
|
184
|
+
success, err = s, e
|
|
185
|
+
end
|
|
186
|
+
end)
|
|
187
|
+
|
|
188
|
+
-- If the task thread yielded, yield this thread too:
|
|
189
|
+
if success == nil then
|
|
190
|
+
success, err = coroutine.yield()
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
self._firingThread = nil
|
|
194
|
+
|
|
195
|
+
-- Throw error if the task failed:
|
|
196
|
+
if not success then
|
|
197
|
+
error(debug.traceback(taskThread, tostring(err)))
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
if cancelled then
|
|
201
|
+
break
|
|
202
|
+
end
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
-- If connections were disconnected while firing connections, disconnect them now:
|
|
206
|
+
if self._queuedDisconnect then
|
|
207
|
+
self._queuedDisconnect = false
|
|
208
|
+
for i = #self._connections, 1, -1 do
|
|
209
|
+
local connection = self._connections[i]
|
|
210
|
+
if not connection.Connected then
|
|
211
|
+
self:_removeConnection(connection)
|
|
212
|
+
end
|
|
213
|
+
end
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
self._firing = false
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
--[=[
|
|
220
|
+
Returns `true` if the Sequent is currently firing.
|
|
221
|
+
]=]
|
|
222
|
+
function Sequent:IsFiring(): boolean
|
|
223
|
+
return self._firing
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
--[=[
|
|
227
|
+
Connects a callback to the Sequent, which gets called anytime `Fire`
|
|
228
|
+
is called.
|
|
229
|
+
|
|
230
|
+
The given `priority` indicates the firing priority of the callback. Higher
|
|
231
|
+
priority values will be run first. There are a few defaults available via
|
|
232
|
+
`Sequent.Priority`.
|
|
233
|
+
]=]
|
|
234
|
+
function Sequent:Connect(callback: (...unknown) -> (), priority: number): SequentConnection
|
|
235
|
+
assert(not self._firing, "cannot connect while firing")
|
|
236
|
+
|
|
237
|
+
local connection = setmetatable({
|
|
238
|
+
Connected = true,
|
|
239
|
+
_callback = callback,
|
|
240
|
+
_priority = priority,
|
|
241
|
+
_sequent = self,
|
|
242
|
+
}, SequentConnection)
|
|
243
|
+
|
|
244
|
+
-- Find the correct index to remain sorted by priority:
|
|
245
|
+
local idx = #self._connections + 1
|
|
246
|
+
for i, c: InternalSequentConnection in self._connections do
|
|
247
|
+
if c._priority < priority then
|
|
248
|
+
idx = i
|
|
249
|
+
break
|
|
250
|
+
end
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
table.insert(self._connections, idx, connection)
|
|
254
|
+
|
|
255
|
+
return connection
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
--[=[
|
|
259
|
+
`Once()` is the same as `Connect()`, except the connection is automatically
|
|
260
|
+
disconnected after being fired once.
|
|
261
|
+
]=]
|
|
262
|
+
function Sequent:Once(callback: (...unknown) -> (), priority: number): SequentConnection
|
|
263
|
+
local connection: SequentConnection
|
|
264
|
+
|
|
265
|
+
connection = self:Connect(function(...)
|
|
266
|
+
if not connection.Connected then
|
|
267
|
+
return
|
|
268
|
+
end
|
|
269
|
+
connection:Disconnect()
|
|
270
|
+
callback(...)
|
|
271
|
+
end, priority)
|
|
272
|
+
|
|
273
|
+
return connection
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
--[=[
|
|
277
|
+
Cancels a currently-firing Sequent.
|
|
278
|
+
]=]
|
|
279
|
+
function Sequent:Cancel()
|
|
280
|
+
if not self._firing then
|
|
281
|
+
return
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
if self._taskThread == coroutine.running() then
|
|
285
|
+
error("cannot cancel sequent from connected task", 2)
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
if self._taskThread then
|
|
289
|
+
-- pcall needed as the task thread may have yielded from a call to
|
|
290
|
+
-- a roblox service, which will throw an error when calling task.cancel:
|
|
291
|
+
pcall(function()
|
|
292
|
+
task.cancel(self._taskThread)
|
|
293
|
+
end)
|
|
294
|
+
self._taskThread = nil
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
if self._firingThread then
|
|
298
|
+
local thread = self._firingThread
|
|
299
|
+
self._firingThread = nil
|
|
300
|
+
task.spawn(thread, true)
|
|
301
|
+
end
|
|
302
|
+
end
|
|
303
|
+
|
|
304
|
+
--[=[
|
|
305
|
+
Cleans up the Sequent. All connections are disconnected. The Sequent is cancelled
|
|
306
|
+
if it is currently firing.
|
|
307
|
+
]=]
|
|
308
|
+
function Sequent:Destroy()
|
|
309
|
+
self:Cancel()
|
|
310
|
+
|
|
311
|
+
for _, connection in self._connections do
|
|
312
|
+
connection.Connected = false
|
|
313
|
+
end
|
|
314
|
+
end
|
|
315
|
+
|
|
316
|
+
function Sequent:_disconnect(connection)
|
|
317
|
+
if not connection.Connected then
|
|
318
|
+
return
|
|
319
|
+
end
|
|
320
|
+
connection.Connected = false
|
|
321
|
+
|
|
322
|
+
if self._firing then
|
|
323
|
+
self._queuedDisconnect = true
|
|
324
|
+
return
|
|
325
|
+
end
|
|
326
|
+
|
|
327
|
+
self:_removeConnection(connection)
|
|
328
|
+
end
|
|
329
|
+
|
|
330
|
+
function Sequent:_removeConnection(connection)
|
|
331
|
+
local idx = table.find(self._connections, connection)
|
|
332
|
+
if idx then
|
|
333
|
+
table.remove(self._connections, idx)
|
|
334
|
+
end
|
|
335
|
+
end
|
|
336
|
+
|
|
337
|
+
return table.freeze({
|
|
338
|
+
new = Sequent.new,
|
|
339
|
+
Priority = Priority,
|
|
340
|
+
})
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@rbxutil/sequent",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"main": "init.luau",
|
|
5
|
+
"repository": "github:Sleitnick/RbxUtil",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"types": "index.d.ts",
|
|
8
|
+
"files": [
|
|
9
|
+
"./",
|
|
10
|
+
"!*.toml",
|
|
11
|
+
"!*.json"
|
|
12
|
+
],
|
|
13
|
+
"publishConfig": {
|
|
14
|
+
"access": "public"
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
[package]
|
|
2
|
+
name = "sleitnick/sequent"
|
|
3
|
+
description = "Sequent class"
|
|
4
|
+
version = "0.1.0"
|
|
5
|
+
license = "MIT"
|
|
6
|
+
authors = ["Stephen Leitnick"]
|
|
7
|
+
registry = "https://github.com/UpliftGames/wally-index"
|
|
8
|
+
realm = "shared"
|
|
9
|
+
exclude = ["node_modules", "package.json", "**/*.ts"]
|