@rbxts/replecs 0.2.3-test1 → 0.2.4

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.
@@ -1,71 +1,85 @@
1
1
  --!optimize 2
2
2
  --!native
3
3
 
4
- local jecs = require "../jecs"
5
- local utils = require "./utils"
6
- local common = require "./common"
7
- local customid = require "./customid"
8
- local masking_controller = require "./masking"
4
+ local utils = require (script.Parent:WaitForChild('utils'))
5
+ local common = require (script.Parent:WaitForChild('common'))
6
+ local types = require (script.Parent:WaitForChild('types'))
7
+ local customid = require (script.Parent:WaitForChild('customid'))
8
+ local masking_controller = require (script.Parent:WaitForChild('masking'))
9
9
 
10
10
  local cursor = utils.cursor
11
11
 
12
12
  type Cursor = utils.Cursor
13
13
  type CustomId = customid.CustomId
14
+ type StorageGroup = masking_controller.StorageGroup
14
15
 
15
- type World = jecs.World
16
- type Entity<T = any> = jecs.Entity<T>
17
- type Component = Entity
16
+ type World = common.World
17
+ type Entity = common.Entity
18
+ type Component<T = any> = common.Component<T>
18
19
 
19
20
  type Set<T> = { [T]: boolean }
20
21
  type Map<K, V> = { [K]: V }
21
22
  type Array<T> = { T }
22
23
 
23
- type FunctionFilter = common.FunctionFilter
24
- type AnyFilter = common.AnyFilter
24
+ type FunctionFilter = types.FunctionFilter
25
+ type AnyFilter = types.AnyFilter
25
26
 
26
27
  type CustomIdSerialization = {
27
28
  required: Map<Entity, CustomId>,
28
29
  cursor_skip: number,
29
30
  }
30
31
 
32
+ type EntityTrackInfo = {
33
+ components: Map<Component, number>,
34
+ pairs: Map<Component, number>,
35
+ }
36
+
31
37
  type TrackInfo = {
32
38
  networked: Set<Entity>,
33
- entities: Map<Entity, Map<Component, number>>,
39
+ entities: Map<Entity, EntityTrackInfo>,
34
40
  components: Map<Component, Map<Entity, number>>,
41
+ pairs: Map<Component, Map<Entity, number>>,
35
42
  }
36
43
 
37
44
  type EntityStorage = {
38
45
  tags: { [Component]: boolean },
39
- values: { [Component]: any },
40
- pairs: { [Component]: Set<Entity> },
41
- pairs_values: { [Component]: Map<Entity, any> },
46
+ components: { [Component]: any },
47
+ pair_tags: { [Component]: boolean },
48
+ pair_components: { [Component]: any },
49
+
50
+ relations: { [Component]: Set<Entity> },
51
+ relation_values: { [Component]: Map<Entity, any> },
42
52
  }
43
53
 
44
54
  type Storage = { [Entity]: EntityStorage }
45
55
 
46
56
  export type ServerImp = {
47
57
  set_networked: (server: Server, entity: Entity, filter: AnyFilter?) -> (),
48
- stop_networked: (server: Server, entity: Entity) -> (),
49
-
50
58
  set_reliable: (server: Server, entity: Entity, component: Component, filter: AnyFilter?) -> (),
51
59
  set_unreliable: (server: Server, entity: Entity, component: Component, filter: AnyFilter?) -> (),
52
- set_pair: (server: Server, entity: Entity, relation: Component, filter: AnyFilter?) -> (),
53
- set_custom: (server: Server, entity: Entity, component: Component | CustomId) -> (),
60
+ set_pair: (server: Server, entity: Entity, id: Component, filter: AnyFilter?) -> (),
61
+ set_relation: (server: Server, entity: Entity, relation: Component, filter: AnyFilter?) -> (),
62
+
63
+ stop_networked: (server: Server, entity: Entity, keep: boolean?) -> (),
64
+ stop_reliable: (server: Server, entity: Entity, component: Component, keep: boolean?) -> (),
65
+ stop_unreliable: (server: Server, entity: Entity, component: Component, keep: boolean?) -> (),
66
+ stop_pair: (server: Server, entity: Entity, id: Component, keep: boolean?) -> (),
67
+ stop_relation: (server: Server, entity: Entity, relation: Component, keep: boolean?) -> (),
54
68
 
55
- stop_reliable: (server: Server, entity: Entity, component: Component) -> (),
56
- stop_unreliable: (server: Server, entity: Entity, component: Component) -> (),
57
- stop_pair: (server: Server, entity: Entity, relation: Component) -> (),
69
+ set_custom: (server: Server, entity: Entity, component: Component | CustomId) -> (),
58
70
  remove_custom: (server: Server, entity: Entity) -> (),
71
+
72
+ set_serdes: <T>(server: Server, id: Component<T>, serdes: types.Serdes<T>) -> (),
73
+ remove_serdes: (server: Server, id: Component) -> (),
59
74
  }
60
75
 
61
76
  export type Server = ServerImp & {
62
77
  world: World,
63
78
  inited: boolean?,
64
79
 
65
- shared: common.Shared,
80
+ shared: types.Shared,
66
81
 
67
- components: common.Components,
68
- hooks: common.WorldHooks,
82
+ components: types.Components,
69
83
  alive_tracked: Set<Entity>,
70
84
 
71
85
  is_shared_dirty: boolean,
@@ -83,15 +97,18 @@ export type Server = ServerImp & {
83
97
  function_filters: masking_controller.EntityComponentIndex<FunctionFilter>,
84
98
 
85
99
  registered_custom_ids: Map<CustomId, boolean>,
100
+ component_serdes: Map<Component, types.Serdes>,
86
101
 
87
102
  init: (self: Server, world: World?) -> (),
88
103
  destroy: (self: Server) -> (),
89
104
 
90
105
  encode_component: (self: Server, component: Component) -> number,
91
- decode_component: (self: Server, component: number) -> Component,
106
+ decode_component: (self: Server, component: number) -> Component?,
107
+ get_shared_count: (self: Server) -> number,
92
108
  register_custom_id: (self: Server, custom_id: CustomId) -> (),
93
109
 
94
110
  get_full: (self: Server, player: Player) -> (buffer, { { any } }),
111
+ collect_entity: (self: Server, entity: Entity) -> () -> (Player, buffer, { { any } }),
95
112
  collect_updates: (self: Server) -> () -> (Player, buffer, { { any } }),
96
113
  collect_unreliable: (self: Server) -> () -> (Player, buffer, { { any } }),
97
114
 
@@ -101,8 +118,8 @@ export type Server = ServerImp & {
101
118
  add_player_alias: (self: Server, client: Player, alias: any) -> (),
102
119
  remove_player_alias: (self: Server, alias: any) -> (),
103
120
 
104
- generate_handshake: (self: Server) -> common.HandshakeInfo,
105
- verify_handshake: (self: Server, handshake: common.HandshakeInfo) -> (boolean, string?),
121
+ generate_handshake: (self: Server) -> types.HandshakeInfo,
122
+ verify_handshake: (self: Server, handshake: types.HandshakeInfo) -> (boolean, string?),
106
123
  }
107
124
 
108
125
  local server_replicator = {}
@@ -111,18 +128,30 @@ server_replicator.__index = server_replicator
111
128
  local NIL_COMPONENT_VALUE = newproxy()
112
129
  local GLOBAL_ID_OFFSET = 10
113
130
 
114
- local COMPONENT_TYPES = masking_controller.COMPONENT_TYPES
131
+ local COMPONENT_TYPES = {
132
+ tag = 1,
133
+ component = 2,
134
+ pair_tag = 3,
135
+ pair_component = 4,
136
+ relation = 5,
137
+ relation_value = 6,
138
+ unreliable = 7,
139
+ }
140
+
115
141
  local TRACK_TYPES = {
116
- component = 1,
117
- tag = 2,
118
- pair = 3,
119
- pair_value = 4,
142
+ tag = 1,
143
+ component = 2,
144
+ pair_tag = 3,
145
+ pair_component = 4,
146
+ relation = 5,
147
+ relation_value = 6,
120
148
  }
121
149
 
122
150
  local PACKET_TYPES = {
123
151
  full = 1,
124
- unreliable = 2,
125
- reliable = 3,
152
+ entity = 2,
153
+ updates = 3,
154
+ unreliable = 4,
126
155
  }
127
156
 
128
157
  local MAX_PACKET_SIZE = 900
@@ -133,22 +162,93 @@ local ENTITY_ID_TYPES = {
133
162
  shared = 4,
134
163
  }
135
164
 
136
- local ECS_COMPONENT = jecs.Component
137
- local WILDCARD = jecs.Wildcard
165
+ local RELATIONSHIPS = common.relationships
166
+ local WILDCARD = common.wildcard
167
+ local ECS_NAME = common.ecs_name
168
+
169
+ local IS_PAIR = common.is_pair
170
+ local PAIR = common.pair
171
+ local PAIR_FIRST = common.pair_first
172
+ local PAIR_SECOND = common.pair_second
173
+ local WORLD_ADD = common.world_add
174
+ local WORLD_HAS = common.world_has
175
+ local WORLD_GET = common.world_get
176
+ local WORLD_TARGET = common.world_target
177
+ local IS_COMPONENT = common.is_component
178
+
179
+ local LISTEN_RELATION = common.listen_relation
180
+
181
+ local HOOK_ADDED = common.hook_added
182
+ local HOOK_CHANGED = common.hook_changed
183
+ local HOOK_REMOVED = common.hook_removed
184
+
185
+ local function HOOK_PAIR_ADDED(world: World, pair_id: Entity, callback: (Entity, Component, any) -> ())
186
+ local relation = PAIR_FIRST(world, pair_id)
187
+
188
+ return HOOK_ADDED(world, relation, function(entity, id, value)
189
+ if id ~= pair_id then
190
+ return
191
+ end
192
+ callback(entity, id, value)
193
+ end)
194
+ end
195
+
196
+ local function HOOK_PAIR_CHANGED(world: World, pair_id: Entity, callback: (Entity, Component, any) -> ())
197
+ local relation = PAIR_FIRST(world, pair_id)
138
198
 
139
- local function IS_PAIR(id: Component): boolean
140
- return jecs.IS_PAIR(id)
199
+ return HOOK_CHANGED(world, relation, function(entity, id, value)
200
+ if id ~= pair_id then
201
+ return
202
+ end
203
+ callback(entity, id, value)
204
+ end)
141
205
  end
142
206
 
143
- local function PAIR(relation: Entity, target: Entity): Entity
144
- return jecs.pair(relation, target)
207
+ local function HOOK_PAIR_REMOVED(world: World, pair_id: Entity, callback: (Entity, Component) -> ())
208
+ local relation = PAIR_FIRST(world, pair_id)
209
+
210
+ return HOOK_REMOVED(world, relation, function(entity, id)
211
+ if id ~= pair_id then
212
+ return
213
+ end
214
+ callback(entity, id)
215
+ end)
145
216
  end
146
217
 
147
- local function PAIR_SECOND(world: World, id: Entity): Entity
148
- if not IS_PAIR(id) then
149
- error(`expected a pair, got: {utils.logcomponent(world, id)}`)
218
+ local function QUERY_TRACKING_TYPE(server: Server, track_type: Component)
219
+ local world = server.world
220
+ for entity in world:query(PAIR(track_type, WILDCARD)):iter() do
221
+ local index = 0
222
+ while true do
223
+ local target = WORLD_TARGET(world, entity, track_type, index)
224
+ if not target then
225
+ break
226
+ end
227
+ server.set_reliable(server, entity, target, WORLD_GET(world, entity, PAIR(track_type, target)))
228
+ index += 1
229
+ end
230
+ end
231
+ end
232
+
233
+ local function QUERY_CURRENT_NETWORKED(server: Server)
234
+ for entity, filter in server.world:query(server.components.networked):iter() do
235
+ server.set_networked(server, entity, filter)
236
+ end
237
+
238
+ if RELATIONSHIPS then
239
+ QUERY_TRACKING_TYPE(server, server.components.reliable)
240
+ QUERY_TRACKING_TYPE(server, server.components.unreliable)
241
+ QUERY_TRACKING_TYPE(server, server.components.relation)
242
+ end
243
+ end
244
+
245
+ local function QUERY_CURRENT_COMPONENTS(server: Server)
246
+ for component, serdes in server.world:query(server.components.serdes):iter() do
247
+ server.component_serdes[component] = serdes
248
+ end
249
+ for entity, id in server.world:query(server.components.global):iter() do
250
+ server.global_ids[entity] = id
150
251
  end
151
- return jecs.pair_second(world, id)
152
252
  end
153
253
 
154
254
  local function track_entity_lifetime(server: Server, entity: Entity)
@@ -156,18 +256,20 @@ local function track_entity_lifetime(server: Server, entity: Entity)
156
256
  return
157
257
  end
158
258
  server.alive_tracked[entity] = true
159
- server.world:add(entity, server.components.__alive_tracking__)
259
+ WORLD_ADD(server.world, entity, server.components.__alive_tracking__)
160
260
  end
161
261
 
162
262
  local function get_or_set_entity_storage(server: Server, entity: Entity): EntityStorage
163
- local storage = server.storage[entity]
263
+ local storage: EntityStorage = server.storage[entity]
164
264
 
165
265
  if not storage then
166
266
  storage = {
167
267
  tags = {},
168
- values = {},
169
- pairs = {},
170
- pairs_values = {},
268
+ components = {},
269
+ pair_tags = {},
270
+ pair_components = {},
271
+ relations = {},
272
+ relation_values = {},
171
273
  }
172
274
  server.storage[entity] = storage
173
275
  end
@@ -175,36 +277,47 @@ local function get_or_set_entity_storage(server: Server, entity: Entity): Entity
175
277
  return storage
176
278
  end
177
279
 
178
- local function add_entity_tracked(server: Server, entity: Entity, component: Component, track_type: number)
179
- local track = server.track_info.entities[entity]
180
- if track == nil then
181
- track = {
182
- [component] = track_type,
183
- }
184
- server.track_info.entities[entity] = track
185
- else
186
- track[component] = track_type
280
+ local function allocate_component_change(server: Server, entity: Entity, component: Component, value: any)
281
+ local storage = get_or_set_entity_storage(server, entity)
282
+
283
+ local non_nil = if value == nil then NIL_COMPONENT_VALUE else value
284
+ storage.components[component] = non_nil
285
+
286
+ if not server.additions[entity] and server.track_info.networked[entity] then
287
+ server.masking:allocate_component_change(entity, component, non_nil)
187
288
  end
188
289
  end
189
290
 
190
- local function remove_entity_tracked(server: Server, entity: Entity, component: Component)
191
- local track = server.track_info.entities[entity]
192
- if track then
193
- track[component] = nil
291
+ local function allocate_tag_addition(server: Server, entity: Entity, tag: Component)
292
+ local storage = get_or_set_entity_storage(server, entity)
293
+ storage.tags[tag] = true
294
+
295
+ if not server.additions[entity] and server.track_info.networked[entity] then
296
+ server.masking:allocate_tag_addition(entity, tag)
194
297
  end
195
298
  end
196
299
 
197
- local function allocate_component_change(server: Server, entity: Entity, component: Component, value: any)
300
+ local function allocate_pair_addition(server: Server, entity: Entity, id: Component)
301
+ local storage = get_or_set_entity_storage(server, entity)
302
+ storage.pair_tags[id] = true
303
+
304
+ if not server.additions[entity] and server.track_info.networked[entity] then
305
+ server.masking:allocate_pair_addition(entity, id)
306
+ end
307
+ end
308
+
309
+ local function allocate_pair_change(server: Server, entity: Entity, id: Component, value: any)
198
310
  local storage = get_or_set_entity_storage(server, entity)
199
311
 
200
312
  local non_nil = if value == nil then NIL_COMPONENT_VALUE else value
313
+ storage.pair_components[id] = non_nil
201
314
 
202
- storage.values[component] = non_nil
203
315
  if not server.additions[entity] and server.track_info.networked[entity] then
204
- server.masking:allocate_component_change(entity, component, non_nil)
316
+ server.masking:allocate_pair_change(entity, id, non_nil)
205
317
  end
206
318
  end
207
- local function allocate_pair_value_change(
319
+
320
+ local function allocate_relation_value_change(
208
321
  server: Server,
209
322
  entity: Entity,
210
323
  relation: Component,
@@ -213,79 +326,91 @@ local function allocate_pair_value_change(
213
326
  )
214
327
  local storage = get_or_set_entity_storage(server, entity)
215
328
 
216
- local non_nil = if value == nil then NIL_COMPONENT_VALUE else value
217
-
218
- local values = storage.pairs_values[relation]
329
+ local values = storage.relation_values[relation]
219
330
  if values == nil then
220
331
  values = {}
221
- storage.pairs_values[relation] = values
332
+ storage.relation_values[relation] = values
222
333
  end
334
+
335
+ local non_nil = if value == nil then NIL_COMPONENT_VALUE else value
223
336
  values[target] = non_nil
224
337
 
225
338
  if not server.additions[entity] and server.track_info.networked[entity] then
226
- server.masking:allocate_pair_value_change(entity, relation, target, non_nil)
339
+ server.masking:allocate_relation_value_change(entity, relation, target, non_nil)
227
340
  end
228
341
  end
229
342
 
230
- local function allocate_tag_addition(server: Server, entity: Entity, tag: Component)
231
- local storage = get_or_set_entity_storage(server, entity)
232
- storage.tags[tag] = true
233
-
234
- if not server.additions[entity] and server.track_info.networked[entity] then
235
- server.masking:allocate_tag_addition(entity, tag)
236
- end
237
- end
238
- local function allocate_pair_addition(server: Server, entity: Entity, relation: Component, target: Entity)
343
+ local function allocate_relation_addition(server: Server, entity: Entity, relation: Component, target: Entity)
239
344
  local storage = get_or_set_entity_storage(server, entity)
240
- local targets = storage.pairs[relation]
345
+ local targets = storage.relations[relation]
241
346
  if targets == nil then
242
347
  targets = {}
243
- storage.pairs[relation] = targets
348
+ storage.relations[relation] = targets
244
349
  end
245
350
  targets[target] = true
246
351
 
247
352
  if not server.additions[entity] and server.track_info.networked[entity] then
248
- server.masking:allocate_pair_addition(entity, relation, target)
353
+ server.masking:allocate_relation_addition(entity, relation, target)
249
354
  end
250
355
  end
251
356
 
252
357
  local function allocate_component_removal(server: Server, entity: Entity, component: Component)
253
358
  local storage = get_or_set_entity_storage(server, entity)
254
- storage.values[component] = nil
359
+ storage.components[component] = nil
255
360
 
256
361
  if not server.additions[entity] and server.track_info.networked[entity] then
257
362
  server.masking:allocate_component_removal(entity, component)
258
363
  end
259
364
  end
260
- local function allocate_pair_value_removal(server: Server, entity: Entity, relation: Component, target: Entity)
365
+
366
+ local function allocate_tag_removal(server: Server, entity: Entity, tag: Component)
261
367
  local storage = get_or_set_entity_storage(server, entity)
262
- local values = storage.pairs_values[relation]
263
- if values then
264
- values[target] = nil
368
+ storage.tags[tag] = nil
369
+
370
+ if not server.additions[entity] and server.track_info.networked[entity] then
371
+ server.masking:allocate_tag_removal(entity, tag)
265
372
  end
373
+ end
374
+
375
+ local function allocate_pair_tag_removal(server: Server, entity: Entity, id: Component)
376
+ local storage = get_or_set_entity_storage(server, entity)
377
+ storage.pair_tags[id] = nil
266
378
 
267
379
  if not server.additions[entity] and server.track_info.networked[entity] then
268
- server.masking:allocate_pair_value_removal(entity, relation, target)
380
+ server.masking:allocate_pair_tag_removal(entity, id)
269
381
  end
270
382
  end
271
383
 
272
- local function allocate_tag_removal(server: Server, entity: Entity, tag: Component)
384
+ local function allocate_pair_component_removal(server: Server, entity: Entity, id: Component)
273
385
  local storage = get_or_set_entity_storage(server, entity)
274
- storage.tags[tag] = nil
386
+ storage.pair_components[id] = nil
275
387
 
276
388
  if not server.additions[entity] and server.track_info.networked[entity] then
277
- server.masking:allocate_tag_removal(entity, tag)
389
+ server.masking:allocate_pair_component_removal(entity, id)
278
390
  end
279
391
  end
280
- local function allocate_pair_removal(server: Server, entity: Entity, relation: Component, target: Entity)
392
+
393
+ local function allocate_relation_value_removal(server: Server, entity: Entity, relation: Component, target: Entity)
281
394
  local storage = get_or_set_entity_storage(server, entity)
282
- local targets = storage.pairs[relation]
395
+ local values = storage.relation_values[relation]
396
+ if values then
397
+ values[target] = nil
398
+ end
399
+
400
+ if not server.additions[entity] and server.track_info.networked[entity] then
401
+ server.masking:allocate_relation_value_removal(entity, relation, target)
402
+ end
403
+ end
404
+
405
+ local function allocate_relation_removal(server: Server, entity: Entity, relation: Component, target: Entity)
406
+ local storage = get_or_set_entity_storage(server, entity)
407
+ local targets = storage.relations[relation]
283
408
  if targets then
284
409
  targets[target] = nil
285
410
  end
286
411
 
287
412
  if not server.additions[entity] and server.track_info.networked[entity] then
288
- server.masking:allocate_pair_removal(entity, relation, target)
413
+ server.masking:allocate_relation_removal(entity, relation, target)
289
414
  end
290
415
  end
291
416
 
@@ -299,22 +424,77 @@ local function cleanup_entity(server: Server, entity: Entity)
299
424
 
300
425
  local track_info = server.track_info.entities[entity]
301
426
  if track_info then
302
- for component in track_info do
427
+ for component in track_info.components do
303
428
  local track_component = server.track_info.components[component]
304
429
  if track_component then
305
430
  track_component[entity] = nil
306
431
  end
307
432
  end
433
+ for id in track_info.pairs do
434
+ local track_pair = server.track_info.pairs[id]
435
+ if track_pair then
436
+ track_pair[entity] = nil
437
+ end
438
+ end
308
439
  server.track_info.entities[entity] = nil
309
440
  end
310
441
  end
311
442
 
443
+ local function track_pair(server: Server, pair_id: Component)
444
+ local world = server.world
445
+
446
+ if server.track_info.pairs[pair_id] then
447
+ error(`attemped to track a pair twice: {common.log_component(server.world, PAIR_SECOND(world, pair_id))}`)
448
+ end
449
+
450
+ local info = {} :: Map<Entity, number>
451
+ server.track_info.pairs[pair_id] = info
452
+
453
+ local function hook(unhook: () -> ())
454
+ table.insert(server.hooked, unhook)
455
+ end
456
+
457
+ hook(HOOK_PAIR_ADDED(world, pair_id, function(entity, id, value)
458
+ local track_type = info[entity]
459
+ if not track_type then
460
+ return
461
+ end
462
+
463
+ if track_type == TRACK_TYPES.pair_component then
464
+ allocate_pair_change(server, entity, id, value)
465
+ else
466
+ allocate_pair_addition(server, entity, id)
467
+ end
468
+ end))
469
+ hook(HOOK_PAIR_CHANGED(world, pair_id, function(entity, id, value)
470
+ local track_type = info[entity]
471
+ if not track_type then
472
+ return
473
+ end
474
+
475
+ allocate_pair_change(server, entity, id, value)
476
+ end))
477
+ hook(HOOK_PAIR_REMOVED(world, pair_id, function(entity, id)
478
+ local track_type = info[entity]
479
+ if not track_type then
480
+ return
481
+ end
482
+
483
+ if track_type == TRACK_TYPES.pair_component then
484
+ allocate_pair_component_removal(server, entity, id)
485
+ else
486
+ allocate_pair_tag_removal(server, entity, id)
487
+ end
488
+ end))
489
+
490
+ return info
491
+ end
492
+
312
493
  local function track_component(server: Server, component: Component)
313
494
  local world = server.world
314
- local hooks = server.hooks
315
495
 
316
496
  if server.track_info.components[component] then
317
- error(`attemped to track a component twice: {utils.logcomponent(server.world, component)}`)
497
+ error(`attemped to track a component twice: {common.log_component(server.world, component)}`)
318
498
  end
319
499
 
320
500
  local info = {} :: Map<Entity, number>
@@ -324,7 +504,7 @@ local function track_component(server: Server, component: Component)
324
504
  table.insert(server.hooked, unhook)
325
505
  end
326
506
 
327
- hook(hooks.added(world, component, function(entity, id, value)
507
+ hook(HOOK_ADDED(world, component, function(entity, id, value)
328
508
  local track_type = info[entity]
329
509
  if not track_type then
330
510
  return
@@ -334,33 +514,33 @@ local function track_component(server: Server, component: Component)
334
514
  allocate_component_change(server, entity, component, value)
335
515
  elseif track_type == TRACK_TYPES.tag then
336
516
  allocate_tag_addition(server, entity, component)
337
- elseif track_type == TRACK_TYPES.pair then
517
+ elseif track_type == TRACK_TYPES.relation then
338
518
  if not IS_PAIR(id) then
339
519
  return
340
520
  end
341
- allocate_pair_addition(server, entity, component, PAIR_SECOND(world, id))
342
- elseif track_type == TRACK_TYPES.pair_value then
521
+ allocate_relation_addition(server, entity, component, PAIR_SECOND(world, id))
522
+ elseif track_type == TRACK_TYPES.relation_value then
343
523
  if not IS_PAIR(id) then
344
524
  return
345
525
  end
346
- allocate_pair_value_change(server, entity, component, PAIR_SECOND(world, id), value)
526
+ allocate_relation_value_change(server, entity, component, PAIR_SECOND(world, id), value)
347
527
  end
348
528
  end))
349
- hook(hooks.changed(world, component, function(entity, id, value)
529
+ hook(HOOK_CHANGED(world, component, function(entity, id, value)
350
530
  local track_type = info[entity]
351
531
  if not track_type then
352
532
  return
353
533
  end
354
534
  if track_type == TRACK_TYPES.component then
355
535
  allocate_component_change(server, entity, component, value)
356
- elseif track_type == TRACK_TYPES.pair_value then
536
+ elseif track_type == TRACK_TYPES.relation_value then
357
537
  if not IS_PAIR(id) then
358
538
  return
359
539
  end
360
- allocate_pair_value_change(server, entity, component, PAIR_SECOND(world, id), value)
540
+ allocate_relation_value_change(server, entity, component, PAIR_SECOND(world, id), value)
361
541
  end
362
542
  end))
363
- hook(hooks.removed(world, component, function(entity, id)
543
+ hook(HOOK_REMOVED(world, component, function(entity, id)
364
544
  local track_type = info[entity]
365
545
  if not track_type then
366
546
  return
@@ -370,23 +550,63 @@ local function track_component(server: Server, component: Component)
370
550
  allocate_component_removal(server, entity, component)
371
551
  elseif track_type == TRACK_TYPES.tag then
372
552
  allocate_tag_removal(server, entity, component)
373
- elseif track_type == TRACK_TYPES.pair then
553
+ elseif track_type == TRACK_TYPES.relation then
374
554
  if not IS_PAIR(id) then
375
555
  return
376
556
  end
377
- allocate_pair_removal(server, entity, component, PAIR_SECOND(world, id))
378
- elseif track_type == TRACK_TYPES.pair_value then
557
+ allocate_relation_removal(server, entity, component, PAIR_SECOND(world, id))
558
+ elseif track_type == TRACK_TYPES.relation_value then
379
559
  if not IS_PAIR(id) then
380
560
  return
381
561
  end
382
- allocate_pair_value_removal(server, entity, component, PAIR_SECOND(world, id))
562
+ allocate_relation_value_removal(server, entity, component, PAIR_SECOND(world, id))
383
563
  end
384
564
  end))
385
565
 
386
566
  return info
387
567
  end
388
568
 
389
- local function track_entity_component(server: Server, entity: Entity, component: Entity<any>)
569
+ local function add_entity_component_tracked(server: Server, entity: Entity, component: Component, track_type: number)
570
+ local track: EntityTrackInfo = server.track_info.entities[entity]
571
+ if track == nil then
572
+ track = {
573
+ components = { [component] = track_type },
574
+ pairs = {},
575
+ }
576
+ server.track_info.entities[entity] = track
577
+ else
578
+ track.components[component] = track_type
579
+ end
580
+ end
581
+
582
+ local function add_entity_pair_tracked(server: Server, entity: Entity, id: Component, track_type: number)
583
+ local track: EntityTrackInfo = server.track_info.entities[entity]
584
+ if track == nil then
585
+ track = {
586
+ components = {},
587
+ pairs = { [id] = track_type },
588
+ }
589
+ server.track_info.entities[entity] = track
590
+ else
591
+ track.pairs[id] = track_type
592
+ end
593
+ end
594
+
595
+ local function remove_entity_component_tracked(server: Server, entity: Entity, component: Component)
596
+ local track = server.track_info.entities[entity]
597
+ if track then
598
+ track.components[component] = nil
599
+ end
600
+ end
601
+
602
+ local function remove_entity_pair_tracked(server: Server, entity: Entity, id: Component)
603
+ local track = server.track_info.entities[entity]
604
+ if track then
605
+ track.pairs[id] = nil
606
+ end
607
+ end
608
+
609
+ local function track_entity_component(server: Server, entity: Entity, component: Component)
390
610
  local world = server.world
391
611
  local info = server.track_info.components[component]
392
612
  if not info then
@@ -395,34 +615,70 @@ local function track_entity_component(server: Server, entity: Entity, component:
395
615
 
396
616
  local entity_storage = get_or_set_entity_storage(server, entity)
397
617
 
398
- if world:has(component, ECS_COMPONENT) then
399
- if world:has(entity, component) then
400
- local value = world:get(entity, component)
618
+ if IS_COMPONENT(world, component) then
619
+ if WORLD_HAS(world, entity, component) then
620
+ local value = WORLD_GET(world, entity, component)
401
621
 
402
622
  if value == nil then
403
- entity_storage.values[component] = NIL_COMPONENT_VALUE
623
+ entity_storage.components[component] = NIL_COMPONENT_VALUE
404
624
  else
405
- entity_storage.values[component] = value
625
+ entity_storage.components[component] = value
406
626
  end
407
627
  end
408
628
 
409
629
  info[entity] = TRACK_TYPES.component
410
- add_entity_tracked(server, entity, component, TRACK_TYPES.component)
630
+ add_entity_component_tracked(server, entity, component, TRACK_TYPES.component)
411
631
 
412
632
  return COMPONENT_TYPES.component
413
633
  else
414
- if world:has(entity, component) then
634
+ if WORLD_HAS(world, entity, component) then
415
635
  entity_storage.tags[component] = true
416
636
  end
417
637
 
418
638
  info[entity] = TRACK_TYPES.tag
419
- add_entity_tracked(server, entity, component, TRACK_TYPES.tag)
639
+ add_entity_component_tracked(server, entity, component, TRACK_TYPES.tag)
420
640
 
421
641
  return COMPONENT_TYPES.tag
422
642
  end
423
643
  end
424
644
 
425
- local function track_entity_pair(server: Server, entity: Entity, relation: Entity)
645
+ local function track_entity_pair(server: Server, entity: Entity, id: Component)
646
+ local world = server.world
647
+ local info = server.track_info.pairs[id]
648
+ if not info then
649
+ info = track_pair(server, id)
650
+ end
651
+
652
+ local entity_storage = get_or_set_entity_storage(server, entity)
653
+
654
+ if IS_COMPONENT(world, id) then
655
+ if WORLD_HAS(world, entity, id) then
656
+ local value = WORLD_GET(world, entity, id)
657
+
658
+ if value == nil then
659
+ entity_storage.pair_components[id] = NIL_COMPONENT_VALUE
660
+ else
661
+ entity_storage.pair_components[id] = value
662
+ end
663
+ end
664
+
665
+ info[entity] = TRACK_TYPES.pair_component
666
+ add_entity_pair_tracked(server, entity, id, TRACK_TYPES.pair_component)
667
+
668
+ return COMPONENT_TYPES.pair_component
669
+ else
670
+ if WORLD_HAS(world, entity, id) then
671
+ entity_storage.pair_tags[id] = true
672
+ end
673
+
674
+ info[entity] = TRACK_TYPES.pair_tag
675
+ add_entity_pair_tracked(server, entity, id, TRACK_TYPES.pair_tag)
676
+
677
+ return COMPONENT_TYPES.pair_tag
678
+ end
679
+ end
680
+
681
+ local function track_entity_relation(server: Server, entity: Entity, relation: Component)
426
682
  local world = server.world
427
683
  local info = server.track_info.components[relation]
428
684
  if not info then
@@ -431,31 +687,31 @@ local function track_entity_pair(server: Server, entity: Entity, relation: Entit
431
687
 
432
688
  local entity_storage = get_or_set_entity_storage(server, entity)
433
689
 
434
- if world:has(relation, ECS_COMPONENT) then
690
+ if IS_COMPONENT(world, relation) then
435
691
  local targets = {} :: Map<Entity, any>
436
692
 
437
693
  local index = 0
438
694
  while true do
439
- local target = world:target(entity, relation, index)
695
+ local target = WORLD_TARGET(world, entity, relation, index)
440
696
  if not target then
441
697
  break
442
698
  end
443
699
  index += 1
444
- local value = world:get(entity, jecs.pair(relation, target))
700
+ local value = WORLD_GET(world, entity, PAIR(relation, target))
445
701
  targets[target] = if value == nil then NIL_COMPONENT_VALUE else value :: any
446
702
  end
447
703
 
448
- entity_storage.pairs_values[relation] = targets
449
- info[entity] = TRACK_TYPES.pair_value
450
- add_entity_tracked(server, entity, relation, TRACK_TYPES.pair_value)
704
+ entity_storage.relation_values[relation] = targets
705
+ info[entity] = TRACK_TYPES.relation_value
706
+ add_entity_component_tracked(server, entity, relation, TRACK_TYPES.relation_value)
451
707
 
452
- return COMPONENT_TYPES.pair_value
708
+ return COMPONENT_TYPES.relation_value
453
709
  else
454
710
  local targets = {} :: Set<Entity>
455
711
 
456
712
  local index = 0
457
713
  while true do
458
- local target = world:target(entity, relation, index)
714
+ local target = WORLD_TARGET(world, entity, relation, index)
459
715
  if not target then
460
716
  break
461
717
  end
@@ -463,15 +719,15 @@ local function track_entity_pair(server: Server, entity: Entity, relation: Entit
463
719
  targets[target] = true
464
720
  end
465
721
 
466
- entity_storage.pairs[relation] = targets
467
- info[entity] = TRACK_TYPES.pair
468
- add_entity_tracked(server, entity, relation, TRACK_TYPES.pair)
722
+ entity_storage.relations[relation] = targets
723
+ info[entity] = TRACK_TYPES.relation
724
+ add_entity_component_tracked(server, entity, relation, TRACK_TYPES.relation)
469
725
 
470
- return COMPONENT_TYPES.pair
726
+ return COMPONENT_TYPES.relation
471
727
  end
472
728
  end
473
729
 
474
- local function untrack_entity_component(server: Server, entity: Entity, component: Entity<any>): number?
730
+ local function untrack_entity_component(server: Server, entity: Entity, component: Component): number?
475
731
  local info = server.track_info.components[component]
476
732
  if not info then
477
733
  return nil
@@ -481,21 +737,33 @@ local function untrack_entity_component(server: Server, entity: Entity, componen
481
737
 
482
738
  local storage = server.storage[entity]
483
739
  if storage then
484
- storage.values[component] = nil
740
+ storage.components[component] = nil
485
741
  storage.tags[component] = nil
486
742
  end
487
743
 
488
- local entity_tracked = server.track_info.entities[entity]
489
- if entity_tracked then
490
- entity_tracked[component] = nil
744
+ remove_entity_component_tracked(server, entity, component)
745
+ return listen_type
746
+ end
747
+
748
+ local function untrack_entity_pair(server: Server, entity: Entity, id: Entity): number?
749
+ local info = server.track_info.pairs[id]
750
+ if not info then
751
+ return nil
491
752
  end
753
+ local listen_type = info[entity]
754
+ info[entity] = nil
492
755
 
493
- remove_entity_tracked(server, entity, component)
756
+ local storage = server.storage[entity]
757
+ if storage then
758
+ storage.pair_tags[id] = nil
759
+ storage.pair_components[id] = nil
760
+ end
494
761
 
762
+ remove_entity_pair_tracked(server, entity, id)
495
763
  return listen_type
496
764
  end
497
765
 
498
- local function untrack_entity_pair(server: Server, entity: Entity, relation: Entity): number?
766
+ local function untrack_entity_relation(server: Server, entity: Entity, relation: Entity): number?
499
767
  local info = server.track_info.components[relation]
500
768
  if not info then
501
769
  return nil
@@ -505,55 +773,41 @@ local function untrack_entity_pair(server: Server, entity: Entity, relation: Ent
505
773
 
506
774
  local storage = server.storage[entity]
507
775
  if storage then
508
- storage.pairs[relation] = nil
509
- storage.pairs_values[relation] = nil
510
- end
511
-
512
- local entity_tracked = server.track_info.entities[entity]
513
- if entity_tracked then
514
- entity_tracked[relation] = nil
776
+ storage.relations[relation] = nil
777
+ storage.relation_values[relation] = nil
515
778
  end
516
779
 
517
- remove_entity_tracked(server, entity, relation)
780
+ remove_entity_component_tracked(server, entity, relation)
518
781
  return listen_type
519
782
  end
520
783
 
521
- function server_replicator.encode_component(server: Server, component: Entity): number
522
- local encoded = server.shared.components.members[component]
523
- if not encoded then
524
- utils.logerror(`attempted to encode a non-shared component `, utils.logcomponent(server.world, component))
525
- return 0
526
- end
527
- return encoded
528
- end
529
-
530
- function server_replicator.decode_component(server: Server, encoded: number): Entity
531
- local component = server.shared.components.indexes[encoded]
532
- if not component then
533
- print("NON SHARED COMPONENTS", encoded, server.shared.components)
534
- error "attemped to decode a non shared component"
784
+ local function write_vlq_bitmask(c: Cursor, value: number, mask: number, bit: number): number
785
+ if value > 0 then
786
+ cursor.write_vlq(c, value)
787
+ return utils.setbit(mask, bit)
788
+ else
789
+ return mask
535
790
  end
536
- return component
537
791
  end
538
792
 
539
793
  function server_replicator.write_component_id(server: Server, c: Cursor, component: Entity)
540
794
  local shared_componens = server.shared.components
541
795
  local encoded = shared_componens.members[component]
542
796
  if not encoded then
543
- utils.logerror(`attempted to replicate a non-shared component `, utils.logcomponent(server.world, component))
797
+ common.log_error(`attempted to replicate a non-shared component `, common.log_component(server.world, component))
544
798
  return
545
799
  end
546
800
  cursor.write_span(c, encoded, #shared_componens.keys)
547
801
  end
548
802
 
549
- function server_replicator.write_component_value(
803
+ function server_replicator.write_variant_value(
550
804
  server: Server,
551
805
  c: Cursor,
552
- component: Entity,
806
+ log_component: Component,
807
+ serdes: types.Serdes?,
553
808
  value: any,
554
- variants: { any }
809
+ variants: any
555
810
  )
556
- local serdes = server.shared.serdes[component]
557
811
  if serdes then
558
812
  local output, serdes_variants = serdes.serialize(if value == NIL_COMPONENT_VALUE then nil else value)
559
813
 
@@ -570,9 +824,9 @@ function server_replicator.write_component_value(
570
824
  cursor.write_vlq(c, start_variants + 1)
571
825
  end
572
826
  elseif serdes_variants ~= nil then
573
- utils.logerror(
574
- "serdes: serializer provided variants yet includes_variants is not set to true for component",
575
- utils.logcomponent(server.world, component)
827
+ common.log_error(
828
+ "serdes: serializer provided variants yet includes_variants is not set to true for component: ",
829
+ common.log_component(server.world, log_component)
576
830
  )
577
831
  end
578
832
 
@@ -580,9 +834,9 @@ function server_replicator.write_component_value(
580
834
  cursor.write_buffer(c, output)
581
835
  if bytespan then
582
836
  if bytespan ~= buffer.len(output) then
583
- utils.logerror(
584
- `bytespan: {bytespan} mismatch for buffer lenght: {buffer.len(output)} in component`,
585
- utils.logcomponent(server.world, component)
837
+ common.log_error(
838
+ `bytespan: {bytespan} mismatch for buffer lenght: {buffer.len(output)} in component: `,
839
+ common.log_component(server.world, log_component)
586
840
  )
587
841
  end
588
842
  else
@@ -600,9 +854,27 @@ function server_replicator.write_component_value(
600
854
  end
601
855
  end
602
856
 
603
- function server_replicator.write_component(server: Server, c: Cursor, component: Entity, value: any, variants: { any })
604
- server_replicator.write_component_value(server, c, component, value, variants)
605
- server_replicator.write_component_id(server, c, component)
857
+ function server_replicator.write_component_value(
858
+ server: Server,
859
+ c: Cursor,
860
+ component: Component,
861
+ value: any,
862
+ variants: { any }
863
+ )
864
+ local serdes = server.shared.serdes[component]
865
+ server_replicator.write_variant_value(server, c, component, serdes, value, variants)
866
+ end
867
+
868
+ function server_replicator.write_pair_value(
869
+ server: Server,
870
+ c: Cursor,
871
+ relation: Component,
872
+ id: Entity,
873
+ value: any,
874
+ variants: { any }
875
+ )
876
+ local serdes = server.shared.serdes[id] or server.shared.serdes[PAIR(relation, WILDCARD)]
877
+ server_replicator.write_variant_value(server, c, relation, serdes, value, variants)
606
878
  end
607
879
 
608
880
  function server_replicator.write_entity_id(server: Server, c: Cursor, entity: Entity)
@@ -634,7 +906,7 @@ function server_replicator.write_entity_id(server: Server, c: Cursor, entity: En
634
906
  end
635
907
 
636
908
  function server_replicator.write_entity_relations(server: Server, storage: EntityStorage, c: Cursor, relation: Entity)
637
- local targets = storage.pairs[relation]
909
+ local targets = storage.relations[relation]
638
910
  local total_targets = 0
639
911
 
640
912
  for target in targets do
@@ -652,7 +924,7 @@ function server_replicator.write_entity_relations_values(
652
924
  relation: Entity,
653
925
  variants: { any }
654
926
  )
655
- local targets = storage.pairs_values[relation]
927
+ local targets = storage.relation_values[relation]
656
928
  local total_targets = 0
657
929
 
658
930
  for target, value in targets do
@@ -664,6 +936,35 @@ function server_replicator.write_entity_relations_values(
664
936
  server_replicator.write_component_id(server, c, relation)
665
937
  end
666
938
 
939
+ function server_replicator.write_entity_pair_value(
940
+ server: Server,
941
+ world: World,
942
+ c: Cursor,
943
+ id: Component,
944
+ value: any,
945
+ variants: { any }
946
+ )
947
+ local first, second = PAIR_FIRST(world, id), PAIR_SECOND(world, id)
948
+ local pointer_start = c.offset
949
+
950
+ server_replicator.write_pair_value(server, c, first, id, value, variants)
951
+
952
+ -- if the entity is a custom id, we dont know if this has a serdes in the client, as it needs to be processed first
953
+ -- we write a vlq so the client can jump in the cursor to skip this value entirely and process it later
954
+ local pointer_offset = c.offset - pointer_start
955
+ cursor.write_vlq(c, pointer_offset)
956
+
957
+ server_replicator.write_entity_id(server, c, second)
958
+ server_replicator.write_component_id(server, c, first)
959
+ end
960
+
961
+ function server_replicator.write_entity_pair(server: Server, world: World, c: Cursor, id: Component)
962
+ local first, second = PAIR_FIRST(world, id), PAIR_SECOND(world, id)
963
+
964
+ server_replicator.write_entity_id(server, c, second)
965
+ server_replicator.write_component_id(server, c, first)
966
+ end
967
+
667
968
  function server_replicator.write_entity(
668
969
  server: Server,
669
970
  c: Cursor,
@@ -671,56 +972,87 @@ function server_replicator.write_entity(
671
972
  active: masking_controller.ActiveEntity,
672
973
  variants: { any }
673
974
  )
975
+ local world = server.world
674
976
  local storage = server.storage[entity]
977
+ local entity_mask = 0
675
978
 
676
- local all_pairs_values = 0
677
- for relation in active.components[COMPONENT_TYPES.pair_value] do
979
+ local total_relation_values = 0
980
+ for relation in active.components[COMPONENT_TYPES.relation_value] do
678
981
  server_replicator.write_entity_relations_values(server, storage, c, relation, variants)
679
- all_pairs_values += 1
982
+ total_relation_values += 1
680
983
  end
681
- cursor.write_vlq(c, all_pairs_values)
984
+ entity_mask = write_vlq_bitmask(c, total_relation_values, entity_mask, 5)
682
985
 
683
- local all_pairs = 0
684
- for relation in active.components[COMPONENT_TYPES.pair] do
986
+ local total_relations = 0
987
+ for relation in active.components[COMPONENT_TYPES.relation] do
685
988
  server_replicator.write_entity_relations(server, storage, c, relation)
686
- all_pairs += 1
989
+ total_relations += 1
990
+ end
991
+ entity_mask = write_vlq_bitmask(c, total_relations, entity_mask, 4)
992
+
993
+ local total_pair_values = 0
994
+ for id in active.components[COMPONENT_TYPES.pair_component] do
995
+ local value = storage.pair_components[id]
996
+ if value == nil then
997
+ continue
998
+ end
999
+
1000
+ server_replicator.write_entity_pair_value(server, world, c, id, value, variants)
1001
+ total_pair_values += 1
1002
+ end
1003
+ entity_mask = write_vlq_bitmask(c, total_pair_values, entity_mask, 3)
1004
+
1005
+ local total_pairs = 0
1006
+ for id in active.components[COMPONENT_TYPES.pair_tag] do
1007
+ local has_pair = storage.pair_tags[id]
1008
+ if has_pair then
1009
+ server_replicator.write_entity_pair(server, world, c, id)
1010
+ total_pairs += 1
1011
+ end
687
1012
  end
688
- cursor.write_vlq(c, all_pairs)
1013
+ entity_mask = write_vlq_bitmask(c, total_pairs, entity_mask, 2)
689
1014
 
690
- local components = 0
1015
+ local total_components = 0
691
1016
  for component in active.components[COMPONENT_TYPES.component] do
692
- local value = storage.values[component]
1017
+ local value = storage.components[component]
693
1018
  if value == nil then
694
1019
  continue
695
1020
  end
696
1021
 
697
- server_replicator.write_component(server, c, component, value, variants)
698
- components += 1
1022
+ server_replicator.write_component_value(server, c, component, value, variants)
1023
+ server_replicator.write_component_id(server, c, component)
1024
+ total_components += 1
699
1025
  end
700
- cursor.write_vlq(c, components)
1026
+ entity_mask = write_vlq_bitmask(c, total_components, entity_mask, 1)
701
1027
 
702
- local tags = 0
1028
+ local total_tags = 0
703
1029
  for tag in active.components[COMPONENT_TYPES.tag] do
704
1030
  local has_tag = storage.tags[tag]
705
1031
  if has_tag then
706
1032
  server_replicator.write_component_id(server, c, tag)
707
- tags += 1
1033
+ total_tags += 1
708
1034
  end
709
1035
  end
710
- cursor.write_vlq(c, tags)
711
- server_replicator.write_entity_id(server, c, entity)
1036
+ entity_mask = write_vlq_bitmask(c, total_tags, entity_mask, 0)
1037
+ cursor.writeu8(c, entity_mask)
712
1038
  end
713
1039
 
714
1040
  function server_replicator.resolve_dirty(server: Server)
715
1041
  if server.is_shared_dirty then
716
- server.shared = utils.resolved_shared(server.world, server.components, server.registered_custom_ids)
1042
+ -- stylua: ignore
1043
+ server.shared = utils.resolved_shared(
1044
+ server.world,
1045
+ server.components,
1046
+ server.registered_custom_ids,
1047
+ server.component_serdes
1048
+ )
717
1049
  server.is_shared_dirty = false
718
1050
  end
719
1051
  end
720
1052
 
721
1053
  type Packet = {
722
1054
  buffer: buffer,
723
- variants: { { any } },
1055
+ variants: { any },
724
1056
  }
725
1057
  type MemberPackets = {
726
1058
  packets: Array<Packet>,
@@ -728,12 +1060,7 @@ type MemberPackets = {
728
1060
  total_size: number,
729
1061
  }
730
1062
 
731
- local function append_packet(
732
- packets: { [Player]: MemberPackets },
733
- members: { any },
734
- output: buffer,
735
- variants: { { any } }
736
- )
1063
+ local function append_packet(packets: { [Player]: MemberPackets }, members: { any }, output: buffer, variants: { any })
737
1064
  local len = buffer.len(output)
738
1065
  for _, member in members do
739
1066
  if not utils.is_client_valid(member) then
@@ -783,14 +1110,14 @@ end
783
1110
  type PacketIterator = () -> (Player, buffer, { { any } })
784
1111
 
785
1112
  local function create_packet_iterator(packets: { [Player]: MemberPackets }, id: number)
786
- local iterated: Player? = nil
787
- local function iterator()
1113
+ local iterated: Player?
1114
+ local function iterator()
788
1115
  local player, data = next(packets, iterated)
789
1116
  while not utils.is_client_valid(player) do
790
1117
  if not player and not data then
791
1118
  break
792
1119
  end
793
- player, data = next(packets, iterated)
1120
+ player, data = next(packets, player)
794
1121
  end
795
1122
  if not player then
796
1123
  return nil :: any
@@ -849,7 +1176,7 @@ function server_replicator.get_full(server: Server, client: Player): (buffer, {
849
1176
  server_replicator.resolve_dirty(server)
850
1177
  local index = server.masking.client_indexes[client]
851
1178
  if index == nil then
852
- utils.logerror "attempted to replicate for a non registered client"
1179
+ common.log_error "attempted to replicate for a non registered client"
853
1180
  end
854
1181
 
855
1182
  local packets: Array<Packet> = {}
@@ -864,11 +1191,12 @@ function server_replicator.get_full(server: Server, client: Player): (buffer, {
864
1191
  continue
865
1192
  end
866
1193
  local c = cursor.new()
867
- local variants = {}
1194
+ local variants: { any } = {}
868
1195
 
869
1196
  local total_entities = 0
870
1197
  for entity, active in storage.active do
871
1198
  server_replicator.write_entity(server, c, entity, active, variants)
1199
+ server_replicator.write_entity_id(server, c, entity)
872
1200
  total_entities += 1
873
1201
  end
874
1202
  cursor.write_vlq(c, total_entities)
@@ -884,22 +1212,49 @@ function server_replicator.get_full(server: Server, client: Player): (buffer, {
884
1212
  return combine_packet_outputs(packets, total_size, PACKET_TYPES.full)
885
1213
  end
886
1214
 
887
- local function write_vlq_bitmask(c: Cursor, value: number, mask: number, bit: number): number
888
- if value > 0 then
889
- cursor.write_vlq(c, value)
890
- return utils.setbit(mask, bit)
891
- else
892
- return mask
1215
+ function server_replicator.collect_entity(server: Server, entity: Entity)
1216
+ server_replicator.resolve_dirty(server)
1217
+ local packets: { [Player]: MemberPackets } = {}
1218
+ local processed_storages: Set<StorageGroup> = {}
1219
+
1220
+ local lookup = server.masking.lookups.entities[entity]
1221
+ local entity_storage = lookup.storage_group
1222
+
1223
+ local c_main = cursor.new()
1224
+ local variants_main = {}
1225
+
1226
+ server_replicator.write_entity(server, c_main, entity, entity_storage.active[entity], variants_main)
1227
+ server_replicator.write_entity_id(server, c_main, entity)
1228
+ append_packet(packets, entity_storage.mask.members, cursor.close(c_main), variants_main)
1229
+ processed_storages[entity_storage] = true
1230
+
1231
+ for _, filtered in lookup.filtered_components do
1232
+ for _, component in filtered do
1233
+ local storage = component.storage_group
1234
+ if processed_storages[storage] then
1235
+ continue
1236
+ end
1237
+
1238
+ local c = cursor.new()
1239
+ local variants = {}
1240
+
1241
+ server_replicator.write_entity(server, c, entity, storage.active[entity], variants)
1242
+ server_replicator.write_entity_id(server, c_main, entity)
1243
+ append_packet(packets, storage.mask.members, cursor.close(c), variants)
1244
+ processed_storages[storage] = true
1245
+ end
893
1246
  end
1247
+
1248
+ return create_packet_iterator(packets, PACKET_TYPES.entity)
894
1249
  end
895
1250
 
896
1251
  function server_replicator.collect_updates(server: Server)
897
1252
  server_replicator.resolve_dirty(server)
1253
+ local world = server.world
898
1254
  local packets: { [Player]: MemberPackets } = {}
899
1255
 
900
1256
  for _, storage in server.masking.storages do
901
1257
  local c = cursor.new()
902
-
903
1258
  local variants = {}
904
1259
 
905
1260
  local storage_mask = 0
@@ -916,28 +1271,39 @@ function server_replicator.collect_updates(server: Server)
916
1271
  local total_component_deleted = 0
917
1272
  local component_deletions = storage.deletions.components
918
1273
  for entity, deleted in component_deletions do
919
- local total_pairs = 0
1274
+ local total_relations = 0
920
1275
 
921
- for relation in deleted[COMPONENT_TYPES.pair_value] do
1276
+ for relation in deleted[COMPONENT_TYPES.relation_value] do
922
1277
  server_replicator.write_component_id(server, c, relation)
923
- total_pairs += 1
1278
+ total_relations += 1
924
1279
  end
925
- for relation in deleted[COMPONENT_TYPES.pair] do
1280
+ for relation in deleted[COMPONENT_TYPES.relation] do
926
1281
  server_replicator.write_component_id(server, c, relation)
1282
+ total_relations += 1
1283
+ end
1284
+ cursor.write_vlq(c, total_relations)
1285
+
1286
+ local total_pairs = 0
1287
+ for id in deleted[COMPONENT_TYPES.pair_component] do
1288
+ server_replicator.write_entity_pair(server, world, c, id)
1289
+ total_pairs += 1
1290
+ end
1291
+ for id in deleted[COMPONENT_TYPES.pair_tag] do
1292
+ server_replicator.write_entity_pair(server, world, c, id)
927
1293
  total_pairs += 1
928
1294
  end
929
1295
  cursor.write_vlq(c, total_pairs)
930
1296
 
931
- local total_removed = 0
1297
+ local total_components = 0
932
1298
  for component in deleted[COMPONENT_TYPES.component] do
933
1299
  server_replicator.write_component_id(server, c, component)
934
- total_removed += 1
1300
+ total_components += 1
935
1301
  end
936
1302
  for tag in deleted[COMPONENT_TYPES.tag] do
937
1303
  server_replicator.write_component_id(server, c, tag)
938
- total_removed += 1
1304
+ total_components += 1
939
1305
  end
940
- cursor.write_vlq(c, total_removed)
1306
+ cursor.write_vlq(c, total_components)
941
1307
 
942
1308
  server_replicator.write_entity_id(server, c, entity)
943
1309
  total_component_deleted += 1
@@ -948,25 +1314,21 @@ function server_replicator.collect_updates(server: Server)
948
1314
  local storage_changes = storage.changes
949
1315
  local changed = 0
950
1316
  for entity, changes in storage_changes.changed do
951
- local changed_mask = 0
1317
+ -- relations remove
952
1318
 
953
- local total_pairs_values = 0
954
- for relation, targets in changes.pairs_values.changed do
1319
+ local total_relations_removed = 0
1320
+ for relation, targets in changes.relation_removed.component do
955
1321
  local total_targets = 0
956
1322
 
957
- for target, value in targets do
1323
+ for target in targets do
958
1324
  server_replicator.write_entity_id(server, c, target)
959
- server_replicator.write_component_value(server, c, relation, value, variants)
960
1325
  total_targets += 1
961
1326
  end
962
1327
  cursor.write_vlq(c, total_targets)
963
1328
  server_replicator.write_component_id(server, c, relation)
964
- total_pairs_values += 1
1329
+ total_relations_removed += 1
965
1330
  end
966
- changed_mask = write_vlq_bitmask(c, total_pairs_values, changed_mask, 5)
967
-
968
- local total_pairs_values_removed = 0
969
- for relation, targets in changes.pairs_values.removed do
1331
+ for relation, targets in changes.relation_removed.tag do
970
1332
  local total_targets = 0
971
1333
 
972
1334
  for target in targets do
@@ -975,39 +1337,93 @@ function server_replicator.collect_updates(server: Server)
975
1337
  end
976
1338
  cursor.write_vlq(c, total_targets)
977
1339
  server_replicator.write_component_id(server, c, relation)
978
- total_pairs_values_removed += 1
1340
+ total_relations_removed += 1
979
1341
  end
980
- changed_mask = write_vlq_bitmask(c, total_pairs_values_removed, changed_mask, 4)
1342
+ -- using a normal vlq here sadly
1343
+ -- cause I ran out of bitmask space for this one :/
1344
+ cursor.write_vlq(c, total_relations_removed)
981
1345
 
982
- local total_pairs = 0
983
- for relation, targets in changes.pairs do
1346
+ local changed_mask = 0
1347
+
1348
+ -- relations add/set
1349
+
1350
+ local total_relation_values = 0
1351
+ for relation, targets in changes.relation_value do
984
1352
  local total_targets = 0
985
1353
 
986
- for target, added in targets do
1354
+ for target, value in targets do
987
1355
  server_replicator.write_entity_id(server, c, target)
988
- if added then
989
- cursor.writei8(c, 1)
990
- else
991
- cursor.writei8(c, -1)
992
- end
1356
+ server_replicator.write_component_value(server, c, relation, value, variants)
993
1357
  total_targets += 1
994
1358
  end
995
1359
  cursor.write_vlq(c, total_targets)
996
1360
  server_replicator.write_component_id(server, c, relation)
997
- total_pairs += 1
1361
+ total_relation_values += 1
1362
+ end
1363
+ changed_mask = write_vlq_bitmask(c, total_relation_values, changed_mask, 7)
1364
+
1365
+ local total_relations_added = 0
1366
+ for relation, targets in changes.relation_added do
1367
+ local total_targets = 0
1368
+
1369
+ for target in targets do
1370
+ server_replicator.write_entity_id(server, c, target)
1371
+ total_targets += 1
1372
+ end
1373
+ cursor.write_vlq(c, total_targets)
1374
+ server_replicator.write_component_id(server, c, relation)
1375
+ total_relations_added += 1
998
1376
  end
999
- changed_mask = write_vlq_bitmask(c, total_pairs, changed_mask, 3)
1377
+ changed_mask = write_vlq_bitmask(c, total_relations_added, changed_mask, 6)
1378
+
1379
+ -- pairs removed
1380
+
1381
+ local total_pairs_removed = 0
1382
+ for id in changes.pair_removed.component do
1383
+ server_replicator.write_entity_pair(server, world, c, id)
1384
+ total_pairs_removed += 1
1385
+ end
1386
+ for id in changes.pair_removed.tag do
1387
+ server_replicator.write_entity_pair(server, world, c, id)
1388
+ total_pairs_removed += 1
1389
+ end
1390
+ changed_mask = write_vlq_bitmask(c, total_pairs_removed, changed_mask, 5)
1391
+
1392
+ -- pairs add/set
1393
+
1394
+ local total_pairs_set = 0
1395
+ for id, value in changes.pair_changed do
1396
+ server_replicator.write_entity_pair_value(server, world, c, id, value, variants)
1397
+ total_pairs_set += 1
1398
+ end
1399
+ changed_mask = write_vlq_bitmask(c, total_pairs_set, changed_mask, 4)
1400
+
1401
+ local total_pairs_added = 0
1402
+ for id in changes.pair_added do
1403
+ server_replicator.write_entity_pair(server, world, c, id)
1404
+ total_pairs_added += 1
1405
+ end
1406
+ changed_mask = write_vlq_bitmask(c, total_pairs_added, changed_mask, 3)
1407
+
1408
+ -- tags/components removed
1000
1409
 
1001
1410
  local total_removed = 0
1002
- for component in changes.removed do
1411
+ for component in changes.removed.component do
1412
+ server_replicator.write_component_id(server, c, component)
1413
+ total_removed += 1
1414
+ end
1415
+ for component in changes.removed.tag do
1003
1416
  server_replicator.write_component_id(server, c, component)
1004
1417
  total_removed += 1
1005
1418
  end
1006
1419
  changed_mask = write_vlq_bitmask(c, total_removed, changed_mask, 2)
1007
1420
 
1421
+ -- tags/components set
1422
+
1008
1423
  local total_components = 0
1009
1424
  for component, value in changes.component do
1010
- server_replicator.write_component(server, c, component, value, variants)
1425
+ server_replicator.write_component_value(server, c, component, value, variants)
1426
+ server_replicator.write_component_id(server, c, component)
1011
1427
  total_components += 1
1012
1428
  end
1013
1429
  changed_mask = write_vlq_bitmask(c, total_components, changed_mask, 1)
@@ -1019,7 +1435,7 @@ function server_replicator.collect_updates(server: Server)
1019
1435
  end
1020
1436
  changed_mask = write_vlq_bitmask(c, total_tagged, changed_mask, 0)
1021
1437
 
1022
- if changed_mask ~= 0 then
1438
+ if changed_mask + total_relations_removed ~= 0 then
1023
1439
  cursor.writeu8(c, changed_mask)
1024
1440
  server_replicator.write_entity_id(server, c, entity)
1025
1441
  changed += 1
@@ -1033,27 +1449,49 @@ function server_replicator.collect_updates(server: Server)
1033
1449
  local entity_storage = server.storage[entity]
1034
1450
  local added_mask = 0
1035
1451
 
1036
- local total_pairs_values = 0
1037
- for relation in components[COMPONENT_TYPES.pair_value] do
1452
+ local total_relation_values = 0
1453
+ for relation in components[COMPONENT_TYPES.relation_value] do
1038
1454
  server_replicator.write_entity_relations_values(server, entity_storage, c, relation, variants)
1039
- total_pairs_values += 1
1455
+ total_relation_values += 1
1040
1456
  end
1041
- added_mask = write_vlq_bitmask(c, total_pairs_values, added_mask, 3)
1457
+ added_mask = write_vlq_bitmask(c, total_relation_values, added_mask, 5)
1042
1458
 
1043
- local total_pairs = 0
1044
- for relation in components[COMPONENT_TYPES.pair] do
1459
+ local total_relations = 0
1460
+ for relation in components[COMPONENT_TYPES.relation] do
1045
1461
  server_replicator.write_entity_relations(server, entity_storage, c, relation)
1462
+ total_relations += 1
1463
+ end
1464
+ added_mask = write_vlq_bitmask(c, total_relations, added_mask, 4)
1465
+
1466
+ local total_pair_values = 0
1467
+ for id in components[COMPONENT_TYPES.pair_component] do
1468
+ local value = entity_storage.pair_components[id]
1469
+ -- nil is saved here as a special value, this gets automatically handled by write_component_value
1470
+ if value == nil then
1471
+ continue
1472
+ end
1473
+
1474
+ server_replicator.write_entity_pair_value(server, world, c, id, value, variants)
1475
+ total_pair_values += 1
1476
+ end
1477
+ added_mask = write_vlq_bitmask(c, total_pair_values, added_mask, 3)
1478
+
1479
+ local total_pairs = 0
1480
+ for id in components[COMPONENT_TYPES.pair_tag] do
1481
+ server_replicator.write_entity_pair(server, world, c, id)
1046
1482
  total_pairs += 1
1047
1483
  end
1048
1484
  added_mask = write_vlq_bitmask(c, total_pairs, added_mask, 2)
1049
1485
 
1050
1486
  local total_components = 0
1051
1487
  for component in components[COMPONENT_TYPES.component] do
1052
- local value = entity_storage.values[component]
1488
+ local value = entity_storage.components[component]
1489
+ -- nil is saved here as a special value, this gets automatically handled by write_component_value
1053
1490
  if value == nil then
1054
1491
  continue
1055
1492
  end
1056
- server_replicator.write_component(server, c, component, value, variants)
1493
+ server_replicator.write_component_value(server, c, component, value, variants)
1494
+ server_replicator.write_component_id(server, c, component)
1057
1495
  total_components += 1
1058
1496
  end
1059
1497
  added_mask = write_vlq_bitmask(c, total_components, added_mask, 1)
@@ -1085,6 +1523,7 @@ function server_replicator.collect_updates(server: Server)
1085
1523
  end
1086
1524
 
1087
1525
  server_replicator.write_entity(server, c, entity, active, variants)
1526
+ server_replicator.write_entity_id(server, c, entity)
1088
1527
  total_added += 1
1089
1528
  end
1090
1529
  table.clear(storage_changes.added)
@@ -1097,7 +1536,7 @@ function server_replicator.collect_updates(server: Server)
1097
1536
  end
1098
1537
  end
1099
1538
  table.clear(server.additions)
1100
- return create_packet_iterator(packets, PACKET_TYPES.reliable)
1539
+ return create_packet_iterator(packets, PACKET_TYPES.updates)
1101
1540
  end
1102
1541
 
1103
1542
  function server_replicator.collect_unreliable(server: Server)
@@ -1112,20 +1551,17 @@ function server_replicator.collect_unreliable(server: Server)
1112
1551
  local active = mask_storage.active
1113
1552
 
1114
1553
  local c = cursor.new()
1115
- local variants = {} :: { { any } }
1116
- local custom_ids: Set<Entity> = {}
1554
+ local variants = {} :: Array<{ any }>
1117
1555
  local total_entities = 0
1118
1556
 
1119
1557
  local checkpoint_offset = 0
1120
1558
  local checkpoint_variants_count = 0
1121
1559
  local checkpoint_total_entities = 0
1122
- local checkpoint_entity: Entity? = nil
1123
1560
 
1124
- local function create_checkpoint(entity: Entity)
1561
+ local function create_checkpoint()
1125
1562
  checkpoint_offset = c.offset
1126
1563
  checkpoint_variants_count = #variants
1127
1564
  checkpoint_total_entities = total_entities
1128
- checkpoint_entity = entity
1129
1565
  end
1130
1566
 
1131
1567
  local function rollback_checkpoint()
@@ -1134,17 +1570,10 @@ function server_replicator.collect_unreliable(server: Server)
1134
1570
  c.offset = checkpoint_offset
1135
1571
  c = new_cursor
1136
1572
 
1137
- local new_variants = {} :: { { any } }
1573
+ local new_variants = {} :: Array<{ any }>
1138
1574
  for _ = #variants, checkpoint_variants_count + 1, -1 do
1139
- table.insert(new_variants, 1, table.remove(variants))
1140
- end
1141
-
1142
- local new_custom_ids = {} :: Set<Entity>
1143
- if checkpoint_entity then
1144
- new_custom_ids[checkpoint_entity] = true
1145
- custom_ids[checkpoint_entity] = nil
1575
+ table.insert(new_variants, 1, table.remove(variants) :: { any })
1146
1576
  end
1147
- custom_ids = new_custom_ids
1148
1577
 
1149
1578
  variants = new_variants
1150
1579
  total_entities = total_entities - checkpoint_total_entities
@@ -1161,16 +1590,18 @@ function server_replicator.collect_unreliable(server: Server)
1161
1590
  end
1162
1591
 
1163
1592
  for entity, actives in active do
1164
- create_checkpoint(entity)
1593
+ create_checkpoint()
1165
1594
 
1166
1595
  local total_unreliable = 0
1167
1596
  for component in actives.components[COMPONENT_TYPES.unreliable] do
1168
- local value = world:get(entity, component)
1597
+ local value = WORLD_GET(world, entity, component)
1169
1598
  if value == nil then
1170
1599
  continue
1171
1600
  end
1172
1601
 
1173
- server_replicator.write_component(server, c, component, value, variants)
1602
+ server_replicator.write_component_value(server, c, component, value, variants)
1603
+ server_replicator.write_component_id(server, c, component)
1604
+
1174
1605
  total_unreliable += 1
1175
1606
  end
1176
1607
 
@@ -1198,47 +1629,64 @@ end
1198
1629
  function server_replicator.start_networked(server: Server, entity: Entity, filter: AnyFilter?)
1199
1630
  local masking = server.masking
1200
1631
 
1201
- masking:unregister_stop_entity(entity)
1632
+ masking:deallocate_entity_stop(entity)
1202
1633
  masking:start_entity(entity, filter)
1203
- masking:propagate_entity_addition(entity)
1634
+ masking:allocate_propagated_entity_start(entity)
1204
1635
 
1205
1636
  server.additions[entity] = true
1206
1637
  server.track_info.networked[entity] = true
1207
1638
  track_entity_lifetime(server, entity)
1208
1639
  end
1640
+
1209
1641
  function server_replicator.start_reliable(server: Server, entity: Entity, component: Component, filter: AnyFilter?)
1210
1642
  local masking = server.masking
1211
1643
 
1212
- local component_type = track_entity_component(server :: Server, entity, component)
1213
- masking:unregister_stop_component(entity, component, component_type)
1214
- masking:start_component(entity, component, component_type, filter)
1644
+ local track_type = track_entity_component(server :: Server, entity, component)
1645
+ masking:deallocate_component_stop(entity, component, track_type)
1646
+ masking:start_component(entity, component, track_type, filter)
1647
+
1215
1648
  if server.additions[entity] then
1216
- masking:allocate_entity_addition(entity, component, component_type)
1649
+ masking:allocate_shared_entity_start(entity, component, track_type)
1217
1650
  elseif server.track_info.networked[entity] then
1218
- masking:register_component_addition(entity, component, component_type)
1651
+ masking:allocate_component_start(entity, component, track_type)
1219
1652
  end
1220
1653
  end
1221
1654
 
1222
1655
  function server_replicator.start_unreliable(server: Server, entity: Entity, component: Component, filter: AnyFilter?)
1223
1656
  local masking = server.masking
1224
1657
 
1225
- masking:unregister_stop_component(entity, component, COMPONENT_TYPES.unreliable)
1658
+ masking:deallocate_component_stop(entity, component, COMPONENT_TYPES.unreliable)
1226
1659
  masking:start_component(entity, component, COMPONENT_TYPES.unreliable, filter)
1227
1660
  if server.additions[entity] then
1228
- masking:allocate_entity_addition(entity, component, COMPONENT_TYPES.unreliable)
1661
+ masking:allocate_component_start(entity, component, COMPONENT_TYPES.unreliable)
1229
1662
  end
1230
1663
  end
1231
1664
 
1232
- function server_replicator.start_pair(server: Server, entity: Entity, relation: Component, filter: AnyFilter?)
1665
+ function server_replicator.start_pair(server: Server, entity: Entity, id: Component, filter: AnyFilter?)
1233
1666
  local masking = server.masking
1234
1667
 
1235
- local component_type = track_entity_pair(server, entity, relation)
1236
- masking:unregister_stop_component(entity, relation, component_type)
1237
- masking:start_component(entity, relation, component_type, filter)
1668
+ local track_type = track_entity_pair(server :: Server, entity, id)
1669
+ masking:deallocate_component_stop(entity, id, track_type)
1670
+ masking:start_component(entity, id, track_type, filter)
1671
+
1238
1672
  if server.additions[entity] then
1239
- masking:allocate_entity_addition(entity, relation, component_type)
1673
+ masking:allocate_shared_entity_start(entity, id, track_type)
1240
1674
  elseif server.track_info.networked[entity] then
1241
- masking:register_component_addition(entity, relation, component_type)
1675
+ masking:allocate_component_start(entity, id, track_type)
1676
+ end
1677
+ end
1678
+
1679
+ function server_replicator.start_relation(server: Server, entity: Entity, relation: Component, filter: AnyFilter?)
1680
+ local masking = server.masking
1681
+
1682
+ local track_type = track_entity_relation(server, entity, relation)
1683
+ masking:deallocate_component_stop(entity, relation, track_type)
1684
+ masking:start_component(entity, relation, track_type, filter)
1685
+
1686
+ if server.additions[entity] then
1687
+ masking:allocate_shared_entity_start(entity, relation, track_type)
1688
+ elseif server.track_info.networked[entity] then
1689
+ masking:allocate_component_start(entity, relation, track_type)
1242
1690
  end
1243
1691
  end
1244
1692
 
@@ -1246,92 +1694,127 @@ function server_replicator.change_networked(server: Server, entity: Entity, filt
1246
1694
  local masking = server.masking
1247
1695
  masking:set_entity(entity, filter)
1248
1696
  end
1697
+
1249
1698
  function server_replicator.change_reliable(server: Server, entity: Entity, component: Component, filter: AnyFilter?)
1250
1699
  local world = server.world
1251
1700
  local masking = server.masking
1252
1701
 
1253
- if world:has(component, ECS_COMPONENT) then
1702
+ if IS_COMPONENT(world, component) then
1254
1703
  masking:set_component(entity, component, COMPONENT_TYPES.component, filter)
1255
1704
  else
1256
1705
  masking:set_component(entity, component, COMPONENT_TYPES.tag, filter)
1257
1706
  end
1258
1707
  end
1708
+
1259
1709
  function server_replicator.change_unreliable(server: Server, entity: Entity, component: Component, filter: AnyFilter?)
1260
1710
  local masking = server.masking
1261
1711
  masking:set_component(entity, component, COMPONENT_TYPES.unreliable, filter)
1262
1712
  end
1263
- function server_replicator.change_pair(server: Server, entity: Entity, relation: Component, filter: AnyFilter?)
1713
+
1714
+ function server_replicator.change_pair(server: Server, entity: Entity, id: Component, filter: AnyFilter?)
1264
1715
  local world = server.world
1265
1716
  local masking = server.masking
1266
1717
 
1267
- if world:has(relation, ECS_COMPONENT) then
1268
- masking:set_component(entity, relation, COMPONENT_TYPES.pair_value, filter)
1718
+ if IS_COMPONENT(world, id) then
1719
+ masking:set_component(entity, id, COMPONENT_TYPES.pair_component, filter)
1269
1720
  else
1270
- masking:set_component(entity, relation, COMPONENT_TYPES.pair, filter)
1721
+ masking:set_component(entity, id, COMPONENT_TYPES.pair_tag, filter)
1271
1722
  end
1272
1723
  end
1273
1724
 
1274
- function server_replicator.stop_networked(server: Server, entity: Entity)
1725
+ function server_replicator.change_relation(server: Server, entity: Entity, relation: Component, filter: AnyFilter?)
1726
+ local world = server.world
1727
+ local masking = server.masking
1728
+
1729
+ if IS_COMPONENT(world, relation) then
1730
+ masking:set_component(entity, relation, COMPONENT_TYPES.relation_value, filter)
1731
+ else
1732
+ masking:set_component(entity, relation, COMPONENT_TYPES.relation, filter)
1733
+ end
1734
+ end
1735
+
1736
+ local function stop_tracked_component(
1737
+ server: Server,
1738
+ entity: Entity,
1739
+ component: Component,
1740
+ track_type: number,
1741
+ keep: boolean?
1742
+ )
1743
+ local masking = server.masking
1744
+ if server.track_info.networked[entity] then
1745
+ masking:deallocate_component_start(entity, component, track_type)
1746
+ if not keep then
1747
+ masking:allocate_component_stop(entity, component, track_type)
1748
+ end
1749
+ end
1750
+ masking:stop_component(entity, component, track_type)
1751
+ end
1752
+
1753
+ function server_replicator.stop_networked(server: Server, entity: Entity, keep: boolean?)
1275
1754
  if not server.track_info.networked[entity] then
1276
1755
  return
1277
1756
  end
1278
1757
 
1279
1758
  local masking = server.masking
1280
- masking:register_stop_entity(entity)
1759
+ if not keep then
1760
+ masking:allocate_entity_stop(entity)
1761
+ end
1281
1762
  masking:stop_entity(entity)
1282
1763
 
1283
1764
  server.additions[entity] = nil
1284
1765
  server.track_info.networked[entity] = nil
1285
1766
  end
1286
- function server_replicator.stop_reliable(server: Server, entity: Entity, component: Component)
1287
- local masking = server.masking
1767
+
1768
+ function server_replicator.stop_reliable(server: Server, entity: Entity, component: Component, keep: boolean?)
1288
1769
  if not server.track_info.entities[entity] then
1289
1770
  return
1290
1771
  end
1291
1772
 
1292
- local component_type = untrack_entity_component(server, entity, component)
1293
- if not component_type then
1773
+ local track_type = untrack_entity_component(server, entity, component)
1774
+ if not track_type then
1294
1775
  return
1295
1776
  end
1296
1777
 
1297
- if server.track_info.networked[entity] then
1298
- masking:unregister_component_addition(entity, component, component_type)
1299
- masking:register_stop_component(entity, component, component_type)
1300
- end
1301
- masking:stop_component(entity, component, component_type)
1778
+ stop_tracked_component(server, entity, component, track_type, keep)
1302
1779
  end
1303
- function server_replicator.stop_unreliable(server: Server, entity: Entity, component: Component)
1304
- local masking = server.masking
1780
+
1781
+ function server_replicator.stop_unreliable(server: Server, entity: Entity, component: Component, keep: boolean?)
1305
1782
  if not server.track_info.entities[entity] then
1306
1783
  return
1307
1784
  end
1308
1785
 
1309
- local component_type = untrack_entity_component(server, entity, component)
1310
- if not component_type then
1786
+ local track_type = untrack_entity_component(server, entity, component)
1787
+ if not track_type then
1311
1788
  return
1312
1789
  end
1313
1790
 
1314
- if server.track_info.networked[entity] then
1315
- masking:register_stop_component(entity, component, COMPONENT_TYPES.unreliable)
1316
- end
1317
- masking:stop_component(entity, component, COMPONENT_TYPES.unreliable)
1791
+ stop_tracked_component(server, entity, component, COMPONENT_TYPES.unreliable, keep)
1318
1792
  end
1319
- function server_replicator.stop_pair(server: Server, entity: Entity, relation: Component)
1320
- local masking = server.masking
1793
+
1794
+ function server_replicator.stop_pair(server: Server, entity: Entity, id: Component, keep: boolean?)
1321
1795
  if not server.track_info.entities[entity] then
1322
1796
  return
1323
1797
  end
1324
1798
 
1325
- local component_type = untrack_entity_pair(server, entity, relation)
1326
- if not component_type then
1799
+ local track_type = untrack_entity_pair(server, entity, id)
1800
+ if not track_type then
1327
1801
  return
1328
1802
  end
1329
1803
 
1330
- if server.track_info.networked[entity] then
1331
- masking:unregister_component_addition(entity, relation, component_type)
1332
- masking:register_stop_component(entity, relation, component_type)
1804
+ stop_tracked_component(server, entity, id, track_type, keep)
1805
+ end
1806
+
1807
+ function server_replicator.stop_relation(server: Server, entity: Entity, relation: Component, keep: boolean?)
1808
+ if not server.track_info.entities[entity] then
1809
+ return
1810
+ end
1811
+
1812
+ local track_type = untrack_entity_relation(server, entity, relation)
1813
+ if not track_type then
1814
+ return
1333
1815
  end
1334
- masking:stop_component(entity, relation, component_type)
1816
+
1817
+ stop_tracked_component(server, entity, relation, track_type, keep)
1335
1818
  end
1336
1819
 
1337
1820
  function server_replicator.set_networked(server: Server, entity: Entity, filter: AnyFilter?)
@@ -1341,33 +1824,46 @@ function server_replicator.set_networked(server: Server, entity: Entity, filter:
1341
1824
  server_replicator.start_networked(server, entity, filter)
1342
1825
  end
1343
1826
  end
1827
+
1344
1828
  function server_replicator.set_reliable(server: Server, entity: Entity, component: Component, filter: AnyFilter?)
1345
1829
  local entity_tracked = server.track_info.entities[entity]
1346
- if entity_tracked and entity_tracked[component] then
1830
+ if entity_tracked and entity_tracked.components[component] then
1347
1831
  server_replicator.change_reliable(server, entity, component, filter)
1348
1832
  else
1349
1833
  server_replicator.start_reliable(server, entity, component, filter)
1350
1834
  end
1351
1835
  end
1836
+
1352
1837
  function server_replicator.set_unreliable(server: Server, entity: Entity, component: Component, filter: AnyFilter?)
1353
1838
  local entity_tracked = server.track_info.entities[entity]
1354
- if entity_tracked and entity_tracked[component] then
1839
+ if entity_tracked and entity_tracked.components[component] then
1355
1840
  server_replicator.change_unreliable(server, entity, component, filter)
1356
1841
  else
1357
1842
  server_replicator.start_unreliable(server, entity, component, filter)
1358
1843
  end
1359
1844
  end
1360
- function server_replicator.set_pair(server: Server, entity: Entity, relation: Component, filter: AnyFilter?)
1845
+
1846
+ function server_replicator.set_pair(server: Server, entity: Entity, id: Component, filter: AnyFilter?)
1847
+ local entity_tracked = server.track_info.entities[entity]
1848
+ if entity_tracked and entity_tracked.pairs[id] then
1849
+ server_replicator.change_pair(server, entity, id, filter)
1850
+ else
1851
+ server_replicator.start_pair(server, entity, id, filter)
1852
+ end
1853
+ end
1854
+
1855
+ function server_replicator.set_relation(server: Server, entity: Entity, relation: Component, filter: AnyFilter?)
1361
1856
  local entity_tracked = server.track_info.entities[entity]
1362
- if entity_tracked and entity_tracked[relation] then
1363
- server_replicator.change_pair(server, entity, relation, filter)
1857
+ if entity_tracked and entity_tracked.components[relation] then
1858
+ server_replicator.change_relation(server, entity, relation, filter)
1364
1859
  else
1365
- server_replicator.start_pair(server, entity, relation, filter)
1860
+ server_replicator.start_relation(server, entity, relation, filter)
1366
1861
  end
1367
1862
  end
1863
+
1368
1864
  function server_replicator.set_custom(server: Server, entity: Entity, handler: Component | CustomId)
1369
1865
  if server.custom_ids[entity] then
1370
- utils.logwarn("attempted to register a custom_id twice for the same entity", debug.traceback())
1866
+ common.log_warn("attempted to register a custom_id twice for the same entity", debug.traceback())
1371
1867
  return
1372
1868
  end
1373
1869
  server.custom_ids[entity] = handler
@@ -1377,42 +1873,28 @@ function server_replicator.remove_custom(server: Server, entity: Entity)
1377
1873
  server.custom_ids[entity] = nil
1378
1874
  end
1379
1875
 
1876
+ function server_replicator.set_serdes(server: Server, component: Component, serdes: types.Serdes)
1877
+ server.component_serdes[component] = serdes
1878
+ server.is_shared_dirty = true
1879
+ end
1880
+
1881
+ function server_replicator.remove_serdes(server: Server, component: Component)
1882
+ server.component_serdes[component] = nil
1883
+ server.is_shared_dirty = true
1884
+ end
1885
+
1380
1886
  local function check_created(server: Server)
1381
1887
  if server.inited == true then
1382
1888
  warn "attempted to init a server twice"
1383
1889
  return false
1384
1890
  end
1385
1891
  if server.inited == nil then
1386
- warn "attempted to create a server twice"
1892
+ warn "attempted to init a destroyed server"
1387
1893
  return false
1388
1894
  end
1389
1895
  return true
1390
1896
  end
1391
1897
 
1392
- local function query_tracking_type(server: Server, track_type: Component)
1393
- for entity in server.world:query(PAIR(track_type, WILDCARD)):iter() do
1394
- local index = 0
1395
- while true do
1396
- local target = server.world:target(entity, track_type, index)
1397
- if not target then
1398
- break
1399
- end
1400
- server.set_reliable(server, entity, target, server.world:get(entity, PAIR(track_type, target)))
1401
- index += 1
1402
- end
1403
- end
1404
- end
1405
-
1406
- local function query_current_networked(server: Server)
1407
- for entity, filter in server.world:query(server.components.networked):iter() do
1408
- server.set_networked(server, entity, filter)
1409
- end
1410
-
1411
- query_tracking_type(server, server.components.reliable)
1412
- query_tracking_type(server, server.components.unreliable)
1413
- query_tracking_type(server, server.components.pair)
1414
- end
1415
-
1416
1898
  function server_replicator.init(server: Server, wrd: World?)
1417
1899
  if not check_created(server) then
1418
1900
  return
@@ -1426,100 +1908,108 @@ function server_replicator.init(server: Server, wrd: World?)
1426
1908
  error "Providing a world is required to start replecs"
1427
1909
  end
1428
1910
 
1429
- local hooks = server.hooks
1430
- if not hooks then
1431
- hooks = {
1432
- added = (world :: any).added,
1433
- changed = (world :: any).changed,
1434
- removed = (world :: any).removed,
1435
- }
1436
- server.hooks = hooks
1911
+ if not server.components then
1912
+ server.components = utils.create_components(utils.tag_factory(world), utils.component_factory(world))
1913
+ utils.add_component_names(server.components, function(component, name)
1914
+ common.add_name(world, component, name)
1915
+ end)
1437
1916
  end
1438
1917
 
1439
1918
  local components = server.components
1440
- server.shared = utils.resolved_shared(world, components, server.registered_custom_ids)
1441
1919
 
1442
1920
  local function hook(unhook: () -> ())
1443
1921
  table.insert(server.hooked, unhook)
1444
1922
  end
1445
1923
 
1446
- hook(hooks.added(world, components.networked, function(entity, _, filter)
1924
+ hook(HOOK_ADDED(world, components.networked, function(entity, _, filter)
1447
1925
  server_replicator.start_networked(server, entity, filter)
1448
1926
  end))
1449
- hook(hooks.changed(world, components.networked, function(entity, _, filter)
1927
+ hook(HOOK_CHANGED(world, components.networked, function(entity, _, filter)
1450
1928
  server_replicator.change_networked(server, entity, filter)
1451
1929
  end))
1452
- hook(hooks.removed(world, components.networked, function(entity)
1930
+ hook(HOOK_REMOVED(world, components.networked, function(entity)
1453
1931
  server_replicator.stop_networked(server, entity)
1454
1932
  end))
1455
1933
 
1456
- hook(hooks.added(world, components.reliable, function(entity, id, filter)
1457
- local component = PAIR_SECOND(world, id)
1458
- server_replicator.start_reliable(server, entity, component, filter)
1459
- end))
1460
- hook(hooks.changed(world, components.reliable, function(entity, id, filter)
1461
- local component = PAIR_SECOND(world, id)
1462
- server_replicator.change_reliable(server, entity, component, filter)
1463
- end))
1464
- hook(hooks.removed(world, components.reliable, function(entity, id)
1465
- local component = PAIR_SECOND(world, id)
1466
- server_replicator.stop_reliable(server, entity, component)
1467
- end))
1934
+ if RELATIONSHIPS then
1935
+ hook(HOOK_ADDED(world, LISTEN_RELATION(components.reliable), function(entity, id, filter)
1936
+ local component = PAIR_SECOND(world, id)
1937
+ server_replicator.start_reliable(server, entity, component, filter)
1938
+ end))
1939
+ hook(HOOK_CHANGED(world, LISTEN_RELATION(components.reliable), function(entity, id, filter)
1940
+ local component = PAIR_SECOND(world, id)
1941
+ server_replicator.change_reliable(server, entity, component, filter)
1942
+ end))
1943
+ hook(HOOK_REMOVED(world, LISTEN_RELATION(components.reliable), function(entity, id)
1944
+ local component = PAIR_SECOND(world, id)
1945
+ server_replicator.stop_reliable(server, entity, component)
1946
+ end))
1468
1947
 
1469
- hook(hooks.added(world, components.pair, function(entity, id, filter)
1470
- local relation = PAIR_SECOND(world, id)
1471
- server_replicator.start_pair(server, entity, relation, filter)
1472
- end))
1473
- hook(hooks.changed(world, components.pair, function(entity, id, filter)
1474
- local relation = PAIR_SECOND(world, id)
1475
- server_replicator.change_pair(server, entity, relation, filter)
1476
- end))
1477
- hook(hooks.removed(world, components.pair, function(entity, id)
1478
- local relation = PAIR_SECOND(world, id)
1479
- server_replicator.stop_pair(server, entity, relation)
1480
- end))
1948
+ hook(HOOK_ADDED(world, LISTEN_RELATION(components.relation), function(entity, id, filter)
1949
+ local relation = PAIR_SECOND(world, id)
1950
+ server_replicator.start_relation(server, entity, relation, filter)
1951
+ end))
1952
+ hook(HOOK_CHANGED(world, LISTEN_RELATION(components.relation), function(entity, id, filter)
1953
+ local relation = PAIR_SECOND(world, id)
1954
+ server_replicator.change_relation(server, entity, relation, filter)
1955
+ end))
1956
+ hook(HOOK_REMOVED(world, LISTEN_RELATION(components.relation), function(entity, id)
1957
+ local relation = PAIR_SECOND(world, id)
1958
+ server_replicator.stop_relation(server, entity, relation)
1959
+ end))
1481
1960
 
1482
- hook(hooks.added(world, components.unreliable, function(entity, id, filter)
1483
- local component = PAIR_SECOND(world, id)
1484
- server_replicator.start_unreliable(server, entity, component, filter)
1485
- end))
1486
- hook(hooks.changed(world, components.unreliable, function(entity, id, filter)
1487
- local component = PAIR_SECOND(world, id)
1488
- server_replicator.change_unreliable(server, entity, component, filter)
1489
- end))
1490
- hook(hooks.removed(world, components.unreliable, function(entity, id)
1491
- local component = PAIR_SECOND(world, id)
1492
- server_replicator.stop_unreliable(server, entity, component)
1493
- end))
1961
+ hook(HOOK_ADDED(world, LISTEN_RELATION(components.unreliable), function(entity, id, filter)
1962
+ local component = PAIR_SECOND(world, id)
1963
+ server_replicator.start_unreliable(server, entity, component, filter)
1964
+ end))
1965
+ hook(HOOK_CHANGED(world, LISTEN_RELATION(components.unreliable), function(entity, id, filter)
1966
+ local component = PAIR_SECOND(world, id)
1967
+ server_replicator.change_unreliable(server, entity, component, filter)
1968
+ end))
1969
+ hook(HOOK_REMOVED(world, LISTEN_RELATION(components.unreliable), function(entity, id)
1970
+ local component = PAIR_SECOND(world, id)
1971
+ server_replicator.stop_unreliable(server, entity, component)
1972
+ end))
1494
1973
 
1495
- hook(hooks.added(world, components.custom, function(entity, id)
1496
- if not IS_PAIR(id) then
1497
- utils.logerror "replecs.custom should be used with a relationship in the server"
1498
- end
1499
- local target = PAIR_SECOND(world, id)
1500
- server_replicator.set_custom(server, entity, target)
1501
- end))
1502
- hook(hooks.removed(world, components.custom, function(entity)
1503
- server_replicator.remove_custom(server, entity)
1504
- end))
1505
- hook(hooks.added(world, components.global, function(entity, _, value)
1974
+ hook(HOOK_ADDED(world, LISTEN_RELATION(components.custom), function(entity, id)
1975
+ if not IS_PAIR(id) then
1976
+ common.log_error "replecs.custom should be used with a relationship in the server"
1977
+ end
1978
+ local target = PAIR_SECOND(world, id)
1979
+ server_replicator.set_custom(server, entity, target)
1980
+ end))
1981
+ hook(HOOK_REMOVED(world, LISTEN_RELATION(components.custom), function(entity)
1982
+ server_replicator.remove_custom(server, entity)
1983
+ end))
1984
+ end
1985
+ hook(HOOK_ADDED(world, components.global, function(entity, _, value)
1506
1986
  if value > 245 then
1507
- utils.logerror "global id size exceeded, max is 245"
1987
+ common.log_error "global id size exceeded, max is 245"
1508
1988
  end
1509
1989
  server.global_ids[entity] = value
1510
1990
  end))
1511
1991
 
1512
- hook(hooks.changed(world, components.global, function(entity, _, value)
1992
+ hook(HOOK_CHANGED(world, components.global, function(entity, _, value)
1513
1993
  if value > 245 then
1514
- utils.logerror "global id size exceeded, max is 245"
1994
+ common.log_error "global id size exceeded, max is 245"
1515
1995
  end
1516
1996
  server.global_ids[entity] = value
1517
1997
  end))
1518
- hook(hooks.removed(world, components.global, function(entity)
1998
+ hook(HOOK_REMOVED(world, components.global, function(entity)
1519
1999
  server.global_ids[entity] = nil
1520
2000
  end))
1521
2001
 
1522
- hook(hooks.removed(world, components.__alive_tracking__, function(entity)
2002
+ hook(HOOK_ADDED(world, components.serdes, function(component, _, serdes)
2003
+ server_replicator.set_serdes(server, component, serdes)
2004
+ end))
2005
+ hook(HOOK_CHANGED(world, components.serdes, function(component, _, serdes)
2006
+ server_replicator.set_serdes(server, component, serdes)
2007
+ end))
2008
+ hook(HOOK_REMOVED(world, components.serdes, function(component)
2009
+ server_replicator.remove_serdes(server, component)
2010
+ end))
2011
+
2012
+ hook(HOOK_REMOVED(world, components.__alive_tracking__, function(entity)
1523
2013
  if server.track_info.networked[entity] then
1524
2014
  server_replicator.stop_networked(server, entity)
1525
2015
  end
@@ -1527,18 +2017,21 @@ function server_replicator.init(server: Server, wrd: World?)
1527
2017
  end))
1528
2018
 
1529
2019
  for _, component in server.requires_shared_lookup do
1530
- hook(hooks.added(world, component, function()
2020
+ hook(HOOK_ADDED(world, component, function()
1531
2021
  server.is_shared_dirty = true
1532
2022
  end))
1533
- hook(hooks.changed(world, component, function()
2023
+ hook(HOOK_CHANGED(world, component, function()
1534
2024
  server.is_shared_dirty = true
1535
2025
  end))
1536
- hook(hooks.removed(world, component, function()
2026
+ hook(HOOK_REMOVED(world, component, function()
1537
2027
  server.is_shared_dirty = true
1538
2028
  end))
1539
2029
  end
1540
2030
 
1541
- query_current_networked(server)
2031
+ QUERY_CURRENT_COMPONENTS(server)
2032
+ QUERY_CURRENT_NETWORKED(server)
2033
+
2034
+ server.shared = utils.resolved_shared(world, components, server.registered_custom_ids, server.component_serdes)
1542
2035
 
1543
2036
  if game and game:GetService("RunService"):IsServer() then
1544
2037
  local Players = game:GetService "Players"
@@ -1558,6 +2051,27 @@ function server_replicator.init(server: Server, wrd: World?)
1558
2051
  end
1559
2052
  end
1560
2053
 
2054
+ function server_replicator.encode_component(server: Server, component: Entity): number
2055
+ server_replicator.resolve_dirty(server)
2056
+ local encoded = server.shared.components.members[component]
2057
+ if not encoded then
2058
+ common.log_error(`attempted to encode a non-shared component `, common.log_component(server.world, component))
2059
+ return 0
2060
+ end
2061
+ return encoded
2062
+ end
2063
+
2064
+ function server_replicator.decode_component(server: Server, encoded: number): Entity?
2065
+ server_replicator.resolve_dirty(server)
2066
+ local component = server.shared.components.indexes[encoded]
2067
+ return component
2068
+ end
2069
+
2070
+ function server_replicator.get_shared_count(server: Server): number
2071
+ server_replicator.resolve_dirty(server)
2072
+ return #server.shared.components.keys
2073
+ end
2074
+
1561
2075
  function server_replicator.mark_player_ready(server: Server, player: Player)
1562
2076
  server.masking:activate_client(player)
1563
2077
  end
@@ -1579,14 +2093,14 @@ function server_replicator.register_custom_id(server: Server, custom_id: CustomI
1579
2093
  server.is_shared_dirty = true
1580
2094
  end
1581
2095
 
1582
- function server_replicator.generate_handshake(server: Server): common.HandshakeInfo
2096
+ function server_replicator.generate_handshake(server: Server): types.HandshakeInfo
1583
2097
  server_replicator.resolve_dirty(server)
1584
- return utils.generate_handshake(server.world, server.shared)
2098
+ return utils.generate_handshake(server.shared)
1585
2099
  end
1586
2100
 
1587
- function server_replicator.verify_handshake(server: Server, handshake: common.HandshakeInfo): (boolean, string?)
2101
+ function server_replicator.verify_handshake(server: Server, handshake: types.HandshakeInfo): (boolean, string?)
1588
2102
  server_replicator.resolve_dirty(server)
1589
- return utils.verify_handshake(server.world, server.shared, handshake, "client", "server")
2103
+ return utils.verify_handshake(server.shared, handshake, "client", "server")
1590
2104
  end
1591
2105
 
1592
2106
  function server_replicator.destroy(server: Server)
@@ -1603,12 +2117,19 @@ function server_replicator.destroy(server: Server)
1603
2117
  end
1604
2118
  end
1605
2119
 
1606
- local function create(world: World?, components: common.Components): Server
2120
+ local function create(world: World?, components: types.Components?): Server
1607
2121
  local self = {} :: Server
1608
2122
 
1609
- self.components = components
2123
+ if components then
2124
+ self.components = components
2125
+ elseif world then
2126
+ self.components = utils.create_components(utils.tag_factory(world), utils.component_factory(world))
2127
+ utils.add_component_names(self.components, function(component, name)
2128
+ common.add_name(world, component, name)
2129
+ end)
2130
+ end
1610
2131
 
1611
- self.shared = {} :: common.Shared
2132
+ self.shared = {} :: types.Shared
1612
2133
  self.world = world :: any
1613
2134
  self.additions = {}
1614
2135
  self.storage = {}
@@ -1620,6 +2141,7 @@ local function create(world: World?, components: common.Components): Server
1620
2141
  networked = {},
1621
2142
  entities = {},
1622
2143
  components = {},
2144
+ pairs = {},
1623
2145
  }
1624
2146
  self.connections = {}
1625
2147
  self.inited = false
@@ -1627,21 +2149,12 @@ local function create(world: World?, components: common.Components): Server
1627
2149
  self.alive_tracked = {}
1628
2150
  self.custom_ids = {}
1629
2151
  self.registered_custom_ids = {}
2152
+ self.component_serdes = {}
1630
2153
  self.requires_shared_lookup = {
1631
2154
  self.components.shared,
1632
- self.components.serdes,
1633
- jecs.Name,
2155
+ ECS_NAME,
1634
2156
  }
1635
2157
 
1636
- if world then
1637
- local hooks = {
1638
- added = (world :: any).added,
1639
- changed = (world :: any).changed,
1640
- removed = (world :: any).removed,
1641
- }
1642
- self.hooks = hooks
1643
- end
1644
-
1645
2158
  return setmetatable(self, server_replicator) :: any
1646
2159
  end
1647
2160