@rbxts/replecs 0.3.1 → 0.4.0-rc.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,1673 +0,0 @@
1
- --!optimize 2
2
- --!native
3
-
4
- local common = require (script.Parent:WaitForChild('common'))
5
- local types = require (script.Parent:WaitForChild('types'))
6
- local customid = require (script.Parent:WaitForChild('customid'))
7
- local utils = require (script.Parent:WaitForChild('utils'))
8
-
9
- local cursor = utils.cursor
10
-
11
- type Cursor = utils.Cursor
12
- type CustomId = customid.CustomId
13
-
14
- type Entity = common.Entity
15
- type Component<T = any> = common.Component<T>
16
- type World = common.World
17
-
18
- type Array<T> = { T }
19
- type Map<K, V> = { [K]: V }
20
- type Set<T> = { [T]: boolean }
21
- type Disconnect = () -> ()
22
-
23
- type CommandBuffer = {
24
- tags: Set<Component>,
25
- components: Map<Component, { value: any }>,
26
- unreliable_components: Map<Component, { value: any }>,
27
- remove: Set<Component>,
28
-
29
- pairs_add: { [Component]: Set<Entity> },
30
- pairs_set: { [Component]: Map<Entity, { value: any }> },
31
- pairs_unprocessed: {
32
- [Component]: Map<Entity, {
33
- cursor: Cursor,
34
- variants: { any }?,
35
- processed_value: { value: any }?,
36
- }>,
37
- },
38
- pairs_remove: { [Component]: Set<Entity> },
39
- relations_clear: Set<Component>,
40
- }
41
-
42
- type HookMethod =
43
- & ((
44
- self: Client,
45
- action: "changed",
46
- relation: Component,
47
- callback: (entity: Entity, id: Component, value: any) -> ()
48
- ) -> Disconnect)
49
- & ((
50
- self: Client,
51
- action: "removed",
52
- relation: Component,
53
- callback: (entity: Entity, id: Component) -> ()
54
- ) -> Disconnect)
55
- & ((self: Client, action: "deleted", entity: Entity, callback: (entity: Entity) -> ()) -> Disconnect
56
- )
57
- type ChangedHooksEntry = {
58
- overrides: boolean,
59
- callbacks: Array<(entity: Entity, id: Component, value: any) -> ()>,
60
- }
61
- type RemovedHooksEntry = {
62
- overrides: boolean,
63
- callbacks: Array<(entity: Entity, id: Component) -> ()>,
64
- }
65
- type DeletedHookEntry = {
66
- overrides: boolean,
67
- callbacks: Array<(entity: Entity) -> ()>,
68
- }
69
-
70
- type CustomIdMap = { [Entity]: CustomId | Entity }
71
-
72
- export type ClientImp = {
73
- set_serdes: <T>(self: Client, id: Component<T>, serdes: types.Serdes<T>) -> (),
74
- remove_serdes: (self: Client, id: Component) -> (),
75
- }
76
-
77
- export type Client = ClientImp & {
78
- world: World,
79
- inited: boolean?,
80
-
81
- is_replicating: boolean,
82
- after_replication_callbacks: { () -> () },
83
-
84
- is_shared_dirty: boolean,
85
- requires_shared_lookup: { Entity },
86
- components: types.Components,
87
- shared: types.Shared,
88
- global_handler: ((id: number) -> Entity)?,
89
- server_ids: { [number]: Entity },
90
- client_ids: { [Entity]: number },
91
- command_buffers: { [Entity]: CommandBuffer }?,
92
- command_buffers_active: boolean,
93
-
94
- registered_custom_ids: { [CustomId]: boolean },
95
- component_serdes: Map<Component, types.Serdes>,
96
-
97
- init: (self: Client, world: World?) -> (),
98
- destroy: (self: Client) -> (),
99
- handle_global: (self: Client, handler: (id: number) -> Entity) -> (),
100
- get_server_entity: (self: Client, client_entity: Entity) -> number?,
101
- get_client_entity: (self: Client, server_entity: number) -> Entity?,
102
-
103
- register_entity: (self: Client, entity: Entity, server_entity: number) -> (),
104
- unregister_entity: (self: Client, entity: Entity) -> (),
105
-
106
- hooked: Array<() -> ()>,
107
-
108
- after_replication: (self: Client, callback: () -> ()) -> (),
109
- added: (self: Client, callback: (entity: Entity) -> ()) -> Disconnect,
110
- hook: HookMethod,
111
- override: HookMethod,
112
- addition_hooks: Array<(entity: Entity) -> ()>,
113
- network_hooks: {
114
- deleted: { [Entity]: DeletedHookEntry },
115
- changed: { [Component]: ChangedHooksEntry },
116
- removed: { [Component]: RemovedHooksEntry },
117
- },
118
-
119
- encode_component: (self: Client, component: Entity) -> number,
120
- decode_component: (self: Client, component: number) -> Entity,
121
- get_shared_count: (self: Client) -> number,
122
-
123
- register_custom_id: (self: Client, custom_id: CustomId) -> (),
124
-
125
- apply_full: (self: Client, buf: buffer, all_variants: { { any } }?) -> (),
126
- apply_entity: (self: Client, buf: buffer, all_variants: { { any } }?) -> (),
127
- apply_updates: (self: Client, buf: buffer, all_variants: { { any } }?) -> (),
128
- apply_unreliable: (self: Client, buf: buffer, all_variants: { { any } }?) -> (),
129
-
130
- generate_handshake: (self: Client) -> types.HandshakeInfo,
131
- verify_handshake: (self: Client, handshake: types.HandshakeInfo) -> (boolean, string?),
132
- }
133
-
134
- local client_replicator = {}
135
- client_replicator.__index = client_replicator
136
-
137
- local GLOBAL_ID_OFFSET = 10
138
-
139
- local ENTITY_ID_TYPES = {
140
- entity = 1,
141
- custom_handler = 2,
142
- custom_id = 3,
143
- shared = 4,
144
- }
145
- local PACKET_TYPES = {
146
- full = 1,
147
- entity = 2,
148
- updates = 3,
149
- unreliable = 4,
150
- }
151
-
152
- local ECS_NAME = common.ecs_name
153
- local ECS_WILDCARD = common.wildcard
154
- local PAIR = common.pair
155
- local ITERATE_ALL_RELATIONS = common.iterate_all_relations
156
- local WORLD_ENTITY = common.world_entity
157
- local WORLD_ADD = common.world_add
158
- local WORLD_SET = common.world_set
159
- local WORLD_REMOVE = common.world_remove
160
- local WORLD_GET = common.world_get
161
- local WORLD_HAS = common.world_has
162
- local WORLD_DELETE = common.world_delete
163
-
164
- local HOOK_ADDED = common.hook_added
165
- local HOOK_CHANGED = common.hook_changed
166
- local HOOK_REMOVED = common.hook_removed
167
-
168
- local function QUERY_CURRENT_COMPONENTS(client: Client)
169
- for component, serdes in client.world:query(client.components.serdes):iter() do
170
- client.component_serdes[component] = serdes
171
- end
172
- end
173
-
174
- local function get_or_create_entity(client: Client, server_id: number): Entity
175
- local world = client.world
176
-
177
- local server_entity = client.server_ids[server_id]
178
- if server_entity then
179
- return server_entity
180
- else
181
- local entity = WORLD_ENTITY(world)
182
- WORLD_ADD(world, entity, client.components.__alive_tracking__)
183
-
184
- client.server_ids[server_id] = entity
185
- client.client_ids[entity] = server_id
186
-
187
- for _, callback in client.addition_hooks do
188
- callback(entity)
189
- end
190
-
191
- return entity
192
- end
193
- end
194
-
195
- local function get_or_create_command_buffer(client: Client, entity: Entity): CommandBuffer
196
- local command_buffers = client.command_buffers
197
-
198
- if not command_buffers then
199
- error "attempted to use a command buffer without being active. (this should never happen)"
200
- end
201
-
202
- local command_buffer = command_buffers[entity :: any]
203
- if not command_buffer then
204
- command_buffer = {
205
- tags = {},
206
- components = {},
207
- unreliable_components = {},
208
- remove = {},
209
- pairs_add = {},
210
- pairs_set = {},
211
- pairs_unprocessed = {},
212
- pairs_remove = {},
213
- relations_clear = {},
214
- }
215
- command_buffers[entity :: any] = command_buffer
216
- end
217
- return command_buffer
218
- end
219
-
220
- function client_replicator.entity_set(
221
- client: Client,
222
- entity: Entity,
223
- id: Component,
224
- value: any,
225
- changed_hooks: ChangedHooksEntry?
226
- )
227
- if client.command_buffers_active then
228
- local command_buffer = get_or_create_command_buffer(client, entity)
229
- command_buffer.components[id] = { value = value }
230
- else
231
- if changed_hooks then
232
- if not changed_hooks.overrides then
233
- WORLD_SET(client.world, entity, id, value)
234
- end
235
- for _, callback in changed_hooks.callbacks do
236
- callback(entity, id, value)
237
- end
238
- else
239
- WORLD_SET(client.world, entity, id, value)
240
- end
241
- end
242
- end
243
-
244
- function client_replicator.entity_add(client: Client, entity: Entity, tag: Entity, changed_hooks: ChangedHooksEntry?)
245
- if client.command_buffers_active then
246
- local command_buffer = get_or_create_command_buffer(client, entity)
247
- command_buffer.tags[tag] = true
248
- else
249
- if changed_hooks then
250
- if not changed_hooks.overrides then
251
- WORLD_ADD(client.world, entity, tag)
252
- end
253
- for _, callback in changed_hooks.callbacks do
254
- callback(entity, tag)
255
- end
256
- else
257
- WORLD_ADD(client.world, entity, tag)
258
- end
259
- end
260
- end
261
-
262
- function client_replicator.entity_set_unreliable(
263
- client: Client,
264
- entity: Entity,
265
- id: Entity,
266
- value: any,
267
- changed_hooks: ChangedHooksEntry?
268
- )
269
- if client.command_buffers_active then
270
- local command_buffer = get_or_create_command_buffer(client, entity)
271
- command_buffer.unreliable_components[id] = { value = value }
272
- else
273
- if WORLD_HAS(client.world, entity, id) then
274
- client_replicator.entity_set(client, entity, id, value, changed_hooks)
275
- end
276
- end
277
- end
278
-
279
- function client_replicator.entity_set_pair(
280
- client: Client,
281
- entity: Entity,
282
- relation: Entity,
283
- target: Entity,
284
- value: any,
285
- changed_hooks: ChangedHooksEntry?
286
- )
287
- if client.command_buffers_active then
288
- local command_buffer = get_or_create_command_buffer(client, entity)
289
- local pair_relation = command_buffer.pairs_set[relation]
290
-
291
- if pair_relation then
292
- pair_relation[target] = { value = value }
293
- else
294
- command_buffer.pairs_set[relation] = { [target] = { value = value } }
295
- end
296
- else
297
- client_replicator.entity_set(client, entity, PAIR(relation, target), value, changed_hooks)
298
- end
299
- end
300
-
301
- function client_replicator.entity_add_pair(
302
- client: Client,
303
- entity: Entity,
304
- relation: Entity,
305
- target: Entity,
306
- changed_hooks: ChangedHooksEntry?
307
- )
308
- if client.command_buffers_active then
309
- local command_buffer = get_or_create_command_buffer(client, entity)
310
- local pair_relation = command_buffer.pairs_add[relation]
311
-
312
- if pair_relation then
313
- pair_relation[target] = true
314
- else
315
- command_buffer.pairs_add[relation] = { [target] = true }
316
- end
317
- else
318
- client_replicator.entity_add(client, entity, PAIR(relation, target), changed_hooks)
319
- end
320
- end
321
-
322
- function client_replicator.entity_set_postponed_pair(
323
- client: Client,
324
- entity: Entity,
325
- relation: Component,
326
- target: Entity,
327
- c: Cursor,
328
- variants: { any }?
329
- ): any
330
- if client.command_buffers_active then
331
- local commmand_buffer = get_or_create_command_buffer(client, entity)
332
- local pairs_unprocessed = commmand_buffer.pairs_unprocessed
333
- local pair_relation = pairs_unprocessed[relation]
334
- if pair_relation then
335
- pair_relation[target] = {
336
- cursor = c,
337
- variants = variants,
338
- }
339
- else
340
- pairs_unprocessed[relation] = {
341
- [target] = {
342
- cursor = c,
343
- variants = variants,
344
- },
345
- }
346
- end
347
- return nil
348
- else
349
- local pair_id, value = client_replicator.read_pair_value(client, relation, target, c, variants)
350
- -- TODO: respect hooks
351
- WORLD_SET(client.world, entity, pair_id, value)
352
- return value
353
- end
354
- end
355
-
356
- function client_replicator.entity_remove(client: Client, entity: Entity, id: Entity, removed_hooks: RemovedHooksEntry?)
357
- if client.command_buffers_active then
358
- local command_buffer = get_or_create_command_buffer(client, entity)
359
- command_buffer.remove[id] = true
360
- else
361
- if removed_hooks then
362
- for _, callback in removed_hooks.callbacks do
363
- callback(entity, id)
364
- end
365
- if not removed_hooks.overrides then
366
- WORLD_REMOVE(client.world, entity, id)
367
- end
368
- else
369
- WORLD_REMOVE(client.world, entity, id)
370
- end
371
- end
372
- end
373
-
374
- function client_replicator.entity_remove_pair(
375
- client: Client,
376
- entity: Entity,
377
- relation: Entity,
378
- target: Entity,
379
- removed_hooks: RemovedHooksEntry?
380
- )
381
- if client.command_buffers_active then
382
- local command_buffer = get_or_create_command_buffer(client, entity)
383
- local pair_relation = command_buffer.pairs_remove[relation]
384
-
385
- if pair_relation then
386
- pair_relation[target] = true
387
- else
388
- command_buffer.pairs_remove[relation] = { [target] = true }
389
- end
390
- else
391
- client_replicator.entity_remove(client, entity, PAIR(relation, target), removed_hooks)
392
- end
393
- end
394
-
395
- function client_replicator.entity_clear_relation(
396
- client: Client,
397
- entity: Entity,
398
- relation: Entity,
399
- removed_hooks: RemovedHooksEntry?
400
- )
401
- if client.command_buffers_active then
402
- local command_buffer = get_or_create_command_buffer(client, entity)
403
- command_buffer.relations_clear[relation] = true
404
- else
405
- local world = client.world
406
- if removed_hooks then
407
- ITERATE_ALL_RELATIONS(world, entity, relation, function(pair)
408
- for _, callback in removed_hooks.callbacks do
409
- callback(entity, pair)
410
- end
411
- if not removed_hooks.overrides then
412
- WORLD_REMOVE(world, entity, pair)
413
- end
414
- end)
415
- else
416
- ITERATE_ALL_RELATIONS(world, entity, relation, function(pair)
417
- WORLD_REMOVE(world, entity, pair)
418
- end)
419
- end
420
- end
421
- end
422
-
423
- local function read_variant_value(c: Cursor, serdes: types.Serdes?, variants: { any }?)
424
- if serdes then
425
- local bytespan = serdes.bytespan or cursor.read_vlq(c)
426
-
427
- local appended = cursor.read_buffer(c, bytespan)
428
- local serdes_variants: { any }?
429
-
430
- if serdes.includes_variants then
431
- local start_variant = cursor.read_vlq(c)
432
-
433
- if start_variant > 0 then
434
- local size = cursor.read_vlq(c)
435
- serdes_variants = table.move(variants :: { any }, start_variant, start_variant + size - 1, 1, {})
436
- end
437
- end
438
-
439
- local output = serdes.deserialize(appended, serdes_variants :: any)
440
- return output
441
- else
442
- local variant_id = cursor.read_vlq(c)
443
- if variant_id == 0 then
444
- return nil
445
- end
446
- local value = (variants :: { any })[variant_id]
447
- return value
448
- end
449
- end
450
-
451
- function client_replicator.read_pair_value(
452
- client: Client,
453
- relation: Component,
454
- target: Entity,
455
- c: Cursor,
456
- variants: { any }?
457
- )
458
- local pair_id = PAIR(relation, target)
459
- local pair_wildcard = PAIR(relation, ECS_WILDCARD)
460
- local serdes = client.component_serdes[pair_id] or client.component_serdes[pair_wildcard]
461
- local value = read_variant_value(c, serdes, variants)
462
- return pair_id, value
463
- end
464
-
465
- function client_replicator.read_component_value(
466
- client: Client,
467
- component: Component,
468
- c: Cursor,
469
- variants: { any }?
470
- ): any
471
- local serdes = client.shared.serdes[component]
472
-
473
- if serdes then
474
- local bytespan = serdes.bytespan or cursor.read_vlq(c)
475
-
476
- local appended = cursor.read_buffer(c, bytespan)
477
- local serdes_variants: { any }?
478
-
479
- if serdes.includes_variants then
480
- local start_variant = cursor.read_vlq(c)
481
-
482
- if start_variant > 0 then
483
- local size = cursor.read_vlq(c)
484
- serdes_variants = table.move(variants :: { any }, start_variant, start_variant + size - 1, 1, {})
485
- end
486
- end
487
-
488
- local output = serdes.deserialize(appended, serdes_variants :: any)
489
- return output
490
- else
491
- local variant_id = cursor.read_vlq(c)
492
- if variant_id == 0 then
493
- return nil
494
- end
495
- local value = (variants :: { any })[variant_id]
496
- return value
497
- end
498
- end
499
-
500
- function client_replicator.read_component_id(client: Client, c: Cursor): Entity
501
- local shared_components = client.shared.components
502
- local shared_id = cursor.read_span(c, #shared_components.keys)
503
- local component = shared_components.indexes[shared_id]
504
- if not component then
505
- print("NON SHARED COMPONENT", shared_id, client.shared.components)
506
- error "received a non shared component"
507
- end
508
- return component
509
- end
510
-
511
- function client_replicator.resolve_global(client: Client, global_id: number): Entity
512
- if not client.global_handler then
513
- error "global id parser not set, consider using client:handle_global()"
514
- end
515
- local parsed = client.global_handler(global_id)
516
- return parsed
517
- end
518
-
519
- -- returns entity, server_id, id_type
520
- function client_replicator.read_entity_id(client: Client, c: Cursor): (Entity?, number?, number?)
521
- local id_type = cursor.readu8(c)
522
-
523
- if id_type <= GLOBAL_ID_OFFSET then
524
- if
525
- id_type == ENTITY_ID_TYPES.entity
526
- or id_type == ENTITY_ID_TYPES.custom_id
527
- or id_type == ENTITY_ID_TYPES.custom_handler
528
- then
529
- local server_id = cursor.readu40(c)
530
- return client.server_ids[server_id], server_id, id_type
531
- elseif id_type == ENTITY_ID_TYPES.shared then
532
- return client_replicator.read_component_id(client, c), nil, id_type
533
- end
534
- error(`malformed entity type {id_type} ` .. cursor.readu32(c))
535
- else
536
- return client_replicator.resolve_global(client, id_type - GLOBAL_ID_OFFSET), nil, id_type
537
- end
538
- end
539
-
540
- local function read_vlq_bitmask(c: Cursor, mask: number, bit: number): number
541
- if utils.checkbit(mask, bit) then
542
- return cursor.read_vlq(c)
543
- else
544
- return 0
545
- end
546
- end
547
-
548
- function client_replicator.process_entity_id(
549
- client: Client,
550
- c: Cursor,
551
- custom_ids: CustomIdMap,
552
- process: (entity: Entity) -> ()
553
- )
554
- local entity, server_id, id_type = client_replicator.read_entity_id(client, c)
555
-
556
- if entity then
557
- -- skip customid, keep cursor offset
558
- if id_type == ENTITY_ID_TYPES.custom_id then
559
- client_replicator.read_component_id(client, c)
560
- elseif id_type == ENTITY_ID_TYPES.custom_handler then
561
- cursor.readu8(c)
562
- end
563
-
564
- return process(entity)
565
- else
566
- if id_type == ENTITY_ID_TYPES.custom_id or id_type == ENTITY_ID_TYPES.custom_handler then
567
- if id_type == ENTITY_ID_TYPES.custom_id then
568
- local component_id = client_replicator.read_component_id(client, c)
569
- custom_ids[server_id :: any] = component_id
570
- elseif id_type == ENTITY_ID_TYPES.custom_handler then
571
- local shared_custom_id = cursor.readu8(c)
572
- local handler = client.shared.custom_ids.indexes[shared_custom_id]
573
-
574
- if not handler then
575
- common.log_error "attempted to use a custom id that wasn't registered"
576
- end
577
- custom_ids[server_id :: any] = handler
578
- end
579
-
580
- if client.command_buffers_active then
581
- -- negative id means it's a custom id,
582
- -- it needs to be translated first
583
- process(-server_id :: any)
584
- else
585
- client.command_buffers_active = true
586
- process(-server_id :: any)
587
- client.command_buffers_active = false
588
- end
589
- else
590
- local new_entity = get_or_create_entity(client, server_id :: number)
591
- process(new_entity)
592
- end
593
- end
594
- end
595
-
596
- function client_replicator.process_entity_relations(client: Client, entity: Entity, c: Cursor, custom_ids: CustomIdMap)
597
- local components = client.components
598
- local relation = client_replicator.read_component_id(client, c)
599
- local total_targets = cursor.read_vlq(c)
600
- local pair_hooks = client.network_hooks.changed[PAIR(components.relation, relation)]
601
-
602
- for _ = 1, total_targets do
603
- client_replicator.process_entity_id(client, c, custom_ids, function(target)
604
- client_replicator.entity_add_pair(client, entity, relation, target, pair_hooks)
605
- end)
606
- end
607
- end
608
-
609
- function client_replicator.process_entity_relation_values(
610
- client: Client,
611
- entity: Entity,
612
- c: Cursor,
613
- custom_ids: CustomIdMap,
614
- variants: { any }?
615
- )
616
- local relation = client_replicator.read_component_id(client, c)
617
- local total_targets = cursor.read_vlq(c)
618
- local components = client.components
619
- local relation_hooks = client.network_hooks.changed[PAIR(components.relation, relation)]
620
-
621
- for _ = 1, total_targets do
622
- local value = client_replicator.read_component_value(client, relation, c, variants)
623
- client_replicator.process_entity_id(client, c, custom_ids, function(target)
624
- client_replicator.entity_set_pair(client, entity, relation, target, value, relation_hooks)
625
- end)
626
- end
627
- end
628
-
629
- function client_replicator.process_entity_pair_value(
630
- client: Client,
631
- entity: Entity,
632
- c: Cursor,
633
- custom_ids: CustomIdMap,
634
- variants: { any }?
635
- )
636
- local relation = client_replicator.read_component_id(client, c)
637
- client_replicator.process_entity_id(client, c, custom_ids, function(target)
638
- if (target :: any) > 0 then
639
- local pointer_offset = cursor.read_vlq(c)
640
- local jump_offset = c.offset - pointer_offset
641
-
642
- local _, value = client_replicator.read_pair_value(client, relation, target, c, variants)
643
- client_replicator.entity_set_pair(client, entity, relation, target, value)
644
-
645
- c.offset = jump_offset
646
- else
647
- local frozen_cursor = cursor.from_offset(c.buffer, c.offset)
648
-
649
- local pointer_offset = cursor.read_vlq(c)
650
- c.offset -= pointer_offset
651
-
652
- client_replicator.entity_set_postponed_pair(client, entity, relation, target, frozen_cursor, variants)
653
- end
654
- end)
655
- end
656
-
657
- function client_replicator.process_entity_pair(client: Client, entity: Entity, c: Cursor, custom_ids: CustomIdMap)
658
- local relation = client_replicator.read_component_id(client, c)
659
- client_replicator.process_entity_id(client, c, custom_ids, function(target)
660
- -- TODO: respect hooks/overrides
661
- client_replicator.entity_add_pair(client, entity, relation, target)
662
- end)
663
- end
664
-
665
- function client_replicator.process_entity(
666
- client: Client,
667
- entity: Entity,
668
- c: Cursor,
669
- custom_ids: CustomIdMap,
670
- variants: { any }?
671
- )
672
- local mask = cursor.readu8(c)
673
- local changed_hooks = client.network_hooks.changed
674
- local components = client.components
675
-
676
- local total_tags = read_vlq_bitmask(c, mask, 0)
677
- for _ = 1, total_tags do
678
- local tag = client_replicator.read_component_id(client, c)
679
- local tag_hooks = changed_hooks[PAIR(components.reliable, tag)]
680
- client_replicator.entity_add(client, entity, tag, tag_hooks)
681
- end
682
-
683
- local total_components = read_vlq_bitmask(c, mask, 1)
684
- for _ = 1, total_components do
685
- local component = client_replicator.read_component_id(client, c)
686
- local value = client_replicator.read_component_value(client, component, c, variants)
687
- local component_hooks = changed_hooks[PAIR(components.reliable, component)]
688
- client_replicator.entity_set(client, entity, component, value, component_hooks)
689
- end
690
-
691
- local total_pairs = read_vlq_bitmask(c, mask, 2)
692
- for _ = 1, total_pairs do
693
- client_replicator.process_entity_pair(client, entity, c, custom_ids)
694
- end
695
-
696
- local total_pair_values = read_vlq_bitmask(c, mask, 3)
697
- for _ = 1, total_pair_values do
698
- client_replicator.process_entity_pair_value(client, entity, c, custom_ids, variants)
699
- end
700
-
701
- local total_relations = read_vlq_bitmask(c, mask, 4)
702
- for _ = 1, total_relations do
703
- client_replicator.process_entity_relations(client, entity, c, custom_ids)
704
- end
705
-
706
- local total_relation_values = read_vlq_bitmask(c, mask, 5)
707
- for _ = 1, total_relation_values do
708
- client_replicator.process_entity_relation_values(client, entity, c, custom_ids, variants)
709
- end
710
- end
711
-
712
- function client_replicator.finish_replication(client: Client)
713
- client.is_replicating = false
714
- for _, callback in client.after_replication_callbacks do
715
- callback()
716
- end
717
- table.clear(client.after_replication_callbacks)
718
- end
719
-
720
- function client_replicator.resolve_dirty(client: Client)
721
- if client.is_shared_dirty then
722
- -- stylua: ignore
723
- client.shared = utils.resolved_shared(
724
- client.world,
725
- client.components,
726
- client.registered_custom_ids,
727
- client.component_serdes
728
- )
729
- client.is_shared_dirty = false
730
- end
731
- end
732
-
733
- local function check_packet_type(c: Cursor, expected_byte: number)
734
- local got_byte = cursor.readu8(c)
735
- if got_byte ~= expected_byte then
736
- local got_type: string?
737
- local expected_type: string?
738
-
739
- for packet_type, byte in PACKET_TYPES :: { [string]: number } do
740
- if byte == got_byte then
741
- got_type = packet_type
742
- elseif byte == expected_byte then
743
- expected_type = packet_type
744
- end
745
- end
746
- common.log_error(
747
- `packet type mismatch, expected: {expected_type or "(unknown)"} got: {got_type or "(unknown)"} instead`
748
- )
749
- end
750
- end
751
-
752
- function client_replicator.apply_command_buffer(
753
- client: Client,
754
- entity: Entity,
755
- command_buffer: CommandBuffer,
756
- request: (e: Entity,...any) -> Entity?
757
- )
758
- local components = client.components
759
-
760
- for tag in command_buffer.tags do
761
- local tag_hooks = client.network_hooks.changed[PAIR(components.reliable, tag)]
762
- client_replicator.entity_add(client, entity, tag, tag_hooks)
763
- end
764
- for component, value in command_buffer.components do
765
- local component_hooks = client.network_hooks.changed[PAIR(components.reliable, component)]
766
- client_replicator.entity_set(client, entity, component, value.value, component_hooks)
767
- end
768
- for component, value in command_buffer.unreliable_components do
769
- local component_hooks = client.network_hooks.changed[PAIR(components.unreliable, component)]
770
- client_replicator.entity_set(client, entity, component, value.value, component_hooks)
771
- end
772
- for component in command_buffer.remove do
773
- local component_hooks = client.network_hooks.removed[PAIR(components.reliable, component)]
774
- client_replicator.entity_remove(client, entity, component, component_hooks)
775
- end
776
- for relation, targets in command_buffer.pairs_add do
777
- local relation_hooks = client.network_hooks.changed[PAIR(components.relation, relation)]
778
- for target in targets do
779
- local client_target = request(target)
780
- if client_target then
781
- client_replicator.entity_add_pair(client, entity, relation, client_target, relation_hooks)
782
- end
783
- end
784
- end
785
- for relation, targets in command_buffer.pairs_set do
786
- local relation_hooks = client.network_hooks.changed[PAIR(components.relation, relation)]
787
- for target, value in targets do
788
- local client_target = request(target)
789
- if client_target then
790
- client_replicator.entity_set_pair(client, entity, relation, client_target, value.value, relation_hooks)
791
- end
792
- end
793
- end
794
- for relation, targets in command_buffer.pairs_unprocessed do
795
- -- TODO: respect hooks
796
- for target, unprocessed in targets do
797
- local client_target = request(target)
798
- if client_target then
799
- local processed_value = unprocessed.processed_value
800
- if processed_value then
801
- client_replicator.entity_set_pair(client, entity, relation, client_target, processed_value.value)
802
- else
803
- local value = client_replicator.entity_set_postponed_pair(
804
- client,
805
- entity,
806
- relation,
807
- client_target,
808
- unprocessed.cursor,
809
- unprocessed.variants
810
- )
811
- unprocessed.processed_value = { value = value }
812
- end
813
- end
814
- end
815
- end
816
-
817
- for relation, targets in command_buffer.pairs_remove do
818
- local relation_hooks = client.network_hooks.removed[PAIR(components.relation, relation)]
819
- for target in targets do
820
- local client_target = request(target)
821
- if client_target then
822
- client_replicator.entity_remove_pair(client, entity, relation, client_target, relation_hooks)
823
- end
824
- end
825
- end
826
- for relation in command_buffer.relations_clear do
827
- local relation_hooks = client.network_hooks.removed[PAIR(components.relation, relation)]
828
- client_replicator.entity_clear_relation(client, entity, relation, relation_hooks)
829
- end
830
- end
831
-
832
- function client_replicator.find_component_in_buffer(command_buffer: CommandBuffer, component: Entity): { value: any }?
833
- return command_buffer.components[component] or command_buffer.unreliable_components[component]
834
- end
835
-
836
- function client_replicator.find_has_in_buffer(command_buffer: CommandBuffer, tag: Entity): boolean
837
- return (command_buffer.tags[tag] ~= nil)
838
- or (command_buffer.components[tag] ~= nil)
839
- or (command_buffer.unreliable_components[tag] ~= nil)
840
- end
841
-
842
- function client_replicator.find_pair_in_buffer(
843
- command_buffer: CommandBuffer,
844
- relation: Entity,
845
- target: Entity,
846
- find: (unprocessed_entity: Entity) -> (Entity?, Entity)
847
- ): (boolean, any)
848
- local value_relations = command_buffer.pairs_set[relation]
849
- if value_relations then
850
- for buffer_target, value in value_relations do
851
- local found = find(buffer_target)
852
- if found == target then
853
- return true, value.value
854
- end
855
- end
856
- end
857
-
858
- local relations = command_buffer.pairs_add[relation]
859
- if relations then
860
- for buffer_target in relations do
861
- local found = find(buffer_target)
862
- if found == target then
863
- return true, nil
864
- end
865
- end
866
- end
867
-
868
- local unprocessed_relations = command_buffer.pairs_unprocessed[relation]
869
- if unprocessed_relations then
870
- for buffer_target, unprocessed in unprocessed_relations do
871
- local found = find(buffer_target)
872
- if found == target then
873
- local processed_value = unprocessed.processed_value
874
- return true, processed_value and processed_value.value
875
- end
876
- end
877
- end
878
-
879
- return false, nil
880
- end
881
-
882
- function client_replicator.find_target_in_buffer(
883
- command_buffer: CommandBuffer,
884
- relation: Entity,
885
- index: number?
886
- ): Entity?
887
- local i = 0
888
-
889
- local pairs = command_buffer.pairs_add[relation]
890
- if pairs then
891
- for target in pairs do
892
- if i == (index or 0) then
893
- return target
894
- end
895
- i += 1
896
- end
897
- end
898
-
899
- local pairs_values = command_buffer.pairs_set[relation]
900
- if pairs_values then
901
- for target in pairs_values do
902
- if i == (index or 0) then
903
- return target
904
- end
905
- i += 1
906
- end
907
- end
908
-
909
- local unprocessed_pairs = command_buffer.pairs_unprocessed[relation]
910
- if unprocessed_pairs then
911
- for target in unprocessed_pairs do
912
- if i == (index or 0) then
913
- return target
914
- end
915
- i += 1
916
- end
917
- end
918
-
919
- return nil
920
- end
921
-
922
- function client_replicator.finish_custom_ids(
923
- client: Client,
924
- custom_ids: CustomIdMap,
925
- command_buffers: { [Entity]: CommandBuffer }
926
- )
927
- local world = client.world
928
- local funcs = {} -- this is so process can use create_context even if its defined after
929
- local processed: { [Entity]: boolean } = {}
930
-
931
- local function find(unprocessed_entity: Entity): (Entity?, Entity)
932
- -- negative entities means they are still server ids that haven't been processed yet
933
- if (unprocessed_entity :: any) > 0 then
934
- return unprocessed_entity, unprocessed_entity
935
- end
936
- local server_entity = -(unprocessed_entity :: any)
937
- local client_entity = client.server_ids[server_entity]
938
- if client_entity then
939
- return client_entity, server_entity
940
- end
941
- return nil, server_entity
942
- end
943
-
944
- local function process(unprocessed_entity: Entity, custom_handler: (CustomId | Entity)?): Entity?
945
- local client_entity, server_entity = find(unprocessed_entity)
946
- if client_entity then
947
- return client_entity
948
- end
949
-
950
- if processed[server_entity] then
951
- return nil
952
- end
953
-
954
- local new_entity: Entity?
955
- local command_buffer = command_buffers[unprocessed_entity :: any]
956
- custom_handler = custom_handler or custom_ids[server_entity]
957
-
958
- if type(custom_handler) == "number" then
959
- local component: Entity = custom_handler :: any
960
-
961
- local handler = WORLD_GET(world, component, client.components.custom_handler)
962
- if not handler then
963
- return common.log_error(
964
- `received a custom id for a non custom component, consider adding custom_handler to component: {common.log_component(
965
- world,
966
- component
967
- )}`
968
- )
969
- end
970
- if command_buffer then
971
- local value = client_replicator.find_component_in_buffer(command_buffer, component)
972
- if value then
973
- new_entity = handler(value.value)
974
- else
975
- common.log_warn(`No component found for custom id handler: {common.log_component(world, component)}`)
976
- new_entity = handler(nil)
977
- end
978
- else
979
- common.log_warn(`No component found for custom id handler: {common.log_component(world, component)}`)
980
- new_entity = handler(nil)
981
- end
982
- else
983
- local handle_callback = (custom_handler :: CustomId).handle_callback
984
- if not handle_callback then
985
- return common.log_error(
986
- "no handler callback was set for custom id:",
987
- (custom_handler :: CustomId).identifier
988
- )
989
- end
990
- new_entity = handle_callback(funcs.create_context(unprocessed_entity))
991
- end
992
-
993
- if new_entity then
994
- WORLD_ADD(world, new_entity, client.components.__alive_tracking__)
995
-
996
- client.server_ids[server_entity :: any] = new_entity
997
- client.client_ids[new_entity] = server_entity :: any
998
-
999
- if command_buffer then
1000
- client_replicator.apply_command_buffer(client, new_entity, command_buffer, process)
1001
- command_buffers[unprocessed_entity] = nil
1002
- end
1003
- end
1004
-
1005
- processed[server_entity] = true
1006
- return new_entity
1007
- end
1008
-
1009
- local function create_context(unprocessed_entity: Entity)
1010
- local command_buffer = command_buffers[unprocessed_entity]
1011
-
1012
- local function component(component: Entity): any
1013
- if not command_buffer then
1014
- return nil
1015
- end
1016
- local val = client_replicator.find_component_in_buffer(command_buffer, component)
1017
- return val and val.value
1018
- end
1019
- local function target(relation: Entity, index: number?): Entity
1020
- if not command_buffer then
1021
- return nil :: any
1022
- end
1023
- local server_target = client_replicator.find_target_in_buffer(command_buffer, relation, index)
1024
- if server_target then
1025
- return process(server_target :: any) :: Entity
1026
- end
1027
- return nil :: any
1028
- end
1029
- local function pair_value(relation: Entity, target: Entity): any
1030
- if not command_buffer then
1031
- return nil :: any
1032
- end
1033
- local _, value = client_replicator.find_pair_in_buffer(command_buffer, relation, target, find)
1034
- return value
1035
- end
1036
- local function has_pair(relation: Entity, target: Entity): boolean
1037
- if not command_buffer then
1038
- return nil :: any
1039
- end
1040
- local has = client_replicator.find_pair_in_buffer(command_buffer, relation, target, find)
1041
- return has
1042
- end
1043
- local function has(tag: Entity): boolean
1044
- if not command_buffer then
1045
- return nil :: any
1046
- end
1047
- return client_replicator.find_has_in_buffer(command_buffer, tag)
1048
- end
1049
- local function entity(server_entity: number): Entity
1050
- return process(-server_entity :: any) :: Entity
1051
- end
1052
-
1053
- local context: customid.HandleContext = {
1054
- entity_id = math.abs(unprocessed_entity :: any),
1055
- has = has,
1056
- component = component,
1057
- target = target,
1058
- pair_value = pair_value,
1059
- has_pair = has_pair,
1060
- entity = entity,
1061
- }
1062
-
1063
- return context
1064
- end
1065
- funcs.create_context = create_context
1066
-
1067
- for entity, custom_handler in custom_ids do
1068
- process(-(entity :: any), custom_handler)
1069
- end
1070
-
1071
- for entity, command_buffer in command_buffers do
1072
- if (entity :: any) < 0 then
1073
- continue
1074
- end
1075
- client_replicator.apply_command_buffer(client, entity, command_buffer, process)
1076
- end
1077
- end
1078
-
1079
- function client_replicator.apply_full(client: Client, buf: buffer, all_variants: { { any } }?)
1080
- client_replicator.resolve_dirty(client)
1081
- client.is_replicating = true
1082
-
1083
- local c = cursor.from(buf)
1084
- check_packet_type(c, PACKET_TYPES.full)
1085
-
1086
- local total_packets = cursor.read_vlq(c)
1087
- local variant_start = (all_variants and #all_variants + 1) :: number
1088
-
1089
- local command_buffers: { [Entity]: CommandBuffer } = {}
1090
- local custom_ids: CustomIdMap = {}
1091
-
1092
- client.command_buffers = command_buffers
1093
-
1094
- for a = 1, total_packets do
1095
- local total_entities = cursor.read_vlq(c)
1096
- local variants = all_variants and all_variants[variant_start - a]
1097
-
1098
- for _ = 1, total_entities do
1099
- client_replicator.process_entity_id(client, c, custom_ids, function(entity)
1100
- client_replicator.process_entity(client, entity, c, custom_ids, variants)
1101
- end)
1102
- end
1103
- end
1104
-
1105
- client_replicator.finish_custom_ids(client, custom_ids, command_buffers)
1106
- client_replicator.finish_replication(client)
1107
- end
1108
-
1109
- function client_replicator.apply_entity(client: Client, buf: buffer, all_variants: { { any } })
1110
- client_replicator.resolve_dirty(client)
1111
- client.is_replicating = true
1112
-
1113
- local c = cursor.from(buf)
1114
- check_packet_type(c, PACKET_TYPES.entity)
1115
-
1116
- local total_packets = cursor.read_vlq(c)
1117
- local variant_start = (all_variants and #all_variants + 1) :: number
1118
-
1119
- local command_buffers: { [Entity]: CommandBuffer } = {}
1120
- local custom_ids: CustomIdMap = {}
1121
-
1122
- client.command_buffers = command_buffers
1123
-
1124
- for a = 1, total_packets do
1125
- local variants = all_variants and all_variants[variant_start - a]
1126
-
1127
- client_replicator.process_entity_id(client, c, custom_ids, function(entity)
1128
- client_replicator.process_entity(client, entity, c, custom_ids, variants)
1129
- end)
1130
- end
1131
-
1132
- client_replicator.finish_custom_ids(client, custom_ids, command_buffers)
1133
- client_replicator.finish_replication(client)
1134
- end
1135
-
1136
- function client_replicator.apply_updates(client: Client, buf: buffer, all_variants: { { any } }?)
1137
- client_replicator.resolve_dirty(client)
1138
- client.is_replicating = true
1139
-
1140
- local c = cursor.from(buf)
1141
- check_packet_type(c, PACKET_TYPES.updates)
1142
-
1143
- local world = client.world
1144
- local components = client.components
1145
- local total_packets = cursor.read_vlq(c)
1146
- local variant_start = (all_variants and #all_variants + 1) :: number
1147
- local changed_hooks = client.network_hooks.changed
1148
- local removed_hooks = client.network_hooks.removed
1149
- local deleted_hooks = client.network_hooks.deleted
1150
-
1151
- local command_buffers: { [Entity]: CommandBuffer } = {}
1152
- local custom_ids: CustomIdMap = {}
1153
-
1154
- client.command_buffers = command_buffers
1155
-
1156
- for a = 1, total_packets do
1157
- local variants = all_variants and all_variants[variant_start - a]
1158
- local storage_mask = cursor.readu8(c)
1159
-
1160
- local total_added = read_vlq_bitmask(c, storage_mask, 0)
1161
- for _ = 1, total_added do
1162
- client_replicator.process_entity_id(client, c, custom_ids, function(entity)
1163
- client_replicator.process_entity(client, entity, c, custom_ids, variants)
1164
- end)
1165
- end
1166
-
1167
- local total_components_added = read_vlq_bitmask(c, storage_mask, 1)
1168
- for _ = 1, total_components_added do
1169
- client_replicator.process_entity_id(client, c, custom_ids, function(entity)
1170
- local added_mask = cursor.readu8(c)
1171
-
1172
- local total_tags = read_vlq_bitmask(c, added_mask, 0)
1173
- for _ = 1, total_tags do
1174
- local tag = client_replicator.read_component_id(client, c)
1175
- local tag_hooks = changed_hooks[PAIR(components.reliable, tag)]
1176
- client_replicator.entity_add(client, entity, tag, tag_hooks)
1177
- end
1178
-
1179
- local total_components = read_vlq_bitmask(c, added_mask, 1)
1180
- for _ = 1, total_components do
1181
- local component = client_replicator.read_component_id(client, c)
1182
- local value = client_replicator.read_component_value(client, component, c, variants)
1183
- local component_hooks = changed_hooks[PAIR(components.reliable, component)]
1184
- client_replicator.entity_set(client, entity, component, value, component_hooks)
1185
- end
1186
-
1187
- local total_pairs = read_vlq_bitmask(c, added_mask, 2)
1188
- for _ = 1, total_pairs do
1189
- client_replicator.process_entity_pair(client, entity, c, custom_ids)
1190
- end
1191
-
1192
- local total_pair_values = read_vlq_bitmask(c, added_mask, 3)
1193
- for _ = 1, total_pair_values do
1194
- client_replicator.process_entity_pair_value(client, entity, c, custom_ids, variants)
1195
- end
1196
-
1197
- local total_relations = read_vlq_bitmask(c, added_mask, 4)
1198
- for _ = 1, total_relations do
1199
- client_replicator.process_entity_relations(client, entity, c, custom_ids)
1200
- end
1201
-
1202
- local total_relation_values = read_vlq_bitmask(c, added_mask, 5)
1203
- for _ = 1, total_relation_values do
1204
- client_replicator.process_entity_relation_values(client, entity, c, custom_ids, variants)
1205
- end
1206
- end)
1207
- end
1208
-
1209
- local total_changed = read_vlq_bitmask(c, storage_mask, 2)
1210
- for _ = 1, total_changed do
1211
- client_replicator.process_entity_id(client, c, custom_ids, function(entity)
1212
- local changed_mask = cursor.readu8(c)
1213
-
1214
- local total_tagged = read_vlq_bitmask(c, changed_mask, 0)
1215
- for _ = 1, total_tagged do
1216
- local tag = client_replicator.read_component_id(client, c)
1217
- local tag_hooks = changed_hooks[PAIR(components.reliable, tag)]
1218
- client_replicator.entity_add(client, entity, tag, tag_hooks)
1219
- end
1220
-
1221
- local total_components = read_vlq_bitmask(c, changed_mask, 1)
1222
- for _ = 1, total_components do
1223
- local component = client_replicator.read_component_id(client, c)
1224
- local value = client_replicator.read_component_value(client, component, c, variants)
1225
- local component_hooks = changed_hooks[PAIR(components.reliable, component)]
1226
- client_replicator.entity_set(client, entity, component, value, component_hooks)
1227
- end
1228
-
1229
- local total_removed = read_vlq_bitmask(c, changed_mask, 2)
1230
- for _ = 1, total_removed do
1231
- local component = client_replicator.read_component_id(client, c)
1232
- local component_hooks = removed_hooks[PAIR(components.reliable, component)]
1233
- client_replicator.entity_remove(client, entity, component, component_hooks)
1234
- end
1235
-
1236
- local total_pairs_added = read_vlq_bitmask(c, changed_mask, 3)
1237
- for _ = 1, total_pairs_added do
1238
- client_replicator.process_entity_pair(client, entity, c, custom_ids)
1239
- end
1240
-
1241
- local total_pairs_set = read_vlq_bitmask(c, changed_mask, 4)
1242
- for _ = 1, total_pairs_set do
1243
- client_replicator.process_entity_pair_value(client, entity, c, custom_ids, variants)
1244
- end
1245
-
1246
- local total_pairs_removed = read_vlq_bitmask(c, changed_mask, 5)
1247
- for _ = 1, total_pairs_removed do
1248
- local relation = client_replicator.read_component_id(client, c)
1249
- client_replicator.process_entity_id(client, c, custom_ids, function(target)
1250
- -- TODO: respect hooks/overrides
1251
- client_replicator.entity_remove_pair(client, entity, relation, target)
1252
- end)
1253
- end
1254
-
1255
- local total_relations_added = read_vlq_bitmask(c, changed_mask, 6)
1256
- for _ = 1, total_relations_added do
1257
- local relation = client_replicator.read_component_id(client, c)
1258
- local total_targets = cursor.read_vlq(c)
1259
- local pair_changed_hooks = changed_hooks[PAIR(components.relation, relation)]
1260
-
1261
- for _ = 1, total_targets do
1262
- client_replicator.process_entity_id(client, c, custom_ids, function(target)
1263
- client_replicator.entity_add_pair(client, entity, relation, target, pair_changed_hooks)
1264
- end)
1265
- end
1266
- end
1267
-
1268
- local total_relation_values = read_vlq_bitmask(c, changed_mask, 7)
1269
- for _ = 1, total_relation_values do
1270
- local relation = client_replicator.read_component_id(client, c)
1271
- local total_targets = cursor.read_vlq(c)
1272
- local pair_changed_hooks = changed_hooks[PAIR(components.relation, relation)]
1273
-
1274
- for _ = 1, total_targets do
1275
- local value = client_replicator.read_component_value(client, relation, c, variants)
1276
- client_replicator.process_entity_id(client, c, custom_ids, function(target)
1277
- client_replicator.entity_set_pair(client, entity, relation, target, value, pair_changed_hooks)
1278
- end)
1279
- end
1280
- end
1281
-
1282
- -- using a normal vlq here sadly
1283
- -- cause I ran out of bitmask space for this one :/
1284
- local total_relations_removed = cursor.read_vlq(c)
1285
- for _ = 1, total_relations_removed do
1286
- local relation = client_replicator.read_component_id(client, c)
1287
- local total_targets = cursor.read_vlq(c)
1288
- local pair_removed_hooks = removed_hooks[PAIR(components.relation, relation)]
1289
-
1290
- for _ = 1, total_targets do
1291
- client_replicator.process_entity_id(client, c, custom_ids, function(target)
1292
- client_replicator.entity_remove_pair(client, entity, relation, target, pair_removed_hooks)
1293
- end)
1294
- end
1295
- end
1296
- end)
1297
- end
1298
-
1299
- local total_component_deletions = read_vlq_bitmask(c, storage_mask, 3)
1300
- for _ = 1, total_component_deletions do
1301
- client_replicator.process_entity_id(client, c, custom_ids, function(entity)
1302
- local total_components = cursor.read_vlq(c)
1303
- for _ = 1, total_components do
1304
- local component = client_replicator.read_component_id(client, c)
1305
- local component_hooks = removed_hooks[PAIR(components.reliable, component)]
1306
- client_replicator.entity_remove(client, entity, component, component_hooks)
1307
- end
1308
-
1309
- local total_pairs = cursor.read_vlq(c)
1310
- for _ = 1, total_pairs do
1311
- local relation = client_replicator.read_component_id(client, c)
1312
- client_replicator.process_entity_id(client, c, custom_ids, function(target)
1313
- -- TODO: respect hooks/overrides
1314
- client_replicator.entity_remove_pair(client, entity, relation, target)
1315
- end)
1316
- end
1317
-
1318
- local total_relations = cursor.read_vlq(c)
1319
- for _ = 1, total_relations do
1320
- local relation = client_replicator.read_component_id(client, c)
1321
- local pair_hooks = removed_hooks[PAIR(components.relation, relation)]
1322
- client_replicator.entity_clear_relation(client, entity, relation, pair_hooks)
1323
- end
1324
- end)
1325
- end
1326
-
1327
- local total_deleted = read_vlq_bitmask(c, storage_mask, 4)
1328
- for _ = 1, total_deleted do
1329
- local entity, server_id = client_replicator.read_entity_id(client, c)
1330
- if entity then
1331
- local deleted_hook = deleted_hooks[entity]
1332
- if deleted_hook then
1333
- for _, callback in deleted_hook.callbacks do
1334
- callback(entity)
1335
- end
1336
- if not deleted_hook.overrides then
1337
- WORLD_DELETE(world, entity)
1338
- end
1339
- else
1340
- WORLD_DELETE(world, entity)
1341
- end
1342
- end
1343
- if server_id then
1344
- client.server_ids[server_id] = nil
1345
- end
1346
- end
1347
- end
1348
-
1349
- client_replicator.finish_custom_ids(client, custom_ids, command_buffers)
1350
- client_replicator.finish_replication(client)
1351
- end
1352
-
1353
- function client_replicator.apply_unreliable(client: Client, buf: buffer, all_variants: { { any } }?)
1354
- client_replicator.resolve_dirty(client)
1355
- client.is_replicating = true
1356
-
1357
- local c = cursor.from(buf)
1358
- check_packet_type(c, PACKET_TYPES.unreliable)
1359
-
1360
- local components = client.components
1361
- local total_packets = cursor.read_vlq(c)
1362
- local variant_start = (all_variants and #all_variants + 1) :: number
1363
- local changed_hooks = client.network_hooks.changed
1364
-
1365
- for a = 1, total_packets do
1366
- local total_entities = cursor.read_vlq(c)
1367
- local variants = all_variants and all_variants[variant_start - a]
1368
-
1369
- for _ = 1, total_entities do
1370
- local entity = client_replicator.read_entity_id(client, c)
1371
- local total_unreliable = cursor.read_vlq(c)
1372
-
1373
- if entity then
1374
- for _ = 1, total_unreliable do
1375
- local component = client_replicator.read_component_id(client, c)
1376
- local value = client_replicator.read_component_value(client, component, c, variants)
1377
-
1378
- local unreliable_hooks = changed_hooks[PAIR(components.unreliable, component)]
1379
- client_replicator.entity_set_unreliable(client, entity, component, value, unreliable_hooks)
1380
- end
1381
- else
1382
- -- dont apply unreliable updates to entities that dont exist in the client yet
1383
- -- but we still need to process the values to keep the cursor in the right place
1384
- for _ = 1, total_unreliable do
1385
- local component = client_replicator.read_component_id(client, c)
1386
- client_replicator.read_component_value(client, component, c, variants)
1387
- end
1388
- end
1389
- end
1390
- end
1391
-
1392
- client_replicator.finish_replication(client)
1393
- end
1394
-
1395
- function client_replicator.set_serdes(client: Client, component: Component, serdes: types.Serdes)
1396
- client.component_serdes[component] = serdes
1397
- client.is_shared_dirty = true
1398
- end
1399
-
1400
- function client_replicator.remove_serdes(client: Client, component: Component)
1401
- client.component_serdes[component] = nil
1402
- client.is_shared_dirty = true
1403
- end
1404
-
1405
- -- TODO: Deserialize pairs in client
1406
-
1407
- function client_replicator.init(client: Client, wrd: World?)
1408
- if client.inited == true then
1409
- return warn "attempted to init a client twice"
1410
- end
1411
- if client.inited == nil then
1412
- return warn "attempted to re-init a destroyed client"
1413
- end
1414
- client.inited = true :: any
1415
-
1416
- local world = wrd or client.world
1417
- client.world = world
1418
-
1419
- if not world then
1420
- error "Providing a world is required to start replecs"
1421
- end
1422
-
1423
- if not client.components then
1424
- client.components = utils.create_components(utils.tag_factory(world), utils.component_factory(world))
1425
- utils.add_component_names(client.components, function(component, name)
1426
- common.add_name(world, component, name)
1427
- end)
1428
- end
1429
-
1430
- local components = client.components
1431
-
1432
- local function hook(unhook: () -> ())
1433
- table.insert(client.hooked, unhook)
1434
- end
1435
-
1436
- hook(HOOK_REMOVED(world, components.__alive_tracking__, function(entity)
1437
- local server_id = client.client_ids[entity]
1438
- if server_id then
1439
- client.server_ids[server_id] = nil
1440
- client.client_ids[entity] = nil
1441
- end
1442
- client.network_hooks.deleted[entity] = nil
1443
- end))
1444
-
1445
- hook(HOOK_ADDED(world, components.serdes, function(component, _, serdes)
1446
- client_replicator.set_serdes(client, component, serdes)
1447
- end))
1448
- hook(HOOK_CHANGED(world, components.serdes, function(component, _, serdes)
1449
- client_replicator.set_serdes(client, component, serdes)
1450
- end))
1451
- hook(HOOK_REMOVED(world, components.serdes, function(component)
1452
- client_replicator.remove_serdes(client, component)
1453
- end))
1454
-
1455
- for _, component in client.requires_shared_lookup do
1456
- hook(HOOK_ADDED(world, component, function()
1457
- client.is_shared_dirty = true
1458
- end))
1459
- hook(HOOK_REMOVED(world, component, function()
1460
- client.is_shared_dirty = true
1461
- end))
1462
- end
1463
-
1464
- QUERY_CURRENT_COMPONENTS(client)
1465
-
1466
- client.shared = utils.resolved_shared(world, components, client.registered_custom_ids, client.component_serdes)
1467
- end
1468
-
1469
- function client_replicator.after_replication(client: Client, callback: () -> ())
1470
- if client.is_replicating then
1471
- table.insert(client.after_replication_callbacks, callback)
1472
- else
1473
- callback()
1474
- end
1475
- end
1476
-
1477
- function client_replicator.added(client: Client, callback: (entity: Entity) -> ())
1478
- table.insert(client.addition_hooks, callback)
1479
- return function()
1480
- local index = table.find(client.addition_hooks, callback)
1481
- if index then
1482
- table.remove(client.addition_hooks, index)
1483
- end
1484
- end
1485
- end
1486
-
1487
- local function add_hook_entry(client: Client, action: string, ...): ({ overrides: boolean }, () -> ())
1488
- if action == "changed" or action == "removed" then
1489
- local relation = select(1, ...) :: Entity
1490
- local callback = select(2, ...) :: (entity: Entity, id: Component, value: any) -> ()
1491
- local hooks = action == "changed" and client.network_hooks.changed or client.network_hooks.removed
1492
- local entries = hooks[relation] :: ChangedHooksEntry
1493
-
1494
- if not entries then
1495
- entries = {
1496
- overrides = false,
1497
- callbacks = {},
1498
- }
1499
- hooks[relation] = entries
1500
- end
1501
- table.insert(entries.callbacks, callback)
1502
-
1503
- local function disconnect()
1504
- local callbacks = entries.callbacks
1505
- local index = table.find(callbacks, callback)
1506
- if index then
1507
- table.remove(callbacks, index)
1508
- if #callbacks == 0 then
1509
- hooks[relation] = nil
1510
- end
1511
- end
1512
- end
1513
- return entries, disconnect
1514
- elseif action == "deleted" then
1515
- local entity = select(1, ...) :: Entity
1516
- local callback = select(2, ...) :: (entity: Entity) -> ()
1517
- local hooks = client.network_hooks.deleted
1518
- local entries = hooks[entity]
1519
-
1520
- if not entries then
1521
- entries = {
1522
- overrides = false,
1523
- callbacks = {},
1524
- }
1525
- hooks[entity] = entries
1526
- end
1527
- table.insert(entries.callbacks, callback)
1528
-
1529
- local function disconnect()
1530
- local callbacks = entries.callbacks
1531
- local index = table.find(callbacks, callback)
1532
- if index then
1533
- table.remove(callbacks, index)
1534
- if #callbacks == 0 then
1535
- hooks[entity] = nil
1536
- end
1537
- end
1538
- end
1539
- return entries, disconnect
1540
- else
1541
- error("invalid hook action: " .. action)
1542
- end
1543
- end
1544
-
1545
- function client_replicator.hook(client: Client, action: string, ...)
1546
- local entry, disconnect = add_hook_entry(client, action, ...)
1547
- entry.overrides = false
1548
- return disconnect
1549
- end
1550
- function client_replicator.override(client: Client, action: string, ...)
1551
- local entry, disconnect = add_hook_entry(client, action, ...)
1552
- entry.overrides = true
1553
- return disconnect
1554
- end
1555
-
1556
- function client_replicator.encode_component(client: Client, component: Entity): number
1557
- client_replicator.resolve_dirty(client)
1558
- local encoded = client.shared.components.members[component]
1559
- if not encoded then
1560
- common.log_error(`attempted to encode a non-shared component `, common.log_component(client.world, component))
1561
- return 0
1562
- end
1563
- return encoded
1564
- end
1565
-
1566
- function client_replicator.decode_component(client: Client, encoded: number): Entity
1567
- client_replicator.resolve_dirty(client)
1568
- local component = client.shared.components.indexes[encoded]
1569
- if not component then
1570
- print("NON SHARED COMPONENT", encoded, client.shared.components)
1571
- error "attemped to decode a non shared component"
1572
- end
1573
- return component
1574
- end
1575
-
1576
- function client_replicator.get_shared_count(client: Client): number
1577
- client_replicator.resolve_dirty(client)
1578
- return #client.shared.components.keys
1579
- end
1580
-
1581
- function client_replicator.get_server_entity(client: Client, client_entity: Entity): number?
1582
- return client.client_ids[client_entity]
1583
- end
1584
-
1585
- function client_replicator.get_client_entity(client: Client, client_entity: number): Entity?
1586
- return client.server_ids[client_entity]
1587
- end
1588
-
1589
- function client_replicator.register_entity(client: Client, entity: Entity, server_entity: number)
1590
- client.server_ids[server_entity] = entity
1591
- client.client_ids[entity] = server_entity
1592
- WORLD_ADD(client.world, entity, client.components.__alive_tracking__)
1593
- end
1594
-
1595
- function client_replicator.unregister_entity(client: Client, entity: Entity)
1596
- local server_id = client.client_ids[entity]
1597
- if server_id then
1598
- client.server_ids[server_id] = nil
1599
- client.client_ids[entity] = nil
1600
- end
1601
- end
1602
-
1603
- function client_replicator.register_custom_id(client: Client, custom_id: CustomId)
1604
- client.registered_custom_ids[custom_id] = true
1605
- client.is_shared_dirty = true
1606
- end
1607
-
1608
- function client_replicator.generate_handshake(client: Client): types.HandshakeInfo
1609
- client_replicator.resolve_dirty(client)
1610
- return utils.generate_handshake(client.shared)
1611
- end
1612
-
1613
- function client_replicator.verify_handshake(client: Client, handshake: types.HandshakeInfo): (boolean, string?)
1614
- client_replicator.resolve_dirty(client)
1615
- return utils.verify_handshake(client.shared, handshake, "server", "client")
1616
- end
1617
-
1618
- function client_replicator.destroy(client: Client)
1619
- if client.inited == nil then
1620
- return warn "attempted to destroy a client twice"
1621
- end
1622
- client.inited = nil :: any
1623
- for _, unhook in client.hooked do
1624
- unhook()
1625
- end
1626
- end
1627
-
1628
- function client_replicator.handle_global(client: Client, handler: (id: number) -> Entity)
1629
- client.global_handler = handler
1630
- end
1631
-
1632
- local function create(world: World?, components: types.Components?): Client
1633
- local self = {} :: Client
1634
-
1635
- if components then
1636
- self.components = components
1637
- elseif world then
1638
- self.components = utils.create_components(utils.tag_factory(world), utils.component_factory(world))
1639
- utils.add_component_names(self.components, function(component, name)
1640
- common.add_name(world, component, name)
1641
- end)
1642
- end
1643
-
1644
- self.server_ids = {}
1645
- self.client_ids = {}
1646
- self.is_shared_dirty = false
1647
- self.component_serdes = {}
1648
- self.requires_shared_lookup = {
1649
- self.components.shared,
1650
- ECS_NAME,
1651
- }
1652
- self.global_handler = nil
1653
- self.world = world :: any
1654
- self.inited = false
1655
- self.is_replicating = false
1656
- self.hooked = {}
1657
- self.registered_custom_ids = {}
1658
-
1659
- self.addition_hooks = {}
1660
- self.network_hooks = {
1661
- deleted = {},
1662
- changed = {},
1663
- removed = {},
1664
- }
1665
- self.after_replication_callbacks = {}
1666
-
1667
- return setmetatable(self, client_replicator) :: any
1668
- end
1669
-
1670
- return {
1671
- create = create,
1672
- client_replicator = client_replicator,
1673
- }