@flamework-experimental/core 2.0.0-alpha.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 +66 -0
- package/flamework.build +17 -0
- package/out/dependency.d.ts +18 -0
- package/out/dependency.luau +32 -0
- package/out/flamework.d.ts +78 -0
- package/out/flamework.luau +138 -0
- package/out/index.d.ts +28 -0
- package/out/init.luau +40 -0
- package/out/injectable.d.ts +13 -0
- package/out/injectable.luau +23 -0
- package/out/lifecycle/lifecycleInterfaces.d.ts +94 -0
- package/out/lifecycle/lifecycleInterfaces.luau +55 -0
- package/out/lifecycle/lifecyclePlugin.d.ts +85 -0
- package/out/lifecycle/lifecyclePlugin.luau +424 -0
- package/out/modding.d.ts +171 -0
- package/out/modding.luau +66 -0
- package/out/module/defaultModule.d.ts +5 -0
- package/out/module/defaultModule.luau +28 -0
- package/out/module/module.d.ts +78 -0
- package/out/module/module.luau +811 -0
- package/out/module/moduleBuilder.d.ts +88 -0
- package/out/module/moduleBuilder.luau +169 -0
- package/out/module/moduleDefinition.d.ts +105 -0
- package/out/module/moduleDefinition.luau +79 -0
- package/out/module/moduleHooks.d.ts +23 -0
- package/out/module/moduleHooks.luau +19 -0
- package/out/module/providerRegistration.d.ts +22 -0
- package/out/module/providerRegistration.luau +80 -0
- package/out/module/scopes.d.ts +40 -0
- package/out/module/scopes.luau +159 -0
- package/out/plugin/pluginDefinition.d.ts +128 -0
- package/out/plugin/pluginDefinition.luau +61 -0
- package/out/prelude.d.ts +8 -0
- package/out/prelude.luau +14 -0
- package/out/provider.d.ts +27 -0
- package/out/provider.luau +26 -0
- package/out/reflect.d.ts +60 -0
- package/out/reflect.luau +310 -0
- package/out/serialization/types.d.ts +86 -0
- package/out/serialization/types.luau +9 -0
- package/out/utility/constructors.d.ts +4 -0
- package/out/utility/constructors.luau +12 -0
- package/out/utility/convertConciseDependencyInfo.d.ts +5 -0
- package/out/utility/convertConciseDependencyInfo.luau +29 -0
- package/out/utility/getClassImplements.d.ts +7 -0
- package/out/utility/getClassImplements.luau +27 -0
- package/out/utility/getClassesInPath.d.ts +23 -0
- package/out/utility/getClassesInPath.luau +91 -0
- package/out/utility/globs.d.ts +9 -0
- package/out/utility/globs.luau +64 -0
- package/out/utility/metadata.d.ts +12 -0
- package/out/utility/metadata.luau +43 -0
- package/out/utility/pathRoot.d.ts +17 -0
- package/out/utility/pathRoot.luau +105 -0
- package/out/utility/recycleThread.d.ts +1 -0
- package/out/utility/recycleThread.luau +31 -0
- package/out/utility/runtimeConfig.d.ts +59 -0
- package/out/utility/runtimeConfig.luau +25 -0
- package/out/utility/tsImport.d.ts +6 -0
- package/out/utility/tsImport.luau +15 -0
- package/out/utility/types.d.ts +16 -0
- package/out/utility/types.luau +22 -0
- package/out/utility/writable.d.ts +4 -0
- package/out/utility/writable.luau +2 -0
- package/package.json +33 -0
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import type { Module } from "../module/module";
|
|
2
|
+
import type { OnExtinguished, OnInit, OnPhysics, OnRender, OnStart, OnTick } from "./lifecycleInterfaces";
|
|
3
|
+
import { PluginDefinition, type InterfaceContext } from "../plugin/pluginDefinition";
|
|
4
|
+
export interface LifecyclePluginOptions {
|
|
5
|
+
/**
|
|
6
|
+
* Whether per-frame lifecycle callbacks are wrapped in `debug.profilebegin` and
|
|
7
|
+
* `debug.setmemorycategory` with the provider's identifier, so that they show up by name in the
|
|
8
|
+
* MicroProfiler and the memory view.
|
|
9
|
+
*
|
|
10
|
+
* Defaults to `RunService.IsStudio()`, which is what v1's `flamework.json` defaulted to as well.
|
|
11
|
+
*/
|
|
12
|
+
profiling?: boolean;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Tracks the objects attached to each lifecycle event for one module.
|
|
16
|
+
*
|
|
17
|
+
* The plugin builds one per ignition of every module that includes it, so nothing here is shared
|
|
18
|
+
* between modules, and provides it, so `module.resolveDependency<LifecycleProvider>()` answers what
|
|
19
|
+
* is attached to a module's events right now.
|
|
20
|
+
*/
|
|
21
|
+
export declare class LifecycleProvider {
|
|
22
|
+
/** In attachment order, which for providers is dependency order. */
|
|
23
|
+
private onInit;
|
|
24
|
+
private initMembers;
|
|
25
|
+
/** The providers `postIgnite` starts, in attachment order; `onStart` is every member. */
|
|
26
|
+
private startOrder;
|
|
27
|
+
onStart: Set<OnStart>;
|
|
28
|
+
onTick: Set<OnTick>;
|
|
29
|
+
onPhysics: Set<OnPhysics>;
|
|
30
|
+
onRender: Set<OnRender>;
|
|
31
|
+
onExtinguished: Set<OnExtinguished>;
|
|
32
|
+
private identifiers;
|
|
33
|
+
private moduleConnections;
|
|
34
|
+
private lateProviders;
|
|
35
|
+
private hasStarted;
|
|
36
|
+
private isProfiling;
|
|
37
|
+
constructor(options: LifecyclePluginOptions);
|
|
38
|
+
private getIdentifier;
|
|
39
|
+
/**
|
|
40
|
+
* Drops the memoised identifier of an object that has left its last lifecycle event.
|
|
41
|
+
*
|
|
42
|
+
* The memo is keyed by the object itself, so an entry left behind is a strong reference to it:
|
|
43
|
+
* a removed component, and with it its instance, its attributes and everything it links to,
|
|
44
|
+
* held for as long as the module lives. `profile` fills it in for every object it runs a
|
|
45
|
+
* per-frame callback for, so the table grew by one for every component that ever ticked
|
|
46
|
+
* whenever profiling was on -- which it is in Studio by default, and in production for anyone
|
|
47
|
+
* who sets `core.profiling`.
|
|
48
|
+
*
|
|
49
|
+
* The entry stays while any event still holds the object: dropping it there would only make the
|
|
50
|
+
* next frame look it up again.
|
|
51
|
+
*/
|
|
52
|
+
private forget;
|
|
53
|
+
private profile;
|
|
54
|
+
/**
|
|
55
|
+
* Runs `onInit` synchronously, waiting on a returned Promise, so that initialisation happens in
|
|
56
|
+
* dependency order and is complete before anything starts.
|
|
57
|
+
*/
|
|
58
|
+
private runInit;
|
|
59
|
+
private runStart;
|
|
60
|
+
/**
|
|
61
|
+
* A provider constructed after ignition (a lazy one) still gets `onInit` and `onStart`, in that
|
|
62
|
+
* order, once every one of its interfaces has been attached. Instances attached late through
|
|
63
|
+
* `listen` or `createClassInstance` do not; they are owned by whoever created them.
|
|
64
|
+
*/
|
|
65
|
+
private scheduleLateProvider;
|
|
66
|
+
addInit(object: OnInit, context: InterfaceContext): void;
|
|
67
|
+
removeInit(object: OnInit): void;
|
|
68
|
+
addStart(object: OnStart, context: InterfaceContext): void;
|
|
69
|
+
removeStart(object: OnStart): void;
|
|
70
|
+
postIgnite(module: Module): void;
|
|
71
|
+
extinguished(module: Module): void;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Creates a lifecycle plugin with the specified options.
|
|
75
|
+
*
|
|
76
|
+
* `LifecyclePlugin` is `createLifecyclePlugin()` with the defaults; use this when a module needs
|
|
77
|
+
* different ones, such as forcing profiling on or off.
|
|
78
|
+
*/
|
|
79
|
+
export declare function createLifecyclePlugin(options?: LifecyclePluginOptions): PluginDefinition;
|
|
80
|
+
/**
|
|
81
|
+
* The lifecycle plugin with default options. Every module made with `Flamework.createModule()`
|
|
82
|
+
* starts with it; `disableDefaultLifecycle()` on the builder leaves it out, and including one built
|
|
83
|
+
* with {@link createLifecyclePlugin} takes its place.
|
|
84
|
+
*/
|
|
85
|
+
export declare const LifecyclePlugin: PluginDefinition;
|
|
@@ -0,0 +1,424 @@
|
|
|
1
|
+
-- Compiled with roblox-ts v3.0.0
|
|
2
|
+
local TS = _G[script]
|
|
3
|
+
local Reflect_1 = TS.import(script, script.Parent.Parent, "reflect").Reflect
|
|
4
|
+
local RunService = TS.import(script, TS.getModule(script, "@rbxts", "services")).RunService
|
|
5
|
+
local getRuntimeConfig = TS.import(script, script.Parent.Parent, "utility", "runtimeConfig").getRuntimeConfig
|
|
6
|
+
local Provider = TS.import(script, script.Parent.Parent, "provider").Provider
|
|
7
|
+
local recycleThread = TS.import(script, script.Parent.Parent, "utility", "recycleThread").recycleThread
|
|
8
|
+
local Reflect = TS.import(script, script.Parent.Parent, "reflect").Reflect
|
|
9
|
+
local _pluginDefinition = TS.import(script, script.Parent.Parent, "plugin", "pluginDefinition")
|
|
10
|
+
local LIFECYCLE_SLOT = _pluginDefinition.LIFECYCLE_SLOT
|
|
11
|
+
local PluginDefinition = _pluginDefinition.PluginDefinition
|
|
12
|
+
--[[
|
|
13
|
+
*
|
|
14
|
+
* Tracks the objects attached to each lifecycle event for one module.
|
|
15
|
+
*
|
|
16
|
+
* The plugin builds one per ignition of every module that includes it, so nothing here is shared
|
|
17
|
+
* between modules, and provides it, so `module.resolveDependency<LifecycleProvider>()` answers what
|
|
18
|
+
* is attached to a module's events right now.
|
|
19
|
+
|
|
20
|
+
]]
|
|
21
|
+
local LifecycleProvider
|
|
22
|
+
do
|
|
23
|
+
LifecycleProvider = setmetatable({}, {
|
|
24
|
+
__tostring = function()
|
|
25
|
+
return "LifecycleProvider"
|
|
26
|
+
end,
|
|
27
|
+
})
|
|
28
|
+
LifecycleProvider.__index = LifecycleProvider
|
|
29
|
+
function LifecycleProvider.new(...)
|
|
30
|
+
local self = setmetatable({}, LifecycleProvider)
|
|
31
|
+
return self:constructor(...) or self
|
|
32
|
+
end
|
|
33
|
+
function LifecycleProvider:constructor(options)
|
|
34
|
+
self.onInit = {}
|
|
35
|
+
self.initMembers = {}
|
|
36
|
+
self.startOrder = {}
|
|
37
|
+
self.onStart = {}
|
|
38
|
+
self.onTick = {}
|
|
39
|
+
self.onPhysics = {}
|
|
40
|
+
self.onRender = {}
|
|
41
|
+
self.onExtinguished = {}
|
|
42
|
+
self.identifiers = {}
|
|
43
|
+
self.moduleConnections = {}
|
|
44
|
+
self.lateProviders = {}
|
|
45
|
+
self.hasStarted = false
|
|
46
|
+
-- Per-module option, then the project's flamework.config.json, then Studio.
|
|
47
|
+
local _condition = options.profiling
|
|
48
|
+
if _condition == nil then
|
|
49
|
+
local _result = getRuntimeConfig().core
|
|
50
|
+
if _result ~= nil then
|
|
51
|
+
_result = _result.profiling
|
|
52
|
+
end
|
|
53
|
+
_condition = _result
|
|
54
|
+
if _condition == nil then
|
|
55
|
+
_condition = RunService:IsStudio()
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
self.isProfiling = _condition
|
|
59
|
+
end
|
|
60
|
+
function LifecycleProvider:getIdentifier(object)
|
|
61
|
+
local _identifiers = self.identifiers
|
|
62
|
+
local _object = object
|
|
63
|
+
local identifier = _identifiers[_object]
|
|
64
|
+
if identifier == nil then
|
|
65
|
+
local _condition = Reflect.getMetadata(object, "identifier")
|
|
66
|
+
if _condition == nil then
|
|
67
|
+
_condition = "[flamework listener]"
|
|
68
|
+
end
|
|
69
|
+
identifier = _condition
|
|
70
|
+
local _identifiers_1 = self.identifiers
|
|
71
|
+
local _object_1 = object
|
|
72
|
+
local _identifier = identifier
|
|
73
|
+
_identifiers_1[_object_1] = _identifier
|
|
74
|
+
end
|
|
75
|
+
return identifier
|
|
76
|
+
end
|
|
77
|
+
function LifecycleProvider:forget(object)
|
|
78
|
+
local _initMembers = self.initMembers
|
|
79
|
+
local _object = object
|
|
80
|
+
local _condition = _initMembers[_object] ~= nil
|
|
81
|
+
if not _condition then
|
|
82
|
+
local _onStart = self.onStart
|
|
83
|
+
local _object_1 = object
|
|
84
|
+
_condition = _onStart[_object_1] ~= nil
|
|
85
|
+
if not _condition then
|
|
86
|
+
local _onTick = self.onTick
|
|
87
|
+
local _object_2 = object
|
|
88
|
+
_condition = _onTick[_object_2] ~= nil
|
|
89
|
+
if not _condition then
|
|
90
|
+
local _onPhysics = self.onPhysics
|
|
91
|
+
local _object_3 = object
|
|
92
|
+
_condition = _onPhysics[_object_3] ~= nil
|
|
93
|
+
if not _condition then
|
|
94
|
+
local _onRender = self.onRender
|
|
95
|
+
local _object_4 = object
|
|
96
|
+
_condition = _onRender[_object_4] ~= nil
|
|
97
|
+
if not _condition then
|
|
98
|
+
local _onExtinguished = self.onExtinguished
|
|
99
|
+
local _object_5 = object
|
|
100
|
+
_condition = _onExtinguished[_object_5] ~= nil
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
local attached = _condition
|
|
107
|
+
if not attached then
|
|
108
|
+
local _identifiers = self.identifiers
|
|
109
|
+
local _object_1 = object
|
|
110
|
+
_identifiers[_object_1] = nil
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
function LifecycleProvider:removeFrom(set, value)
|
|
114
|
+
local _set = set
|
|
115
|
+
local _value = value
|
|
116
|
+
_set[_value] = nil
|
|
117
|
+
self:forget(value)
|
|
118
|
+
end
|
|
119
|
+
function LifecycleProvider:profile(callback, object)
|
|
120
|
+
if self.isProfiling then
|
|
121
|
+
local id = self:getIdentifier(object)
|
|
122
|
+
return recycleThread(function()
|
|
123
|
+
-- `profilebegin` ends when the thread yields or dies.
|
|
124
|
+
debug.profilebegin(id)
|
|
125
|
+
debug.setmemorycategory(id)
|
|
126
|
+
callback()
|
|
127
|
+
debug.resetmemorycategory()
|
|
128
|
+
end)
|
|
129
|
+
end
|
|
130
|
+
return recycleThread(callback)
|
|
131
|
+
end
|
|
132
|
+
function LifecycleProvider:runInit(object)
|
|
133
|
+
local id = self:getIdentifier(object)
|
|
134
|
+
if self.isProfiling then
|
|
135
|
+
debug.setmemorycategory(id)
|
|
136
|
+
end
|
|
137
|
+
local result = object:onInit()
|
|
138
|
+
if TS.Promise.is(result) then
|
|
139
|
+
local status, value = result:awaitStatus()
|
|
140
|
+
if status == TS.Promise.Status.Rejected then
|
|
141
|
+
error(`onInit failed for '{id}': {tostring(value)}`, 0)
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
if self.isProfiling then
|
|
145
|
+
debug.resetmemorycategory()
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
function LifecycleProvider:runStart(object)
|
|
149
|
+
task.spawn(function()
|
|
150
|
+
return object:onStart()
|
|
151
|
+
end)
|
|
152
|
+
end
|
|
153
|
+
function LifecycleProvider:scheduleLateProvider(object)
|
|
154
|
+
local _lateProviders = self.lateProviders
|
|
155
|
+
local _object = object
|
|
156
|
+
if _lateProviders[_object] ~= nil then
|
|
157
|
+
return nil
|
|
158
|
+
end
|
|
159
|
+
local _lateProviders_1 = self.lateProviders
|
|
160
|
+
local _object_1 = object
|
|
161
|
+
_lateProviders_1[_object_1] = true
|
|
162
|
+
task.defer(function()
|
|
163
|
+
local _lateProviders_2 = self.lateProviders
|
|
164
|
+
local _object_2 = object
|
|
165
|
+
if not (_lateProviders_2[_object_2] ~= nil) then
|
|
166
|
+
return nil
|
|
167
|
+
end
|
|
168
|
+
local _lateProviders_3 = self.lateProviders
|
|
169
|
+
local _object_3 = object
|
|
170
|
+
_lateProviders_3[_object_3] = nil
|
|
171
|
+
local _initMembers = self.initMembers
|
|
172
|
+
local _object_4 = object
|
|
173
|
+
if _initMembers[_object_4] ~= nil then
|
|
174
|
+
self:runInit(object)
|
|
175
|
+
end
|
|
176
|
+
local _onStart = self.onStart
|
|
177
|
+
local _object_5 = object
|
|
178
|
+
if _onStart[_object_5] ~= nil then
|
|
179
|
+
self:runStart(object)
|
|
180
|
+
end
|
|
181
|
+
end)
|
|
182
|
+
end
|
|
183
|
+
function LifecycleProvider:addInit(object, context)
|
|
184
|
+
local _initMembers = self.initMembers
|
|
185
|
+
local _object = object
|
|
186
|
+
_initMembers[_object] = true
|
|
187
|
+
-- Only a provider is initialised by the plugin. An instance attached through `listen` or
|
|
188
|
+
-- `createClassInstance` is owned by whoever created it -- `Components` runs a component's
|
|
189
|
+
-- `onInit` itself, before the component can be seen -- so one built during ignition must not
|
|
190
|
+
-- be initialised a second time here.
|
|
191
|
+
if context.kind ~= "provider" then
|
|
192
|
+
return nil
|
|
193
|
+
end
|
|
194
|
+
if not self.hasStarted then
|
|
195
|
+
local _onInit = self.onInit
|
|
196
|
+
local _object_1 = object
|
|
197
|
+
table.insert(_onInit, _object_1)
|
|
198
|
+
else
|
|
199
|
+
self:scheduleLateProvider(object)
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
function LifecycleProvider:removeInit(object)
|
|
203
|
+
local _initMembers = self.initMembers
|
|
204
|
+
local _object = object
|
|
205
|
+
_initMembers[_object] = nil
|
|
206
|
+
local _lateProviders = self.lateProviders
|
|
207
|
+
local _object_1 = object
|
|
208
|
+
_lateProviders[_object_1] = nil
|
|
209
|
+
local _onInit = self.onInit
|
|
210
|
+
local _object_2 = object
|
|
211
|
+
local index = (table.find(_onInit, _object_2) or 0) - 1
|
|
212
|
+
if index ~= -1 then
|
|
213
|
+
table.remove(self.onInit, index + 1)
|
|
214
|
+
end
|
|
215
|
+
self:forget(object)
|
|
216
|
+
end
|
|
217
|
+
function LifecycleProvider:addStart(object, context)
|
|
218
|
+
local _onStart = self.onStart
|
|
219
|
+
local _object = object
|
|
220
|
+
_onStart[_object] = true
|
|
221
|
+
-- Only a provider is started by the plugin, as with `onInit`: an instance attached through
|
|
222
|
+
-- `listen` or `createClassInstance` is owned by whoever created it. `Components` starts a
|
|
223
|
+
-- component itself, once the component is attached and ignition has finished.
|
|
224
|
+
if context.kind ~= "provider" then
|
|
225
|
+
return nil
|
|
226
|
+
end
|
|
227
|
+
if not self.hasStarted then
|
|
228
|
+
local _startOrder = self.startOrder
|
|
229
|
+
local _object_1 = object
|
|
230
|
+
table.insert(_startOrder, _object_1)
|
|
231
|
+
else
|
|
232
|
+
self:scheduleLateProvider(object)
|
|
233
|
+
end
|
|
234
|
+
end
|
|
235
|
+
function LifecycleProvider:removeStart(object)
|
|
236
|
+
local _onStart = self.onStart
|
|
237
|
+
local _object = object
|
|
238
|
+
_onStart[_object] = nil
|
|
239
|
+
local _lateProviders = self.lateProviders
|
|
240
|
+
local _object_1 = object
|
|
241
|
+
_lateProviders[_object_1] = nil
|
|
242
|
+
local _startOrder = self.startOrder
|
|
243
|
+
local _object_2 = object
|
|
244
|
+
local index = (table.find(_startOrder, _object_2) or 0) - 1
|
|
245
|
+
if index ~= -1 then
|
|
246
|
+
table.remove(self.startOrder, index + 1)
|
|
247
|
+
end
|
|
248
|
+
self:forget(object)
|
|
249
|
+
end
|
|
250
|
+
function LifecycleProvider:postIgnite(module)
|
|
251
|
+
-- Walked live rather than over a copy: an `onInit` may resolve a lazy provider, which joins
|
|
252
|
+
-- the end of the list while we iterate and is initialised in its turn -- over a copy it was
|
|
253
|
+
-- skipped, and then started with the rest, never initialised. Nothing leaves the list
|
|
254
|
+
-- during ignition, so the index stays true. A `while`, since a `for` compiles to a numeric
|
|
255
|
+
-- loop that reads the length once.
|
|
256
|
+
local index = 0
|
|
257
|
+
while index < #self.onInit do
|
|
258
|
+
self:runInit(self.onInit[index + 1])
|
|
259
|
+
index += 1
|
|
260
|
+
end
|
|
261
|
+
self.hasStarted = true
|
|
262
|
+
local _array = {}
|
|
263
|
+
local _length = #_array
|
|
264
|
+
local _array_1 = self.startOrder
|
|
265
|
+
table.move(_array_1, 1, #_array_1, _length + 1, _array)
|
|
266
|
+
for _, object in _array do
|
|
267
|
+
self:runStart(object)
|
|
268
|
+
end
|
|
269
|
+
local onTick = self.onTick
|
|
270
|
+
local onPhysics = self.onPhysics
|
|
271
|
+
local onRender = self.onRender
|
|
272
|
+
local connections = {}
|
|
273
|
+
-- Heartbeat rather than PostSimulation: the same point of the frame in a running game, but
|
|
274
|
+
-- Heartbeat also fires where no simulation runs (an edit-mode plugin, an Open Cloud Luau
|
|
275
|
+
-- task), so onTick works there too. PreSimulation has no such alias; onPhysics stays silent.
|
|
276
|
+
local _arg0 = RunService.Heartbeat:Connect(function(dt)
|
|
277
|
+
for provider in onTick do
|
|
278
|
+
self:profile(function()
|
|
279
|
+
return provider:onTick(dt)
|
|
280
|
+
end, provider)
|
|
281
|
+
end
|
|
282
|
+
end)
|
|
283
|
+
table.insert(connections, _arg0)
|
|
284
|
+
local _arg0_1 = RunService.PreSimulation:Connect(function(dt)
|
|
285
|
+
local now = time()
|
|
286
|
+
for provider in onPhysics do
|
|
287
|
+
self:profile(function()
|
|
288
|
+
return provider:onPhysics(dt, now)
|
|
289
|
+
end, provider)
|
|
290
|
+
end
|
|
291
|
+
end)
|
|
292
|
+
table.insert(connections, _arg0_1)
|
|
293
|
+
-- PreRender never fires on the server, so there is nothing to connect there.
|
|
294
|
+
if RunService:IsClient() then
|
|
295
|
+
local _arg0_2 = RunService.PreRender:Connect(function(dt)
|
|
296
|
+
for provider in onRender do
|
|
297
|
+
self:profile(function()
|
|
298
|
+
return provider:onRender(dt)
|
|
299
|
+
end, provider)
|
|
300
|
+
end
|
|
301
|
+
end)
|
|
302
|
+
table.insert(connections, _arg0_2)
|
|
303
|
+
end
|
|
304
|
+
local _moduleConnections = self.moduleConnections
|
|
305
|
+
local _module = module
|
|
306
|
+
_moduleConnections[_module] = connections
|
|
307
|
+
end
|
|
308
|
+
function LifecycleProvider:extinguished(module)
|
|
309
|
+
local _moduleConnections = self.moduleConnections
|
|
310
|
+
local _module = module
|
|
311
|
+
local connections = _moduleConnections[_module]
|
|
312
|
+
if connections then
|
|
313
|
+
local _moduleConnections_1 = self.moduleConnections
|
|
314
|
+
local _module_1 = module
|
|
315
|
+
_moduleConnections_1[_module_1] = nil
|
|
316
|
+
for _, connection in connections do
|
|
317
|
+
connection:Disconnect()
|
|
318
|
+
end
|
|
319
|
+
end
|
|
320
|
+
-- Over a copy, since a handler may detach objects; one detached by a handler before it --
|
|
321
|
+
-- `removeClassInstance` from an `onExtinguished` -- has left the event, so it is not told.
|
|
322
|
+
-- One failing handler must not leave the module stuck half-extinguished.
|
|
323
|
+
local _array = {}
|
|
324
|
+
local _length = #_array
|
|
325
|
+
for _v in self.onExtinguished do
|
|
326
|
+
_length += 1
|
|
327
|
+
_array[_length] = _v
|
|
328
|
+
end
|
|
329
|
+
for _, provider in _array do
|
|
330
|
+
if not (self.onExtinguished[provider] ~= nil) then
|
|
331
|
+
continue
|
|
332
|
+
end
|
|
333
|
+
local success, err = pcall(function()
|
|
334
|
+
return provider:onExtinguished()
|
|
335
|
+
end)
|
|
336
|
+
if not success then
|
|
337
|
+
warn(`[Flamework] onExtinguished failed for '{self:getIdentifier(provider)}': {tostring(err)}`)
|
|
338
|
+
end
|
|
339
|
+
end
|
|
340
|
+
end
|
|
341
|
+
do
|
|
342
|
+
-- (Flamework) LifecycleProvider metadata
|
|
343
|
+
Reflect_1.defineMetadata(LifecycleProvider, "identifier", "$:lifecycle/lifecyclePlugin@LifecycleProvider")
|
|
344
|
+
Reflect_1.defineMetadata(LifecycleProvider, "flamework:implements", {})
|
|
345
|
+
Reflect_1.defineMetadata(LifecycleProvider, "flamework:parameters", { "$:lifecycle/lifecyclePlugin@LifecyclePluginOptions" })
|
|
346
|
+
Reflect_1.defineMetadata(LifecycleProvider, "flamework:dependencies", { {
|
|
347
|
+
id = "$:lifecycle/lifecyclePlugin@LifecyclePluginOptions",
|
|
348
|
+
} })
|
|
349
|
+
end
|
|
350
|
+
LifecycleProvider = Provider()(LifecycleProvider) or LifecycleProvider
|
|
351
|
+
end
|
|
352
|
+
--* An observer that keeps one of the provider's plain event sets in step with the module.
|
|
353
|
+
local function observeSet(provider, set)
|
|
354
|
+
return {
|
|
355
|
+
onAdded = function(value)
|
|
356
|
+
local _set = set
|
|
357
|
+
local _value = value
|
|
358
|
+
_set[_value] = true
|
|
359
|
+
return _set
|
|
360
|
+
end,
|
|
361
|
+
onRemoved = function(value)
|
|
362
|
+
return provider:removeFrom(set, value)
|
|
363
|
+
end,
|
|
364
|
+
}
|
|
365
|
+
end
|
|
366
|
+
--[[
|
|
367
|
+
*
|
|
368
|
+
* Creates a lifecycle plugin with the specified options.
|
|
369
|
+
*
|
|
370
|
+
* `LifecyclePlugin` is `createLifecyclePlugin()` with the defaults; use this when a module needs
|
|
371
|
+
* different ones, such as forcing profiling on or off.
|
|
372
|
+
|
|
373
|
+
]]
|
|
374
|
+
local function createLifecyclePlugin(options)
|
|
375
|
+
if options == nil then
|
|
376
|
+
options = {}
|
|
377
|
+
end
|
|
378
|
+
local setup = function(target)
|
|
379
|
+
-- One per ignition: the setup runs for every module that includes the plugin, and again for
|
|
380
|
+
-- every ignition of a definition, so nothing here is shared between modules.
|
|
381
|
+
local lifecycle = LifecycleProvider.new(options)
|
|
382
|
+
target.provideInstance(lifecycle, "$:lifecycle/lifecyclePlugin@LifecycleProvider")
|
|
383
|
+
target.onPostIgnite(function(module)
|
|
384
|
+
return lifecycle:postIgnite(module)
|
|
385
|
+
end)
|
|
386
|
+
target.onExtinguished(function(module)
|
|
387
|
+
return lifecycle:extinguished(module)
|
|
388
|
+
end)
|
|
389
|
+
target.observe({
|
|
390
|
+
onAdded = function(value, context)
|
|
391
|
+
return lifecycle:addInit(value, context)
|
|
392
|
+
end,
|
|
393
|
+
onRemoved = function(value)
|
|
394
|
+
return lifecycle:removeInit(value)
|
|
395
|
+
end,
|
|
396
|
+
}, "$:lifecycle/lifecycleInterfaces@OnInit")
|
|
397
|
+
target.observe({
|
|
398
|
+
onAdded = function(value, context)
|
|
399
|
+
return lifecycle:addStart(value, context)
|
|
400
|
+
end,
|
|
401
|
+
onRemoved = function(value)
|
|
402
|
+
return lifecycle:removeStart(value)
|
|
403
|
+
end,
|
|
404
|
+
}, "$:lifecycle/lifecycleInterfaces@OnStart")
|
|
405
|
+
target.observe(observeSet(lifecycle, lifecycle.onTick), "$:lifecycle/lifecycleInterfaces@OnTick")
|
|
406
|
+
target.observe(observeSet(lifecycle, lifecycle.onRender), "$:lifecycle/lifecycleInterfaces@OnRender")
|
|
407
|
+
target.observe(observeSet(lifecycle, lifecycle.onPhysics), "$:lifecycle/lifecycleInterfaces@OnPhysics")
|
|
408
|
+
target.observe(observeSet(lifecycle, lifecycle.onExtinguished), "$:lifecycle/lifecycleInterfaces@OnExtinguished")
|
|
409
|
+
end
|
|
410
|
+
return PluginDefinition.new("Lifecycle", setup, LIFECYCLE_SLOT)
|
|
411
|
+
end
|
|
412
|
+
--[[
|
|
413
|
+
*
|
|
414
|
+
* The lifecycle plugin with default options. Every module made with `Flamework.createModule()`
|
|
415
|
+
* starts with it; `disableDefaultLifecycle()` on the builder leaves it out, and including one built
|
|
416
|
+
* with {@link createLifecyclePlugin} takes its place.
|
|
417
|
+
|
|
418
|
+
]]
|
|
419
|
+
local LifecyclePlugin = createLifecyclePlugin()
|
|
420
|
+
return {
|
|
421
|
+
createLifecyclePlugin = createLifecyclePlugin,
|
|
422
|
+
LifecycleProvider = LifecycleProvider,
|
|
423
|
+
LifecyclePlugin = LifecyclePlugin,
|
|
424
|
+
}
|
package/out/modding.d.ts
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { t } from "@rbxts/t";
|
|
2
|
+
export declare namespace Modding {
|
|
3
|
+
/**
|
|
4
|
+
* This function is able to utilize Flamework's user macros to generate and inspect types.
|
|
5
|
+
* This function supports all values natively supported by Flamework's user macros.
|
|
6
|
+
*
|
|
7
|
+
* For example, if you want to retrieve the properties of an instance, you could write code like this:
|
|
8
|
+
* ```ts
|
|
9
|
+
* // Returns an array of all keys part of the union.
|
|
10
|
+
* const basePartKeys = Modding.inspect<InstancePropertyNames<BasePart>[]>();
|
|
11
|
+
* ```
|
|
12
|
+
*
|
|
13
|
+
* @metadata macro
|
|
14
|
+
*/
|
|
15
|
+
export function inspect<T>(value?: Modding.Emit<T>): T;
|
|
16
|
+
/**
|
|
17
|
+
* This type emits runtime equivalents of types, such as generating strings from string literal types.
|
|
18
|
+
*
|
|
19
|
+
* You are able to generate most TS types, including objects and tuples which will generate equivalent objects at runtime.
|
|
20
|
+
* Additionally, you can generate unions by using `Array<T>`, which will generate an array where each constituent of `T` is its own element.
|
|
21
|
+
*
|
|
22
|
+
* This type is primarily used to mark a user macro parameter as metadata, and is not necessary if you use other macro types.
|
|
23
|
+
*/
|
|
24
|
+
export type Emit<T> = T & {
|
|
25
|
+
/** @hidden */ _flamework_macro_many: T;
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Creates an injectable type that can be used to modify dependency injection behavior.
|
|
29
|
+
*/
|
|
30
|
+
export type Injectable<C extends {
|
|
31
|
+
type: unknown;
|
|
32
|
+
id?: unknown;
|
|
33
|
+
metadata?: unknown[];
|
|
34
|
+
}> = RealType<C["type"]> & {
|
|
35
|
+
/** @hidden @deprecated */
|
|
36
|
+
_flamework_injectable: C;
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* An internal type for intrinsic user macro metadata.
|
|
40
|
+
*
|
|
41
|
+
* @hidden
|
|
42
|
+
*/
|
|
43
|
+
export type Intrinsic<N extends string, M extends unknown[], T = symbol> = T & {
|
|
44
|
+
_flamework_intrinsic: [N, ...M];
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* This namespace contains types and metadata related to the current macro's callsite.
|
|
48
|
+
*/
|
|
49
|
+
export namespace Caller {
|
|
50
|
+
/**
|
|
51
|
+
* Retrieves metadata about the callsite using Flamework's user macros.
|
|
52
|
+
*/
|
|
53
|
+
type CallerHelper<U, M extends string> = U & {
|
|
54
|
+
/** @hidden */ _flamework_macro_caller: M;
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* The starting line of the expression in the TypeScript source, starting at 1.
|
|
58
|
+
*/
|
|
59
|
+
export type Line = CallerHelper<number, "line">;
|
|
60
|
+
/**
|
|
61
|
+
* The char at the start of the expression relative to the starting line, starting at 1.
|
|
62
|
+
*/
|
|
63
|
+
export type Character = CallerHelper<number, "character">;
|
|
64
|
+
/**
|
|
65
|
+
* The width of the expression.
|
|
66
|
+
* This includes the width of multiline statements.
|
|
67
|
+
*/
|
|
68
|
+
export type Width = CallerHelper<number, "width">;
|
|
69
|
+
/**
|
|
70
|
+
* A unique identifier that can be used to identify exact callsites.
|
|
71
|
+
* This can be used for hooks.
|
|
72
|
+
*
|
|
73
|
+
* Derived from the callsite's position, so it is the same in every file of one build and,
|
|
74
|
+
* without obfuscation, across builds. With obfuscation on it changes with every build, so
|
|
75
|
+
* that what it names -- a remote, say -- cannot be mapped once and found again in the next
|
|
76
|
+
* release.
|
|
77
|
+
*/
|
|
78
|
+
export type Uuid = CallerHelper<string, "uuid">;
|
|
79
|
+
/**
|
|
80
|
+
* The source text for the expression.
|
|
81
|
+
*/
|
|
82
|
+
export type Text = CallerHelper<string, "text">;
|
|
83
|
+
/**
|
|
84
|
+
* This API will generate a constant reference to the nested metadata.
|
|
85
|
+
* This means that the same object will be passed in for every invocation of a specific function call.
|
|
86
|
+
*
|
|
87
|
+
* This can be used to implement caching, and avoid allocation overhead for large metadata.
|
|
88
|
+
*/
|
|
89
|
+
export type Constant<T> = T & {
|
|
90
|
+
/** @hidden */ _flamework_macro_shared_ref: T;
|
|
91
|
+
};
|
|
92
|
+
export {};
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* This namespace contains types that allow you to perform functions or fetch metadata about specific types.
|
|
96
|
+
*/
|
|
97
|
+
export namespace Target {
|
|
98
|
+
type TargetHelper<T, U, M extends string> = U & {
|
|
99
|
+
/** @hidden */ _flamework_macro_generic: [T, M];
|
|
100
|
+
};
|
|
101
|
+
/**
|
|
102
|
+
* Retrieves the ID from the type.
|
|
103
|
+
*
|
|
104
|
+
* The ID is a mostly unique identifier meant to identify specific resources in Flamework projects, such as providers.
|
|
105
|
+
*/
|
|
106
|
+
export type Id<T> = TargetHelper<T, string, "id">;
|
|
107
|
+
/**
|
|
108
|
+
* Retrieves the text of the type, equivalent to what is seen in TypeScript's intellisense.
|
|
109
|
+
*
|
|
110
|
+
* The resulting text may not be identical as the type inputted as its dependent on how TypeScript renders types.
|
|
111
|
+
*/
|
|
112
|
+
export type Text<T> = TargetHelper<T, string, "text">;
|
|
113
|
+
/**
|
|
114
|
+
* Retrieves a `t` guard that matches this specific type.
|
|
115
|
+
*/
|
|
116
|
+
export type Guard<T> = TargetHelper<T, t.check<T>, "guard">;
|
|
117
|
+
/**
|
|
118
|
+
* Retrieves the dependency info for this type, which contains the ID and any metadata included on the type.
|
|
119
|
+
*/
|
|
120
|
+
export type Dependency<T> = TargetHelper<T, DependencyInfo, "dependency">;
|
|
121
|
+
/**
|
|
122
|
+
* Retrieves the dependency info for this type, which contains the ID and any metadata included on the type.
|
|
123
|
+
*
|
|
124
|
+
* This is equivalent to the {@link Dependency} type, except it will shorten itself to a string (the type's ID) if possible.
|
|
125
|
+
*/
|
|
126
|
+
export type DependencyConcise<T> = TargetHelper<T, DependencyInfo | string, "dependencyConcise">;
|
|
127
|
+
/**
|
|
128
|
+
* Retrieves the labels from this tuple.
|
|
129
|
+
*
|
|
130
|
+
* This can also be used to extract parameter names via `Parameters<T>`
|
|
131
|
+
*/
|
|
132
|
+
export type Labels<T extends readonly unknown[]> = (string[] & {
|
|
133
|
+
_flamework_macro_tuple_labels: T;
|
|
134
|
+
}) | undefined;
|
|
135
|
+
/**
|
|
136
|
+
* Hashes a string literal type (such as an event name.)
|
|
137
|
+
*
|
|
138
|
+
* The second type argument, `C`, is for providing a context to the hashing which will generate new hashes
|
|
139
|
+
* for strings which already have a hash under another context.
|
|
140
|
+
*/
|
|
141
|
+
export type Hash<T extends string, C extends string = never> = string & {
|
|
142
|
+
/** @hidden */ _flamework_macro_hash: [T, C];
|
|
143
|
+
};
|
|
144
|
+
/**
|
|
145
|
+
* This is equivalent to {@link Hash `Hash`} except it will only hash strings when `obfuscation` is turned on.
|
|
146
|
+
*/
|
|
147
|
+
export type Obfuscate<T extends string, C extends string = never> = string & {
|
|
148
|
+
/** @hidden */ _flamework_macro_hash: [T, C, true];
|
|
149
|
+
};
|
|
150
|
+
export {};
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Information about an injected dependency.
|
|
154
|
+
*/
|
|
155
|
+
export interface DependencyInfo {
|
|
156
|
+
/**
|
|
157
|
+
* The ID used to resolve this dependency.
|
|
158
|
+
*/
|
|
159
|
+
id: string;
|
|
160
|
+
/**
|
|
161
|
+
* Metadata provided by the injectable type.
|
|
162
|
+
*/
|
|
163
|
+
metadata?: unknown[];
|
|
164
|
+
}
|
|
165
|
+
type RealType<T> = T extends {
|
|
166
|
+
_flamework_injectable: {
|
|
167
|
+
type: infer R;
|
|
168
|
+
};
|
|
169
|
+
} ? RealType<R> : T;
|
|
170
|
+
export {};
|
|
171
|
+
}
|