@rbxts/replecs 0.1.0-alpha9 → 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.
- package/out/replecs/client.luau +790 -280
- package/out/replecs/common.luau +40 -23
- package/out/replecs/customid.luau +39 -0
- package/out/replecs/index.d.ts +109 -15
- package/out/replecs/init.luau +45 -17
- package/out/replecs/masking/init.luau +38 -34
- package/out/replecs/masking/mask_generator.luau +1 -1
- package/out/replecs/server.luau +530 -267
- package/out/replecs/utils.luau +183 -30
- package/out/replecs/ver.luau +2 -0
- package/package.json +1 -1
- package/out/replecs/masking/filter_group.luau +0 -1
package/out/replecs/client.luau
CHANGED
|
@@ -3,10 +3,13 @@
|
|
|
3
3
|
|
|
4
4
|
local jecs = require "../jecs"
|
|
5
5
|
local common = require "./common"
|
|
6
|
+
local customid = require "./customid"
|
|
6
7
|
local utils = require "./utils"
|
|
7
8
|
|
|
8
9
|
local cursor = utils.cursor
|
|
10
|
+
|
|
9
11
|
type Cursor = utils.Cursor
|
|
12
|
+
type CustomId = customid.CustomId
|
|
10
13
|
|
|
11
14
|
type Entity<T = any> = jecs.Entity<T>
|
|
12
15
|
type Id<T = any> = jecs.Id<T>
|
|
@@ -14,8 +17,20 @@ type World = jecs.World
|
|
|
14
17
|
|
|
15
18
|
type Array<T> = { T }
|
|
16
19
|
type Map<K, V> = { [K]: V }
|
|
20
|
+
type Set<T> = { [T]: boolean }
|
|
17
21
|
type Disconnect = () -> ()
|
|
18
22
|
|
|
23
|
+
type CommandBuffer = {
|
|
24
|
+
tags: { [Entity]: boolean },
|
|
25
|
+
components: { [Entity]: { value: any } },
|
|
26
|
+
unreliable_components: { [Entity]: { value: any } },
|
|
27
|
+
remove: { [Entity]: boolean },
|
|
28
|
+
pairs: { [Entity]: Set<Entity> },
|
|
29
|
+
pairs_values: { [Entity]: { [Entity]: { value: any } } },
|
|
30
|
+
pairs_remove: { [Entity]: Set<Entity> },
|
|
31
|
+
pairs_clear: Set<Entity>,
|
|
32
|
+
}
|
|
33
|
+
|
|
19
34
|
type HookMethod =
|
|
20
35
|
& ((
|
|
21
36
|
self: Client,
|
|
@@ -39,6 +54,8 @@ type DeletedHookEntry = {
|
|
|
39
54
|
callbacks: Array<(entity: Entity) -> ()>,
|
|
40
55
|
}
|
|
41
56
|
|
|
57
|
+
type CustomIdMap = { [Entity]: CustomId | Entity }
|
|
58
|
+
|
|
42
59
|
export type Client = {
|
|
43
60
|
world: World,
|
|
44
61
|
inited: boolean?,
|
|
@@ -46,7 +63,7 @@ export type Client = {
|
|
|
46
63
|
is_replicating: boolean,
|
|
47
64
|
after_replication_callbacks: { () -> () },
|
|
48
65
|
|
|
49
|
-
|
|
66
|
+
is_shared_dirty: boolean,
|
|
50
67
|
requires_shared_lookup: { Entity },
|
|
51
68
|
components: common.Components,
|
|
52
69
|
shared: common.Shared,
|
|
@@ -54,7 +71,9 @@ export type Client = {
|
|
|
54
71
|
server_ids: { [number]: Entity },
|
|
55
72
|
client_ids: { [Entity]: number },
|
|
56
73
|
ordered_creation: boolean,
|
|
57
|
-
|
|
74
|
+
registered_custom_ids: { [CustomId]: boolean },
|
|
75
|
+
command_buffers: { [Entity]: CommandBuffer }?,
|
|
76
|
+
command_buffers_active: boolean,
|
|
58
77
|
|
|
59
78
|
init: (self: Client, world: World?) -> (),
|
|
60
79
|
destroy: (self: Client) -> (),
|
|
@@ -62,6 +81,9 @@ export type Client = {
|
|
|
62
81
|
get_server_entity: (self: Client, client_entity: Entity) -> number?,
|
|
63
82
|
get_client_entity: (self: Client, server_entity: number) -> Entity?,
|
|
64
83
|
|
|
84
|
+
register_entity: (self: Client, entity: Entity, server_entity: number) -> (),
|
|
85
|
+
unregister_entity: (self: Client, entity: Entity) -> (),
|
|
86
|
+
|
|
65
87
|
hooks: common.WorldHooks,
|
|
66
88
|
hooked: Array<() -> ()>,
|
|
67
89
|
|
|
@@ -78,17 +100,26 @@ export type Client = {
|
|
|
78
100
|
|
|
79
101
|
encode_component: (self: Client, component: Entity) -> number,
|
|
80
102
|
decode_component: (self: Client, component: number) -> Entity,
|
|
103
|
+
register_custom_id: (self: Client, custom_id: CustomId) -> (),
|
|
81
104
|
|
|
82
105
|
apply_updates: (self: Client, buf: buffer, all_variants: { { any } }?) -> (),
|
|
83
106
|
apply_unreliable: (self: Client, buf: buffer, all_variants: { { any } }?) -> (),
|
|
84
107
|
apply_full: (self: Client, buf: buffer, all_variants: { { any } }?) -> (),
|
|
108
|
+
|
|
109
|
+
generate_handshake: (self: Client) -> common.HandshakeInfo,
|
|
110
|
+
verify_handshake: (self: Client, handshake: common.HandshakeInfo) -> (boolean, string?),
|
|
85
111
|
}
|
|
86
112
|
|
|
113
|
+
local client_replicator = {}
|
|
114
|
+
client_replicator.__index = client_replicator
|
|
115
|
+
|
|
87
116
|
local GLOBAL_ID_OFFSET = 10
|
|
117
|
+
|
|
88
118
|
local ENTITY_ID_TYPES = {
|
|
89
119
|
entity = 1,
|
|
90
|
-
|
|
91
|
-
|
|
120
|
+
custom_handler = 2,
|
|
121
|
+
custom_id = 3,
|
|
122
|
+
shared = 4,
|
|
92
123
|
}
|
|
93
124
|
local PACKET_TYPES = {
|
|
94
125
|
full = 1,
|
|
@@ -96,7 +127,6 @@ local PACKET_TYPES = {
|
|
|
96
127
|
reliable = 3,
|
|
97
128
|
}
|
|
98
129
|
|
|
99
|
-
local ECS_NAME = jecs.Name
|
|
100
130
|
local WILDCARD = jecs.Wildcard
|
|
101
131
|
|
|
102
132
|
local function PAIR(first: Entity, second: Entity): Entity
|
|
@@ -122,20 +152,97 @@ local function get_or_create_entity(client: Client, server_id: number): Entity
|
|
|
122
152
|
end
|
|
123
153
|
end
|
|
124
154
|
|
|
125
|
-
local function
|
|
126
|
-
|
|
127
|
-
|
|
155
|
+
local function get_command_buffer(client: Client, entity: Entity): CommandBuffer
|
|
156
|
+
local command_buffers = client.command_buffers
|
|
157
|
+
|
|
158
|
+
if not command_buffers then
|
|
159
|
+
error "attempted to use a command buffer without having one. (this should never happen)"
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
local command_buffer = command_buffers[entity :: any]
|
|
163
|
+
if not command_buffer then
|
|
164
|
+
command_buffer = {
|
|
165
|
+
tags = {},
|
|
166
|
+
components = {},
|
|
167
|
+
unreliable_components = {},
|
|
168
|
+
remove = {},
|
|
169
|
+
pairs = {},
|
|
170
|
+
pairs_values = {},
|
|
171
|
+
pairs_remove = {},
|
|
172
|
+
pairs_clear = {},
|
|
173
|
+
}
|
|
174
|
+
command_buffers[entity :: any] = command_buffer
|
|
175
|
+
end
|
|
176
|
+
return command_buffer
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
function client_replicator.entity_set(
|
|
180
|
+
client: Client,
|
|
181
|
+
entity: Entity,
|
|
182
|
+
id: Id,
|
|
183
|
+
value: any,
|
|
184
|
+
changed_hooks: ChangedHooksEntry?
|
|
185
|
+
)
|
|
186
|
+
if client.command_buffers_active then
|
|
187
|
+
local command_buffer = get_command_buffer(client, entity)
|
|
188
|
+
command_buffer.components[id] = { value = value }
|
|
189
|
+
else
|
|
190
|
+
if changed_hooks then
|
|
191
|
+
if not changed_hooks.overrides then
|
|
192
|
+
client.world:set(entity, id, value)
|
|
193
|
+
end
|
|
194
|
+
for _, callback in changed_hooks.callbacks do
|
|
195
|
+
callback(entity, id, value)
|
|
196
|
+
end
|
|
197
|
+
else
|
|
128
198
|
client.world:set(entity, id, value)
|
|
129
199
|
end
|
|
130
|
-
|
|
131
|
-
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
function client_replicator.entity_set_unreliable(
|
|
204
|
+
client: Client,
|
|
205
|
+
entity: Entity,
|
|
206
|
+
component: Entity,
|
|
207
|
+
value: any,
|
|
208
|
+
changed_hooks: ChangedHooksEntry?
|
|
209
|
+
)
|
|
210
|
+
if client.command_buffers_active then
|
|
211
|
+
local command_buffer = get_command_buffer(client, entity)
|
|
212
|
+
command_buffer.unreliable_components[component] = value
|
|
213
|
+
else
|
|
214
|
+
client_replicator.entity_set(client, entity, component, value, changed_hooks)
|
|
215
|
+
end
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
function client_replicator.entity_set_pair(
|
|
219
|
+
client: Client,
|
|
220
|
+
entity: Entity,
|
|
221
|
+
relation: Entity,
|
|
222
|
+
target: Entity,
|
|
223
|
+
value: any,
|
|
224
|
+
changed_hooks: ChangedHooksEntry?
|
|
225
|
+
)
|
|
226
|
+
if client.command_buffers_active then
|
|
227
|
+
local command_buffer = get_command_buffer(client, entity)
|
|
228
|
+
local pair_relation = command_buffer.pairs_values[relation]
|
|
229
|
+
|
|
230
|
+
if pair_relation then
|
|
231
|
+
pair_relation[target] = { value = value }
|
|
232
|
+
else
|
|
233
|
+
command_buffer.pairs_values[relation] = { [target] = value }
|
|
132
234
|
end
|
|
133
235
|
else
|
|
134
|
-
|
|
236
|
+
client_replicator.entity_set(client, entity, PAIR(relation, target), value, changed_hooks)
|
|
135
237
|
end
|
|
136
238
|
end
|
|
137
239
|
|
|
138
|
-
|
|
240
|
+
function client_replicator.entity_add(
|
|
241
|
+
client: Client,
|
|
242
|
+
entity: Entity,
|
|
243
|
+
component: Entity,
|
|
244
|
+
changed_hooks: ChangedHooksEntry?
|
|
245
|
+
)
|
|
139
246
|
if changed_hooks then
|
|
140
247
|
if not changed_hooks.overrides then
|
|
141
248
|
client.world:add(entity, component)
|
|
@@ -148,77 +255,129 @@ local function network_entity_add(client: Client, entity: Entity, component: Ent
|
|
|
148
255
|
end
|
|
149
256
|
end
|
|
150
257
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
258
|
+
function client_replicator.entity_add_pair(
|
|
259
|
+
client: Client,
|
|
260
|
+
entity: Entity,
|
|
261
|
+
relation: Entity,
|
|
262
|
+
target: Entity,
|
|
263
|
+
changed_hooks: ChangedHooksEntry?
|
|
264
|
+
)
|
|
265
|
+
if client.command_buffers_active then
|
|
266
|
+
local command_buffer = get_command_buffer(client, entity)
|
|
267
|
+
local pair_relation = command_buffer.pairs[relation]
|
|
268
|
+
|
|
269
|
+
if pair_relation then
|
|
270
|
+
pair_relation[target] = true
|
|
271
|
+
else
|
|
272
|
+
command_buffer.pairs[relation] = { [target] = true }
|
|
155
273
|
end
|
|
156
|
-
|
|
274
|
+
else
|
|
275
|
+
client_replicator.entity_add(client, entity, PAIR(relation, target), changed_hooks)
|
|
276
|
+
end
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
function client_replicator.entity_remove(client: Client, entity: Entity, id: Entity, removed_hooks: RemovedHooksEntry?)
|
|
280
|
+
if client.command_buffers_active then
|
|
281
|
+
local command_buffer = get_command_buffer(client, entity)
|
|
282
|
+
command_buffer.remove[id] = true
|
|
283
|
+
else
|
|
284
|
+
if removed_hooks then
|
|
285
|
+
for _, callback in removed_hooks.callbacks do
|
|
286
|
+
callback(entity, id)
|
|
287
|
+
end
|
|
288
|
+
if not removed_hooks.overrides then
|
|
289
|
+
client.world:remove(entity, id)
|
|
290
|
+
end
|
|
291
|
+
else
|
|
157
292
|
client.world:remove(entity, id)
|
|
158
293
|
end
|
|
159
|
-
else
|
|
160
|
-
client.world:remove(entity, id)
|
|
161
294
|
end
|
|
162
295
|
end
|
|
163
296
|
|
|
164
|
-
|
|
297
|
+
function client_replicator.entity_remove_pair(
|
|
165
298
|
client: Client,
|
|
166
299
|
entity: Entity,
|
|
167
300
|
relation: Entity,
|
|
301
|
+
target: Entity,
|
|
168
302
|
removed_hooks: RemovedHooksEntry?
|
|
169
303
|
)
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
304
|
+
if client.command_buffers_active then
|
|
305
|
+
local command_buffer = get_command_buffer(client, entity)
|
|
306
|
+
local pair_relation = command_buffer.pairs_remove[relation]
|
|
307
|
+
|
|
308
|
+
if pair_relation then
|
|
309
|
+
pair_relation[target] = true
|
|
310
|
+
else
|
|
311
|
+
command_buffer.pairs_remove[relation] = { [target] = true }
|
|
312
|
+
end
|
|
313
|
+
else
|
|
314
|
+
client_replicator.entity_remove(client, entity, PAIR(relation, target), removed_hooks)
|
|
174
315
|
end
|
|
175
|
-
|
|
316
|
+
end
|
|
176
317
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
318
|
+
function client_replicator.entity_remove_relations(
|
|
319
|
+
client: Client,
|
|
320
|
+
entity: Entity,
|
|
321
|
+
relation: Entity,
|
|
322
|
+
removed_hooks: RemovedHooksEntry?
|
|
323
|
+
)
|
|
324
|
+
if client.command_buffers_active then
|
|
325
|
+
local command_buffer = get_command_buffer(client, entity)
|
|
326
|
+
command_buffer.pairs_clear[relation] = true
|
|
327
|
+
else
|
|
328
|
+
local world = client.world
|
|
329
|
+
local entity_index = jecs.entity_index_try_get_fast(world.entity_index :: any, entity :: any)
|
|
330
|
+
if not entity_index then
|
|
331
|
+
return
|
|
332
|
+
end
|
|
333
|
+
local archetype = entity_index.archetype
|
|
182
334
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
335
|
+
local wildcard = PAIR(relation, WILDCARD) :: any
|
|
336
|
+
local idr = world.component_index[wildcard]
|
|
337
|
+
if not idr then
|
|
338
|
+
return
|
|
339
|
+
end
|
|
188
340
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
341
|
+
local archetype_id = archetype.id
|
|
342
|
+
local count = idr.counts[archetype_id]
|
|
343
|
+
if not count then
|
|
344
|
+
return
|
|
345
|
+
end
|
|
193
346
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
347
|
+
local start = idr.records[archetype_id]
|
|
348
|
+
if not start then
|
|
349
|
+
return
|
|
350
|
+
end
|
|
351
|
+
|
|
352
|
+
if removed_hooks then
|
|
353
|
+
for i = start, start + count - 1 do
|
|
354
|
+
local pair = archetype.types[i]
|
|
355
|
+
for _, callback in removed_hooks.callbacks do
|
|
356
|
+
callback(entity, pair)
|
|
357
|
+
end
|
|
358
|
+
if not removed_hooks.overrides then
|
|
359
|
+
world:remove(entity, pair :: any)
|
|
360
|
+
end
|
|
199
361
|
end
|
|
200
|
-
|
|
362
|
+
else
|
|
363
|
+
for i = start, start + count - 1 do
|
|
364
|
+
local pair = archetype.types[i]
|
|
201
365
|
world:remove(entity, pair :: any)
|
|
202
366
|
end
|
|
203
367
|
end
|
|
204
|
-
else
|
|
205
|
-
for i = start, start + count - 1 do
|
|
206
|
-
local pair = archetype.types[i]
|
|
207
|
-
world:remove(entity, pair :: any)
|
|
208
|
-
end
|
|
209
368
|
end
|
|
210
369
|
end
|
|
211
370
|
|
|
212
|
-
|
|
213
|
-
local encoded = client.shared.
|
|
371
|
+
function client_replicator.encode_component(client: Client, component: Entity): number
|
|
372
|
+
local encoded = client.shared.components.members[component]
|
|
214
373
|
if not encoded then
|
|
215
374
|
utils.logerror(`attempted to encode a non-shared component `, utils.logcomponent(client.world, component))
|
|
216
375
|
return 0
|
|
217
376
|
end
|
|
218
377
|
return encoded
|
|
219
378
|
end
|
|
220
|
-
|
|
221
|
-
local component = client.shared.components[encoded]
|
|
379
|
+
function client_replicator.decode_component(client: Client, encoded: number): Entity
|
|
380
|
+
local component = client.shared.components.indexes[encoded]
|
|
222
381
|
if not component then
|
|
223
382
|
print("NON SHARED COMPONENT", encoded, client.shared.components)
|
|
224
383
|
error "attemped to decode a non shared component"
|
|
@@ -226,9 +385,10 @@ local function decode_component(client: Client, encoded: number): Entity
|
|
|
226
385
|
return component
|
|
227
386
|
end
|
|
228
387
|
|
|
229
|
-
|
|
230
|
-
local
|
|
231
|
-
local
|
|
388
|
+
function client_replicator.read_component_id(client: Client, c: Cursor): Entity
|
|
389
|
+
local shared_components = client.shared.components
|
|
390
|
+
local shared_id = cursor.read_span(c, #shared_components.keys)
|
|
391
|
+
local component = shared_components.indexes[shared_id]
|
|
232
392
|
if not component then
|
|
233
393
|
print("NON SHARED COMPONENT", shared_id, client.shared.components)
|
|
234
394
|
error "received a non shared component"
|
|
@@ -236,11 +396,11 @@ local function read_component_id(client: Client, c: Cursor): Entity
|
|
|
236
396
|
return component
|
|
237
397
|
end
|
|
238
398
|
|
|
239
|
-
|
|
399
|
+
function client_replicator.read_component_value(client: Client, component: Entity, c: Cursor, variants: { any }?): any
|
|
240
400
|
local serdes = client.shared.serdes[component]
|
|
241
401
|
|
|
242
402
|
if serdes then
|
|
243
|
-
local bytespan =
|
|
403
|
+
local bytespan = serdes.bytespan or cursor.read_vlq(c)
|
|
244
404
|
|
|
245
405
|
local appended = cursor.read_buffer(c, bytespan)
|
|
246
406
|
local serdes_variants: { any }? = nil
|
|
@@ -266,13 +426,13 @@ local function read_component_value(client: Client, component: Entity, c: Cursor
|
|
|
266
426
|
end
|
|
267
427
|
end
|
|
268
428
|
|
|
269
|
-
|
|
270
|
-
local component = read_component_id(client, c)
|
|
271
|
-
local value = read_component_value(client, component, c, variants)
|
|
429
|
+
function client_replicator.read_component(client: Client, c: Cursor, variants: { any }?): (Entity, any)
|
|
430
|
+
local component = client_replicator.read_component_id(client, c)
|
|
431
|
+
local value = client_replicator.read_component_value(client, component, c, variants)
|
|
272
432
|
return component, value
|
|
273
433
|
end
|
|
274
434
|
|
|
275
|
-
|
|
435
|
+
function client_replicator.resolve_global(client: Client, global_id: number): Entity
|
|
276
436
|
if not client.global_handler then
|
|
277
437
|
error "global id parser not set, consider using client:handle_global()"
|
|
278
438
|
end
|
|
@@ -280,99 +440,145 @@ local function resolve_global(client: Client, global_id: number): Entity
|
|
|
280
440
|
return parsed
|
|
281
441
|
end
|
|
282
442
|
|
|
283
|
-
|
|
443
|
+
-- returns entity, server_id, id_type
|
|
444
|
+
function client_replicator.read_entity_id(client: Client, c: Cursor): (Entity?, number?, number?)
|
|
284
445
|
local id_type = cursor.readu8(c)
|
|
285
446
|
|
|
286
447
|
if id_type <= GLOBAL_ID_OFFSET then
|
|
287
|
-
if
|
|
448
|
+
if
|
|
449
|
+
id_type == ENTITY_ID_TYPES.entity
|
|
450
|
+
or id_type == ENTITY_ID_TYPES.custom_id
|
|
451
|
+
or id_type == ENTITY_ID_TYPES.custom_handler
|
|
452
|
+
then
|
|
288
453
|
local server_id = cursor.readu40(c)
|
|
289
|
-
return client.server_ids[server_id], server_id
|
|
290
|
-
elseif id_type == ENTITY_ID_TYPES.custom then
|
|
291
|
-
local component, value = read_component(client, c, variants)
|
|
292
|
-
local custom_getter = client.custom_ids[component]
|
|
293
|
-
if not custom_getter then
|
|
294
|
-
error(
|
|
295
|
-
`received a custom id for a non custom component, consider adding custom_id to component: {client.world:get(
|
|
296
|
-
component,
|
|
297
|
-
ECS_NAME
|
|
298
|
-
) or "(no name)"} id: {component}`
|
|
299
|
-
)
|
|
300
|
-
end
|
|
301
|
-
return custom_getter(value), nil
|
|
454
|
+
return client.server_ids[server_id], server_id, id_type
|
|
302
455
|
elseif id_type == ENTITY_ID_TYPES.shared then
|
|
303
|
-
return read_component_id(client, c), nil
|
|
456
|
+
return client_replicator.read_component_id(client, c), nil, id_type
|
|
304
457
|
end
|
|
305
|
-
error(`malformed entity
|
|
458
|
+
error(`malformed entity type {id_type} ` .. cursor.readu32(c))
|
|
306
459
|
else
|
|
307
|
-
return resolve_global(client, id_type - GLOBAL_ID_OFFSET), nil
|
|
460
|
+
return client_replicator.resolve_global(client, id_type - GLOBAL_ID_OFFSET), nil, id_type
|
|
308
461
|
end
|
|
309
462
|
end
|
|
310
463
|
|
|
311
|
-
|
|
312
|
-
|
|
464
|
+
function client_replicator.process_entity_id(
|
|
465
|
+
client: Client,
|
|
466
|
+
c: Cursor,
|
|
467
|
+
custom_ids: CustomIdMap,
|
|
468
|
+
process: (entity: Entity) -> ()
|
|
469
|
+
)
|
|
470
|
+
local entity, server_id, id_type = client_replicator.read_entity_id(client, c)
|
|
471
|
+
|
|
313
472
|
if entity then
|
|
314
|
-
|
|
473
|
+
-- skip customid, keep cursor offset
|
|
474
|
+
if id_type == ENTITY_ID_TYPES.custom_id then
|
|
475
|
+
client_replicator.read_component_id(client, c)
|
|
476
|
+
elseif id_type == ENTITY_ID_TYPES.custom_handler then
|
|
477
|
+
cursor.readu8(c)
|
|
478
|
+
end
|
|
479
|
+
|
|
480
|
+
return process(entity)
|
|
315
481
|
else
|
|
316
|
-
|
|
482
|
+
if id_type == ENTITY_ID_TYPES.custom_id or id_type == ENTITY_ID_TYPES.custom_handler then
|
|
483
|
+
if id_type == ENTITY_ID_TYPES.custom_id then
|
|
484
|
+
local component_id = client_replicator.read_component_id(client, c)
|
|
485
|
+
custom_ids[server_id :: any] = component_id
|
|
486
|
+
elseif id_type == ENTITY_ID_TYPES.custom_handler then
|
|
487
|
+
local shared_custom_id = cursor.readu8(c)
|
|
488
|
+
local handler = client.shared.custom_ids.indexes[shared_custom_id]
|
|
489
|
+
|
|
490
|
+
if not handler then
|
|
491
|
+
utils.logerror "attempted to use a custom id that wasn't registered"
|
|
492
|
+
end
|
|
493
|
+
custom_ids[server_id :: any] = handler
|
|
494
|
+
end
|
|
495
|
+
|
|
496
|
+
if client.command_buffers_active then
|
|
497
|
+
-- negative id means it's a custom id,
|
|
498
|
+
-- it needs to be translated first
|
|
499
|
+
process(-server_id :: any)
|
|
500
|
+
else
|
|
501
|
+
client.command_buffers_active = true
|
|
502
|
+
process(-server_id :: any)
|
|
503
|
+
client.command_buffers_active = false
|
|
504
|
+
end
|
|
505
|
+
else
|
|
506
|
+
local new_entity = get_or_create_entity(client, server_id :: number)
|
|
507
|
+
process(new_entity)
|
|
508
|
+
end
|
|
317
509
|
end
|
|
318
510
|
end
|
|
319
511
|
|
|
320
|
-
|
|
512
|
+
function client_replicator.process_entity_relations(
|
|
513
|
+
client: Client,
|
|
514
|
+
entity: jecs.Entity,
|
|
515
|
+
c: Cursor,
|
|
516
|
+
custom_ids: CustomIdMap
|
|
517
|
+
)
|
|
321
518
|
local components = client.components
|
|
322
|
-
local relation = read_component_id(client, c)
|
|
519
|
+
local relation = client_replicator.read_component_id(client, c)
|
|
323
520
|
local total_targets = cursor.read_vlq(c)
|
|
324
521
|
local pair_hooks = client.network_hooks.changed[PAIR(components.pair, relation)]
|
|
325
522
|
|
|
326
523
|
for _ = 1, total_targets do
|
|
327
|
-
|
|
328
|
-
|
|
524
|
+
client_replicator.process_entity_id(client, c, custom_ids, function(target)
|
|
525
|
+
client_replicator.entity_add_pair(client, entity, relation, target, pair_hooks)
|
|
526
|
+
end)
|
|
329
527
|
end
|
|
330
528
|
end
|
|
331
529
|
|
|
332
|
-
|
|
333
|
-
|
|
530
|
+
function client_replicator.process_entity_relation_values(
|
|
531
|
+
client: Client,
|
|
532
|
+
entity: jecs.Entity,
|
|
533
|
+
c: Cursor,
|
|
534
|
+
custom_ids: CustomIdMap,
|
|
535
|
+
variants: { any }?
|
|
536
|
+
)
|
|
537
|
+
local relation = client_replicator.read_component_id(client, c)
|
|
334
538
|
local total_targets = cursor.read_vlq(c)
|
|
335
539
|
local components = client.components
|
|
336
540
|
local pair_hooks = client.network_hooks.changed[PAIR(components.pair, relation)]
|
|
337
541
|
|
|
338
542
|
for _ = 1, total_targets do
|
|
339
|
-
local value = read_component_value(client, relation, c, variants)
|
|
340
|
-
|
|
341
|
-
|
|
543
|
+
local value = client_replicator.read_component_value(client, relation, c, variants)
|
|
544
|
+
client_replicator.process_entity_id(client, c, custom_ids, function(target)
|
|
545
|
+
client_replicator.entity_set_pair(client, entity, relation, target, value, pair_hooks)
|
|
546
|
+
end)
|
|
342
547
|
end
|
|
343
548
|
end
|
|
344
549
|
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
550
|
+
function client_replicator.process_entity(client: Client, c: Cursor, custom_ids: CustomIdMap, variants: { any }?)
|
|
551
|
+
client_replicator.process_entity_id(client, c, custom_ids, function(entity)
|
|
552
|
+
local changed_hooks = client.network_hooks.changed
|
|
553
|
+
local components = client.components
|
|
349
554
|
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
555
|
+
local total_tags = cursor.read_vlq(c)
|
|
556
|
+
for _ = 1, total_tags do
|
|
557
|
+
local tag = client_replicator.read_component_id(client, c)
|
|
558
|
+
local tag_hooks = changed_hooks[PAIR(components.reliable, tag)]
|
|
559
|
+
client_replicator.entity_add(client, entity, tag, tag_hooks)
|
|
560
|
+
end
|
|
356
561
|
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
562
|
+
local total_components = cursor.read_vlq(c)
|
|
563
|
+
for _ = 1, total_components do
|
|
564
|
+
local component, value = client_replicator.read_component(client, c, variants)
|
|
565
|
+
local component_hooks = changed_hooks[PAIR(components.reliable, component)]
|
|
566
|
+
client_replicator.entity_set(client, entity, component, value, component_hooks)
|
|
567
|
+
end
|
|
363
568
|
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
569
|
+
local total_pairs = cursor.read_vlq(c)
|
|
570
|
+
for _ = 1, total_pairs do
|
|
571
|
+
client_replicator.process_entity_relations(client, entity, c, custom_ids)
|
|
572
|
+
end
|
|
368
573
|
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
574
|
+
local total_pairs_values = cursor.read_vlq(c)
|
|
575
|
+
for _ = 1, total_pairs_values do
|
|
576
|
+
client_replicator.process_entity_relation_values(client, entity, c, custom_ids, variants)
|
|
577
|
+
end
|
|
578
|
+
end)
|
|
373
579
|
end
|
|
374
580
|
|
|
375
|
-
|
|
581
|
+
function client_replicator.finish_replication(client: Client)
|
|
376
582
|
client.is_replicating = false
|
|
377
583
|
for _, callback in client.after_replication_callbacks do
|
|
378
584
|
callback()
|
|
@@ -380,10 +586,10 @@ local function finish_replication(client: Client)
|
|
|
380
586
|
table.clear(client.after_replication_callbacks)
|
|
381
587
|
end
|
|
382
588
|
|
|
383
|
-
|
|
384
|
-
if client.
|
|
385
|
-
client.shared = utils.
|
|
386
|
-
client.
|
|
589
|
+
function client_replicator.resolve_dirty(client: Client)
|
|
590
|
+
if client.is_shared_dirty then
|
|
591
|
+
client.shared = utils.resolved_shared(client.world, client.components, client.registered_custom_ids)
|
|
592
|
+
client.is_shared_dirty = false :: true -- wtf
|
|
387
593
|
end
|
|
388
594
|
end
|
|
389
595
|
|
|
@@ -411,10 +617,287 @@ local function read_vlq_bitmask(c: Cursor, mask: number, bit: number): number
|
|
|
411
617
|
end
|
|
412
618
|
end
|
|
413
619
|
|
|
414
|
-
|
|
620
|
+
function client_replicator.apply_command_buffer(
|
|
621
|
+
client: Client,
|
|
622
|
+
entity: Entity,
|
|
623
|
+
command_buffer: CommandBuffer,
|
|
624
|
+
request: (e: Entity, ...any) -> Entity?
|
|
625
|
+
)
|
|
626
|
+
local components = client.components
|
|
627
|
+
|
|
628
|
+
for tag in command_buffer.tags do
|
|
629
|
+
local tag_hooks = client.network_hooks.changed[PAIR(components.reliable, tag)]
|
|
630
|
+
client_replicator.entity_add(client, entity, tag, tag_hooks)
|
|
631
|
+
end
|
|
632
|
+
for component, value in command_buffer.components do
|
|
633
|
+
local component_hooks = client.network_hooks.changed[PAIR(components.reliable, component)]
|
|
634
|
+
client_replicator.entity_set(client, entity, component, value, component_hooks)
|
|
635
|
+
end
|
|
636
|
+
for component, value in command_buffer.unreliable_components do
|
|
637
|
+
local component_hooks = client.network_hooks.changed[PAIR(components.unreliable, component)]
|
|
638
|
+
client_replicator.entity_set(client, entity, component, value, component_hooks)
|
|
639
|
+
end
|
|
640
|
+
for component in command_buffer.remove do
|
|
641
|
+
local component_hooks = client.network_hooks.removed[PAIR(components.reliable, component)]
|
|
642
|
+
client_replicator.entity_remove(client, entity, component, component_hooks)
|
|
643
|
+
end
|
|
644
|
+
for relation, targets in command_buffer.pairs do
|
|
645
|
+
local pair_hooks = client.network_hooks.changed[PAIR(components.pair, relation)]
|
|
646
|
+
for target in targets do
|
|
647
|
+
local client_target = request(target)
|
|
648
|
+
if client_target then
|
|
649
|
+
client_replicator.entity_add_pair(client, entity, relation, client_target, pair_hooks)
|
|
650
|
+
end
|
|
651
|
+
end
|
|
652
|
+
end
|
|
653
|
+
for relation, targets in command_buffer.pairs_values do
|
|
654
|
+
local pair_hooks = client.network_hooks.changed[PAIR(components.pair, relation)]
|
|
655
|
+
for target, value in targets do
|
|
656
|
+
local client_target = request(target)
|
|
657
|
+
if client_target then
|
|
658
|
+
client_replicator.entity_set_pair(client, entity, relation, client_target, value.value, pair_hooks)
|
|
659
|
+
end
|
|
660
|
+
end
|
|
661
|
+
end
|
|
662
|
+
for relation, targets in command_buffer.pairs_remove do
|
|
663
|
+
local pair_hooks = client.network_hooks.removed[PAIR(components.pair, relation)]
|
|
664
|
+
for target in targets do
|
|
665
|
+
local client_target = request(target)
|
|
666
|
+
if client_target then
|
|
667
|
+
client_replicator.entity_remove_pair(client, entity, relation, client_target, pair_hooks)
|
|
668
|
+
end
|
|
669
|
+
end
|
|
670
|
+
end
|
|
671
|
+
for relation in command_buffer.pairs_clear do
|
|
672
|
+
local pair_hooks = client.network_hooks.removed[PAIR(components.pair, relation)]
|
|
673
|
+
client_replicator.entity_remove_relations(client, entity, relation, pair_hooks)
|
|
674
|
+
end
|
|
675
|
+
end
|
|
676
|
+
|
|
677
|
+
function client_replicator.find_component_in_buffer(command_buffer: CommandBuffer, component: Entity): { value: any }?
|
|
678
|
+
return command_buffer.components[component] or command_buffer.unreliable_components[component]
|
|
679
|
+
end
|
|
680
|
+
|
|
681
|
+
function client_replicator.find_has_in_buffer(command_buffer: CommandBuffer, tag: Entity): boolean
|
|
682
|
+
return (command_buffer.tags[tag] ~= nil)
|
|
683
|
+
or (command_buffer.components[tag] ~= nil)
|
|
684
|
+
or (command_buffer.unreliable_components[tag] ~= nil)
|
|
685
|
+
end
|
|
686
|
+
function client_replicator.find_pair_in_buffer(
|
|
687
|
+
command_buffer: CommandBuffer,
|
|
688
|
+
relation: Entity,
|
|
689
|
+
target: Entity,
|
|
690
|
+
find: (unprocessed_entity: Entity) -> (Entity?, Entity)
|
|
691
|
+
): (boolean, any)
|
|
692
|
+
local value_relations = command_buffer.pairs_values[relation]
|
|
693
|
+
|
|
694
|
+
if value_relations then
|
|
695
|
+
for unprocessed_target, value in value_relations do
|
|
696
|
+
local found = find(unprocessed_target)
|
|
697
|
+
if found == target then
|
|
698
|
+
return true, value.value
|
|
699
|
+
end
|
|
700
|
+
end
|
|
701
|
+
end
|
|
702
|
+
|
|
703
|
+
local relations = command_buffer.pairs[relation]
|
|
704
|
+
if relations then
|
|
705
|
+
for unprocessed_target in relations do
|
|
706
|
+
local found = find(unprocessed_target)
|
|
707
|
+
if found == target then
|
|
708
|
+
return true, nil
|
|
709
|
+
end
|
|
710
|
+
end
|
|
711
|
+
end
|
|
712
|
+
return false, nil
|
|
713
|
+
end
|
|
714
|
+
|
|
715
|
+
function client_replicator.find_target_in_buffer(
|
|
716
|
+
command_buffer: CommandBuffer,
|
|
717
|
+
relation: Entity,
|
|
718
|
+
index: number?
|
|
719
|
+
): Entity?
|
|
720
|
+
local i = 0
|
|
721
|
+
|
|
722
|
+
local pairs = command_buffer.pairs[relation]
|
|
723
|
+
if pairs then
|
|
724
|
+
for target in pairs do
|
|
725
|
+
if i == (index or 0) then
|
|
726
|
+
return target
|
|
727
|
+
end
|
|
728
|
+
i += 1
|
|
729
|
+
end
|
|
730
|
+
end
|
|
731
|
+
local pairs_values = command_buffer.pairs_values[relation]
|
|
732
|
+
if pairs_values then
|
|
733
|
+
for target in pairs_values do
|
|
734
|
+
if i == (index or 0) then
|
|
735
|
+
return target
|
|
736
|
+
end
|
|
737
|
+
i += 1
|
|
738
|
+
end
|
|
739
|
+
end
|
|
740
|
+
return nil
|
|
741
|
+
end
|
|
742
|
+
|
|
743
|
+
function client_replicator.finish_custom_ids(
|
|
744
|
+
client: Client,
|
|
745
|
+
custom_ids: CustomIdMap,
|
|
746
|
+
command_buffers: { [Entity]: CommandBuffer }
|
|
747
|
+
)
|
|
748
|
+
local funcs = {} -- this is so process can use create_context even if its defined after
|
|
749
|
+
local processed: { [Entity]: boolean } = {}
|
|
750
|
+
|
|
751
|
+
local function find(unprocessed_entity: Entity): (Entity?, Entity)
|
|
752
|
+
-- negative entities means they are still server ids that haven't been processed yet
|
|
753
|
+
if (unprocessed_entity :: any) > 0 then
|
|
754
|
+
return unprocessed_entity, unprocessed_entity
|
|
755
|
+
end
|
|
756
|
+
local server_entity = -(unprocessed_entity :: any)
|
|
757
|
+
local client_entity = client.server_ids[server_entity]
|
|
758
|
+
if client_entity then
|
|
759
|
+
return client_entity, server_entity
|
|
760
|
+
end
|
|
761
|
+
return nil, server_entity
|
|
762
|
+
end
|
|
763
|
+
|
|
764
|
+
local function process(unprocessed_entity: Entity, custom_handler: (CustomId | Entity)?): Entity?
|
|
765
|
+
local client_entity, server_entity = find(unprocessed_entity)
|
|
766
|
+
if client_entity then
|
|
767
|
+
return client_entity
|
|
768
|
+
end
|
|
769
|
+
|
|
770
|
+
if processed[server_entity] then
|
|
771
|
+
return nil
|
|
772
|
+
end
|
|
773
|
+
|
|
774
|
+
local new_entity: Entity? = nil
|
|
775
|
+
local command_buffer = command_buffers[unprocessed_entity :: any]
|
|
776
|
+
custom_handler = custom_handler or custom_ids[server_entity]
|
|
777
|
+
|
|
778
|
+
if type(custom_handler) == "number" then
|
|
779
|
+
local component: Entity = custom_handler :: any
|
|
780
|
+
|
|
781
|
+
local handler = client.world:get(component, client.components.custom_handler)
|
|
782
|
+
if not handler then
|
|
783
|
+
return utils.logerror(
|
|
784
|
+
`received a custom id for a non custom component, consider adding custom_handler to component: {utils.logcomponent(
|
|
785
|
+
client.world,
|
|
786
|
+
component
|
|
787
|
+
)}`
|
|
788
|
+
)
|
|
789
|
+
end
|
|
790
|
+
if command_buffer then
|
|
791
|
+
local value = client_replicator.find_component_in_buffer(command_buffer, component)
|
|
792
|
+
if value then
|
|
793
|
+
new_entity = handler(value.value)
|
|
794
|
+
else
|
|
795
|
+
utils.logwarn(
|
|
796
|
+
`No component found for custom id handler: {utils.logcomponent(client.world, component)}`
|
|
797
|
+
)
|
|
798
|
+
new_entity = handler(nil)
|
|
799
|
+
end
|
|
800
|
+
else
|
|
801
|
+
utils.logwarn(`No component found for custom id handler: {utils.logcomponent(client.world, component)}`)
|
|
802
|
+
new_entity = handler(nil)
|
|
803
|
+
end
|
|
804
|
+
else
|
|
805
|
+
local handle_callback = (custom_handler :: CustomId).handle_callback
|
|
806
|
+
if not handle_callback then
|
|
807
|
+
return utils.logerror(
|
|
808
|
+
"no handler callback was set for custom id:",
|
|
809
|
+
(custom_handler :: CustomId).identifier
|
|
810
|
+
)
|
|
811
|
+
end
|
|
812
|
+
new_entity = handle_callback(funcs.create_context(unprocessed_entity))
|
|
813
|
+
end
|
|
814
|
+
|
|
815
|
+
if new_entity then
|
|
816
|
+
client.server_ids[server_entity :: any] = new_entity
|
|
817
|
+
if command_buffer then
|
|
818
|
+
client_replicator.apply_command_buffer(client, new_entity, command_buffer, process)
|
|
819
|
+
command_buffers[unprocessed_entity] = nil
|
|
820
|
+
end
|
|
821
|
+
end
|
|
822
|
+
|
|
823
|
+
processed[server_entity] = true
|
|
824
|
+
return new_entity
|
|
825
|
+
end
|
|
826
|
+
|
|
827
|
+
local function create_context(unprocessed_entity: Entity)
|
|
828
|
+
local command_buffer = command_buffers[unprocessed_entity]
|
|
829
|
+
|
|
830
|
+
local function component(component: Entity): any
|
|
831
|
+
if not command_buffer then
|
|
832
|
+
return nil
|
|
833
|
+
end
|
|
834
|
+
local val = client_replicator.find_component_in_buffer(command_buffer, component)
|
|
835
|
+
return val and val.value
|
|
836
|
+
end
|
|
837
|
+
local function target(relation: Entity, index: number?): Entity
|
|
838
|
+
if not command_buffer then
|
|
839
|
+
return nil :: any
|
|
840
|
+
end
|
|
841
|
+
local server_target = client_replicator.find_target_in_buffer(command_buffer, relation, index)
|
|
842
|
+
if server_target then
|
|
843
|
+
return process(server_target :: any) :: Entity
|
|
844
|
+
end
|
|
845
|
+
return nil :: any
|
|
846
|
+
end
|
|
847
|
+
local function pair_value(relation: Entity, target: Entity): any
|
|
848
|
+
if not command_buffer then
|
|
849
|
+
return nil :: any
|
|
850
|
+
end
|
|
851
|
+
local _, value = client_replicator.find_pair_in_buffer(command_buffer, relation, target, find)
|
|
852
|
+
return value
|
|
853
|
+
end
|
|
854
|
+
local function has_pair(relation: Entity, target: Entity): boolean
|
|
855
|
+
if not command_buffer then
|
|
856
|
+
return nil :: any
|
|
857
|
+
end
|
|
858
|
+
local has = client_replicator.find_pair_in_buffer(command_buffer, relation, target, find)
|
|
859
|
+
return has
|
|
860
|
+
end
|
|
861
|
+
local function has(tag: Entity): boolean
|
|
862
|
+
if not command_buffer then
|
|
863
|
+
return nil :: any
|
|
864
|
+
end
|
|
865
|
+
return client_replicator.find_has_in_buffer(command_buffer, tag)
|
|
866
|
+
end
|
|
867
|
+
local function entity(server_entity: number): Entity
|
|
868
|
+
return process(-server_entity :: any) :: Entity
|
|
869
|
+
end
|
|
870
|
+
|
|
871
|
+
local context: customid.HandleContext = {
|
|
872
|
+
entity_id = math.abs(unprocessed_entity :: any),
|
|
873
|
+
has = has,
|
|
874
|
+
component = component,
|
|
875
|
+
target = target,
|
|
876
|
+
pair_value = pair_value,
|
|
877
|
+
has_pair = has_pair,
|
|
878
|
+
entity = entity,
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
return context
|
|
882
|
+
end
|
|
883
|
+
funcs.create_context = create_context
|
|
884
|
+
|
|
885
|
+
for entity, custom_handler in custom_ids do
|
|
886
|
+
process(-(entity :: any), custom_handler)
|
|
887
|
+
end
|
|
888
|
+
|
|
889
|
+
for entity, command_buffer in command_buffers do
|
|
890
|
+
if (entity :: any) < 0 then
|
|
891
|
+
continue
|
|
892
|
+
end
|
|
893
|
+
client_replicator.apply_command_buffer(client, entity, command_buffer, process)
|
|
894
|
+
end
|
|
895
|
+
end
|
|
896
|
+
|
|
897
|
+
function client_replicator.apply_updates(client: Client, buf: buffer, all_variants: { { any } }?)
|
|
415
898
|
local c = cursor.from(buf)
|
|
416
899
|
check_packet_type(c, "reliable")
|
|
417
|
-
resolve_dirty(client)
|
|
900
|
+
client_replicator.resolve_dirty(client)
|
|
418
901
|
client.is_replicating = true
|
|
419
902
|
|
|
420
903
|
local components = client.components
|
|
@@ -424,143 +907,156 @@ local function apply_updates(client: Client, buf: buffer, all_variants: { { any
|
|
|
424
907
|
local removed_hooks = client.network_hooks.removed
|
|
425
908
|
local deleted_hooks = client.network_hooks.deleted
|
|
426
909
|
|
|
910
|
+
local command_buffers: { [Entity]: CommandBuffer } = {}
|
|
911
|
+
local custom_ids: CustomIdMap = {}
|
|
912
|
+
|
|
913
|
+
client.command_buffers = command_buffers
|
|
914
|
+
|
|
427
915
|
for a = 1, total_packets do
|
|
428
916
|
local variants = all_variants and all_variants[variant_start - a]
|
|
429
917
|
local storage_mask = cursor.readu8(c)
|
|
430
918
|
|
|
431
919
|
local total_added = read_vlq_bitmask(c, storage_mask, 0)
|
|
432
920
|
for _ = 1, total_added do
|
|
433
|
-
process_entity(client, c, variants)
|
|
921
|
+
client_replicator.process_entity(client, c, custom_ids, variants)
|
|
434
922
|
end
|
|
435
923
|
|
|
436
924
|
local total_components_added = read_vlq_bitmask(c, storage_mask, 1)
|
|
437
925
|
for _ = 1, total_components_added do
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
926
|
+
client_replicator.process_entity_id(client, c, custom_ids, function(entity)
|
|
927
|
+
local added_mask = cursor.readu8(c)
|
|
928
|
+
|
|
929
|
+
local total_tags = read_vlq_bitmask(c, added_mask, 0)
|
|
930
|
+
for _ = 1, total_tags do
|
|
931
|
+
local tag = client_replicator.read_component_id(client, c)
|
|
932
|
+
local tag_hooks = changed_hooks[PAIR(components.reliable, tag)]
|
|
933
|
+
client_replicator.entity_add(client, entity, tag, tag_hooks)
|
|
934
|
+
end
|
|
447
935
|
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
936
|
+
local total_components = read_vlq_bitmask(c, added_mask, 1)
|
|
937
|
+
for _ = 1, total_components do
|
|
938
|
+
local component, value = client_replicator.read_component(client, c, variants)
|
|
939
|
+
local component_hooks = changed_hooks[PAIR(components.reliable, component)]
|
|
940
|
+
client_replicator.entity_set(client, entity, component, value, component_hooks)
|
|
941
|
+
end
|
|
454
942
|
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
943
|
+
local total_pairs = read_vlq_bitmask(c, added_mask, 2)
|
|
944
|
+
for _ = 1, total_pairs do
|
|
945
|
+
client_replicator.process_entity_relations(client, entity, c, custom_ids)
|
|
946
|
+
end
|
|
459
947
|
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
948
|
+
local total_pairs_values = read_vlq_bitmask(c, added_mask, 3)
|
|
949
|
+
for _ = 1, total_pairs_values do
|
|
950
|
+
client_replicator.process_entity_relation_values(client, entity, c, custom_ids, variants)
|
|
951
|
+
end
|
|
952
|
+
end)
|
|
464
953
|
end
|
|
465
954
|
|
|
466
955
|
local total_changed = read_vlq_bitmask(c, storage_mask, 2)
|
|
467
956
|
for _ = 1, total_changed do
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
957
|
+
client_replicator.process_entity_id(client, c, custom_ids, function(entity)
|
|
958
|
+
local changed_mask = cursor.readu8(c)
|
|
959
|
+
|
|
960
|
+
local total_tagged = read_vlq_bitmask(c, changed_mask, 0)
|
|
961
|
+
for _ = 1, total_tagged do
|
|
962
|
+
local tag = client_replicator.read_component_id(client, c)
|
|
963
|
+
local tag_hooks = changed_hooks[PAIR(components.reliable, tag)]
|
|
964
|
+
client_replicator.entity_add(client, entity, tag, tag_hooks)
|
|
965
|
+
end
|
|
966
|
+
|
|
967
|
+
local total_components = read_vlq_bitmask(c, changed_mask, 1)
|
|
968
|
+
for _ = 1, total_components do
|
|
969
|
+
local component, value = client_replicator.read_component(client, c, variants)
|
|
970
|
+
local component_hooks = changed_hooks[PAIR(components.reliable, component)]
|
|
971
|
+
client_replicator.entity_set(client, entity, component, value, component_hooks)
|
|
972
|
+
end
|
|
973
|
+
|
|
974
|
+
local total_removed = read_vlq_bitmask(c, changed_mask, 2)
|
|
975
|
+
for _ = 1, total_removed do
|
|
976
|
+
local component = client_replicator.read_component_id(client, c)
|
|
977
|
+
local component_hooks = removed_hooks[PAIR(components.reliable, component)]
|
|
978
|
+
client_replicator.entity_remove(client, entity, component, component_hooks)
|
|
979
|
+
end
|
|
980
|
+
|
|
981
|
+
local total_pairs = read_vlq_bitmask(c, changed_mask, 3)
|
|
982
|
+
for _ = 1, total_pairs do
|
|
983
|
+
local relation = client_replicator.read_component_id(client, c)
|
|
984
|
+
local pair_changed_hooks = changed_hooks[PAIR(components.pair, relation)]
|
|
985
|
+
local pair_removed_hooks = removed_hooks[PAIR(components.pair, relation)]
|
|
986
|
+
local total_targets = cursor.read_vlq(c)
|
|
987
|
+
|
|
988
|
+
for _ = 1, total_targets do
|
|
989
|
+
local action_type = cursor.readi8(c)
|
|
990
|
+
|
|
991
|
+
if action_type == 1 then -- add pair
|
|
992
|
+
client_replicator.process_entity_id(client, c, custom_ids, function(target)
|
|
993
|
+
client_replicator.entity_add_pair(client, entity, relation, target, pair_changed_hooks)
|
|
994
|
+
end)
|
|
995
|
+
elseif action_type == -1 then -- remove pair
|
|
996
|
+
client_replicator.process_entity_id(client, c, custom_ids, function(target)
|
|
997
|
+
client_replicator.entity_remove_pair(
|
|
998
|
+
client,
|
|
999
|
+
entity,
|
|
1000
|
+
relation,
|
|
1001
|
+
target,
|
|
1002
|
+
pair_removed_hooks
|
|
1003
|
+
)
|
|
1004
|
+
end)
|
|
509
1005
|
end
|
|
510
1006
|
end
|
|
511
1007
|
end
|
|
512
|
-
end
|
|
513
1008
|
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
1009
|
+
local total_pairs_values_removed = read_vlq_bitmask(c, changed_mask, 4)
|
|
1010
|
+
for _ = 1, total_pairs_values_removed do
|
|
1011
|
+
local relation = client_replicator.read_component_id(client, c)
|
|
1012
|
+
local pair_hooks = removed_hooks[PAIR(components.pair, relation)]
|
|
1013
|
+
local total_targets = cursor.read_vlq(c)
|
|
519
1014
|
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
1015
|
+
for _ = 1, total_targets do
|
|
1016
|
+
client_replicator.process_entity_id(client, c, custom_ids, function(target)
|
|
1017
|
+
client_replicator.entity_remove_pair(client, entity, relation, target, pair_hooks)
|
|
1018
|
+
end)
|
|
524
1019
|
end
|
|
525
1020
|
end
|
|
526
|
-
end
|
|
527
1021
|
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
1022
|
+
local total_pairs_values = read_vlq_bitmask(c, changed_mask, 5)
|
|
1023
|
+
for _ = 1, total_pairs_values do
|
|
1024
|
+
local relation = client_replicator.read_component_id(client, c)
|
|
1025
|
+
local pair_hooks = changed_hooks[PAIR(components.pair, relation)]
|
|
1026
|
+
local total_targets = cursor.read_vlq(c)
|
|
1027
|
+
|
|
1028
|
+
for _ = 1, total_targets do
|
|
1029
|
+
local value = client_replicator.read_component_value(client, relation, c, variants)
|
|
1030
|
+
client_replicator.process_entity_id(client, c, custom_ids, function(target)
|
|
1031
|
+
client_replicator.entity_set_pair(client, entity, relation, target, value, pair_hooks)
|
|
1032
|
+
end)
|
|
1033
|
+
end
|
|
538
1034
|
end
|
|
539
|
-
end
|
|
1035
|
+
end)
|
|
540
1036
|
end
|
|
541
1037
|
|
|
542
1038
|
local total_component_deletions = read_vlq_bitmask(c, storage_mask, 3)
|
|
543
1039
|
for _ = 1, total_component_deletions do
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
end
|
|
1040
|
+
client_replicator.process_entity_id(client, c, custom_ids, function(entity)
|
|
1041
|
+
local total_removed = cursor.read_vlq(c)
|
|
1042
|
+
for _ = 1, total_removed do
|
|
1043
|
+
local component = client_replicator.read_component_id(client, c)
|
|
1044
|
+
local component_hooks = removed_hooks[PAIR(components.reliable, component)]
|
|
1045
|
+
client_replicator.entity_remove(client, entity, component, component_hooks)
|
|
1046
|
+
end
|
|
552
1047
|
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
1048
|
+
local total_pairs = cursor.read_vlq(c)
|
|
1049
|
+
for _ = 1, total_pairs do
|
|
1050
|
+
local relation = client_replicator.read_component_id(client, c)
|
|
1051
|
+
local pair_hooks = removed_hooks[PAIR(components.pair, relation)]
|
|
1052
|
+
client_replicator.entity_remove_relations(client, entity, relation, pair_hooks)
|
|
1053
|
+
end
|
|
1054
|
+
end)
|
|
559
1055
|
end
|
|
560
1056
|
|
|
561
1057
|
local total_deleted = read_vlq_bitmask(c, storage_mask, 4)
|
|
562
1058
|
for _ = 1, total_deleted do
|
|
563
|
-
local entity, server_id = read_entity_id(client, c
|
|
1059
|
+
local entity, server_id = client_replicator.read_entity_id(client, c)
|
|
564
1060
|
if entity then
|
|
565
1061
|
local deleted_hook = deleted_hooks[entity]
|
|
566
1062
|
if deleted_hook then
|
|
@@ -580,13 +1076,14 @@ local function apply_updates(client: Client, buf: buffer, all_variants: { { any
|
|
|
580
1076
|
end
|
|
581
1077
|
end
|
|
582
1078
|
|
|
583
|
-
|
|
1079
|
+
client_replicator.finish_custom_ids(client, custom_ids, command_buffers)
|
|
1080
|
+
client_replicator.finish_replication(client)
|
|
584
1081
|
end
|
|
585
1082
|
|
|
586
|
-
|
|
1083
|
+
function client_replicator.apply_unreliable(client: Client, buf: buffer, all_variants: { { any } }?)
|
|
587
1084
|
local c = cursor.from(buf)
|
|
588
1085
|
check_packet_type(c, "unreliable")
|
|
589
|
-
resolve_dirty(client)
|
|
1086
|
+
client_replicator.resolve_dirty(client)
|
|
590
1087
|
client.is_replicating = true
|
|
591
1088
|
|
|
592
1089
|
local components = client.components
|
|
@@ -599,51 +1096,56 @@ local function apply_unreliable(client: Client, buf: buffer, all_variants: { { a
|
|
|
599
1096
|
local variants = all_variants and all_variants[variant_start - a]
|
|
600
1097
|
|
|
601
1098
|
for _ = 1, total_entities do
|
|
602
|
-
local entity = read_entity_id(client, c
|
|
603
|
-
|
|
1099
|
+
local entity = client_replicator.read_entity_id(client, c)
|
|
604
1100
|
local total_unreliable = cursor.read_vlq(c)
|
|
605
1101
|
|
|
606
1102
|
if entity then
|
|
607
1103
|
for _ = 1, total_unreliable do
|
|
608
|
-
local component_id, value = read_component(client, c, variants)
|
|
1104
|
+
local component_id, value = client_replicator.read_component(client, c, variants)
|
|
609
1105
|
local unreliable_hooks = changed_hooks[PAIR(components.unreliable, component_id)]
|
|
610
|
-
|
|
1106
|
+
client_replicator.entity_set_unreliable(client, entity, component_id, value, unreliable_hooks)
|
|
611
1107
|
end
|
|
612
1108
|
else
|
|
613
1109
|
-- dont apply unreliable updates to entities that dont exist in the client yet
|
|
614
1110
|
-- but we still need to process the values to keep the cursor in the right place
|
|
615
1111
|
for _ = 1, total_unreliable do
|
|
616
|
-
read_component(client, c, variants)
|
|
1112
|
+
client_replicator.read_component(client, c, variants)
|
|
617
1113
|
end
|
|
618
1114
|
end
|
|
619
1115
|
end
|
|
620
1116
|
end
|
|
621
1117
|
|
|
622
|
-
finish_replication(client)
|
|
1118
|
+
client_replicator.finish_replication(client)
|
|
623
1119
|
end
|
|
624
1120
|
|
|
625
|
-
|
|
1121
|
+
function client_replicator.apply_full(client: Client, buf: buffer, all_variants: { { any } }?)
|
|
626
1122
|
local c = cursor.from(buf)
|
|
627
1123
|
check_packet_type(c, "full")
|
|
628
|
-
resolve_dirty(client)
|
|
1124
|
+
client_replicator.resolve_dirty(client)
|
|
629
1125
|
client.is_replicating = true
|
|
630
1126
|
|
|
631
1127
|
local total_packets = cursor.read_vlq(c)
|
|
632
1128
|
local variant_start = (all_variants and #all_variants + 1) :: number
|
|
633
1129
|
|
|
1130
|
+
local command_buffers: { [Entity]: CommandBuffer } = {}
|
|
1131
|
+
local custom_ids: CustomIdMap = {}
|
|
1132
|
+
|
|
1133
|
+
client.command_buffers = command_buffers
|
|
1134
|
+
|
|
634
1135
|
for a = 1, total_packets do
|
|
635
1136
|
local total_entities = cursor.read_vlq(c)
|
|
636
1137
|
local variants = all_variants and all_variants[variant_start - a]
|
|
637
1138
|
|
|
638
1139
|
for _ = 1, total_entities do
|
|
639
|
-
process_entity(client, c, variants)
|
|
1140
|
+
client_replicator.process_entity(client, c, custom_ids, variants)
|
|
640
1141
|
end
|
|
641
1142
|
end
|
|
642
1143
|
|
|
643
|
-
|
|
1144
|
+
client_replicator.finish_custom_ids(client, custom_ids, command_buffers)
|
|
1145
|
+
client_replicator.finish_replication(client)
|
|
644
1146
|
end
|
|
645
1147
|
|
|
646
|
-
|
|
1148
|
+
function client_replicator.init(client: Client, _world: World?)
|
|
647
1149
|
if client.inited == true then
|
|
648
1150
|
return warn "attempted to init a client twice"
|
|
649
1151
|
end
|
|
@@ -668,11 +1170,7 @@ local function init(client: Client, _world: World?)
|
|
|
668
1170
|
|
|
669
1171
|
local components = client.components
|
|
670
1172
|
|
|
671
|
-
client.shared = utils.
|
|
672
|
-
|
|
673
|
-
for component, custom_get in world:query(components.custom_handler):with(components.shared, ECS_NAME) do
|
|
674
|
-
client.custom_ids[component] = custom_get
|
|
675
|
-
end
|
|
1173
|
+
client.shared = utils.resolved_shared(world, components, client.registered_custom_ids)
|
|
676
1174
|
|
|
677
1175
|
local alive_unhook = hooks.removed(world, components.__alive_tracking__, function(entity)
|
|
678
1176
|
local server_id = client.client_ids[entity]
|
|
@@ -686,17 +1184,17 @@ local function init(client: Client, _world: World?)
|
|
|
686
1184
|
|
|
687
1185
|
for _, component in client.requires_shared_lookup do
|
|
688
1186
|
local added_hook = hooks.added(world, component, function()
|
|
689
|
-
client.
|
|
1187
|
+
client.is_shared_dirty = true
|
|
690
1188
|
end)
|
|
691
1189
|
local removed_hook = hooks.removed(world, component, function()
|
|
692
|
-
client.
|
|
1190
|
+
client.is_shared_dirty = true
|
|
693
1191
|
end)
|
|
694
1192
|
table.insert(client.hooked, added_hook)
|
|
695
1193
|
table.insert(client.hooked, removed_hook)
|
|
696
1194
|
end
|
|
697
1195
|
end
|
|
698
1196
|
|
|
699
|
-
|
|
1197
|
+
function client_replicator.after_replication(client: Client, callback: () -> ())
|
|
700
1198
|
if client.is_replicating then
|
|
701
1199
|
table.insert(client.after_replication_callbacks, callback)
|
|
702
1200
|
else
|
|
@@ -704,7 +1202,7 @@ local function after_replication(client: Client, callback: () -> ())
|
|
|
704
1202
|
end
|
|
705
1203
|
end
|
|
706
1204
|
|
|
707
|
-
|
|
1205
|
+
function client_replicator.added(client: Client, callback: (entity: Entity) -> ())
|
|
708
1206
|
table.insert(client.addition_hooks, callback)
|
|
709
1207
|
return function()
|
|
710
1208
|
local index = table.find(client.addition_hooks, callback)
|
|
@@ -772,26 +1270,55 @@ local function add_hook_entry(client: Client, action: string, ...): ({ overrides
|
|
|
772
1270
|
end
|
|
773
1271
|
end
|
|
774
1272
|
|
|
775
|
-
|
|
1273
|
+
function client_replicator.hook(client: Client, action: string, ...)
|
|
776
1274
|
local entry, disconnect = add_hook_entry(client, action, ...)
|
|
777
1275
|
entry.overrides = false
|
|
778
1276
|
return disconnect
|
|
779
1277
|
end
|
|
780
|
-
|
|
1278
|
+
function client_replicator.override(client: Client, action: string, ...)
|
|
781
1279
|
local entry, disconnect = add_hook_entry(client, action, ...)
|
|
782
1280
|
entry.overrides = true
|
|
783
1281
|
return disconnect
|
|
784
1282
|
end
|
|
785
1283
|
|
|
786
|
-
|
|
1284
|
+
function client_replicator.get_server_entity(client: Client, client_entity: Entity): number?
|
|
787
1285
|
return client.client_ids[client_entity]
|
|
788
1286
|
end
|
|
789
1287
|
|
|
790
|
-
|
|
1288
|
+
function client_replicator.get_client_entity(client: Client, client_entity: number): Entity?
|
|
791
1289
|
return client.server_ids[client_entity]
|
|
792
1290
|
end
|
|
793
1291
|
|
|
794
|
-
|
|
1292
|
+
function client_replicator.register_entity(client: Client, entity: Entity, server_entity: number)
|
|
1293
|
+
client.server_ids[server_entity] = entity
|
|
1294
|
+
client.client_ids[entity] = server_entity
|
|
1295
|
+
client.world:add(entity, client.components.__alive_tracking__)
|
|
1296
|
+
end
|
|
1297
|
+
|
|
1298
|
+
function client_replicator.unregister_entity(client: Client, entity: Entity)
|
|
1299
|
+
local server_id = client.client_ids[entity]
|
|
1300
|
+
if server_id then
|
|
1301
|
+
client.server_ids[server_id] = nil
|
|
1302
|
+
client.client_ids[entity] = nil
|
|
1303
|
+
end
|
|
1304
|
+
end
|
|
1305
|
+
|
|
1306
|
+
function client_replicator.register_custom_id(client: Client, custom_id: CustomId)
|
|
1307
|
+
client.registered_custom_ids[custom_id] = true
|
|
1308
|
+
client.is_shared_dirty = true
|
|
1309
|
+
end
|
|
1310
|
+
|
|
1311
|
+
function client_replicator.generate_handshake(client: Client): common.HandshakeInfo
|
|
1312
|
+
client_replicator.resolve_dirty(client)
|
|
1313
|
+
return utils.generate_handshake(client.world, client.shared)
|
|
1314
|
+
end
|
|
1315
|
+
|
|
1316
|
+
function client_replicator.verify_handshake(client: Client, handshake: common.HandshakeInfo): (boolean, string?)
|
|
1317
|
+
client_replicator.resolve_dirty(client)
|
|
1318
|
+
return utils.verify_handshake(client.world, client.shared, handshake, "server", "client")
|
|
1319
|
+
end
|
|
1320
|
+
|
|
1321
|
+
function client_replicator.destroy(client: Client)
|
|
795
1322
|
if client.inited == nil then
|
|
796
1323
|
return warn "attempted to destroy a client twice"
|
|
797
1324
|
end
|
|
@@ -801,40 +1328,21 @@ local function destroy(client: Client)
|
|
|
801
1328
|
end
|
|
802
1329
|
end
|
|
803
1330
|
|
|
804
|
-
|
|
1331
|
+
function client_replicator.handle_global(client: Client, handler: (id: number) -> Entity)
|
|
805
1332
|
client.global_handler = handler
|
|
806
1333
|
end
|
|
807
1334
|
|
|
808
|
-
local client = {}
|
|
809
|
-
client.__index = client
|
|
810
|
-
client.init = init
|
|
811
|
-
client.destroy = destroy
|
|
812
|
-
client.apply_updates = apply_updates
|
|
813
|
-
client.apply_unreliable = apply_unreliable
|
|
814
|
-
client.apply_full = apply_full
|
|
815
|
-
client.encode_component = encode_component
|
|
816
|
-
client.decode_component = decode_component
|
|
817
|
-
client.get_server_entity = get_server_entity
|
|
818
|
-
client.get_client_entity = get_client_entity
|
|
819
|
-
client.handle_global = handle_global
|
|
820
|
-
client.after_replication = after_replication
|
|
821
|
-
client.hook = hook
|
|
822
|
-
client.override = override
|
|
823
|
-
client.added = added
|
|
824
|
-
|
|
825
1335
|
local function create(world: World?, components: common.Components): Client
|
|
826
1336
|
local self = {} :: Client
|
|
827
1337
|
|
|
828
1338
|
self.components = components
|
|
829
1339
|
self.ordered_creation = true
|
|
830
|
-
self.custom_ids = {}
|
|
831
1340
|
self.server_ids = {}
|
|
832
1341
|
self.client_ids = {}
|
|
833
|
-
self.
|
|
1342
|
+
self.is_shared_dirty = false
|
|
834
1343
|
self.requires_shared_lookup = {
|
|
835
1344
|
self.components.shared,
|
|
836
1345
|
self.components.serdes,
|
|
837
|
-
self.components.bytespan,
|
|
838
1346
|
jecs.Name,
|
|
839
1347
|
}
|
|
840
1348
|
self.global_handler = nil
|
|
@@ -842,6 +1350,7 @@ local function create(world: World?, components: common.Components): Client
|
|
|
842
1350
|
self.inited = false
|
|
843
1351
|
self.is_replicating = false
|
|
844
1352
|
self.hooked = {}
|
|
1353
|
+
self.registered_custom_ids = {}
|
|
845
1354
|
|
|
846
1355
|
self.addition_hooks = {}
|
|
847
1356
|
self.network_hooks = {
|
|
@@ -851,9 +1360,10 @@ local function create(world: World?, components: common.Components): Client
|
|
|
851
1360
|
}
|
|
852
1361
|
self.after_replication_callbacks = {}
|
|
853
1362
|
|
|
854
|
-
return setmetatable(self,
|
|
1363
|
+
return setmetatable(self, client_replicator) :: any
|
|
855
1364
|
end
|
|
856
1365
|
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
1366
|
+
return {
|
|
1367
|
+
create = create,
|
|
1368
|
+
client_replicator = client_replicator,
|
|
1369
|
+
}
|