@rbxts/planck 0.2.5 → 0.3.0-alpha.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.
@@ -0,0 +1,69 @@
1
+ import type { EventInstance, EventLike, ExtractEvents } from "./utils";
2
+
3
+ export type Condition<T extends unknown[] = unknown[]> = (
4
+ ...args: T
5
+ ) => boolean;
6
+
7
+ /**
8
+ * A Throttle condition which checks whether the amount of time given has passed
9
+ * or not.
10
+ */
11
+ export const timePassed: (time: number) => Condition;
12
+
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
28
+ * [OnEvent](https://yetanotherclown.github.io/planck/docs/design/conditions/#on-event)
29
+ * for more information.
30
+ */
31
+ export function onEvent<T extends EventInstance, E extends ExtractEvents<T>>(
32
+ instance: T,
33
+ event: E,
34
+ ): LuaTuple<
35
+ [hasNewEvent: Condition, collectEvents: CollectEvents<ExtractEvent<T>[E]>]
36
+ >;
37
+
38
+ /**
39
+ * Checks for any new events and allows for the collection of those events.
40
+ *
41
+ * Read
42
+ * [OnEvent](https://yetanotherclown.github.io/planck/docs/design/conditions/#on-event)
43
+ * for more information.
44
+ */
45
+ export function onEvent<T extends EventLike>(
46
+ instance: EventInstance,
47
+ event: T,
48
+ ): LuaTuple<
49
+ [hasNewEvent: Condition, collectEvents: CollectEvents<ExtractEventArgs<T>>]
50
+ >;
51
+
52
+ /**
53
+ * Checks for any new events and allows for the collection of those events.
54
+ *
55
+ * Read
56
+ * [OnEvent](https://yetanotherclown.github.io/planck/docs/design/conditions/#on-event)
57
+ * for more information.
58
+ */
59
+ export function onEvent<T extends EventLike>(
60
+ instance: T,
61
+ ): LuaTuple<
62
+ [hasNewEvent: Condition, collectEvents: CollectEvents<ExtractEventArgs<T>>]
63
+ >;
64
+
65
+ /** Inverses a given condition. */
66
+ export const isNot: <T extends unknown[]>(
67
+ fn: Condition<T>,
68
+ ...any: any[]
69
+ ) => Condition<T>;
@@ -1,151 +1,189 @@
1
- local utils = require("./utils")
2
- local getConnectFunction = utils.getConnectFunction
3
-
4
- type EventLike = utils.EventLike
5
- type EventInstance = utils.EventInstance
6
- type ConnectionLike = utils.ConnectionLike
7
-
8
- type Condition = () -> boolean
9
-
10
- --- @class Conditions
11
- ---
12
- --- Conditions can be used in systems or as Run Conditions.
13
-
14
- --- @within Conditions
15
- --- @param time number -- Time in seconds
16
- --- @return hasTimePassed () -> boolean
17
- ---
18
- --- A Throttle condition which checks whether the amount of
19
- --- time given has passed or not.
20
- local function timePassed(time: number): Condition
21
- local storedTime
22
-
23
- return function()
24
- if storedTime == nil or os.clock() - storedTime >= time then
25
- storedTime = os.clock()
26
- return true
27
- end
28
-
29
- return false
30
- end
31
- end
32
-
33
- --- @within Conditions
34
- --- @return hasRanOnce () -> boolean
35
- ---
36
- --- Checks whether the condition has been called once before
37
- local function runOnce(): Condition
38
- local hasRan = false
39
-
40
- return function()
41
- if not hasRan then
42
- hasRan = true
43
- return true
44
- end
45
-
46
- return false
47
- end
48
- end
49
-
50
- type CollectEvents<U...> = () -> () -> (number, U...)
51
-
52
- local conditionToCleanupFn = {}
53
-
54
- local function cleanupCondition(condition: Condition)
55
- local cleanup = conditionToCleanupFn[condition]
56
- if cleanup then
57
- cleanup()
58
- conditionToCleanupFn[condition] = nil
59
- end
60
- end
61
-
62
- --- @within Conditions
63
- --- @return hasNewEvent () -> boolean
64
- --- @return collectEvents () -> () -> (number, U...)
65
- --- @return getDisconnectFn () -> () -> ()
66
- ---
67
- --- Checks for any new events and allows for the collection of
68
- --- those events.
69
- local function onEvent<U...>(
70
- instance: EventInstance | EventLike,
71
- event: string | EventLike
72
- ): (Condition, CollectEvents<U...>, () -> () -> ())
73
- local connect = getConnectFunction(instance, event)
74
- assert(connect, "Event passed to .onEvent is not valid")
75
-
76
- local newEvent = false
77
- local queue = {}
78
-
79
- local connection: ConnectionLike?
80
-
81
- local function disconnect()
82
- if not connection then
83
- return
84
- end
85
-
86
- utils.disconnectEvent(connection)
87
- connection = nil
88
- end
89
-
90
- local function callback(...)
91
- newEvent = true
92
- table.insert(queue, { ... })
93
- end
94
-
95
- connection = connect(callback)
96
-
97
- local function hasNewEvent()
98
- if newEvent then
99
- newEvent = false
100
- return true
101
- end
102
-
103
- table.clear(queue)
104
- return false
105
- end
106
-
107
- local function collectEvents()
108
- local n = 0
109
- return function(): (number, U...)
110
- n += 1
111
-
112
- local args = table.remove(queue, 1)
113
-
114
- if args then
115
- return n, table.unpack(args)
116
- end
117
-
118
- return nil :: any
119
- end
120
- end
121
-
122
- local function getDisconnectFn()
123
- return disconnect
124
- end
125
-
126
- conditionToCleanupFn[hasNewEvent] = disconnect
127
-
128
- return hasNewEvent, collectEvents, getDisconnectFn
129
- end
130
-
131
- --- @within Conditions
132
- --- @param condition () -> boolean
133
- --- @return inverseCondition () -> boolean
134
- ---
135
- --- Inverses a given condition.
136
-
137
- -- selene: allow(unused_variable)
138
- local function isNot(condition: Condition, ...: any): Condition
139
- return function()
140
- return not condition()
141
- end
142
- end
143
-
144
- return {
145
- timePassed = timePassed,
146
- runOnce = runOnce,
147
- onEvent = onEvent,
148
- isNot = isNot,
149
-
150
- cleanupCondition = cleanupCondition,
151
- }
1
+ local utils = require(script.Parent.utils)
2
+ local getConnectFunction = utils.getConnectFunction
3
+
4
+ type GenericTable = utils.GenericTable
5
+ type SignalLike<U...> = utils.SignalLike<U...>
6
+ type ConnectionLike = utils.ConnectionLike
7
+ type ConnectFn<T, U...> = utils.ConnectFn<T, U...>
8
+ type Callback<U...> = utils.Callback<U...>
9
+
10
+ type Condition = () -> boolean
11
+
12
+ --- @class Conditions
13
+ ---
14
+ --- Conditions can be used in systems or as Run Conditions.
15
+
16
+ --- @within Conditions
17
+ --- @param time number -- Time in seconds
18
+ --- @return hasTimePassed () -> boolean
19
+ ---
20
+ --- A Throttle condition which checks whether the amount of
21
+ --- time given has passed or not.
22
+ local function timePassed(time: number): Condition
23
+ local storedTime
24
+
25
+ return function()
26
+ if storedTime == nil or os.clock() - storedTime >= time then
27
+ storedTime = os.clock()
28
+ return true
29
+ end
30
+
31
+ return false
32
+ end
33
+ end
34
+
35
+ --- @within Conditions
36
+ --- @return hasRanOnce () -> boolean
37
+ ---
38
+ --- Checks whether the condition has been called once before
39
+ local function runOnce(): Condition
40
+ local hasRan = false
41
+
42
+ return function()
43
+ if not hasRan then
44
+ hasRan = true
45
+ return true
46
+ end
47
+
48
+ return false
49
+ end
50
+ end
51
+
52
+ type CollectEvents<U...> = () -> () -> (number, U...)
53
+
54
+ local conditionToCleanupFn = {}
55
+
56
+ local function cleanupCondition(condition: Condition)
57
+ local cleanup = conditionToCleanupFn[condition]
58
+ if cleanup then
59
+ cleanup()
60
+ conditionToCleanupFn[condition] = nil
61
+ end
62
+ end
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
+
96
+ --- @within Conditions
97
+ --- @param instance RBXScriptSignal | Instance | SignalLike<...any> | GenericTable | ((Callback<U...>,...any) -> ...any)
98
+ --- @param event (RBXScriptSignal | string | (...any) -> ())?
99
+ --- @return hasNewEvent () -> boolean
100
+ --- @return collectEvents () -> () -> (number, U...)
101
+ --- @return getDisconnectFn () -> () -> ()
102
+ ---
103
+ --- Checks for any new events and allows for the collection of
104
+ --- those events.\
105
+ --- \
106
+ --- Read [OnEvent](../docs/design/conditions#on-event) for more information.
107
+ local function onEvent<U...>(
108
+ instance,
109
+ event
110
+ ): (Condition, CollectEvents<U...>, () -> () -> ())
111
+ local connect = getConnectFunction(instance, event)
112
+ assert(connect, "Event passed to .onEvent is not valid")
113
+
114
+ local newEvent = false
115
+ local queue = {}
116
+
117
+ local connection: ConnectionLike?
118
+
119
+ local function disconnect()
120
+ if not connection then
121
+ return
122
+ end
123
+
124
+ utils.disconnectEvent(connection)
125
+ connection = nil
126
+ end
127
+
128
+ local function callback(...)
129
+ newEvent = true
130
+ table.insert(queue, { ... })
131
+ end
132
+
133
+ connection = connect(callback)
134
+
135
+ local function hasNewEvent()
136
+ if newEvent then
137
+ newEvent = false
138
+ return true
139
+ end
140
+
141
+ table.clear(queue)
142
+ return false
143
+ end
144
+
145
+ local function collectEvents()
146
+ local n = 0
147
+ return function(): (number, U...)
148
+ n += 1
149
+
150
+ local args = table.remove(queue, 1)
151
+
152
+ if args then
153
+ return n, table.unpack(args)
154
+ end
155
+
156
+ return nil :: any
157
+ end
158
+ end
159
+
160
+ local function getDisconnectFn()
161
+ return disconnect
162
+ end
163
+
164
+ conditionToCleanupFn[hasNewEvent] = disconnect
165
+
166
+ return hasNewEvent, collectEvents, getDisconnectFn
167
+ end
168
+
169
+ --- @within Conditions
170
+ --- @param condition () -> boolean
171
+ --- @return inverseCondition () -> boolean
172
+ ---
173
+ --- Inverses a given condition.
174
+
175
+ -- selene: allow(unused_variable)
176
+ local function isNot(condition: Condition, ...: any): Condition
177
+ return function()
178
+ return not condition()
179
+ end
180
+ end
181
+
182
+ return {
183
+ timePassed = timePassed,
184
+ runOnce = runOnce,
185
+ onEvent = onEvent :: OnEventFn,
186
+ isNot = isNot,
187
+
188
+ cleanupCondition = cleanupCondition,
189
+ }