@rbxts/replecs 0.1.0-alpha9 → 0.2.0-cdtest.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,34 +4,61 @@
4
4
  local jecs = require "../jecs"
5
5
  local utils = require "./utils"
6
6
  local common = require "./common"
7
+ local customid = require "./customid"
7
8
  local masking_controller = require "./masking"
8
9
 
10
+ local cursor = utils.cursor
11
+
9
12
  type Cursor = utils.Cursor
13
+ type CustomId = customid.CustomId
10
14
 
11
15
  type World = jecs.World
12
16
  type Entity<T = any> = jecs.Entity<T>
17
+ type Component = Entity
13
18
 
14
19
  type Set<T> = { [T]: boolean }
15
20
  type Map<K, V> = { [K]: V }
16
21
  type Array<T> = { T }
17
22
 
18
- type FunctionFilter = (player: Player) -> boolean
23
+ type FunctionFilter = common.FunctionFilter
24
+ type AnyFilter = common.AnyFilter
25
+
26
+ type CustomIdSerialization = {
27
+ required: Map<Entity, CustomId>,
28
+ cursor_skip: number,
29
+ }
19
30
 
20
31
  type TrackInfo = {
21
- entities: Map<Entity, boolean>,
22
- components: { [Entity]: { [Entity]: number } },
32
+ networked: Set<Entity>,
33
+ entities: Map<Entity, Map<Component, number>>,
34
+ components: Map<Component, Map<Entity, number>>,
23
35
  }
24
36
 
25
37
  type EntityStorage = {
26
- tags: { [Entity]: boolean },
27
- values: { [Entity]: any },
28
- pairs: { [Entity]: Set<Entity> },
29
- pairs_values: { [Entity]: Map<Entity, any> },
38
+ tags: { [Component]: boolean },
39
+ values: { [Component]: any },
40
+ pairs: { [Component]: Set<Entity> },
41
+ pairs_values: { [Component]: Map<Entity, any> },
30
42
  }
31
43
 
32
44
  type Storage = { [Entity]: EntityStorage }
33
45
 
34
- export type Server = {
46
+ export type ServerImp = {
47
+ set_networked: (server: Server, entity: Entity, filter: AnyFilter?) -> (),
48
+ stop_networked: (server: Server, entity: Entity) -> (),
49
+
50
+ set_reliable: (server: Server, entity: Entity, component: Component, filter: AnyFilter?) -> (),
51
+ 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) -> (),
54
+
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) -> (),
58
+ remove_custom: (server: Server, entity: Entity) -> (),
59
+ }
60
+
61
+ export type Server = ServerImp & {
35
62
  world: World,
36
63
  inited: boolean?,
37
64
 
@@ -41,12 +68,12 @@ export type Server = {
41
68
  hooks: common.WorldHooks,
42
69
  alive_tracked: Set<Entity>,
43
70
 
44
- is_dirty: boolean,
71
+ is_shared_dirty: boolean,
45
72
  requires_shared_lookup: { Entity },
46
73
 
47
74
  track_info: TrackInfo,
48
75
  additions: Set<Entity>,
49
- custom_ids: Map<Entity, Entity<any>>,
76
+ custom_ids: Map<Entity, CustomId | Entity>,
50
77
  global_ids: Map<Entity, number>,
51
78
  storage: Storage,
52
79
  hooked: Array<() -> ()>,
@@ -55,22 +82,31 @@ export type Server = {
55
82
  connections: Array<RBXScriptConnection>,
56
83
  function_filters: masking_controller.EntityComponentIndex<FunctionFilter>,
57
84
 
85
+ registered_custom_ids: Map<CustomId, boolean>,
86
+
58
87
  init: (self: Server, world: World?) -> (),
59
88
  destroy: (self: Server) -> (),
60
89
 
61
- encode_component: (self: Server, component: Entity) -> number,
62
- decode_component: (self: Server, component: number) -> Entity,
90
+ encode_component: (self: Server, component: Component) -> number,
91
+ decode_component: (self: Server, component: number) -> Component,
92
+ register_custom_id: (self: Server, custom_id: CustomId) -> (),
63
93
 
64
94
  get_full: (self: Server, player: Player) -> (buffer, { { any } }),
65
95
  collect_updates: (self: Server) -> () -> (Player, buffer, { { any } }),
66
96
  collect_unreliable: (self: Server) -> () -> (Player, buffer, { { any } }),
97
+
67
98
  mark_player_ready: (self: Server, player: Player) -> (),
68
99
  is_player_ready: (self: Server, player: Player) -> boolean,
100
+
69
101
  add_player_alias: (self: Server, client: Player, alias: any) -> (),
70
102
  remove_player_alias: (self: Server, alias: any) -> (),
103
+
104
+ generate_handshake: (self: Server) -> common.HandshakeInfo,
105
+ verify_handshake: (self: Server, handshake: common.HandshakeInfo) -> (boolean, string?),
71
106
  }
72
107
 
73
- local cursor = utils.cursor
108
+ local server_replicator = {}
109
+ server_replicator.__index = server_replicator
74
110
 
75
111
  local NIL_COMPONENT_VALUE = newproxy()
76
112
  local GLOBAL_ID_OFFSET = 10
@@ -92,15 +128,26 @@ local PACKET_TYPES = {
92
128
  local MAX_PACKET_SIZE = 900
93
129
  local ENTITY_ID_TYPES = {
94
130
  entity = 1,
95
- custom = 2,
96
- shared = 3,
131
+ custom_handler = 2,
132
+ custom_id = 3,
133
+ shared = 4,
97
134
  }
135
+
98
136
  local ECS_COMPONENT = jecs.Component
137
+ local WILDCARD = jecs.Wildcard
99
138
 
100
- local function IS_PAIR(id: Entity): boolean
139
+ local function IS_PAIR(id: Component): boolean
101
140
  return jecs.IS_PAIR(id)
102
141
  end
142
+
143
+ local function PAIR(relation: Entity, target: Entity): Entity
144
+ return jecs.pair(relation, target)
145
+ end
146
+
103
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)}`)
150
+ end
104
151
  return jecs.pair_second(world, id)
105
152
  end
106
153
 
@@ -128,17 +175,42 @@ local function get_or_set_entity_storage(server: Server, entity: Entity): Entity
128
175
  return storage
129
176
  end
130
177
 
131
- local function allocate_component_change(server: Server, entity: Entity, component: Entity, value: any)
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
187
+ end
188
+ end
189
+
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
194
+ end
195
+ end
196
+
197
+ local function allocate_component_change(server: Server, entity: Entity, component: Component, value: any)
132
198
  local storage = get_or_set_entity_storage(server, entity)
133
199
 
134
200
  local non_nil = if value == nil then NIL_COMPONENT_VALUE else value
135
201
 
136
202
  storage.values[component] = non_nil
137
- if not server.additions[entity] and server.track_info.entities[entity] then
203
+ if not server.additions[entity] and server.track_info.networked[entity] then
138
204
  server.masking:allocate_component_change(entity, component, non_nil)
139
205
  end
140
206
  end
141
- local function allocate_pair_value_change(server: Server, entity: Entity, relation: Entity, target: Entity, value: any)
207
+ local function allocate_pair_value_change(
208
+ server: Server,
209
+ entity: Entity,
210
+ relation: Component,
211
+ target: Entity,
212
+ value: any
213
+ )
142
214
  local storage = get_or_set_entity_storage(server, entity)
143
215
 
144
216
  local non_nil = if value == nil then NIL_COMPONENT_VALUE else value
@@ -150,20 +222,20 @@ local function allocate_pair_value_change(server: Server, entity: Entity, relati
150
222
  end
151
223
  values[target] = non_nil
152
224
 
153
- if not server.additions[entity] and server.track_info.entities[entity] then
225
+ if not server.additions[entity] and server.track_info.networked[entity] then
154
226
  server.masking:allocate_pair_value_change(entity, relation, target, non_nil)
155
227
  end
156
228
  end
157
229
 
158
- local function allocate_tag_addition(server: Server, entity: Entity, tag: Entity)
230
+ local function allocate_tag_addition(server: Server, entity: Entity, tag: Component)
159
231
  local storage = get_or_set_entity_storage(server, entity)
160
232
  storage.tags[tag] = true
161
233
 
162
- if not server.additions[entity] and server.track_info.entities[entity] then
234
+ if not server.additions[entity] and server.track_info.networked[entity] then
163
235
  server.masking:allocate_tag_addition(entity, tag)
164
236
  end
165
237
  end
166
- local function allocate_pair_addition(server: Server, entity: Entity, relation: Entity, target: Entity)
238
+ local function allocate_pair_addition(server: Server, entity: Entity, relation: Component, target: Entity)
167
239
  local storage = get_or_set_entity_storage(server, entity)
168
240
  local targets = storage.pairs[relation]
169
241
  if targets == nil then
@@ -172,47 +244,47 @@ local function allocate_pair_addition(server: Server, entity: Entity, relation:
172
244
  end
173
245
  targets[target] = true
174
246
 
175
- if not server.additions[entity] and server.track_info.entities[entity] then
247
+ if not server.additions[entity] and server.track_info.networked[entity] then
176
248
  server.masking:allocate_pair_addition(entity, relation, target)
177
249
  end
178
250
  end
179
251
 
180
- local function allocate_component_removal(server: Server, entity: Entity, component: Entity)
252
+ local function allocate_component_removal(server: Server, entity: Entity, component: Component)
181
253
  local storage = get_or_set_entity_storage(server, entity)
182
254
  storage.values[component] = nil
183
255
 
184
- if not server.additions[entity] and server.track_info.entities[entity] then
256
+ if not server.additions[entity] and server.track_info.networked[entity] then
185
257
  server.masking:allocate_component_removal(entity, component)
186
258
  end
187
259
  end
188
- local function allocate_pair_value_removal(server: Server, entity: Entity, relation: Entity, target: Entity)
260
+ local function allocate_pair_value_removal(server: Server, entity: Entity, relation: Component, target: Entity)
189
261
  local storage = get_or_set_entity_storage(server, entity)
190
262
  local values = storage.pairs_values[relation]
191
263
  if values then
192
264
  values[target] = nil
193
265
  end
194
266
 
195
- if not server.additions[entity] and server.track_info.entities[entity] then
267
+ if not server.additions[entity] and server.track_info.networked[entity] then
196
268
  server.masking:allocate_pair_value_removal(entity, relation, target)
197
269
  end
198
270
  end
199
271
 
200
- local function allocate_tag_removal(server: Server, entity: Entity, tag: Entity)
272
+ local function allocate_tag_removal(server: Server, entity: Entity, tag: Component)
201
273
  local storage = get_or_set_entity_storage(server, entity)
202
274
  storage.tags[tag] = nil
203
275
 
204
- if not server.additions[entity] and server.track_info.entities[entity] then
276
+ if not server.additions[entity] and server.track_info.networked[entity] then
205
277
  server.masking:allocate_tag_removal(entity, tag)
206
278
  end
207
279
  end
208
- local function allocate_pair_removal(server: Server, entity: Entity, relation: Entity, target: Entity)
280
+ local function allocate_pair_removal(server: Server, entity: Entity, relation: Component, target: Entity)
209
281
  local storage = get_or_set_entity_storage(server, entity)
210
282
  local targets = storage.pairs[relation]
211
283
  if targets then
212
284
  targets[target] = nil
213
285
  end
214
286
 
215
- if not server.additions[entity] and server.track_info.entities[entity] then
287
+ if not server.additions[entity] and server.track_info.networked[entity] then
216
288
  server.masking:allocate_pair_removal(entity, relation, target)
217
289
  end
218
290
  end
@@ -224,13 +296,28 @@ local function cleanup_entity(server: Server, entity: Entity)
224
296
  server.custom_ids[entity] = nil
225
297
  server.additions[entity] = nil
226
298
  server.masking:cleanup_entity(entity)
299
+
300
+ local track_info = server.track_info.entities[entity]
301
+ if track_info then
302
+ for component in track_info do
303
+ local track_component = server.track_info.components[component]
304
+ if track_component then
305
+ track_component[entity] = nil
306
+ end
307
+ end
308
+ server.track_info.entities[entity] = nil
309
+ end
227
310
  end
228
311
 
229
- local function track_component(server: Server, component: Entity<any>)
312
+ local function track_component(server: Server, component: Component)
230
313
  local world = server.world
231
314
  local hooks = server.hooks
232
315
 
233
- local info = {}
316
+ if server.track_info.components[component] then
317
+ error(`attemped to track a component twice: {utils.logcomponent(server.world, component)}`)
318
+ end
319
+
320
+ local info = {} :: Map<Entity, number>
234
321
  server.track_info.components[component] = info
235
322
 
236
323
  local function hook(unhook: () -> ())
@@ -320,13 +407,16 @@ local function track_entity_component(server: Server, entity: Entity, component:
320
407
  end
321
408
 
322
409
  info[entity] = TRACK_TYPES.component
410
+ add_entity_tracked(server, entity, component, TRACK_TYPES.component)
323
411
 
324
412
  return COMPONENT_TYPES.component
325
413
  else
326
414
  if world:has(entity, component) then
327
415
  entity_storage.tags[component] = true
328
416
  end
417
+
329
418
  info[entity] = TRACK_TYPES.tag
419
+ add_entity_tracked(server, entity, component, TRACK_TYPES.tag)
330
420
 
331
421
  return COMPONENT_TYPES.tag
332
422
  end
@@ -354,8 +444,11 @@ local function track_entity_pair(server: Server, entity: Entity, relation: Entit
354
444
  local value = world:get(entity, jecs.pair(relation, target))
355
445
  targets[target] = if value == nil then NIL_COMPONENT_VALUE else value :: any
356
446
  end
447
+
357
448
  entity_storage.pairs_values[relation] = targets
358
449
  info[entity] = TRACK_TYPES.pair_value
450
+ add_entity_tracked(server, entity, relation, TRACK_TYPES.pair_value)
451
+
359
452
  return COMPONENT_TYPES.pair_value
360
453
  else
361
454
  local targets = {} :: Set<Entity>
@@ -369,8 +462,11 @@ local function track_entity_pair(server: Server, entity: Entity, relation: Entit
369
462
  index += 1
370
463
  targets[target] = true
371
464
  end
465
+
372
466
  entity_storage.pairs[relation] = targets
373
467
  info[entity] = TRACK_TYPES.pair
468
+ add_entity_tracked(server, entity, relation, TRACK_TYPES.pair)
469
+
374
470
  return COMPONENT_TYPES.pair
375
471
  end
376
472
  end
@@ -389,6 +485,13 @@ local function untrack_entity_component(server: Server, entity: Entity, componen
389
485
  storage.tags[component] = nil
390
486
  end
391
487
 
488
+ local entity_tracked = server.track_info.entities[entity]
489
+ if entity_tracked then
490
+ entity_tracked[component] = nil
491
+ end
492
+
493
+ remove_entity_tracked(server, entity, component)
494
+
392
495
  return listen_type
393
496
  end
394
497
 
@@ -405,11 +508,18 @@ local function untrack_entity_pair(server: Server, entity: Entity, relation: Ent
405
508
  storage.pairs[relation] = nil
406
509
  storage.pairs_values[relation] = nil
407
510
  end
511
+
512
+ local entity_tracked = server.track_info.entities[entity]
513
+ if entity_tracked then
514
+ entity_tracked[relation] = nil
515
+ end
516
+
517
+ remove_entity_tracked(server, entity, relation)
408
518
  return listen_type
409
519
  end
410
520
 
411
- local function encode_component(server: Server, component: Entity): number
412
- local encoded = server.shared.ids[component]
521
+ function server_replicator.encode_component(server: Server, component: Entity): number
522
+ local encoded = server.shared.components.members[component]
413
523
  if not encoded then
414
524
  utils.logerror(`attempted to encode a non-shared component `, utils.logcomponent(server.world, component))
415
525
  return 0
@@ -417,8 +527,8 @@ local function encode_component(server: Server, component: Entity): number
417
527
  return encoded
418
528
  end
419
529
 
420
- local function decode_component(server: Server, encoded: number): Entity
421
- local component = server.shared.components[encoded]
530
+ function server_replicator.decode_component(server: Server, encoded: number): Entity
531
+ local component = server.shared.components.indexes[encoded]
422
532
  if not component then
423
533
  print("NON SHARED COMPONENTS", encoded, server.shared.components)
424
534
  error "attemped to decode a non shared component"
@@ -426,16 +536,23 @@ local function decode_component(server: Server, encoded: number): Entity
426
536
  return component
427
537
  end
428
538
 
429
- local function write_component_id(server: Server, c: Cursor, component: Entity)
430
- local encoded = server.shared.ids[component]
539
+ function server_replicator.write_component_id(server: Server, c: Cursor, component: Entity)
540
+ local shared_componens = server.shared.components
541
+ local encoded = shared_componens.members[component]
431
542
  if not encoded then
432
543
  utils.logerror(`attempted to replicate a non-shared component `, utils.logcomponent(server.world, component))
433
544
  return
434
545
  end
435
- cursor.writeu8(c, encoded)
546
+ cursor.write_span(c, encoded, #shared_componens.keys)
436
547
  end
437
548
 
438
- local function write_component_value(server: Server, c: Cursor, component: Entity, value: any, variants: { any })
549
+ function server_replicator.write_component_value(
550
+ server: Server,
551
+ c: Cursor,
552
+ component: Entity,
553
+ value: any,
554
+ variants: { any }
555
+ )
439
556
  local serdes = server.shared.serdes[component]
440
557
  if serdes then
441
558
  local output, serdes_variants = serdes.serialize(if value == NIL_COMPONENT_VALUE then nil else value)
@@ -459,7 +576,7 @@ local function write_component_value(server: Server, c: Cursor, component: Entit
459
576
  )
460
577
  end
461
578
 
462
- local bytespan = server.shared.bytespan[component]
579
+ local bytespan = serdes.bytespan
463
580
  cursor.write_buffer(c, output)
464
581
  if bytespan then
465
582
  if bytespan ~= buffer.len(output) then
@@ -483,23 +600,29 @@ local function write_component_value(server: Server, c: Cursor, component: Entit
483
600
  end
484
601
  end
485
602
 
486
- local function write_component(server: Server, c: Cursor, component: Entity, value: any, variants: { any })
487
- write_component_value(server, c, component, value, variants)
488
- write_component_id(server, c, component)
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)
489
606
  end
490
607
 
491
- local function write_entity_id(server: Server, c: Cursor, entity: Entity, variants: { any })
608
+ function server_replicator.write_entity_id(server: Server, c: Cursor, entity: Entity)
492
609
  local custom = server.custom_ids[entity]
493
610
  local global_id = server.global_ids[entity]
494
611
 
495
612
  if global_id then
496
613
  cursor.writeu8(c, global_id + GLOBAL_ID_OFFSET)
497
614
  elseif custom then
498
- local value = server.world:get(entity, custom)
499
- write_component(server, c, custom, value, variants)
500
- cursor.writeu8(c, ENTITY_ID_TYPES.custom)
615
+ if type(custom) == "number" then
616
+ server_replicator.write_component_id(server, c, (custom :: any) :: Entity)
617
+ cursor.writeu40(c, entity :: any)
618
+ cursor.writeu8(c, ENTITY_ID_TYPES.custom_id)
619
+ else
620
+ cursor.writeu8(c, server.shared.custom_ids.members[custom :: CustomId])
621
+ cursor.writeu40(c, entity :: any)
622
+ cursor.writeu8(c, ENTITY_ID_TYPES.custom_handler)
623
+ end
501
624
  else
502
- local shared_id = server.shared.ids[entity]
625
+ local shared_id = server.shared.components.members[entity]
503
626
  if shared_id then
504
627
  cursor.writeu8(c, shared_id)
505
628
  cursor.writeu8(c, ENTITY_ID_TYPES.shared)
@@ -510,25 +633,19 @@ local function write_entity_id(server: Server, c: Cursor, entity: Entity, varian
510
633
  end
511
634
  end
512
635
 
513
- local function write_entity_relations(
514
- server: Server,
515
- storage: EntityStorage,
516
- c: Cursor,
517
- relation: Entity,
518
- variants: { any }
519
- )
636
+ function server_replicator.write_entity_relations(server: Server, storage: EntityStorage, c: Cursor, relation: Entity)
520
637
  local targets = storage.pairs[relation]
521
638
  local total_targets = 0
522
639
 
523
640
  for target in targets do
524
- write_entity_id(server, c, target, variants)
641
+ server_replicator.write_entity_id(server, c, target)
525
642
  total_targets += 1
526
643
  end
527
644
  cursor.write_vlq(c, total_targets)
528
- write_component_id(server, c, relation)
645
+ server_replicator.write_component_id(server, c, relation)
529
646
  end
530
647
 
531
- local function write_entity_relations_values(
648
+ function server_replicator.write_entity_relations_values(
532
649
  server: Server,
533
650
  storage: EntityStorage,
534
651
  c: Cursor,
@@ -539,15 +656,15 @@ local function write_entity_relations_values(
539
656
  local total_targets = 0
540
657
 
541
658
  for target, value in targets do
542
- write_entity_id(server, c, target, variants)
543
- write_component_value(server, c, relation, value, variants)
659
+ server_replicator.write_entity_id(server, c, target)
660
+ server_replicator.write_component_value(server, c, relation, value, variants)
544
661
  total_targets += 1
545
662
  end
546
663
  cursor.write_vlq(c, total_targets)
547
- write_component_id(server, c, relation)
664
+ server_replicator.write_component_id(server, c, relation)
548
665
  end
549
666
 
550
- local function write_entity(
667
+ function server_replicator.write_entity(
551
668
  server: Server,
552
669
  c: Cursor,
553
670
  entity: Entity,
@@ -558,14 +675,14 @@ local function write_entity(
558
675
 
559
676
  local all_pairs_values = 0
560
677
  for relation in active.components[COMPONENT_TYPES.pair_value] do
561
- write_entity_relations_values(server, storage, c, relation, variants)
678
+ server_replicator.write_entity_relations_values(server, storage, c, relation, variants)
562
679
  all_pairs_values += 1
563
680
  end
564
681
  cursor.write_vlq(c, all_pairs_values)
565
682
 
566
683
  local all_pairs = 0
567
684
  for relation in active.components[COMPONENT_TYPES.pair] do
568
- write_entity_relations(server, storage, c, relation, variants)
685
+ server_replicator.write_entity_relations(server, storage, c, relation)
569
686
  all_pairs += 1
570
687
  end
571
688
  cursor.write_vlq(c, all_pairs)
@@ -577,7 +694,7 @@ local function write_entity(
577
694
  continue
578
695
  end
579
696
 
580
- write_component(server, c, component, value, variants)
697
+ server_replicator.write_component(server, c, component, value, variants)
581
698
  components += 1
582
699
  end
583
700
  cursor.write_vlq(c, components)
@@ -586,18 +703,18 @@ local function write_entity(
586
703
  for tag in active.components[COMPONENT_TYPES.tag] do
587
704
  local has_tag = storage.tags[tag]
588
705
  if has_tag then
589
- write_component_id(server, c, tag)
706
+ server_replicator.write_component_id(server, c, tag)
590
707
  tags += 1
591
708
  end
592
709
  end
593
710
  cursor.write_vlq(c, tags)
594
- write_entity_id(server, c, entity, variants)
711
+ server_replicator.write_entity_id(server, c, entity)
595
712
  end
596
713
 
597
- local function resolve_dirty(server: Server)
598
- if server.is_dirty then
599
- server.shared = utils.create_shared_lookup(server.world, server.components)
600
- server.is_dirty = false :: true -- wtf
714
+ function server_replicator.resolve_dirty(server: Server)
715
+ if server.is_shared_dirty then
716
+ server.shared = utils.resolved_shared(server.world, server.components, server.registered_custom_ids)
717
+ server.is_shared_dirty = false
601
718
  end
602
719
  end
603
720
 
@@ -619,6 +736,10 @@ local function append_packet(
619
736
  )
620
737
  local len = buffer.len(output)
621
738
  for _, member in members do
739
+ if not utils.is_client_valid(member) then
740
+ continue
741
+ end
742
+
622
743
  local member_packets = packets[member]
623
744
 
624
745
  if member_packets then
@@ -665,6 +786,12 @@ local function create_packet_iterator(packets: { [Player]: MemberPackets }, id:
665
786
  local iterated: Player? = nil
666
787
  local function iterator()
667
788
  local player, data = next(packets, iterated)
789
+ while not utils.is_client_valid(player) do
790
+ if not player and not data then
791
+ break
792
+ end
793
+ player, data = next(packets, iterated)
794
+ end
668
795
  if not player then
669
796
  return nil :: any
670
797
  end
@@ -679,6 +806,10 @@ end
679
806
  local function create_unreliable_packet_iterator(packets: { [Player]: MemberPackets })
680
807
  return coroutine.wrap(function()
681
808
  for player, data in packets do
809
+ if not utils.is_client_valid(player) then
810
+ continue
811
+ end
812
+
682
813
  table.sort(data.packets, function(a, b)
683
814
  return buffer.len(a.buffer) < buffer.len(b.buffer)
684
815
  end)
@@ -714,8 +845,8 @@ local function create_unreliable_packet_iterator(packets: { [Player]: MemberPack
714
845
  end) :: PacketIterator
715
846
  end
716
847
 
717
- local function get_full(server: Server, client: Player): (buffer, { { any } })
718
- resolve_dirty(server)
848
+ function server_replicator.get_full(server: Server, client: Player): (buffer, { { any } })
849
+ server_replicator.resolve_dirty(server)
719
850
  local index = server.masking.client_indexes[client]
720
851
  if index == nil then
721
852
  utils.logerror "attempted to replicate for a non registered client"
@@ -726,6 +857,9 @@ local function get_full(server: Server, client: Player): (buffer, { { any } })
726
857
 
727
858
  -- maybe edges to quickly find all relevant storages improves performance?
728
859
  for _, storage in server.masking.storages do
860
+ if storage.active_count == 0 then
861
+ continue
862
+ end
729
863
  if not storage.mask.bitmask:get(index) then
730
864
  continue
731
865
  end
@@ -734,7 +868,7 @@ local function get_full(server: Server, client: Player): (buffer, { { any } })
734
868
 
735
869
  local total_entities = 0
736
870
  for entity, active in storage.active do
737
- write_entity(server, c, entity, active, variants)
871
+ server_replicator.write_entity(server, c, entity, active, variants)
738
872
  total_entities += 1
739
873
  end
740
874
  cursor.write_vlq(c, total_entities)
@@ -759,20 +893,21 @@ local function write_vlq_bitmask(c: Cursor, value: number, mask: number, bit: nu
759
893
  end
760
894
  end
761
895
 
762
- local function collect_updates(server: Server)
763
- resolve_dirty(server)
896
+ function server_replicator.collect_updates(server: Server)
897
+ server_replicator.resolve_dirty(server)
764
898
  local packets: { [Player]: MemberPackets } = {}
765
899
 
766
900
  for _, storage in server.masking.storages do
767
901
  local c = cursor.new()
768
902
 
769
903
  local variants = {}
904
+
770
905
  local storage_mask = 0
771
906
 
772
907
  local total_deleted = 0
773
908
  local entity_deletions = storage.deletions.entities
774
909
  for entity in entity_deletions do
775
- write_entity_id(server, c, entity, variants)
910
+ server_replicator.write_entity_id(server, c, entity)
776
911
  total_deleted += 1
777
912
  end
778
913
  table.clear(entity_deletions)
@@ -782,28 +917,29 @@ local function collect_updates(server: Server)
782
917
  local component_deletions = storage.deletions.components
783
918
  for entity, deleted in component_deletions do
784
919
  local total_pairs = 0
920
+
785
921
  for relation in deleted[COMPONENT_TYPES.pair_value] do
786
- write_component_id(server, c, relation)
922
+ server_replicator.write_component_id(server, c, relation)
787
923
  total_pairs += 1
788
924
  end
789
925
  for relation in deleted[COMPONENT_TYPES.pair] do
790
- write_component_id(server, c, relation)
926
+ server_replicator.write_component_id(server, c, relation)
791
927
  total_pairs += 1
792
928
  end
793
929
  cursor.write_vlq(c, total_pairs)
794
930
 
795
931
  local total_removed = 0
796
932
  for component in deleted[COMPONENT_TYPES.component] do
797
- write_component_id(server, c, component)
933
+ server_replicator.write_component_id(server, c, component)
798
934
  total_removed += 1
799
935
  end
800
936
  for tag in deleted[COMPONENT_TYPES.tag] do
801
- write_component_id(server, c, tag)
937
+ server_replicator.write_component_id(server, c, tag)
802
938
  total_removed += 1
803
939
  end
804
940
  cursor.write_vlq(c, total_removed)
805
941
 
806
- write_entity_id(server, c, entity, variants)
942
+ server_replicator.write_entity_id(server, c, entity)
807
943
  total_component_deleted += 1
808
944
  end
809
945
  table.clear(component_deletions)
@@ -819,12 +955,12 @@ local function collect_updates(server: Server)
819
955
  local total_targets = 0
820
956
 
821
957
  for target, value in targets do
822
- write_entity_id(server, c, target, variants)
823
- write_component_value(server, c, relation, value, variants)
958
+ server_replicator.write_entity_id(server, c, target)
959
+ server_replicator.write_component_value(server, c, relation, value, variants)
824
960
  total_targets += 1
825
961
  end
826
962
  cursor.write_vlq(c, total_targets)
827
- write_component_id(server, c, relation)
963
+ server_replicator.write_component_id(server, c, relation)
828
964
  total_pairs_values += 1
829
965
  end
830
966
  changed_mask = write_vlq_bitmask(c, total_pairs_values, changed_mask, 5)
@@ -834,11 +970,11 @@ local function collect_updates(server: Server)
834
970
  local total_targets = 0
835
971
 
836
972
  for target in targets do
837
- write_entity_id(server, c, target, variants)
973
+ server_replicator.write_entity_id(server, c, target)
838
974
  total_targets += 1
839
975
  end
840
976
  cursor.write_vlq(c, total_targets)
841
- write_component_id(server, c, relation)
977
+ server_replicator.write_component_id(server, c, relation)
842
978
  total_pairs_values_removed += 1
843
979
  end
844
980
  changed_mask = write_vlq_bitmask(c, total_pairs_values_removed, changed_mask, 4)
@@ -848,7 +984,7 @@ local function collect_updates(server: Server)
848
984
  local total_targets = 0
849
985
 
850
986
  for target, added in targets do
851
- write_entity_id(server, c, target, variants)
987
+ server_replicator.write_entity_id(server, c, target)
852
988
  if added then
853
989
  cursor.writei8(c, 1)
854
990
  else
@@ -857,35 +993,35 @@ local function collect_updates(server: Server)
857
993
  total_targets += 1
858
994
  end
859
995
  cursor.write_vlq(c, total_targets)
860
- write_component_id(server, c, relation)
996
+ server_replicator.write_component_id(server, c, relation)
861
997
  total_pairs += 1
862
998
  end
863
999
  changed_mask = write_vlq_bitmask(c, total_pairs, changed_mask, 3)
864
1000
 
865
1001
  local total_removed = 0
866
1002
  for component in changes.removed do
867
- write_component_id(server, c, component)
1003
+ server_replicator.write_component_id(server, c, component)
868
1004
  total_removed += 1
869
1005
  end
870
1006
  changed_mask = write_vlq_bitmask(c, total_removed, changed_mask, 2)
871
1007
 
872
1008
  local total_components = 0
873
1009
  for component, value in changes.component do
874
- write_component(server, c, component, value, variants)
1010
+ server_replicator.write_component(server, c, component, value, variants)
875
1011
  total_components += 1
876
1012
  end
877
1013
  changed_mask = write_vlq_bitmask(c, total_components, changed_mask, 1)
878
1014
 
879
1015
  local total_tagged = 0
880
1016
  for tag in changes.tagged do
881
- write_component_id(server, c, tag)
1017
+ server_replicator.write_component_id(server, c, tag)
882
1018
  total_tagged += 1
883
1019
  end
884
1020
  changed_mask = write_vlq_bitmask(c, total_tagged, changed_mask, 0)
885
1021
 
886
1022
  if changed_mask ~= 0 then
887
1023
  cursor.writeu8(c, changed_mask)
888
- write_entity_id(server, c, entity, variants)
1024
+ server_replicator.write_entity_id(server, c, entity)
889
1025
  changed += 1
890
1026
  end
891
1027
  end
@@ -899,14 +1035,14 @@ local function collect_updates(server: Server)
899
1035
 
900
1036
  local total_pairs_values = 0
901
1037
  for relation in components[COMPONENT_TYPES.pair_value] do
902
- write_entity_relations_values(server, entity_storage, c, relation, variants)
1038
+ server_replicator.write_entity_relations_values(server, entity_storage, c, relation, variants)
903
1039
  total_pairs_values += 1
904
1040
  end
905
1041
  added_mask = write_vlq_bitmask(c, total_pairs_values, added_mask, 3)
906
1042
 
907
1043
  local total_pairs = 0
908
1044
  for relation in components[COMPONENT_TYPES.pair] do
909
- write_entity_relations(server, entity_storage, c, relation, variants)
1045
+ server_replicator.write_entity_relations(server, entity_storage, c, relation)
910
1046
  total_pairs += 1
911
1047
  end
912
1048
  added_mask = write_vlq_bitmask(c, total_pairs, added_mask, 2)
@@ -917,7 +1053,7 @@ local function collect_updates(server: Server)
917
1053
  if value == nil then
918
1054
  continue
919
1055
  end
920
- write_component(server, c, component, value, variants)
1056
+ server_replicator.write_component(server, c, component, value, variants)
921
1057
  total_components += 1
922
1058
  end
923
1059
  added_mask = write_vlq_bitmask(c, total_components, added_mask, 1)
@@ -926,7 +1062,7 @@ local function collect_updates(server: Server)
926
1062
  for component in components[COMPONENT_TYPES.tag] do
927
1063
  local has_tag = entity_storage.tags[component]
928
1064
  if has_tag then
929
- write_component_id(server, c, component)
1065
+ server_replicator.write_component_id(server, c, component)
930
1066
  total_tags += 1
931
1067
  end
932
1068
  end
@@ -934,7 +1070,7 @@ local function collect_updates(server: Server)
934
1070
 
935
1071
  if added_mask ~= 0 then
936
1072
  cursor.writeu8(c, added_mask)
937
- write_entity_id(server, c, entity, variants)
1073
+ server_replicator.write_entity_id(server, c, entity)
938
1074
  total_components_added += 1
939
1075
  end
940
1076
  end
@@ -948,7 +1084,7 @@ local function collect_updates(server: Server)
948
1084
  continue
949
1085
  end
950
1086
 
951
- write_entity(server, c, entity, active, variants)
1087
+ server_replicator.write_entity(server, c, entity, active, variants)
952
1088
  total_added += 1
953
1089
  end
954
1090
  table.clear(storage_changes.added)
@@ -964,26 +1100,32 @@ local function collect_updates(server: Server)
964
1100
  return create_packet_iterator(packets, PACKET_TYPES.reliable)
965
1101
  end
966
1102
 
967
- local function collect_unreliable(server: Server)
968
- resolve_dirty(server)
1103
+ function server_replicator.collect_unreliable(server: Server)
1104
+ server_replicator.resolve_dirty(server)
969
1105
  local world = server.world
970
1106
  local packets: { [Player]: MemberPackets } = {}
971
1107
 
972
1108
  for _, mask_storage in server.masking.storages do
1109
+ if mask_storage.active_count == 0 then
1110
+ continue
1111
+ end
973
1112
  local active = mask_storage.active
974
1113
 
975
1114
  local c = cursor.new()
976
1115
  local variants = {} :: { { any } }
1116
+ local custom_ids: Set<Entity> = {}
977
1117
  local total_entities = 0
978
1118
 
979
1119
  local checkpoint_offset = 0
980
1120
  local checkpoint_variants_count = 0
981
1121
  local checkpoint_total_entities = 0
1122
+ local checkpoint_entity: Entity? = nil
982
1123
 
983
- local function create_checkpoint()
1124
+ local function create_checkpoint(entity: Entity)
984
1125
  checkpoint_offset = c.offset
985
1126
  checkpoint_variants_count = #variants
986
1127
  checkpoint_total_entities = total_entities
1128
+ checkpoint_entity = entity
987
1129
  end
988
1130
 
989
1131
  local function rollback_checkpoint()
@@ -996,6 +1138,14 @@ local function collect_unreliable(server: Server)
996
1138
  for _ = #variants, checkpoint_variants_count + 1, -1 do
997
1139
  table.insert(new_variants, 1, table.remove(variants))
998
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
1146
+ end
1147
+ custom_ids = new_custom_ids
1148
+
999
1149
  variants = new_variants
1000
1150
  total_entities = total_entities - checkpoint_total_entities
1001
1151
  end
@@ -1011,7 +1161,7 @@ local function collect_unreliable(server: Server)
1011
1161
  end
1012
1162
 
1013
1163
  for entity, actives in active do
1014
- create_checkpoint()
1164
+ create_checkpoint(entity)
1015
1165
 
1016
1166
  local total_unreliable = 0
1017
1167
  for component in actives.components[COMPONENT_TYPES.unreliable] do
@@ -1020,7 +1170,7 @@ local function collect_unreliable(server: Server)
1020
1170
  continue
1021
1171
  end
1022
1172
 
1023
- write_component(server, c, component, value, variants)
1173
+ server_replicator.write_component(server, c, component, value, variants)
1024
1174
  total_unreliable += 1
1025
1175
  end
1026
1176
 
@@ -1029,11 +1179,12 @@ local function collect_unreliable(server: Server)
1029
1179
  end
1030
1180
  total_entities += 1
1031
1181
  cursor.write_vlq(c, total_unreliable)
1032
- write_entity_id(server, c, entity, variants)
1182
+ server_replicator.write_entity_id(server, c, entity)
1033
1183
 
1034
1184
  if c.offset > MAX_PACKET_SIZE then
1035
1185
  local commit_cursor = c
1036
1186
  local commit_variants = variants
1187
+
1037
1188
  rollback_checkpoint()
1038
1189
  commit_checkpoint(commit_cursor, commit_variants, checkpoint_total_entities)
1039
1190
  end
@@ -1044,6 +1195,188 @@ local function collect_unreliable(server: Server)
1044
1195
  return create_unreliable_packet_iterator(packets)
1045
1196
  end
1046
1197
 
1198
+ function server_replicator.start_networked(server: Server, entity: Entity, filter: AnyFilter?)
1199
+ local masking = server.masking
1200
+
1201
+ masking:unregister_stop_entity(entity)
1202
+ masking:start_entity(entity, filter)
1203
+ masking:propagate_entity_addition(entity)
1204
+
1205
+ server.additions[entity] = true
1206
+ server.track_info.networked[entity] = true
1207
+ track_entity_lifetime(server, entity)
1208
+ end
1209
+ function server_replicator.start_reliable(server: Server, entity: Entity, component: Component, filter: AnyFilter?)
1210
+ local masking = server.masking
1211
+
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)
1215
+ if server.additions[entity] then
1216
+ masking:allocate_entity_addition(entity, component, component_type)
1217
+ elseif server.track_info.networked[entity] then
1218
+ masking:register_component_addition(entity, component, component_type)
1219
+ end
1220
+ end
1221
+
1222
+ function server_replicator.start_unreliable(server: Server, entity: Entity, component: Component, filter: AnyFilter?)
1223
+ local masking = server.masking
1224
+
1225
+ masking:unregister_stop_component(entity, component, COMPONENT_TYPES.unreliable)
1226
+ masking:start_component(entity, component, COMPONENT_TYPES.unreliable, filter)
1227
+ if server.additions[entity] then
1228
+ masking:allocate_entity_addition(entity, component, COMPONENT_TYPES.unreliable)
1229
+ end
1230
+ end
1231
+
1232
+ function server_replicator.start_pair(server: Server, entity: Entity, relation: Component, filter: AnyFilter?)
1233
+ local masking = server.masking
1234
+
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)
1238
+ if server.additions[entity] then
1239
+ masking:allocate_entity_addition(entity, relation, component_type)
1240
+ elseif server.track_info.networked[entity] then
1241
+ masking:register_component_addition(entity, relation, component_type)
1242
+ end
1243
+ end
1244
+
1245
+ function server_replicator.change_networked(server: Server, entity: Entity, filter: AnyFilter?)
1246
+ local masking = server.masking
1247
+ masking:set_entity(entity, filter)
1248
+ end
1249
+ function server_replicator.change_reliable(server: Server, entity: Entity, component: Component, filter: AnyFilter?)
1250
+ local world = server.world
1251
+ local masking = server.masking
1252
+
1253
+ if world:has(component, ECS_COMPONENT) then
1254
+ masking:set_component(entity, component, COMPONENT_TYPES.component, filter)
1255
+ else
1256
+ masking:set_component(entity, component, COMPONENT_TYPES.tag, filter)
1257
+ end
1258
+ end
1259
+ function server_replicator.change_unreliable(server: Server, entity: Entity, component: Component, filter: AnyFilter?)
1260
+ local masking = server.masking
1261
+ masking:set_component(entity, component, COMPONENT_TYPES.unreliable, filter)
1262
+ end
1263
+ function server_replicator.change_pair(server: Server, entity: Entity, relation: Component, filter: AnyFilter?)
1264
+ local world = server.world
1265
+ local masking = server.masking
1266
+
1267
+ if world:has(relation, ECS_COMPONENT) then
1268
+ masking:set_component(entity, relation, COMPONENT_TYPES.pair_value, filter)
1269
+ else
1270
+ masking:set_component(entity, relation, COMPONENT_TYPES.pair, filter)
1271
+ end
1272
+ end
1273
+
1274
+ function server_replicator.stop_networked(server: Server, entity: Entity)
1275
+ if not server.track_info.networked[entity] then
1276
+ return
1277
+ end
1278
+
1279
+ local masking = server.masking
1280
+ masking:register_stop_entity(entity)
1281
+ masking:stop_entity(entity)
1282
+
1283
+ server.additions[entity] = nil
1284
+ server.track_info.networked[entity] = nil
1285
+ end
1286
+ function server_replicator.stop_reliable(server: Server, entity: Entity, component: Component)
1287
+ local masking = server.masking
1288
+ if not server.track_info.entities[entity] then
1289
+ return
1290
+ end
1291
+
1292
+ local component_type = untrack_entity_component(server, entity, component)
1293
+ if not component_type then
1294
+ return
1295
+ end
1296
+
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)
1302
+ end
1303
+ function server_replicator.stop_unreliable(server: Server, entity: Entity, component: Component)
1304
+ local masking = server.masking
1305
+ if not server.track_info.entities[entity] then
1306
+ return
1307
+ end
1308
+
1309
+ local component_type = untrack_entity_component(server, entity, component)
1310
+ if not component_type then
1311
+ return
1312
+ end
1313
+
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)
1318
+ end
1319
+ function server_replicator.stop_pair(server: Server, entity: Entity, relation: Component)
1320
+ local masking = server.masking
1321
+ if not server.track_info.entities[entity] then
1322
+ return
1323
+ end
1324
+
1325
+ local component_type = untrack_entity_pair(server, entity, relation)
1326
+ if not component_type then
1327
+ return
1328
+ end
1329
+
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)
1333
+ end
1334
+ masking:stop_component(entity, relation, component_type)
1335
+ end
1336
+
1337
+ function server_replicator.set_networked(server: Server, entity: Entity, filter: AnyFilter?)
1338
+ if server.track_info.networked[entity] then
1339
+ server_replicator.change_networked(server, entity, filter)
1340
+ else
1341
+ server_replicator.start_networked(server, entity, filter)
1342
+ end
1343
+ end
1344
+ function server_replicator.set_reliable(server: Server, entity: Entity, component: Component, filter: AnyFilter?)
1345
+ local entity_tracked = server.track_info.entities[entity]
1346
+ if entity_tracked and entity_tracked[component] then
1347
+ server_replicator.change_reliable(server, entity, component, filter)
1348
+ else
1349
+ server_replicator.start_reliable(server, entity, component, filter)
1350
+ end
1351
+ end
1352
+ function server_replicator.set_unreliable(server: Server, entity: Entity, component: Component, filter: AnyFilter?)
1353
+ local entity_tracked = server.track_info.entities[entity]
1354
+ if entity_tracked and entity_tracked[component] then
1355
+ server_replicator.change_unreliable(server, entity, component, filter)
1356
+ else
1357
+ server_replicator.start_unreliable(server, entity, component, filter)
1358
+ end
1359
+ end
1360
+ function server_replicator.set_pair(server: Server, entity: Entity, relation: Component, filter: AnyFilter?)
1361
+ 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)
1364
+ else
1365
+ server_replicator.start_pair(server, entity, relation, filter)
1366
+ end
1367
+ end
1368
+ function server_replicator.set_custom(server: Server, entity: Entity, handler: Component | CustomId)
1369
+ if server.custom_ids[entity] then
1370
+ utils.logwarn("attempted to register a custom_id twice for the same entity", debug.traceback())
1371
+ return
1372
+ end
1373
+ server.custom_ids[entity] = handler
1374
+ end
1375
+
1376
+ function server_replicator.remove_custom(server: Server, entity: Entity)
1377
+ server.custom_ids[entity] = nil
1378
+ end
1379
+
1047
1380
  local function check_created(server: Server)
1048
1381
  if server.inited == true then
1049
1382
  warn "attempted to init a server twice"
@@ -1056,13 +1389,37 @@ local function check_created(server: Server)
1056
1389
  return true
1057
1390
  end
1058
1391
 
1059
- function init(server: Server, _world: World?)
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
+ function server_replicator.init(server: Server, wrd: World?)
1060
1417
  if not check_created(server) then
1061
1418
  return
1062
1419
  end
1063
1420
  server.inited = true :: any
1064
1421
 
1065
- local world = _world or server.world
1422
+ local world = wrd or server.world
1066
1423
  server.world = world
1067
1424
 
1068
1425
  if not world then
@@ -1077,159 +1434,59 @@ function init(server: Server, _world: World?)
1077
1434
  server.hooks = hooks
1078
1435
 
1079
1436
  local components = server.components
1080
- local masking = server.masking
1081
-
1082
- server.shared = utils.create_shared_lookup(world, components)
1437
+ server.shared = utils.resolved_shared(world, components, server.registered_custom_ids)
1083
1438
 
1084
1439
  local function hook(unhook: () -> ())
1085
1440
  table.insert(server.hooked, unhook)
1086
1441
  end
1087
1442
 
1088
- hook(hooks.added(world, components.networked, function(entity, _id, filter)
1089
- masking:unregister_stop_entity(entity)
1090
- masking:start_entity(entity, filter)
1091
- masking:propagate_entity_addition(entity)
1092
-
1093
- server.additions[entity] = true
1094
- server.track_info.entities[entity] = true
1095
- track_entity_lifetime(server, entity)
1443
+ hook(hooks.added(world, components.networked, function(entity, _, filter)
1444
+ server_replicator.start_networked(server, entity, filter)
1096
1445
  end))
1097
- hook(hooks.changed(world, components.networked, function(entity, _id, filter)
1098
- masking:set_entity(entity, filter)
1446
+ hook(hooks.changed(world, components.networked, function(entity, _, filter)
1447
+ server_replicator.change_networked(server, entity, filter)
1099
1448
  end))
1100
1449
  hook(hooks.removed(world, components.networked, function(entity)
1101
- masking:register_stop_entity(entity)
1102
- masking:stop_entity(entity)
1103
-
1104
- if server.pending_cleanups[entity] then
1105
- server.pending_cleanups[entity] = nil
1106
- cleanup_entity(server, entity)
1107
- end
1108
-
1109
- server.additions[entity] = nil
1110
- server.track_info.entities[entity] = nil
1450
+ server_replicator.stop_networked(server, entity)
1111
1451
  end))
1112
1452
 
1113
1453
  hook(hooks.added(world, components.reliable, function(entity, id, filter)
1114
- if not IS_PAIR(id) then
1115
- utils.logerror "reliable should be used with a pair relationship"
1116
- end
1117
1454
  local component = PAIR_SECOND(world, id)
1118
-
1119
- local component_type = track_entity_component(server :: Server, entity, component)
1120
- masking:unregister_stop_component(entity, component, component_type)
1121
- masking:start_component(entity, component, component_type, filter)
1122
- if server.additions[entity] then
1123
- masking:allocate_entity_addition(entity, component, component_type)
1124
- elseif server.track_info.entities[entity] then
1125
- masking:register_component_addition(entity, component, component_type)
1126
- end
1455
+ server_replicator.start_reliable(server, entity, component, filter)
1127
1456
  end))
1128
1457
  hook(hooks.changed(world, components.reliable, function(entity, id, filter)
1129
- if not IS_PAIR(id) then
1130
- utils.logerror "reliable should be used with a pair relationship"
1131
- end
1132
1458
  local component = PAIR_SECOND(world, id)
1133
-
1134
- if world:has(component, ECS_COMPONENT) then
1135
- masking:set_component(entity, component, COMPONENT_TYPES.component, filter)
1136
- else
1137
- masking:set_component(entity, component, COMPONENT_TYPES.tag, filter)
1138
- end
1459
+ server_replicator.change_reliable(server, entity, component, filter)
1139
1460
  end))
1140
1461
  hook(hooks.removed(world, components.reliable, function(entity, id)
1141
- if not IS_PAIR(id) then
1142
- utils.logerror "reliable should be used with a pair relationship"
1143
- end
1144
- if not server.track_info.entities[entity] then
1145
- return
1146
- end
1147
-
1148
1462
  local component = PAIR_SECOND(world, id)
1149
- local component_type = untrack_entity_component(server, entity, component)
1150
- if not component_type then
1151
- return
1152
- end
1153
- masking:unregister_component_addition(entity, component, component_type)
1154
- masking:register_stop_component(entity, component, component_type)
1155
- masking:stop_component(entity, component, component_type)
1463
+ server_replicator.stop_reliable(server, entity, component)
1156
1464
  end))
1157
1465
 
1158
1466
  hook(hooks.added(world, components.pair, function(entity, id, filter)
1159
- if not IS_PAIR(id) then
1160
- utils.logerror "pair should be used with a relationship"
1161
- end
1162
1467
  local relation = PAIR_SECOND(world, id)
1163
-
1164
- local component_type = track_entity_pair(server, entity, relation)
1165
- masking:unregister_stop_component(entity, relation, component_type)
1166
- masking:start_component(entity, relation, component_type, filter)
1167
- if server.additions[entity] then
1168
- masking:allocate_entity_addition(entity, relation, component_type)
1169
- elseif server.track_info.entities[entity] then
1170
- masking:register_component_addition(entity, relation, component_type)
1171
- end
1468
+ server_replicator.start_pair(server, entity, relation, filter)
1172
1469
  end))
1173
1470
  hook(hooks.changed(world, components.pair, function(entity, id, filter)
1174
- if not IS_PAIR(id) then
1175
- utils.logerror "reliable should be used with a pair relationship"
1176
- end
1177
1471
  local relation = PAIR_SECOND(world, id)
1178
-
1179
- if world:has(relation, ECS_COMPONENT) then
1180
- masking:set_component(entity, relation, COMPONENT_TYPES.pair_value, filter)
1181
- else
1182
- masking:set_component(entity, relation, COMPONENT_TYPES.pair, filter)
1183
- end
1472
+ server_replicator.change_pair(server, entity, relation, filter)
1184
1473
  end))
1185
1474
  hook(hooks.removed(world, components.pair, function(entity, id)
1186
- if not IS_PAIR(id) then
1187
- utils.logerror "reliable should be used with a pair relationship"
1188
- end
1189
- if not server.track_info.entities[entity] then
1190
- return
1191
- end
1192
-
1193
1475
  local relation = PAIR_SECOND(world, id)
1194
- local component_type = untrack_entity_pair(server, entity, relation)
1195
- if not component_type then
1196
- return
1197
- end
1198
- masking:unregister_component_addition(entity, relation, component_type)
1199
- masking:register_stop_component(entity, relation, component_type)
1200
- masking:stop_component(entity, relation, component_type)
1476
+ server_replicator.stop_pair(server, entity, relation)
1201
1477
  end))
1202
1478
 
1203
1479
  hook(hooks.added(world, components.unreliable, function(entity, id, filter)
1204
- if not IS_PAIR(id) then
1205
- utils.logerror "unreliable should be used with a pair relationship"
1206
- end
1207
1480
  local component = PAIR_SECOND(world, id)
1208
- masking:unregister_stop_component(entity, component, COMPONENT_TYPES.unreliable)
1209
- masking:start_component(entity, component, COMPONENT_TYPES.unreliable, filter)
1210
- if server.additions[entity] then
1211
- masking:allocate_entity_addition(entity, component, COMPONENT_TYPES.unreliable)
1212
- end
1481
+ server_replicator.start_unreliable(server, entity, component, filter)
1213
1482
  end))
1214
1483
  hook(hooks.changed(world, components.unreliable, function(entity, id, filter)
1215
- if not IS_PAIR(id) then
1216
- utils.logerror "unreliable should be used with a pair relationship"
1217
- end
1218
1484
  local component = PAIR_SECOND(world, id)
1219
- masking:set_component(entity, component, COMPONENT_TYPES.unreliable, filter)
1485
+ server_replicator.change_unreliable(server, entity, component, filter)
1220
1486
  end))
1221
1487
  hook(hooks.removed(world, components.unreliable, function(entity, id)
1222
- if not IS_PAIR(id) then
1223
- utils.logerror "unreliable should be used with a pair relationship"
1224
- end
1225
- if not server.track_info.entities[entity] then
1226
- return
1227
- end
1228
-
1229
1488
  local component = PAIR_SECOND(world, id)
1230
- untrack_entity_component(server, entity, component)
1231
- masking:register_stop_component(entity, component, COMPONENT_TYPES.unreliable)
1232
- masking:stop_component(entity, component, COMPONENT_TYPES.unreliable)
1489
+ server_replicator.stop_unreliable(server, entity, component)
1233
1490
  end))
1234
1491
 
1235
1492
  hook(hooks.added(world, components.custom, function(entity, id)
@@ -1237,15 +1494,10 @@ function init(server: Server, _world: World?)
1237
1494
  utils.logerror "replecs.custom should be used with a relationship in the server"
1238
1495
  end
1239
1496
  local target = PAIR_SECOND(world, id)
1240
- if server.custom_ids[entity] then
1241
- utils.logwarn("attempted to register a custom_id twice for the same entity", debug.traceback())
1242
- return
1243
- end
1244
-
1245
- server.custom_ids[entity] = target
1497
+ server_replicator.set_custom(server, entity, target)
1246
1498
  end))
1247
1499
  hook(hooks.removed(world, components.custom, function(entity)
1248
- server.custom_ids[entity] = nil
1500
+ server_replicator.remove_custom(server, entity)
1249
1501
  end))
1250
1502
  hook(hooks.added(world, components.global, function(entity, _, value)
1251
1503
  if value > 245 then
@@ -1265,53 +1517,76 @@ function init(server: Server, _world: World?)
1265
1517
  end))
1266
1518
 
1267
1519
  hook(hooks.removed(world, components.__alive_tracking__, function(entity)
1268
- if server.track_info.entities[entity] then
1269
- -- This is in case alive tracking removal is called before networked removal
1270
- server.pending_cleanups[entity] = true
1271
- else
1272
- cleanup_entity(server, entity)
1520
+ if server.track_info.networked[entity] then
1521
+ server_replicator.stop_networked(server, entity)
1273
1522
  end
1523
+ cleanup_entity(server, entity)
1274
1524
  end))
1275
1525
 
1276
1526
  for _, component in server.requires_shared_lookup do
1277
1527
  hook(hooks.added(world, component, function()
1278
- server.is_dirty = true
1528
+ server.is_shared_dirty = true
1529
+ end))
1530
+ hook(hooks.changed(world, component, function()
1531
+ server.is_shared_dirty = true
1279
1532
  end))
1280
1533
  hook(hooks.removed(world, component, function()
1281
- server.is_dirty = true
1534
+ server.is_shared_dirty = true
1282
1535
  end))
1283
1536
  end
1284
1537
 
1538
+ query_current_networked(server)
1539
+
1285
1540
  if game and game:GetService("RunService"):IsServer() then
1286
- local added = game:GetService("Players").PlayerAdded:Connect(function(player)
1541
+ local Players = game:GetService "Players"
1542
+
1543
+ local added = Players.PlayerAdded:Connect(function(player)
1287
1544
  server.masking:register_client(player)
1288
1545
  end)
1289
- local removed = game:GetService("Players").PlayerRemoving:Connect(function(player)
1290
- server.masking:register_client(player)
1546
+ local removed = Players.PlayerRemoving:Connect(function(player)
1547
+ server.masking:unregister_client(player)
1291
1548
  end)
1549
+ for _, player in Players:GetPlayers() do
1550
+ server.masking:register_client(player)
1551
+ end
1292
1552
 
1293
1553
  table.insert(server.connections, added)
1294
1554
  table.insert(server.connections, removed)
1295
1555
  end
1296
1556
  end
1297
1557
 
1298
- local function mark_player_ready(server: Server, player: Player)
1558
+ function server_replicator.mark_player_ready(server: Server, player: Player)
1299
1559
  server.masking:activate_client(player)
1300
1560
  end
1301
1561
 
1302
- local function is_player_ready(server: Server, player: Player): boolean
1562
+ function server_replicator.is_player_ready(server: Server, player: Player): boolean
1303
1563
  return server.masking:member_is_active(player)
1304
1564
  end
1305
1565
 
1306
- local function add_player_alias(server: Server, client: Player, alias: any)
1566
+ function server_replicator.add_player_alias(server: Server, client: Player, alias: any)
1307
1567
  server.masking.client_aliases[alias] = client
1308
1568
  end
1309
1569
 
1310
- local function remove_player_alias(server: Server, alias: any)
1570
+ function server_replicator.remove_player_alias(server: Server, alias: any)
1311
1571
  server.masking.client_aliases[alias] = nil
1312
1572
  end
1313
1573
 
1314
- local function destroy(server: Server)
1574
+ function server_replicator.register_custom_id(server: Server, custom_id: CustomId)
1575
+ server.registered_custom_ids[custom_id] = true
1576
+ server.is_shared_dirty = true
1577
+ end
1578
+
1579
+ function server_replicator.generate_handshake(server: Server): common.HandshakeInfo
1580
+ server_replicator.resolve_dirty(server)
1581
+ return utils.generate_handshake(server.world, server.shared)
1582
+ end
1583
+
1584
+ function server_replicator.verify_handshake(server: Server, handshake: common.HandshakeInfo): (boolean, string?)
1585
+ server_replicator.resolve_dirty(server)
1586
+ return utils.verify_handshake(server.world, server.shared, handshake, "client", "server")
1587
+ end
1588
+
1589
+ function server_replicator.destroy(server: Server)
1315
1590
  if server.inited == nil then
1316
1591
  return warn "attempted to destroy a server twice"
1317
1592
  end
@@ -1325,20 +1600,6 @@ local function destroy(server: Server)
1325
1600
  end
1326
1601
  end
1327
1602
 
1328
- local server = {}
1329
- server.__index = server
1330
- server.init = init
1331
- server.destroy = destroy
1332
- server.get_full = get_full
1333
- server.collect_updates = collect_updates
1334
- server.collect_unreliable = collect_unreliable
1335
- server.encode_component = encode_component
1336
- server.decode_component = decode_component
1337
- server.mark_player_ready = mark_player_ready
1338
- server.is_player_ready = is_player_ready
1339
- server.add_player_alias = add_player_alias
1340
- server.remove_player_alias = remove_player_alias
1341
-
1342
1603
  local function create(world: World?, components: common.Components): Server
1343
1604
  local self = {} :: Server
1344
1605
 
@@ -1349,10 +1610,11 @@ local function create(world: World?, components: common.Components): Server
1349
1610
  self.additions = {}
1350
1611
  self.storage = {}
1351
1612
  self.hooked = {}
1352
- self.is_dirty = false
1613
+ self.is_shared_dirty = false
1353
1614
  self.global_ids = {}
1354
1615
  self.pending_cleanups = {}
1355
1616
  self.track_info = {
1617
+ networked = {},
1356
1618
  entities = {},
1357
1619
  components = {},
1358
1620
  }
@@ -1361,16 +1623,17 @@ local function create(world: World?, components: common.Components): Server
1361
1623
  self.masking = masking_controller.create()
1362
1624
  self.alive_tracked = {}
1363
1625
  self.custom_ids = {}
1626
+ self.registered_custom_ids = {}
1364
1627
  self.requires_shared_lookup = {
1365
1628
  self.components.shared,
1366
1629
  self.components.serdes,
1367
- self.components.bytespan,
1368
1630
  jecs.Name,
1369
1631
  }
1370
1632
 
1371
- return setmetatable(self, server) :: any
1633
+ return setmetatable(self, server_replicator) :: any
1372
1634
  end
1373
1635
 
1374
- server.create = create
1375
-
1376
- return server :: { create: typeof(create) }
1636
+ return {
1637
+ create = create,
1638
+ server_replicator = server_replicator,
1639
+ }