cluaupp 1.5.0 → 1.5.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/CHANGELOG.md +47 -0
- package/README.md +10 -5
- package/api/CHANGELOG.md +3 -0
- package/api/chat.js +74 -0
- package/api/fixtures/roblox/README.md +6 -0
- package/api/fixtures/roblox/aux/sample.d.luau +6 -0
- package/api/fixtures/roblox/mini/Mini-API-Dump.json +72 -0
- package/api/generated/bench-latest.json +39 -0
- package/api/generated/capability-profile.json +76 -0
- package/api/generated/lsp-index.json +1 -0
- package/api/generated/luau/classes.d.luau +11221 -0
- package/api/generated/luau/datatypes.d.luau +327 -0
- package/api/generated/luau/enums.d.luau +4918 -0
- package/api/generated/luau/globals.d.luau +12 -0
- package/api/manifests/roblox-target.manifest.json +22 -0
- package/api/normalized/roblox-target.profile.json +237461 -0
- package/api/overrides/classes.json +8 -0
- package/api/overrides/compatibility.json +9 -0
- package/api/overrides/datatypes.json +1579 -0
- package/api/overrides/enums.json +8 -0
- package/api/overrides/globals.json +8 -0
- package/api/overrides/type-mappings.json +9 -0
- package/api/roblox-api.lock.json +9 -0
- package/data/Mini-API-Dump.json +1 -0
- package/editors/vscode/README.md +12 -10
- package/editors/vscode/extension.js +82 -0
- package/editors/vscode/icons/axiom.svg +4 -0
- package/editors/vscode/icons/bloom.svg +5 -0
- package/editors/vscode/icons/helm.svg +4 -0
- package/editors/vscode/icons/hive.svg +5 -0
- package/editors/vscode/icons/mint.svg +4 -0
- package/editors/vscode/icons/shift.svg +6 -0
- package/editors/vscode/language-configuration-schema.json +24 -0
- package/editors/vscode/package.json +172 -12
- package/editors/vscode/snippets/axiom.json +12 -0
- package/editors/vscode/snippets/bloom.json +12 -0
- package/editors/vscode/snippets/helm.json +12 -0
- package/editors/vscode/snippets/hive.json +12 -0
- package/editors/vscode/snippets/mint.json +12 -0
- package/editors/vscode/snippets/shift.json +17 -0
- package/editors/vscode/syntaxes/axiom.tmLanguage.json +5 -0
- package/editors/vscode/syntaxes/bloom.tmLanguage.json +5 -0
- package/editors/vscode/syntaxes/helm.tmLanguage.json +5 -0
- package/editors/vscode/syntaxes/hive.tmLanguage.json +5 -0
- package/editors/vscode/syntaxes/mint.tmLanguage.json +5 -0
- package/editors/vscode/syntaxes/schema.tmLanguage.json +89 -0
- package/editors/vscode/syntaxes/shift.tmLanguage.json +5 -0
- package/examples/game/.cluaupp/compile-cache/ReplicatedStorage__Shared__Constants__Datas__TemplateData.clh.json +1 -0
- package/examples/game/.cluaupp/compile-cache/ServerScriptService__Boot__DataBoot.server.clpp.json +1 -0
- package/examples/game/.cluaupp/compile-cache/ServerScriptService__Configuration__ServerConfig.clp.json +1 -0
- package/examples/game/.cluaupp/compile-cache/ServerScriptService__Handlers__Guard.server.clpp.json +1 -0
- package/examples/game/.cluaupp/compile-cache/ServerScriptService__Handlers__PlayerHandler.server.clpp.json +1 -0
- package/examples/game/.cluaupp/compile-cache/StarterPlayer__StarterCharacterScripts__Character__CharacterReady.client.clpp.json +1 -0
- package/examples/game/.cluaupp/compile-cache/StarterPlayer__StarterPlayerScripts__Controllers__DataController.client.clpp.json +1 -0
- package/examples/game/.cluaupp/compile-cache/index.json +12 -0
- package/examples/game/.cluaupp/datamodel-profile.json +94 -0
- package/examples/game/.vscode/settings.json +12 -1
- package/examples/game/include/clpp/datatypes.clh +337 -373
- package/examples/game/include/clpp/generated/datamodel.clh +25 -0
- package/examples/game/include/clpp/generated/enums.clh +1 -1
- package/examples/game/include/clpp/generated/instances.clh +41135 -41064
- package/examples/game/include/clpp/libs/axiom.clh +1 -1
- package/examples/game/include/clpp/libs/math.clh +14 -0
- package/examples/game/include/clpp/libs/spring.clh +17 -0
- package/examples/game/include/clpp/libs/ward.clh +1 -0
- package/examples/game/include/clpp/roblox.clh +3 -4
- package/examples/game/libs/ArrayIndexer/init.luau +209 -0
- package/examples/game/libs/Axiom/init.luau +608 -0
- package/examples/game/libs/Bloom/init.luau +433 -0
- package/examples/game/libs/Coil/init.luau +215 -0
- package/examples/game/libs/Crest/init.luau +426 -0
- package/examples/game/libs/Echo/init.luau +417 -0
- package/examples/game/libs/Ember/init.luau +365 -0
- package/examples/game/libs/Flare/init.luau +717 -0
- package/examples/game/libs/Gleam/init.luau +729 -0
- package/examples/game/libs/Guide/init.luau +215 -0
- package/examples/game/libs/Helm/init.luau +377 -0
- package/examples/game/libs/Hive/init.luau +241 -0
- package/examples/game/libs/Keep/Client.luau +114 -0
- package/examples/game/libs/Keep/Data.luau +883 -0
- package/examples/game/libs/Keep/Engine.luau +211 -0
- package/examples/game/libs/Keep/Enum.luau +6 -0
- package/examples/game/libs/Keep/Enums.luau +10 -0
- package/examples/game/libs/Keep/Path.luau +236 -0
- package/examples/game/libs/Keep/Replicator.luau +298 -0
- package/examples/game/libs/Keep/Server.luau +251 -0
- package/examples/game/libs/Keep/Store.luau +652 -0
- package/examples/game/libs/Keep/Trade.luau +455 -0
- package/examples/game/libs/Keep/init.luau +205 -0
- package/examples/game/libs/Lens/init.luau +609 -0
- package/examples/game/libs/Mint/init.luau +279 -0
- package/examples/game/libs/Net/init.luau +156 -0
- package/examples/game/libs/Net/src/codec.luau +224 -0
- package/examples/game/libs/Occlude/init.luau +117 -0
- package/examples/game/libs/Pin/init.luau +309 -0
- package/examples/game/libs/Promise/LICENSE +21 -0
- package/examples/game/libs/Promise/_impl/LICENSE +21 -0
- package/examples/game/libs/Promise/_impl/init.lua +1991 -0
- package/examples/game/libs/Promise/init.lua +1990 -0
- package/examples/game/libs/Promise/init.luau +13 -0
- package/examples/game/libs/Promise/types.luau +46 -0
- package/examples/game/libs/Roster/init.luau +686 -0
- package/examples/game/libs/SOURCES.md +31 -0
- package/examples/game/libs/Shift/init.luau +238 -0
- package/examples/game/libs/Spark/init.luau +487 -0
- package/examples/game/libs/Stage/init.luau +178 -0
- package/examples/game/libs/Sweep/init.luau +259 -0
- package/examples/game/libs/Trace/init.luau +213 -0
- package/examples/game/libs/Ward/init.luau +211 -0
- package/examples/game/out/ReplicatedStorage/Shared/Constants/Datas/TemplateData.luau +29 -0
- package/examples/game/out/ReplicatedStorage/Shared/Constants/Datas/TemplateData.luau.map.json +13 -0
- package/examples/game/out/ReplicatedStorage/Shared/Net/Net.luau +83 -0
- package/examples/game/out/ReplicatedStorage/Shared/Net/Net.luau.map.json +13 -0
- package/examples/game/out/ServerScriptService/Boot/DataBoot.server.luau +18 -0
- package/examples/game/out/ServerScriptService/Boot/DataBoot.server.luau.map.json +13 -0
- package/examples/game/out/ServerScriptService/Configuration/ServerConfig.luau +14 -0
- package/examples/game/out/ServerScriptService/Configuration/ServerConfig.luau.map.json +13 -0
- package/examples/game/out/ServerScriptService/Handlers/Guard.server.luau +15 -0
- package/examples/game/out/ServerScriptService/Handlers/Guard.server.luau.map.json +13 -0
- package/examples/game/out/ServerScriptService/Handlers/PlayerHandler.server.luau +50 -0
- package/examples/game/out/ServerScriptService/Handlers/PlayerHandler.server.luau.map.json +13 -0
- package/examples/game/out/StarterPlayer/StarterCharacterScripts/Character/CharacterReady.client.luau +12 -0
- package/examples/game/out/StarterPlayer/StarterCharacterScripts/Character/CharacterReady.client.luau.map.json +13 -0
- package/examples/game/out/StarterPlayer/StarterPlayerScripts/Controllers/DataController.client.luau +16 -0
- package/examples/game/out/StarterPlayer/StarterPlayerScripts/Controllers/DataController.client.luau.map.json +13 -0
- package/examples/game/src/ReplicatedStorage/Shared/Net/Net.clh +26 -0
- package/examples/game/src/ServerScriptService/Boot/DataBoot.server.clpp +1 -1
- package/examples/game/src/ServerScriptService/Handlers/PlayerHandler.server.clpp +1 -1
- package/examples/game/stylua.toml +9 -0
- package/generated/api/build-profile.js +115 -0
- package/generated/api/cache.js +44 -0
- package/generated/api/coverage.js +32 -0
- package/generated/api/diff.js +125 -0
- package/generated/api/generators/clpp-headers.js +353 -0
- package/generated/api/generators/docs-reference.js +7 -0
- package/generated/api/generators/lsp-index.js +81 -0
- package/generated/api/generators/luau-defs.js +94 -0
- package/generated/api/ide.js +76 -0
- package/generated/api/identifier.js +47 -0
- package/generated/api/index.js +324 -0
- package/generated/api/loader.js +57 -0
- package/generated/api/merge.js +88 -0
- package/generated/api/model.js +5 -0
- package/generated/api/normalize.js +231 -0
- package/generated/api/overrides-validate.js +58 -0
- package/generated/api/perf.js +12 -0
- package/generated/api/registry.js +136 -0
- package/generated/api/release.js +44 -0
- package/generated/api/resolver.js +250 -0
- package/generated/api/sources/aux-types-diff.js +75 -0
- package/generated/api/sources/client-tracker.js +11 -0
- package/generated/api/sources/creator-docs.js +42 -0
- package/generated/api/sources/luau-types.js +34 -0
- package/generated/api/sources/mini-dump.js +17 -0
- package/generated/api/sources/studio-api.js +8 -0
- package/generated/api/sources/studio-apiv2.js +11 -0
- package/generated/api/sources/studio-full-api.js +8 -0
- package/generated/api/studio-smoke.js +80 -0
- package/generated/api/type-parse.js +49 -0
- package/generated/api/understander.js +51 -0
- package/generated/api/validate.js +135 -0
- package/generated/api-cli.js +421 -0
- package/generated/cli.js +16 -5
- package/generated/clpp/contract.js +3 -3
- package/generated/clpp/format-luau.js +236 -0
- package/generated/clpp/index.js +13 -1
- package/generated/clpp/modules.js +227 -0
- package/generated/clpp/postprocess.js +86 -5
- package/generated/clpp/rewrite-janitor.js +145 -0
- package/generated/clpp/runner.js +14 -2
- package/generated/compile.js +82 -0
- package/generated/flare/parse.js +12 -1
- package/generated/intellisense.js +57 -1
- package/generated/native/index.js +217 -16
- package/generated/target/authority-check.js +136 -0
- package/generated/target/authority-graph.js +74 -0
- package/generated/target/build-cache.js +112 -0
- package/generated/target/capabilities.js +89 -0
- package/generated/target/capability-profile.js +30 -0
- package/generated/target/component-contracts.js +60 -0
- package/generated/target/context-check.js +160 -0
- package/generated/target/datamodel-check.js +170 -0
- package/generated/target/datamodel-generate.js +74 -0
- package/generated/target/datamodel.js +233 -0
- package/generated/target/diagnostics.js +63 -0
- package/generated/target/doctor.js +152 -0
- package/generated/target/flare-version.js +58 -0
- package/generated/target/get-service.js +69 -0
- package/generated/target/lifetime-check.js +47 -0
- package/generated/target/luau-stamp.js +39 -0
- package/generated/target/optimizer-advise.js +88 -0
- package/generated/target/optimizer-apply.js +44 -0
- package/generated/target/optimizer-soa.js +254 -0
- package/generated/target/parallel-check.js +136 -0
- package/generated/target/pgo.js +148 -0
- package/generated/target/project-docs.js +69 -0
- package/generated/target/project-graph.js +71 -0
- package/generated/target/roblox.js +63 -0
- package/generated/target/security-check.js +41 -0
- package/generated/target/source-map.js +25 -0
- package/generated/target/studio-bridge.js +112 -0
- package/generated/utils/project.js +178 -8
- package/generated/utils/rojo-mapper.js +11 -3
- package/include/clpp/datatypes.clh +337 -373
- package/include/clpp/generated/enums.clh +1 -1
- package/include/clpp/generated/instances.clh +41135 -41064
- package/include/clpp/libs/axiom.clh +1 -1
- package/include/clpp/libs/hive.clh +1 -0
- package/include/clpp/libs/keep.clh +2 -0
- package/include/clpp/libs/math.clh +14 -0
- package/include/clpp/libs/spring.clh +17 -0
- package/include/clpp/libs/ward.clh +1 -0
- package/include/clpp/roblox.clh +3 -4
- package/package.json +10 -3
- package/plugins/CluauppNav/Plugin.luau +207 -0
- package/plugins/CluauppNav/ProfileLogger.luau +27 -0
- package/plugins/CluauppNav/README.md +24 -0
- package/runtime/Axiom/init.luau +10 -7
- package/runtime/Coil/init.luau +8 -2
- package/runtime/Crest/init.luau +1 -0
- package/runtime/Flare/init.luau +2 -1
- package/runtime/Gleam/init.luau +15 -4
- package/runtime/Hive/init.luau +36 -14
- package/runtime/Pin/init.luau +5 -2
- package/runtime/Roster/init.luau +2 -0
- package/runtime/Spark/init.luau +3 -0
- package/runtime/Sweep/init.luau +2 -0
- package/runtime/Trace/init.luau +3 -0
- package/runtime/Ward/init.luau +38 -5
- package/scripts/postinstall-editor.js +17 -0
- package/skills/README.md +13 -0
- package/skills/clpp-hive-flare/SKILL.md +79 -0
- package/skills/clpp-language/SKILL.md +123 -0
- package/skills/clpp-language/compiler.md +89 -0
- package/skills/clpp-style/SKILL.md +95 -0
- package/src/api/build-profile.ts +138 -0
- package/src/api/cache.ts +45 -0
- package/src/api/coverage.ts +46 -0
- package/src/api/diff.ts +143 -0
- package/src/api/generators/clpp-headers.ts +377 -0
- package/src/api/generators/docs-reference.ts +11 -0
- package/src/api/generators/lsp-index.ts +106 -0
- package/src/api/generators/luau-defs.ts +98 -0
- package/src/api/ide.ts +87 -0
- package/src/api/identifier.ts +47 -0
- package/src/api/index.ts +269 -0
- package/src/api/loader.ts +60 -0
- package/src/api/merge.ts +126 -0
- package/src/api/model.ts +283 -0
- package/src/api/normalize.ts +257 -0
- package/src/api/overrides-validate.ts +58 -0
- package/src/api/perf.ts +15 -0
- package/src/api/registry.ts +162 -0
- package/src/api/release.ts +47 -0
- package/src/api/resolver.ts +255 -0
- package/src/api/sources/aux-types-diff.ts +81 -0
- package/src/api/sources/client-tracker.ts +10 -0
- package/src/api/sources/creator-docs.ts +37 -0
- package/src/api/sources/luau-types.ts +30 -0
- package/src/api/sources/mini-dump.ts +50 -0
- package/src/api/sources/studio-api.ts +7 -0
- package/src/api/sources/studio-apiv2.ts +10 -0
- package/src/api/sources/studio-full-api.ts +7 -0
- package/src/api/studio-smoke.ts +82 -0
- package/src/api/type-parse.ts +48 -0
- package/src/api/understander.ts +72 -0
- package/src/api/validate.ts +160 -0
- package/src/api-cli.ts +493 -0
- package/src/api.generated.js +37 -22
- package/src/cli.ts +21 -6
- package/src/clpp/contract.ts +34 -3
- package/src/clpp/format-luau.ts +262 -0
- package/src/clpp/index.ts +13 -2
- package/src/clpp/modules.ts +252 -0
- package/src/clpp/postprocess.ts +100 -5
- package/src/clpp/rewrite-janitor.ts +156 -0
- package/src/clpp/runner.ts +14 -2
- package/src/compile.ts +87 -0
- package/src/flare/parse.ts +14 -1
- package/src/flare/types.ts +2 -0
- package/src/intellisense.ts +58 -1
- package/src/native/index.ts +225 -16
- package/src/target/authority-check.ts +162 -0
- package/src/target/authority-graph.ts +80 -0
- package/src/target/build-cache.ts +129 -0
- package/src/target/capabilities.ts +115 -0
- package/src/target/capability-profile.ts +25 -0
- package/src/target/component-contracts.ts +64 -0
- package/src/target/context-check.ts +177 -0
- package/src/target/datamodel-check.ts +188 -0
- package/src/target/datamodel-generate.ts +78 -0
- package/src/target/datamodel.ts +261 -0
- package/src/target/diagnostics.ts +67 -0
- package/src/target/doctor.ts +171 -0
- package/src/target/flare-version.ts +61 -0
- package/src/target/get-service.ts +85 -0
- package/src/target/lifetime-check.ts +45 -0
- package/src/target/luau-stamp.ts +33 -0
- package/src/target/optimizer-advise.ts +93 -0
- package/src/target/optimizer-apply.ts +63 -0
- package/src/target/optimizer-soa.ts +270 -0
- package/src/target/parallel-check.ts +135 -0
- package/src/target/pgo.ts +157 -0
- package/src/target/project-docs.ts +68 -0
- package/src/target/project-graph.ts +75 -0
- package/src/target/roblox.ts +78 -0
- package/src/target/security-check.ts +40 -0
- package/src/target/source-map.ts +36 -0
- package/src/target/studio-bridge.ts +140 -0
- package/src/types.ts +14 -0
- package/src/utils/project.ts +183 -9
- package/src/utils/rojo-mapper.ts +12 -3
- package/stylua.toml +9 -0
- package/templates/game/.vscode/settings.json +7 -1
- package/templates/game/include/clpp/datatypes.clh +337 -373
- package/templates/game/include/clpp/generated/enums.clh +1 -1
- package/templates/game/include/clpp/generated/instances.clh +41135 -41064
- package/templates/game/include/clpp/libs/axiom.clh +1 -1
- package/templates/game/include/clpp/libs/ward.clh +1 -0
- package/templates/game/include/clpp/roblox.clh +3 -4
- package/templates/game/src/ServerScriptService/Boot/DataBoot.server.clpp +1 -1
- package/templates/game/src/ServerScriptService/Handlers/PlayerHandler.server.clpp +1 -1
- package/templates/game/stylua.toml +9 -0
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
--!native
|
|
2
|
+
--!optimize 2
|
|
3
|
+
--!strict
|
|
4
|
+
-- Shift — compiled FSM/HSM. State ids are u8. No per-frame OnDataChanged.
|
|
5
|
+
|
|
6
|
+
local Shift = {}
|
|
7
|
+
Shift.__index = Shift
|
|
8
|
+
|
|
9
|
+
export type ShiftMachine = typeof(setmetatable(
|
|
10
|
+
{} :: {
|
|
11
|
+
State: number,
|
|
12
|
+
Previous: number,
|
|
13
|
+
History: { number },
|
|
14
|
+
Ids: { [string]: number },
|
|
15
|
+
Names: { [number]: string },
|
|
16
|
+
Parents: { [string]: string },
|
|
17
|
+
Transitions: { { From: string, To: string, Guard: string } },
|
|
18
|
+
Data: { [string]: any },
|
|
19
|
+
Alive: boolean,
|
|
20
|
+
_guards: { [string]: () -> boolean },
|
|
21
|
+
_enters: { [string]: () -> () },
|
|
22
|
+
_leaves: { [string]: () -> () },
|
|
23
|
+
},
|
|
24
|
+
Shift
|
|
25
|
+
))
|
|
26
|
+
|
|
27
|
+
local function ancestorChain(self: ShiftMachine, name: string?): { string }
|
|
28
|
+
local chain = {}
|
|
29
|
+
local current = name
|
|
30
|
+
local seen: { [string]: boolean } = {}
|
|
31
|
+
while current and not seen[current] do
|
|
32
|
+
seen[current] = true
|
|
33
|
+
table.insert(chain, 1, current)
|
|
34
|
+
current = self.Parents[current]
|
|
35
|
+
end
|
|
36
|
+
return chain
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
local function inBranch(self: ShiftMachine, name: string): boolean
|
|
40
|
+
local current = self.Names[self.State]
|
|
41
|
+
local seen: { [string]: boolean } = {}
|
|
42
|
+
while current and not seen[current] do
|
|
43
|
+
if current == name then
|
|
44
|
+
return true
|
|
45
|
+
end
|
|
46
|
+
seen[current] = true
|
|
47
|
+
current = self.Parents[current]
|
|
48
|
+
end
|
|
49
|
+
return false
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
local function edgeAllowed(self: ShiftMachine, fromName: string?, toName: string): boolean?
|
|
53
|
+
if fromName == nil then
|
|
54
|
+
return nil
|
|
55
|
+
end
|
|
56
|
+
for _, edge in self.Transitions do
|
|
57
|
+
if edge.From == fromName and edge.To == toName then
|
|
58
|
+
if edge.Guard == "" or edge.Guard == nil then
|
|
59
|
+
return true
|
|
60
|
+
end
|
|
61
|
+
local guard = self._guards[edge.Guard]
|
|
62
|
+
if not guard then
|
|
63
|
+
return true
|
|
64
|
+
end
|
|
65
|
+
return guard()
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
return nil
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
function Shift.New(ids: { [string]: number }, transitions: { any }, parents: { [string]: string }?): ShiftMachine
|
|
72
|
+
local names = {}
|
|
73
|
+
local initial = 0
|
|
74
|
+
for name, id in ids do
|
|
75
|
+
names[id] = name
|
|
76
|
+
if id == 0 then
|
|
77
|
+
initial = 0
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
return setmetatable({
|
|
81
|
+
State = initial,
|
|
82
|
+
Previous = initial,
|
|
83
|
+
History = { initial },
|
|
84
|
+
Ids = ids,
|
|
85
|
+
Names = names,
|
|
86
|
+
Parents = parents or {},
|
|
87
|
+
Transitions = transitions,
|
|
88
|
+
Data = {},
|
|
89
|
+
Alive = true,
|
|
90
|
+
_guards = {} :: { [string]: () -> boolean },
|
|
91
|
+
_enters = {} :: { [string]: () -> () },
|
|
92
|
+
_leaves = {} :: { [string]: () -> () },
|
|
93
|
+
}, Shift)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
function Shift:Guard(name: string, fn: () -> boolean)
|
|
97
|
+
self._guards[name] = fn
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
function Shift:OnEnter(name: string, fn: () -> ())
|
|
101
|
+
self._enters[name] = fn
|
|
102
|
+
if self.Alive and self.Names[self.State] == name then
|
|
103
|
+
fn()
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
function Shift:OnLeave(name: string, fn: () -> ())
|
|
108
|
+
self._leaves[name] = fn
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
function Shift:CanEnter(toName: string, visiting: { [string]: boolean }?): boolean
|
|
112
|
+
if not self.Alive then
|
|
113
|
+
return false
|
|
114
|
+
end
|
|
115
|
+
if self.Ids[toName] == nil then
|
|
116
|
+
return false
|
|
117
|
+
end
|
|
118
|
+
local fromName = self.Names[self.State]
|
|
119
|
+
if fromName == toName then
|
|
120
|
+
return false
|
|
121
|
+
end
|
|
122
|
+
local explicit = edgeAllowed(self, fromName, toName)
|
|
123
|
+
if explicit ~= nil then
|
|
124
|
+
return explicit
|
|
125
|
+
end
|
|
126
|
+
local parent = self.Parents[toName]
|
|
127
|
+
if parent == nil then
|
|
128
|
+
return false
|
|
129
|
+
end
|
|
130
|
+
if inBranch(self, parent) then
|
|
131
|
+
return true
|
|
132
|
+
end
|
|
133
|
+
local seen = visiting or {}
|
|
134
|
+
if seen[toName] then
|
|
135
|
+
return false
|
|
136
|
+
end
|
|
137
|
+
seen[toName] = true
|
|
138
|
+
return self:CanEnter(parent, seen)
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
local function switchTo(self: ShiftMachine, name: string, id: number)
|
|
142
|
+
local fromName = self.Names[self.State]
|
|
143
|
+
local leaveChain = ancestorChain(self, fromName)
|
|
144
|
+
local enterChain = ancestorChain(self, name)
|
|
145
|
+
local common = 0
|
|
146
|
+
local limit = math.min(#leaveChain, #enterChain)
|
|
147
|
+
for index = 1, limit do
|
|
148
|
+
if leaveChain[index] == enterChain[index] then
|
|
149
|
+
common = index
|
|
150
|
+
else
|
|
151
|
+
break
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
for index = #leaveChain, common + 1, -1 do
|
|
155
|
+
local fn = self._leaves[leaveChain[index]]
|
|
156
|
+
if fn then
|
|
157
|
+
fn()
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
self.Previous = self.State
|
|
161
|
+
self.State = id
|
|
162
|
+
table.insert(self.History, id)
|
|
163
|
+
for index = common + 1, #enterChain do
|
|
164
|
+
local fn = self._enters[enterChain[index]]
|
|
165
|
+
if fn then
|
|
166
|
+
fn()
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
function Shift:ChangeState(name: string)
|
|
172
|
+
if not self.Alive then
|
|
173
|
+
return
|
|
174
|
+
end
|
|
175
|
+
local id = self.Ids[name]
|
|
176
|
+
if id == nil then
|
|
177
|
+
return
|
|
178
|
+
end
|
|
179
|
+
if self.State == id then
|
|
180
|
+
return
|
|
181
|
+
end
|
|
182
|
+
if not self:CanEnter(name) then
|
|
183
|
+
return
|
|
184
|
+
end
|
|
185
|
+
switchTo(self, name, id)
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
function Shift:GetState(): string
|
|
189
|
+
return self.Names[self.State] or ""
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
function Shift:GetCurrentState(): string
|
|
193
|
+
return self:GetState()
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
function Shift:GetPreviousState(): string
|
|
197
|
+
return self.Names[self.Previous] or ""
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
function Shift:GetId(): number
|
|
201
|
+
return self.State
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
function Shift:WriteId(): buffer
|
|
205
|
+
local buf = buffer.create(1)
|
|
206
|
+
buffer.writeu8(buf, 0, self.State)
|
|
207
|
+
return buf
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
function Shift:ReadId(buf: buffer)
|
|
211
|
+
if not self.Alive then
|
|
212
|
+
return
|
|
213
|
+
end
|
|
214
|
+
local id = buffer.readu8(buf, 0)
|
|
215
|
+
local name = self.Names[id]
|
|
216
|
+
if name == nil or self.State == id then
|
|
217
|
+
return
|
|
218
|
+
end
|
|
219
|
+
switchTo(self, name, id)
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
function Shift:GetData()
|
|
223
|
+
return self.Data
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
function Shift:ChangeData(index: string, value: any)
|
|
227
|
+
self.Data[index] = value
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
function Shift:Destroy()
|
|
231
|
+
self.Alive = false
|
|
232
|
+
table.clear(self.Data)
|
|
233
|
+
table.clear(self._guards)
|
|
234
|
+
table.clear(self._enters)
|
|
235
|
+
table.clear(self._leaves)
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
return Shift
|
|
@@ -0,0 +1,487 @@
|
|
|
1
|
+
--!native
|
|
2
|
+
--!optimize 2
|
|
3
|
+
--!strict
|
|
4
|
+
-- Spark — engine-grade yield-safe signal.
|
|
5
|
+
-- Intrusive doubly-linked list (O(1) Disconnect, Fire-safe unhook).
|
|
6
|
+
-- Pooled runner threads (GoodSignal). Reentrant Fire is queued, not stacked.
|
|
7
|
+
-- Destroy seals the signal. ConnectParallel never reuses the serial runner.
|
|
8
|
+
|
|
9
|
+
export type SparkConnection = {
|
|
10
|
+
Connected: boolean,
|
|
11
|
+
Disconnect: (self: SparkConnection) -> (),
|
|
12
|
+
Destroy: (self: SparkConnection) -> (),
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export type Connection = SparkConnection
|
|
16
|
+
|
|
17
|
+
export type Spark<T...> = {
|
|
18
|
+
Fire: (self: Spark<T...>, T...) -> (),
|
|
19
|
+
FireDeferred: (self: Spark<T...>, T...) -> (),
|
|
20
|
+
Connect: (self: Spark<T...>, fn: (T...) -> ()) -> SparkConnection,
|
|
21
|
+
ConnectParallel: (self: Spark<T...>, fn: (T...) -> ()) -> SparkConnection,
|
|
22
|
+
Once: (self: Spark<T...>, fn: (T...) -> ()) -> SparkConnection,
|
|
23
|
+
OnceParallel: (self: Spark<T...>, fn: (T...) -> ()) -> SparkConnection,
|
|
24
|
+
ConnectOnce: (self: Spark<T...>, fn: (T...) -> ()) -> SparkConnection,
|
|
25
|
+
DisconnectAll: (self: Spark<T...>) -> (),
|
|
26
|
+
GetConnections: (self: Spark<T...>) -> { SparkConnection },
|
|
27
|
+
Destroy: (self: Spark<T...>) -> (),
|
|
28
|
+
IsDestroyed: (self: Spark<T...>) -> boolean,
|
|
29
|
+
Wait: (self: Spark<T...>) -> T...,
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
type Handler = (...any) -> ()
|
|
33
|
+
type Packed = { n: number, [number]: any }
|
|
34
|
+
|
|
35
|
+
type ConnectionNode = {
|
|
36
|
+
Connected: boolean,
|
|
37
|
+
_signal: SparkImpl?,
|
|
38
|
+
_fn: Handler?,
|
|
39
|
+
_next: ConnectionNode?,
|
|
40
|
+
_prev: ConnectionNode?,
|
|
41
|
+
_once: boolean,
|
|
42
|
+
_parallel: boolean,
|
|
43
|
+
Disconnect: (self: ConnectionNode) -> (),
|
|
44
|
+
Destroy: (self: ConnectionNode) -> (),
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
type SparkImpl = {
|
|
48
|
+
_head: ConnectionNode?,
|
|
49
|
+
_tail: ConnectionNode?,
|
|
50
|
+
_count: number,
|
|
51
|
+
_destroyed: boolean,
|
|
52
|
+
_firing: boolean,
|
|
53
|
+
_queue: { Packed },
|
|
54
|
+
_queueN: number,
|
|
55
|
+
_proxyHandler: RBXScriptConnection?,
|
|
56
|
+
_yieldedThreads: { [thread]: boolean }?,
|
|
57
|
+
Fire: (self: SparkImpl, ...any) -> (),
|
|
58
|
+
FireDeferred: (self: SparkImpl, ...any) -> (),
|
|
59
|
+
Connect: (self: SparkImpl, fn: Handler) -> ConnectionNode,
|
|
60
|
+
ConnectParallel: (self: SparkImpl, fn: Handler) -> ConnectionNode,
|
|
61
|
+
Once: (self: SparkImpl, fn: Handler) -> ConnectionNode,
|
|
62
|
+
OnceParallel: (self: SparkImpl, fn: Handler) -> ConnectionNode,
|
|
63
|
+
ConnectOnce: (self: SparkImpl, fn: Handler) -> ConnectionNode,
|
|
64
|
+
DisconnectAll: (self: SparkImpl) -> (),
|
|
65
|
+
GetConnections: (self: SparkImpl) -> { SparkConnection },
|
|
66
|
+
Destroy: (self: SparkImpl) -> (),
|
|
67
|
+
IsDestroyed: (self: SparkImpl) -> boolean,
|
|
68
|
+
Wait: (self: SparkImpl) -> ...any,
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
local MAX_CONNECTIONS = 4096
|
|
72
|
+
local MAX_REENTRY = 64
|
|
73
|
+
local PACK_POOL_CAP = 16
|
|
74
|
+
local SNAP_POOL_CAP = 8
|
|
75
|
+
|
|
76
|
+
local freeRunnerThread: thread? = nil
|
|
77
|
+
local packPool: { Packed } = {}
|
|
78
|
+
local packPoolN = 0
|
|
79
|
+
local snapPool: { { ConnectionNode } } = {}
|
|
80
|
+
local snapPoolN = 0
|
|
81
|
+
|
|
82
|
+
local function acquirePack(...: any): Packed
|
|
83
|
+
local packed: Packed
|
|
84
|
+
if packPoolN > 0 then
|
|
85
|
+
packed = packPool[packPoolN]
|
|
86
|
+
packPool[packPoolN] = nil
|
|
87
|
+
packPoolN -= 1
|
|
88
|
+
else
|
|
89
|
+
packed = table.pack(...)
|
|
90
|
+
return packed
|
|
91
|
+
end
|
|
92
|
+
local n = select("#", ...)
|
|
93
|
+
packed.n = n
|
|
94
|
+
for i = 1, n do
|
|
95
|
+
packed[i] = select(i, ...)
|
|
96
|
+
end
|
|
97
|
+
return packed
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
local function releasePack(packed: Packed)
|
|
101
|
+
for i = 1, packed.n do
|
|
102
|
+
packed[i] = nil
|
|
103
|
+
end
|
|
104
|
+
packed.n = 0
|
|
105
|
+
if packPoolN < PACK_POOL_CAP then
|
|
106
|
+
packPoolN += 1
|
|
107
|
+
packPool[packPoolN] = packed
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
local function acquireSnap(): { ConnectionNode }
|
|
112
|
+
if snapPoolN > 0 then
|
|
113
|
+
local snap = snapPool[snapPoolN]
|
|
114
|
+
snapPool[snapPoolN] = nil
|
|
115
|
+
snapPoolN -= 1
|
|
116
|
+
return snap
|
|
117
|
+
end
|
|
118
|
+
return {}
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
local function releaseSnap(snap: { ConnectionNode }, n: number)
|
|
122
|
+
for i = 1, n do
|
|
123
|
+
snap[i] = nil
|
|
124
|
+
end
|
|
125
|
+
if snapPoolN < SNAP_POOL_CAP then
|
|
126
|
+
snapPoolN += 1
|
|
127
|
+
snapPool[snapPoolN] = snap
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
local function acquireRunnerThreadAndCallEventHandler(fn: Handler, ...: any)
|
|
132
|
+
local acquired = freeRunnerThread
|
|
133
|
+
freeRunnerThread = nil
|
|
134
|
+
fn(...)
|
|
135
|
+
freeRunnerThread = acquired
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
local function runEventHandlerInFreeThread(...: any)
|
|
139
|
+
acquireRunnerThreadAndCallEventHandler(...)
|
|
140
|
+
while true do
|
|
141
|
+
acquireRunnerThreadAndCallEventHandler(coroutine.yield())
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
local function runParallelHandler(fn: Handler, ...: any)
|
|
146
|
+
local desynced = pcall(task.desynchronize)
|
|
147
|
+
fn(...)
|
|
148
|
+
if desynced then
|
|
149
|
+
pcall(task.synchronize)
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
local function expectFunction(method: string, fn: Handler)
|
|
154
|
+
if type(fn) ~= "function" then
|
|
155
|
+
error(`Spark.{method} expected function, got {typeof(fn)}`, 4)
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
local Connection = {}
|
|
160
|
+
Connection.__index = Connection
|
|
161
|
+
|
|
162
|
+
local function unlink(node: ConnectionNode)
|
|
163
|
+
local signal = node._signal
|
|
164
|
+
if not signal then
|
|
165
|
+
return
|
|
166
|
+
end
|
|
167
|
+
local prev = node._prev
|
|
168
|
+
local next = node._next
|
|
169
|
+
if prev then
|
|
170
|
+
prev._next = next
|
|
171
|
+
elseif signal._head == node then
|
|
172
|
+
signal._head = next
|
|
173
|
+
end
|
|
174
|
+
if next then
|
|
175
|
+
next._prev = prev
|
|
176
|
+
elseif signal._tail == node then
|
|
177
|
+
signal._tail = prev
|
|
178
|
+
end
|
|
179
|
+
node._prev = nil
|
|
180
|
+
-- Keep _next so an in-flight Fire iterator can continue.
|
|
181
|
+
if node.Connected then
|
|
182
|
+
signal._count -= 1
|
|
183
|
+
if signal._count < 0 then
|
|
184
|
+
signal._count = 0
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
local function clearNode(node: ConnectionNode)
|
|
190
|
+
node._fn = nil
|
|
191
|
+
node._signal = nil
|
|
192
|
+
node._once = false
|
|
193
|
+
node._parallel = false
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
function Connection.Disconnect(self: ConnectionNode)
|
|
197
|
+
if not self.Connected then
|
|
198
|
+
return
|
|
199
|
+
end
|
|
200
|
+
unlink(self)
|
|
201
|
+
self.Connected = false
|
|
202
|
+
clearNode(self)
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
Connection.Destroy = Connection.Disconnect
|
|
206
|
+
|
|
207
|
+
local function deadConnection(): ConnectionNode
|
|
208
|
+
return setmetatable({
|
|
209
|
+
Connected = false,
|
|
210
|
+
_signal = nil,
|
|
211
|
+
_fn = nil,
|
|
212
|
+
_next = nil,
|
|
213
|
+
_prev = nil,
|
|
214
|
+
_once = false,
|
|
215
|
+
_parallel = false,
|
|
216
|
+
}, Connection) :: any
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
local Spark = {}
|
|
220
|
+
Spark.__index = Spark
|
|
221
|
+
|
|
222
|
+
local function invoke(conn: ConnectionNode, ...: any)
|
|
223
|
+
local fn = conn._fn
|
|
224
|
+
if not fn then
|
|
225
|
+
return
|
|
226
|
+
end
|
|
227
|
+
local parallel = conn._parallel
|
|
228
|
+
if conn._once then
|
|
229
|
+
conn:Disconnect()
|
|
230
|
+
end
|
|
231
|
+
if parallel then
|
|
232
|
+
task.spawn(runParallelHandler, fn, ...)
|
|
233
|
+
return
|
|
234
|
+
end
|
|
235
|
+
if not freeRunnerThread then
|
|
236
|
+
freeRunnerThread = coroutine.create(runEventHandlerInFreeThread)
|
|
237
|
+
end
|
|
238
|
+
task.spawn(freeRunnerThread :: thread, fn, ...)
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
local function dispatchList(self: SparkImpl, ...: any)
|
|
242
|
+
local item = self._head
|
|
243
|
+
while item do
|
|
244
|
+
if item.Connected then
|
|
245
|
+
invoke(item, ...)
|
|
246
|
+
end
|
|
247
|
+
item = item._next
|
|
248
|
+
end
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
local function bind(self: SparkImpl, fn: Handler, once: boolean, parallel: boolean): ConnectionNode
|
|
252
|
+
if self._destroyed then
|
|
253
|
+
return deadConnection()
|
|
254
|
+
end
|
|
255
|
+
expectFunction(if parallel then "ConnectParallel" else "Connect", fn)
|
|
256
|
+
if self._count >= MAX_CONNECTIONS then
|
|
257
|
+
warn(`Spark: connection cap ({MAX_CONNECTIONS}) reached; refusing Connect`)
|
|
258
|
+
return deadConnection()
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
local node = setmetatable({
|
|
262
|
+
Connected = true,
|
|
263
|
+
_signal = self,
|
|
264
|
+
_fn = fn,
|
|
265
|
+
_next = self._head,
|
|
266
|
+
_prev = nil,
|
|
267
|
+
_once = once,
|
|
268
|
+
_parallel = parallel,
|
|
269
|
+
}, Connection) :: ConnectionNode
|
|
270
|
+
|
|
271
|
+
if self._head then
|
|
272
|
+
self._head._prev = node
|
|
273
|
+
else
|
|
274
|
+
self._tail = node
|
|
275
|
+
end
|
|
276
|
+
self._head = node
|
|
277
|
+
self._count += 1
|
|
278
|
+
return node
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
function Spark.new<T...>(): Spark<T...>
|
|
282
|
+
return setmetatable({
|
|
283
|
+
_head = nil,
|
|
284
|
+
_tail = nil,
|
|
285
|
+
_count = 0,
|
|
286
|
+
_destroyed = false,
|
|
287
|
+
_firing = false,
|
|
288
|
+
_queue = {},
|
|
289
|
+
_queueN = 0,
|
|
290
|
+
_proxyHandler = nil,
|
|
291
|
+
_yieldedThreads = nil,
|
|
292
|
+
}, Spark) :: any
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
Spark.New = Spark.new
|
|
296
|
+
|
|
297
|
+
function Spark.Wrap<T...>(rbxScriptSignal: RBXScriptSignal): Spark<T...>
|
|
298
|
+
if typeof(rbxScriptSignal) ~= "RBXScriptSignal" then
|
|
299
|
+
error("Spark.Wrap expected RBXScriptSignal, got " .. typeof(rbxScriptSignal), 2)
|
|
300
|
+
end
|
|
301
|
+
local spark = Spark.new() :: SparkImpl
|
|
302
|
+
spark._proxyHandler = rbxScriptSignal:Connect(function(...: any)
|
|
303
|
+
if not spark._destroyed then
|
|
304
|
+
spark:Fire(...)
|
|
305
|
+
end
|
|
306
|
+
end)
|
|
307
|
+
return spark :: any
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
function Spark.Is(obj: any): boolean
|
|
311
|
+
return type(obj) == "table" and getmetatable(obj) == Spark
|
|
312
|
+
end
|
|
313
|
+
|
|
314
|
+
function Spark.Connect(self: SparkImpl, fn: Handler): ConnectionNode
|
|
315
|
+
return bind(self, fn, false, false)
|
|
316
|
+
end
|
|
317
|
+
|
|
318
|
+
function Spark.ConnectParallel(self: SparkImpl, fn: Handler): ConnectionNode
|
|
319
|
+
return bind(self, fn, false, true)
|
|
320
|
+
end
|
|
321
|
+
|
|
322
|
+
function Spark.Once(self: SparkImpl, fn: Handler): ConnectionNode
|
|
323
|
+
return bind(self, fn, true, false)
|
|
324
|
+
end
|
|
325
|
+
|
|
326
|
+
function Spark.OnceParallel(self: SparkImpl, fn: Handler): ConnectionNode
|
|
327
|
+
return bind(self, fn, true, true)
|
|
328
|
+
end
|
|
329
|
+
|
|
330
|
+
function Spark.ConnectOnce(self: SparkImpl, fn: Handler): ConnectionNode
|
|
331
|
+
return bind(self, fn, true, false)
|
|
332
|
+
end
|
|
333
|
+
|
|
334
|
+
function Spark.GetConnections(self: SparkImpl): { SparkConnection }
|
|
335
|
+
local items = table.create(self._count)
|
|
336
|
+
local i = 0
|
|
337
|
+
local item = self._head
|
|
338
|
+
while item do
|
|
339
|
+
if item.Connected then
|
|
340
|
+
i += 1
|
|
341
|
+
items[i] = item
|
|
342
|
+
end
|
|
343
|
+
item = item._next
|
|
344
|
+
end
|
|
345
|
+
return items
|
|
346
|
+
end
|
|
347
|
+
|
|
348
|
+
function Spark.IsDestroyed(self: SparkImpl): boolean
|
|
349
|
+
return self._destroyed
|
|
350
|
+
end
|
|
351
|
+
|
|
352
|
+
function Spark.DisconnectAll(self: SparkImpl)
|
|
353
|
+
if not self then
|
|
354
|
+
return
|
|
355
|
+
end
|
|
356
|
+
local item = self._head
|
|
357
|
+
self._head = nil
|
|
358
|
+
self._tail = nil
|
|
359
|
+
self._count = 0
|
|
360
|
+
while item do
|
|
361
|
+
local next = item._next
|
|
362
|
+
item.Connected = false
|
|
363
|
+
clearNode(item)
|
|
364
|
+
item = next
|
|
365
|
+
end
|
|
366
|
+
|
|
367
|
+
local yielded = self._yieldedThreads
|
|
368
|
+
if not yielded then
|
|
369
|
+
return
|
|
370
|
+
end
|
|
371
|
+
for thread in yielded do
|
|
372
|
+
if coroutine.status(thread) == "suspended" then
|
|
373
|
+
warn(debug.traceback(thread, "spark disconnected; yielded thread cancelled", 2))
|
|
374
|
+
task.cancel(thread)
|
|
375
|
+
end
|
|
376
|
+
end
|
|
377
|
+
table.clear(yielded)
|
|
378
|
+
end
|
|
379
|
+
|
|
380
|
+
function Spark.Fire(self: SparkImpl, ...: any)
|
|
381
|
+
if self._destroyed or self._count == 0 then
|
|
382
|
+
return
|
|
383
|
+
end
|
|
384
|
+
if self._firing then
|
|
385
|
+
if self._queueN >= MAX_REENTRY then
|
|
386
|
+
warn("Spark: reentrant Fire dropped (queue full)")
|
|
387
|
+
return
|
|
388
|
+
end
|
|
389
|
+
self._queueN += 1
|
|
390
|
+
self._queue[self._queueN] = acquirePack(...)
|
|
391
|
+
return
|
|
392
|
+
end
|
|
393
|
+
|
|
394
|
+
self._firing = true
|
|
395
|
+
dispatchList(self, ...)
|
|
396
|
+
local i = 1
|
|
397
|
+
while i <= self._queueN do
|
|
398
|
+
local packed = self._queue[i]
|
|
399
|
+
self._queue[i] = nil
|
|
400
|
+
dispatchList(self, table.unpack(packed, 1, packed.n))
|
|
401
|
+
releasePack(packed)
|
|
402
|
+
i += 1
|
|
403
|
+
end
|
|
404
|
+
self._queueN = 0
|
|
405
|
+
self._firing = false
|
|
406
|
+
end
|
|
407
|
+
|
|
408
|
+
local function deferredFlush(snap: { ConnectionNode }, n: number, packed: Packed)
|
|
409
|
+
for i = 1, n do
|
|
410
|
+
local conn = snap[i]
|
|
411
|
+
if conn and conn.Connected then
|
|
412
|
+
invoke(conn, table.unpack(packed, 1, packed.n))
|
|
413
|
+
end
|
|
414
|
+
end
|
|
415
|
+
releaseSnap(snap, n)
|
|
416
|
+
releasePack(packed)
|
|
417
|
+
end
|
|
418
|
+
|
|
419
|
+
function Spark.FireDeferred(self: SparkImpl, ...: any)
|
|
420
|
+
if self._destroyed or self._count == 0 then
|
|
421
|
+
return
|
|
422
|
+
end
|
|
423
|
+
local snap = acquireSnap()
|
|
424
|
+
local n = 0
|
|
425
|
+
local item = self._head
|
|
426
|
+
while item do
|
|
427
|
+
if item.Connected then
|
|
428
|
+
n += 1
|
|
429
|
+
snap[n] = item
|
|
430
|
+
end
|
|
431
|
+
item = item._next
|
|
432
|
+
end
|
|
433
|
+
if n == 0 then
|
|
434
|
+
releaseSnap(snap, 0)
|
|
435
|
+
return
|
|
436
|
+
end
|
|
437
|
+
task.defer(deferredFlush, snap, n, acquirePack(...))
|
|
438
|
+
end
|
|
439
|
+
|
|
440
|
+
function Spark.Wait(self: SparkImpl): ...any
|
|
441
|
+
if self._destroyed then
|
|
442
|
+
error("Spark.Wait on destroyed signal", 2)
|
|
443
|
+
end
|
|
444
|
+
|
|
445
|
+
local yielded = self._yieldedThreads
|
|
446
|
+
if not yielded then
|
|
447
|
+
yielded = {}
|
|
448
|
+
self._yieldedThreads = yielded
|
|
449
|
+
end
|
|
450
|
+
|
|
451
|
+
local thread = coroutine.running()
|
|
452
|
+
yielded[thread] = true
|
|
453
|
+
local pending: Packed? = nil
|
|
454
|
+
|
|
455
|
+
self:Once(function(...: any)
|
|
456
|
+
yielded[thread] = nil
|
|
457
|
+
if coroutine.status(thread) == "suspended" then
|
|
458
|
+
task.spawn(thread, ...)
|
|
459
|
+
else
|
|
460
|
+
pending = table.pack(...)
|
|
461
|
+
end
|
|
462
|
+
end)
|
|
463
|
+
|
|
464
|
+
if pending then
|
|
465
|
+
return table.unpack(pending, 1, pending.n)
|
|
466
|
+
end
|
|
467
|
+
return coroutine.yield()
|
|
468
|
+
end
|
|
469
|
+
|
|
470
|
+
function Spark.Destroy(self: SparkImpl)
|
|
471
|
+
if self._destroyed then
|
|
472
|
+
return
|
|
473
|
+
end
|
|
474
|
+
self._destroyed = true
|
|
475
|
+
self:DisconnectAll()
|
|
476
|
+
local proxy = self._proxyHandler
|
|
477
|
+
if proxy then
|
|
478
|
+
proxy:Disconnect()
|
|
479
|
+
self._proxyHandler = nil
|
|
480
|
+
end
|
|
481
|
+
table.clear(self._queue)
|
|
482
|
+
self._queueN = 0
|
|
483
|
+
end
|
|
484
|
+
|
|
485
|
+
Spark.Connection = Connection
|
|
486
|
+
|
|
487
|
+
return Spark
|