@rbxts/replecs 0.1.0-alpha8 → 0.1.0-alpha9

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.
@@ -26,6 +26,7 @@ type EntityStorage = {
26
26
  tags: { [Entity]: boolean },
27
27
  values: { [Entity]: any },
28
28
  pairs: { [Entity]: Set<Entity> },
29
+ pairs_values: { [Entity]: Map<Entity, any> },
29
30
  }
30
31
 
31
32
  type Storage = { [Entity]: EntityStorage }
@@ -40,6 +41,9 @@ export type Server = {
40
41
  hooks: common.WorldHooks,
41
42
  alive_tracked: Set<Entity>,
42
43
 
44
+ is_dirty: boolean,
45
+ requires_shared_lookup: { Entity },
46
+
43
47
  track_info: TrackInfo,
44
48
  additions: Set<Entity>,
45
49
  custom_ids: Map<Entity, Entity<any>>,
@@ -62,6 +66,8 @@ export type Server = {
62
66
  collect_unreliable: (self: Server) -> () -> (Player, buffer, { { any } }),
63
67
  mark_player_ready: (self: Server, player: Player) -> (),
64
68
  is_player_ready: (self: Server, player: Player) -> boolean,
69
+ add_player_alias: (self: Server, client: Player, alias: any) -> (),
70
+ remove_player_alias: (self: Server, alias: any) -> (),
65
71
  }
66
72
 
67
73
  local cursor = utils.cursor
@@ -74,18 +80,20 @@ local TRACK_TYPES = {
74
80
  component = 1,
75
81
  tag = 2,
76
82
  pair = 3,
83
+ pair_value = 4,
77
84
  }
85
+
78
86
  local PACKET_TYPES = {
79
87
  full = 1,
80
88
  unreliable = 2,
81
89
  reliable = 3,
82
90
  }
91
+
83
92
  local MAX_PACKET_SIZE = 900
84
93
  local ENTITY_ID_TYPES = {
85
94
  entity = 1,
86
95
  custom = 2,
87
96
  shared = 3,
88
- global = 4,
89
97
  }
90
98
  local ECS_COMPONENT = jecs.Component
91
99
 
@@ -104,7 +112,7 @@ local function track_entity_lifetime(server: Server, entity: Entity)
104
112
  server.world:add(entity, server.components.__alive_tracking__)
105
113
  end
106
114
 
107
- local function get_or_set_entity_storage(server: Server, entity: Entity)
115
+ local function get_or_set_entity_storage(server: Server, entity: Entity): EntityStorage
108
116
  local storage = server.storage[entity]
109
117
 
110
118
  if not storage then
@@ -112,6 +120,7 @@ local function get_or_set_entity_storage(server: Server, entity: Entity)
112
120
  tags = {},
113
121
  values = {},
114
122
  pairs = {},
123
+ pairs_values = {},
115
124
  }
116
125
  server.storage[entity] = storage
117
126
  end
@@ -129,6 +138,23 @@ local function allocate_component_change(server: Server, entity: Entity, compone
129
138
  server.masking:allocate_component_change(entity, component, non_nil)
130
139
  end
131
140
  end
141
+ local function allocate_pair_value_change(server: Server, entity: Entity, relation: Entity, target: Entity, value: any)
142
+ local storage = get_or_set_entity_storage(server, entity)
143
+
144
+ local non_nil = if value == nil then NIL_COMPONENT_VALUE else value
145
+
146
+ local values = storage.pairs_values[relation]
147
+ if values == nil then
148
+ values = {}
149
+ storage.pairs_values[relation] = values
150
+ end
151
+ values[target] = non_nil
152
+
153
+ if not server.additions[entity] and server.track_info.entities[entity] then
154
+ server.masking:allocate_pair_value_change(entity, relation, target, non_nil)
155
+ end
156
+ end
157
+
132
158
  local function allocate_tag_addition(server: Server, entity: Entity, tag: Entity)
133
159
  local storage = get_or_set_entity_storage(server, entity)
134
160
  storage.tags[tag] = true
@@ -159,6 +185,18 @@ local function allocate_component_removal(server: Server, entity: Entity, compon
159
185
  server.masking:allocate_component_removal(entity, component)
160
186
  end
161
187
  end
188
+ local function allocate_pair_value_removal(server: Server, entity: Entity, relation: Entity, target: Entity)
189
+ local storage = get_or_set_entity_storage(server, entity)
190
+ local values = storage.pairs_values[relation]
191
+ if values then
192
+ values[target] = nil
193
+ end
194
+
195
+ if not server.additions[entity] and server.track_info.entities[entity] then
196
+ server.masking:allocate_pair_value_removal(entity, relation, target)
197
+ end
198
+ end
199
+
162
200
  local function allocate_tag_removal(server: Server, entity: Entity, tag: Entity)
163
201
  local storage = get_or_set_entity_storage(server, entity)
164
202
  storage.tags[tag] = nil
@@ -182,6 +220,8 @@ end
182
220
  local function cleanup_entity(server: Server, entity: Entity)
183
221
  server.alive_tracked[entity] = nil
184
222
  server.storage[entity] = nil
223
+ server.global_ids[entity] = nil
224
+ server.custom_ids[entity] = nil
185
225
  server.additions[entity] = nil
186
226
  server.masking:cleanup_entity(entity)
187
227
  end
@@ -207,20 +247,31 @@ local function track_component(server: Server, component: Entity<any>)
207
247
  allocate_component_change(server, entity, component, value)
208
248
  elseif track_type == TRACK_TYPES.tag then
209
249
  allocate_tag_addition(server, entity, component)
210
- else
250
+ elseif track_type == TRACK_TYPES.pair then
211
251
  if not IS_PAIR(id) then
212
252
  return
213
253
  end
214
254
  allocate_pair_addition(server, entity, component, PAIR_SECOND(world, id))
255
+ elseif track_type == TRACK_TYPES.pair_value then
256
+ if not IS_PAIR(id) then
257
+ return
258
+ end
259
+ allocate_pair_value_change(server, entity, component, PAIR_SECOND(world, id), value)
215
260
  end
216
261
  end))
217
- hook(hooks.changed(world, component, function(entity, _id, value)
262
+ hook(hooks.changed(world, component, function(entity, id, value)
218
263
  local track_type = info[entity]
219
264
  if not track_type then
220
265
  return
221
266
  end
222
- -- no check here because only components can trigger changed (I think?)
223
- allocate_component_change(server, entity, component, value)
267
+ if track_type == TRACK_TYPES.component then
268
+ allocate_component_change(server, entity, component, value)
269
+ elseif track_type == TRACK_TYPES.pair_value then
270
+ if not IS_PAIR(id) then
271
+ return
272
+ end
273
+ allocate_pair_value_change(server, entity, component, PAIR_SECOND(world, id), value)
274
+ end
224
275
  end))
225
276
  hook(hooks.removed(world, component, function(entity, id)
226
277
  local track_type = info[entity]
@@ -232,11 +283,16 @@ local function track_component(server: Server, component: Entity<any>)
232
283
  allocate_component_removal(server, entity, component)
233
284
  elseif track_type == TRACK_TYPES.tag then
234
285
  allocate_tag_removal(server, entity, component)
235
- else
286
+ elseif track_type == TRACK_TYPES.pair then
236
287
  if not IS_PAIR(id) then
237
288
  return
238
289
  end
239
290
  allocate_pair_removal(server, entity, component, PAIR_SECOND(world, id))
291
+ elseif track_type == TRACK_TYPES.pair_value then
292
+ if not IS_PAIR(id) then
293
+ return
294
+ end
295
+ allocate_pair_value_removal(server, entity, component, PAIR_SECOND(world, id))
240
296
  end
241
297
  end))
242
298
 
@@ -245,7 +301,6 @@ end
245
301
 
246
302
  local function track_entity_component(server: Server, entity: Entity, component: Entity<any>)
247
303
  local world = server.world
248
-
249
304
  local info = server.track_info.components[component]
250
305
  if not info then
251
306
  info = track_component(server, component)
@@ -254,7 +309,6 @@ local function track_entity_component(server: Server, entity: Entity, component:
254
309
  local entity_storage = get_or_set_entity_storage(server, entity)
255
310
 
256
311
  if world:has(component, ECS_COMPONENT) then
257
- -- component
258
312
  if world:has(entity, component) then
259
313
  local value = world:get(entity, component)
260
314
 
@@ -269,7 +323,6 @@ local function track_entity_component(server: Server, entity: Entity, component:
269
323
 
270
324
  return COMPONENT_TYPES.component
271
325
  else
272
- -- tag
273
326
  if world:has(entity, component) then
274
327
  entity_storage.tags[component] = true
275
328
  end
@@ -287,20 +340,39 @@ local function track_entity_pair(server: Server, entity: Entity, relation: Entit
287
340
  end
288
341
 
289
342
  local entity_storage = get_or_set_entity_storage(server, entity)
290
- local targets = {}
291
- local index = 0
292
343
 
293
- while true do
294
- local target = world:target(entity, relation, index)
295
- if not target then
296
- break
344
+ if world:has(relation, ECS_COMPONENT) then
345
+ local targets = {} :: Map<Entity, any>
346
+
347
+ local index = 0
348
+ while true do
349
+ local target = world:target(entity, relation, index)
350
+ if not target then
351
+ break
352
+ end
353
+ index += 1
354
+ local value = world:get(entity, jecs.pair(relation, target))
355
+ targets[target] = if value == nil then NIL_COMPONENT_VALUE else value :: any
297
356
  end
298
- index += 1
299
- targets[target] = true
300
- end
301
- entity_storage.pairs[relation] = targets
357
+ entity_storage.pairs_values[relation] = targets
358
+ info[entity] = TRACK_TYPES.pair_value
359
+ return COMPONENT_TYPES.pair_value
360
+ else
361
+ local targets = {} :: Set<Entity>
302
362
 
303
- info[entity] = TRACK_TYPES.pair
363
+ local index = 0
364
+ while true do
365
+ local target = world:target(entity, relation, index)
366
+ if not target then
367
+ break
368
+ end
369
+ index += 1
370
+ targets[target] = true
371
+ end
372
+ entity_storage.pairs[relation] = targets
373
+ info[entity] = TRACK_TYPES.pair
374
+ return COMPONENT_TYPES.pair
375
+ end
304
376
  end
305
377
 
306
378
  local function untrack_entity_component(server: Server, entity: Entity, component: Entity<any>): number?
@@ -320,17 +392,20 @@ local function untrack_entity_component(server: Server, entity: Entity, componen
320
392
  return listen_type
321
393
  end
322
394
 
323
- local function untrack_entity_pair(server: Server, entity: Entity, relation: Entity)
395
+ local function untrack_entity_pair(server: Server, entity: Entity, relation: Entity): number?
324
396
  local info = server.track_info.components[relation]
325
397
  if not info then
326
- return
398
+ return nil
327
399
  end
400
+ local listen_type = info[entity]
328
401
  info[entity] = nil
329
402
 
330
403
  local storage = server.storage[entity]
331
404
  if storage then
332
405
  storage.pairs[relation] = nil
406
+ storage.pairs_values[relation] = nil
333
407
  end
408
+ return listen_type
334
409
  end
335
410
 
336
411
  local function encode_component(server: Server, component: Entity): number
@@ -406,33 +481,31 @@ local function write_component_value(server: Server, c: Cursor, component: Entit
406
481
  cursor.write_vlq(c, #variants)
407
482
  end
408
483
  end
484
+ end
409
485
 
486
+ local function write_component(server: Server, c: Cursor, component: Entity, value: any, variants: { any })
487
+ write_component_value(server, c, component, value, variants)
410
488
  write_component_id(server, c, component)
411
489
  end
412
490
 
413
- local function write_entity_id(server: Server, c: Cursor, entity: Entity, variants: { any }, multiply: number?)
491
+ local function write_entity_id(server: Server, c: Cursor, entity: Entity, variants: { any })
414
492
  local custom = server.custom_ids[entity]
415
493
  local global_id = server.global_ids[entity]
416
494
 
417
495
  if global_id then
418
- if multiply then
419
- cursor.writei8(c, ENTITY_ID_TYPES.global * multiply)
420
- cursor.writeu8(c, global_id + GLOBAL_ID_OFFSET)
421
- else
422
- cursor.writei8(c, global_id + GLOBAL_ID_OFFSET)
423
- end
496
+ cursor.writeu8(c, global_id + GLOBAL_ID_OFFSET)
424
497
  elseif custom then
425
498
  local value = server.world:get(entity, custom)
426
- write_component_value(server, c, custom, value, variants)
427
- cursor.writei8(c, ENTITY_ID_TYPES.custom * (multiply or 1))
499
+ write_component(server, c, custom, value, variants)
500
+ cursor.writeu8(c, ENTITY_ID_TYPES.custom)
428
501
  else
429
502
  local shared_id = server.shared.ids[entity]
430
503
  if shared_id then
431
504
  cursor.writeu8(c, shared_id)
432
- cursor.writei8(c, ENTITY_ID_TYPES.shared * (multiply or 1))
505
+ cursor.writeu8(c, ENTITY_ID_TYPES.shared)
433
506
  else
434
507
  cursor.writeu40(c, entity :: any)
435
- cursor.writei8(c, ENTITY_ID_TYPES.entity * (multiply or 1), entity)
508
+ cursor.writeu8(c, ENTITY_ID_TYPES.entity, entity)
436
509
  end
437
510
  end
438
511
  end
@@ -455,6 +528,25 @@ local function write_entity_relations(
455
528
  write_component_id(server, c, relation)
456
529
  end
457
530
 
531
+ local function write_entity_relations_values(
532
+ server: Server,
533
+ storage: EntityStorage,
534
+ c: Cursor,
535
+ relation: Entity,
536
+ variants: { any }
537
+ )
538
+ local targets = storage.pairs_values[relation]
539
+ local total_targets = 0
540
+
541
+ for target, value in targets do
542
+ write_entity_id(server, c, target, variants)
543
+ write_component_value(server, c, relation, value, variants)
544
+ total_targets += 1
545
+ end
546
+ cursor.write_vlq(c, total_targets)
547
+ write_component_id(server, c, relation)
548
+ end
549
+
458
550
  local function write_entity(
459
551
  server: Server,
460
552
  c: Cursor,
@@ -464,6 +556,13 @@ local function write_entity(
464
556
  )
465
557
  local storage = server.storage[entity]
466
558
 
559
+ local all_pairs_values = 0
560
+ for relation in active.components[COMPONENT_TYPES.pair_value] do
561
+ write_entity_relations_values(server, storage, c, relation, variants)
562
+ all_pairs_values += 1
563
+ end
564
+ cursor.write_vlq(c, all_pairs_values)
565
+
467
566
  local all_pairs = 0
468
567
  for relation in active.components[COMPONENT_TYPES.pair] do
469
568
  write_entity_relations(server, storage, c, relation, variants)
@@ -478,7 +577,7 @@ local function write_entity(
478
577
  continue
479
578
  end
480
579
 
481
- write_component_value(server, c, component, value, variants)
580
+ write_component(server, c, component, value, variants)
482
581
  components += 1
483
582
  end
484
583
  cursor.write_vlq(c, components)
@@ -495,6 +594,13 @@ local function write_entity(
495
594
  write_entity_id(server, c, entity, variants)
496
595
  end
497
596
 
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
601
+ end
602
+ end
603
+
498
604
  type Packet = {
499
605
  buffer: buffer,
500
606
  variants: { { any } },
@@ -523,12 +629,10 @@ local function append_packet(
523
629
  member_packets.total_size += len
524
630
  else
525
631
  member_packets = {
526
- packets = {
527
- {
528
- buffer = output,
529
- variants = variants,
530
- },
531
- },
632
+ packets = { {
633
+ buffer = output,
634
+ variants = variants,
635
+ } },
532
636
  total_size = len,
533
637
  }
534
638
  packets[member] = member_packets :: MemberPackets
@@ -610,11 +714,13 @@ local function create_unreliable_packet_iterator(packets: { [Player]: MemberPack
610
714
  end) :: PacketIterator
611
715
  end
612
716
 
613
- local function get_full(server: Server, member: Player): (buffer, { { any } })
614
- local index = server.masking.member_indexes[member]
717
+ local function get_full(server: Server, client: Player): (buffer, { { any } })
718
+ resolve_dirty(server)
719
+ local index = server.masking.client_indexes[client]
615
720
  if index == nil then
616
- utils.logerror "attempted to replicate for a non registered member"
721
+ utils.logerror "attempted to replicate for a non registered client"
617
722
  end
723
+
618
724
  local packets: Array<Packet> = {}
619
725
  local total_size = 0
620
726
 
@@ -654,6 +760,7 @@ local function write_vlq_bitmask(c: Cursor, value: number, mask: number, bit: nu
654
760
  end
655
761
 
656
762
  local function collect_updates(server: Server)
763
+ resolve_dirty(server)
657
764
  local packets: { [Player]: MemberPackets } = {}
658
765
 
659
766
  for _, storage in server.masking.storages do
@@ -674,30 +781,28 @@ local function collect_updates(server: Server)
674
781
  local total_component_deleted = 0
675
782
  local component_deletions = storage.deletions.components
676
783
  for entity, deleted in component_deletions do
677
- local deleted_mask = 0
678
-
679
784
  local total_pairs = 0
785
+ for relation in deleted[COMPONENT_TYPES.pair_value] do
786
+ write_component_id(server, c, relation)
787
+ total_pairs += 1
788
+ end
680
789
  for relation in deleted[COMPONENT_TYPES.pair] do
681
790
  write_component_id(server, c, relation)
682
791
  total_pairs += 1
683
792
  end
684
- deleted_mask = write_vlq_bitmask(c, total_pairs, deleted_mask, 2)
793
+ cursor.write_vlq(c, total_pairs)
685
794
 
686
- local total_components = 0
795
+ local total_removed = 0
687
796
  for component in deleted[COMPONENT_TYPES.component] do
688
797
  write_component_id(server, c, component)
689
- total_components += 1
798
+ total_removed += 1
690
799
  end
691
- deleted_mask = write_vlq_bitmask(c, total_components, deleted_mask, 1)
692
-
693
- local total_tags = 0
694
800
  for tag in deleted[COMPONENT_TYPES.tag] do
695
801
  write_component_id(server, c, tag)
696
- total_tags += 1
802
+ total_removed += 1
697
803
  end
698
- deleted_mask = write_vlq_bitmask(c, total_tags, deleted_mask, 0)
804
+ cursor.write_vlq(c, total_removed)
699
805
 
700
- cursor.writeu8(c, deleted_mask)
701
806
  write_entity_id(server, c, entity, variants)
702
807
  total_component_deleted += 1
703
808
  end
@@ -709,22 +814,45 @@ local function collect_updates(server: Server)
709
814
  for entity, changes in storage_changes.changed do
710
815
  local changed_mask = 0
711
816
 
712
- local total_removed = 0
713
- for component in changes.removed do
714
- write_component_id(server, c, component)
715
- total_removed += 1
817
+ local total_pairs_values = 0
818
+ for relation, targets in changes.pairs_values.changed do
819
+ local total_targets = 0
820
+
821
+ for target, value in targets do
822
+ write_entity_id(server, c, target, variants)
823
+ write_component_value(server, c, relation, value, variants)
824
+ total_targets += 1
825
+ end
826
+ cursor.write_vlq(c, total_targets)
827
+ write_component_id(server, c, relation)
828
+ total_pairs_values += 1
829
+ end
830
+ changed_mask = write_vlq_bitmask(c, total_pairs_values, changed_mask, 5)
831
+
832
+ local total_pairs_values_removed = 0
833
+ for relation, targets in changes.pairs_values.removed do
834
+ local total_targets = 0
835
+
836
+ for target in targets do
837
+ write_entity_id(server, c, target, variants)
838
+ total_targets += 1
839
+ end
840
+ cursor.write_vlq(c, total_targets)
841
+ write_component_id(server, c, relation)
842
+ total_pairs_values_removed += 1
716
843
  end
717
- changed_mask = write_vlq_bitmask(c, total_removed, changed_mask, 3)
844
+ changed_mask = write_vlq_bitmask(c, total_pairs_values_removed, changed_mask, 4)
718
845
 
719
846
  local total_pairs = 0
720
847
  for relation, targets in changes.pairs do
721
848
  local total_targets = 0
722
849
 
723
850
  for target, added in targets do
851
+ write_entity_id(server, c, target, variants)
724
852
  if added then
725
- write_entity_id(server, c, target, variants, 1)
853
+ cursor.writei8(c, 1)
726
854
  else
727
- write_entity_id(server, c, target, variants, -1)
855
+ cursor.writei8(c, -1)
728
856
  end
729
857
  total_targets += 1
730
858
  end
@@ -732,11 +860,18 @@ local function collect_updates(server: Server)
732
860
  write_component_id(server, c, relation)
733
861
  total_pairs += 1
734
862
  end
735
- changed_mask = write_vlq_bitmask(c, total_pairs, changed_mask, 2)
863
+ changed_mask = write_vlq_bitmask(c, total_pairs, changed_mask, 3)
864
+
865
+ local total_removed = 0
866
+ for component in changes.removed do
867
+ write_component_id(server, c, component)
868
+ total_removed += 1
869
+ end
870
+ changed_mask = write_vlq_bitmask(c, total_removed, changed_mask, 2)
736
871
 
737
872
  local total_components = 0
738
873
  for component, value in changes.component do
739
- write_component_value(server, c, component, value, variants)
874
+ write_component(server, c, component, value, variants)
740
875
  total_components += 1
741
876
  end
742
877
  changed_mask = write_vlq_bitmask(c, total_components, changed_mask, 1)
@@ -748,9 +883,11 @@ local function collect_updates(server: Server)
748
883
  end
749
884
  changed_mask = write_vlq_bitmask(c, total_tagged, changed_mask, 0)
750
885
 
751
- cursor.writeu8(c, changed_mask)
752
- write_entity_id(server, c, entity, variants)
753
- changed += 1
886
+ if changed_mask ~= 0 then
887
+ cursor.writeu8(c, changed_mask)
888
+ write_entity_id(server, c, entity, variants)
889
+ changed += 1
890
+ end
754
891
  end
755
892
  table.clear(storage_changes.changed)
756
893
  storage_mask = write_vlq_bitmask(c, changed, storage_mask, 2)
@@ -760,6 +897,13 @@ local function collect_updates(server: Server)
760
897
  local entity_storage = server.storage[entity]
761
898
  local added_mask = 0
762
899
 
900
+ local total_pairs_values = 0
901
+ for relation in components[COMPONENT_TYPES.pair_value] do
902
+ write_entity_relations_values(server, entity_storage, c, relation, variants)
903
+ total_pairs_values += 1
904
+ end
905
+ added_mask = write_vlq_bitmask(c, total_pairs_values, added_mask, 3)
906
+
763
907
  local total_pairs = 0
764
908
  for relation in components[COMPONENT_TYPES.pair] do
765
909
  write_entity_relations(server, entity_storage, c, relation, variants)
@@ -773,7 +917,7 @@ local function collect_updates(server: Server)
773
917
  if value == nil then
774
918
  continue
775
919
  end
776
- write_component_value(server, c, component, value, variants)
920
+ write_component(server, c, component, value, variants)
777
921
  total_components += 1
778
922
  end
779
923
  added_mask = write_vlq_bitmask(c, total_components, added_mask, 1)
@@ -788,9 +932,11 @@ local function collect_updates(server: Server)
788
932
  end
789
933
  added_mask = write_vlq_bitmask(c, total_tags, added_mask, 0)
790
934
 
791
- cursor.writeu8(c, added_mask)
792
- write_entity_id(server, c, entity, variants)
793
- total_components_added += 1
935
+ if added_mask ~= 0 then
936
+ cursor.writeu8(c, added_mask)
937
+ write_entity_id(server, c, entity, variants)
938
+ total_components_added += 1
939
+ end
794
940
  end
795
941
  table.clear(storage_changes.added_components)
796
942
  storage_mask = write_vlq_bitmask(c, total_components_added, storage_mask, 1)
@@ -808,15 +954,18 @@ local function collect_updates(server: Server)
808
954
  table.clear(storage_changes.added)
809
955
  storage_mask = write_vlq_bitmask(c, total_added, storage_mask, 0)
810
956
 
811
- cursor.writeu8(c, storage_mask)
812
- local output = cursor.close(c)
813
- append_packet(packets, storage.mask.members, output, variants)
957
+ if storage_mask ~= 0 then
958
+ cursor.writeu8(c, storage_mask)
959
+ local output = cursor.close(c)
960
+ append_packet(packets, storage.mask.members, output, variants)
961
+ end
814
962
  end
815
963
  table.clear(server.additions)
816
964
  return create_packet_iterator(packets, PACKET_TYPES.reliable)
817
965
  end
818
966
 
819
967
  local function collect_unreliable(server: Server)
968
+ resolve_dirty(server)
820
969
  local world = server.world
821
970
  local packets: { [Player]: MemberPackets } = {}
822
971
 
@@ -871,7 +1020,7 @@ local function collect_unreliable(server: Server)
871
1020
  continue
872
1021
  end
873
1022
 
874
- write_component_value(server, c, component, value, variants)
1023
+ write_component(server, c, component, value, variants)
875
1024
  total_unreliable += 1
876
1025
  end
877
1026
 
@@ -952,12 +1101,13 @@ function init(server: Server, _world: World?)
952
1101
  masking:register_stop_entity(entity)
953
1102
  masking:stop_entity(entity)
954
1103
 
955
- server.additions[entity] = nil
956
- server.track_info.entities[entity] = nil
957
1104
  if server.pending_cleanups[entity] then
958
1105
  server.pending_cleanups[entity] = nil
959
1106
  cleanup_entity(server, entity)
960
1107
  end
1108
+
1109
+ server.additions[entity] = nil
1110
+ server.track_info.entities[entity] = nil
961
1111
  end))
962
1112
 
963
1113
  hook(hooks.added(world, components.reliable, function(entity, id, filter)
@@ -1010,13 +1160,14 @@ function init(server: Server, _world: World?)
1010
1160
  utils.logerror "pair should be used with a relationship"
1011
1161
  end
1012
1162
  local relation = PAIR_SECOND(world, id)
1013
- track_entity_pair(server, entity, relation)
1014
- masking:unregister_stop_component(entity, relation, COMPONENT_TYPES.pair)
1015
- masking:start_component(entity, relation, COMPONENT_TYPES.pair, filter)
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)
1016
1167
  if server.additions[entity] then
1017
- masking:allocate_entity_addition(entity, relation, COMPONENT_TYPES.pair)
1168
+ masking:allocate_entity_addition(entity, relation, component_type)
1018
1169
  elseif server.track_info.entities[entity] then
1019
- masking:register_component_addition(entity, relation, COMPONENT_TYPES.pair)
1170
+ masking:register_component_addition(entity, relation, component_type)
1020
1171
  end
1021
1172
  end))
1022
1173
  hook(hooks.changed(world, components.pair, function(entity, id, filter)
@@ -1024,7 +1175,12 @@ function init(server: Server, _world: World?)
1024
1175
  utils.logerror "reliable should be used with a pair relationship"
1025
1176
  end
1026
1177
  local relation = PAIR_SECOND(world, id)
1027
- masking:set_component(entity, relation, COMPONENT_TYPES.pair, filter)
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
1028
1184
  end))
1029
1185
  hook(hooks.removed(world, components.pair, function(entity, id)
1030
1186
  if not IS_PAIR(id) then
@@ -1035,10 +1191,13 @@ function init(server: Server, _world: World?)
1035
1191
  end
1036
1192
 
1037
1193
  local relation = PAIR_SECOND(world, id)
1038
- untrack_entity_pair(server, entity, relation)
1039
- masking:unregister_component_addition(entity, relation, COMPONENT_TYPES.pair)
1040
- masking:register_stop_component(entity, relation, COMPONENT_TYPES.pair)
1041
- masking:stop_component(entity, relation, COMPONENT_TYPES.pair)
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)
1042
1201
  end))
1043
1202
 
1044
1203
  hook(hooks.added(world, components.unreliable, function(entity, id, filter)
@@ -1114,12 +1273,21 @@ function init(server: Server, _world: World?)
1114
1273
  end
1115
1274
  end))
1116
1275
 
1276
+ for _, component in server.requires_shared_lookup do
1277
+ hook(hooks.added(world, component, function()
1278
+ server.is_dirty = true
1279
+ end))
1280
+ hook(hooks.removed(world, component, function()
1281
+ server.is_dirty = true
1282
+ end))
1283
+ end
1284
+
1117
1285
  if game and game:GetService("RunService"):IsServer() then
1118
1286
  local added = game:GetService("Players").PlayerAdded:Connect(function(player)
1119
- server.masking:register_member(player)
1287
+ server.masking:register_client(player)
1120
1288
  end)
1121
1289
  local removed = game:GetService("Players").PlayerRemoving:Connect(function(player)
1122
- server.masking:unregister_member(player)
1290
+ server.masking:register_client(player)
1123
1291
  end)
1124
1292
 
1125
1293
  table.insert(server.connections, added)
@@ -1128,13 +1296,21 @@ function init(server: Server, _world: World?)
1128
1296
  end
1129
1297
 
1130
1298
  local function mark_player_ready(server: Server, player: Player)
1131
- server.masking:activate_member(player)
1299
+ server.masking:activate_client(player)
1132
1300
  end
1133
1301
 
1134
1302
  local function is_player_ready(server: Server, player: Player): boolean
1135
1303
  return server.masking:member_is_active(player)
1136
1304
  end
1137
1305
 
1306
+ local function add_player_alias(server: Server, client: Player, alias: any)
1307
+ server.masking.client_aliases[alias] = client
1308
+ end
1309
+
1310
+ local function remove_player_alias(server: Server, alias: any)
1311
+ server.masking.client_aliases[alias] = nil
1312
+ end
1313
+
1138
1314
  local function destroy(server: Server)
1139
1315
  if server.inited == nil then
1140
1316
  return warn "attempted to destroy a server twice"
@@ -1160,6 +1336,8 @@ server.encode_component = encode_component
1160
1336
  server.decode_component = decode_component
1161
1337
  server.mark_player_ready = mark_player_ready
1162
1338
  server.is_player_ready = is_player_ready
1339
+ server.add_player_alias = add_player_alias
1340
+ server.remove_player_alias = remove_player_alias
1163
1341
 
1164
1342
  local function create(world: World?, components: common.Components): Server
1165
1343
  local self = {} :: Server
@@ -1171,6 +1349,7 @@ local function create(world: World?, components: common.Components): Server
1171
1349
  self.additions = {}
1172
1350
  self.storage = {}
1173
1351
  self.hooked = {}
1352
+ self.is_dirty = false
1174
1353
  self.global_ids = {}
1175
1354
  self.pending_cleanups = {}
1176
1355
  self.track_info = {
@@ -1182,6 +1361,12 @@ local function create(world: World?, components: common.Components): Server
1182
1361
  self.masking = masking_controller.create()
1183
1362
  self.alive_tracked = {}
1184
1363
  self.custom_ids = {}
1364
+ self.requires_shared_lookup = {
1365
+ self.components.shared,
1366
+ self.components.serdes,
1367
+ self.components.bytespan,
1368
+ jecs.Name,
1369
+ }
1185
1370
 
1186
1371
  return setmetatable(self, server) :: any
1187
1372
  end