@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rbxts/covenant",
3
- "version": "1.0.1",
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/index.d.ts",
22
+ "types": "src/covenant.d.ts",
23
23
  "files": [
24
- "out",
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
+ }
@@ -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
+ };
@@ -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
@@ -0,0 +1,2 @@
1
+ import { Covenant } from "./covenant";
2
+ export = Covenant;
package/src/init.luau ADDED
@@ -0,0 +1,4 @@
1
+ -- Compiled with roblox-ts v3.0.0
2
+ local TS = _G[script]
3
+ local Covenant = TS.import(script, script, "covenant").Covenant
4
+ return Covenant
@@ -0,0 +1,6 @@
1
+ export type Remove = "6ggQCh*zYyb&j2";
2
+ export declare const Remove: Remove;
3
+ export type None = "C5@j^TKCart!5R";
4
+ export declare const None: None;
5
+ export type Delete = "A@EB7PVpkBf#VT";
6
+ export declare const Delete: Delete;
@@ -0,0 +1,9 @@
1
+ -- Compiled with roblox-ts v3.0.0
2
+ local Remove = "6ggQCh*zYyb&j2"
3
+ local None = "C5@j^TKCart!5R"
4
+ local Delete = "A@EB7PVpkBf#VT"
5
+ return {
6
+ Remove = Remove,
7
+ None = None,
8
+ Delete = Delete,
9
+ }