@rbxts/replecs 0.1.0-alpha2 → 0.1.0-alpha3
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/README.md +123 -0
- package/out/replecs/client.luau +84 -18
- package/out/replecs/masking/init.luau +119 -2
- package/out/replecs/server.luau +117 -33
- package/out/replecs/utils.luau +7 -0
- package/package.json +2 -2
package/README.md
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# Replecs ⚡
|
|
2
|
+
Replecs is a fast, fine controlled JECS replication library
|
|
3
|
+
|
|
4
|
+
Replecs is a feature rich, fast, flexible, powerful, and runtime/library agnostic replication library for ECS.
|
|
5
|
+
|
|
6
|
+
- Per-entity replication
|
|
7
|
+
- Heavily optimized granular player filtering for entities and components
|
|
8
|
+
- Entity ID remapping
|
|
9
|
+
- Optional serdes for values
|
|
10
|
+
- Luau runtime agnostic
|
|
11
|
+
- Buffer-based replication
|
|
12
|
+
- Bandwidth efficient
|
|
13
|
+
- Supports tags and relationships
|
|
14
|
+
- Unreliable replication, with automatic 1kb buffer size limit
|
|
15
|
+
|
|
16
|
+
Demo place: https://www.roblox.com/games/132070456195381/
|
|
17
|
+
# Getting Started
|
|
18
|
+
### Roblox-TS
|
|
19
|
+
Install `@rbxts/jecs-addons` `@rbxts/replecs` `@rbxts/jecs`.
|
|
20
|
+
|
|
21
|
+
**Make sure you install jecs as v0.8.3, not ^0.9.0** as they are not compatible. You can check the versioning by running `npm ls @rbxts/jecs`
|
|
22
|
+
|
|
23
|
+
## 🔥Setting Up
|
|
24
|
+
|
|
25
|
+
`shared/world.ts`
|
|
26
|
+
```ts
|
|
27
|
+
import { observer_add } from "@rbxts/jecs-addons"
|
|
28
|
+
import { world } from "@rbxts/jecs"
|
|
29
|
+
|
|
30
|
+
// you need to add the observer addon before passing it to the replicator!
|
|
31
|
+
export const world = observer_add(world())
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
`server/runtime.server.ts`
|
|
35
|
+
```ts
|
|
36
|
+
import { world } from "shared/world"
|
|
37
|
+
import { create_server } from "@rbxts/replecs"
|
|
38
|
+
|
|
39
|
+
const replicator = create_server(world)
|
|
40
|
+
|
|
41
|
+
//make sure you call replicator.init before you apply any operations
|
|
42
|
+
replicator.init()
|
|
43
|
+
|
|
44
|
+
//use whatever networking library you want, I am using @rbxts/remo
|
|
45
|
+
InitialReplecsRemotes.requestInitialPackets.connect(player => {
|
|
46
|
+
if (replicator.is_player_ready(player)) return;
|
|
47
|
+
replicator.mark_player_ready(player);
|
|
48
|
+
|
|
49
|
+
const [buf, variants] = replicator.get_full(player);
|
|
50
|
+
|
|
51
|
+
InitialReplecsRemotes.sendInitialPackets(player, buf, variants);
|
|
52
|
+
});
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
`client/runtime.client.ts`
|
|
56
|
+
```ts
|
|
57
|
+
import { world } from "shared/world"
|
|
58
|
+
import { create_client } from "@rbxts/replecs"
|
|
59
|
+
|
|
60
|
+
const replicator = create_server(world)
|
|
61
|
+
|
|
62
|
+
//make sure you call replicator.init before you apply any operations
|
|
63
|
+
replicator.init()
|
|
64
|
+
|
|
65
|
+
InitialReplecsRemotes.requestInitialPackets();
|
|
66
|
+
|
|
67
|
+
InitialReplecsRemotes.sendInitialPackets.connect((buf, variants) => {
|
|
68
|
+
const replicator = HANDLE.getClientReplicator();
|
|
69
|
+
|
|
70
|
+
replicator.apply_full(buf, variants);
|
|
71
|
+
});
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Using in action
|
|
75
|
+
Basic replicated component
|
|
76
|
+
```ts
|
|
77
|
+
const component1 = world.component<string>()
|
|
78
|
+
//you must add shared or Shared component to components you want to replicate
|
|
79
|
+
world.add(component1, shared)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
const replicatedEntity = world.entity()
|
|
83
|
+
world.set(replicatedEntity, component1, "string")
|
|
84
|
+
|
|
85
|
+
//you must add replicatedEntity as networked and add the components you want to replicate
|
|
86
|
+
world.add(replicatedEntity, networked)
|
|
87
|
+
|
|
88
|
+
//this makes components appear in collect_updates
|
|
89
|
+
world.add(replicatedEntity, pair(reliable, component1))
|
|
90
|
+
|
|
91
|
+
//this makes components appear in collect_unreliable
|
|
92
|
+
world.add(replicatedEntity, pair(unreliable, component1))
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Replication process
|
|
96
|
+
```ts
|
|
97
|
+
RunService.Heartbeat.Connect(() => {
|
|
98
|
+
//this collects reliable updates
|
|
99
|
+
for (const [player, buf, variants] of serverReplicator.collect_updates()) {
|
|
100
|
+
//here I am using yetanothernet
|
|
101
|
+
reliableRoute.send(buf, variants).to(player)
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
//this collects unrealible updates
|
|
105
|
+
for (const [player, buf, variants] serverReplicator.collect_updates()) {
|
|
106
|
+
//here I am using yetanothernet
|
|
107
|
+
unreliableRoute.send(buf, variants).to(player)
|
|
108
|
+
}
|
|
109
|
+
})
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
This is the basics of Replecs. For deeper understanding check out the demo folder files here
|
|
113
|
+
- [player first hydration](https://github.com/PepeElToro41/replecs/blob/main/demo/src/server/init.server.luau#L22)
|
|
114
|
+
- [send replication](https://github.com/PepeElToro41/replecs/blob/main/demo/src/server/systems/replecs_server.luau#L12)
|
|
115
|
+
- [receive replication](https://github.com/PepeElToro41/replecs/blob/main/demo/src/client/systems/replecs_client.luau)
|
|
116
|
+
- [setup an entity to replicate](https://github.com/PepeElToro41/replecs/blob/main/demo/src/server/controllers/spawn_cubes.luau#L10)
|
|
117
|
+
- custom ids: [client](https://github.com/PepeElToro41/replecs/blob/main/demo/src/shared/components/init.luau#L33) - [server](https://github.com/PepeElToro41/replecs/blob/main/demo/src/shared/players.luau#L16)
|
|
118
|
+
- [serdes](https://github.com/PepeElToro41/replecs/blob/main/demo/src/shared/components/init.luau#L37)
|
|
119
|
+
- [how you would add `shared` to all components](https://github.com/PepeElToro41/replecs/blob/main/demo/src/shared/components/init.luau#L52)
|
|
120
|
+
- create the replicators: [client](https://github.com/PepeElToro41/replecs/blob/main/demo/src/client/replicator.luau) - [server](https://github.com/PepeElToro41/replecs/blob/main/demo/src/server/replicator.luau)
|
|
121
|
+
-
|
|
122
|
+
### Luau
|
|
123
|
+
TODO
|
package/out/replecs/client.luau
CHANGED
|
@@ -44,6 +44,11 @@ local ENTITY_ID_TYPES = {
|
|
|
44
44
|
shared = 3,
|
|
45
45
|
global = 4,
|
|
46
46
|
}
|
|
47
|
+
local PACKET_TYPES = {
|
|
48
|
+
full = 1,
|
|
49
|
+
unreliable = 2,
|
|
50
|
+
reliable = 3,
|
|
51
|
+
}
|
|
47
52
|
|
|
48
53
|
local ECS_NAME = jecs.Name
|
|
49
54
|
|
|
@@ -132,7 +137,7 @@ local function read_entity_id(client: Client, c: Cursor, variants: { any }?): (E
|
|
|
132
137
|
end
|
|
133
138
|
end
|
|
134
139
|
|
|
135
|
-
local function process_entity_id(client: Client, c: Cursor, variants: { any }
|
|
140
|
+
local function process_entity_id(client: Client, c: Cursor, variants: { any }?)
|
|
136
141
|
local entity, server_id = read_entity_id(client, c, variants)
|
|
137
142
|
if entity then
|
|
138
143
|
return entity
|
|
@@ -141,6 +146,16 @@ local function process_entity_id(client: Client, c: Cursor, variants: { any }?,
|
|
|
141
146
|
end
|
|
142
147
|
end
|
|
143
148
|
|
|
149
|
+
local function process_entity_relation(client: Client, entity: jecs.Entity, c: Cursor, variants: { any }?)
|
|
150
|
+
local relation = read_component_id(client, c)
|
|
151
|
+
local total_targets = cursor.read_vlq(c)
|
|
152
|
+
|
|
153
|
+
for _ = 1, total_targets do
|
|
154
|
+
local target = process_entity_id(client, c, variants)
|
|
155
|
+
client.world:add(entity, PAIR(relation, target))
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
|
|
144
159
|
local function process_entity(client: Client, c: Cursor, variants: { any }?)
|
|
145
160
|
local entity = process_entity_id(client, c, variants)
|
|
146
161
|
|
|
@@ -158,45 +173,91 @@ local function process_entity(client: Client, c: Cursor, variants: { any }?)
|
|
|
158
173
|
|
|
159
174
|
local total_pairs = cursor.read_vlq(c)
|
|
160
175
|
for _ = 1, total_pairs do
|
|
161
|
-
|
|
162
|
-
|
|
176
|
+
process_entity_relation(client, entity, c, variants)
|
|
177
|
+
end
|
|
178
|
+
end
|
|
163
179
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
180
|
+
local function check_packet_type(c: Cursor, type: string)
|
|
181
|
+
local byte_type = PACKET_TYPES[type]
|
|
182
|
+
local packet_type = cursor.readu8(c)
|
|
183
|
+
if packet_type ~= byte_type then
|
|
184
|
+
local got: string = nil :: any
|
|
185
|
+
for k, v in PACKET_TYPES do
|
|
186
|
+
if v == packet_type then
|
|
187
|
+
got = k
|
|
188
|
+
break
|
|
189
|
+
end
|
|
167
190
|
end
|
|
191
|
+
|
|
192
|
+
error(`packet type mismatch, expected {type} got {got} instead`)
|
|
193
|
+
end
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
local function read_vlq_bitmask(c: Cursor, mask: number, bit: number): number
|
|
197
|
+
if utils.checkbit(mask, bit) then
|
|
198
|
+
return cursor.read_vlq(c)
|
|
199
|
+
else
|
|
200
|
+
return 0
|
|
168
201
|
end
|
|
169
202
|
end
|
|
170
203
|
|
|
171
204
|
local function apply_updates(client: Client, buf: buffer, all_variants: { { any } }?)
|
|
172
205
|
local c = cursor.from(buf)
|
|
206
|
+
check_packet_type(c, "reliable")
|
|
207
|
+
|
|
173
208
|
local total_packets = cursor.read_vlq(c)
|
|
174
209
|
local variant_start = (all_variants and #all_variants + 1) :: number
|
|
175
210
|
|
|
176
211
|
for a = 1, total_packets do
|
|
177
212
|
local variants = all_variants and all_variants[variant_start - a]
|
|
178
|
-
local
|
|
213
|
+
local storage_mask = cursor.readu8(c)
|
|
179
214
|
|
|
180
|
-
|
|
215
|
+
local total_added = read_vlq_bitmask(c, storage_mask, 0)
|
|
216
|
+
for _ = 1, total_added do
|
|
181
217
|
process_entity(client, c, variants)
|
|
182
218
|
end
|
|
183
219
|
|
|
184
|
-
local
|
|
220
|
+
local total_components_added = read_vlq_bitmask(c, storage_mask, 1)
|
|
221
|
+
for _ = 1, total_components_added do
|
|
222
|
+
local entity = process_entity_id(client, c, variants)
|
|
223
|
+
local added_mask = cursor.readu8(c)
|
|
224
|
+
|
|
225
|
+
local total_tags = read_vlq_bitmask(c, added_mask, 0)
|
|
226
|
+
for _ = 1, total_tags do
|
|
227
|
+
local tag = read_component_id(client, c)
|
|
228
|
+
client.world:add(entity, tag)
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
local total_components = read_vlq_bitmask(c, added_mask, 1)
|
|
232
|
+
for _ = 1, total_components do
|
|
233
|
+
local component, value = read_component_value(client, c, variants)
|
|
234
|
+
client.world:set(entity, component, value)
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
local total_pairs = read_vlq_bitmask(c, added_mask, 2)
|
|
238
|
+
for _ = 1, total_pairs do
|
|
239
|
+
process_entity_relation(client, entity, c, variants)
|
|
240
|
+
end
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
local total_changed = read_vlq_bitmask(c, storage_mask, 2)
|
|
185
244
|
for _ = 1, total_changed do
|
|
186
245
|
local entity = process_entity_id(client, c, variants)
|
|
187
|
-
local
|
|
246
|
+
local changed_mask = cursor.readu8(c)
|
|
247
|
+
|
|
248
|
+
local total_tagged = read_vlq_bitmask(c, changed_mask, 0)
|
|
188
249
|
for _ = 1, total_tagged do
|
|
189
250
|
local tag = read_component_id(client, c)
|
|
190
251
|
client.world:add(entity, tag)
|
|
191
252
|
end
|
|
192
253
|
|
|
193
|
-
local total_components =
|
|
254
|
+
local total_components = read_vlq_bitmask(c, changed_mask, 1)
|
|
194
255
|
for _ = 1, total_components do
|
|
195
256
|
local component, value = read_component_value(client, c, variants)
|
|
196
257
|
client.world:set(entity, component, value)
|
|
197
258
|
end
|
|
198
259
|
|
|
199
|
-
local total_pairs =
|
|
260
|
+
local total_pairs = read_vlq_bitmask(c, changed_mask, 2)
|
|
200
261
|
for _ = 1, total_pairs do
|
|
201
262
|
local relation = read_component_id(client, c)
|
|
202
263
|
local total_targets = cursor.read_vlq(c)
|
|
@@ -218,37 +279,38 @@ local function apply_updates(client: Client, buf: buffer, all_variants: { { any
|
|
|
218
279
|
end
|
|
219
280
|
end
|
|
220
281
|
|
|
221
|
-
local total_removed =
|
|
282
|
+
local total_removed = read_vlq_bitmask(c, changed_mask, 3)
|
|
222
283
|
for _ = 1, total_removed do
|
|
223
284
|
local component = read_component_id(client, c)
|
|
224
285
|
client.world:remove(entity, component)
|
|
225
286
|
end
|
|
226
287
|
end
|
|
227
288
|
|
|
228
|
-
local total_component_deleted =
|
|
289
|
+
local total_component_deleted = read_vlq_bitmask(c, storage_mask, 3)
|
|
229
290
|
for _ = 1, total_component_deleted do
|
|
230
291
|
local entity = process_entity_id(client, c, variants)
|
|
292
|
+
local deleted_mask = cursor.readu8(c)
|
|
231
293
|
|
|
232
|
-
local total_tags =
|
|
294
|
+
local total_tags = read_vlq_bitmask(c, deleted_mask, 0)
|
|
233
295
|
for _ = 1, total_tags do
|
|
234
296
|
local tag = read_component_id(client, c)
|
|
235
297
|
client.world:remove(entity, tag)
|
|
236
298
|
end
|
|
237
299
|
|
|
238
|
-
local total_components =
|
|
300
|
+
local total_components = read_vlq_bitmask(c, deleted_mask, 1)
|
|
239
301
|
for _ = 1, total_components do
|
|
240
302
|
local component = read_component_id(client, c)
|
|
241
303
|
client.world:remove(entity, component)
|
|
242
304
|
end
|
|
243
305
|
|
|
244
|
-
local total_pairs =
|
|
306
|
+
local total_pairs = read_vlq_bitmask(c, deleted_mask, 2)
|
|
245
307
|
for _ = 1, total_pairs do
|
|
246
308
|
local relation = read_component_id(client, c)
|
|
247
309
|
utils.remove_all_relations(client.world, entity, relation)
|
|
248
310
|
end
|
|
249
311
|
end
|
|
250
312
|
|
|
251
|
-
local total_deleted =
|
|
313
|
+
local total_deleted = read_vlq_bitmask(c, storage_mask, 4)
|
|
252
314
|
for _ = 1, total_deleted do
|
|
253
315
|
local entity, server_id = read_entity_id(client, c, variants)
|
|
254
316
|
if entity then
|
|
@@ -263,6 +325,8 @@ end
|
|
|
263
325
|
|
|
264
326
|
local function apply_unreliable(client: Client, buf: buffer, all_variants: { { any } }?)
|
|
265
327
|
local c = cursor.from(buf)
|
|
328
|
+
check_packet_type(c, "unreliable")
|
|
329
|
+
|
|
266
330
|
local total_packets = cursor.read_vlq(c)
|
|
267
331
|
local variant_start = (all_variants and #all_variants + 1) :: number
|
|
268
332
|
|
|
@@ -290,6 +354,8 @@ end
|
|
|
290
354
|
|
|
291
355
|
local function apply_full(client: Client, buf: buffer, all_variants: { { any } }?)
|
|
292
356
|
local c = cursor.from(buf)
|
|
357
|
+
check_packet_type(c, "full")
|
|
358
|
+
|
|
293
359
|
local total_packets = cursor.read_vlq(c)
|
|
294
360
|
local variant_start = (all_variants and #all_variants + 1) :: number
|
|
295
361
|
|
|
@@ -91,6 +91,7 @@ type StorageGroup = {
|
|
|
91
91
|
|
|
92
92
|
changes: {
|
|
93
93
|
added: Map<Entity, boolean>,
|
|
94
|
+
added_components: EntityComponentIndex<boolean>,
|
|
94
95
|
changed: Map<Entity, EntityChanges>,
|
|
95
96
|
},
|
|
96
97
|
}
|
|
@@ -124,6 +125,18 @@ export type MaskingController = {
|
|
|
124
125
|
component: Entity,
|
|
125
126
|
component_type: number
|
|
126
127
|
) -> (),
|
|
128
|
+
register_component_addition: (
|
|
129
|
+
self: MaskingController,
|
|
130
|
+
entity: Entity,
|
|
131
|
+
component: Entity,
|
|
132
|
+
component_type: number
|
|
133
|
+
) -> (),
|
|
134
|
+
unregister_component_addition: (
|
|
135
|
+
self: MaskingController,
|
|
136
|
+
entity: Entity,
|
|
137
|
+
component: Entity,
|
|
138
|
+
component_type: number
|
|
139
|
+
) -> (),
|
|
127
140
|
unregister_stop_entity: (self: MaskingController, entity: Entity) -> (),
|
|
128
141
|
unregister_stop_component: (
|
|
129
142
|
self: MaskingController,
|
|
@@ -245,6 +258,7 @@ function masking_controller.create_new_storage(
|
|
|
245
258
|
|
|
246
259
|
changes = {
|
|
247
260
|
added = {},
|
|
261
|
+
added_components = {},
|
|
248
262
|
changed = {},
|
|
249
263
|
},
|
|
250
264
|
|
|
@@ -352,6 +366,19 @@ local function get_or_set_active(storage: StorageGroup, entity: Entity, active:
|
|
|
352
366
|
return storage_active
|
|
353
367
|
end
|
|
354
368
|
|
|
369
|
+
local function get_or_set_component_added(
|
|
370
|
+
storage: StorageGroup,
|
|
371
|
+
entity: Entity,
|
|
372
|
+
added: ComponentIndex<boolean>?
|
|
373
|
+
): ComponentIndex<boolean>
|
|
374
|
+
local storage_added = storage.changes.added_components[entity]
|
|
375
|
+
if storage_added == nil then
|
|
376
|
+
storage_added = added or create_component_indexes() :: ComponentIndex<boolean>
|
|
377
|
+
storage.changes.added_components[entity] = storage_added
|
|
378
|
+
end
|
|
379
|
+
return storage_added
|
|
380
|
+
end
|
|
381
|
+
|
|
355
382
|
local function remove_active(storage: StorageGroup, entity: Entity): ActiveEntity
|
|
356
383
|
local active = storage.active[entity]
|
|
357
384
|
if active then
|
|
@@ -430,7 +457,24 @@ local function dissect_component_actives(
|
|
|
430
457
|
end
|
|
431
458
|
return new_active
|
|
432
459
|
end
|
|
433
|
-
|
|
460
|
+
|
|
461
|
+
local function dissect_component_additions(added: ComponentIndex<boolean>, shared_index: ComponentIndex<boolean>)
|
|
462
|
+
local new_added: ComponentIndex<boolean>
|
|
463
|
+
|
|
464
|
+
for component_type, components in added do
|
|
465
|
+
for component in components do
|
|
466
|
+
local is_shared = shared_index[component_type] and shared_index[component_type][component]
|
|
467
|
+
if is_shared then
|
|
468
|
+
new_added = (new_added or create_component_indexes()) :: ComponentIndex<boolean>
|
|
469
|
+
new_added[component_type][component] = true
|
|
470
|
+
added[component_type][component] = nil
|
|
471
|
+
end
|
|
472
|
+
end
|
|
473
|
+
end
|
|
474
|
+
return new_added
|
|
475
|
+
end
|
|
476
|
+
|
|
477
|
+
local function dissect_component_changes(changes: EntityChanges, shared_index: ComponentIndex<boolean>)
|
|
434
478
|
local new_changes: EntityChanges
|
|
435
479
|
|
|
436
480
|
for component, change in changes.component do
|
|
@@ -468,6 +512,14 @@ local function merge_component_actives(current: ActiveEntity, target: ActiveEnti
|
|
|
468
512
|
end
|
|
469
513
|
end
|
|
470
514
|
|
|
515
|
+
local function merge_component_additions(current: ComponentIndex<boolean>, target: ComponentIndex<boolean>)
|
|
516
|
+
for component_type, components in current do
|
|
517
|
+
for component in components do
|
|
518
|
+
target[component_type][component] = true
|
|
519
|
+
end
|
|
520
|
+
end
|
|
521
|
+
end
|
|
522
|
+
|
|
471
523
|
local function merge_component_changes(current: EntityChanges, target: EntityChanges)
|
|
472
524
|
for component, change in current.component do
|
|
473
525
|
target.component[component] = change
|
|
@@ -538,9 +590,27 @@ function masking_controller.move_entity_storage(
|
|
|
538
590
|
merge_component_actives(old_active, new_active)
|
|
539
591
|
end
|
|
540
592
|
|
|
593
|
+
local old_component_added = storage.changes.added_components[entity]
|
|
594
|
+
if old_component_added then
|
|
595
|
+
local new_component_added = get_or_set_component_added(target_storage, entity, old_component_added)
|
|
596
|
+
|
|
597
|
+
if shared_with then
|
|
598
|
+
local dissected_added = dissect_component_additions(old_component_added, shared_with)
|
|
599
|
+
if dissected_added then
|
|
600
|
+
storage.changes.added_components[entity] = dissected_added
|
|
601
|
+
else
|
|
602
|
+
storage.changes.added_components[entity] = nil
|
|
603
|
+
end
|
|
604
|
+
end
|
|
605
|
+
|
|
606
|
+
if old_component_added ~= new_component_added then
|
|
607
|
+
merge_component_additions(old_component_added, new_component_added)
|
|
608
|
+
end
|
|
609
|
+
end
|
|
610
|
+
|
|
541
611
|
local old_changes = storage.changes.changed[entity]
|
|
542
612
|
if old_changes then
|
|
543
|
-
local new_changes = get_or_set_changed(target_storage, entity)
|
|
613
|
+
local new_changes = get_or_set_changed(target_storage, entity, old_changes)
|
|
544
614
|
|
|
545
615
|
if shared_with then
|
|
546
616
|
local dissected_changes = dissect_component_changes(old_changes, shared_with)
|
|
@@ -555,6 +625,12 @@ function masking_controller.move_entity_storage(
|
|
|
555
625
|
merge_component_changes(old_changes, new_changes)
|
|
556
626
|
end
|
|
557
627
|
end
|
|
628
|
+
|
|
629
|
+
if storage.changes.added[entity] then
|
|
630
|
+
target_storage.changes.added[entity] = true
|
|
631
|
+
storage.changes.added[entity] = nil
|
|
632
|
+
end
|
|
633
|
+
|
|
558
634
|
return target_storage
|
|
559
635
|
end
|
|
560
636
|
|
|
@@ -579,6 +655,12 @@ function masking_controller.move_component_storage(
|
|
|
579
655
|
set_component_index_entry(target_storage.shared_with, entity, component, component_type, true)
|
|
580
656
|
remove_component_index_entry(storage.shared_with, entity, component, component_type)
|
|
581
657
|
|
|
658
|
+
local component_added =
|
|
659
|
+
get_component_index_entry(storage.changes.added_components, entity, component, component_type)
|
|
660
|
+
if component_added then
|
|
661
|
+
set_component_index_entry(target_storage.changes.added_components, entity, component, component_type, true)
|
|
662
|
+
end
|
|
663
|
+
|
|
582
664
|
local changes = storage.changes.changed[entity]
|
|
583
665
|
if changes then
|
|
584
666
|
local target_changes = get_or_set_changed(target_storage, entity)
|
|
@@ -706,6 +788,18 @@ function masking_controller.register_stop_component(
|
|
|
706
788
|
storage.deletions_count += 1
|
|
707
789
|
end
|
|
708
790
|
end
|
|
791
|
+
|
|
792
|
+
function masking_controller.register_component_addition(
|
|
793
|
+
masking: MaskingInternal,
|
|
794
|
+
entity: Entity,
|
|
795
|
+
component: Entity,
|
|
796
|
+
component_type: number
|
|
797
|
+
)
|
|
798
|
+
local storage = masking:get_component_storage_group(entity, component, component_type)
|
|
799
|
+
local additions = get_or_set_component_added(storage, entity)
|
|
800
|
+
additions[component_type][component] = true
|
|
801
|
+
end
|
|
802
|
+
|
|
709
803
|
function masking_controller.unregister_stop_entity(masking: MaskingInternal, entity: Entity)
|
|
710
804
|
local deletion_lookup = masking.lookups.deletions.entities[entity]
|
|
711
805
|
if not deletion_lookup then
|
|
@@ -741,6 +835,19 @@ function masking_controller.unregister_stop_component(
|
|
|
741
835
|
end
|
|
742
836
|
end
|
|
743
837
|
|
|
838
|
+
function masking_controller.unregister_component_addition(
|
|
839
|
+
masking: MaskingInternal,
|
|
840
|
+
entity: Entity,
|
|
841
|
+
component: Entity,
|
|
842
|
+
component_type: number
|
|
843
|
+
)
|
|
844
|
+
local storage: StorageGroup = masking:get_component_storage_group(entity, component, component_type)
|
|
845
|
+
local additions = storage.changes.added_components[entity]
|
|
846
|
+
if additions then
|
|
847
|
+
additions[component_type][component] = nil
|
|
848
|
+
end
|
|
849
|
+
end
|
|
850
|
+
|
|
744
851
|
function masking_controller.propagate_entity_addition(masking: MaskingInternal, entity: Entity)
|
|
745
852
|
local entity_lookup = masking.lookups.entities[entity]
|
|
746
853
|
if entity_lookup then
|
|
@@ -1115,6 +1222,9 @@ function masking_controller.merge_storages(
|
|
|
1115
1222
|
old_storage: StorageGroup,
|
|
1116
1223
|
new_storage: StorageGroup
|
|
1117
1224
|
)
|
|
1225
|
+
if new_storage == old_storage then
|
|
1226
|
+
return
|
|
1227
|
+
end
|
|
1118
1228
|
for entity, active in old_storage.active do
|
|
1119
1229
|
local new_active = get_or_set_active(new_storage, entity)
|
|
1120
1230
|
merge_component_actives(new_active, active)
|
|
@@ -1137,10 +1247,17 @@ function masking_controller.merge_storages(
|
|
|
1137
1247
|
end
|
|
1138
1248
|
end
|
|
1139
1249
|
end
|
|
1250
|
+
for entity, added_components in old_storage.changes.added_components do
|
|
1251
|
+
local new_added_components = get_or_set_component_added(new_storage, entity)
|
|
1252
|
+
merge_component_additions(new_added_components, added_components)
|
|
1253
|
+
end
|
|
1140
1254
|
for entity, changes in old_storage.changes.changed do
|
|
1141
1255
|
local new_changes = get_or_set_changes(new_storage, entity)
|
|
1142
1256
|
merge_component_changes(new_changes, changes)
|
|
1143
1257
|
end
|
|
1258
|
+
for entity in old_storage.changes.added do
|
|
1259
|
+
new_storage.changes.added[entity] = true
|
|
1260
|
+
end
|
|
1144
1261
|
for entity in old_storage.deletions.entities do
|
|
1145
1262
|
new_storage.deletions.entities[entity] = true
|
|
1146
1263
|
end
|
package/out/replecs/server.luau
CHANGED
|
@@ -72,6 +72,11 @@ local TRACK_TYPES = {
|
|
|
72
72
|
tag = 2,
|
|
73
73
|
pair = 3,
|
|
74
74
|
}
|
|
75
|
+
local PACKET_TYPES = {
|
|
76
|
+
full = 1,
|
|
77
|
+
unreliable = 2,
|
|
78
|
+
reliable = 3,
|
|
79
|
+
}
|
|
75
80
|
local MAX_PACKET_SIZE = 900
|
|
76
81
|
local ENTITY_ID_TYPES = {
|
|
77
82
|
entity = 1,
|
|
@@ -201,7 +206,7 @@ local function track_component(server: Server, component: Entity<any>)
|
|
|
201
206
|
allocate_tag_addition(server, entity, component)
|
|
202
207
|
else
|
|
203
208
|
if not IS_PAIR(id) then
|
|
204
|
-
|
|
209
|
+
return
|
|
205
210
|
end
|
|
206
211
|
allocate_pair_addition(server, entity, component, PAIR_SECOND(world, id))
|
|
207
212
|
end
|
|
@@ -226,7 +231,7 @@ local function track_component(server: Server, component: Entity<any>)
|
|
|
226
231
|
allocate_tag_removal(server, entity, component)
|
|
227
232
|
else
|
|
228
233
|
if not IS_PAIR(id) then
|
|
229
|
-
|
|
234
|
+
return
|
|
230
235
|
end
|
|
231
236
|
allocate_pair_removal(server, entity, component, PAIR_SECOND(world, id))
|
|
232
237
|
end
|
|
@@ -354,7 +359,7 @@ local function write_component_value(server: Server, c: Cursor, component: Entit
|
|
|
354
359
|
end
|
|
355
360
|
else
|
|
356
361
|
if value == NIL_COMPONENT_VALUE then
|
|
357
|
-
--
|
|
362
|
+
-- 128 is zero for vlq
|
|
358
363
|
cursor.writeu8(c, 128)
|
|
359
364
|
else
|
|
360
365
|
table.insert(variants, value :: any)
|
|
@@ -392,6 +397,24 @@ local function write_entity_id(server: Server, c: Cursor, entity: Entity, varian
|
|
|
392
397
|
end
|
|
393
398
|
end
|
|
394
399
|
|
|
400
|
+
local function write_entity_relations(
|
|
401
|
+
server: Server,
|
|
402
|
+
storage: EntityStorage,
|
|
403
|
+
c: Cursor,
|
|
404
|
+
relation: Entity,
|
|
405
|
+
variants: { any }
|
|
406
|
+
)
|
|
407
|
+
local targets = storage.pairs[relation]
|
|
408
|
+
local total_targets = 0
|
|
409
|
+
|
|
410
|
+
for target in targets do
|
|
411
|
+
write_entity_id(server, c, target, variants)
|
|
412
|
+
total_targets += 1
|
|
413
|
+
end
|
|
414
|
+
cursor.write_vlq(c, total_targets)
|
|
415
|
+
write_component_id(server, c, relation)
|
|
416
|
+
end
|
|
417
|
+
|
|
395
418
|
local function write_entity(
|
|
396
419
|
server: Server,
|
|
397
420
|
c: Cursor,
|
|
@@ -403,15 +426,7 @@ local function write_entity(
|
|
|
403
426
|
|
|
404
427
|
local all_pairs = 0
|
|
405
428
|
for relation in active.components[COMPONENT_TYPES.pair] do
|
|
406
|
-
|
|
407
|
-
local total_targets = 0
|
|
408
|
-
|
|
409
|
-
for target in targets do
|
|
410
|
-
write_entity_id(server, c, target, variants)
|
|
411
|
-
total_targets += 1
|
|
412
|
-
end
|
|
413
|
-
cursor.write_vlq(c, total_targets)
|
|
414
|
-
write_component_id(server, c, relation)
|
|
429
|
+
write_entity_relations(server, storage, c, relation, variants)
|
|
415
430
|
all_pairs += 1
|
|
416
431
|
end
|
|
417
432
|
cursor.write_vlq(c, all_pairs)
|
|
@@ -419,6 +434,10 @@ local function write_entity(
|
|
|
419
434
|
local components = 0
|
|
420
435
|
for component in active.components[COMPONENT_TYPES.component] do
|
|
421
436
|
local value = storage.values[component]
|
|
437
|
+
if value == nil then
|
|
438
|
+
continue
|
|
439
|
+
end
|
|
440
|
+
|
|
422
441
|
write_component_value(server, c, component, value, variants)
|
|
423
442
|
components += 1
|
|
424
443
|
end
|
|
@@ -477,8 +496,8 @@ local function append_packet(
|
|
|
477
496
|
end
|
|
478
497
|
end
|
|
479
498
|
|
|
480
|
-
local function combine_packet_outputs(outputs: Array<Packet>, total_size: number): (buffer, { { any } })
|
|
481
|
-
local combined = buffer.create(total_size + utils.vlq_span(#outputs))
|
|
499
|
+
local function combine_packet_outputs(outputs: Array<Packet>, total_size: number, id: number): (buffer, { { any } })
|
|
500
|
+
local combined = buffer.create(total_size + utils.vlq_span(#outputs) + 1)
|
|
482
501
|
local offset = 0
|
|
483
502
|
local variants = table.create(#outputs) :: { { any } }
|
|
484
503
|
|
|
@@ -491,13 +510,14 @@ local function combine_packet_outputs(outputs: Array<Packet>, total_size: number
|
|
|
491
510
|
offset = offset,
|
|
492
511
|
buffer = combined,
|
|
493
512
|
}, #outputs)
|
|
513
|
+
buffer.writeu8(combined, buffer.len(combined) - 1, id)
|
|
494
514
|
|
|
495
515
|
return combined, variants
|
|
496
516
|
end
|
|
497
517
|
|
|
498
518
|
type PacketIterator = () -> (Player, buffer, { { any } })
|
|
499
519
|
|
|
500
|
-
local function create_packet_iterator(packets: { [Player]: MemberPackets })
|
|
520
|
+
local function create_packet_iterator(packets: { [Player]: MemberPackets }, id: number)
|
|
501
521
|
local iterated: Player? = nil
|
|
502
522
|
local function iterator()
|
|
503
523
|
local player, data = next(packets, iterated)
|
|
@@ -506,7 +526,7 @@ local function create_packet_iterator(packets: { [Player]: MemberPackets })
|
|
|
506
526
|
end
|
|
507
527
|
iterated = player
|
|
508
528
|
|
|
509
|
-
local combined, variants = combine_packet_outputs(data.packets, data.total_size)
|
|
529
|
+
local combined, variants = combine_packet_outputs(data.packets, data.total_size, id)
|
|
510
530
|
return player, combined, variants
|
|
511
531
|
end
|
|
512
532
|
return iterator :: PacketIterator
|
|
@@ -543,7 +563,7 @@ local function create_unreliable_packet_iterator(packets: { [Player]: MemberPack
|
|
|
543
563
|
end
|
|
544
564
|
|
|
545
565
|
if #sending > 0 then
|
|
546
|
-
coroutine.yield(player, combine_packet_outputs(sending, total_size))
|
|
566
|
+
coroutine.yield(player, combine_packet_outputs(sending, total_size, PACKET_TYPES.unreliable))
|
|
547
567
|
end
|
|
548
568
|
end
|
|
549
569
|
end
|
|
@@ -581,7 +601,16 @@ local function get_full(server: Server, member: Player): (buffer, { { any } })
|
|
|
581
601
|
total_size += buffer.len(output)
|
|
582
602
|
end
|
|
583
603
|
|
|
584
|
-
return combine_packet_outputs(packets, total_size)
|
|
604
|
+
return combine_packet_outputs(packets, total_size, PACKET_TYPES.full)
|
|
605
|
+
end
|
|
606
|
+
|
|
607
|
+
local function write_vlq_bitmask(c: Cursor, value: number, mask: number, bit: number): number
|
|
608
|
+
if value > 0 then
|
|
609
|
+
cursor.write_vlq(c, value)
|
|
610
|
+
return utils.setbit(mask, bit)
|
|
611
|
+
else
|
|
612
|
+
return mask
|
|
613
|
+
end
|
|
585
614
|
end
|
|
586
615
|
|
|
587
616
|
local function collect_updates(server: Server)
|
|
@@ -589,7 +618,9 @@ local function collect_updates(server: Server)
|
|
|
589
618
|
|
|
590
619
|
for _, storage in server.masking.storages do
|
|
591
620
|
local c = cursor.new()
|
|
621
|
+
|
|
592
622
|
local variants = {}
|
|
623
|
+
local storage_mask = 0
|
|
593
624
|
|
|
594
625
|
local total_deleted = 0
|
|
595
626
|
local entity_deletions = storage.deletions.entities
|
|
@@ -598,47 +629,52 @@ local function collect_updates(server: Server)
|
|
|
598
629
|
total_deleted += 1
|
|
599
630
|
end
|
|
600
631
|
table.clear(entity_deletions)
|
|
601
|
-
|
|
632
|
+
storage_mask = write_vlq_bitmask(c, total_deleted, storage_mask, 4)
|
|
602
633
|
|
|
603
634
|
local total_component_deleted = 0
|
|
604
635
|
local component_deletions = storage.deletions.components
|
|
605
636
|
for entity, deleted in component_deletions do
|
|
637
|
+
local deleted_mask = 0
|
|
638
|
+
|
|
606
639
|
local total_pairs = 0
|
|
607
640
|
for relation in deleted[COMPONENT_TYPES.pair] do
|
|
608
641
|
write_component_id(server, c, relation)
|
|
609
642
|
total_pairs += 1
|
|
610
643
|
end
|
|
611
|
-
|
|
644
|
+
deleted_mask = write_vlq_bitmask(c, total_pairs, deleted_mask, 2)
|
|
612
645
|
|
|
613
646
|
local total_components = 0
|
|
614
647
|
for component in deleted[COMPONENT_TYPES.component] do
|
|
615
648
|
write_component_id(server, c, component)
|
|
616
649
|
total_components += 1
|
|
617
650
|
end
|
|
618
|
-
|
|
651
|
+
deleted_mask = write_vlq_bitmask(c, total_components, deleted_mask, 1)
|
|
619
652
|
|
|
620
653
|
local total_tags = 0
|
|
621
654
|
for tag in deleted[COMPONENT_TYPES.tag] do
|
|
622
655
|
write_component_id(server, c, tag)
|
|
623
656
|
total_tags += 1
|
|
624
657
|
end
|
|
625
|
-
|
|
658
|
+
deleted_mask = write_vlq_bitmask(c, total_tags, deleted_mask, 0)
|
|
626
659
|
|
|
660
|
+
cursor.writeu8(c, deleted_mask)
|
|
627
661
|
write_entity_id(server, c, entity, variants)
|
|
628
662
|
total_component_deleted += 1
|
|
629
663
|
end
|
|
630
664
|
table.clear(component_deletions)
|
|
631
|
-
|
|
665
|
+
storage_mask = write_vlq_bitmask(c, total_component_deleted, storage_mask, 3)
|
|
632
666
|
|
|
633
667
|
local storage_changes = storage.changes
|
|
634
668
|
local changed = 0
|
|
635
669
|
for entity, changes in storage_changes.changed do
|
|
670
|
+
local changed_mask = 0
|
|
671
|
+
|
|
636
672
|
local total_removed = 0
|
|
637
673
|
for component in changes.removed do
|
|
638
674
|
write_component_id(server, c, component)
|
|
639
675
|
total_removed += 1
|
|
640
676
|
end
|
|
641
|
-
|
|
677
|
+
changed_mask = write_vlq_bitmask(c, total_removed, changed_mask, 3)
|
|
642
678
|
|
|
643
679
|
local total_pairs = 0
|
|
644
680
|
for relation, targets in changes.pairs do
|
|
@@ -656,27 +692,68 @@ local function collect_updates(server: Server)
|
|
|
656
692
|
write_component_id(server, c, relation)
|
|
657
693
|
total_pairs += 1
|
|
658
694
|
end
|
|
659
|
-
|
|
695
|
+
changed_mask = write_vlq_bitmask(c, total_pairs, changed_mask, 2)
|
|
660
696
|
|
|
661
697
|
local total_components = 0
|
|
662
698
|
for component, value in changes.component do
|
|
663
699
|
write_component_value(server, c, component, value, variants)
|
|
664
700
|
total_components += 1
|
|
665
701
|
end
|
|
666
|
-
|
|
702
|
+
changed_mask = write_vlq_bitmask(c, total_components, changed_mask, 1)
|
|
667
703
|
|
|
668
704
|
local total_tagged = 0
|
|
669
705
|
for tag in changes.tagged do
|
|
670
706
|
write_component_id(server, c, tag)
|
|
671
707
|
total_tagged += 1
|
|
672
708
|
end
|
|
673
|
-
|
|
709
|
+
changed_mask = write_vlq_bitmask(c, total_tagged, changed_mask, 0)
|
|
674
710
|
|
|
711
|
+
cursor.writeu8(c, changed_mask)
|
|
675
712
|
write_entity_id(server, c, entity, variants)
|
|
676
713
|
changed += 1
|
|
677
714
|
end
|
|
678
715
|
table.clear(storage_changes.changed)
|
|
679
|
-
|
|
716
|
+
storage_mask = write_vlq_bitmask(c, changed, storage_mask, 2)
|
|
717
|
+
|
|
718
|
+
local total_components_added = 0
|
|
719
|
+
for entity, components in storage_changes.added_components do
|
|
720
|
+
local entity_storage = server.storage[entity]
|
|
721
|
+
local added_mask = 0
|
|
722
|
+
|
|
723
|
+
local total_pairs = 0
|
|
724
|
+
for relation in components[COMPONENT_TYPES.pair] do
|
|
725
|
+
write_entity_relations(server, entity_storage, c, relation, variants)
|
|
726
|
+
total_pairs += 1
|
|
727
|
+
end
|
|
728
|
+
added_mask = write_vlq_bitmask(c, total_pairs, added_mask, 2)
|
|
729
|
+
|
|
730
|
+
local total_components = 0
|
|
731
|
+
for component in components[COMPONENT_TYPES.component] do
|
|
732
|
+
local value = entity_storage.values[component]
|
|
733
|
+
if value == nil then
|
|
734
|
+
continue
|
|
735
|
+
end
|
|
736
|
+
write_component_value(server, c, component, value, variants)
|
|
737
|
+
total_components += 1
|
|
738
|
+
end
|
|
739
|
+
added_mask = write_vlq_bitmask(c, total_components, added_mask, 1)
|
|
740
|
+
|
|
741
|
+
local total_tags = 0
|
|
742
|
+
for component in components[COMPONENT_TYPES.tag] do
|
|
743
|
+
local has_tag = entity_storage.tags[component]
|
|
744
|
+
if has_tag then
|
|
745
|
+
write_component_id(server, c, component)
|
|
746
|
+
total_tags += 1
|
|
747
|
+
end
|
|
748
|
+
end
|
|
749
|
+
added_mask = write_vlq_bitmask(c, total_tags, added_mask, 0)
|
|
750
|
+
|
|
751
|
+
cursor.writeu8(c, added_mask)
|
|
752
|
+
write_entity_id(server, c, entity, variants)
|
|
753
|
+
total_components_added += 1
|
|
754
|
+
end
|
|
755
|
+
table.clear(storage_changes.added_components)
|
|
756
|
+
storage_mask = write_vlq_bitmask(c, total_components_added, storage_mask, 1)
|
|
680
757
|
|
|
681
758
|
local total_added = 0
|
|
682
759
|
for entity in storage_changes.added do
|
|
@@ -689,14 +766,14 @@ local function collect_updates(server: Server)
|
|
|
689
766
|
total_added += 1
|
|
690
767
|
end
|
|
691
768
|
table.clear(storage_changes.added)
|
|
692
|
-
|
|
769
|
+
storage_mask = write_vlq_bitmask(c, total_added, storage_mask, 0)
|
|
693
770
|
|
|
771
|
+
cursor.writeu8(c, storage_mask)
|
|
694
772
|
local output = cursor.close(c)
|
|
695
773
|
append_packet(packets, storage.mask.members, output, variants)
|
|
696
774
|
end
|
|
697
775
|
table.clear(server.additions)
|
|
698
|
-
|
|
699
|
-
return create_packet_iterator(packets)
|
|
776
|
+
return create_packet_iterator(packets, PACKET_TYPES.reliable)
|
|
700
777
|
end
|
|
701
778
|
|
|
702
779
|
local function collect_unreliable(server: Server)
|
|
@@ -854,6 +931,8 @@ function init(server: Server, _world: World?)
|
|
|
854
931
|
masking:start_component(entity, component, component_type, filter)
|
|
855
932
|
if server.additions[entity] then
|
|
856
933
|
masking:allocate_entity_addition(entity, component, component_type)
|
|
934
|
+
else
|
|
935
|
+
masking:register_component_addition(entity, component, component_type)
|
|
857
936
|
end
|
|
858
937
|
end))
|
|
859
938
|
hook(hooks.changed(world, components.reliable, function(entity, id, filter)
|
|
@@ -881,6 +960,7 @@ function init(server: Server, _world: World?)
|
|
|
881
960
|
if not component_type then
|
|
882
961
|
return
|
|
883
962
|
end
|
|
963
|
+
masking:unregister_component_addition(entity, component, component_type)
|
|
884
964
|
masking:register_stop_component(entity, component, component_type)
|
|
885
965
|
masking:stop_component(entity, component, component_type)
|
|
886
966
|
end))
|
|
@@ -895,6 +975,8 @@ function init(server: Server, _world: World?)
|
|
|
895
975
|
masking:start_component(entity, relation, COMPONENT_TYPES.pair, filter)
|
|
896
976
|
if server.additions[entity] then
|
|
897
977
|
masking:allocate_entity_addition(entity, relation, COMPONENT_TYPES.pair)
|
|
978
|
+
else
|
|
979
|
+
masking:register_component_addition(entity, relation, COMPONENT_TYPES.pair)
|
|
898
980
|
end
|
|
899
981
|
end))
|
|
900
982
|
hook(hooks.changed(world, components.pair, function(entity, id, filter)
|
|
@@ -914,6 +996,7 @@ function init(server: Server, _world: World?)
|
|
|
914
996
|
|
|
915
997
|
local relation = PAIR_SECOND(world, id)
|
|
916
998
|
untrack_entity_pair(server, entity, relation)
|
|
999
|
+
masking:unregister_component_addition(entity, relation, COMPONENT_TYPES.pair)
|
|
917
1000
|
masking:register_stop_component(entity, relation, COMPONENT_TYPES.pair)
|
|
918
1001
|
masking:stop_component(entity, relation, COMPONENT_TYPES.pair)
|
|
919
1002
|
end))
|
|
@@ -965,13 +1048,14 @@ function init(server: Server, _world: World?)
|
|
|
965
1048
|
hook(hooks.removed(world, components.custom_id, function(entity)
|
|
966
1049
|
server.custom_ids[entity] = nil
|
|
967
1050
|
end))
|
|
968
|
-
hook(hooks.added(world, components.global_id, function(entity,
|
|
1051
|
+
hook(hooks.added(world, components.global_id, function(entity, _, value)
|
|
969
1052
|
if value > 245 then
|
|
970
1053
|
utils.logerror "global id size exceeded, max is 245"
|
|
971
1054
|
end
|
|
972
1055
|
server.global_ids[entity] = value
|
|
973
1056
|
end))
|
|
974
|
-
|
|
1057
|
+
|
|
1058
|
+
hook(hooks.changed(world, components.global_id, function(entity, _, value)
|
|
975
1059
|
if value > 245 then
|
|
976
1060
|
utils.logerror "global id size exceeded, max is 245"
|
|
977
1061
|
end
|
package/out/replecs/utils.luau
CHANGED
|
@@ -663,6 +663,13 @@ function utils.remove_all_relations(world: World, entity: Entity, relation: Enti
|
|
|
663
663
|
end
|
|
664
664
|
end
|
|
665
665
|
|
|
666
|
+
function utils.setbit(mask: number, bit: number)
|
|
667
|
+
return bit32.bor(mask, bit32.lshift(1, bit))
|
|
668
|
+
end
|
|
669
|
+
function utils.checkbit(mask: number, bit: number)
|
|
670
|
+
return bit32.band(mask, bit32.lshift(1, bit)) ~= 0
|
|
671
|
+
end
|
|
672
|
+
|
|
666
673
|
function utils.logerror(...: string): never
|
|
667
674
|
error("REPLECS ERROR - " .. table.concat({ ... }, " "))
|
|
668
675
|
end
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rbxts/replecs",
|
|
3
|
-
"version": "0.1.0-
|
|
3
|
+
"version": "0.1.0-alpha3",
|
|
4
4
|
"description": "Replication library for Jecs",
|
|
5
5
|
"main": "out/init.lua",
|
|
6
6
|
"types": "out/index.d.ts",
|
|
@@ -41,6 +41,6 @@
|
|
|
41
41
|
"prettier": "^3.2.5"
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
|
-
"@rbxts/jecs": "^0.
|
|
44
|
+
"@rbxts/jecs": "^0.9.0-rc.7"
|
|
45
45
|
}
|
|
46
46
|
}
|