@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.
@@ -0,0 +1,14 @@
1
+ import { EventInstance, EventLike } from "./types";
2
+
3
+ type Condition = () => boolean;
4
+
5
+ declare const timePassed: (time: number) => Condition;
6
+
7
+ declare const exported: {
8
+ timePassed: (time: number) => Condition;
9
+ runOnce: () => Condition;
10
+ onEvent: <T extends unknown[]>(instance: EventInstance | EventLike, event: string | EventLike) => LuaTuple<[Condition, IterableFunction<T>, () => void]>;
11
+ isNot: (condition: Condition) => Condition;
12
+ cleanupCondition: (condition: Condition) => void
13
+ }
14
+ export = exported
@@ -0,0 +1,151 @@
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
+ }
package/out/index.d.ts CHANGED
@@ -1,11 +1,17 @@
1
1
  import phase from "./Phase";
2
2
  import pipeline from "./Pipeline";
3
3
  import schedular from "./Scheduler";
4
+ import condition from "./conditions"
4
5
 
5
6
  interface Planck {
6
7
  Phase: typeof phase;
7
8
  Pipeline: typeof pipeline;
8
9
  Scheduler: typeof schedular;
10
+
11
+ isNot: typeof condition.isNot;
12
+ timePassed: typeof condition.timePassed;
13
+ runOnce: typeof condition.runOnce;
14
+ onEvent: typeof condition.onEvent;
9
15
  }
10
16
 
11
17
  declare const planck: Planck;
package/out/init.luau CHANGED
@@ -1,66 +1,48 @@
1
- local Phase = require(script:WaitForChild('Phase')):: any
2
- local Pipeline = require(script:WaitForChild('Pipeline')):: any
3
- local Scheduler = require(script:WaitForChild('Scheduler')):: any
1
+ local Phase = require(script:FindFirstChild("Phase")) :: any
2
+ local Pipeline = require(script:FindFirstChild("Pipeline")) :: any
3
+ local Scheduler = require(script:FindFirstChild("Scheduler")) :: any
4
4
 
5
- type SystemFn<U...> = ((U...) -> any) | ((U...) -> ())
5
+ local conditions = require(script:FindFirstChild("conditions"))
6
+ local utils = require(script:FindFirstChild("utils"))
6
7
 
7
- type SystemTable<U...> = {
8
+ type EventLike = utils.EventLike
9
+ type EventInstance = utils.EventInstance
10
+
11
+ export type SystemFn<U...> = ((U...) -> any) | ((U...) -> ())
12
+
13
+ export type SystemTable<U...> = {
8
14
  system: SystemFn<U...>,
9
15
  phase: Phase?,
10
- [any]: any
16
+ name: string?,
17
+ runConditions: { (U...) -> boolean }?,
18
+ [any]: any,
11
19
  }
12
20
 
13
- type System<U...> = SystemFn<U...> | SystemTable<U...>
14
-
15
- type EventLike = RBXScriptSignal | {
16
- connect: (self: EventLike,...any) -> any,
17
- [any]: any
18
- } | {
19
- Connect: (self: EventLike,...any) -> any,
20
- [any]: any
21
- } | {
22
- on: (self: EventLike,...any) -> any,
23
- [any]: any
24
- }
25
-
26
- type EventInstance = Instance | {
27
- [any]: EventLike
28
- }
21
+ export type System<U...> = SystemFn<U...> | SystemTable<U...>
29
22
 
30
- type Phase = {
23
+ export type Phase = {
31
24
  PreStartup: Phase,
32
25
  Startup: Phase,
33
26
  PostStartup: Phase,
34
27
 
35
- PreRender: Phase,
36
- PreAnimation: Phase,
37
- PreSimulation: Phase,
38
- PostSimulation: Phase,
39
-
40
- First: Phase,
41
- PreUpdate: Phase,
42
- Update: Phase,
43
- PostUpdate: Phase,
44
- Last: Phase,
45
-
46
- new: (debugName: string?) -> Phase
28
+ new: (debugName: string?) -> Phase,
47
29
  }
48
30
 
49
- type Pipeline = {
50
- Main: Pipeline,
31
+ export type Pipeline = {
51
32
  Startup: Pipeline,
52
33
 
53
34
  insert: (self: Pipeline, phase: Phase) -> Pipeline,
54
35
  insertAfter: (self: Pipeline, phase: Phase, after: Phase) -> Pipeline,
55
- new: (debugName: string?) -> Pipeline
36
+ new: (debugName: string?) -> Pipeline,
56
37
  }
57
38
 
58
39
  type Plugin<U...> = {
59
40
  build: (self: Plugin<U...>, scheduler: Scheduler<U...>) -> (),
60
- [any]: any
41
+ cleanup: ((self: Plugin<U...>) -> ())?,
42
+ [any]: any,
61
43
  }
62
44
 
63
- type Scheduler<U...> = {
45
+ export type Scheduler<U...> = {
64
46
  addPlugin: (self: Scheduler<U...>, plugin: Plugin<U...>) -> Scheduler<U...>,
65
47
 
66
48
  addSystem: (
@@ -92,18 +74,21 @@ type Scheduler<U...> = {
92
74
  system: System<U...>
93
75
  ) -> Scheduler<U...>,
94
76
 
95
- setRunCondition: ((
77
+ addRunCondition: ((
96
78
  self: Scheduler<U...>,
97
79
  system: System<U...>,
98
- fn: (U...) -> boolean
80
+ fn: (U...) -> boolean,
81
+ ...any
99
82
  ) -> Scheduler<U...>) & ((
100
83
  self: Scheduler<U...>,
101
84
  phase: Phase,
102
- fn: (U...) -> boolean
85
+ fn: (U...) -> boolean,
86
+ ...any
103
87
  ) -> Scheduler<U...>) & ((
104
88
  self: Scheduler<U...>,
105
89
  pipeline: Pipeline,
106
- fn: (U...) -> boolean
90
+ fn: (U...) -> boolean,
91
+ ...any
107
92
  ) -> Scheduler<U...>),
108
93
 
109
94
  run: ((self: Scheduler<U...>, system: System<U...>) -> Scheduler<U...>)
@@ -112,6 +97,8 @@ type Scheduler<U...> = {
112
97
 
113
98
  runAll: (self: Scheduler<U...>) -> Scheduler<U...>,
114
99
 
100
+ getDeltaTime: (self: Scheduler<U...>) -> number,
101
+
115
102
  insert: ((self: Scheduler<U...>, phase: Phase) -> Scheduler<U...>) & ((
116
103
  self: Scheduler<U...>,
117
104
  pipeline: Pipeline
@@ -137,13 +124,20 @@ type Scheduler<U...> = {
137
124
  after: Phase | Pipeline
138
125
  ) -> Scheduler<U...>),
139
126
 
140
- new: (U...) -> Scheduler<U...>
127
+ cleanup: (self: Scheduler<U...>) -> (),
128
+
129
+ new: (U...) -> Scheduler<U...>,
141
130
  }
142
131
 
143
132
  return {
144
133
  Phase = Phase :: Phase,
145
134
  Pipeline = Pipeline :: Pipeline,
146
135
  Scheduler = Scheduler :: {
147
- new: <U...>(U...) -> Scheduler<U...>
148
- },
136
+ new: <U...>(U...) -> Scheduler<U...>,
137
+ },
138
+
139
+ isNot = conditions.isNot,
140
+ runOnce = conditions.runOnce,
141
+ timePassed = conditions.timePassed,
142
+ onEvent = conditions.onEvent,
149
143
  }
package/out/types.d.ts CHANGED
@@ -85,6 +85,8 @@ export interface EventLike {
85
85
  }
86
86
 
87
87
  export type EventInstance = Instance | EventLike | RBXScriptSignal;
88
+ export type Disconnectable = RBXScriptConnection | { Disconnect(): void } | { disconnect(): void } | { Destroy(): void } | { destroy(): void; }
89
+ export type ConnectFn = (callback: (...args: unknown[]) => void) => Disconnectable;
88
90
 
89
91
 
90
92
  export interface Utils {
@@ -93,7 +95,9 @@ export interface Utils {
93
95
  isPhase: (phase: Phase) => Phase | undefined
94
96
  isPipeline: (pipeline: Pipeline) => Pipeline | undefined
95
97
  getEventIdentifier: (instance: EventInstance, event?: EventLike) => string
96
- isValidEvent: (instance: EventInstance, event?: EventLike) => boolean
98
+ isValidEvent: (instance: EventInstance, event: EventLike) => boolean
99
+ getConnectedFunction: (instance: EventInstance | EventLike, event: string | EventLike) => ConnectFn | undefined
100
+ disconnectEvent: (disconectable: Disconnectable) => void
97
101
  }
98
102
 
99
103
  export interface Plugin {
package/out/utils.luau CHANGED
@@ -6,7 +6,7 @@ type SystemFn<U...> = ((U...) -> any) | ((U...) -> ())
6
6
  type SystemTable<U...> = {
7
7
  system: SystemFn<U...>,
8
8
  phase: Phase?,
9
- [any]: any
9
+ [any]: any,
10
10
  }
11
11
 
12
12
  type System<U...> = SystemFn<U...> | SystemTable<U...>
@@ -24,7 +24,8 @@ end
24
24
  local function getSystemName(system: any): string
25
25
  local name = debug.info(system, "n")
26
26
  if not name or string.len(name) == 0 then
27
- name = debug.info(system, "sl")
27
+ local source, line = debug.info(system, "sl")
28
+ name = `{source}:{line}`
28
29
  end
29
30
 
30
31
  return name
@@ -50,27 +51,102 @@ local function getEventIdentifier(instance, event)
50
51
  return `{instance}{event and `@{event}` or ""}`
51
52
  end
52
53
 
53
- local validEventMethods = {
54
- "Connect",
55
- "connect",
56
- "On",
57
- "on",
54
+ local EVENT_CONNECT_METHODS = { "Connect", "On", "on", "connect" }
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,
58
65
  }
59
66
 
60
- local function isValidEvent(instance, event)
61
- local eventInstance = event and instance[event] or instance
62
-
63
- if typeof(eventInstance) == "RBXScriptSignal" then
64
- return true
65
- elseif typeof(eventInstance) == "table" then
66
- for _, method in validEventMethods do
67
- if eventInstance[method] ~= nil then
68
- return true
67
+ export type EventInstance = Instance | {
68
+ [any]: EventLike,
69
+ }
70
+
71
+ export type ConnectionLike = RBXScriptConnection | {
72
+ disconnect: (self: ConnectionLike, ...any) -> any,
73
+ [any]: any,
74
+ } | {
75
+ Disconnect: (self: ConnectionLike, ...any) -> any,
76
+ [any]: any,
77
+ } | {
78
+ destroy: (self: ConnectionLike, ...any) -> any,
79
+ [any]: any,
80
+ } | {
81
+ Destroy: (self: ConnectionLike, ...any) -> any,
82
+ [any]: any,
83
+ } | (...any) -> any
84
+
85
+ export type ConnectFn<U...> = (callback: (U...) -> ()) -> ConnectionLike
86
+
87
+ local EVENT_DISCONNECT_METHODS =
88
+ { "disconnect", "Disconnect", "destroy", "Destroy" }
89
+
90
+ local function disconnectEvent(connection: ConnectionLike)
91
+ if type(connection) == "function" then
92
+ connection()
93
+ return
94
+ elseif typeof(connection) == "RBXScriptConnection" then
95
+ connection:Disconnect()
96
+ return
97
+ elseif type(connection) == "table" then
98
+ for _, method in EVENT_DISCONNECT_METHODS do
99
+ if
100
+ connection[method]
101
+ and type(connection[method]) == "function"
102
+ then
103
+ connection[method](connection)
104
+ return
69
105
  end
70
106
  end
71
107
  end
108
+ end
109
+
110
+ -- This function is inspired by useEvent in Matter, a library by evaera (https://github.com/evaera)
111
+ -- License: Copyright (c) 2021 Eryn L. K., MIT License
112
+ -- Source: https://github.com/matter-ecs/matter/blob/main/lib/hooks/useEvent.luau
113
+ local function getConnectFunction<U...>(
114
+ instance: EventInstance | EventLike,
115
+ event: string | EventLike
116
+ ): ConnectFn<U...>?
117
+ local eventInstance = instance
118
+
119
+ if typeof(event) == "RBXScriptSignal" or type(event) == "table" then
120
+ eventInstance = event
121
+ elseif type(event) == "string" then
122
+ eventInstance = (instance :: any)[event]
123
+ end
72
124
 
73
- return false
125
+ if type(eventInstance) == "function" then
126
+ return eventInstance
127
+ elseif typeof(eventInstance) == "RBXScriptSignal" then
128
+ return function(callback)
129
+ return eventInstance:Connect(callback)
130
+ end
131
+ end
132
+
133
+ if type(eventInstance) == "table" then
134
+ for _, method in EVENT_CONNECT_METHODS do
135
+ if type(eventInstance[method]) ~= "function" then
136
+ continue
137
+ end
138
+
139
+ return function(callback)
140
+ return eventInstance[method](eventInstance, callback)
141
+ end
142
+ end
143
+ end
144
+
145
+ return nil
146
+ end
147
+
148
+ local function isValidEvent(instance, event)
149
+ return getConnectFunction(instance, event) ~= nil
74
150
  end
75
151
 
76
152
  return {
@@ -80,4 +156,6 @@ return {
80
156
  isPipeline = isPipeline,
81
157
  getEventIdentifier = getEventIdentifier,
82
158
  isValidEvent = isValidEvent,
159
+ getConnectFunction = getConnectFunction,
160
+ disconnectEvent = disconnectEvent,
83
161
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rbxts/planck",
3
- "version": "0.1.3-rc.5",
3
+ "version": "0.2.0",
4
4
  "description": "An agnostic scheduler for ECS",
5
5
  "main": "out/init.lua",
6
6
  "repository": {