@rbxts/replecs 0.1.0-alpha9-test5 → 0.2.0-cdtest.1

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
@@ -629,12 +750,10 @@ local function append_packet(
629
750
  member_packets.total_size += len
630
751
  else
631
752
  member_packets = {
632
- packets = {
633
- {
634
- buffer = output,
635
- variants = variants,
636
- },
637
- },
753
+ packets = { {
754
+ buffer = output,
755
+ variants = variants,
756
+ } },
638
757
  total_size = len,
639
758
  }
640
759
  packets[member] = member_packets :: MemberPackets
@@ -667,6 +786,12 @@ local function create_packet_iterator(packets: { [Player]: MemberPackets }, id:
667
786
  local iterated: Player? = nil
668
787
  local function iterator()
669
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
670
795
  if not player then
671
796
  return nil :: any
672
797
  end
@@ -681,6 +806,10 @@ end
681
806
  local function create_unreliable_packet_iterator(packets: { [Player]: MemberPackets })
682
807
  return coroutine.wrap(function()
683
808
  for player, data in packets do
809
+ if not utils.is_client_valid(player) then
810
+ continue
811
+ end
812
+
684
813
  table.sort(data.packets, function(a, b)
685
814
  return buffer.len(a.buffer) < buffer.len(b.buffer)
686
815
  end)
@@ -716,8 +845,8 @@ local function create_unreliable_packet_iterator(packets: { [Player]: MemberPack
716
845
  end) :: PacketIterator
717
846
  end
718
847
 
719
- local function get_full(server: Server, client: Player): (buffer, { { any } })
720
- resolve_dirty(server)
848
+ function server_replicator.get_full(server: Server, client: Player): (buffer, { { any } })
849
+ server_replicator.resolve_dirty(server)
721
850
  local index = server.masking.client_indexes[client]
722
851
  if index == nil then
723
852
  utils.logerror "attempted to replicate for a non registered client"
@@ -728,6 +857,9 @@ local function get_full(server: Server, client: Player): (buffer, { { any } })
728
857
 
729
858
  -- maybe edges to quickly find all relevant storages improves performance?
730
859
  for _, storage in server.masking.storages do
860
+ if storage.active_count == 0 then
861
+ continue
862
+ end
731
863
  if not storage.mask.bitmask:get(index) then
732
864
  continue
733
865
  end
@@ -736,7 +868,7 @@ local function get_full(server: Server, client: Player): (buffer, { { any } })
736
868
 
737
869
  local total_entities = 0
738
870
  for entity, active in storage.active do
739
- write_entity(server, c, entity, active, variants)
871
+ server_replicator.write_entity(server, c, entity, active, variants)
740
872
  total_entities += 1
741
873
  end
742
874
  cursor.write_vlq(c, total_entities)
@@ -761,20 +893,21 @@ local function write_vlq_bitmask(c: Cursor, value: number, mask: number, bit: nu
761
893
  end
762
894
  end
763
895
 
764
- local function collect_updates(server: Server)
765
- resolve_dirty(server)
896
+ function server_replicator.collect_updates(server: Server)
897
+ server_replicator.resolve_dirty(server)
766
898
  local packets: { [Player]: MemberPackets } = {}
767
899
 
768
900
  for _, storage in server.masking.storages do
769
901
  local c = cursor.new()
770
902
 
771
903
  local variants = {}
904
+
772
905
  local storage_mask = 0
773
906
 
774
907
  local total_deleted = 0
775
908
  local entity_deletions = storage.deletions.entities
776
909
  for entity in entity_deletions do
777
- write_entity_id(server, c, entity, variants)
910
+ server_replicator.write_entity_id(server, c, entity)
778
911
  total_deleted += 1
779
912
  end
780
913
  table.clear(entity_deletions)
@@ -784,28 +917,29 @@ local function collect_updates(server: Server)
784
917
  local component_deletions = storage.deletions.components
785
918
  for entity, deleted in component_deletions do
786
919
  local total_pairs = 0
920
+
787
921
  for relation in deleted[COMPONENT_TYPES.pair_value] do
788
- write_component_id(server, c, relation)
922
+ server_replicator.write_component_id(server, c, relation)
789
923
  total_pairs += 1
790
924
  end
791
925
  for relation in deleted[COMPONENT_TYPES.pair] do
792
- write_component_id(server, c, relation)
926
+ server_replicator.write_component_id(server, c, relation)
793
927
  total_pairs += 1
794
928
  end
795
929
  cursor.write_vlq(c, total_pairs)
796
930
 
797
931
  local total_removed = 0
798
932
  for component in deleted[COMPONENT_TYPES.component] do
799
- write_component_id(server, c, component)
933
+ server_replicator.write_component_id(server, c, component)
800
934
  total_removed += 1
801
935
  end
802
936
  for tag in deleted[COMPONENT_TYPES.tag] do
803
- write_component_id(server, c, tag)
937
+ server_replicator.write_component_id(server, c, tag)
804
938
  total_removed += 1
805
939
  end
806
940
  cursor.write_vlq(c, total_removed)
807
941
 
808
- write_entity_id(server, c, entity, variants)
942
+ server_replicator.write_entity_id(server, c, entity)
809
943
  total_component_deleted += 1
810
944
  end
811
945
  table.clear(component_deletions)
@@ -821,12 +955,12 @@ local function collect_updates(server: Server)
821
955
  local total_targets = 0
822
956
 
823
957
  for target, value in targets do
824
- write_entity_id(server, c, target, variants)
825
- 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)
826
960
  total_targets += 1
827
961
  end
828
962
  cursor.write_vlq(c, total_targets)
829
- write_component_id(server, c, relation)
963
+ server_replicator.write_component_id(server, c, relation)
830
964
  total_pairs_values += 1
831
965
  end
832
966
  changed_mask = write_vlq_bitmask(c, total_pairs_values, changed_mask, 5)
@@ -836,11 +970,11 @@ local function collect_updates(server: Server)
836
970
  local total_targets = 0
837
971
 
838
972
  for target in targets do
839
- write_entity_id(server, c, target, variants)
973
+ server_replicator.write_entity_id(server, c, target)
840
974
  total_targets += 1
841
975
  end
842
976
  cursor.write_vlq(c, total_targets)
843
- write_component_id(server, c, relation)
977
+ server_replicator.write_component_id(server, c, relation)
844
978
  total_pairs_values_removed += 1
845
979
  end
846
980
  changed_mask = write_vlq_bitmask(c, total_pairs_values_removed, changed_mask, 4)
@@ -850,7 +984,7 @@ local function collect_updates(server: Server)
850
984
  local total_targets = 0
851
985
 
852
986
  for target, added in targets do
853
- write_entity_id(server, c, target, variants)
987
+ server_replicator.write_entity_id(server, c, target)
854
988
  if added then
855
989
  cursor.writei8(c, 1)
856
990
  else
@@ -859,35 +993,37 @@ local function collect_updates(server: Server)
859
993
  total_targets += 1
860
994
  end
861
995
  cursor.write_vlq(c, total_targets)
862
- write_component_id(server, c, relation)
996
+ server_replicator.write_component_id(server, c, relation)
863
997
  total_pairs += 1
864
998
  end
865
999
  changed_mask = write_vlq_bitmask(c, total_pairs, changed_mask, 3)
866
1000
 
867
1001
  local total_removed = 0
868
1002
  for component in changes.removed do
869
- write_component_id(server, c, component)
1003
+ server_replicator.write_component_id(server, c, component)
870
1004
  total_removed += 1
871
1005
  end
872
1006
  changed_mask = write_vlq_bitmask(c, total_removed, changed_mask, 2)
873
1007
 
874
1008
  local total_components = 0
875
1009
  for component, value in changes.component do
876
- write_component(server, c, component, value, variants)
1010
+ server_replicator.write_component(server, c, component, value, variants)
877
1011
  total_components += 1
878
1012
  end
879
1013
  changed_mask = write_vlq_bitmask(c, total_components, changed_mask, 1)
880
1014
 
881
1015
  local total_tagged = 0
882
1016
  for tag in changes.tagged do
883
- write_component_id(server, c, tag)
1017
+ server_replicator.write_component_id(server, c, tag)
884
1018
  total_tagged += 1
885
1019
  end
886
1020
  changed_mask = write_vlq_bitmask(c, total_tagged, changed_mask, 0)
887
1021
 
888
- cursor.writeu8(c, changed_mask)
889
- write_entity_id(server, c, entity, variants)
890
- changed += 1
1022
+ if changed_mask ~= 0 then
1023
+ cursor.writeu8(c, changed_mask)
1024
+ server_replicator.write_entity_id(server, c, entity)
1025
+ changed += 1
1026
+ end
891
1027
  end
892
1028
  table.clear(storage_changes.changed)
893
1029
  storage_mask = write_vlq_bitmask(c, changed, storage_mask, 2)
@@ -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,15 +1062,17 @@ 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
933
1069
  added_mask = write_vlq_bitmask(c, total_tags, added_mask, 0)
934
1070
 
935
- cursor.writeu8(c, added_mask)
936
- write_entity_id(server, c, entity, variants)
937
- total_components_added += 1
1071
+ if added_mask ~= 0 then
1072
+ cursor.writeu8(c, added_mask)
1073
+ server_replicator.write_entity_id(server, c, entity)
1074
+ total_components_added += 1
1075
+ end
938
1076
  end
939
1077
  table.clear(storage_changes.added_components)
940
1078
  storage_mask = write_vlq_bitmask(c, total_components_added, storage_mask, 1)
@@ -946,40 +1084,48 @@ local function collect_updates(server: Server)
946
1084
  continue
947
1085
  end
948
1086
 
949
- write_entity(server, c, entity, active, variants)
1087
+ server_replicator.write_entity(server, c, entity, active, variants)
950
1088
  total_added += 1
951
1089
  end
952
1090
  table.clear(storage_changes.added)
953
1091
  storage_mask = write_vlq_bitmask(c, total_added, storage_mask, 0)
954
1092
 
955
- cursor.writeu8(c, storage_mask)
956
- local output = cursor.close(c)
957
- append_packet(packets, storage.mask.members, output, variants)
1093
+ if storage_mask ~= 0 then
1094
+ cursor.writeu8(c, storage_mask)
1095
+ local output = cursor.close(c)
1096
+ append_packet(packets, storage.mask.members, output, variants)
1097
+ end
958
1098
  end
959
1099
  table.clear(server.additions)
960
1100
  return create_packet_iterator(packets, PACKET_TYPES.reliable)
961
1101
  end
962
1102
 
963
- local function collect_unreliable(server: Server)
964
- resolve_dirty(server)
1103
+ function server_replicator.collect_unreliable(server: Server)
1104
+ server_replicator.resolve_dirty(server)
965
1105
  local world = server.world
966
1106
  local packets: { [Player]: MemberPackets } = {}
967
1107
 
968
1108
  for _, mask_storage in server.masking.storages do
1109
+ if mask_storage.active_count == 0 then
1110
+ continue
1111
+ end
969
1112
  local active = mask_storage.active
970
1113
 
971
1114
  local c = cursor.new()
972
1115
  local variants = {} :: { { any } }
1116
+ local custom_ids: Set<Entity> = {}
973
1117
  local total_entities = 0
974
1118
 
975
1119
  local checkpoint_offset = 0
976
1120
  local checkpoint_variants_count = 0
977
1121
  local checkpoint_total_entities = 0
1122
+ local checkpoint_entity: Entity? = nil
978
1123
 
979
- local function create_checkpoint()
1124
+ local function create_checkpoint(entity: Entity)
980
1125
  checkpoint_offset = c.offset
981
1126
  checkpoint_variants_count = #variants
982
1127
  checkpoint_total_entities = total_entities
1128
+ checkpoint_entity = entity
983
1129
  end
984
1130
 
985
1131
  local function rollback_checkpoint()
@@ -992,6 +1138,14 @@ local function collect_unreliable(server: Server)
992
1138
  for _ = #variants, checkpoint_variants_count + 1, -1 do
993
1139
  table.insert(new_variants, 1, table.remove(variants))
994
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
+
995
1149
  variants = new_variants
996
1150
  total_entities = total_entities - checkpoint_total_entities
997
1151
  end
@@ -1007,7 +1161,7 @@ local function collect_unreliable(server: Server)
1007
1161
  end
1008
1162
 
1009
1163
  for entity, actives in active do
1010
- create_checkpoint()
1164
+ create_checkpoint(entity)
1011
1165
 
1012
1166
  local total_unreliable = 0
1013
1167
  for component in actives.components[COMPONENT_TYPES.unreliable] do
@@ -1016,7 +1170,7 @@ local function collect_unreliable(server: Server)
1016
1170
  continue
1017
1171
  end
1018
1172
 
1019
- write_component(server, c, component, value, variants)
1173
+ server_replicator.write_component(server, c, component, value, variants)
1020
1174
  total_unreliable += 1
1021
1175
  end
1022
1176
 
@@ -1025,11 +1179,12 @@ local function collect_unreliable(server: Server)
1025
1179
  end
1026
1180
  total_entities += 1
1027
1181
  cursor.write_vlq(c, total_unreliable)
1028
- write_entity_id(server, c, entity, variants)
1182
+ server_replicator.write_entity_id(server, c, entity)
1029
1183
 
1030
1184
  if c.offset > MAX_PACKET_SIZE then
1031
1185
  local commit_cursor = c
1032
1186
  local commit_variants = variants
1187
+
1033
1188
  rollback_checkpoint()
1034
1189
  commit_checkpoint(commit_cursor, commit_variants, checkpoint_total_entities)
1035
1190
  end
@@ -1040,6 +1195,188 @@ local function collect_unreliable(server: Server)
1040
1195
  return create_unreliable_packet_iterator(packets)
1041
1196
  end
1042
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
+
1043
1380
  local function check_created(server: Server)
1044
1381
  if server.inited == true then
1045
1382
  warn "attempted to init a server twice"
@@ -1052,13 +1389,37 @@ local function check_created(server: Server)
1052
1389
  return true
1053
1390
  end
1054
1391
 
1055
- 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?)
1056
1417
  if not check_created(server) then
1057
1418
  return
1058
1419
  end
1059
1420
  server.inited = true :: any
1060
1421
 
1061
- local world = _world or server.world
1422
+ local world = wrd or server.world
1062
1423
  server.world = world
1063
1424
 
1064
1425
  if not world then
@@ -1073,159 +1434,59 @@ function init(server: Server, _world: World?)
1073
1434
  server.hooks = hooks
1074
1435
 
1075
1436
  local components = server.components
1076
- local masking = server.masking
1077
-
1078
- server.shared = utils.create_shared_lookup(world, components)
1437
+ server.shared = utils.resolved_shared(world, components, server.registered_custom_ids)
1079
1438
 
1080
1439
  local function hook(unhook: () -> ())
1081
1440
  table.insert(server.hooked, unhook)
1082
1441
  end
1083
1442
 
1084
- hook(hooks.added(world, components.networked, function(entity, _id, filter)
1085
- masking:unregister_stop_entity(entity)
1086
- masking:start_entity(entity, filter)
1087
- masking:propagate_entity_addition(entity)
1088
-
1089
- server.additions[entity] = true
1090
- server.track_info.entities[entity] = true
1091
- track_entity_lifetime(server, entity)
1443
+ hook(hooks.added(world, components.networked, function(entity, _, filter)
1444
+ server_replicator.start_networked(server, entity, filter)
1092
1445
  end))
1093
- hook(hooks.changed(world, components.networked, function(entity, _id, filter)
1094
- masking:set_entity(entity, filter)
1446
+ hook(hooks.changed(world, components.networked, function(entity, _, filter)
1447
+ server_replicator.change_networked(server, entity, filter)
1095
1448
  end))
1096
1449
  hook(hooks.removed(world, components.networked, function(entity)
1097
- masking:register_stop_entity(entity)
1098
- masking:stop_entity(entity)
1099
-
1100
- if server.pending_cleanups[entity] then
1101
- server.pending_cleanups[entity] = nil
1102
- cleanup_entity(server, entity)
1103
- end
1104
-
1105
- server.additions[entity] = nil
1106
- server.track_info.entities[entity] = nil
1450
+ server_replicator.stop_networked(server, entity)
1107
1451
  end))
1108
1452
 
1109
1453
  hook(hooks.added(world, components.reliable, function(entity, id, filter)
1110
- if not IS_PAIR(id) then
1111
- utils.logerror "reliable should be used with a pair relationship"
1112
- end
1113
1454
  local component = PAIR_SECOND(world, id)
1114
-
1115
- local component_type = track_entity_component(server :: Server, entity, component)
1116
- masking:unregister_stop_component(entity, component, component_type)
1117
- masking:start_component(entity, component, component_type, filter)
1118
- if server.additions[entity] then
1119
- masking:allocate_entity_addition(entity, component, component_type)
1120
- elseif server.track_info.entities[entity] then
1121
- masking:register_component_addition(entity, component, component_type)
1122
- end
1455
+ server_replicator.start_reliable(server, entity, component, filter)
1123
1456
  end))
1124
1457
  hook(hooks.changed(world, components.reliable, function(entity, id, filter)
1125
- if not IS_PAIR(id) then
1126
- utils.logerror "reliable should be used with a pair relationship"
1127
- end
1128
1458
  local component = PAIR_SECOND(world, id)
1129
-
1130
- if world:has(component, ECS_COMPONENT) then
1131
- masking:set_component(entity, component, COMPONENT_TYPES.component, filter)
1132
- else
1133
- masking:set_component(entity, component, COMPONENT_TYPES.tag, filter)
1134
- end
1459
+ server_replicator.change_reliable(server, entity, component, filter)
1135
1460
  end))
1136
1461
  hook(hooks.removed(world, components.reliable, function(entity, id)
1137
- if not IS_PAIR(id) then
1138
- utils.logerror "reliable should be used with a pair relationship"
1139
- end
1140
- if not server.track_info.entities[entity] then
1141
- return
1142
- end
1143
-
1144
1462
  local component = PAIR_SECOND(world, id)
1145
- local component_type = untrack_entity_component(server, entity, component)
1146
- if not component_type then
1147
- return
1148
- end
1149
- masking:unregister_component_addition(entity, component, component_type)
1150
- masking:register_stop_component(entity, component, component_type)
1151
- masking:stop_component(entity, component, component_type)
1463
+ server_replicator.stop_reliable(server, entity, component)
1152
1464
  end))
1153
1465
 
1154
1466
  hook(hooks.added(world, components.pair, function(entity, id, filter)
1155
- if not IS_PAIR(id) then
1156
- utils.logerror "pair should be used with a relationship"
1157
- end
1158
1467
  local relation = PAIR_SECOND(world, id)
1159
-
1160
- local component_type = track_entity_pair(server, entity, relation)
1161
- masking:unregister_stop_component(entity, relation, component_type)
1162
- masking:start_component(entity, relation, component_type, filter)
1163
- if server.additions[entity] then
1164
- masking:allocate_entity_addition(entity, relation, component_type)
1165
- elseif server.track_info.entities[entity] then
1166
- masking:register_component_addition(entity, relation, component_type)
1167
- end
1468
+ server_replicator.start_pair(server, entity, relation, filter)
1168
1469
  end))
1169
1470
  hook(hooks.changed(world, components.pair, function(entity, id, filter)
1170
- if not IS_PAIR(id) then
1171
- utils.logerror "reliable should be used with a pair relationship"
1172
- end
1173
1471
  local relation = PAIR_SECOND(world, id)
1174
-
1175
- if world:has(relation, ECS_COMPONENT) then
1176
- masking:set_component(entity, relation, COMPONENT_TYPES.pair_value, filter)
1177
- else
1178
- masking:set_component(entity, relation, COMPONENT_TYPES.pair, filter)
1179
- end
1472
+ server_replicator.change_pair(server, entity, relation, filter)
1180
1473
  end))
1181
1474
  hook(hooks.removed(world, components.pair, function(entity, id)
1182
- if not IS_PAIR(id) then
1183
- utils.logerror "reliable should be used with a pair relationship"
1184
- end
1185
- if not server.track_info.entities[entity] then
1186
- return
1187
- end
1188
-
1189
1475
  local relation = PAIR_SECOND(world, id)
1190
- local component_type = untrack_entity_pair(server, entity, relation)
1191
- if not component_type then
1192
- return
1193
- end
1194
- masking:unregister_component_addition(entity, relation, component_type)
1195
- masking:register_stop_component(entity, relation, component_type)
1196
- masking:stop_component(entity, relation, component_type)
1476
+ server_replicator.stop_pair(server, entity, relation)
1197
1477
  end))
1198
1478
 
1199
1479
  hook(hooks.added(world, components.unreliable, function(entity, id, filter)
1200
- if not IS_PAIR(id) then
1201
- utils.logerror "unreliable should be used with a pair relationship"
1202
- end
1203
1480
  local component = PAIR_SECOND(world, id)
1204
- masking:unregister_stop_component(entity, component, COMPONENT_TYPES.unreliable)
1205
- masking:start_component(entity, component, COMPONENT_TYPES.unreliable, filter)
1206
- if server.additions[entity] then
1207
- masking:allocate_entity_addition(entity, component, COMPONENT_TYPES.unreliable)
1208
- end
1481
+ server_replicator.start_unreliable(server, entity, component, filter)
1209
1482
  end))
1210
1483
  hook(hooks.changed(world, components.unreliable, function(entity, id, filter)
1211
- if not IS_PAIR(id) then
1212
- utils.logerror "unreliable should be used with a pair relationship"
1213
- end
1214
1484
  local component = PAIR_SECOND(world, id)
1215
- masking:set_component(entity, component, COMPONENT_TYPES.unreliable, filter)
1485
+ server_replicator.change_unreliable(server, entity, component, filter)
1216
1486
  end))
1217
1487
  hook(hooks.removed(world, components.unreliable, function(entity, id)
1218
- if not IS_PAIR(id) then
1219
- utils.logerror "unreliable should be used with a pair relationship"
1220
- end
1221
- if not server.track_info.entities[entity] then
1222
- return
1223
- end
1224
-
1225
1488
  local component = PAIR_SECOND(world, id)
1226
- untrack_entity_component(server, entity, component)
1227
- masking:register_stop_component(entity, component, COMPONENT_TYPES.unreliable)
1228
- masking:stop_component(entity, component, COMPONENT_TYPES.unreliable)
1489
+ server_replicator.stop_unreliable(server, entity, component)
1229
1490
  end))
1230
1491
 
1231
1492
  hook(hooks.added(world, components.custom, function(entity, id)
@@ -1233,15 +1494,10 @@ function init(server: Server, _world: World?)
1233
1494
  utils.logerror "replecs.custom should be used with a relationship in the server"
1234
1495
  end
1235
1496
  local target = PAIR_SECOND(world, id)
1236
- if server.custom_ids[entity] then
1237
- utils.logwarn("attempted to register a custom_id twice for the same entity", debug.traceback())
1238
- return
1239
- end
1240
-
1241
- server.custom_ids[entity] = target
1497
+ server_replicator.set_custom(server, entity, target)
1242
1498
  end))
1243
1499
  hook(hooks.removed(world, components.custom, function(entity)
1244
- server.custom_ids[entity] = nil
1500
+ server_replicator.remove_custom(server, entity)
1245
1501
  end))
1246
1502
  hook(hooks.added(world, components.global, function(entity, _, value)
1247
1503
  if value > 245 then
@@ -1261,53 +1517,76 @@ function init(server: Server, _world: World?)
1261
1517
  end))
1262
1518
 
1263
1519
  hook(hooks.removed(world, components.__alive_tracking__, function(entity)
1264
- if server.track_info.entities[entity] then
1265
- -- This is in case alive tracking removal is called before networked removal
1266
- server.pending_cleanups[entity] = true
1267
- else
1268
- cleanup_entity(server, entity)
1520
+ if server.track_info.networked[entity] then
1521
+ server_replicator.stop_networked(server, entity)
1269
1522
  end
1523
+ cleanup_entity(server, entity)
1270
1524
  end))
1271
1525
 
1272
1526
  for _, component in server.requires_shared_lookup do
1273
1527
  hook(hooks.added(world, component, function()
1274
- 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
1275
1532
  end))
1276
1533
  hook(hooks.removed(world, component, function()
1277
- server.is_dirty = true
1534
+ server.is_shared_dirty = true
1278
1535
  end))
1279
1536
  end
1280
1537
 
1538
+ query_current_networked(server)
1539
+
1281
1540
  if game and game:GetService("RunService"):IsServer() then
1282
- local added = game:GetService("Players").PlayerAdded:Connect(function(player)
1541
+ local Players = game:GetService "Players"
1542
+
1543
+ local added = Players.PlayerAdded:Connect(function(player)
1283
1544
  server.masking:register_client(player)
1284
1545
  end)
1285
- local removed = game:GetService("Players").PlayerRemoving:Connect(function(player)
1286
- server.masking:register_client(player)
1546
+ local removed = Players.PlayerRemoving:Connect(function(player)
1547
+ server.masking:unregister_client(player)
1287
1548
  end)
1549
+ for _, player in Players:GetPlayers() do
1550
+ server.masking:register_client(player)
1551
+ end
1288
1552
 
1289
1553
  table.insert(server.connections, added)
1290
1554
  table.insert(server.connections, removed)
1291
1555
  end
1292
1556
  end
1293
1557
 
1294
- local function mark_player_ready(server: Server, player: Player)
1558
+ function server_replicator.mark_player_ready(server: Server, player: Player)
1295
1559
  server.masking:activate_client(player)
1296
1560
  end
1297
1561
 
1298
- local function is_player_ready(server: Server, player: Player): boolean
1562
+ function server_replicator.is_player_ready(server: Server, player: Player): boolean
1299
1563
  return server.masking:member_is_active(player)
1300
1564
  end
1301
1565
 
1302
- local function add_player_alias(server: Server, client: Player, alias: any)
1566
+ function server_replicator.add_player_alias(server: Server, client: Player, alias: any)
1303
1567
  server.masking.client_aliases[alias] = client
1304
1568
  end
1305
1569
 
1306
- local function remove_player_alias(server: Server, alias: any)
1570
+ function server_replicator.remove_player_alias(server: Server, alias: any)
1307
1571
  server.masking.client_aliases[alias] = nil
1308
1572
  end
1309
1573
 
1310
- 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)
1311
1590
  if server.inited == nil then
1312
1591
  return warn "attempted to destroy a server twice"
1313
1592
  end
@@ -1321,20 +1600,6 @@ local function destroy(server: Server)
1321
1600
  end
1322
1601
  end
1323
1602
 
1324
- local server = {}
1325
- server.__index = server
1326
- server.init = init
1327
- server.destroy = destroy
1328
- server.get_full = get_full
1329
- server.collect_updates = collect_updates
1330
- server.collect_unreliable = collect_unreliable
1331
- server.encode_component = encode_component
1332
- server.decode_component = decode_component
1333
- server.mark_player_ready = mark_player_ready
1334
- server.is_player_ready = is_player_ready
1335
- server.add_player_alias = add_player_alias
1336
- server.remove_player_alias = remove_player_alias
1337
-
1338
1603
  local function create(world: World?, components: common.Components): Server
1339
1604
  local self = {} :: Server
1340
1605
 
@@ -1345,10 +1610,11 @@ local function create(world: World?, components: common.Components): Server
1345
1610
  self.additions = {}
1346
1611
  self.storage = {}
1347
1612
  self.hooked = {}
1348
- self.is_dirty = false
1613
+ self.is_shared_dirty = false
1349
1614
  self.global_ids = {}
1350
1615
  self.pending_cleanups = {}
1351
1616
  self.track_info = {
1617
+ networked = {},
1352
1618
  entities = {},
1353
1619
  components = {},
1354
1620
  }
@@ -1357,16 +1623,17 @@ local function create(world: World?, components: common.Components): Server
1357
1623
  self.masking = masking_controller.create()
1358
1624
  self.alive_tracked = {}
1359
1625
  self.custom_ids = {}
1626
+ self.registered_custom_ids = {}
1360
1627
  self.requires_shared_lookup = {
1361
1628
  self.components.shared,
1362
1629
  self.components.serdes,
1363
- self.components.bytespan,
1364
1630
  jecs.Name,
1365
1631
  }
1366
1632
 
1367
- return setmetatable(self, server) :: any
1633
+ return setmetatable(self, server_replicator) :: any
1368
1634
  end
1369
1635
 
1370
- server.create = create
1371
-
1372
- return server :: { create: typeof(create) }
1636
+ return {
1637
+ create = create,
1638
+ server_replicator = server_replicator,
1639
+ }