@rbxts/planck 0.2.5 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +168 -0
- package/out/DependencyGraph.luau +49 -9
- package/out/Phase.d.ts +20 -7
- package/out/Phase.luau +1 -1
- package/out/Pipeline.d.ts +22 -9
- package/out/Pipeline.luau +3 -3
- package/out/Scheduler.d.ts +207 -29
- package/out/Scheduler.luau +7 -7
- package/out/conditions.d.ts +60 -11
- package/out/conditions.luau +46 -8
- package/out/hooks.luau +3 -3
- package/out/index.d.ts +9 -15
- package/out/init.luau +65 -19
- package/out/utils.d.ts +9 -3
- package/out/utils.luau +47 -22
- package/package.json +20 -34
- package/out/hooks.d.ts +0 -4
- package/out/types.d.ts +0 -113
package/README.md
ADDED
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
# Planck, an ECS Scheduler
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+
[](https://yetanotherclown.github.io/planck)
|
|
5
|
+
[](https://wally.run/package/yetanotherclown/planck)
|
|
6
|
+
|
|
7
|
+
An Agnostic Scheduler, inspired by Bevy Schedules and Flecs Pipelines and Phases.
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
You can install Planck with Wally
|
|
12
|
+
|
|
13
|
+
```toml
|
|
14
|
+
[dependencies]
|
|
15
|
+
Planck = "yetanotherclown/planck@0.2.0"
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## What is Planck?
|
|
19
|
+
|
|
20
|
+
Planck is a standalone scheduler, which allows you to execute code on specific events, with certain conditions, and in a particular order.
|
|
21
|
+
|
|
22
|
+
This scheduler is library agnostic, which means that it *doesn't matter* which ECS library your using or if you're even using an ECS.
|
|
23
|
+
You can use this with [Jecs], [Matter], [ECR], and other Luau ECS Libraries.
|
|
24
|
+
|
|
25
|
+
## Does any of this really matter?
|
|
26
|
+
|
|
27
|
+
Yes, and no.
|
|
28
|
+
Your ECS code should be able to run in any order, without any conditions, and without concern for which event it's running on, as long as *it is* running.
|
|
29
|
+
|
|
30
|
+
The order of execution, and conditions both serve to *optimize* your code. Some systems don't need to run every frame, which is why we have conditions.
|
|
31
|
+
And the actual order of execution is to reduce latency between changes and effects in your ECS world.
|
|
32
|
+
|
|
33
|
+
Let's say we have `systemA` and `systemB`. `systemA` modifies data in our world which `systemB` depends on.
|
|
34
|
+
If `systemA` runs *after* `systemB`, then `systemB` will have to wait a whole frame for the modifications to be made.
|
|
35
|
+
This is called being *off-by-a-frame*, and this is why we care about the order of execution.
|
|
36
|
+
|
|
37
|
+
## What's Next?
|
|
38
|
+
|
|
39
|
+
You may not completely understand what's written above. That's fine.
|
|
40
|
+
|
|
41
|
+
For now, you should read the [Official Documentation](https://yetanotherclown.github.io/planck) on how to get started with Planck. These concepts will be explained more in depth as you read.
|
|
42
|
+
|
|
43
|
+
## Quick Overview
|
|
44
|
+
|
|
45
|
+
While it's highly suggested you read the documentation, here is a quick overview of Planck's API.
|
|
46
|
+
|
|
47
|
+
### The Scheduler
|
|
48
|
+
|
|
49
|
+
This is the core of Planck, this is where you add your Systems and set your Phases, Pipelines, and Run Conditions.
|
|
50
|
+
|
|
51
|
+
```luau
|
|
52
|
+
local Planck = require("@packages/Planck")
|
|
53
|
+
local Scheduler = Planck.Scheduler
|
|
54
|
+
|
|
55
|
+
local Jecs = require("@packages/Jecs")
|
|
56
|
+
local World = Jecs.World
|
|
57
|
+
|
|
58
|
+
local world = World.new()
|
|
59
|
+
local state = {}
|
|
60
|
+
|
|
61
|
+
local scheduler = Scheduler.new(world, state)
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Systems
|
|
65
|
+
|
|
66
|
+
Systems are really simple, they are just functions which run on an event or in a loop.
|
|
67
|
+
|
|
68
|
+
```luau
|
|
69
|
+
local function systemA(world, state)
|
|
70
|
+
-- ...
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
return systemA
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
And to add it to our Scheduler,
|
|
77
|
+
|
|
78
|
+
```luau
|
|
79
|
+
-- ...
|
|
80
|
+
|
|
81
|
+
local systemA = require("@shared/systems/systemA")
|
|
82
|
+
|
|
83
|
+
local scheduler = Scheduler.new(world, state)
|
|
84
|
+
:addSystem(systemA)
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Phases
|
|
88
|
+
|
|
89
|
+
Phases are used to split up your frame into different sections, this allows us to schedule our systems to run at different moments of a given frame.
|
|
90
|
+
|
|
91
|
+
```luau
|
|
92
|
+
local Planck = require("@packages/Planck")
|
|
93
|
+
local Scheduler = Planck.Scheduler
|
|
94
|
+
local Phase = Planck.Phase
|
|
95
|
+
|
|
96
|
+
-- ...
|
|
97
|
+
|
|
98
|
+
local systemA = require("@shared/systems/systemA")
|
|
99
|
+
|
|
100
|
+
local myPhase = Phase.new("myPhase")
|
|
101
|
+
|
|
102
|
+
local scheduler = Scheduler.new(world, state)
|
|
103
|
+
:insert(myPhase)
|
|
104
|
+
:addSystem(systemA, myPhase)
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Planck has lots of built-in Phases that should work for most cases,
|
|
108
|
+
→ [Built-in Phases](https://yetanotherclown.github.io/planck/docs/getting_started/phases#built-in-phases)
|
|
109
|
+
|
|
110
|
+
### Pipelines
|
|
111
|
+
|
|
112
|
+
Pipelines are ordered groups of Phases, they make working with larger collections of Phases (which all run on the same event) easier.
|
|
113
|
+
|
|
114
|
+
```luau
|
|
115
|
+
local Phase = Planck.Phase
|
|
116
|
+
local Pipeline = Planck.Pipeline
|
|
117
|
+
local Scheduler = Planck.Scheduler
|
|
118
|
+
|
|
119
|
+
local PreUpdate = Phase.new()
|
|
120
|
+
local Update = Phase.new()
|
|
121
|
+
local PostUpdate = Phase.new()
|
|
122
|
+
|
|
123
|
+
local UpdatePipeline = Pipeline.new()
|
|
124
|
+
:insert(PreUpdate)
|
|
125
|
+
:insert(Update)
|
|
126
|
+
:insert(PostUpdate)
|
|
127
|
+
|
|
128
|
+
local scheduler = scheduler.new(world)
|
|
129
|
+
:insert(UpdatePipeline, RunService, "Heartbeat")
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
> [!TIP]
|
|
133
|
+
> The `UpdatePipeline` seen here, already exists in Planck! It's a built-in Pipeline that you can use without any setup.
|
|
134
|
+
> See all [Built-in Phases](https://yetanotherclown.github.io/planck/docs/getting_started/phases#built-in-phases).
|
|
135
|
+
|
|
136
|
+
### Conditions
|
|
137
|
+
|
|
138
|
+
When we run all our systems every frame, there are a lot of systems that may not actually need to run. Run Conditions allow us to
|
|
139
|
+
run our Systems, Phases and Pipelines only sometimes.
|
|
140
|
+
|
|
141
|
+
```luau
|
|
142
|
+
local function condition(world)
|
|
143
|
+
if someCondition then
|
|
144
|
+
return true
|
|
145
|
+
else
|
|
146
|
+
return false
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
local scheduler = Scheduler.new(world)
|
|
151
|
+
:addRunCondition(systemA, condition)
|
|
152
|
+
:addRunCondition(somePhase, condition)
|
|
153
|
+
:addRunCondition(somePipeline, condition)
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
Conditions can be useful, but you should use them carefully. It's suggested that you read our page on
|
|
157
|
+
[Conditions](https://yetanotherclown.github.io/planck/docs/design/conditions) to see some useful examples and learn when you should use them.
|
|
158
|
+
|
|
159
|
+
## Inspiration
|
|
160
|
+
|
|
161
|
+
Planck's API design is heavily influenced by the [Bevy Engine](https://bevyengine.org/), with Schedules, RunConditions, and more.
|
|
162
|
+
Planck also draws inspiration from [Flecs](https://www.flecs.dev/) for Pipelines and Phases.
|
|
163
|
+
|
|
164
|
+
We're combining the simple, and beloved API of Bevy with the concept of Pipelines and Phases.
|
|
165
|
+
|
|
166
|
+
[Jecs]: https://ukendio.github.io/jecs
|
|
167
|
+
[Matter]: https://matter-ecs.github.io/matter
|
|
168
|
+
[ECR]: https://centau.github.io/ecr/
|
package/out/DependencyGraph.luau
CHANGED
|
@@ -1,6 +1,18 @@
|
|
|
1
1
|
local AdjacencyMatrix = {}
|
|
2
2
|
AdjacencyMatrix.__index = AdjacencyMatrix
|
|
3
3
|
|
|
4
|
+
export type AdjacencyMatrix = {
|
|
5
|
+
matrix: { { number } },
|
|
6
|
+
length: number,
|
|
7
|
+
width: number,
|
|
8
|
+
|
|
9
|
+
extend: (self: AdjacencyMatrix) -> (),
|
|
10
|
+
setEdge: (self: AdjacencyMatrix, i: number, j: number, v: number) -> (),
|
|
11
|
+
toAdjacencyList: (self: AdjacencyMatrix) -> { { number } },
|
|
12
|
+
topologicalSort: (self: AdjacencyMatrix) -> { number }?,
|
|
13
|
+
new: () -> AdjacencyMatrix,
|
|
14
|
+
}
|
|
15
|
+
|
|
4
16
|
function AdjacencyMatrix:__tostring()
|
|
5
17
|
local s = "\n"
|
|
6
18
|
|
|
@@ -97,14 +109,35 @@ function AdjacencyMatrix:topologicalSort(): { number }?
|
|
|
97
109
|
return result
|
|
98
110
|
end
|
|
99
111
|
|
|
100
|
-
function AdjacencyMatrix.new()
|
|
112
|
+
function AdjacencyMatrix.new(): AdjacencyMatrix
|
|
101
113
|
return setmetatable({
|
|
102
114
|
matrix = {},
|
|
103
115
|
length = 0,
|
|
104
116
|
width = 0,
|
|
105
|
-
}, AdjacencyMatrix)
|
|
117
|
+
}, AdjacencyMatrix) :: any
|
|
106
118
|
end
|
|
107
119
|
|
|
120
|
+
export type DependencyGraph<T> = {
|
|
121
|
+
nodes: { T },
|
|
122
|
+
matrix: AdjacencyMatrix,
|
|
123
|
+
length: number,
|
|
124
|
+
width: number,
|
|
125
|
+
|
|
126
|
+
getOrderedList: (self: DependencyGraph<T>) -> { T }?,
|
|
127
|
+
insert: (self: DependencyGraph<T>, node: T) -> DependencyGraph<T>,
|
|
128
|
+
insertAfter: (
|
|
129
|
+
self: DependencyGraph<T>,
|
|
130
|
+
node: T,
|
|
131
|
+
afterNode: T
|
|
132
|
+
) -> DependencyGraph<T>,
|
|
133
|
+
insertBefore: (
|
|
134
|
+
self: DependencyGraph<T>,
|
|
135
|
+
node: T,
|
|
136
|
+
beforeNode: T
|
|
137
|
+
) -> DependencyGraph<T>,
|
|
138
|
+
new: () -> DependencyGraph<T>,
|
|
139
|
+
}
|
|
140
|
+
|
|
108
141
|
local DependencyGraph = {}
|
|
109
142
|
DependencyGraph.__index = DependencyGraph
|
|
110
143
|
|
|
@@ -128,8 +161,12 @@ function DependencyGraph:insertBefore(node, beforeNode)
|
|
|
128
161
|
error("Node not found in DependencyGraph:insertBefore(_, unknown)")
|
|
129
162
|
end
|
|
130
163
|
|
|
131
|
-
table.
|
|
132
|
-
|
|
164
|
+
local j = table.find(self.nodes, node)
|
|
165
|
+
if not j then
|
|
166
|
+
table.insert(self.nodes, node)
|
|
167
|
+
j = #self.nodes
|
|
168
|
+
end
|
|
169
|
+
|
|
133
170
|
local i = table.find(self.nodes, beforeNode)
|
|
134
171
|
|
|
135
172
|
self.matrix:extend()
|
|
@@ -143,9 +180,12 @@ function DependencyGraph:insertAfter(node, afterNode)
|
|
|
143
180
|
error("Node not found in DependencyGraph:insertAfter(_, unknown)")
|
|
144
181
|
end
|
|
145
182
|
|
|
146
|
-
table.
|
|
183
|
+
local j = table.find(self.nodes, node)
|
|
184
|
+
if not j then
|
|
185
|
+
table.insert(self.nodes, node)
|
|
186
|
+
j = #self.nodes
|
|
187
|
+
end
|
|
147
188
|
|
|
148
|
-
local j = #self.nodes
|
|
149
189
|
local i = table.find(self.nodes, afterNode)
|
|
150
190
|
|
|
151
191
|
self.matrix:extend()
|
|
@@ -168,13 +208,13 @@ function DependencyGraph:insert(node)
|
|
|
168
208
|
return self
|
|
169
209
|
end
|
|
170
210
|
|
|
171
|
-
function DependencyGraph.new()
|
|
211
|
+
function DependencyGraph.new<T>(): DependencyGraph<T>
|
|
172
212
|
return setmetatable({
|
|
173
213
|
nodes = {},
|
|
174
214
|
matrix = AdjacencyMatrix.new(),
|
|
175
215
|
length = 0,
|
|
176
216
|
width = 0,
|
|
177
|
-
}, DependencyGraph)
|
|
217
|
+
}, DependencyGraph) :: any
|
|
178
218
|
end
|
|
179
219
|
|
|
180
|
-
return DependencyGraph
|
|
220
|
+
return DependencyGraph
|
package/out/Phase.d.ts
CHANGED
|
@@ -1,8 +1,21 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Phases represent tags that tell the scheduler when to
|
|
3
|
+
* schedule a set of systems.
|
|
4
|
+
*/
|
|
5
|
+
export class Phase {
|
|
6
|
+
/** Runs before the `Startup` Phase. */
|
|
7
|
+
static PreStartup: Phase;
|
|
8
|
+
/**
|
|
9
|
+
* This Phase will run once, the first time the Scheduler is ran,
|
|
10
|
+
* before any other Phases are ran.
|
|
11
|
+
*/
|
|
12
|
+
static Startup: Phase;
|
|
13
|
+
/** Runs after the `Startup` phase. */
|
|
14
|
+
static PostStartup: Phase;
|
|
7
15
|
|
|
8
|
-
|
|
16
|
+
/**
|
|
17
|
+
* Creates a new Phase, with an optional name to use for debugging.
|
|
18
|
+
* When no name is provided, the script and line number will be used.
|
|
19
|
+
*/
|
|
20
|
+
constructor(name?: string);
|
|
21
|
+
}
|
package/out/Phase.luau
CHANGED
package/out/Pipeline.d.ts
CHANGED
|
@@ -1,11 +1,24 @@
|
|
|
1
|
-
import Phase from "./Phase";
|
|
1
|
+
import { Phase } from "./Phase";
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
3
|
+
/**
|
|
4
|
+
* Pipelines represent a set of ordered Phases. Systems cannot be
|
|
5
|
+
* assigned to Pipelines themselves, but rather to Phases within
|
|
6
|
+
* those Pipelines.
|
|
7
|
+
*/
|
|
8
|
+
export class Pipeline {
|
|
9
|
+
/** A Pipeline containing the `PreStartup`, `Startup`, and `PostStartup` phases. */
|
|
10
|
+
static Startup: Pipeline;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Creates a new Pipeline, with an optional name to use for debugging.
|
|
14
|
+
* When no name is provided, the script and line number will be used.
|
|
15
|
+
*/
|
|
16
|
+
constructor(name?: string);
|
|
10
17
|
|
|
11
|
-
|
|
18
|
+
/** Adds a Phase to the Pipeline, ordering it implicitly. */
|
|
19
|
+
insert(phase: Phase): this;
|
|
20
|
+
/** Adds a Phase to the Pipeline after another Phase, ordering it explicitly. */
|
|
21
|
+
insertAfter(phase: Phase, after: Phase): this;
|
|
22
|
+
/** Adds a Phase to the Pipeline before another Phase, ordering it explicitly. */
|
|
23
|
+
insertBefore(phase: Phase, before: Phase): this;
|
|
24
|
+
}
|
package/out/Pipeline.luau
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
--!nonstrict
|
|
2
|
-
local DependencyGraph = require(
|
|
3
|
-
local Phase = require(
|
|
2
|
+
local DependencyGraph = require(script.Parent.DependencyGraph)
|
|
3
|
+
local Phase = require(script.Parent.Phase)
|
|
4
4
|
|
|
5
5
|
--- @class Pipeline
|
|
6
6
|
---
|
|
@@ -83,4 +83,4 @@ Pipeline.Startup = Pipeline.new()
|
|
|
83
83
|
:insert(Phase.Startup)
|
|
84
84
|
:insert(Phase.PostStartup)
|
|
85
85
|
|
|
86
|
-
return Pipeline
|
|
86
|
+
return Pipeline
|
package/out/Scheduler.d.ts
CHANGED
|
@@ -1,31 +1,209 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
addSystem(system: System<T>, phase?: Phase): Scheduler<T>
|
|
15
|
-
addSystems(systems: System<T>[], phase?: Phase): Scheduler<T>
|
|
16
|
-
insertBefore(dependent: Phase, before: Phase): Scheduler<T>
|
|
17
|
-
insertBefore(dependent: Pipeline, before: Phase): Scheduler<T>
|
|
18
|
-
insertAfter(phase: Phase, after: Phase | Pipeline): Scheduler<T>
|
|
19
|
-
insertAfter(pipeline: Pipeline, after: Phase | Pipeline): Scheduler<T>
|
|
20
|
-
insert(dependent: Phase | Pipeline, instance: EventInstance, event?: string): Scheduler<T>
|
|
21
|
-
insert(dependent: Phase | Pipeline): Scheduler<T>
|
|
22
|
-
runAll(): Scheduler<T>
|
|
23
|
-
run(dependent: System<T> | Phase | Pipeline): Scheduler<T>
|
|
24
|
-
getDeltaTime(): number
|
|
25
|
-
addPlugin(plugin: Plugin): Scheduler<T>
|
|
26
|
-
/** @hidden */
|
|
27
|
-
_addHook<K extends keyof HookFunctionMap>(hook: K, fn: (info: HookFunctionArgs<K, T>) => void): void
|
|
28
|
-
constructor(...args: T)
|
|
1
|
+
import { Plugin } from ".";
|
|
2
|
+
import { Condition } from "./conditions";
|
|
3
|
+
import { Phase } from "./Phase";
|
|
4
|
+
import { Pipeline } from "./Pipeline";
|
|
5
|
+
import { EventInstance, EventLike, ExtractEvents } from "./utils";
|
|
6
|
+
|
|
7
|
+
export type SystemFn<T extends unknown[]> = (...args: T) => any;
|
|
8
|
+
export interface SystemTable<T extends unknown[]> {
|
|
9
|
+
system: SystemFn<T>;
|
|
10
|
+
phase?: Phase;
|
|
11
|
+
name?: string;
|
|
12
|
+
runConditions?: Condition<T>[];
|
|
13
|
+
[key: string]: any;
|
|
29
14
|
}
|
|
15
|
+
export type System<T extends unknown[]> = SystemTable<T> | SystemFn<T>;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* An Object which handles scheduling Systems to run within different
|
|
19
|
+
* Phases. The order of which Systems run will be defined either
|
|
20
|
+
* implicitly by when it was added, or explicitly by tagging the system
|
|
21
|
+
* with a Phase.
|
|
22
|
+
*/
|
|
23
|
+
export class Scheduler<T extends unknown[]> {
|
|
24
|
+
/**
|
|
25
|
+
* Creates a new Scheduler, the args passed will be passed to
|
|
26
|
+
* any System anytime it is ran by the Scheduler.
|
|
27
|
+
*/
|
|
28
|
+
constructor(...args: T);
|
|
29
|
+
|
|
30
|
+
/** Initializes a plugin with the scheduler, see the [Plugin Docs](/docs/plugins) for more information. */
|
|
31
|
+
addPlugin(plugin: Plugin<T>): this;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Adds the System to the Scheduler, scheduling it to be ran
|
|
35
|
+
* implicitly within the provided Phase or on the default Main phase.
|
|
36
|
+
*/
|
|
37
|
+
addSystem(system: System<T>, phase?: Phase): this;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Adds the Systems to the Scheduler, scheduling them to be ran
|
|
41
|
+
* implicitly within the provided Phase or on the default Main phase.
|
|
42
|
+
*/
|
|
43
|
+
addSystems(systems: System<T>[], phase?: Phase): this;
|
|
44
|
+
|
|
45
|
+
/** Changes the Phase that this system is scheduled on. */
|
|
46
|
+
editSystem(system: System<T>, newPhase: Phase): this;
|
|
47
|
+
|
|
48
|
+
/** Removes the System from the Scheduler. */
|
|
49
|
+
removeSystem(system: System<T>): this;
|
|
50
|
+
|
|
51
|
+
/** Replaces the System with a new System. */
|
|
52
|
+
replaceSystem(system: System<T>, newSystem: System<T>): this;
|
|
30
53
|
|
|
31
|
-
|
|
54
|
+
/**
|
|
55
|
+
* Returns the time since the system was ran last.
|
|
56
|
+
* This must be used within a registered system.
|
|
57
|
+
*/
|
|
58
|
+
getDeltaTime(): number;
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Initializes the Phase within the Scheduler, ordering it implicitly by
|
|
62
|
+
* setting it as a dependent of the previous Phase/Pipeline.
|
|
63
|
+
*/
|
|
64
|
+
insert(phase: Phase): this;
|
|
65
|
+
/**
|
|
66
|
+
* Initializes the Pipeline and it's Phases within the Scheduler,
|
|
67
|
+
* ordering the Pipeline implicitly by setting it as a dependent
|
|
68
|
+
* of the previous Phase/Pipeline.
|
|
69
|
+
*/
|
|
70
|
+
insert(pipeline: Pipeline): this;
|
|
71
|
+
/**
|
|
72
|
+
* Initializes the Phase within the Scheduler, ordering it implicitly
|
|
73
|
+
* by setting it as a dependent of the previous Phase/Pipeline, and
|
|
74
|
+
* scheduling it to be ran on the specified event.
|
|
75
|
+
*
|
|
76
|
+
* ```ts
|
|
77
|
+
* const myScheduler = new Scheduler()
|
|
78
|
+
* .insert(myPhase, RunService, "Heartbeat")
|
|
79
|
+
* ```
|
|
80
|
+
*/
|
|
81
|
+
insert<T extends EventInstance>(
|
|
82
|
+
phase: Phase,
|
|
83
|
+
instance: T,
|
|
84
|
+
event: ExtractEvents<T>
|
|
85
|
+
): this;
|
|
86
|
+
/**
|
|
87
|
+
* Initializes the Phase within the Scheduler, ordering it implicitly
|
|
88
|
+
* by setting it as a dependent of the previous Phase/Pipeline, and
|
|
89
|
+
* scheduling it to be ran on the specified event.
|
|
90
|
+
*
|
|
91
|
+
* ```ts
|
|
92
|
+
* const myScheduler = new Scheduler()
|
|
93
|
+
* .insert(myPhase, RunService, "Heartbeat")
|
|
94
|
+
* ```
|
|
95
|
+
*/
|
|
96
|
+
insert(phase: Phase, instance: EventLike, event: string): this;
|
|
97
|
+
/**
|
|
98
|
+
* Initializes the Pipeline and it's Phases within the Scheduler,
|
|
99
|
+
* ordering the Pipeline implicitly by setting it as a dependent of
|
|
100
|
+
* the previous Phase/Pipeline, and scheduling it to be ran on the
|
|
101
|
+
* specified event.
|
|
102
|
+
*
|
|
103
|
+
* ```ts
|
|
104
|
+
* const myScheduler = new Scheduler()
|
|
105
|
+
* .insert(myPipeline, RunService, "Heartbeat")
|
|
106
|
+
* ```
|
|
107
|
+
*/
|
|
108
|
+
insert<T extends EventInstance>(
|
|
109
|
+
pipeline: Pipeline,
|
|
110
|
+
instance: T,
|
|
111
|
+
event: ExtractEvents<T>
|
|
112
|
+
): this;
|
|
113
|
+
/**
|
|
114
|
+
* Initializes the Pipeline and it's Phases within the Scheduler,
|
|
115
|
+
* ordering the Pipeline implicitly by setting it as a dependent of
|
|
116
|
+
* the previous Phase/Pipeline, and scheduling it to be ran on the
|
|
117
|
+
* specified event.
|
|
118
|
+
*
|
|
119
|
+
* ```ts
|
|
120
|
+
* const myScheduler = new Scheduler()
|
|
121
|
+
* .insert(myPipeline, RunService, "Heartbeat")
|
|
122
|
+
* ```
|
|
123
|
+
*/
|
|
124
|
+
insert(pipeline: Pipeline, instance: EventLike, event: string): this;
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Initializes the Phase within the Scheduler, ordering it
|
|
128
|
+
* explicitly by setting the after Phase/Pipeline as a dependent.
|
|
129
|
+
*/
|
|
130
|
+
insertAfter(phase: Phase, after: Phase | Pipeline): this;
|
|
131
|
+
/**
|
|
132
|
+
* Initializes the Pipeline and it's Phases within the Scheduler,
|
|
133
|
+
* ordering the Pipeline explicitly by setting the after Phase/Pipeline
|
|
134
|
+
* as a dependent.
|
|
135
|
+
*/
|
|
136
|
+
insertAfter(pipeline: Pipeline, after: Phase | Pipeline): this;
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Initializes the Phase within the Scheduler, ordering it
|
|
140
|
+
* explicitly by setting the before Phase/Pipeline as a dependency.
|
|
141
|
+
*/
|
|
142
|
+
insertBefore(phase: Phase, before: Phase | Pipeline): this;
|
|
143
|
+
/**
|
|
144
|
+
* Initializes the Pipeline and it's Phases within the Scheduler,
|
|
145
|
+
* ordering the Pipeline explicitly by setting the before Phase/Pipeline
|
|
146
|
+
* as a dependency.
|
|
147
|
+
*/
|
|
148
|
+
insertBefore(pipeline: Pipeline, before: Phase | Pipeline): this;
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Adds a Run Condition which the Scheduler will check before
|
|
152
|
+
* this System is ran.
|
|
153
|
+
*/
|
|
154
|
+
addRunCondition(system: System<T>, fn: Condition<T>, ...args: any): this;
|
|
155
|
+
/**
|
|
156
|
+
* Adds a Run Condition which the Scheduler will check before
|
|
157
|
+
* any Systems within this Phase are ran.
|
|
158
|
+
*/
|
|
159
|
+
addRunCondition(phase: Phase, fn: Condition<T>, ...args: any): this;
|
|
160
|
+
/**
|
|
161
|
+
* Adds a Run Condition which the Scheduler will check before
|
|
162
|
+
* any Systems within any Phases apart of this Pipeline are ran.
|
|
163
|
+
*/
|
|
164
|
+
addRunCondition(pipeline: Pipeline, fn: Condition<T>, ...args: any): this;
|
|
165
|
+
|
|
166
|
+
/** Runs all Systems tagged with the Phase in order. */
|
|
167
|
+
run(system: Phase): this;
|
|
168
|
+
/** Runs all Systems tagged with any Phase within the Pipeline in order. */
|
|
169
|
+
run(pipeline: Pipeline): this;
|
|
170
|
+
/** Runs the System, passing in the arguments of the Scheduler, `U...`. */
|
|
171
|
+
run(system: System<T>): this;
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Runs all Systems within order.
|
|
175
|
+
*
|
|
176
|
+
* ### NOTE
|
|
177
|
+
*
|
|
178
|
+
* When you add a Pipeline or Phase with an event, it will be grouped
|
|
179
|
+
* with other Pipelines/Phases on that event. Otherwise, it will be
|
|
180
|
+
* added to the default group.
|
|
181
|
+
*
|
|
182
|
+
* When not running systems on Events, such as with the `runAll` method,
|
|
183
|
+
* the Default group will be ran first, and then each Event Group in the
|
|
184
|
+
* order created.
|
|
185
|
+
*
|
|
186
|
+
* Pipelines/Phases in these groups are still ordered by their dependencies
|
|
187
|
+
* and by the order of insertion.
|
|
188
|
+
*/
|
|
189
|
+
runAll(): this;
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Disconnects all events, closes all threads, and performs
|
|
193
|
+
* other cleanup work.
|
|
194
|
+
*
|
|
195
|
+
* ### Danger
|
|
196
|
+
* Only use this if you intend to not use the associated
|
|
197
|
+
* Scheduler anymore. It will not work as intended.
|
|
198
|
+
*
|
|
199
|
+
* You should dereference the scheduler object so that
|
|
200
|
+
* it may be garbage collected.
|
|
201
|
+
*
|
|
202
|
+
* ### Warning
|
|
203
|
+
* If you're creating a "throwaway" scheduler, you should
|
|
204
|
+
* not add plugins like Jabby or the Matter Debugger to it.
|
|
205
|
+
* These plugins are unable to properly be cleaned up, use
|
|
206
|
+
* them with caution.
|
|
207
|
+
*/
|
|
208
|
+
cleanup(): void;
|
|
209
|
+
}
|
package/out/Scheduler.luau
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
--!nonstrict
|
|
2
|
-
local DependencyGraph = require(
|
|
3
|
-
local Pipeline = require(
|
|
4
|
-
local Phase = require(
|
|
2
|
+
local DependencyGraph = require(script.Parent.DependencyGraph)
|
|
3
|
+
local Pipeline = require(script.Parent.Pipeline)
|
|
4
|
+
local Phase = require(script.Parent.Phase)
|
|
5
5
|
|
|
6
|
-
local utils = require(
|
|
7
|
-
local hooks = require(
|
|
8
|
-
local conditions = require(
|
|
6
|
+
local utils = require(script.Parent.utils)
|
|
7
|
+
local hooks = require(script.Parent.hooks)
|
|
8
|
+
local conditions = require(script.Parent.conditions)
|
|
9
9
|
|
|
10
10
|
local getSystem = utils.getSystem
|
|
11
11
|
local getSystemName = utils.getSystemName
|
|
@@ -903,4 +903,4 @@ function Scheduler.new(...)
|
|
|
903
903
|
return self
|
|
904
904
|
end
|
|
905
905
|
|
|
906
|
-
return Scheduler
|
|
906
|
+
return Scheduler
|
package/out/conditions.d.ts
CHANGED
|
@@ -1,14 +1,63 @@
|
|
|
1
|
-
import { EventInstance, EventLike } from "./
|
|
1
|
+
import { EventInstance, EventLike, ExtractEvents } from "./utils";
|
|
2
2
|
|
|
3
|
-
type Condition =
|
|
3
|
+
export type Condition<T extends unknown[] = unknown[]> = (
|
|
4
|
+
...args: T
|
|
5
|
+
) => boolean;
|
|
4
6
|
|
|
5
|
-
|
|
7
|
+
/**
|
|
8
|
+
* A Throttle condition which checks whether the amount of
|
|
9
|
+
* time given has passed or not.
|
|
10
|
+
*/
|
|
11
|
+
export const timePassed: (time: number) => Condition;
|
|
6
12
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
}
|
|
14
|
-
|
|
13
|
+
/** Checks whether the condition has been called once before. */
|
|
14
|
+
export const runOnce: () => Condition;
|
|
15
|
+
|
|
16
|
+
type ExtractEventArgs<T> = T extends EventLike<infer U> ? U : never;
|
|
17
|
+
type ExtractEvent<T extends EventInstance> = {
|
|
18
|
+
[K in keyof T]: T[K] extends EventLike ? ExtractEventArgs<T[K]> : never;
|
|
19
|
+
};
|
|
20
|
+
type CollectEvents<T extends unknown[]> = () => IterableFunction<
|
|
21
|
+
LuaTuple<[number, ...T]>
|
|
22
|
+
>;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Checks for any new events and allows for the collection of those events.
|
|
26
|
+
*
|
|
27
|
+
* Read [OnEvent](https://yetanotherclown.github.io/planck/docs/design/conditions/#on-event) for more information.
|
|
28
|
+
*/
|
|
29
|
+
export function onEvent<T extends EventInstance, E extends ExtractEvents<T>>(
|
|
30
|
+
instance: T,
|
|
31
|
+
event: E
|
|
32
|
+
): LuaTuple<
|
|
33
|
+
[hasNewEvent: Condition, collectEvents: CollectEvents<ExtractEvent<T>[E]>]
|
|
34
|
+
>;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Checks for any new events and allows for the collection of those events.
|
|
38
|
+
*
|
|
39
|
+
* Read [OnEvent](https://yetanotherclown.github.io/planck/docs/design/conditions/#on-event) for more information.
|
|
40
|
+
*/
|
|
41
|
+
export function onEvent<T extends EventLike>(
|
|
42
|
+
instance: EventInstance,
|
|
43
|
+
event: T
|
|
44
|
+
): LuaTuple<
|
|
45
|
+
[hasNewEvent: Condition, collectEvents: CollectEvents<ExtractEventArgs<T>>]
|
|
46
|
+
>;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Checks for any new events and allows for the collection of those events.
|
|
50
|
+
*
|
|
51
|
+
* Read [OnEvent](https://yetanotherclown.github.io/planck/docs/design/conditions/#on-event) for more information.
|
|
52
|
+
*/
|
|
53
|
+
export function onEvent<T extends EventLike>(
|
|
54
|
+
instance: T
|
|
55
|
+
): LuaTuple<
|
|
56
|
+
[hasNewEvent: Condition, collectEvents: CollectEvents<ExtractEventArgs<T>>]
|
|
57
|
+
>;
|
|
58
|
+
|
|
59
|
+
/** Inverses a given condition. */
|
|
60
|
+
export const isNot: <T extends unknown[]>(
|
|
61
|
+
fn: Condition<T>,
|
|
62
|
+
...any: any[]
|
|
63
|
+
) => Condition<T>;
|
package/out/conditions.luau
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
local utils = require(
|
|
1
|
+
local utils = require(script.Parent.utils)
|
|
2
2
|
local getConnectFunction = utils.getConnectFunction
|
|
3
3
|
|
|
4
|
-
type
|
|
5
|
-
type
|
|
4
|
+
type GenericTable = utils.GenericTable
|
|
5
|
+
type SignalLike<U...> = utils.SignalLike<U...>
|
|
6
6
|
type ConnectionLike = utils.ConnectionLike
|
|
7
|
+
type ConnectFn<T, U...> = utils.ConnectFn<T, U...>
|
|
8
|
+
type Callback<U...> = utils.Callback<U...>
|
|
7
9
|
|
|
8
10
|
type Condition = () -> boolean
|
|
9
11
|
|
|
@@ -59,16 +61,52 @@ local function cleanupCondition(condition: Condition)
|
|
|
59
61
|
end
|
|
60
62
|
end
|
|
61
63
|
|
|
64
|
+
type GetDisconnectFn = () -> () -> ()
|
|
65
|
+
|
|
66
|
+
type OnEventFn =
|
|
67
|
+
-- RBXScriptSignal & nil
|
|
68
|
+
(<U...>(
|
|
69
|
+
RBXScriptSignal<U...>
|
|
70
|
+
) -> (Condition, CollectEvents<U...>, GetDisconnectFn))
|
|
71
|
+
-- Instance & RBXScriptSignal
|
|
72
|
+
-- Instance & string
|
|
73
|
+
& (<U...>(
|
|
74
|
+
Instance,
|
|
75
|
+
RBXScriptSignal<U...> | string
|
|
76
|
+
) -> (Condition, CollectEvents<U...>, GetDisconnectFn))
|
|
77
|
+
-- SignalLike & nil
|
|
78
|
+
& (<U...>(
|
|
79
|
+
SignalLike<U...>
|
|
80
|
+
) -> (Condition, CollectEvents<U...>, GetDisconnectFn))
|
|
81
|
+
-- table & string
|
|
82
|
+
& (<U...>(
|
|
83
|
+
GenericTable,
|
|
84
|
+
string
|
|
85
|
+
) -> (Condition, CollectEvents<U...>, GetDisconnectFn))
|
|
86
|
+
-- table & connectable method
|
|
87
|
+
& (<T, U...>(
|
|
88
|
+
GenericTable,
|
|
89
|
+
(GenericTable, Callback<U...>, ...any) -> T?
|
|
90
|
+
) -> (Condition, CollectEvents<U...>, GetDisconnectFn))
|
|
91
|
+
-- connectable function
|
|
92
|
+
& (<T, U...>(
|
|
93
|
+
(Callback<U...>, ...any) -> T?
|
|
94
|
+
) -> (Condition, CollectEvents<U...>, GetDisconnectFn))
|
|
95
|
+
|
|
62
96
|
--- @within Conditions
|
|
97
|
+
--- @param instance RBXScriptSignal | Instance | SignalLike<...any> | GenericTable | ((Callback<U...>,...any) -> ...any)
|
|
98
|
+
--- @param event (RBXScriptSignal | string | (...any) -> ())?
|
|
63
99
|
--- @return hasNewEvent () -> boolean
|
|
64
100
|
--- @return collectEvents () -> () -> (number, U...)
|
|
65
101
|
--- @return getDisconnectFn () -> () -> ()
|
|
66
102
|
---
|
|
67
103
|
--- Checks for any new events and allows for the collection of
|
|
68
|
-
--- those events
|
|
104
|
+
--- those events.\
|
|
105
|
+
--- \
|
|
106
|
+
--- Read [OnEvent](../docs/design/conditions#on-event) for more information.
|
|
69
107
|
local function onEvent<U...>(
|
|
70
|
-
instance
|
|
71
|
-
event
|
|
108
|
+
instance,
|
|
109
|
+
event
|
|
72
110
|
): (Condition, CollectEvents<U...>, () -> () -> ())
|
|
73
111
|
local connect = getConnectFunction(instance, event)
|
|
74
112
|
assert(connect, "Event passed to .onEvent is not valid")
|
|
@@ -144,8 +182,8 @@ end
|
|
|
144
182
|
return {
|
|
145
183
|
timePassed = timePassed,
|
|
146
184
|
runOnce = runOnce,
|
|
147
|
-
onEvent = onEvent,
|
|
185
|
+
onEvent = onEvent :: OnEventFn,
|
|
148
186
|
isNot = isNot,
|
|
149
187
|
|
|
150
188
|
cleanupCondition = cleanupCondition,
|
|
151
|
-
}
|
|
189
|
+
}
|
package/out/hooks.luau
CHANGED
|
@@ -47,7 +47,7 @@ local function systemReplace(scheduler, oldSystemInfo, newSystemInfo)
|
|
|
47
47
|
end
|
|
48
48
|
|
|
49
49
|
local function systemCall(scheduler, hookName, systemInfo, nextFn)
|
|
50
|
-
local hooks = scheduler._hooks[scheduler.Hooks[hookName]
|
|
50
|
+
local hooks = scheduler._hooks[scheduler.Hooks[hookName]]
|
|
51
51
|
|
|
52
52
|
if hooks then
|
|
53
53
|
for _, hook in hooks do
|
|
@@ -70,7 +70,7 @@ local function systemCall(scheduler, hookName, systemInfo, nextFn)
|
|
|
70
70
|
end
|
|
71
71
|
|
|
72
72
|
local function systemError(scheduler, systemInfo, err)
|
|
73
|
-
local hooks = scheduler._hooks[scheduler.Hooks["SystemError"]
|
|
73
|
+
local hooks = scheduler._hooks[scheduler.Hooks["SystemError"]]
|
|
74
74
|
|
|
75
75
|
if hooks then
|
|
76
76
|
for _, hook in hooks do
|
|
@@ -85,7 +85,7 @@ end
|
|
|
85
85
|
|
|
86
86
|
type PhaseAdd = {
|
|
87
87
|
scheduler: any,
|
|
88
|
-
phase: any
|
|
88
|
+
phase: any,
|
|
89
89
|
}
|
|
90
90
|
|
|
91
91
|
local function phaseAdd(scheduler, phase)
|
package/out/index.d.ts
CHANGED
|
@@ -1,18 +1,12 @@
|
|
|
1
|
-
import
|
|
2
|
-
import pipeline from "./Pipeline";
|
|
3
|
-
import schedular from "./Scheduler";
|
|
4
|
-
import condition from "./conditions"
|
|
1
|
+
import { Scheduler } from "./Scheduler";
|
|
5
2
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
3
|
+
export * from "./conditions";
|
|
4
|
+
export * from "./Phase";
|
|
5
|
+
export * from "./Pipeline";
|
|
6
|
+
export * from "./Scheduler";
|
|
10
7
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
8
|
+
export interface Plugin<T extends unknown[]> {
|
|
9
|
+
build(scheduler: Scheduler<T>): void;
|
|
10
|
+
cleanup?(): void;
|
|
11
|
+
[key: string | number | symbol]: any;
|
|
15
12
|
}
|
|
16
|
-
|
|
17
|
-
declare const planck: Planck;
|
|
18
|
-
export = planck;
|
package/out/init.luau
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
|
-
local Phase = require(script
|
|
2
|
-
local Pipeline = require(script
|
|
3
|
-
local Scheduler = require(script
|
|
1
|
+
local Phase = require(script.Phase) :: any
|
|
2
|
+
local Pipeline = require(script.Pipeline) :: any
|
|
3
|
+
local Scheduler = require(script.Scheduler) :: any
|
|
4
4
|
|
|
5
|
-
local conditions = require(script
|
|
6
|
-
local utils = require(script
|
|
5
|
+
local conditions = require(script.conditions)
|
|
6
|
+
local utils = require(script.utils)
|
|
7
7
|
|
|
8
|
-
type
|
|
9
|
-
type
|
|
8
|
+
type GenericTable = utils.GenericTable
|
|
9
|
+
type SignalLike<U...> = utils.SignalLike<U...>
|
|
10
|
+
type ConnectionLike = utils.ConnectionLike
|
|
11
|
+
type ConnectFn<T, U...> = utils.ConnectFn<T, U...>
|
|
12
|
+
type Callback<U...> = utils.Callback<U...>
|
|
10
13
|
|
|
11
14
|
export type SystemFn<U...> = ((U...) -> any) | ((U...) -> ())
|
|
12
15
|
|
|
@@ -38,7 +41,10 @@ export type Pipeline = {
|
|
|
38
41
|
|
|
39
42
|
type Plugin<U...> = {
|
|
40
43
|
build: (self: Plugin<U...>, scheduler: Scheduler<U...>) -> (),
|
|
41
|
-
|
|
44
|
+
[any]: any,
|
|
45
|
+
} | {
|
|
46
|
+
build: (self: Plugin<U...>, scheduler: Scheduler<U...>) -> (),
|
|
47
|
+
cleanup: (self: Plugin<U...>) -> (),
|
|
42
48
|
[any]: any,
|
|
43
49
|
}
|
|
44
50
|
|
|
@@ -99,29 +105,69 @@ export type Scheduler<U...> = {
|
|
|
99
105
|
|
|
100
106
|
getDeltaTime: (self: Scheduler<U...>) -> number,
|
|
101
107
|
|
|
102
|
-
insert: ((
|
|
108
|
+
insert: ((
|
|
103
109
|
self: Scheduler<U...>,
|
|
104
|
-
|
|
105
|
-
) -> Scheduler<U...>)
|
|
110
|
+
dependency: Phase | Pipeline
|
|
111
|
+
) -> Scheduler<U...>)
|
|
112
|
+
-- RBXScriptSignal & nil
|
|
113
|
+
& ((
|
|
114
|
+
self: Scheduler<U...>,
|
|
115
|
+
dependency: Phase | Pipeline,
|
|
116
|
+
signal: RBXScriptSignal<U...>
|
|
117
|
+
) -> Scheduler<U...>)
|
|
118
|
+
-- Instance & RBXScriptSignal
|
|
119
|
+
-- Instance & string
|
|
120
|
+
& ((
|
|
121
|
+
self: Scheduler<U...>,
|
|
122
|
+
dependency: Phase | Pipeline,
|
|
123
|
+
instance: Instance,
|
|
124
|
+
event: RBXScriptSignal<U...> | string
|
|
125
|
+
) -> Scheduler<U...>)
|
|
126
|
+
-- SignalLike & nil
|
|
127
|
+
& ((
|
|
128
|
+
self: Scheduler<U...>,
|
|
129
|
+
dependency: Phase | Pipeline,
|
|
130
|
+
signal: SignalLike<U...>
|
|
131
|
+
) -> Scheduler<U...>)
|
|
132
|
+
-- table & string
|
|
133
|
+
& ((
|
|
134
|
+
self: Scheduler<U...>,
|
|
135
|
+
dependency: Phase | Pipeline,
|
|
136
|
+
table: GenericTable,
|
|
137
|
+
event: string
|
|
138
|
+
) -> Scheduler<U...>)
|
|
139
|
+
-- table & connectable method
|
|
140
|
+
& (<T>(
|
|
141
|
+
self: Scheduler<U...>,
|
|
142
|
+
dependency: Phase | Pipeline,
|
|
143
|
+
instance: GenericTable,
|
|
144
|
+
connectMethod: (GenericTable, Callback<U...>, ...any) -> T
|
|
145
|
+
) -> Scheduler<U...>)
|
|
146
|
+
-- connectable function
|
|
147
|
+
& (<T>(
|
|
148
|
+
self: Scheduler<U...>,
|
|
149
|
+
dependency: Phase | Pipeline,
|
|
150
|
+
connectFn: (Callback<U...>, ...any) -> T
|
|
151
|
+
) -> Scheduler<U...>),
|
|
152
|
+
|
|
153
|
+
insertAfter: ((
|
|
106
154
|
self: Scheduler<U...>,
|
|
107
155
|
phase: Phase,
|
|
108
|
-
|
|
109
|
-
event: string | EventLike
|
|
156
|
+
after: Phase | Pipeline
|
|
110
157
|
) -> Scheduler<U...>) & ((
|
|
111
158
|
self: Scheduler<U...>,
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
event: string | EventLike
|
|
159
|
+
pipeline: Pipeline,
|
|
160
|
+
after: Phase | Pipeline
|
|
115
161
|
) -> Scheduler<U...>),
|
|
116
162
|
|
|
117
|
-
|
|
163
|
+
insertBefore: ((
|
|
118
164
|
self: Scheduler<U...>,
|
|
119
165
|
phase: Phase,
|
|
120
|
-
|
|
166
|
+
before: Phase | Pipeline
|
|
121
167
|
) -> Scheduler<U...>) & ((
|
|
122
168
|
self: Scheduler<U...>,
|
|
123
169
|
pipeline: Pipeline,
|
|
124
|
-
|
|
170
|
+
before: Phase | Pipeline
|
|
125
171
|
) -> Scheduler<U...>),
|
|
126
172
|
|
|
127
173
|
cleanup: (self: Scheduler<U...>) -> (),
|
package/out/utils.d.ts
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
|
|
1
|
+
export type EventLike<T extends unknown[] = unknown[]> =
|
|
2
|
+
| RBXScriptSignal<(...args: T) => void>
|
|
3
|
+
| { connect(...args: T): unknown }
|
|
4
|
+
| { Connect(...args: T): unknown }
|
|
5
|
+
| { on(...args: T): unknown };
|
|
6
|
+
export type EventInstance = Instance | { [k: string]: EventLike };
|
|
2
7
|
|
|
3
|
-
|
|
4
|
-
|
|
8
|
+
export type ExtractEvents<T extends EventInstance> = {
|
|
9
|
+
[K in keyof T]: T[K] extends EventLike ? K : never;
|
|
10
|
+
}[keyof T];
|
package/out/utils.luau
CHANGED
|
@@ -53,21 +53,6 @@ end
|
|
|
53
53
|
|
|
54
54
|
local EVENT_CONNECT_METHODS = { "Connect", "On", "on", "connect" }
|
|
55
55
|
|
|
56
|
-
export type EventLike = RBXScriptSignal | {
|
|
57
|
-
connect: (self: EventLike, ...any) -> any,
|
|
58
|
-
[any]: any,
|
|
59
|
-
} | {
|
|
60
|
-
Connect: (self: EventLike, ...any) -> any,
|
|
61
|
-
[any]: any,
|
|
62
|
-
} | {
|
|
63
|
-
on: (self: EventLike, ...any) -> any,
|
|
64
|
-
[any]: any,
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
export type EventInstance = Instance | {
|
|
68
|
-
[any]: EventLike,
|
|
69
|
-
}
|
|
70
|
-
|
|
71
56
|
export type ConnectionLike = RBXScriptConnection | {
|
|
72
57
|
disconnect: (self: ConnectionLike, ...any) -> any,
|
|
73
58
|
[any]: any,
|
|
@@ -82,8 +67,6 @@ export type ConnectionLike = RBXScriptConnection | {
|
|
|
82
67
|
[any]: any,
|
|
83
68
|
} | (...any) -> any
|
|
84
69
|
|
|
85
|
-
export type ConnectFn<U...> = (callback: (U...) -> ()) -> ConnectionLike
|
|
86
|
-
|
|
87
70
|
local EVENT_DISCONNECT_METHODS =
|
|
88
71
|
{ "disconnect", "Disconnect", "destroy", "Destroy" }
|
|
89
72
|
|
|
@@ -107,13 +90,49 @@ local function disconnectEvent(connection: ConnectionLike)
|
|
|
107
90
|
end
|
|
108
91
|
end
|
|
109
92
|
|
|
93
|
+
export type Callback<U...> = (U...) -> ...any
|
|
94
|
+
export type ConnectFn<T, U...> = (callback: (U...) -> ...any) -> T
|
|
95
|
+
export type GenericTable = { [any]: any }
|
|
96
|
+
|
|
97
|
+
export type SignalLike<U...> = {
|
|
98
|
+
connect: (self: SignalLike<U...>, Callback<U...>, ...any?) -> any,
|
|
99
|
+
[any]: any,
|
|
100
|
+
} | {
|
|
101
|
+
Connect: (self: SignalLike<U...>, Callback<U...>, ...any?) -> any,
|
|
102
|
+
[any]: any,
|
|
103
|
+
} | {
|
|
104
|
+
on: (self: SignalLike<U...>, Callback<U...>, ...any?) -> any,
|
|
105
|
+
[any]: any,
|
|
106
|
+
} | {
|
|
107
|
+
On: (self: SignalLike<U...>, Callback<U...>, ...any?) -> any,
|
|
108
|
+
[any]: any,
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
type GetConnectFn<U...> =
|
|
112
|
+
-- RBXScriptSignal & nil
|
|
113
|
+
((RBXScriptSignal<U...>) -> ConnectFn<RBXScriptConnection, U...>)
|
|
114
|
+
-- Instance & RBXScriptSignal
|
|
115
|
+
-- Instance & string
|
|
116
|
+
& ((
|
|
117
|
+
Instance,
|
|
118
|
+
RBXScriptSignal<U...> | string
|
|
119
|
+
) -> ConnectFn<RBXScriptConnection, U...>)
|
|
120
|
+
-- SignalLike & nil
|
|
121
|
+
& ((SignalLike<U...>) -> ConnectFn<any, U...>)
|
|
122
|
+
-- table & string
|
|
123
|
+
& ((GenericTable, string) -> ConnectFn<any, U...>)
|
|
124
|
+
-- table & connectable method
|
|
125
|
+
& (<T>(
|
|
126
|
+
GenericTable,
|
|
127
|
+
(GenericTable, Callback<U...>, ...any) -> T
|
|
128
|
+
) -> ConnectFn<T, U...>)
|
|
129
|
+
-- connectable function
|
|
130
|
+
& (<T>((Callback<U...>, ...any) -> T) -> ConnectFn<T, U...>)
|
|
131
|
+
|
|
110
132
|
-- This function is inspired by useEvent in Matter, a library by evaera (https://github.com/evaera)
|
|
111
133
|
-- License: Copyright (c) 2021 Eryn L. K., MIT License
|
|
112
134
|
-- Source: https://github.com/matter-ecs/matter/blob/main/lib/hooks/useEvent.luau
|
|
113
|
-
local function getConnectFunction
|
|
114
|
-
instance: EventInstance | EventLike,
|
|
115
|
-
event: string | EventLike
|
|
116
|
-
): ConnectFn<U...>?
|
|
135
|
+
local function getConnectFunction(instance, event)
|
|
117
136
|
local eventInstance = instance
|
|
118
137
|
|
|
119
138
|
if typeof(event) == "RBXScriptSignal" or type(event) == "table" then
|
|
@@ -131,6 +150,12 @@ local function getConnectFunction<U...>(
|
|
|
131
150
|
end
|
|
132
151
|
|
|
133
152
|
if type(eventInstance) == "table" then
|
|
153
|
+
if type(event) == "function" then
|
|
154
|
+
return function(callback)
|
|
155
|
+
return event(eventInstance, callback)
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
|
|
134
159
|
for _, method in EVENT_CONNECT_METHODS do
|
|
135
160
|
if type(eventInstance[method]) ~= "function" then
|
|
136
161
|
continue
|
|
@@ -156,6 +181,6 @@ return {
|
|
|
156
181
|
isPipeline = isPipeline,
|
|
157
182
|
getEventIdentifier = getEventIdentifier,
|
|
158
183
|
isValidEvent = isValidEvent,
|
|
159
|
-
getConnectFunction = getConnectFunction
|
|
184
|
+
getConnectFunction = getConnectFunction :: GetConnectFn<...any>,
|
|
160
185
|
disconnectEvent = disconnectEvent,
|
|
161
186
|
}
|
package/package.json
CHANGED
|
@@ -1,51 +1,37 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rbxts/planck",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "An
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "An Agnostic Scheduler, inspired by Bevy Schedules and Flecs Pipelines and Phases",
|
|
5
|
+
"author": "yetanotherclown",
|
|
5
6
|
"main": "out/init.lua",
|
|
6
|
-
"
|
|
7
|
-
"
|
|
8
|
-
"
|
|
7
|
+
"scripts": {
|
|
8
|
+
"install-dependencies": "bun install && (cd tests && bun install)",
|
|
9
|
+
"build": "rbxtsc",
|
|
10
|
+
"dev": "bun run build -- -w",
|
|
11
|
+
"prepublishOnly": "bun test",
|
|
12
|
+
"test": "bun run build && bun run build -- -p tests && rojo build tests -o tests/test-environment.rbxl && lune run tests tests/test-environment.rbxl"
|
|
9
13
|
},
|
|
10
|
-
"homepage": "https://yetanotherclown.github.io/planck",
|
|
11
14
|
"keywords": [
|
|
12
|
-
"
|
|
13
|
-
"
|
|
14
|
-
"Scheduler",
|
|
15
|
-
"@rbxts",
|
|
16
|
-
"Roblox",
|
|
17
|
-
"Roblox-TS",
|
|
18
|
-
"roblox ts",
|
|
19
|
-
"roblox-ts"
|
|
15
|
+
"roblox",
|
|
16
|
+
"rbxts"
|
|
20
17
|
],
|
|
21
|
-
"
|
|
22
|
-
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "git+https://github.com/yetanotherclown/planck.git"
|
|
21
|
+
},
|
|
22
|
+
"license": "ISC",
|
|
23
23
|
"types": "out/index.d.ts",
|
|
24
24
|
"files": [
|
|
25
25
|
"out",
|
|
26
|
-
"!**/*.tsbuildinfo"
|
|
27
|
-
"!out/__tests__",
|
|
28
|
-
"!out/__tests__/**/*",
|
|
29
|
-
"!out/jest.config.luau"
|
|
26
|
+
"!**/*.tsbuildinfo"
|
|
30
27
|
],
|
|
31
28
|
"publishConfig": {
|
|
32
29
|
"access": "public"
|
|
33
30
|
},
|
|
34
31
|
"devDependencies": {
|
|
35
|
-
"@rbxts/compiler-types": "3.0.0-types.0",
|
|
32
|
+
"@rbxts/compiler-types": "^3.0.0-types.0",
|
|
36
33
|
"@rbxts/types": "^1.0.813",
|
|
37
|
-
"
|
|
38
|
-
"
|
|
39
|
-
"eslint": "^9.17.0",
|
|
40
|
-
"eslint-config-prettier": "^9.1.0",
|
|
41
|
-
"eslint-plugin-prettier": "^5.2.1",
|
|
42
|
-
"eslint-plugin-roblox-ts": "^0.0.36",
|
|
43
|
-
"prettier": "^3.4.2",
|
|
44
|
-
"roblox-ts": "^3.0.0",
|
|
45
|
-
"typescript": "^5.7.2"
|
|
46
|
-
},
|
|
47
|
-
"scripts": {
|
|
48
|
-
"build": "rbxtsc",
|
|
49
|
-
"watch": "rbxtsc -w"
|
|
34
|
+
"roblox-ts": "npm:@wad4444/roblox-ts@^1.0.2",
|
|
35
|
+
"typescript": "^5.5.3"
|
|
50
36
|
}
|
|
51
37
|
}
|
package/out/hooks.d.ts
DELETED
package/out/types.d.ts
DELETED
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
import Phase from "./Phase";
|
|
2
|
-
import Pipeline from "./Pipeline";
|
|
3
|
-
import Scheduler from "./Scheduler";
|
|
4
|
-
|
|
5
|
-
export type SystemInfo<T extends unknown[]> = {
|
|
6
|
-
readonly system: SystemFn<T>;
|
|
7
|
-
readonly phase: Phase;
|
|
8
|
-
readonly name: string;
|
|
9
|
-
readonly logs: string[];
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
export interface Hooks {
|
|
14
|
-
readonly Hooks: {
|
|
15
|
-
readonly SystemAdd: "SystemAdd";
|
|
16
|
-
readonly SystemRemove: "SystemRemove";
|
|
17
|
-
readonly SystemReplace: "SystemReplace";
|
|
18
|
-
readonly SystemError: "SystemError";
|
|
19
|
-
|
|
20
|
-
readonly OuterSystemCall: "OuterSystemCall";
|
|
21
|
-
readonly InnerSystemCall: "InnerSystemCall";
|
|
22
|
-
readonly SystemCall: "SystemCall";
|
|
23
|
-
|
|
24
|
-
readonly PhaseAdd: "PhaseAdd";
|
|
25
|
-
readonly PhaseBegan: "PhaseBegan";
|
|
26
|
-
}
|
|
27
|
-
systemAdd: <T extends unknown[] = unknown[]>(scheduler: Scheduler<T>, systemInfo: SystemInfo<T>) => void;
|
|
28
|
-
systemRemove: <T extends unknown[] = unknown[]>(scheduler: Scheduler<T>, systemInfo: SystemInfo<T>) => void;
|
|
29
|
-
systemReplace: <T extends unknown[] = unknown[]>(scheduler: Scheduler<T>, oldSystemInfo: SystemInfo<T>, newSystemInfo: SystemInfo<T>) => void;
|
|
30
|
-
systemCall: <T extends unknown[] = unknown[]>(scheduler: Scheduler<T>, hookName: "OuterSystemCall" | "InnerSystemCall" | "SystemCall", systemInfo: SystemInfo<T>, nextFn: () => void) => void;
|
|
31
|
-
systemError: <T extends unknown[] = unknown[]>(scheduler: Scheduler<T>, systemInfo: SystemInfo<T>, error: string) => void;
|
|
32
|
-
phaseAdd: <T extends unknown[] = unknown[]>(scheduler: Scheduler<T>, phase: Phase) => void;
|
|
33
|
-
phaseBegan: <T extends unknown[] = unknown[]>(scheduler: Scheduler<T>, phase: Phase) => void;
|
|
34
|
-
}
|
|
35
|
-
type SystemAddHookArgs<T extends unknown[]> = {
|
|
36
|
-
scheduler: Scheduler<T>,
|
|
37
|
-
system: SystemInfo<T>
|
|
38
|
-
}
|
|
39
|
-
type SystemRemoveHookArgs<T extends unknown[]> = SystemAddHookArgs<T>;
|
|
40
|
-
type SystemReplaceHookArgs<T extends unknown[]> = {
|
|
41
|
-
scheduler: Scheduler<T>,
|
|
42
|
-
old: SystemInfo<T>,
|
|
43
|
-
new: SystemInfo<T>
|
|
44
|
-
}
|
|
45
|
-
type SystemErrorHookArgs<T extends unknown[]> = SystemAddHookArgs<T> & { error: string };
|
|
46
|
-
type SystemCallHookArgs<T extends unknown[]> = {
|
|
47
|
-
scheduler: undefined;
|
|
48
|
-
system: SystemInfo<T>;
|
|
49
|
-
nextFn: () => void;
|
|
50
|
-
}
|
|
51
|
-
type PhaseAddHookArgs<T extends unknown[]> = {
|
|
52
|
-
scheduler: Scheduler<T>;
|
|
53
|
-
phase: Phase;
|
|
54
|
-
}
|
|
55
|
-
type PhaseBeganHookArgs<T extends unknown[]> = PhaseAddHookArgs<T>;
|
|
56
|
-
type HookFunctionMap<T extends unknown[] = unknown[]> = {
|
|
57
|
-
SystemAdd: SystemAddHookArgs<T>;
|
|
58
|
-
SystemRemove: SystemRemoveHookArgs<T>;
|
|
59
|
-
SystemReplace: SystemReplaceHookArgs<T>;
|
|
60
|
-
SystemError: SystemErrorHookArgs<T>;
|
|
61
|
-
OuterSystemCall: SystemCallHookArgs<T>;
|
|
62
|
-
InnerSystemCall: SystemCallHookArgs<T>;
|
|
63
|
-
SystemCall: SystemCallHookArgs<T>;
|
|
64
|
-
PhaseAdd: PhaseAddHookArgs<T>;
|
|
65
|
-
PhaseBegan: PhaseBeganHookArgs<T>;
|
|
66
|
-
}
|
|
67
|
-
// Utility type to get the correct function type based on the hook name
|
|
68
|
-
type HookFunctionArgs<K extends keyof HookFunctionMap, T extends unknown[]> = HookFunctionMap<T>[K];
|
|
69
|
-
|
|
70
|
-
export type SystemFn<T extends unknown[]> = ((...args: T) => unknown[]) | ((...args: T) => void);
|
|
71
|
-
|
|
72
|
-
export interface SystemTable<T extends unknown[]> {
|
|
73
|
-
readonly system: SystemFn<T>;
|
|
74
|
-
readonly phase?: Phase
|
|
75
|
-
readonly [key: string]: unknown
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
export type System<T extends unknown[]> = SystemFn<T> | SystemTable<T>;
|
|
79
|
-
|
|
80
|
-
export type EventLike<T extends unknown[] = unknown[]> = {
|
|
81
|
-
connect(callback: (...args: T) => void): void;
|
|
82
|
-
} | {
|
|
83
|
-
Connect(callback: (...args: T) => void): void;
|
|
84
|
-
} | {
|
|
85
|
-
on(callback: (...args: T) => void): void;
|
|
86
|
-
} | {
|
|
87
|
-
On(callback: (...args: T) => void): void;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
export type EventInstance<T extends unknown[] = unknown[]> = Instance | EventLike<T> | RBXScriptSignal;
|
|
91
|
-
export type Disconnectable = RBXScriptConnection | { Disconnect(): void } | { disconnect(): void } | { Destroy(): void } | { destroy(): void; }
|
|
92
|
-
export type ConnectFn = (callback: (...args: unknown[]) => void) => Disconnectable;
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
export interface Utils {
|
|
96
|
-
getSystem: <T extends unknown[]>(system: System<T>) => SystemFn<T> | undefined
|
|
97
|
-
getSystemName: <T extends unknown[]>(system: SystemFn<T>) => string
|
|
98
|
-
isPhase: (phase: Phase) => Phase | undefined
|
|
99
|
-
isPipeline: (pipeline: Pipeline) => Pipeline | undefined
|
|
100
|
-
getEventIdentifier: <T extends unknown[]>(instance: EventInstance<T>, event?: string) => string
|
|
101
|
-
isValidEvent: <T extends unknown[]>(instance: EventInstance<T>, event?: string) => boolean
|
|
102
|
-
getConnectedFunction: <T extends unknown[]>(instance: EventInstance<T>, event?: string) => ConnectFn | undefined
|
|
103
|
-
disconnectEvent: (disconectable: Disconnectable) => void
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
export interface Plugin {
|
|
107
|
-
build(schedular: Scheduler<unknown[]>): void
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|