roblox-opencode 1.0.0 → 1.0.2
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 +877 -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 +1618 -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,114 +1,114 @@
|
|
|
1
|
-
--!strict
|
|
2
|
-
--!nolint LocalUnused
|
|
3
|
-
--!nolint LocalShadow
|
|
4
|
-
local task = nil -- Disable usage of Roblox's task scheduler
|
|
5
|
-
|
|
6
|
-
--[[
|
|
7
|
-
A graph object that runs user code when it's updated by the reactive graph.
|
|
8
|
-
|
|
9
|
-
http://elttob.uk/Fusion/0.3/api-reference/state/types/observer/
|
|
10
|
-
]]
|
|
11
|
-
|
|
12
|
-
local Package = script.Parent.Parent
|
|
13
|
-
local Types = require(Package.Types)
|
|
14
|
-
local External = require(Package.External)
|
|
15
|
-
-- Memory
|
|
16
|
-
local checkLifetime = require(Package.Memory.checkLifetime)
|
|
17
|
-
-- Graph
|
|
18
|
-
local castToGraph = require(Package.Graph.castToGraph)
|
|
19
|
-
local depend = require(Package.Graph.depend)
|
|
20
|
-
local evaluate = require(Package.Graph.evaluate)
|
|
21
|
-
-- Utility
|
|
22
|
-
local nicknames = require(Package.Utility.nicknames)
|
|
23
|
-
|
|
24
|
-
type Self = Types.Observer & {
|
|
25
|
-
_watchingGraph: Types.GraphObject?,
|
|
26
|
-
_changeListeners: {[unknown]: () -> ()}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
local class = {}
|
|
30
|
-
class.type = "Observer"
|
|
31
|
-
class.timeliness = "eager"
|
|
32
|
-
class.dependentSet = table.freeze {}
|
|
33
|
-
|
|
34
|
-
local METATABLE = table.freeze {__index = class}
|
|
35
|
-
|
|
36
|
-
local function Observer(
|
|
37
|
-
scope: Types.Scope<unknown>,
|
|
38
|
-
watching: unknown
|
|
39
|
-
): Types.Observer
|
|
40
|
-
local createdAt = os.clock()
|
|
41
|
-
if watching == nil then
|
|
42
|
-
External.logError("scopeMissing", nil, "Observers", "myScope:Observer(watching)")
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
local self: Self = setmetatable(
|
|
46
|
-
{
|
|
47
|
-
scope = scope,
|
|
48
|
-
createdAt = createdAt,
|
|
49
|
-
dependencySet = {},
|
|
50
|
-
lastChange = nil,
|
|
51
|
-
validity = "invalid",
|
|
52
|
-
_watchingGraph = castToGraph(watching),
|
|
53
|
-
_changeListeners = {}
|
|
54
|
-
},
|
|
55
|
-
METATABLE
|
|
56
|
-
) :: any
|
|
57
|
-
local destroy = function()
|
|
58
|
-
self.scope = nil
|
|
59
|
-
for dependency in pairs(self.dependencySet) do
|
|
60
|
-
dependency.dependentSet[self] = nil
|
|
61
|
-
end
|
|
62
|
-
end
|
|
63
|
-
self.oldestTask = destroy
|
|
64
|
-
nicknames[self.oldestTask] = "Observer"
|
|
65
|
-
table.insert(scope, destroy)
|
|
66
|
-
|
|
67
|
-
if self._watchingGraph ~= nil then
|
|
68
|
-
checkLifetime.bOutlivesA(
|
|
69
|
-
scope, self.oldestTask,
|
|
70
|
-
self._watchingGraph.scope, self._watchingGraph.oldestTask,
|
|
71
|
-
checkLifetime.formatters.observer
|
|
72
|
-
)
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
-- Eagerly evaluated objects need to evaluate themselves so that they're
|
|
76
|
-
-- valid at all times.
|
|
77
|
-
evaluate(self, true)
|
|
78
|
-
|
|
79
|
-
return self
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
function class.onBind(
|
|
83
|
-
self: Self,
|
|
84
|
-
callback: () -> ()
|
|
85
|
-
): () -> ()
|
|
86
|
-
External.doTaskImmediate(callback)
|
|
87
|
-
return self:onChange(callback)
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
function class.onChange(
|
|
91
|
-
self: Self,
|
|
92
|
-
callback: () -> ()
|
|
93
|
-
): () -> ()
|
|
94
|
-
local uniqueIdentifier = table.freeze {}
|
|
95
|
-
self._changeListeners[uniqueIdentifier] = callback
|
|
96
|
-
return function()
|
|
97
|
-
self._changeListeners[uniqueIdentifier] = nil
|
|
98
|
-
end
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
function class._evaluate(
|
|
102
|
-
self: Self
|
|
103
|
-
): ()
|
|
104
|
-
if self._watchingGraph ~= nil then
|
|
105
|
-
depend(self, self._watchingGraph)
|
|
106
|
-
end
|
|
107
|
-
for _, callback in self._changeListeners do
|
|
108
|
-
External.doTaskImmediate(callback)
|
|
109
|
-
end
|
|
110
|
-
return true
|
|
111
|
-
end
|
|
112
|
-
|
|
113
|
-
table.freeze(class)
|
|
1
|
+
--!strict
|
|
2
|
+
--!nolint LocalUnused
|
|
3
|
+
--!nolint LocalShadow
|
|
4
|
+
local task = nil -- Disable usage of Roblox's task scheduler
|
|
5
|
+
|
|
6
|
+
--[[
|
|
7
|
+
A graph object that runs user code when it's updated by the reactive graph.
|
|
8
|
+
|
|
9
|
+
http://elttob.uk/Fusion/0.3/api-reference/state/types/observer/
|
|
10
|
+
]]
|
|
11
|
+
|
|
12
|
+
local Package = script.Parent.Parent
|
|
13
|
+
local Types = require(Package.Types)
|
|
14
|
+
local External = require(Package.External)
|
|
15
|
+
-- Memory
|
|
16
|
+
local checkLifetime = require(Package.Memory.checkLifetime)
|
|
17
|
+
-- Graph
|
|
18
|
+
local castToGraph = require(Package.Graph.castToGraph)
|
|
19
|
+
local depend = require(Package.Graph.depend)
|
|
20
|
+
local evaluate = require(Package.Graph.evaluate)
|
|
21
|
+
-- Utility
|
|
22
|
+
local nicknames = require(Package.Utility.nicknames)
|
|
23
|
+
|
|
24
|
+
type Self = Types.Observer & {
|
|
25
|
+
_watchingGraph: Types.GraphObject?,
|
|
26
|
+
_changeListeners: {[unknown]: () -> ()}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
local class = {}
|
|
30
|
+
class.type = "Observer"
|
|
31
|
+
class.timeliness = "eager"
|
|
32
|
+
class.dependentSet = table.freeze {}
|
|
33
|
+
|
|
34
|
+
local METATABLE = table.freeze {__index = class}
|
|
35
|
+
|
|
36
|
+
local function Observer(
|
|
37
|
+
scope: Types.Scope<unknown>,
|
|
38
|
+
watching: unknown
|
|
39
|
+
): Types.Observer
|
|
40
|
+
local createdAt = os.clock()
|
|
41
|
+
if watching == nil then
|
|
42
|
+
External.logError("scopeMissing", nil, "Observers", "myScope:Observer(watching)")
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
local self: Self = setmetatable(
|
|
46
|
+
{
|
|
47
|
+
scope = scope,
|
|
48
|
+
createdAt = createdAt,
|
|
49
|
+
dependencySet = {},
|
|
50
|
+
lastChange = nil,
|
|
51
|
+
validity = "invalid",
|
|
52
|
+
_watchingGraph = castToGraph(watching),
|
|
53
|
+
_changeListeners = {}
|
|
54
|
+
},
|
|
55
|
+
METATABLE
|
|
56
|
+
) :: any
|
|
57
|
+
local destroy = function()
|
|
58
|
+
self.scope = nil
|
|
59
|
+
for dependency in pairs(self.dependencySet) do
|
|
60
|
+
dependency.dependentSet[self] = nil
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
self.oldestTask = destroy
|
|
64
|
+
nicknames[self.oldestTask] = "Observer"
|
|
65
|
+
table.insert(scope, destroy)
|
|
66
|
+
|
|
67
|
+
if self._watchingGraph ~= nil then
|
|
68
|
+
checkLifetime.bOutlivesA(
|
|
69
|
+
scope, self.oldestTask,
|
|
70
|
+
self._watchingGraph.scope, self._watchingGraph.oldestTask,
|
|
71
|
+
checkLifetime.formatters.observer
|
|
72
|
+
)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
-- Eagerly evaluated objects need to evaluate themselves so that they're
|
|
76
|
+
-- valid at all times.
|
|
77
|
+
evaluate(self, true)
|
|
78
|
+
|
|
79
|
+
return self
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
function class.onBind(
|
|
83
|
+
self: Self,
|
|
84
|
+
callback: () -> ()
|
|
85
|
+
): () -> ()
|
|
86
|
+
External.doTaskImmediate(callback)
|
|
87
|
+
return self:onChange(callback)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
function class.onChange(
|
|
91
|
+
self: Self,
|
|
92
|
+
callback: () -> ()
|
|
93
|
+
): () -> ()
|
|
94
|
+
local uniqueIdentifier = table.freeze {}
|
|
95
|
+
self._changeListeners[uniqueIdentifier] = callback
|
|
96
|
+
return function()
|
|
97
|
+
self._changeListeners[uniqueIdentifier] = nil
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
function class._evaluate(
|
|
102
|
+
self: Self
|
|
103
|
+
): ()
|
|
104
|
+
if self._watchingGraph ~= nil then
|
|
105
|
+
depend(self, self._watchingGraph)
|
|
106
|
+
end
|
|
107
|
+
for _, callback in self._changeListeners do
|
|
108
|
+
External.doTaskImmediate(callback)
|
|
109
|
+
end
|
|
110
|
+
return true
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
table.freeze(class)
|
|
114
114
|
return Observer :: Types.ObserverConstructor
|
|
@@ -1,29 +1,29 @@
|
|
|
1
|
-
--!strict
|
|
2
|
-
--!nolint LocalUnused
|
|
3
|
-
--!nolint LocalShadow
|
|
4
|
-
local task = nil -- Disable usage of Roblox's task scheduler
|
|
5
|
-
|
|
6
|
-
--[[
|
|
7
|
-
Returns the input *only* if it is a graph object.
|
|
8
|
-
]]
|
|
9
|
-
|
|
10
|
-
local Package = script.Parent.Parent
|
|
11
|
-
local Types = require(Package.Types)
|
|
12
|
-
|
|
13
|
-
local function castToGraph(
|
|
14
|
-
target: any
|
|
15
|
-
): Types.GraphObject?
|
|
16
|
-
if
|
|
17
|
-
typeof(target) == "table" and
|
|
18
|
-
typeof(target.validity) == "string" and
|
|
19
|
-
typeof(target.timeliness) == "string" and
|
|
20
|
-
typeof(target.dependencySet) == "table" and
|
|
21
|
-
typeof(target.dependentSet) == "table"
|
|
22
|
-
then
|
|
23
|
-
return target
|
|
24
|
-
else
|
|
25
|
-
return nil
|
|
26
|
-
end
|
|
27
|
-
end
|
|
28
|
-
|
|
1
|
+
--!strict
|
|
2
|
+
--!nolint LocalUnused
|
|
3
|
+
--!nolint LocalShadow
|
|
4
|
+
local task = nil -- Disable usage of Roblox's task scheduler
|
|
5
|
+
|
|
6
|
+
--[[
|
|
7
|
+
Returns the input *only* if it is a graph object.
|
|
8
|
+
]]
|
|
9
|
+
|
|
10
|
+
local Package = script.Parent.Parent
|
|
11
|
+
local Types = require(Package.Types)
|
|
12
|
+
|
|
13
|
+
local function castToGraph(
|
|
14
|
+
target: any
|
|
15
|
+
): Types.GraphObject?
|
|
16
|
+
if
|
|
17
|
+
typeof(target) == "table" and
|
|
18
|
+
typeof(target.validity) == "string" and
|
|
19
|
+
typeof(target.timeliness) == "string" and
|
|
20
|
+
typeof(target.dependencySet) == "table" and
|
|
21
|
+
typeof(target.dependentSet) == "table"
|
|
22
|
+
then
|
|
23
|
+
return target
|
|
24
|
+
else
|
|
25
|
+
return nil
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
29
|
return castToGraph
|
|
@@ -1,81 +1,81 @@
|
|
|
1
|
-
--!strict
|
|
2
|
-
--!nolint LocalUnused
|
|
3
|
-
--!nolint LocalShadow
|
|
4
|
-
local task = nil -- Disable usage of Roblox's task scheduler
|
|
5
|
-
|
|
6
|
-
--[[
|
|
7
|
-
Prompts a graph object to re-evaluate its own value. If it meaningfully
|
|
8
|
-
changes, then dependents will have to re-evaluate their own values in the
|
|
9
|
-
future.
|
|
10
|
-
|
|
11
|
-
https://fluff.blog/2024/04/16/monotonic-painting.html
|
|
12
|
-
]]
|
|
13
|
-
|
|
14
|
-
local Package = script.Parent.Parent
|
|
15
|
-
local Types = require(Package.Types)
|
|
16
|
-
local External = require(Package.External)
|
|
17
|
-
local evaluate = require(Package.Graph.evaluate)
|
|
18
|
-
|
|
19
|
-
-- How long should this function run before it's considered to be in an infinite
|
|
20
|
-
-- cycle and error out?
|
|
21
|
-
local TERMINATION_TIME = 1
|
|
22
|
-
|
|
23
|
-
local function change(
|
|
24
|
-
target: Types.GraphObject
|
|
25
|
-
): ()
|
|
26
|
-
if target.validity == "busy" then
|
|
27
|
-
return External.logError("infiniteLoop")
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
local meaningfullyChanged = evaluate(target, true)
|
|
31
|
-
if not meaningfullyChanged then
|
|
32
|
-
return
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
local searchInNow: {Types.GraphObject} = {}
|
|
36
|
-
local searchInNext: {Types.GraphObject} = {}
|
|
37
|
-
local invalidateList: {Types.GraphObject} = {}
|
|
38
|
-
|
|
39
|
-
searchInNow[1] = target
|
|
40
|
-
local terminateBy = os.clock() + TERMINATION_TIME * External.safetyTimerMultiplier
|
|
41
|
-
repeat
|
|
42
|
-
if os.clock() > terminateBy then
|
|
43
|
-
return External.logError("infiniteLoop")
|
|
44
|
-
end
|
|
45
|
-
local done = true
|
|
46
|
-
for _, searchTarget in searchInNow do
|
|
47
|
-
for dependent in searchTarget.dependentSet do
|
|
48
|
-
if dependent.validity == "valid" then
|
|
49
|
-
done = false
|
|
50
|
-
table.insert(invalidateList, dependent)
|
|
51
|
-
table.insert(searchInNext, dependent)
|
|
52
|
-
elseif dependent.validity == "busy" then
|
|
53
|
-
return External.logError("infiniteLoop")
|
|
54
|
-
end
|
|
55
|
-
end
|
|
56
|
-
end
|
|
57
|
-
searchInNow, searchInNext = searchInNext, searchInNow
|
|
58
|
-
table.clear(searchInNext)
|
|
59
|
-
until done
|
|
60
|
-
|
|
61
|
-
local eagerList: {Types.GraphObject} = {}
|
|
62
|
-
|
|
63
|
-
for _, invalidateTarget in invalidateList do
|
|
64
|
-
invalidateTarget.validity = "invalid"
|
|
65
|
-
if invalidateTarget.timeliness == "eager" then
|
|
66
|
-
table.insert(eagerList, invalidateTarget)
|
|
67
|
-
end
|
|
68
|
-
end
|
|
69
|
-
-- If objects are not executed in order of creations, then dynamic graphs
|
|
70
|
-
-- may experience 'glitches' where nested graph objects see intermediate
|
|
71
|
-
-- values before being destroyed.
|
|
72
|
-
-- https://fluff.blog/2024/07/14/glitches-in-dynamic-reactive-graphs.html
|
|
73
|
-
table.sort(eagerList, function(a, b)
|
|
74
|
-
return a.createdAt < b.createdAt
|
|
75
|
-
end)
|
|
76
|
-
for _, eagerTarget in eagerList do
|
|
77
|
-
evaluate(eagerTarget, false)
|
|
78
|
-
end
|
|
79
|
-
end
|
|
80
|
-
|
|
1
|
+
--!strict
|
|
2
|
+
--!nolint LocalUnused
|
|
3
|
+
--!nolint LocalShadow
|
|
4
|
+
local task = nil -- Disable usage of Roblox's task scheduler
|
|
5
|
+
|
|
6
|
+
--[[
|
|
7
|
+
Prompts a graph object to re-evaluate its own value. If it meaningfully
|
|
8
|
+
changes, then dependents will have to re-evaluate their own values in the
|
|
9
|
+
future.
|
|
10
|
+
|
|
11
|
+
https://fluff.blog/2024/04/16/monotonic-painting.html
|
|
12
|
+
]]
|
|
13
|
+
|
|
14
|
+
local Package = script.Parent.Parent
|
|
15
|
+
local Types = require(Package.Types)
|
|
16
|
+
local External = require(Package.External)
|
|
17
|
+
local evaluate = require(Package.Graph.evaluate)
|
|
18
|
+
|
|
19
|
+
-- How long should this function run before it's considered to be in an infinite
|
|
20
|
+
-- cycle and error out?
|
|
21
|
+
local TERMINATION_TIME = 1
|
|
22
|
+
|
|
23
|
+
local function change(
|
|
24
|
+
target: Types.GraphObject
|
|
25
|
+
): ()
|
|
26
|
+
if target.validity == "busy" then
|
|
27
|
+
return External.logError("infiniteLoop")
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
local meaningfullyChanged = evaluate(target, true)
|
|
31
|
+
if not meaningfullyChanged then
|
|
32
|
+
return
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
local searchInNow: {Types.GraphObject} = {}
|
|
36
|
+
local searchInNext: {Types.GraphObject} = {}
|
|
37
|
+
local invalidateList: {Types.GraphObject} = {}
|
|
38
|
+
|
|
39
|
+
searchInNow[1] = target
|
|
40
|
+
local terminateBy = os.clock() + TERMINATION_TIME * External.safetyTimerMultiplier
|
|
41
|
+
repeat
|
|
42
|
+
if os.clock() > terminateBy then
|
|
43
|
+
return External.logError("infiniteLoop")
|
|
44
|
+
end
|
|
45
|
+
local done = true
|
|
46
|
+
for _, searchTarget in searchInNow do
|
|
47
|
+
for dependent in searchTarget.dependentSet do
|
|
48
|
+
if dependent.validity == "valid" then
|
|
49
|
+
done = false
|
|
50
|
+
table.insert(invalidateList, dependent)
|
|
51
|
+
table.insert(searchInNext, dependent)
|
|
52
|
+
elseif dependent.validity == "busy" then
|
|
53
|
+
return External.logError("infiniteLoop")
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
searchInNow, searchInNext = searchInNext, searchInNow
|
|
58
|
+
table.clear(searchInNext)
|
|
59
|
+
until done
|
|
60
|
+
|
|
61
|
+
local eagerList: {Types.GraphObject} = {}
|
|
62
|
+
|
|
63
|
+
for _, invalidateTarget in invalidateList do
|
|
64
|
+
invalidateTarget.validity = "invalid"
|
|
65
|
+
if invalidateTarget.timeliness == "eager" then
|
|
66
|
+
table.insert(eagerList, invalidateTarget)
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
-- If objects are not executed in order of creations, then dynamic graphs
|
|
70
|
+
-- may experience 'glitches' where nested graph objects see intermediate
|
|
71
|
+
-- values before being destroyed.
|
|
72
|
+
-- https://fluff.blog/2024/07/14/glitches-in-dynamic-reactive-graphs.html
|
|
73
|
+
table.sort(eagerList, function(a, b)
|
|
74
|
+
return a.createdAt < b.createdAt
|
|
75
|
+
end)
|
|
76
|
+
for _, eagerTarget in eagerList do
|
|
77
|
+
evaluate(eagerTarget, false)
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
81
|
return change
|
|
@@ -1,33 +1,33 @@
|
|
|
1
|
-
--!strict
|
|
2
|
-
--!nolint LocalUnused
|
|
3
|
-
--!nolint LocalShadow
|
|
4
|
-
local task = nil -- Disable usage of Roblox's task scheduler
|
|
5
|
-
|
|
6
|
-
--[[
|
|
7
|
-
Forms a dependency on a graph object.
|
|
8
|
-
]]
|
|
9
|
-
|
|
10
|
-
local Package = script.Parent.Parent
|
|
11
|
-
local Types = require(Package.Types)
|
|
12
|
-
local External = require(Package.External)
|
|
13
|
-
local evaluate = require(Package.Graph.evaluate)
|
|
14
|
-
local nameOf = require(Package.Utility.nameOf)
|
|
15
|
-
|
|
16
|
-
local function depend<T>(
|
|
17
|
-
dependent: Types.GraphObject,
|
|
18
|
-
dependency: Types.GraphObject
|
|
19
|
-
): ()
|
|
20
|
-
-- Ensure dependencies are evaluated and up-to-date
|
|
21
|
-
-- when they are depended on. Also, newly created objects
|
|
22
|
-
-- might not have any transitive dependencies captured yet,
|
|
23
|
-
-- so ensure that they're present.
|
|
24
|
-
evaluate(dependency, false)
|
|
25
|
-
|
|
26
|
-
if table.isfrozen(dependent.dependencySet) or table.isfrozen(dependency.dependentSet) then
|
|
27
|
-
External.logError("cannotDepend", nil, nameOf(dependent, "Dependent"), nameOf(dependency, "dependency"))
|
|
28
|
-
end
|
|
29
|
-
dependency.dependentSet[dependent] = true
|
|
30
|
-
dependent.dependencySet[dependency] = true
|
|
31
|
-
end
|
|
32
|
-
|
|
1
|
+
--!strict
|
|
2
|
+
--!nolint LocalUnused
|
|
3
|
+
--!nolint LocalShadow
|
|
4
|
+
local task = nil -- Disable usage of Roblox's task scheduler
|
|
5
|
+
|
|
6
|
+
--[[
|
|
7
|
+
Forms a dependency on a graph object.
|
|
8
|
+
]]
|
|
9
|
+
|
|
10
|
+
local Package = script.Parent.Parent
|
|
11
|
+
local Types = require(Package.Types)
|
|
12
|
+
local External = require(Package.External)
|
|
13
|
+
local evaluate = require(Package.Graph.evaluate)
|
|
14
|
+
local nameOf = require(Package.Utility.nameOf)
|
|
15
|
+
|
|
16
|
+
local function depend<T>(
|
|
17
|
+
dependent: Types.GraphObject,
|
|
18
|
+
dependency: Types.GraphObject
|
|
19
|
+
): ()
|
|
20
|
+
-- Ensure dependencies are evaluated and up-to-date
|
|
21
|
+
-- when they are depended on. Also, newly created objects
|
|
22
|
+
-- might not have any transitive dependencies captured yet,
|
|
23
|
+
-- so ensure that they're present.
|
|
24
|
+
evaluate(dependency, false)
|
|
25
|
+
|
|
26
|
+
if table.isfrozen(dependent.dependencySet) or table.isfrozen(dependency.dependentSet) then
|
|
27
|
+
External.logError("cannotDepend", nil, nameOf(dependent, "Dependent"), nameOf(dependency, "dependency"))
|
|
28
|
+
end
|
|
29
|
+
dependency.dependentSet[dependent] = true
|
|
30
|
+
dependent.dependencySet[dependency] = true
|
|
31
|
+
end
|
|
32
|
+
|
|
33
33
|
return depend
|
|
@@ -1,56 +1,56 @@
|
|
|
1
|
-
--!strict
|
|
2
|
-
--!nolint LocalUnused
|
|
3
|
-
--!nolint LocalShadow
|
|
4
|
-
local task = nil -- Disable usage of Roblox's task scheduler
|
|
5
|
-
|
|
6
|
-
--[[
|
|
7
|
-
Evaluates the graph object if necessary, so that it is up to date.
|
|
8
|
-
Returns true if it meaningfully changed.
|
|
9
|
-
|
|
10
|
-
https://fluff.blog/2024/04/16/monotonic-painting.html
|
|
11
|
-
]]
|
|
12
|
-
|
|
13
|
-
local Package = script.Parent.Parent
|
|
14
|
-
local Types = require(Package.Types)
|
|
15
|
-
local External = require(Package.External)
|
|
16
|
-
|
|
17
|
-
local function evaluate(
|
|
18
|
-
target: Types.GraphObject,
|
|
19
|
-
forceComputation: boolean
|
|
20
|
-
): boolean
|
|
21
|
-
if target.validity == "busy" then
|
|
22
|
-
return External.logError("infiniteLoop")
|
|
23
|
-
end
|
|
24
|
-
local firstEvaluation = target.lastChange == nil
|
|
25
|
-
local isInvalid = target.validity == "invalid"
|
|
26
|
-
if firstEvaluation or isInvalid or forceComputation then
|
|
27
|
-
local needsComputation = firstEvaluation or forceComputation
|
|
28
|
-
if not needsComputation then
|
|
29
|
-
for dependency in target.dependencySet do
|
|
30
|
-
evaluate(dependency, false)
|
|
31
|
-
if dependency.lastChange > target.lastChange then
|
|
32
|
-
needsComputation = true
|
|
33
|
-
break
|
|
34
|
-
end
|
|
35
|
-
end
|
|
36
|
-
end
|
|
37
|
-
local targetMeaningfullyChanged = false
|
|
38
|
-
if needsComputation then
|
|
39
|
-
for dependency in target.dependencySet do
|
|
40
|
-
dependency.dependentSet[target] = nil
|
|
41
|
-
target.dependencySet[dependency] = nil
|
|
42
|
-
end
|
|
43
|
-
target.validity = "busy"
|
|
44
|
-
targetMeaningfullyChanged = target:_evaluate() or firstEvaluation
|
|
45
|
-
end
|
|
46
|
-
if targetMeaningfullyChanged then
|
|
47
|
-
target.lastChange = os.clock()
|
|
48
|
-
end
|
|
49
|
-
target.validity = "valid"
|
|
50
|
-
return targetMeaningfullyChanged
|
|
51
|
-
else
|
|
52
|
-
return false
|
|
53
|
-
end
|
|
54
|
-
end
|
|
55
|
-
|
|
1
|
+
--!strict
|
|
2
|
+
--!nolint LocalUnused
|
|
3
|
+
--!nolint LocalShadow
|
|
4
|
+
local task = nil -- Disable usage of Roblox's task scheduler
|
|
5
|
+
|
|
6
|
+
--[[
|
|
7
|
+
Evaluates the graph object if necessary, so that it is up to date.
|
|
8
|
+
Returns true if it meaningfully changed.
|
|
9
|
+
|
|
10
|
+
https://fluff.blog/2024/04/16/monotonic-painting.html
|
|
11
|
+
]]
|
|
12
|
+
|
|
13
|
+
local Package = script.Parent.Parent
|
|
14
|
+
local Types = require(Package.Types)
|
|
15
|
+
local External = require(Package.External)
|
|
16
|
+
|
|
17
|
+
local function evaluate(
|
|
18
|
+
target: Types.GraphObject,
|
|
19
|
+
forceComputation: boolean
|
|
20
|
+
): boolean
|
|
21
|
+
if target.validity == "busy" then
|
|
22
|
+
return External.logError("infiniteLoop")
|
|
23
|
+
end
|
|
24
|
+
local firstEvaluation = target.lastChange == nil
|
|
25
|
+
local isInvalid = target.validity == "invalid"
|
|
26
|
+
if firstEvaluation or isInvalid or forceComputation then
|
|
27
|
+
local needsComputation = firstEvaluation or forceComputation
|
|
28
|
+
if not needsComputation then
|
|
29
|
+
for dependency in target.dependencySet do
|
|
30
|
+
evaluate(dependency, false)
|
|
31
|
+
if dependency.lastChange > target.lastChange then
|
|
32
|
+
needsComputation = true
|
|
33
|
+
break
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
local targetMeaningfullyChanged = false
|
|
38
|
+
if needsComputation then
|
|
39
|
+
for dependency in target.dependencySet do
|
|
40
|
+
dependency.dependentSet[target] = nil
|
|
41
|
+
target.dependencySet[dependency] = nil
|
|
42
|
+
end
|
|
43
|
+
target.validity = "busy"
|
|
44
|
+
targetMeaningfullyChanged = target:_evaluate() or firstEvaluation
|
|
45
|
+
end
|
|
46
|
+
if targetMeaningfullyChanged then
|
|
47
|
+
target.lastChange = os.clock()
|
|
48
|
+
end
|
|
49
|
+
target.validity = "valid"
|
|
50
|
+
return targetMeaningfullyChanged
|
|
51
|
+
else
|
|
52
|
+
return false
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
56
|
return evaluate
|