@rbxts/planck 0.3.0-alpha.2 → 0.3.0-rc.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/DependencyGraph.luau +45 -52
- package/src/Phase.luau +46 -41
- package/src/Pipeline.luau +105 -86
- package/src/Scheduler.d.ts +96 -3
- package/src/Scheduler.luau +713 -225
- package/src/__tests__/systems.test.luau +196 -192
- package/src/conditions.d.ts +4 -1
- package/src/conditions.luau +23 -21
- package/src/init.luau +36 -207
- package/src/utils.luau +85 -30
- package/src/hooks.luau +0 -163
|
@@ -1,192 +1,196 @@
|
|
|
1
|
-
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
|
2
|
-
|
|
3
|
-
local root = script.Parent.Parent
|
|
4
|
-
|
|
5
|
-
local Phase = require(root.Phase)
|
|
6
|
-
local Scheduler = require(root.Scheduler)
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
local
|
|
11
|
-
|
|
12
|
-
local
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
myScheduler:
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
myScheduler:
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
myScheduler:
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
local
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
local
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
:
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
local
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
:
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
1
|
+
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
|
2
|
+
|
|
3
|
+
local root = script.Parent.Parent
|
|
4
|
+
|
|
5
|
+
local Phase = require(root.Phase)
|
|
6
|
+
local Scheduler = require(root.Scheduler)
|
|
7
|
+
|
|
8
|
+
type SystemErrorContext = Scheduler.SystemErrorContext
|
|
9
|
+
|
|
10
|
+
local JestGlobals = require(ReplicatedStorage.DevPackages.JestGlobals)
|
|
11
|
+
|
|
12
|
+
local describe = JestGlobals.describe
|
|
13
|
+
local expect = JestGlobals.expect
|
|
14
|
+
local test = JestGlobals.test
|
|
15
|
+
|
|
16
|
+
describe("systems", function()
|
|
17
|
+
test("add", function()
|
|
18
|
+
expect.assertions(1)
|
|
19
|
+
|
|
20
|
+
local myPhase = Phase.new("myPhase")
|
|
21
|
+
local myScheduler = Scheduler.new(1, 2, 3)
|
|
22
|
+
:insert(myPhase)
|
|
23
|
+
:addSystem(function(...)
|
|
24
|
+
expect({ ... }).toEqual({ 1, 2, 3 })
|
|
25
|
+
end, myPhase)
|
|
26
|
+
|
|
27
|
+
myScheduler:runAll()
|
|
28
|
+
end)
|
|
29
|
+
|
|
30
|
+
test("edit", function()
|
|
31
|
+
expect.assertions(2)
|
|
32
|
+
|
|
33
|
+
local function systemA(...)
|
|
34
|
+
expect({ ... }).toEqual({ 1, 2, 3 })
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
local myPhase = Phase.new("myPhase")
|
|
38
|
+
local myScheduler =
|
|
39
|
+
Scheduler.new(1, 2, 3):insert(myPhase):addSystem(systemA, myPhase)
|
|
40
|
+
|
|
41
|
+
myScheduler:runAll()
|
|
42
|
+
|
|
43
|
+
local otherPhase = Phase.new()
|
|
44
|
+
myScheduler:insert(otherPhase)
|
|
45
|
+
|
|
46
|
+
myScheduler:editSystem(systemA, otherPhase)
|
|
47
|
+
myScheduler:run(otherPhase)
|
|
48
|
+
|
|
49
|
+
-- Expect nothing to run here
|
|
50
|
+
myScheduler:run(myPhase)
|
|
51
|
+
end)
|
|
52
|
+
|
|
53
|
+
test("remove", function()
|
|
54
|
+
expect.assertions(1)
|
|
55
|
+
|
|
56
|
+
local function systemA(...)
|
|
57
|
+
expect({ ... }).toEqual({ 1, 2, 3 })
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
local myPhase = Phase.new("myPhase")
|
|
61
|
+
local myScheduler =
|
|
62
|
+
Scheduler.new(1, 2, 3):insert(myPhase):addSystem(systemA, myPhase)
|
|
63
|
+
|
|
64
|
+
myScheduler:runAll()
|
|
65
|
+
|
|
66
|
+
myScheduler:removeSystem(systemA)
|
|
67
|
+
myScheduler:runAll() -- Expect nothing here
|
|
68
|
+
end)
|
|
69
|
+
|
|
70
|
+
test("replace", function()
|
|
71
|
+
expect.assertions(3)
|
|
72
|
+
|
|
73
|
+
local function systemA(...)
|
|
74
|
+
expect({ ... }).toEqual({ 1, 2, 3 })
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
local function systemB(...)
|
|
78
|
+
-- FUTURE: Use Jest.spyOn
|
|
79
|
+
expect(true).toBe(true)
|
|
80
|
+
expect({ ... }).toEqual({ 1, 2, 3 })
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
local myPhase = Phase.new("myPhase")
|
|
84
|
+
local myScheduler =
|
|
85
|
+
Scheduler.new(1, 2, 3):insert(myPhase):addSystem(systemA, myPhase)
|
|
86
|
+
|
|
87
|
+
myScheduler:runAll()
|
|
88
|
+
|
|
89
|
+
myScheduler:replaceSystem(systemA, systemB)
|
|
90
|
+
myScheduler:runAll()
|
|
91
|
+
end)
|
|
92
|
+
|
|
93
|
+
test("system table", function()
|
|
94
|
+
expect.assertions(1)
|
|
95
|
+
|
|
96
|
+
local myPhase = Phase.new("myPhase")
|
|
97
|
+
|
|
98
|
+
local system = {
|
|
99
|
+
system = function(...)
|
|
100
|
+
expect({ ... }).toEqual({ 1, 2, 3 })
|
|
101
|
+
end,
|
|
102
|
+
phase = myPhase,
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
local myScheduler =
|
|
106
|
+
Scheduler.new(1, 2, 3):insert(myPhase):addSystem(system)
|
|
107
|
+
|
|
108
|
+
myScheduler:run(myPhase)
|
|
109
|
+
end)
|
|
110
|
+
|
|
111
|
+
test("run condition", function()
|
|
112
|
+
expect.assertions(1)
|
|
113
|
+
|
|
114
|
+
local bool = true
|
|
115
|
+
|
|
116
|
+
local system = function(...)
|
|
117
|
+
expect({ ... }).toEqual({ 1, 2, 3 })
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
local myPhase = Phase.new("myPhase")
|
|
121
|
+
local myScheduler = Scheduler.new(1, 2, 3)
|
|
122
|
+
:insert(myPhase)
|
|
123
|
+
:addSystem(system, myPhase)
|
|
124
|
+
:addRunCondition(system, function()
|
|
125
|
+
return bool
|
|
126
|
+
end)
|
|
127
|
+
|
|
128
|
+
myScheduler:runAll()
|
|
129
|
+
|
|
130
|
+
bool = false
|
|
131
|
+
myScheduler:runAll() -- Expect system to not run
|
|
132
|
+
end)
|
|
133
|
+
|
|
134
|
+
test("multiple run conditions", function()
|
|
135
|
+
expect.assertions(1)
|
|
136
|
+
|
|
137
|
+
local firstCondition = true
|
|
138
|
+
local secondCondition = true
|
|
139
|
+
|
|
140
|
+
local system = function(...)
|
|
141
|
+
expect({ ... }).toEqual({ 1, 2, 3 })
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
local myPhase = Phase.new("myPhase")
|
|
145
|
+
local myScheduler = Scheduler.new(1, 2, 3)
|
|
146
|
+
:insert(myPhase)
|
|
147
|
+
:addSystem(system, myPhase)
|
|
148
|
+
:addRunCondition(system, function()
|
|
149
|
+
return firstCondition
|
|
150
|
+
end)
|
|
151
|
+
:addRunCondition(system, function()
|
|
152
|
+
return secondCondition
|
|
153
|
+
end)
|
|
154
|
+
|
|
155
|
+
firstCondition = false
|
|
156
|
+
myScheduler:runAll()
|
|
157
|
+
|
|
158
|
+
firstCondition = true
|
|
159
|
+
secondCondition = false
|
|
160
|
+
myScheduler:runAll()
|
|
161
|
+
|
|
162
|
+
firstCondition = false
|
|
163
|
+
secondCondition = false
|
|
164
|
+
myScheduler:runAll()
|
|
165
|
+
|
|
166
|
+
firstCondition = true
|
|
167
|
+
secondCondition = true
|
|
168
|
+
myScheduler:runAll() -- Expect to run
|
|
169
|
+
end)
|
|
170
|
+
|
|
171
|
+
test("yield", function()
|
|
172
|
+
expect.assertions(1)
|
|
173
|
+
|
|
174
|
+
local system = function()
|
|
175
|
+
wait(5)
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
local myPhase = Phase.new("myPhase")
|
|
179
|
+
local myScheduler =
|
|
180
|
+
Scheduler.new(1, 2, 3):insert(myPhase):addSystem(system, myPhase)
|
|
181
|
+
|
|
182
|
+
local err
|
|
183
|
+
|
|
184
|
+
myScheduler:addHook(
|
|
185
|
+
myScheduler.Hooks.SystemError,
|
|
186
|
+
function(context: SystemErrorContext)
|
|
187
|
+
if context.error then
|
|
188
|
+
err = context.error.log
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
myScheduler:runAll()
|
|
194
|
+
expect(err).toEqual(expect.stringContaining("System yielded"))
|
|
195
|
+
end)
|
|
196
|
+
end)
|
package/src/conditions.d.ts
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import type { EventInstance, EventLike, ExtractEvents } from "./utils";
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* If a Run Condition returns a falsy value (`nil`, `void`, `false`), the System/Phase/Pipeline will be prevented from running.
|
|
5
|
+
*/
|
|
3
6
|
export type Condition<T extends unknown[] = unknown[]> = (
|
|
4
7
|
...args: T
|
|
5
|
-
) =>
|
|
8
|
+
) => unknown | void;
|
|
6
9
|
|
|
7
10
|
/**
|
|
8
11
|
* A Throttle condition which checks whether the amount of time given has passed
|
package/src/conditions.luau
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
local utils = require(script.Parent.utils)
|
|
2
|
-
local
|
|
2
|
+
local getConnectFn = utils.getConnectFn
|
|
3
3
|
|
|
4
4
|
type GenericTable = utils.GenericTable
|
|
5
5
|
type SignalLike<U...> = utils.SignalLike<U...>
|
|
@@ -7,7 +7,7 @@ type ConnectionLike = utils.ConnectionLike
|
|
|
7
7
|
type ConnectFn<T, U...> = utils.ConnectFn<T, U...>
|
|
8
8
|
type Callback<U...> = utils.Callback<U...>
|
|
9
9
|
|
|
10
|
-
type Condition = () ->
|
|
10
|
+
export type Condition<U...> = (U...) -> any
|
|
11
11
|
|
|
12
12
|
--- @class Conditions
|
|
13
13
|
---
|
|
@@ -19,10 +19,11 @@ type Condition = () -> boolean
|
|
|
19
19
|
---
|
|
20
20
|
--- A Throttle condition which checks whether the amount of
|
|
21
21
|
--- time given has passed or not.
|
|
22
|
-
local function timePassed(time: number): Condition
|
|
23
|
-
local storedTime
|
|
22
|
+
local function timePassed<U...>(time: number): Condition<U...>
|
|
23
|
+
local storedTime: number?
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
-- selene: allow(unused_variable)
|
|
26
|
+
return function(...)
|
|
26
27
|
if storedTime == nil or os.clock() - storedTime >= time then
|
|
27
28
|
storedTime = os.clock()
|
|
28
29
|
return true
|
|
@@ -36,10 +37,11 @@ end
|
|
|
36
37
|
--- @return hasRanOnce () -> boolean
|
|
37
38
|
---
|
|
38
39
|
--- Checks whether the condition has been called once before
|
|
39
|
-
local function runOnce(): Condition
|
|
40
|
+
local function runOnce<U...>(): Condition<U...>
|
|
40
41
|
local hasRan = false
|
|
41
42
|
|
|
42
|
-
|
|
43
|
+
-- selene: allow(unused_variable)
|
|
44
|
+
return function(...)
|
|
43
45
|
if not hasRan then
|
|
44
46
|
hasRan = true
|
|
45
47
|
return true
|
|
@@ -53,7 +55,7 @@ type CollectEvents<U...> = () -> () -> (number, U...)
|
|
|
53
55
|
|
|
54
56
|
local conditionToCleanupFn = {}
|
|
55
57
|
|
|
56
|
-
local function cleanupCondition(condition: Condition)
|
|
58
|
+
local function cleanupCondition(condition: Condition<...any>)
|
|
57
59
|
local cleanup = conditionToCleanupFn[condition]
|
|
58
60
|
if cleanup then
|
|
59
61
|
cleanup()
|
|
@@ -67,31 +69,31 @@ type OnEventFn =
|
|
|
67
69
|
-- RBXScriptSignal & nil
|
|
68
70
|
(<U...>(
|
|
69
71
|
RBXScriptSignal<U...>
|
|
70
|
-
) -> (Condition
|
|
72
|
+
) -> (Condition<U...>, CollectEvents<U...>, GetDisconnectFn))
|
|
71
73
|
-- Instance & RBXScriptSignal
|
|
72
74
|
-- Instance & string
|
|
73
75
|
& (<U...>(
|
|
74
76
|
Instance,
|
|
75
77
|
RBXScriptSignal<U...> | string
|
|
76
|
-
) -> (Condition
|
|
78
|
+
) -> (Condition<U...>, CollectEvents<U...>, GetDisconnectFn))
|
|
77
79
|
-- SignalLike & nil
|
|
78
80
|
& (<U...>(
|
|
79
81
|
SignalLike<U...>
|
|
80
|
-
) -> (Condition
|
|
82
|
+
) -> (Condition<U...>, CollectEvents<U...>, GetDisconnectFn))
|
|
81
83
|
-- table & string
|
|
82
84
|
& (<U...>(
|
|
83
85
|
GenericTable,
|
|
84
86
|
string
|
|
85
|
-
) -> (Condition
|
|
87
|
+
) -> (Condition<U...>, CollectEvents<U...>, GetDisconnectFn))
|
|
86
88
|
-- table & connectable method
|
|
87
89
|
& (<T, U...>(
|
|
88
90
|
GenericTable,
|
|
89
91
|
(GenericTable, Callback<U...>, ...any) -> T?
|
|
90
|
-
) -> (Condition
|
|
92
|
+
) -> (Condition<U...>, CollectEvents<U...>, GetDisconnectFn))
|
|
91
93
|
-- connectable function
|
|
92
94
|
& (<T, U...>(
|
|
93
95
|
(Callback<U...>, ...any) -> T?
|
|
94
|
-
) -> (Condition
|
|
96
|
+
) -> (Condition<U...>, CollectEvents<U...>, GetDisconnectFn))
|
|
95
97
|
|
|
96
98
|
--- @within Conditions
|
|
97
99
|
--- @param instance RBXScriptSignal | Instance | SignalLike<...any> | GenericTable | ((Callback<U...>,...any) -> ...any)
|
|
@@ -107,12 +109,13 @@ type OnEventFn =
|
|
|
107
109
|
local function onEvent<U...>(
|
|
108
110
|
instance,
|
|
109
111
|
event
|
|
110
|
-
): (Condition
|
|
111
|
-
|
|
112
|
+
): (Condition<U...>, CollectEvents<U...>, (
|
|
113
|
+
) -> () -> ())
|
|
114
|
+
local connect = getConnectFn(instance, event)
|
|
112
115
|
assert(connect, "Event passed to .onEvent is not valid")
|
|
113
116
|
|
|
114
117
|
local newEvent = false
|
|
115
|
-
local queue = {}
|
|
118
|
+
local queue: { { any } } = {}
|
|
116
119
|
|
|
117
120
|
local connection: ConnectionLike?
|
|
118
121
|
|
|
@@ -171,11 +174,10 @@ end
|
|
|
171
174
|
--- @return inverseCondition () -> boolean
|
|
172
175
|
---
|
|
173
176
|
--- Inverses a given condition.
|
|
174
|
-
|
|
175
177
|
-- selene: allow(unused_variable)
|
|
176
|
-
local function isNot(condition: Condition
|
|
177
|
-
return function()
|
|
178
|
-
return not condition()
|
|
178
|
+
local function isNot<U...>(condition: Condition<U...>, ...: unknown): Condition<U...>
|
|
179
|
+
return function(...)
|
|
180
|
+
return not condition(...)
|
|
179
181
|
end
|
|
180
182
|
end
|
|
181
183
|
|