@rbxts/planck 0.1.3-rc.5 → 0.2.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/out/DependencyGraph.luau +180 -0
- package/out/Phase.d.ts +0 -9
- package/out/Phase.luau +1 -49
- package/out/Pipeline.d.ts +1 -1
- package/out/Pipeline.luau +33 -21
- package/out/Scheduler.d.ts +12 -15
- package/out/Scheduler.luau +313 -172
- package/out/conditions.d.ts +14 -0
- package/out/conditions.luau +151 -0
- package/out/index.d.ts +6 -0
- package/out/init.luau +41 -47
- package/out/types.d.ts +5 -1
- package/out/utils.luau +95 -17
- package/package.json +1 -1
package/out/Scheduler.luau
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
|
|
1
|
+
--!nonstrict
|
|
2
|
+
local DependencyGraph = require("./DependencyGraph")
|
|
3
|
+
local Pipeline = require("./Pipeline")
|
|
4
|
+
local Phase = require("./Phase")
|
|
2
5
|
|
|
3
|
-
local
|
|
4
|
-
local
|
|
5
|
-
|
|
6
|
-
local utils = require(script.Parent:WaitForChild('utils'))
|
|
7
|
-
local hooks = require(script.Parent:WaitForChild('hooks'))
|
|
6
|
+
local utils = require("./utils")
|
|
7
|
+
local hooks = require("./hooks")
|
|
8
|
+
local conditions = require("./conditions")
|
|
8
9
|
|
|
9
10
|
local getSystem = utils.getSystem
|
|
10
11
|
local getSystemName = utils.getSystemName
|
|
@@ -49,6 +50,7 @@ Scheduler.Hooks = hooks.Hooks
|
|
|
49
50
|
--- Initializes a plugin with the scheduler, see the [Plugin Docs](/docs/plugins) for more information.
|
|
50
51
|
function Scheduler:addPlugin(plugin)
|
|
51
52
|
plugin:build(self)
|
|
53
|
+
table.insert(self._plugins, plugin)
|
|
52
54
|
return self
|
|
53
55
|
end
|
|
54
56
|
|
|
@@ -105,8 +107,7 @@ function Scheduler:_handleLogs(systemInfo)
|
|
|
105
107
|
end
|
|
106
108
|
|
|
107
109
|
function Scheduler:runSystem(system)
|
|
108
|
-
|
|
109
|
-
if runIf and runIf(table.unpack(self._vargs)) == false then
|
|
110
|
+
if self:_canRun(system) == false then
|
|
110
111
|
return
|
|
111
112
|
end
|
|
112
113
|
|
|
@@ -133,11 +134,14 @@ function Scheduler:runSystem(system)
|
|
|
133
134
|
|
|
134
135
|
local function systemCall()
|
|
135
136
|
local function noYield()
|
|
136
|
-
local success, err
|
|
137
|
-
|
|
137
|
+
local success, err
|
|
138
|
+
coroutine.resume(self._thread, function()
|
|
139
|
+
success, err = xpcall(system, function(e)
|
|
140
|
+
return debug.traceback(e)
|
|
141
|
+
end, table.unpack(self._vargs))
|
|
138
142
|
end)
|
|
139
143
|
|
|
140
|
-
if
|
|
144
|
+
if success == false then
|
|
141
145
|
didYield = true
|
|
142
146
|
table.insert(systemInfo.logs, err)
|
|
143
147
|
hooks.systemError(self, systemInfo, err)
|
|
@@ -146,12 +150,16 @@ function Scheduler:runSystem(system)
|
|
|
146
150
|
|
|
147
151
|
if self._yielded then
|
|
148
152
|
didYield = true
|
|
149
|
-
local
|
|
150
|
-
|
|
153
|
+
local source, line = debug.info(self._thread, 1, "sl")
|
|
154
|
+
local errMessage = `{source}:{line}: System yielded`
|
|
155
|
+
table.insert(
|
|
156
|
+
systemInfo.logs,
|
|
157
|
+
debug.traceback(self._thread, errMessage, 2)
|
|
158
|
+
)
|
|
151
159
|
hooks.systemError(
|
|
152
160
|
self,
|
|
153
161
|
systemInfo,
|
|
154
|
-
|
|
162
|
+
debug.traceback(self._thread, errMessage, 2)
|
|
155
163
|
)
|
|
156
164
|
end
|
|
157
165
|
end
|
|
@@ -205,29 +213,51 @@ function Scheduler:runSystem(system)
|
|
|
205
213
|
end
|
|
206
214
|
|
|
207
215
|
function Scheduler:runPhase(phase)
|
|
208
|
-
|
|
209
|
-
if runIf and runIf(table.unpack(self._vargs)) == false then
|
|
216
|
+
if self:_canRun(phase) == false then
|
|
210
217
|
return
|
|
211
218
|
end
|
|
212
219
|
|
|
213
220
|
hooks.phaseBegan(self, phase)
|
|
214
221
|
|
|
222
|
+
if not self._phaseToSystems[phase] then
|
|
223
|
+
self._phaseToSystems[phase] = {}
|
|
224
|
+
end
|
|
225
|
+
|
|
215
226
|
for _, system in self._phaseToSystems[phase] do
|
|
216
227
|
self:runSystem(system)
|
|
217
228
|
end
|
|
218
229
|
end
|
|
219
230
|
|
|
220
231
|
function Scheduler:runPipeline(pipeline)
|
|
221
|
-
|
|
222
|
-
if runIf and runIf(table.unpack(self._vargs)) == false then
|
|
232
|
+
if self:_canRun(pipeline) == false then
|
|
223
233
|
return
|
|
224
234
|
end
|
|
225
235
|
|
|
226
|
-
|
|
236
|
+
local orderedList = pipeline.dependencyGraph:getOrderedList()
|
|
237
|
+
assert(
|
|
238
|
+
orderedList,
|
|
239
|
+
`Pipeline {pipeline} contains a circular dependency, check it's Phases`
|
|
240
|
+
)
|
|
241
|
+
|
|
242
|
+
for _, phase in orderedList do
|
|
227
243
|
self:runPhase(phase)
|
|
228
244
|
end
|
|
229
245
|
end
|
|
230
246
|
|
|
247
|
+
function Scheduler:_canRun(dependent)
|
|
248
|
+
local conditions = self._runIfConditions[dependent]
|
|
249
|
+
|
|
250
|
+
if conditions then
|
|
251
|
+
for _, runIf in conditions do
|
|
252
|
+
if runIf(table.unpack(self._vargs)) == false then
|
|
253
|
+
return false
|
|
254
|
+
end
|
|
255
|
+
end
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
return true
|
|
259
|
+
end
|
|
260
|
+
|
|
231
261
|
--- @method run
|
|
232
262
|
--- @within Scheduler
|
|
233
263
|
--- @param phase Phase
|
|
@@ -274,37 +304,42 @@ end
|
|
|
274
304
|
--- @return Scheduler
|
|
275
305
|
---
|
|
276
306
|
--- Runs all Systems within order.
|
|
307
|
+
---
|
|
308
|
+
--- :::note
|
|
309
|
+
--- When you add a Pipeline or Phase with an event, it will be grouped
|
|
310
|
+
--- with other Pipelines/Phases on that event. Otherwise, it will be
|
|
311
|
+
--- added to the default group.
|
|
312
|
+
---
|
|
313
|
+
--- When not running systems on Events, such as with the `runAll` method,
|
|
314
|
+
--- the Default group will be ran first, and then each Event Group in the
|
|
315
|
+
--- order created.
|
|
316
|
+
---
|
|
317
|
+
--- Pipelines/Phases in these groups are still ordered by their dependencies
|
|
318
|
+
--- and by the order of insertion.
|
|
319
|
+
--- :::
|
|
277
320
|
function Scheduler:runAll()
|
|
278
|
-
|
|
279
|
-
self:run(phase)
|
|
280
|
-
end
|
|
281
|
-
end
|
|
282
|
-
|
|
283
|
-
function Scheduler:_insertPhaseAt(phase, index, instance, event)
|
|
321
|
+
local orderedDefaults = self._defaultDependencyGraph:getOrderedList()
|
|
284
322
|
assert(
|
|
285
|
-
|
|
286
|
-
"
|
|
323
|
+
orderedDefaults,
|
|
324
|
+
"Default Group contains a circular dependency, check your Pipelines/Phases"
|
|
287
325
|
)
|
|
288
326
|
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
hooks.phaseAdd(self, phase)
|
|
293
|
-
|
|
294
|
-
if isValidEvent(instance, event) then
|
|
295
|
-
self:_schedulePhase(phase, instance, event)
|
|
327
|
+
for _, dependency in orderedDefaults do
|
|
328
|
+
self:run(dependency)
|
|
296
329
|
end
|
|
297
|
-
end
|
|
298
330
|
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
331
|
+
for identifier, dependencyGraph in self._eventDependencyGraphs do
|
|
332
|
+
local orderedList = dependencyGraph:getOrderedList()
|
|
333
|
+
assert(
|
|
334
|
+
orderedDefaults,
|
|
335
|
+
`Event Group '{identifier}' contains a circular dependency, check your Pipelines/Phases`
|
|
336
|
+
)
|
|
337
|
+
for _, dependency in orderedList do
|
|
338
|
+
self:run(dependency)
|
|
339
|
+
end
|
|
307
340
|
end
|
|
341
|
+
|
|
342
|
+
return self
|
|
308
343
|
end
|
|
309
344
|
|
|
310
345
|
--- @method insert
|
|
@@ -312,15 +347,17 @@ end
|
|
|
312
347
|
--- @param phase Phase
|
|
313
348
|
--- @return Scheduler
|
|
314
349
|
---
|
|
315
|
-
--- Initializes the Phase within the Scheduler, ordering it implicitly
|
|
350
|
+
--- Initializes the Phase within the Scheduler, ordering it implicitly by
|
|
351
|
+
--- setting it as a dependent of the previous Phase/Pipeline.
|
|
316
352
|
|
|
317
353
|
--- @method insert
|
|
318
354
|
--- @within Scheduler
|
|
319
355
|
--- @param pipeline Pipeline
|
|
320
356
|
--- @return Scheduler
|
|
321
357
|
---
|
|
322
|
-
--- Initializes
|
|
323
|
-
--- ordering the Pipeline implicitly
|
|
358
|
+
--- Initializes the Pipeline and it's Phases within the Scheduler,
|
|
359
|
+
--- ordering the Pipeline implicitly by setting it as a dependent
|
|
360
|
+
--- of the previous Phase/Pipeline.
|
|
324
361
|
|
|
325
362
|
--- @method insert
|
|
326
363
|
--- @within Scheduler
|
|
@@ -330,7 +367,8 @@ end
|
|
|
330
367
|
--- @return Scheduler
|
|
331
368
|
---
|
|
332
369
|
--- Initializes the Phase within the Scheduler, ordering it implicitly
|
|
333
|
-
---
|
|
370
|
+
--- by setting it as a dependent of the previous Phase/Pipeline, and
|
|
371
|
+
--- scheduling it to be ran on the specified event.
|
|
334
372
|
---
|
|
335
373
|
--- ```lua
|
|
336
374
|
--- local myScheduler = Scheduler.new()
|
|
@@ -344,22 +382,38 @@ end
|
|
|
344
382
|
--- @param event string | EventLike
|
|
345
383
|
--- @return Scheduler
|
|
346
384
|
---
|
|
347
|
-
--- Initializes
|
|
348
|
-
--- ordering the Pipeline implicitly
|
|
349
|
-
--- the
|
|
385
|
+
--- Initializes the Pipeline and it's Phases within the Scheduler,
|
|
386
|
+
--- ordering the Pipeline implicitly by setting it as a dependent of
|
|
387
|
+
--- the previous Phase/Pipeline, and scheduling it to be ran on the
|
|
388
|
+
--- specified event.
|
|
350
389
|
---
|
|
351
390
|
--- ```lua
|
|
352
391
|
--- local myScheduler = Scheduler.new()
|
|
353
392
|
--- :insert(myPipeline, RunService, "Heartbeat")
|
|
354
393
|
--- ```
|
|
355
394
|
|
|
356
|
-
function Scheduler:insert(
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
395
|
+
function Scheduler:insert(dependency, instance, event)
|
|
396
|
+
assert(
|
|
397
|
+
isPhase(dependency) or isPipeline(dependency),
|
|
398
|
+
"Unknown dependency passed to Scheduler:insert(unknown, _, _)"
|
|
399
|
+
)
|
|
400
|
+
|
|
401
|
+
if not instance then
|
|
402
|
+
local dependencyGraph = self._defaultDependencyGraph
|
|
403
|
+
dependencyGraph:insertBefore(dependency, self._defaultPhase)
|
|
361
404
|
else
|
|
362
|
-
|
|
405
|
+
assert(
|
|
406
|
+
isValidEvent(instance, event),
|
|
407
|
+
"Unknown instance/event passed to Scheduler:insert(_, instance, event)"
|
|
408
|
+
)
|
|
409
|
+
|
|
410
|
+
local dependencyGraph = self:_getEventDependencyGraph(instance, event)
|
|
411
|
+
dependencyGraph:insert(dependency)
|
|
412
|
+
end
|
|
413
|
+
|
|
414
|
+
if isPhase(dependency) then
|
|
415
|
+
self._phaseToSystems[dependency] = {}
|
|
416
|
+
hooks.phaseAdd(self, dependency)
|
|
363
417
|
end
|
|
364
418
|
|
|
365
419
|
return self
|
|
@@ -372,8 +426,7 @@ end
|
|
|
372
426
|
--- @return Scheduler
|
|
373
427
|
---
|
|
374
428
|
--- Initializes the Phase within the Scheduler, ordering it
|
|
375
|
-
--- explicitly
|
|
376
|
-
--- Pipeline provided.
|
|
429
|
+
--- explicitly by setting the after Phase/Pipeline as a dependent.
|
|
377
430
|
|
|
378
431
|
--- @method insertAfter
|
|
379
432
|
--- @within Scheduler
|
|
@@ -381,40 +434,66 @@ end
|
|
|
381
434
|
--- @param after Phase | Pipeline
|
|
382
435
|
--- @return Scheduler
|
|
383
436
|
---
|
|
384
|
-
--- Initializes
|
|
385
|
-
--- ordering the Pipeline explicitly
|
|
386
|
-
---
|
|
437
|
+
--- Initializes the Pipeline and it's Phases within the Scheduler,
|
|
438
|
+
--- ordering the Pipeline explicitly by setting the after Phase/Pipeline
|
|
439
|
+
--- as a dependent.
|
|
387
440
|
|
|
388
441
|
function Scheduler:insertAfter(dependent, after)
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
)
|
|
442
|
+
assert(
|
|
443
|
+
isPhase(after) or isPipeline(after),
|
|
444
|
+
"Unknown dependency passed in Scheduler:insertAfter(_, unknown)"
|
|
445
|
+
)
|
|
446
|
+
assert(
|
|
447
|
+
isPhase(dependent) or isPipeline(dependent),
|
|
448
|
+
"Unknown dependent passed in Scheduler:insertAfter(unknown, _)"
|
|
449
|
+
)
|
|
395
450
|
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
elseif isPipeline(dependent) then
|
|
399
|
-
for _, phase in dependent._phases do
|
|
400
|
-
index += 1
|
|
401
|
-
self:_insertPhaseAt(phase, index)
|
|
402
|
-
end
|
|
403
|
-
else
|
|
404
|
-
error(
|
|
405
|
-
"Unknown dependent passed in Scheduler:insertAfter(unknown, _)"
|
|
406
|
-
)
|
|
407
|
-
end
|
|
408
|
-
elseif isPipeline(after) then
|
|
409
|
-
local before = after._phases[#after._phases]
|
|
451
|
+
local dependencyGraph = self:_getGraphOfDependency(after)
|
|
452
|
+
dependencyGraph:insertAfter(dependent, after)
|
|
410
453
|
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
454
|
+
if isPhase(dependent) then
|
|
455
|
+
self._phaseToSystems[dependent] = {}
|
|
456
|
+
hooks.phaseAdd(self, dependent)
|
|
457
|
+
end
|
|
414
458
|
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
459
|
+
return self
|
|
460
|
+
end
|
|
461
|
+
|
|
462
|
+
--- @method insertBefore
|
|
463
|
+
--- @within Scheduler
|
|
464
|
+
--- @param phase Phase
|
|
465
|
+
--- @param before Phase | Pipeline
|
|
466
|
+
--- @return Scheduler
|
|
467
|
+
---
|
|
468
|
+
--- Initializes the Phase within the Scheduler, ordering it
|
|
469
|
+
--- explicitly by setting the before Phase/Pipeline as a dependency.
|
|
470
|
+
|
|
471
|
+
--- @method insertBefore
|
|
472
|
+
--- @within Scheduler
|
|
473
|
+
--- @param pipeline Pipeline
|
|
474
|
+
--- @param before Phase | Pipeline
|
|
475
|
+
--- @return Scheduler
|
|
476
|
+
---
|
|
477
|
+
--- Initializes the Pipeline and it's Phases within the Scheduler,
|
|
478
|
+
--- ordering the Pipeline explicitly by setting the before Phase/Pipeline
|
|
479
|
+
--- as a dependency.
|
|
480
|
+
|
|
481
|
+
function Scheduler:insertBefore(dependent, before)
|
|
482
|
+
assert(
|
|
483
|
+
isPhase(before) or isPipeline(before),
|
|
484
|
+
"Unknown dependency passed in Scheduler:insertBefore(_, unknown)"
|
|
485
|
+
)
|
|
486
|
+
assert(
|
|
487
|
+
isPhase(dependent) or isPipeline(dependent),
|
|
488
|
+
"Unknown dependent passed in Scheduler:insertBefore(unknown, _)"
|
|
489
|
+
)
|
|
490
|
+
|
|
491
|
+
local dependencyGraph = self:_getGraphOfDependency(before)
|
|
492
|
+
dependencyGraph:insertBefore(dependent, before)
|
|
493
|
+
|
|
494
|
+
if isPhase(dependent) then
|
|
495
|
+
self._phaseToSystems[dependent] = {}
|
|
496
|
+
hooks.phaseAdd(self, dependent)
|
|
418
497
|
end
|
|
419
498
|
|
|
420
499
|
return self
|
|
@@ -434,10 +513,15 @@ function Scheduler:addSystem(system, phase)
|
|
|
434
513
|
error("Unknown system passed to Scheduler:addSystem(unknown, phase?)")
|
|
435
514
|
end
|
|
436
515
|
|
|
516
|
+
local name = getSystemName(systemFn)
|
|
517
|
+
if type(system) == "table" and system.name then
|
|
518
|
+
name = system.name
|
|
519
|
+
end
|
|
520
|
+
|
|
437
521
|
local systemInfo = {
|
|
438
522
|
system = systemFn,
|
|
439
523
|
phase = phase,
|
|
440
|
-
name =
|
|
524
|
+
name = name,
|
|
441
525
|
logs = {},
|
|
442
526
|
}
|
|
443
527
|
|
|
@@ -445,15 +529,26 @@ function Scheduler:addSystem(system, phase)
|
|
|
445
529
|
if type(system) == "table" and system.phase then
|
|
446
530
|
systemInfo.phase = system.phase
|
|
447
531
|
else
|
|
448
|
-
systemInfo.phase =
|
|
532
|
+
systemInfo.phase = self._defaultPhase
|
|
449
533
|
end
|
|
450
534
|
end
|
|
451
535
|
|
|
452
536
|
self._systemInfo[systemFn] = systemInfo
|
|
537
|
+
|
|
538
|
+
if not self._phaseToSystems[systemInfo.phase] then
|
|
539
|
+
self._phaseToSystems[systemInfo.phase] = {}
|
|
540
|
+
end
|
|
541
|
+
|
|
453
542
|
table.insert(self._phaseToSystems[systemInfo.phase], systemFn)
|
|
454
543
|
|
|
455
544
|
hooks.systemAdd(self, systemInfo)
|
|
456
545
|
|
|
546
|
+
if type(system) == "table" and system.runConditions then
|
|
547
|
+
for _, condition in system.runConditions do
|
|
548
|
+
self:addRunCondition(systemFn, condition)
|
|
549
|
+
end
|
|
550
|
+
end
|
|
551
|
+
|
|
457
552
|
return self
|
|
458
553
|
end
|
|
459
554
|
|
|
@@ -470,19 +565,27 @@ function Scheduler:addSystems(systems, phase)
|
|
|
470
565
|
end
|
|
471
566
|
|
|
472
567
|
local foundSystem = false
|
|
568
|
+
local n = 0
|
|
473
569
|
|
|
474
570
|
for _, system in systems do
|
|
571
|
+
n += 1
|
|
475
572
|
if getSystem(system) then
|
|
476
573
|
foundSystem = true
|
|
477
574
|
self:addSystem(system, phase)
|
|
478
575
|
end
|
|
479
576
|
end
|
|
480
577
|
|
|
578
|
+
if n == 0 then
|
|
579
|
+
error("Empty table passed to Scheduler:addSystems({ }, phase?)")
|
|
580
|
+
end
|
|
581
|
+
|
|
481
582
|
if not foundSystem then
|
|
482
583
|
error(
|
|
483
584
|
"Unknown table passed to Scheduler:addSystems({ unknown }, phase?)"
|
|
484
585
|
)
|
|
485
586
|
end
|
|
587
|
+
|
|
588
|
+
return self
|
|
486
589
|
end
|
|
487
590
|
|
|
488
591
|
--- @method editSystem
|
|
@@ -510,12 +613,28 @@ function Scheduler:editSystem(system, newPhase)
|
|
|
510
613
|
assert(index, "Unable to find system within phase")
|
|
511
614
|
|
|
512
615
|
table.remove(systems, index)
|
|
616
|
+
|
|
617
|
+
if not self._phaseToSystems[newPhase] then
|
|
618
|
+
self._phaseToSystems[newPhase] = {}
|
|
619
|
+
end
|
|
513
620
|
table.insert(self._phaseToSystems[newPhase], systemFn)
|
|
514
621
|
|
|
515
622
|
systemInfo.phase = newPhase
|
|
516
623
|
return self
|
|
517
624
|
end
|
|
518
625
|
|
|
626
|
+
function Scheduler:_removeCondition(dependent, condition)
|
|
627
|
+
self._runIfConditions[dependent] = nil
|
|
628
|
+
|
|
629
|
+
for _, _conditions in self._runIfConditions do
|
|
630
|
+
if table.find(_conditions, condition) then
|
|
631
|
+
return
|
|
632
|
+
end
|
|
633
|
+
end
|
|
634
|
+
|
|
635
|
+
conditions.cleanupCondition(condition)
|
|
636
|
+
end
|
|
637
|
+
|
|
519
638
|
--- @method removeSystem
|
|
520
639
|
--- @within Scheduler
|
|
521
640
|
--- @param system System
|
|
@@ -537,6 +656,14 @@ function Scheduler:removeSystem(system)
|
|
|
537
656
|
table.remove(systems, index)
|
|
538
657
|
self._systemInfo[systemFn] = nil
|
|
539
658
|
|
|
659
|
+
if self._runIfConditions[system] then
|
|
660
|
+
for _, condition in self._runIfConditions[system] do
|
|
661
|
+
self:_removeCondition(system, condition)
|
|
662
|
+
end
|
|
663
|
+
|
|
664
|
+
self._runIfConditions[system] = nil
|
|
665
|
+
end
|
|
666
|
+
|
|
540
667
|
hooks.systemRemove(self, systemInfo)
|
|
541
668
|
|
|
542
669
|
return self
|
|
@@ -583,7 +710,7 @@ function Scheduler:replaceSystem(old, new)
|
|
|
583
710
|
return self
|
|
584
711
|
end
|
|
585
712
|
|
|
586
|
-
--- @method
|
|
713
|
+
--- @method addRunCondition
|
|
587
714
|
--- @within Scheduler
|
|
588
715
|
--- @param system System
|
|
589
716
|
--- @param fn (U...) -> boolean
|
|
@@ -591,25 +718,23 @@ end
|
|
|
591
718
|
--- Adds a Run Condition which the Scheduler will check before
|
|
592
719
|
--- this System is ran.
|
|
593
720
|
|
|
594
|
-
--- @method
|
|
721
|
+
--- @method addRunCondition
|
|
595
722
|
--- @within Scheduler
|
|
596
723
|
--- @param phase Phase
|
|
597
724
|
--- @param fn (U...) -> boolean
|
|
598
725
|
---
|
|
599
726
|
--- Adds a Run Condition which the Scheduler will check before
|
|
600
|
-
--- any Systems
|
|
727
|
+
--- any Systems within this Phase are ran.
|
|
601
728
|
|
|
602
|
-
--- @method
|
|
729
|
+
--- @method addRunCondition
|
|
603
730
|
--- @within Scheduler
|
|
604
731
|
--- @param pipeline Pipeline
|
|
605
732
|
--- @param fn (U...) -> boolean
|
|
606
733
|
---
|
|
607
734
|
--- Adds a Run Condition which the Scheduler will check before
|
|
608
735
|
--- any Systems within any Phases apart of this Pipeline are ran.\
|
|
609
|
-
--- \
|
|
610
|
-
--- This Run Condition will be applied to the Phases themselves.
|
|
611
736
|
|
|
612
|
-
function Scheduler:
|
|
737
|
+
function Scheduler:addRunCondition(dependent, fn)
|
|
613
738
|
local system = getSystem(dependent)
|
|
614
739
|
if system then
|
|
615
740
|
dependent = system
|
|
@@ -617,111 +742,128 @@ function Scheduler:setRunCondition(dependent, fn)
|
|
|
617
742
|
|
|
618
743
|
assert(
|
|
619
744
|
system or isPhase(dependent) or isPipeline(dependent),
|
|
620
|
-
"Attempt to pass unknown dependent into Scheduler:
|
|
745
|
+
"Attempt to pass unknown dependent into Scheduler:addRunCondition(unknown, _)"
|
|
621
746
|
)
|
|
622
747
|
|
|
623
|
-
self._runIfConditions[dependent]
|
|
748
|
+
if not self._runIfConditions[dependent] then
|
|
749
|
+
self._runIfConditions[dependent] = {}
|
|
750
|
+
end
|
|
751
|
+
|
|
752
|
+
table.insert(self._runIfConditions[dependent], fn)
|
|
753
|
+
|
|
624
754
|
return self
|
|
625
755
|
end
|
|
626
756
|
|
|
627
757
|
function Scheduler:_addBuiltins()
|
|
628
|
-
|
|
758
|
+
self._defaultPhase = Phase.new("Default")
|
|
759
|
+
self._defaultDependencyGraph = DependencyGraph.new()
|
|
629
760
|
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
self:_insertPhaseAt(phase, i)
|
|
633
|
-
end
|
|
761
|
+
self._defaultDependencyGraph:insert(Pipeline.Startup)
|
|
762
|
+
self._defaultDependencyGraph:insert(self._defaultPhase)
|
|
634
763
|
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
self:
|
|
764
|
+
self:addRunCondition(Pipeline.Startup, conditions.runOnce())
|
|
765
|
+
for _, phase in Pipeline.Startup.dependencyGraph.nodes do
|
|
766
|
+
self:addRunCondition(phase, conditions.runOnce())
|
|
638
767
|
end
|
|
768
|
+
end
|
|
639
769
|
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
"
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
for _, event in runServiceEvents do
|
|
648
|
-
i += 1
|
|
649
|
-
self:_insertPhaseAt(Phase[event], i, RunService, event)
|
|
650
|
-
end
|
|
770
|
+
function Scheduler:_scheduleEvent(instance, event)
|
|
771
|
+
local connect = utils.getConnectFunction(instance, event)
|
|
772
|
+
assert(
|
|
773
|
+
connect,
|
|
774
|
+
"Couldn't connect to event as no valid connect methods were found! Ensure the passed event has a 'Connect' or an 'on' method!"
|
|
775
|
+
)
|
|
651
776
|
|
|
652
|
-
local
|
|
777
|
+
local identifier = getEventIdentifier(instance, event)
|
|
653
778
|
|
|
654
|
-
|
|
655
|
-
self:setRunCondition(phase, function()
|
|
656
|
-
local hasRan = startupHasRan[phase]
|
|
779
|
+
local dependencyGraph = DependencyGraph.new()
|
|
657
780
|
|
|
658
|
-
|
|
659
|
-
|
|
781
|
+
local callback = function()
|
|
782
|
+
local orderedList = dependencyGraph:getOrderedList()
|
|
783
|
+
|
|
784
|
+
if orderedList == nil then
|
|
785
|
+
local err =
|
|
786
|
+
`Event Group '{identifier}' contains a circular dependency, check your Pipelines/Phases`
|
|
787
|
+
if not recentLogs[err] then
|
|
788
|
+
task.spawn(error, err, 0)
|
|
789
|
+
warn(
|
|
790
|
+
`Planck: Error occurred while running event, this error will be ignored for 10 seconds`
|
|
791
|
+
)
|
|
792
|
+
recentLogs[err] = true
|
|
660
793
|
end
|
|
794
|
+
end
|
|
661
795
|
|
|
662
|
-
|
|
663
|
-
|
|
796
|
+
for _, dependency in orderedList do
|
|
797
|
+
self:run(dependency)
|
|
798
|
+
end
|
|
664
799
|
end
|
|
665
|
-
end
|
|
666
800
|
|
|
667
|
-
|
|
801
|
+
self._connectedEvents[identifier] = connect(callback)
|
|
802
|
+
self._eventDependencyGraphs[identifier] = dependencyGraph
|
|
803
|
+
end
|
|
668
804
|
|
|
669
|
-
|
|
670
|
-
-- License: Copyright (c) 2021 Eryn L. K., MIT License
|
|
671
|
-
-- Source: https://github.com/matter-ecs/matter/blob/main/lib/hooks/useEvent.luau
|
|
672
|
-
function Scheduler:_scheduleEvent(instance, event)
|
|
805
|
+
function Scheduler:_getEventDependencyGraph(instance, event)
|
|
673
806
|
local identifier = getEventIdentifier(instance, event)
|
|
674
807
|
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
self:run(phase)
|
|
678
|
-
end
|
|
679
|
-
end
|
|
680
|
-
|
|
681
|
-
local eventInstance = instance
|
|
682
|
-
|
|
683
|
-
if typeof(event) == "RBXScriptSignal" or type(event) == "table" then
|
|
684
|
-
eventInstance = event
|
|
685
|
-
elseif type(event) == "string" then
|
|
686
|
-
eventInstance = instance[event]
|
|
808
|
+
if not self._connectedEvents[identifier] then
|
|
809
|
+
self:_scheduleEvent(instance, event)
|
|
687
810
|
end
|
|
688
811
|
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
return eventInstance(eventInstance, callback)
|
|
693
|
-
elseif typeof(eventInstance) == "RBXScriptSignal" then
|
|
694
|
-
self._connectedEvents[identifier] = eventInstance
|
|
812
|
+
return self._eventDependencyGraphs[identifier]
|
|
813
|
+
end
|
|
695
814
|
|
|
696
|
-
|
|
815
|
+
function Scheduler:_getGraphOfDependency(dependency)
|
|
816
|
+
if table.find(self._defaultDependencyGraph.nodes, dependency) then
|
|
817
|
+
return self._defaultDependencyGraph
|
|
697
818
|
end
|
|
698
819
|
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
continue
|
|
703
|
-
end
|
|
704
|
-
|
|
705
|
-
self._connectedEvents[identifier] = eventInstance
|
|
706
|
-
return eventInstance[method](eventInstance, callback)
|
|
820
|
+
for _, dependencyGraph in self._eventDependencyGraphs do
|
|
821
|
+
if table.find(dependencyGraph.nodes, dependency) then
|
|
822
|
+
return dependencyGraph
|
|
707
823
|
end
|
|
708
824
|
end
|
|
709
825
|
|
|
710
|
-
error(
|
|
711
|
-
"Couldn't connect to event as no valid connect methods were found! Ensure the passed event has a 'Connect' or an 'on' method!"
|
|
712
|
-
)
|
|
826
|
+
error("Dependency does not belong to a DependencyGraph")
|
|
713
827
|
end
|
|
714
828
|
|
|
715
|
-
|
|
716
|
-
|
|
829
|
+
--- @within Scheduler
|
|
830
|
+
---
|
|
831
|
+
--- Disconnects all events, closes all threads, and performs
|
|
832
|
+
--- other cleanup work.
|
|
833
|
+
---
|
|
834
|
+
--- :::danger
|
|
835
|
+
--- Only use this if you intend to not use the associated
|
|
836
|
+
--- Scheduler anymore. It will not work as intended.
|
|
837
|
+
---
|
|
838
|
+
--- You should dereference the scheduler object so that
|
|
839
|
+
--- it may be garbage collected.
|
|
840
|
+
--- :::
|
|
841
|
+
---
|
|
842
|
+
--- :::warning
|
|
843
|
+
--- If you're creating a "throwaway" scheduler, you should
|
|
844
|
+
--- not add plugins like Jabby or the Matter Debugger to it.
|
|
845
|
+
--- These plugins are unable to properly be cleaned up, use
|
|
846
|
+
--- them with caution.
|
|
847
|
+
--- :::
|
|
848
|
+
function Scheduler:cleanup()
|
|
849
|
+
for _, connection in self._connectedEvents do
|
|
850
|
+
utils.disconnectEvent(connection)
|
|
851
|
+
end
|
|
852
|
+
|
|
853
|
+
for _, plugin in self._plugins do
|
|
854
|
+
if plugin.cleanup then
|
|
855
|
+
plugin:cleanup()
|
|
856
|
+
end
|
|
857
|
+
end
|
|
717
858
|
|
|
718
|
-
if
|
|
719
|
-
self.
|
|
859
|
+
if self._thread then
|
|
860
|
+
coroutine.close(self._thread)
|
|
720
861
|
end
|
|
721
862
|
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
863
|
+
for _, _conditions in self._runIfConditions do
|
|
864
|
+
for _, condition in _conditions do
|
|
865
|
+
conditions.cleanupCondition(condition)
|
|
866
|
+
end
|
|
725
867
|
end
|
|
726
868
|
end
|
|
727
869
|
|
|
@@ -738,10 +880,7 @@ function Scheduler.new(...)
|
|
|
738
880
|
|
|
739
881
|
self._vargs = { ... }
|
|
740
882
|
|
|
741
|
-
self.
|
|
742
|
-
self._orderedPipelines = {}
|
|
743
|
-
|
|
744
|
-
self._eventToPhases = {}
|
|
883
|
+
self._eventDependencyGraphs = {}
|
|
745
884
|
self._connectedEvents = {}
|
|
746
885
|
|
|
747
886
|
self._phaseToSystems = {}
|
|
@@ -749,6 +888,8 @@ function Scheduler.new(...)
|
|
|
749
888
|
|
|
750
889
|
self._runIfConditions = {}
|
|
751
890
|
|
|
891
|
+
self._plugins = {}
|
|
892
|
+
|
|
752
893
|
setmetatable(self, Scheduler)
|
|
753
894
|
|
|
754
895
|
for _, hookName in hooks.Hooks do
|