@rbxts/covenant 1.0.1 → 1.0.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 +3 -3
- package/src/covenant.d.ts +77 -0
- package/src/covenant.luau +841 -0
- package/src/helpers.d.ts +14 -0
- package/src/helpers.luau +70 -0
- package/src/hooks.d.ts +30 -0
- package/src/hooks.luau +284 -0
- package/src/index.d.ts +2 -0
- package/src/init.luau +4 -0
- package/src/stringEnums.d.ts +6 -0
- package/src/stringEnums.luau +9 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rbxts/covenant",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"main": "src/init.lua",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"build": "rbxtsc",
|
|
@@ -19,9 +19,9 @@
|
|
|
19
19
|
},
|
|
20
20
|
"homepage": "https://github.com/cuberootmctoasted/covenant#readme",
|
|
21
21
|
"description": "",
|
|
22
|
-
"types": "src/
|
|
22
|
+
"types": "src/covenant.d.ts",
|
|
23
23
|
"files": [
|
|
24
|
-
"
|
|
24
|
+
"src",
|
|
25
25
|
"!**/*.tsbuildinfo"
|
|
26
26
|
],
|
|
27
27
|
"publishConfig": {
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { Entity, Id } from "@rbxts/jecs";
|
|
2
|
+
import { CovenantHooks, Discriminator } from "./hooks";
|
|
3
|
+
import { Remove, Delete } from "./stringEnums";
|
|
4
|
+
export type WorldChangesForReplication = Map<string, Delete | Map<string, defined | Remove>>;
|
|
5
|
+
export type WorldChangesForPrediction = Map<string, Map<string, defined | Remove>>;
|
|
6
|
+
export interface CovenantProps {
|
|
7
|
+
replicationSend: (player: Player, worldChanges: WorldChangesForReplication) => void;
|
|
8
|
+
replicationSendAll?: (worldChanges: WorldChangesForReplication) => void;
|
|
9
|
+
replicationConnect: (callback: (worldChanges: WorldChangesForReplication) => void) => void;
|
|
10
|
+
predictionSend: (worldChanges: WorldChangesForPrediction) => void;
|
|
11
|
+
predictionConnect: (callback: (player: Player, worldChanges: WorldChangesForPrediction) => void) => void;
|
|
12
|
+
}
|
|
13
|
+
type ComponentPredictionValidator = (player: Player, entity: Entity, newState: unknown, lastState: unknown) => boolean;
|
|
14
|
+
export declare class Covenant {
|
|
15
|
+
private _world;
|
|
16
|
+
private systems;
|
|
17
|
+
private worldChangesForReplication;
|
|
18
|
+
private worldChangesForPrediction;
|
|
19
|
+
private underivedStringifiedComponents;
|
|
20
|
+
private replicatedStringifiedComponents;
|
|
21
|
+
private predictedStringifiedComponents;
|
|
22
|
+
private started;
|
|
23
|
+
private stringifiedComponentSubscribers;
|
|
24
|
+
private stringifiedComponentValidators;
|
|
25
|
+
private replicationSend;
|
|
26
|
+
private replicationConnect;
|
|
27
|
+
private replicationSendAll;
|
|
28
|
+
private predictionSend;
|
|
29
|
+
private predictionConnect;
|
|
30
|
+
constructor({ replicationSend, replicationConnect, replicationSendAll, predictionSend, predictionConnect, }: CovenantProps);
|
|
31
|
+
private setupPredictionClient;
|
|
32
|
+
private setupPredictionServer;
|
|
33
|
+
private setupPrediction;
|
|
34
|
+
private setupRelicationServer;
|
|
35
|
+
private setupReplicationPayload;
|
|
36
|
+
private setupReplicationClient;
|
|
37
|
+
private setupReplication;
|
|
38
|
+
start(): void;
|
|
39
|
+
private schedule;
|
|
40
|
+
private worldSet;
|
|
41
|
+
subscribeComponent<T>(component: Entity<T>, subscriber: (entity: Entity, state: T | undefined, previousState: T | undefined) => void): () => void;
|
|
42
|
+
private worldDelete;
|
|
43
|
+
worldComponent<T extends defined>(): Entity<T>;
|
|
44
|
+
private checkComponentDerived;
|
|
45
|
+
private defineComponentNetworkBehavior;
|
|
46
|
+
deriveComponent<T extends defined>({ component, queriedComponents, recipe, replicated, predictionValidator, }: {
|
|
47
|
+
replicated: boolean;
|
|
48
|
+
predictionValidator: ComponentPredictionValidator | false;
|
|
49
|
+
component: Entity<T>;
|
|
50
|
+
queriedComponents: Entity[][];
|
|
51
|
+
recipe: (entity: Entity, lastState: T | undefined, updateId: number, hooks: CovenantHooks) => T | undefined;
|
|
52
|
+
}): void;
|
|
53
|
+
deriveChildren<T extends defined>({ parentComponent, parentEntityTrackerComponent, childIdentityComponent, getIdentifier, queriedComponents, recipe, replicated, predictionValidator, }: {
|
|
54
|
+
replicated: boolean;
|
|
55
|
+
predictionValidator: ComponentPredictionValidator | false;
|
|
56
|
+
parentComponent: Entity<ReadonlyArray<T>>;
|
|
57
|
+
parentEntityTrackerComponent: Entity<Map<Discriminator, Entity>>;
|
|
58
|
+
childIdentityComponent: Entity<T>;
|
|
59
|
+
getIdentifier: (state: T) => Discriminator;
|
|
60
|
+
queriedComponents: Entity[][];
|
|
61
|
+
recipe: (entity: Entity, lastChildrenStates: ReadonlyArray<T>, updateId: number, hooks: CovenantHooks) => ReadonlyArray<T>;
|
|
62
|
+
}): void;
|
|
63
|
+
deriveRootEntity<T extends defined>({ identityComponent, recipe, replicated, }: {
|
|
64
|
+
replicated: boolean;
|
|
65
|
+
identityComponent: Entity<T>;
|
|
66
|
+
recipe: (updateId: number, hooks: CovenantHooks) => {
|
|
67
|
+
statesToCreate: ReadonlyArray<T>;
|
|
68
|
+
entitiesToDelete: ReadonlyArray<Entity>;
|
|
69
|
+
};
|
|
70
|
+
}): void;
|
|
71
|
+
private worldEntity;
|
|
72
|
+
worldQuery<T extends Id[]>(...components: T): import("@rbxts/jecs").Query<import("@rbxts/jecs").InferComponents<T>>;
|
|
73
|
+
worldHas(entity: Entity, ...components: Id[]): boolean;
|
|
74
|
+
worldGet<T extends [Id] | [Id, Id] | [Id, Id, Id] | [Id, Id, Id, Id]>(entity: Entity, ...components: T): import("@rbxts/jecs").FlattenTuple<[...import("@rbxts/jecs").Nullable<import("@rbxts/jecs").InferComponents<T>>]>;
|
|
75
|
+
worldContains(entity: Entity): boolean;
|
|
76
|
+
}
|
|
77
|
+
export {};
|
|
@@ -0,0 +1,841 @@
|
|
|
1
|
+
-- Compiled with roblox-ts v3.0.0
|
|
2
|
+
local TS = _G[script]
|
|
3
|
+
local _jecs = TS.import(script, TS.getModule(script, "@rbxts", "jecs").jecs)
|
|
4
|
+
local ChildOf = _jecs.ChildOf
|
|
5
|
+
local pair = _jecs.pair
|
|
6
|
+
local World = _jecs.World
|
|
7
|
+
local _services = TS.import(script, TS.getModule(script, "@rbxts", "services"))
|
|
8
|
+
local Players = _services.Players
|
|
9
|
+
local RunService = _services.RunService
|
|
10
|
+
local createHooks = TS.import(script, script.Parent, "hooks").createHooks
|
|
11
|
+
local _stringEnums = TS.import(script, script.Parent, "stringEnums")
|
|
12
|
+
local Remove = _stringEnums.Remove
|
|
13
|
+
local Delete = _stringEnums.Delete
|
|
14
|
+
local _helpers = TS.import(script, script.Parent, "helpers")
|
|
15
|
+
local compareMaps = _helpers.compareMaps
|
|
16
|
+
local turnArrayWithIdentifierToMap = _helpers.turnArrayWithIdentifierToMap
|
|
17
|
+
-- Map<Entity, Delete | Map<Component, state | Remove>>
|
|
18
|
+
-- Map<Component, Map<Entity, state | Remove>>
|
|
19
|
+
local function createWorldWithRange(minClientEntity, maxClientEntity)
|
|
20
|
+
local world = World.new()
|
|
21
|
+
if RunService:IsClient() then
|
|
22
|
+
world:range(minClientEntity, maxClientEntity)
|
|
23
|
+
end
|
|
24
|
+
if RunService:IsServer() then
|
|
25
|
+
world:range(maxClientEntity)
|
|
26
|
+
end
|
|
27
|
+
return world
|
|
28
|
+
end
|
|
29
|
+
local Covenant
|
|
30
|
+
do
|
|
31
|
+
Covenant = setmetatable({}, {
|
|
32
|
+
__tostring = function()
|
|
33
|
+
return "Covenant"
|
|
34
|
+
end,
|
|
35
|
+
})
|
|
36
|
+
Covenant.__index = Covenant
|
|
37
|
+
function Covenant.new(...)
|
|
38
|
+
local self = setmetatable({}, Covenant)
|
|
39
|
+
return self:constructor(...) or self
|
|
40
|
+
end
|
|
41
|
+
function Covenant:constructor(_param)
|
|
42
|
+
local replicationSend = _param.replicationSend
|
|
43
|
+
local replicationConnect = _param.replicationConnect
|
|
44
|
+
local replicationSendAll = _param.replicationSendAll
|
|
45
|
+
local predictionSend = _param.predictionSend
|
|
46
|
+
local predictionConnect = _param.predictionConnect
|
|
47
|
+
self._world = createWorldWithRange(1000, 20000)
|
|
48
|
+
self.systems = {}
|
|
49
|
+
self.worldChangesForReplication = {}
|
|
50
|
+
self.worldChangesForPrediction = {}
|
|
51
|
+
self.underivedStringifiedComponents = {}
|
|
52
|
+
self.replicatedStringifiedComponents = {}
|
|
53
|
+
self.predictedStringifiedComponents = {}
|
|
54
|
+
self.started = false
|
|
55
|
+
self.stringifiedComponentSubscribers = {}
|
|
56
|
+
self.stringifiedComponentValidators = {}
|
|
57
|
+
self.replicationSend = replicationSend
|
|
58
|
+
self.replicationConnect = replicationConnect
|
|
59
|
+
self.replicationSendAll = replicationSendAll
|
|
60
|
+
self.predictionSend = predictionSend
|
|
61
|
+
self.predictionConnect = predictionConnect
|
|
62
|
+
self:setupReplication()
|
|
63
|
+
self:setupPrediction()
|
|
64
|
+
end
|
|
65
|
+
function Covenant:setupPredictionClient()
|
|
66
|
+
self:schedule(RunService.Heartbeat, function()
|
|
67
|
+
if next(self.worldChangesForPrediction) == nil then
|
|
68
|
+
return nil
|
|
69
|
+
end
|
|
70
|
+
local currentWorldChanges = self.worldChangesForPrediction
|
|
71
|
+
self.worldChangesForPrediction = {}
|
|
72
|
+
self.predictionSend(currentWorldChanges)
|
|
73
|
+
end, math.huge)
|
|
74
|
+
end
|
|
75
|
+
function Covenant:setupPredictionServer()
|
|
76
|
+
self.predictionConnect(function(player, worldChanges)
|
|
77
|
+
local worldReconciliation = {}
|
|
78
|
+
-- ▼ ReadonlyMap.forEach ▼
|
|
79
|
+
local _callback = function(componentChanges, stringifiedComponent)
|
|
80
|
+
local component = tonumber(stringifiedComponent)
|
|
81
|
+
local _stringifiedComponentValidators = self.stringifiedComponentValidators
|
|
82
|
+
local _stringifiedComponent = stringifiedComponent
|
|
83
|
+
local validator = _stringifiedComponentValidators[_stringifiedComponent]
|
|
84
|
+
if not validator then
|
|
85
|
+
return nil
|
|
86
|
+
end
|
|
87
|
+
-- ▼ ReadonlyMap.forEach ▼
|
|
88
|
+
local _callback_1 = function(state, stringifiedEntity)
|
|
89
|
+
local entity = tonumber(stringifiedEntity)
|
|
90
|
+
if not self:worldContains(entity) then
|
|
91
|
+
return nil
|
|
92
|
+
end
|
|
93
|
+
local newState = if state == Remove then nil else state
|
|
94
|
+
local lastState = self:worldGet(entity, component)
|
|
95
|
+
local valid = validator(player, entity, newState, lastState)
|
|
96
|
+
if valid then
|
|
97
|
+
self:worldSet(entity, component, newState)
|
|
98
|
+
else
|
|
99
|
+
local _stringifiedEntity = stringifiedEntity
|
|
100
|
+
local entityReconciliations = worldReconciliation[_stringifiedEntity]
|
|
101
|
+
local _arg0 = entityReconciliations ~= Delete
|
|
102
|
+
assert(_arg0)
|
|
103
|
+
if entityReconciliations == nil then
|
|
104
|
+
entityReconciliations = {}
|
|
105
|
+
local _stringifiedEntity_1 = stringifiedEntity
|
|
106
|
+
local _entityReconciliations = entityReconciliations
|
|
107
|
+
worldReconciliation[_stringifiedEntity_1] = _entityReconciliations
|
|
108
|
+
end
|
|
109
|
+
local _entityReconciliations = entityReconciliations
|
|
110
|
+
local _exp = stringifiedComponent
|
|
111
|
+
local _condition = self:worldGet(entity, component)
|
|
112
|
+
if _condition == nil then
|
|
113
|
+
_condition = Remove
|
|
114
|
+
end
|
|
115
|
+
_entityReconciliations[_exp] = _condition
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
for _k, _v in componentChanges do
|
|
119
|
+
_callback_1(_v, _k, componentChanges)
|
|
120
|
+
end
|
|
121
|
+
-- ▲ ReadonlyMap.forEach ▲
|
|
122
|
+
end
|
|
123
|
+
for _k, _v in worldChanges do
|
|
124
|
+
_callback(_v, _k, worldChanges)
|
|
125
|
+
end
|
|
126
|
+
-- ▲ ReadonlyMap.forEach ▲
|
|
127
|
+
if not (next(worldReconciliation) == nil) then
|
|
128
|
+
self.replicationSend(player, worldReconciliation)
|
|
129
|
+
end
|
|
130
|
+
end)
|
|
131
|
+
end
|
|
132
|
+
function Covenant:setupPrediction()
|
|
133
|
+
if RunService:IsClient() then
|
|
134
|
+
self:setupPredictionClient()
|
|
135
|
+
end
|
|
136
|
+
if RunService:IsServer() then
|
|
137
|
+
self:setupPredictionServer()
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
function Covenant:setupRelicationServer()
|
|
141
|
+
self:schedule(RunService.Heartbeat, function()
|
|
142
|
+
if next(self.worldChangesForReplication) == nil then
|
|
143
|
+
return nil
|
|
144
|
+
end
|
|
145
|
+
local currentWorldChanges = self.worldChangesForReplication
|
|
146
|
+
self.worldChangesForReplication = {}
|
|
147
|
+
if self.replicationSendAll ~= nil then
|
|
148
|
+
self.replicationSendAll(currentWorldChanges)
|
|
149
|
+
else
|
|
150
|
+
local _exp = Players:GetPlayers()
|
|
151
|
+
-- ▼ ReadonlyArray.forEach ▼
|
|
152
|
+
local _callback = function(player)
|
|
153
|
+
self.replicationSend(player, currentWorldChanges)
|
|
154
|
+
end
|
|
155
|
+
for _k, _v in _exp do
|
|
156
|
+
_callback(_v, _k - 1, _exp)
|
|
157
|
+
end
|
|
158
|
+
-- ▲ ReadonlyArray.forEach ▲
|
|
159
|
+
end
|
|
160
|
+
end, math.huge)
|
|
161
|
+
end
|
|
162
|
+
function Covenant:setupReplicationPayload()
|
|
163
|
+
Players.PlayerAdded:Connect(function(player)
|
|
164
|
+
task.defer(function()
|
|
165
|
+
if not player:IsDescendantOf(Players) then
|
|
166
|
+
return nil
|
|
167
|
+
end
|
|
168
|
+
local worldPayload = {}
|
|
169
|
+
local _exp = self.replicatedStringifiedComponents
|
|
170
|
+
-- ▼ ReadonlySet.forEach ▼
|
|
171
|
+
local _callback = function(stringifiedComponent)
|
|
172
|
+
local component = tonumber(stringifiedComponent)
|
|
173
|
+
for entity, state in self:worldQuery(component) do
|
|
174
|
+
local _arg0 = tostring(entity)
|
|
175
|
+
local entityData = worldPayload[_arg0]
|
|
176
|
+
if entityData == nil then
|
|
177
|
+
entityData = {}
|
|
178
|
+
local _arg0_1 = tostring(entity)
|
|
179
|
+
local _entityData = entityData
|
|
180
|
+
worldPayload[_arg0_1] = _entityData
|
|
181
|
+
end
|
|
182
|
+
local _arg0_1 = entityData ~= Delete
|
|
183
|
+
assert(_arg0_1)
|
|
184
|
+
local _entityData = entityData
|
|
185
|
+
local _stringifiedComponent = stringifiedComponent
|
|
186
|
+
_entityData[_stringifiedComponent] = state
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
for _v in _exp do
|
|
190
|
+
_callback(_v, _v, _exp)
|
|
191
|
+
end
|
|
192
|
+
-- ▲ ReadonlySet.forEach ▲
|
|
193
|
+
self.replicationSend(player, worldPayload)
|
|
194
|
+
end)
|
|
195
|
+
end)
|
|
196
|
+
end
|
|
197
|
+
function Covenant:setupReplicationClient()
|
|
198
|
+
self.replicationConnect(function(worldChanges)
|
|
199
|
+
-- ▼ ReadonlyMap.forEach ▼
|
|
200
|
+
local _callback = function(entityData, stringifiedEntity)
|
|
201
|
+
local entity = tonumber(stringifiedEntity)
|
|
202
|
+
if entityData == Delete then
|
|
203
|
+
self:worldDelete(entity)
|
|
204
|
+
return nil
|
|
205
|
+
end
|
|
206
|
+
-- ▼ ReadonlyMap.forEach ▼
|
|
207
|
+
local _callback_1 = function(state, stringifiedComponent)
|
|
208
|
+
local component = tonumber(stringifiedComponent)
|
|
209
|
+
if state == Remove then
|
|
210
|
+
self:worldSet(entity, component, nil, true)
|
|
211
|
+
else
|
|
212
|
+
self:worldSet(entity, component, state, true)
|
|
213
|
+
end
|
|
214
|
+
end
|
|
215
|
+
for _k, _v in entityData do
|
|
216
|
+
_callback_1(_v, _k, entityData)
|
|
217
|
+
end
|
|
218
|
+
-- ▲ ReadonlyMap.forEach ▲
|
|
219
|
+
end
|
|
220
|
+
for _k, _v in worldChanges do
|
|
221
|
+
_callback(_v, _k, worldChanges)
|
|
222
|
+
end
|
|
223
|
+
-- ▲ ReadonlyMap.forEach ▲
|
|
224
|
+
end)
|
|
225
|
+
end
|
|
226
|
+
function Covenant:setupReplication()
|
|
227
|
+
if RunService:IsServer() then
|
|
228
|
+
self:setupRelicationServer()
|
|
229
|
+
self:setupReplicationPayload()
|
|
230
|
+
end
|
|
231
|
+
if RunService:IsClient() then
|
|
232
|
+
self:setupReplicationClient()
|
|
233
|
+
end
|
|
234
|
+
end
|
|
235
|
+
function Covenant:start()
|
|
236
|
+
local _arg0 = not self.started
|
|
237
|
+
assert(_arg0, "Already started")
|
|
238
|
+
local _exp = next(self.underivedStringifiedComponents) == nil
|
|
239
|
+
-- ▼ ReadonlySet.size ▼
|
|
240
|
+
local _size = 0
|
|
241
|
+
for _ in self.underivedStringifiedComponents do
|
|
242
|
+
_size += 1
|
|
243
|
+
end
|
|
244
|
+
-- ▲ ReadonlySet.size ▲
|
|
245
|
+
local _arg1 = `There are {_size} components that are not derived`
|
|
246
|
+
assert(_exp, _arg1)
|
|
247
|
+
self.started = true
|
|
248
|
+
local _exp_1 = self.systems
|
|
249
|
+
-- ▼ ReadonlyMap.forEach ▼
|
|
250
|
+
local _callback = function(systemsOfEvent, event)
|
|
251
|
+
local _systems = self.systems
|
|
252
|
+
local _exp_2 = event
|
|
253
|
+
table.sort(systemsOfEvent, function(a, b)
|
|
254
|
+
return a.priority < b.priority
|
|
255
|
+
end)
|
|
256
|
+
local _systemsOfEvent = systemsOfEvent
|
|
257
|
+
_systems[_exp_2] = _systemsOfEvent
|
|
258
|
+
return _systems
|
|
259
|
+
end
|
|
260
|
+
for _k, _v in _exp_1 do
|
|
261
|
+
_callback(_v, _k, _exp_1)
|
|
262
|
+
end
|
|
263
|
+
-- ▲ ReadonlyMap.forEach ▲
|
|
264
|
+
local _exp_2 = self.systems
|
|
265
|
+
-- ▼ ReadonlyMap.forEach ▼
|
|
266
|
+
local _callback_1 = function(systemsOfEvent, event)
|
|
267
|
+
event:Connect(function()
|
|
268
|
+
-- ▼ ReadonlyArray.forEach ▼
|
|
269
|
+
local _callback_2 = function(_param)
|
|
270
|
+
local system = _param.system
|
|
271
|
+
system()
|
|
272
|
+
end
|
|
273
|
+
for _k, _v in systemsOfEvent do
|
|
274
|
+
_callback_2(_v, _k - 1, systemsOfEvent)
|
|
275
|
+
end
|
|
276
|
+
-- ▲ ReadonlyArray.forEach ▲
|
|
277
|
+
end)
|
|
278
|
+
end
|
|
279
|
+
for _k, _v in _exp_2 do
|
|
280
|
+
_callback_1(_v, _k, _exp_2)
|
|
281
|
+
end
|
|
282
|
+
-- ▲ ReadonlyMap.forEach ▲
|
|
283
|
+
end
|
|
284
|
+
function Covenant:schedule(event, system, priority)
|
|
285
|
+
if priority == nil then
|
|
286
|
+
priority = 0
|
|
287
|
+
end
|
|
288
|
+
local _arg0 = not self.started
|
|
289
|
+
assert(_arg0, "Attempted to schedule system after starting")
|
|
290
|
+
local _systems = self.systems
|
|
291
|
+
local _event = event
|
|
292
|
+
local systemsOfEvent = _systems[_event]
|
|
293
|
+
if systemsOfEvent == nil then
|
|
294
|
+
systemsOfEvent = {}
|
|
295
|
+
local _systems_1 = self.systems
|
|
296
|
+
local _event_1 = event
|
|
297
|
+
local _systemsOfEvent = systemsOfEvent
|
|
298
|
+
_systems_1[_event_1] = _systemsOfEvent
|
|
299
|
+
end
|
|
300
|
+
local _systemsOfEvent = systemsOfEvent
|
|
301
|
+
local _arg0_1 = {
|
|
302
|
+
system = system,
|
|
303
|
+
priority = priority,
|
|
304
|
+
}
|
|
305
|
+
table.insert(_systemsOfEvent, _arg0_1)
|
|
306
|
+
end
|
|
307
|
+
function Covenant:worldSet(entity, component, newState, doNotReconcile)
|
|
308
|
+
if doNotReconcile == nil then
|
|
309
|
+
doNotReconcile = false
|
|
310
|
+
end
|
|
311
|
+
if not self:worldContains(entity) then
|
|
312
|
+
self._world:entity(entity)
|
|
313
|
+
end
|
|
314
|
+
local lastState = self:worldGet(entity, component)
|
|
315
|
+
if newState == lastState then
|
|
316
|
+
return nil
|
|
317
|
+
end
|
|
318
|
+
if newState == nil then
|
|
319
|
+
self._world:remove(entity, component)
|
|
320
|
+
else
|
|
321
|
+
self._world:set(entity, component, newState)
|
|
322
|
+
end
|
|
323
|
+
local _stringifiedComponentSubscribers = self.stringifiedComponentSubscribers
|
|
324
|
+
local _arg0 = tostring(component)
|
|
325
|
+
local _result = _stringifiedComponentSubscribers[_arg0]
|
|
326
|
+
if _result ~= nil then
|
|
327
|
+
-- ▼ ReadonlySet.forEach ▼
|
|
328
|
+
local _callback = function(subscriber)
|
|
329
|
+
subscriber(entity, newState, lastState)
|
|
330
|
+
end
|
|
331
|
+
for _v in _result do
|
|
332
|
+
_callback(_v, _v, _result)
|
|
333
|
+
end
|
|
334
|
+
-- ▲ ReadonlySet.forEach ▲
|
|
335
|
+
end
|
|
336
|
+
if doNotReconcile then
|
|
337
|
+
return nil
|
|
338
|
+
end
|
|
339
|
+
local _replicatedStringifiedComponents = self.replicatedStringifiedComponents
|
|
340
|
+
local _arg0_1 = tostring(component)
|
|
341
|
+
if _replicatedStringifiedComponents[_arg0_1] ~= nil then
|
|
342
|
+
local _worldChangesForReplication = self.worldChangesForReplication
|
|
343
|
+
local _arg0_2 = tostring(entity)
|
|
344
|
+
local entityChanges = _worldChangesForReplication[_arg0_2]
|
|
345
|
+
if entityChanges == nil then
|
|
346
|
+
entityChanges = {}
|
|
347
|
+
local _worldChangesForReplication_1 = self.worldChangesForReplication
|
|
348
|
+
local _arg0_3 = tostring(entity)
|
|
349
|
+
local _entityChanges = entityChanges
|
|
350
|
+
_worldChangesForReplication_1[_arg0_3] = _entityChanges
|
|
351
|
+
end
|
|
352
|
+
if entityChanges ~= Delete then
|
|
353
|
+
local _entityChanges = entityChanges
|
|
354
|
+
local _exp = tostring(component)
|
|
355
|
+
local _condition = newState
|
|
356
|
+
if _condition == nil then
|
|
357
|
+
_condition = Remove
|
|
358
|
+
end
|
|
359
|
+
_entityChanges[_exp] = _condition
|
|
360
|
+
end
|
|
361
|
+
end
|
|
362
|
+
local _condition = RunService:IsClient()
|
|
363
|
+
if _condition then
|
|
364
|
+
local _predictedStringifiedComponents = self.predictedStringifiedComponents
|
|
365
|
+
local _arg0_2 = tostring(component)
|
|
366
|
+
_condition = _predictedStringifiedComponents[_arg0_2] ~= nil
|
|
367
|
+
end
|
|
368
|
+
if _condition then
|
|
369
|
+
local _worldChangesForPrediction = self.worldChangesForPrediction
|
|
370
|
+
local _arg0_2 = tostring(component)
|
|
371
|
+
local componentChanges = _worldChangesForPrediction[_arg0_2]
|
|
372
|
+
if componentChanges == nil then
|
|
373
|
+
componentChanges = {}
|
|
374
|
+
local _worldChangesForPrediction_1 = self.worldChangesForPrediction
|
|
375
|
+
local _arg0_3 = tostring(component)
|
|
376
|
+
local _componentChanges = componentChanges
|
|
377
|
+
_worldChangesForPrediction_1[_arg0_3] = _componentChanges
|
|
378
|
+
end
|
|
379
|
+
local _componentChanges = componentChanges
|
|
380
|
+
local _exp = tostring(entity)
|
|
381
|
+
local _condition_1 = newState
|
|
382
|
+
if _condition_1 == nil then
|
|
383
|
+
_condition_1 = Remove
|
|
384
|
+
end
|
|
385
|
+
_componentChanges[_exp] = _condition_1
|
|
386
|
+
end
|
|
387
|
+
end
|
|
388
|
+
function Covenant:subscribeComponent(component, subscriber)
|
|
389
|
+
local _stringifiedComponentSubscribers = self.stringifiedComponentSubscribers
|
|
390
|
+
local _arg0 = tostring(component)
|
|
391
|
+
local subscribers = _stringifiedComponentSubscribers[_arg0]
|
|
392
|
+
if subscribers == nil then
|
|
393
|
+
subscribers = {}
|
|
394
|
+
local _stringifiedComponentSubscribers_1 = self.stringifiedComponentSubscribers
|
|
395
|
+
local _arg0_1 = tostring(component)
|
|
396
|
+
local _subscribers = subscribers
|
|
397
|
+
_stringifiedComponentSubscribers_1[_arg0_1] = _subscribers
|
|
398
|
+
end
|
|
399
|
+
local subscriberElement = subscriber
|
|
400
|
+
subscribers[subscriberElement] = true
|
|
401
|
+
return function()
|
|
402
|
+
subscribers[subscriberElement] = nil
|
|
403
|
+
end
|
|
404
|
+
end
|
|
405
|
+
function Covenant:worldDelete(entity)
|
|
406
|
+
if not self:worldContains(entity) then
|
|
407
|
+
return nil
|
|
408
|
+
end
|
|
409
|
+
local toDelete = { entity }
|
|
410
|
+
local processed = {}
|
|
411
|
+
while #toDelete > 0 do
|
|
412
|
+
-- ▼ Array.pop ▼
|
|
413
|
+
local _length = #toDelete
|
|
414
|
+
local _result = toDelete[_length]
|
|
415
|
+
toDelete[_length] = nil
|
|
416
|
+
-- ▲ Array.pop ▲
|
|
417
|
+
local currentEntity = _result
|
|
418
|
+
if processed[currentEntity] ~= nil or not self:worldContains(currentEntity) then
|
|
419
|
+
continue
|
|
420
|
+
end
|
|
421
|
+
processed[currentEntity] = true
|
|
422
|
+
for childEntity in self:worldQuery(pair(ChildOf, currentEntity)) do
|
|
423
|
+
table.insert(toDelete, childEntity)
|
|
424
|
+
end
|
|
425
|
+
end
|
|
426
|
+
-- ▼ ReadonlySet.forEach ▼
|
|
427
|
+
local _callback = function(entityToDelete)
|
|
428
|
+
self._world:delete(entityToDelete)
|
|
429
|
+
local _worldChangesForReplication = self.worldChangesForReplication
|
|
430
|
+
local _arg0 = tostring(entityToDelete)
|
|
431
|
+
_worldChangesForReplication[_arg0] = Delete
|
|
432
|
+
end
|
|
433
|
+
for _v in processed do
|
|
434
|
+
_callback(_v, _v, processed)
|
|
435
|
+
end
|
|
436
|
+
-- ▲ ReadonlySet.forEach ▲
|
|
437
|
+
end
|
|
438
|
+
function Covenant:worldComponent()
|
|
439
|
+
local c = self._world:component()
|
|
440
|
+
return c
|
|
441
|
+
end
|
|
442
|
+
function Covenant:checkComponentDerived(component)
|
|
443
|
+
local _underivedStringifiedComponents = self.underivedStringifiedComponents
|
|
444
|
+
local _arg0 = tostring(component)
|
|
445
|
+
local _arg0_1 = _underivedStringifiedComponents[_arg0] ~= nil
|
|
446
|
+
local _arg1 = `Component {component} is already derived`
|
|
447
|
+
assert(_arg0_1, _arg1)
|
|
448
|
+
local _underivedStringifiedComponents_1 = self.underivedStringifiedComponents
|
|
449
|
+
local _arg0_2 = tostring(component)
|
|
450
|
+
_underivedStringifiedComponents_1[_arg0_2] = nil
|
|
451
|
+
end
|
|
452
|
+
function Covenant:defineComponentNetworkBehavior(component, replicated, predictionValidator)
|
|
453
|
+
if replicated then
|
|
454
|
+
local _replicatedStringifiedComponents = self.replicatedStringifiedComponents
|
|
455
|
+
local _arg0 = tostring(component)
|
|
456
|
+
_replicatedStringifiedComponents[_arg0] = true
|
|
457
|
+
end
|
|
458
|
+
if predictionValidator then
|
|
459
|
+
local _predictedStringifiedComponents = self.predictedStringifiedComponents
|
|
460
|
+
local _arg0 = tostring(component)
|
|
461
|
+
_predictedStringifiedComponents[_arg0] = true
|
|
462
|
+
local _stringifiedComponentValidators = self.stringifiedComponentValidators
|
|
463
|
+
local _arg0_1 = tostring(component)
|
|
464
|
+
local _predictionValidator = predictionValidator
|
|
465
|
+
_stringifiedComponentValidators[_arg0_1] = _predictionValidator
|
|
466
|
+
end
|
|
467
|
+
end
|
|
468
|
+
function Covenant:deriveComponent(_param)
|
|
469
|
+
local component = _param.component
|
|
470
|
+
local queriedComponents = _param.queriedComponents
|
|
471
|
+
local recipe = _param.recipe
|
|
472
|
+
local replicated = _param.replicated
|
|
473
|
+
local predictionValidator = _param.predictionValidator
|
|
474
|
+
self:checkComponentDerived(component)
|
|
475
|
+
self:defineComponentNetworkBehavior(component, replicated, predictionValidator)
|
|
476
|
+
local queryThisComponent = self:worldQuery(component):cached()
|
|
477
|
+
local willUpdate = true
|
|
478
|
+
local function indicateUpdate()
|
|
479
|
+
willUpdate = true
|
|
480
|
+
end
|
|
481
|
+
local hooks = createHooks({
|
|
482
|
+
indicateUpdate = indicateUpdate,
|
|
483
|
+
subscribeComponent = function(component, subscriber)
|
|
484
|
+
self:subscribeComponent(component, subscriber)
|
|
485
|
+
end,
|
|
486
|
+
})
|
|
487
|
+
-- ▼ ReadonlyArray.map ▼
|
|
488
|
+
local _newValue = table.create(#queriedComponents)
|
|
489
|
+
local _callback = function(components)
|
|
490
|
+
return self:worldQuery(unpack(components)):cached()
|
|
491
|
+
end
|
|
492
|
+
for _k, _v in queriedComponents do
|
|
493
|
+
_newValue[_k] = _callback(_v, _k - 1, queriedComponents)
|
|
494
|
+
end
|
|
495
|
+
-- ▲ ReadonlyArray.map ▲
|
|
496
|
+
local queries = _newValue
|
|
497
|
+
local _array = {}
|
|
498
|
+
local _length = #_array
|
|
499
|
+
-- ▼ ReadonlyArray.reduce ▼
|
|
500
|
+
local _result = {}
|
|
501
|
+
local _callback_1 = function(accum, components)
|
|
502
|
+
-- ▼ ReadonlyArray.forEach ▼
|
|
503
|
+
local _callback_2 = function(component)
|
|
504
|
+
local stringifiedComponent = tostring(component)
|
|
505
|
+
accum[stringifiedComponent] = true
|
|
506
|
+
end
|
|
507
|
+
for _k, _v in components do
|
|
508
|
+
_callback_2(_v, _k - 1, components)
|
|
509
|
+
end
|
|
510
|
+
-- ▲ ReadonlyArray.forEach ▲
|
|
511
|
+
return accum
|
|
512
|
+
end
|
|
513
|
+
for _i = 1, #queriedComponents do
|
|
514
|
+
_result = _callback_1(_result, queriedComponents[_i], _i - 1, queriedComponents)
|
|
515
|
+
end
|
|
516
|
+
-- ▲ ReadonlyArray.reduce ▲
|
|
517
|
+
for _v in _result do
|
|
518
|
+
_length += 1
|
|
519
|
+
_array[_length] = _v
|
|
520
|
+
end
|
|
521
|
+
-- ▼ ReadonlyArray.map ▼
|
|
522
|
+
local _newValue_1 = table.create(#_array)
|
|
523
|
+
local _callback_2 = function(stringifiedComponent)
|
|
524
|
+
return tonumber(stringifiedComponent)
|
|
525
|
+
end
|
|
526
|
+
for _k, _v in _array do
|
|
527
|
+
_newValue_1[_k] = _callback_2(_v, _k - 1, _array)
|
|
528
|
+
end
|
|
529
|
+
-- ▲ ReadonlyArray.map ▲
|
|
530
|
+
-- ▼ ReadonlyArray.forEach ▼
|
|
531
|
+
local _callback_3 = function(component)
|
|
532
|
+
self:subscribeComponent(component, indicateUpdate)
|
|
533
|
+
end
|
|
534
|
+
for _k, _v in _newValue_1 do
|
|
535
|
+
_callback_3(_v, _k - 1, _newValue_1)
|
|
536
|
+
end
|
|
537
|
+
-- ▲ ReadonlyArray.forEach ▲
|
|
538
|
+
local lastUpdateId = 0
|
|
539
|
+
local updater = function()
|
|
540
|
+
lastUpdateId += 1
|
|
541
|
+
local updateId = lastUpdateId
|
|
542
|
+
local unhandledStringifiedEntities = {}
|
|
543
|
+
local handledStringifiedEntities = {}
|
|
544
|
+
for entity in queryThisComponent do
|
|
545
|
+
local _arg0 = tostring(entity)
|
|
546
|
+
unhandledStringifiedEntities[_arg0] = true
|
|
547
|
+
end
|
|
548
|
+
-- ▼ ReadonlyArray.forEach ▼
|
|
549
|
+
local _callback_4 = function(query)
|
|
550
|
+
for entity in query do
|
|
551
|
+
local stringifiedEntity = tostring(entity)
|
|
552
|
+
if handledStringifiedEntities[stringifiedEntity] ~= nil then
|
|
553
|
+
continue
|
|
554
|
+
end
|
|
555
|
+
handledStringifiedEntities[stringifiedEntity] = true
|
|
556
|
+
unhandledStringifiedEntities[stringifiedEntity] = nil
|
|
557
|
+
local lastState = self:worldGet(entity, component)
|
|
558
|
+
local newState = recipe(entity, lastState, updateId, hooks)
|
|
559
|
+
self:worldSet(entity, component, newState)
|
|
560
|
+
end
|
|
561
|
+
end
|
|
562
|
+
for _k, _v in queries do
|
|
563
|
+
_callback_4(_v, _k - 1, queries)
|
|
564
|
+
end
|
|
565
|
+
-- ▲ ReadonlyArray.forEach ▲
|
|
566
|
+
-- ▼ ReadonlySet.forEach ▼
|
|
567
|
+
local _callback_5 = function(stringifiedEntity)
|
|
568
|
+
local entity = tonumber(stringifiedEntity)
|
|
569
|
+
self:worldSet(entity, component, nil)
|
|
570
|
+
end
|
|
571
|
+
for _v in unhandledStringifiedEntities do
|
|
572
|
+
_callback_5(_v, _v, unhandledStringifiedEntities)
|
|
573
|
+
end
|
|
574
|
+
-- ▲ ReadonlySet.forEach ▲
|
|
575
|
+
end
|
|
576
|
+
self:schedule(RunService.Heartbeat, function()
|
|
577
|
+
if not willUpdate then
|
|
578
|
+
return nil
|
|
579
|
+
end
|
|
580
|
+
willUpdate = false
|
|
581
|
+
updater()
|
|
582
|
+
end)
|
|
583
|
+
end
|
|
584
|
+
function Covenant:deriveChildren(_param)
|
|
585
|
+
local parentComponent = _param.parentComponent
|
|
586
|
+
local parentEntityTrackerComponent = _param.parentEntityTrackerComponent
|
|
587
|
+
local childIdentityComponent = _param.childIdentityComponent
|
|
588
|
+
local getIdentifier = _param.getIdentifier
|
|
589
|
+
local queriedComponents = _param.queriedComponents
|
|
590
|
+
local recipe = _param.recipe
|
|
591
|
+
local replicated = _param.replicated
|
|
592
|
+
local predictionValidator = _param.predictionValidator
|
|
593
|
+
self:checkComponentDerived(parentComponent)
|
|
594
|
+
self:checkComponentDerived(parentEntityTrackerComponent)
|
|
595
|
+
self:checkComponentDerived(childIdentityComponent)
|
|
596
|
+
self:defineComponentNetworkBehavior(parentComponent, replicated, predictionValidator)
|
|
597
|
+
local queryParentComponent = self:worldQuery(parentComponent):cached()
|
|
598
|
+
local willUpdate = true
|
|
599
|
+
local function indicateUpdate()
|
|
600
|
+
willUpdate = true
|
|
601
|
+
end
|
|
602
|
+
local hooks = createHooks({
|
|
603
|
+
indicateUpdate = indicateUpdate,
|
|
604
|
+
subscribeComponent = function(component, subscriber)
|
|
605
|
+
self:subscribeComponent(component, subscriber)
|
|
606
|
+
end,
|
|
607
|
+
})
|
|
608
|
+
-- ▼ ReadonlyArray.map ▼
|
|
609
|
+
local _newValue = table.create(#queriedComponents)
|
|
610
|
+
local _callback = function(components)
|
|
611
|
+
return self:worldQuery(unpack(components)):cached()
|
|
612
|
+
end
|
|
613
|
+
for _k, _v in queriedComponents do
|
|
614
|
+
_newValue[_k] = _callback(_v, _k - 1, queriedComponents)
|
|
615
|
+
end
|
|
616
|
+
-- ▲ ReadonlyArray.map ▲
|
|
617
|
+
local queries = _newValue
|
|
618
|
+
local _array = {}
|
|
619
|
+
local _length = #_array
|
|
620
|
+
-- ▼ ReadonlyArray.reduce ▼
|
|
621
|
+
local _result = {}
|
|
622
|
+
local _callback_1 = function(accum, components)
|
|
623
|
+
-- ▼ ReadonlyArray.forEach ▼
|
|
624
|
+
local _callback_2 = function(component)
|
|
625
|
+
local stringifiedComponent = tostring(component)
|
|
626
|
+
accum[stringifiedComponent] = true
|
|
627
|
+
end
|
|
628
|
+
for _k, _v in components do
|
|
629
|
+
_callback_2(_v, _k - 1, components)
|
|
630
|
+
end
|
|
631
|
+
-- ▲ ReadonlyArray.forEach ▲
|
|
632
|
+
return accum
|
|
633
|
+
end
|
|
634
|
+
for _i = 1, #queriedComponents do
|
|
635
|
+
_result = _callback_1(_result, queriedComponents[_i], _i - 1, queriedComponents)
|
|
636
|
+
end
|
|
637
|
+
-- ▲ ReadonlyArray.reduce ▲
|
|
638
|
+
for _v in _result do
|
|
639
|
+
_length += 1
|
|
640
|
+
_array[_length] = _v
|
|
641
|
+
end
|
|
642
|
+
-- ▼ ReadonlyArray.map ▼
|
|
643
|
+
local _newValue_1 = table.create(#_array)
|
|
644
|
+
local _callback_2 = function(stringifiedComponent)
|
|
645
|
+
return tonumber(stringifiedComponent)
|
|
646
|
+
end
|
|
647
|
+
for _k, _v in _array do
|
|
648
|
+
_newValue_1[_k] = _callback_2(_v, _k - 1, _array)
|
|
649
|
+
end
|
|
650
|
+
-- ▲ ReadonlyArray.map ▲
|
|
651
|
+
-- ▼ ReadonlyArray.forEach ▼
|
|
652
|
+
local _callback_3 = function(component)
|
|
653
|
+
self:subscribeComponent(component, indicateUpdate)
|
|
654
|
+
end
|
|
655
|
+
for _k, _v in _newValue_1 do
|
|
656
|
+
_callback_3(_v, _k - 1, _newValue_1)
|
|
657
|
+
end
|
|
658
|
+
-- ▲ ReadonlyArray.forEach ▲
|
|
659
|
+
local lastUpdateId = 0
|
|
660
|
+
local updater = function()
|
|
661
|
+
lastUpdateId += 1
|
|
662
|
+
local updateId = lastUpdateId
|
|
663
|
+
local unhandledStringifiedEntities = {}
|
|
664
|
+
local handledStringifiedEntities = {}
|
|
665
|
+
for entity in queryParentComponent do
|
|
666
|
+
local _arg0 = tostring(entity)
|
|
667
|
+
unhandledStringifiedEntities[_arg0] = true
|
|
668
|
+
end
|
|
669
|
+
-- ▼ ReadonlyArray.forEach ▼
|
|
670
|
+
local _callback_4 = function(query)
|
|
671
|
+
for entity in query do
|
|
672
|
+
local stringifiedEntity = tostring(entity)
|
|
673
|
+
if handledStringifiedEntities[stringifiedEntity] ~= nil then
|
|
674
|
+
continue
|
|
675
|
+
end
|
|
676
|
+
handledStringifiedEntities[stringifiedEntity] = true
|
|
677
|
+
unhandledStringifiedEntities[stringifiedEntity] = nil
|
|
678
|
+
local entityTracker = self:worldGet(entity, parentEntityTrackerComponent)
|
|
679
|
+
if entityTracker == nil then
|
|
680
|
+
entityTracker = {}
|
|
681
|
+
self:worldSet(entity, parentEntityTrackerComponent, entityTracker)
|
|
682
|
+
end
|
|
683
|
+
local lastState = self:worldGet(entity, parentComponent) or {}
|
|
684
|
+
local newState = recipe(entity, lastState, updateId, hooks)
|
|
685
|
+
self:worldSet(entity, parentComponent, newState)
|
|
686
|
+
local lastStateMap = turnArrayWithIdentifierToMap(lastState, getIdentifier)
|
|
687
|
+
local newStateMap = turnArrayWithIdentifierToMap(newState, getIdentifier)
|
|
688
|
+
local _binding = compareMaps(lastStateMap, newStateMap)
|
|
689
|
+
local entriesChanged = _binding.entriesChanged
|
|
690
|
+
local entriesAdded = _binding.entriesAdded
|
|
691
|
+
local keysRemoved = _binding.keysRemoved
|
|
692
|
+
-- ▼ ReadonlyArray.forEach ▼
|
|
693
|
+
local _callback_5 = function(_param_1)
|
|
694
|
+
local key = _param_1.key
|
|
695
|
+
local value = _param_1.value
|
|
696
|
+
local childEntity = self:worldEntity()
|
|
697
|
+
entityTracker[key] = childEntity
|
|
698
|
+
self:worldSet(childEntity, childIdentityComponent, value)
|
|
699
|
+
self._world:add(childEntity, pair(ChildOf, entity))
|
|
700
|
+
end
|
|
701
|
+
for _k, _v in entriesAdded do
|
|
702
|
+
_callback_5(_v, _k - 1, entriesAdded)
|
|
703
|
+
end
|
|
704
|
+
-- ▲ ReadonlyArray.forEach ▲
|
|
705
|
+
-- ▼ ReadonlyArray.forEach ▼
|
|
706
|
+
local _callback_6 = function(_param_1)
|
|
707
|
+
local key = _param_1.key
|
|
708
|
+
local value = _param_1.value
|
|
709
|
+
local childEntity = entityTracker[key]
|
|
710
|
+
assert(childEntity ~= 0 and childEntity == childEntity and childEntity)
|
|
711
|
+
local _arg0 = self:worldContains(childEntity)
|
|
712
|
+
assert(_arg0)
|
|
713
|
+
self:worldSet(childEntity, childIdentityComponent, value)
|
|
714
|
+
end
|
|
715
|
+
for _k, _v in entriesChanged do
|
|
716
|
+
_callback_6(_v, _k - 1, entriesChanged)
|
|
717
|
+
end
|
|
718
|
+
-- ▲ ReadonlyArray.forEach ▲
|
|
719
|
+
-- ▼ ReadonlyArray.forEach ▼
|
|
720
|
+
local _callback_7 = function(key)
|
|
721
|
+
local _entityTracker = entityTracker
|
|
722
|
+
local _key = key
|
|
723
|
+
local childEntity = _entityTracker[_key]
|
|
724
|
+
assert(childEntity ~= 0 and childEntity == childEntity and childEntity)
|
|
725
|
+
local _arg0 = self:worldContains(childEntity)
|
|
726
|
+
assert(_arg0)
|
|
727
|
+
self:worldDelete(childEntity)
|
|
728
|
+
local _entityTracker_1 = entityTracker
|
|
729
|
+
local _key_1 = key
|
|
730
|
+
_entityTracker_1[_key_1] = nil
|
|
731
|
+
end
|
|
732
|
+
for _k, _v in keysRemoved do
|
|
733
|
+
_callback_7(_v, _k - 1, keysRemoved)
|
|
734
|
+
end
|
|
735
|
+
-- ▲ ReadonlyArray.forEach ▲
|
|
736
|
+
end
|
|
737
|
+
end
|
|
738
|
+
for _k, _v in queries do
|
|
739
|
+
_callback_4(_v, _k - 1, queries)
|
|
740
|
+
end
|
|
741
|
+
-- ▲ ReadonlyArray.forEach ▲
|
|
742
|
+
-- ▼ ReadonlySet.forEach ▼
|
|
743
|
+
local _callback_5 = function(stringifiedEntity)
|
|
744
|
+
local entity = tonumber(stringifiedEntity)
|
|
745
|
+
local children = self:worldGet(entity, parentEntityTrackerComponent)
|
|
746
|
+
if children ~= nil then
|
|
747
|
+
-- ▼ ReadonlyMap.forEach ▼
|
|
748
|
+
local _callback_6 = function(childEntity)
|
|
749
|
+
self:worldDelete(childEntity)
|
|
750
|
+
end
|
|
751
|
+
for _k, _v in children do
|
|
752
|
+
_callback_6(_v, _k, children)
|
|
753
|
+
end
|
|
754
|
+
-- ▲ ReadonlyMap.forEach ▲
|
|
755
|
+
end
|
|
756
|
+
self:worldSet(entity, parentComponent, nil)
|
|
757
|
+
self:worldSet(entity, parentEntityTrackerComponent, nil)
|
|
758
|
+
end
|
|
759
|
+
for _v in unhandledStringifiedEntities do
|
|
760
|
+
_callback_5(_v, _v, unhandledStringifiedEntities)
|
|
761
|
+
end
|
|
762
|
+
-- ▲ ReadonlySet.forEach ▲
|
|
763
|
+
end
|
|
764
|
+
self:schedule(RunService.Heartbeat, function()
|
|
765
|
+
if not willUpdate then
|
|
766
|
+
return nil
|
|
767
|
+
end
|
|
768
|
+
willUpdate = false
|
|
769
|
+
updater()
|
|
770
|
+
end)
|
|
771
|
+
end
|
|
772
|
+
function Covenant:deriveRootEntity(_param)
|
|
773
|
+
local identityComponent = _param.identityComponent
|
|
774
|
+
local recipe = _param.recipe
|
|
775
|
+
local replicated = _param.replicated
|
|
776
|
+
self:checkComponentDerived(identityComponent)
|
|
777
|
+
self:defineComponentNetworkBehavior(identityComponent, replicated, false)
|
|
778
|
+
local willUpdate = true
|
|
779
|
+
local function indicateUpdate()
|
|
780
|
+
willUpdate = true
|
|
781
|
+
end
|
|
782
|
+
local hooks = createHooks({
|
|
783
|
+
indicateUpdate = indicateUpdate,
|
|
784
|
+
subscribeComponent = function(component, subscriber)
|
|
785
|
+
self:subscribeComponent(component, subscriber)
|
|
786
|
+
end,
|
|
787
|
+
})
|
|
788
|
+
local lastUpdateId = 0
|
|
789
|
+
local updater = function()
|
|
790
|
+
lastUpdateId += 1
|
|
791
|
+
local _binding = recipe(lastUpdateId, hooks)
|
|
792
|
+
local statesToCreate = _binding.statesToCreate
|
|
793
|
+
local entitiesToDelete = _binding.entitiesToDelete
|
|
794
|
+
-- ▼ ReadonlyArray.forEach ▼
|
|
795
|
+
local _callback = function(state)
|
|
796
|
+
local entity = self:worldEntity()
|
|
797
|
+
self:worldSet(entity, identityComponent, state)
|
|
798
|
+
end
|
|
799
|
+
for _k, _v in statesToCreate do
|
|
800
|
+
_callback(_v, _k - 1, statesToCreate)
|
|
801
|
+
end
|
|
802
|
+
-- ▲ ReadonlyArray.forEach ▲
|
|
803
|
+
-- ▼ ReadonlyArray.forEach ▼
|
|
804
|
+
local _callback_1 = function(entity)
|
|
805
|
+
self:worldDelete(entity)
|
|
806
|
+
end
|
|
807
|
+
for _k, _v in entitiesToDelete do
|
|
808
|
+
_callback_1(_v, _k - 1, entitiesToDelete)
|
|
809
|
+
end
|
|
810
|
+
-- ▲ ReadonlyArray.forEach ▲
|
|
811
|
+
end
|
|
812
|
+
self:schedule(RunService.Heartbeat, function()
|
|
813
|
+
if not willUpdate then
|
|
814
|
+
return nil
|
|
815
|
+
end
|
|
816
|
+
willUpdate = false
|
|
817
|
+
updater()
|
|
818
|
+
end)
|
|
819
|
+
end
|
|
820
|
+
function Covenant:worldEntity()
|
|
821
|
+
return self._world:entity()
|
|
822
|
+
end
|
|
823
|
+
function Covenant:worldQuery(...)
|
|
824
|
+
local components = { ... }
|
|
825
|
+
return self._world:query(unpack(components))
|
|
826
|
+
end
|
|
827
|
+
function Covenant:worldHas(entity, ...)
|
|
828
|
+
local components = { ... }
|
|
829
|
+
return self._world:has(entity, unpack(components))
|
|
830
|
+
end
|
|
831
|
+
function Covenant:worldGet(entity, ...)
|
|
832
|
+
local components = { ... }
|
|
833
|
+
return self._world:get(entity, unpack(components))
|
|
834
|
+
end
|
|
835
|
+
function Covenant:worldContains(entity)
|
|
836
|
+
return self._world:contains(entity)
|
|
837
|
+
end
|
|
838
|
+
end
|
|
839
|
+
return {
|
|
840
|
+
Covenant = Covenant,
|
|
841
|
+
}
|
package/src/helpers.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Discriminator } from "./hooks";
|
|
2
|
+
export declare function turnArrayWithIdentifierToMap<T extends defined>(array: ReadonlyArray<T>, getIdentifier: (state: T) => Discriminator): Map<defined, T>;
|
|
3
|
+
export declare function compareMaps<TKey extends Discriminator, TValue extends defined>(previousMap: ReadonlyMap<TKey, TValue>, newMap: ReadonlyMap<TKey, TValue>): {
|
|
4
|
+
entriesAdded: {
|
|
5
|
+
key: TKey;
|
|
6
|
+
value: TValue;
|
|
7
|
+
}[];
|
|
8
|
+
entriesChanged: {
|
|
9
|
+
key: TKey;
|
|
10
|
+
value: TValue;
|
|
11
|
+
previousValue: TValue;
|
|
12
|
+
}[];
|
|
13
|
+
keysRemoved: TKey[];
|
|
14
|
+
};
|
package/src/helpers.luau
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
-- Compiled with roblox-ts v3.0.0
|
|
2
|
+
local function turnArrayWithIdentifierToMap(array, getIdentifier)
|
|
3
|
+
local newMap = {}
|
|
4
|
+
-- ▼ ReadonlyArray.forEach ▼
|
|
5
|
+
local _callback = function(value)
|
|
6
|
+
local identifier = getIdentifier(value)
|
|
7
|
+
local _value = value
|
|
8
|
+
newMap[identifier] = _value
|
|
9
|
+
end
|
|
10
|
+
for _k, _v in array do
|
|
11
|
+
_callback(_v, _k - 1, array)
|
|
12
|
+
end
|
|
13
|
+
-- ▲ ReadonlyArray.forEach ▲
|
|
14
|
+
return newMap
|
|
15
|
+
end
|
|
16
|
+
local function compareMaps(previousMap, newMap)
|
|
17
|
+
local entriesAdded = {}
|
|
18
|
+
local entriesChanged = {}
|
|
19
|
+
local keysRemoved = {}
|
|
20
|
+
-- ▼ ReadonlyMap.forEach ▼
|
|
21
|
+
local _callback = function(value, key)
|
|
22
|
+
local _previousMap = previousMap
|
|
23
|
+
local _key = key
|
|
24
|
+
if not (_previousMap[_key] ~= nil) then
|
|
25
|
+
local _arg0 = {
|
|
26
|
+
key = key,
|
|
27
|
+
value = value,
|
|
28
|
+
}
|
|
29
|
+
table.insert(entriesAdded, _arg0)
|
|
30
|
+
else
|
|
31
|
+
local _previousMap_1 = previousMap
|
|
32
|
+
local _key_1 = key
|
|
33
|
+
local previousValue = _previousMap_1[_key_1]
|
|
34
|
+
if previousValue ~= value then
|
|
35
|
+
local _arg0 = {
|
|
36
|
+
key = key,
|
|
37
|
+
value = value,
|
|
38
|
+
previousValue = previousValue,
|
|
39
|
+
}
|
|
40
|
+
table.insert(entriesChanged, _arg0)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
for _k, _v in newMap do
|
|
45
|
+
_callback(_v, _k, newMap)
|
|
46
|
+
end
|
|
47
|
+
-- ▲ ReadonlyMap.forEach ▲
|
|
48
|
+
-- ▼ ReadonlyMap.forEach ▼
|
|
49
|
+
local _callback_1 = function(_, key)
|
|
50
|
+
local _newMap = newMap
|
|
51
|
+
local _key = key
|
|
52
|
+
if not (_newMap[_key] ~= nil) then
|
|
53
|
+
local _key_1 = key
|
|
54
|
+
table.insert(keysRemoved, _key_1)
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
for _k, _v in previousMap do
|
|
58
|
+
_callback_1(_v, _k, previousMap)
|
|
59
|
+
end
|
|
60
|
+
-- ▲ ReadonlyMap.forEach ▲
|
|
61
|
+
return {
|
|
62
|
+
entriesAdded = entriesAdded,
|
|
63
|
+
entriesChanged = entriesChanged,
|
|
64
|
+
keysRemoved = keysRemoved,
|
|
65
|
+
}
|
|
66
|
+
end
|
|
67
|
+
return {
|
|
68
|
+
turnArrayWithIdentifierToMap = turnArrayWithIdentifierToMap,
|
|
69
|
+
compareMaps = compareMaps,
|
|
70
|
+
}
|
package/src/hooks.d.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { Entity } from "@rbxts/jecs";
|
|
2
|
+
type AsyncResult<T = unknown> = {
|
|
3
|
+
completed: boolean;
|
|
4
|
+
value: T | undefined;
|
|
5
|
+
errorMessage?: string;
|
|
6
|
+
};
|
|
7
|
+
export type Discriminator = Exclude<defined, number>;
|
|
8
|
+
type CovenantHook<T extends (...args: Array<any>) => defined> = (updateId: number, ...args: Parameters<T>) => ReturnType<T>;
|
|
9
|
+
export interface CovenantHooks {
|
|
10
|
+
useEvent: CovenantHook<(<T extends Array<unknown>>(event: RBXScriptSignal<(...args: T) => void>) => T[])>;
|
|
11
|
+
useEventImmediately: CovenantHook<(<T extends Array<unknown>, TReturn extends defined>(event: RBXScriptSignal<(...args: T) => void>, callback: (...args: T) => TReturn) => TReturn[])>;
|
|
12
|
+
useComponentChange: CovenantHook<(<T extends defined>(component: Entity<T>) => {
|
|
13
|
+
entity: Entity;
|
|
14
|
+
state: T | undefined;
|
|
15
|
+
previousState: T | undefined;
|
|
16
|
+
}[])>;
|
|
17
|
+
useAsync: CovenantHook<(<T>(asnycFactory: () => T, dependencies: unknown[], discriminator: Discriminator) => AsyncResult<T>)>;
|
|
18
|
+
useImperative: CovenantHook<(<T extends defined>(dirtyFactory: (indicateUpdate: () => void) => {
|
|
19
|
+
value: T;
|
|
20
|
+
cleanup?: () => void;
|
|
21
|
+
}, dependencies: unknown[], discriminator: Discriminator) => T)>;
|
|
22
|
+
useChange: CovenantHook<(dependencies: unknown[], discriminator: Discriminator) => boolean>;
|
|
23
|
+
useInterval: CovenantHook<(seconds: number, trueOnInit: boolean, discriminator: Discriminator) => boolean>;
|
|
24
|
+
}
|
|
25
|
+
interface CovenantHooksProps {
|
|
26
|
+
indicateUpdate: () => void;
|
|
27
|
+
subscribeComponent: <T extends defined>(component: Entity<T>, subscriber: (entity: Entity, state: T | undefined, previousState: T | undefined) => void) => void;
|
|
28
|
+
}
|
|
29
|
+
export declare function createHooks(props: CovenantHooksProps): CovenantHooks;
|
|
30
|
+
export {};
|
package/src/hooks.luau
ADDED
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
-- Compiled with roblox-ts v3.0.0
|
|
2
|
+
-- eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
3
|
+
local function withUpdateId(fn)
|
|
4
|
+
local cache = nil
|
|
5
|
+
local lastUpdateId = -1
|
|
6
|
+
return function(id, ...)
|
|
7
|
+
local args = { ... }
|
|
8
|
+
if lastUpdateId ~= id then
|
|
9
|
+
cache = nil
|
|
10
|
+
lastUpdateId = id
|
|
11
|
+
end
|
|
12
|
+
if cache == nil then
|
|
13
|
+
cache = fn(unpack(args))
|
|
14
|
+
end
|
|
15
|
+
return cache
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
local function createUseEvent(_param)
|
|
19
|
+
local indicateUpdate = _param.indicateUpdate
|
|
20
|
+
local queues = {}
|
|
21
|
+
local watchedEvents = {}
|
|
22
|
+
local hook = function(event)
|
|
23
|
+
local _event = event
|
|
24
|
+
if not (watchedEvents[_event] ~= nil) then
|
|
25
|
+
local _event_1 = event
|
|
26
|
+
watchedEvents[_event_1] = true
|
|
27
|
+
local _event_2 = event
|
|
28
|
+
queues[_event_2] = {}
|
|
29
|
+
event:Connect(function(...)
|
|
30
|
+
local args = { ... }
|
|
31
|
+
local _event_3 = event
|
|
32
|
+
local _exp = queues[_event_3]
|
|
33
|
+
local _args = args
|
|
34
|
+
table.insert(_exp, _args)
|
|
35
|
+
indicateUpdate()
|
|
36
|
+
end)
|
|
37
|
+
return {}
|
|
38
|
+
end
|
|
39
|
+
local _event_1 = event
|
|
40
|
+
local queue = queues[_event_1]
|
|
41
|
+
if not (#queue == 0) then
|
|
42
|
+
local _event_2 = event
|
|
43
|
+
queues[_event_2] = {}
|
|
44
|
+
end
|
|
45
|
+
return queue
|
|
46
|
+
end
|
|
47
|
+
return withUpdateId(hook)
|
|
48
|
+
end
|
|
49
|
+
local function createUseEventImmediately(_param)
|
|
50
|
+
local indicateUpdate = _param.indicateUpdate
|
|
51
|
+
local queues = {}
|
|
52
|
+
local watchedEvents = {}
|
|
53
|
+
local hook = function(event, callback)
|
|
54
|
+
local _event = event
|
|
55
|
+
if not (watchedEvents[_event] ~= nil) then
|
|
56
|
+
local _event_1 = event
|
|
57
|
+
watchedEvents[_event_1] = true
|
|
58
|
+
local _event_2 = event
|
|
59
|
+
queues[_event_2] = {}
|
|
60
|
+
event:Connect(function(...)
|
|
61
|
+
local args = { ... }
|
|
62
|
+
local _event_3 = event
|
|
63
|
+
local _exp = queues[_event_3]
|
|
64
|
+
local _arg0 = callback(unpack(args))
|
|
65
|
+
table.insert(_exp, _arg0)
|
|
66
|
+
indicateUpdate()
|
|
67
|
+
end)
|
|
68
|
+
return {}
|
|
69
|
+
end
|
|
70
|
+
local _event_1 = event
|
|
71
|
+
local queue = queues[_event_1]
|
|
72
|
+
if not (#queue == 0) then
|
|
73
|
+
local _event_2 = event
|
|
74
|
+
queues[_event_2] = {}
|
|
75
|
+
end
|
|
76
|
+
return queue
|
|
77
|
+
end
|
|
78
|
+
return withUpdateId(hook)
|
|
79
|
+
end
|
|
80
|
+
local function createUseComponentChange(_param)
|
|
81
|
+
local subscribeComponent = _param.subscribeComponent
|
|
82
|
+
local update = _param.indicateUpdate
|
|
83
|
+
local queues = {}
|
|
84
|
+
local watchedStringifiedComponents = {}
|
|
85
|
+
local hook = function(component)
|
|
86
|
+
local stringifiedComponent = tostring(component)
|
|
87
|
+
if not (watchedStringifiedComponents[stringifiedComponent] ~= nil) then
|
|
88
|
+
watchedStringifiedComponents[stringifiedComponent] = true
|
|
89
|
+
queues[stringifiedComponent] = {}
|
|
90
|
+
subscribeComponent(component, function(entity, state, previousState)
|
|
91
|
+
local _exp = queues[stringifiedComponent]
|
|
92
|
+
local _arg0 = {
|
|
93
|
+
entity = entity,
|
|
94
|
+
state = state,
|
|
95
|
+
previousState = previousState,
|
|
96
|
+
}
|
|
97
|
+
table.insert(_exp, _arg0)
|
|
98
|
+
update()
|
|
99
|
+
end)
|
|
100
|
+
return {}
|
|
101
|
+
end
|
|
102
|
+
local queue = queues[stringifiedComponent]
|
|
103
|
+
if not (#queue == 0) then
|
|
104
|
+
queues[stringifiedComponent] = {}
|
|
105
|
+
end
|
|
106
|
+
return queue
|
|
107
|
+
end
|
|
108
|
+
return withUpdateId(hook)
|
|
109
|
+
end
|
|
110
|
+
local function equalsDependencies(a, b)
|
|
111
|
+
if a == b then
|
|
112
|
+
return true
|
|
113
|
+
end
|
|
114
|
+
if #a ~= #b then
|
|
115
|
+
return false
|
|
116
|
+
end
|
|
117
|
+
for i = 0, #a - 1 do
|
|
118
|
+
if a[i + 1] ~= b[i + 1] then
|
|
119
|
+
return false
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
return true
|
|
123
|
+
end
|
|
124
|
+
local function executeThread(res, asnycFn, update)
|
|
125
|
+
res.completed = false
|
|
126
|
+
local sucess, errMsg = pcall(function()
|
|
127
|
+
res.value = asnycFn()
|
|
128
|
+
end)
|
|
129
|
+
if not sucess and type(errMsg) == "string" then
|
|
130
|
+
res.errorMessage = errMsg
|
|
131
|
+
end
|
|
132
|
+
res.completed = true
|
|
133
|
+
update()
|
|
134
|
+
end
|
|
135
|
+
local function createUseAsync(_param)
|
|
136
|
+
local indicateUpdate = _param.indicateUpdate
|
|
137
|
+
local storage = {}
|
|
138
|
+
local hook = function(asnycFactory, dependencies, discriminator)
|
|
139
|
+
local _discriminator = discriminator
|
|
140
|
+
if not (storage[_discriminator] ~= nil) then
|
|
141
|
+
local newResult = {
|
|
142
|
+
completed = false,
|
|
143
|
+
value = nil,
|
|
144
|
+
}
|
|
145
|
+
local thread = coroutine.create(executeThread)
|
|
146
|
+
coroutine.resume(thread, newResult, asnycFactory, indicateUpdate)
|
|
147
|
+
local _discriminator_1 = discriminator
|
|
148
|
+
local _arg1 = {
|
|
149
|
+
lastDependencies = dependencies,
|
|
150
|
+
thread = thread,
|
|
151
|
+
result = newResult,
|
|
152
|
+
}
|
|
153
|
+
storage[_discriminator_1] = _arg1
|
|
154
|
+
return newResult
|
|
155
|
+
end
|
|
156
|
+
local _discriminator_1 = discriminator
|
|
157
|
+
local state = storage[_discriminator_1]
|
|
158
|
+
if equalsDependencies(state.lastDependencies, dependencies) then
|
|
159
|
+
return state.result
|
|
160
|
+
else
|
|
161
|
+
coroutine.yield(state.thread)
|
|
162
|
+
coroutine.close(state.thread)
|
|
163
|
+
local newResult = {
|
|
164
|
+
completed = false,
|
|
165
|
+
value = nil,
|
|
166
|
+
}
|
|
167
|
+
local newThread = coroutine.create(executeThread)
|
|
168
|
+
coroutine.resume(newThread, newResult, asnycFactory, indicateUpdate)
|
|
169
|
+
local _discriminator_2 = discriminator
|
|
170
|
+
local _arg1 = {
|
|
171
|
+
lastDependencies = dependencies,
|
|
172
|
+
thread = newThread,
|
|
173
|
+
result = newResult,
|
|
174
|
+
}
|
|
175
|
+
storage[_discriminator_2] = _arg1
|
|
176
|
+
return newResult
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
return withUpdateId(hook)
|
|
180
|
+
end
|
|
181
|
+
local function createUseImperative(_param)
|
|
182
|
+
local indicateUpdate = _param.indicateUpdate
|
|
183
|
+
local storage = {}
|
|
184
|
+
local hook = function(dirtyFactory, dependencies, discriminator)
|
|
185
|
+
local _discriminator = discriminator
|
|
186
|
+
if not (storage[_discriminator] ~= nil) then
|
|
187
|
+
local _binding = dirtyFactory(indicateUpdate)
|
|
188
|
+
local value = _binding.value
|
|
189
|
+
local cleanup = _binding.cleanup
|
|
190
|
+
local _discriminator_1 = discriminator
|
|
191
|
+
local _arg1 = {
|
|
192
|
+
cache = value,
|
|
193
|
+
cleanup = cleanup,
|
|
194
|
+
lastDependencies = dependencies,
|
|
195
|
+
}
|
|
196
|
+
storage[_discriminator_1] = _arg1
|
|
197
|
+
return value
|
|
198
|
+
end
|
|
199
|
+
local _discriminator_1 = discriminator
|
|
200
|
+
local state = storage[_discriminator_1]
|
|
201
|
+
if equalsDependencies(state.lastDependencies, dependencies) then
|
|
202
|
+
return state.cache
|
|
203
|
+
else
|
|
204
|
+
if state.cleanup ~= nil then
|
|
205
|
+
state.cleanup()
|
|
206
|
+
end
|
|
207
|
+
local _binding = dirtyFactory(indicateUpdate)
|
|
208
|
+
local value = _binding.value
|
|
209
|
+
local cleanup = _binding.cleanup
|
|
210
|
+
local _discriminator_2 = discriminator
|
|
211
|
+
local _arg1 = {
|
|
212
|
+
cache = value,
|
|
213
|
+
cleanup = cleanup,
|
|
214
|
+
lastDependencies = dependencies,
|
|
215
|
+
}
|
|
216
|
+
storage[_discriminator_2] = _arg1
|
|
217
|
+
return value
|
|
218
|
+
end
|
|
219
|
+
end
|
|
220
|
+
return withUpdateId(hook)
|
|
221
|
+
end
|
|
222
|
+
local function createUseChange()
|
|
223
|
+
local dependenciesStorage = {}
|
|
224
|
+
local hook = function(dependencies, discriminator)
|
|
225
|
+
local _discriminator = discriminator
|
|
226
|
+
if not (dependenciesStorage[_discriminator] ~= nil) then
|
|
227
|
+
local _discriminator_1 = discriminator
|
|
228
|
+
local _dependencies = dependencies
|
|
229
|
+
dependenciesStorage[_discriminator_1] = _dependencies
|
|
230
|
+
return true
|
|
231
|
+
end
|
|
232
|
+
local _discriminator_1 = discriminator
|
|
233
|
+
local lastDependencies = dependenciesStorage[_discriminator_1]
|
|
234
|
+
if equalsDependencies(lastDependencies, dependencies) then
|
|
235
|
+
return false
|
|
236
|
+
else
|
|
237
|
+
local _discriminator_2 = discriminator
|
|
238
|
+
local _dependencies = dependencies
|
|
239
|
+
dependenciesStorage[_discriminator_2] = _dependencies
|
|
240
|
+
return true
|
|
241
|
+
end
|
|
242
|
+
end
|
|
243
|
+
return withUpdateId(hook)
|
|
244
|
+
end
|
|
245
|
+
local function createUseInterval(_param)
|
|
246
|
+
local indicateUpdate = _param.indicateUpdate
|
|
247
|
+
local nextClocks = {}
|
|
248
|
+
local hook = function(seconds, trueOnInit, discriminator)
|
|
249
|
+
local _discriminator = discriminator
|
|
250
|
+
if not (nextClocks[_discriminator] ~= nil) then
|
|
251
|
+
local _discriminator_1 = discriminator
|
|
252
|
+
local _arg1 = os.clock() + seconds
|
|
253
|
+
nextClocks[_discriminator_1] = _arg1
|
|
254
|
+
task.delay(seconds, indicateUpdate)
|
|
255
|
+
return trueOnInit
|
|
256
|
+
end
|
|
257
|
+
local _discriminator_1 = discriminator
|
|
258
|
+
local nextClock = nextClocks[_discriminator_1]
|
|
259
|
+
if nextClock < os.clock() then
|
|
260
|
+
return false
|
|
261
|
+
else
|
|
262
|
+
local _discriminator_2 = discriminator
|
|
263
|
+
local _arg1 = os.clock() + seconds
|
|
264
|
+
nextClocks[_discriminator_2] = _arg1
|
|
265
|
+
task.delay(seconds, indicateUpdate)
|
|
266
|
+
return true
|
|
267
|
+
end
|
|
268
|
+
end
|
|
269
|
+
return withUpdateId(hook)
|
|
270
|
+
end
|
|
271
|
+
local function createHooks(props)
|
|
272
|
+
return {
|
|
273
|
+
useEvent = createUseEvent(props),
|
|
274
|
+
useEventImmediately = createUseEventImmediately(props),
|
|
275
|
+
useComponentChange = createUseComponentChange(props),
|
|
276
|
+
useAsync = createUseAsync(props),
|
|
277
|
+
useImperative = createUseImperative(props),
|
|
278
|
+
useChange = createUseChange(),
|
|
279
|
+
useInterval = createUseInterval(props),
|
|
280
|
+
}
|
|
281
|
+
end
|
|
282
|
+
return {
|
|
283
|
+
createHooks = createHooks,
|
|
284
|
+
}
|
package/src/index.d.ts
ADDED
package/src/init.luau
ADDED