@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,7 +1,7 @@
1
1
  --!optimize 2
2
2
  --!native
3
3
 
4
- local customid = require (script.Parent:WaitForChild('customid'))
4
+ local jecs = require (script.Parent.Parent:WaitForChild('jecs'))
5
5
  local common = require (script.Parent:WaitForChild('common'))
6
6
  local types = require (script.Parent:WaitForChild('types'))
7
7
 
@@ -9,175 +9,10 @@ type World = common.World
9
9
  type Entity = common.Entity
10
10
  type Component = common.Component
11
11
 
12
- export type Cursor = {
13
- offset: number,
14
- buffer: buffer,
15
- }
16
-
17
- local ECS_NAME = common.ecs_name
18
12
  local RELATIONSHPIS = common.relationships
19
13
 
20
14
  local utils = {}
21
15
 
22
- function utils.create_shared_lookup<T>(lookup: { [string]: T }): types.SharedInfo<T>
23
- local keys = {}
24
- local indexes = {}
25
- local members = {}
26
-
27
- for name in lookup do
28
- table.insert(keys, name)
29
- end
30
- table.sort(keys)
31
-
32
- for index, name in keys do
33
- local member = lookup[name]
34
- members[member] = index
35
- indexes[index] = member
36
- end
37
-
38
- return {
39
- lookup = lookup,
40
- keys = keys,
41
- indexes = indexes,
42
- members = members,
43
- }
44
- end
45
-
46
- function utils.generate_handshake(shared: types.Shared): types.HandshakeInfo
47
- local component_to_name: { [Entity]: string } = {}
48
- local handshake: types.HandshakeInfo = {
49
- components = {},
50
- custom_ids = {},
51
- serdes = {},
52
- }
53
-
54
- for component_name, component in shared.components.lookup do
55
- handshake.components[component_name] = true
56
- component_to_name[component] = component_name
57
- end
58
-
59
- for custom_id in shared.custom_ids.lookup do
60
- handshake.custom_ids[custom_id] = true
61
- end
62
-
63
- for component, serdes in shared.serdes do
64
- local name = component_to_name[component]
65
- if not name then
66
- continue
67
- end
68
-
69
- handshake.serdes[name] = {
70
- includes_variants = serdes.includes_variants,
71
- bytespan = serdes.bytespan,
72
- }
73
- end
74
-
75
- return handshake
76
- end
77
-
78
- function utils.verify_handshake(
79
- shared: types.Shared,
80
- handshake: types.HandshakeInfo,
81
- handshake_side: string,
82
- verify_side: string
83
- ): (boolean, string?)
84
- local component_to_name: { [Entity]: string } = {}
85
-
86
- for component_name in handshake.components do
87
- if not shared.components.lookup[component_name] then
88
- return false, `missing shared component "{component_name}" in {verify_side}`
89
- end
90
- end
91
- for component_name, component in shared.components.lookup do
92
- if not handshake.components[component_name] then
93
- return false, `missing shared component "{component_name}" in {handshake_side}`
94
- end
95
- component_to_name[component] = component_name
96
- end
97
-
98
- for custom_id in handshake.custom_ids do
99
- if not shared.custom_ids.lookup[custom_id] then
100
- return false, `missing custom id "{custom_id}" in {verify_side}`
101
- end
102
- end
103
- for custom_id in shared.custom_ids.lookup do
104
- if not handshake.custom_ids[custom_id] then
105
- return false, `missing custom id "{custom_id}" in {handshake_side}`
106
- end
107
- end
108
-
109
- for component_name, serdes_info in handshake.serdes do
110
- local component = shared.components.lookup[component_name]
111
- if not component then
112
- warn(`{handshake_side} registered a serdes for "{component_name}" that {verify_side} doesn't have`)
113
- continue
114
- end
115
-
116
- local serdes = shared.serdes[component]
117
- if not serdes then
118
- return false, `missing serdes for component "{component_name}" in {verify_side}`
119
- end
120
-
121
- if (serdes_info.includes_variants or false) ~= (serdes.includes_variants or false) then
122
- return false,
123
- `mismatched includes_variants for component "{component_name}": ({serdes_info.includes_variants} ~= {serdes.includes_variants})`
124
- end
125
- if serdes_info.bytespan ~= serdes.bytespan then
126
- return false,
127
- `mismatched bytespan for component "{component_name}": ({serdes_info.bytespan} ~= {serdes.bytespan})`
128
- end
129
- end
130
- for component in shared.serdes do
131
- local component_name = component_to_name[component]
132
- if not component_name then
133
- continue
134
- end
135
-
136
- if not handshake.serdes[component_name] then
137
- warn(`{verify_side} registered a serdes for "{component_name}" that {handshake_side} doesn't have`)
138
- end
139
- end
140
-
141
- return true, nil
142
- end
143
-
144
- function utils.resolved_shared(
145
- world: World,
146
- components: types.Components,
147
- registered_custom_ids: { [customid.CustomId]: boolean },
148
- serdes: { [Component]: types.Serdes }
149
- ): types.Shared
150
- local shared = {} :: types.Shared
151
-
152
- local components_lookup: { [string]: Entity } = table.clone(common.implicitly_shared)
153
- local custom_ids_lookup = {}
154
-
155
- for component, name in world:query(ECS_NAME):with(components.shared):iter() do
156
- if components_lookup[name] then
157
- common.log_error(`detected two components with the same {name} name: ({components_lookup[name]}, {component})`)
158
- end
159
- components_lookup[name] = component
160
- end
161
-
162
- for component in world:query(components.shared):without(ECS_NAME):iter() do
163
- common.log_warn(`shared component: {component} has no name assigned.`)
164
- end
165
-
166
- for custom in registered_custom_ids do
167
- custom_ids_lookup[custom.identifier] = custom
168
- end
169
-
170
- for custom in registered_custom_ids do
171
- custom_ids_lookup[custom.identifier] = custom
172
- end
173
-
174
- shared.serdes = serdes
175
- shared.components = utils.create_shared_lookup(components_lookup)
176
- shared.custom_ids = utils.create_shared_lookup(custom_ids_lookup)
177
-
178
- return shared
179
- end
180
-
181
16
  function utils.create_components(tag: () -> Component, component: () -> Component, push: types.Components?)
182
17
  local components = push or {} :: types.Components
183
18
  components.shared = tag()
@@ -186,13 +21,13 @@ function utils.create_components(tag: () -> Component, component: () -> Componen
186
21
  if RELATIONSHPIS then
187
22
  components.reliable = component()
188
23
  components.unreliable = component()
24
+ components.once = component()
189
25
  components.relation = component()
190
26
 
191
27
  components.custom = tag()
192
28
  end
193
29
  components.custom_handler = component()
194
30
  components.serdes = component()
195
- components.global = component()
196
31
  components.__alive_tracking__ = tag()
197
32
 
198
33
  components.Shared = components.shared
@@ -200,13 +35,13 @@ function utils.create_components(tag: () -> Component, component: () -> Componen
200
35
  if RELATIONSHPIS then
201
36
  components.Reliable = components.reliable
202
37
  components.Unreliable = components.unreliable
38
+ components.Once = components.once
203
39
  components.Relation = components.relation
204
40
 
205
41
  components.Custom = components.custom
206
42
  end
207
43
  components.CustomHandler = components.custom_handler
208
44
  components.Serdes = components.serdes
209
- components.Global = components.global
210
45
  return components
211
46
  end
212
47
 
@@ -216,13 +51,13 @@ function utils.add_component_names(components: types.Components, set: (component
216
51
  set(components.networked, "replecs.networked")
217
52
  set(components.reliable, "replecs.reliable")
218
53
  set(components.unreliable, "replecs.unreliable")
54
+ set(components.once, "replecs.once")
219
55
  set(components.relation, "replecs.relation")
220
56
 
221
57
  set(components.custom, "replecs.custom")
222
58
  end
223
59
  set(components.custom_handler, "replecs.custom_handler")
224
60
  set(components.serdes, "replecs.serdes")
225
- set(components.global, "replecs.global")
226
61
 
227
62
  set(components.__alive_tracking__, "replecs.__alive_tracking__")
228
63
  end
@@ -239,584 +74,18 @@ function utils.tag_factory(world: World)
239
74
  end
240
75
  end
241
76
 
242
- local cursor = {}
243
-
244
- function cursor.new(): Cursor
245
- return {
246
- buffer = buffer.create(100),
247
- offset = 0,
248
- }
249
- end
250
-
251
- function cursor.from(buf: buffer): Cursor
252
- return {
253
- buffer = buf,
254
- offset = buffer.len(buf),
255
- }
256
- end
257
-
258
- function cursor.from_offset(buf: buffer, offset: number): Cursor
259
- return {
260
- buffer = buf,
261
- offset = offset,
262
- }
263
- end
264
-
265
- function cursor.tryalloc(c: Cursor, bytes: number)
266
- local buf = c.buffer
267
- local offset = c.offset
268
- local len = buffer.len(buf)
269
-
270
- if len < offset + bytes then
271
- local exponent = math.ceil(math.log((bytes + offset) / len, 1.5))
272
- local new = buffer.create(len * 1.5 ^ exponent)
273
- buffer.copy(new, 0, buf, 0)
274
- c.buffer = new
275
- end
276
- end
277
-
278
- function cursor.write_buffer(c: Cursor, buf: buffer, start: number?, count: number?)
279
- if start == nil and count == nil then
280
- cursor.tryalloc(c, buffer.len(buf))
281
- buffer.copy(c.buffer, c.offset, buf, 0, buffer.len(buf))
282
- c.offset += buffer.len(buf)
283
- else
284
- local len = buffer.len(buf)
285
- local available = len - (start or 0)
286
- local write_count = count and math.min(available, count) or available
287
-
288
- cursor.tryalloc(c, write_count)
289
- buffer.copy(c.buffer, c.offset, buf, start or 0, write_count)
290
- c.offset += write_count
291
- end
292
- end
293
-
294
- function cursor.print(c: Cursor)
295
- local bytes: { any } = { string.byte(buffer.tostring(c.buffer), 1, -1) }
296
- local offset = 7
297
- for i = 1, c.offset do
298
- local byte = bytes[i] :: number
299
- local digits = if byte == 0 then 1 else math.ceil(math.log10(1 + byte))
300
- offset += digits + 1
301
- end
302
-
303
- local last_byte = bytes[c.offset + 1]
304
- if last_byte then
305
- local lastDigits = if last_byte == 0 then 1 else math.ceil(math.log10(1 + last_byte))
306
- offset += lastDigits // 2
307
- end
308
- bytes[c.offset + 1] = `[{bytes[c.offset + 1] :: number}]` :: any
309
-
310
- if #bytes == 0 or c.offset == buffer.len(c.buffer) then
311
- table.insert(bytes, " ")
312
- end
313
-
314
- return `Pos: {c.offset} / {buffer.len(c.buffer)}\nBuf: \{ {table.concat(bytes, " ")} \}`
315
- end
316
-
317
- function cursor.writeu8(c: Cursor, value: number)
318
- cursor.tryalloc(c, 1)
319
- buffer.writeu8(c.buffer, c.offset, value)
320
- c.offset += 1
321
- end
322
-
323
- function cursor.writeu16(c: Cursor, value: number)
324
- cursor.tryalloc(c, 2)
325
- buffer.writeu16(c.buffer, c.offset, value)
326
- c.offset += 2
327
- end
328
- function cursor.writeu24(c: Cursor, value: number)
329
- cursor.tryalloc(c, 3)
330
- buffer.writeu8(c.buffer, c.offset, value)
331
- buffer.writeu16(c.buffer, c.offset + 1, value // 256)
332
- c.offset += 3
333
- end
334
-
335
- function cursor.writeu32(c: Cursor, value: number)
336
- cursor.tryalloc(c, 4)
337
- buffer.writeu32(c.buffer, c.offset, value :: any)
338
- c.offset += 4
339
- end
340
-
341
- function cursor.writeu40(c: Cursor, value: number)
342
- cursor.tryalloc(c, 5)
343
- buffer.writeu8(c.buffer, c.offset, value)
344
- buffer.writeu32(c.buffer, c.offset + 1, value // 256)
345
- c.offset += 5
346
- end
347
-
348
- function cursor.writei8(c: Cursor, value: number)
349
- cursor.tryalloc(c, 1)
350
- buffer.writei8(c.buffer, c.offset, value)
351
- c.offset += 1
352
- end
353
-
354
- function cursor.writei16(c: Cursor, value: number)
355
- cursor.tryalloc(c, 2)
356
- buffer.writei16(c.buffer, c.offset, value)
357
- c.offset += 2
358
- end
359
-
360
- function cursor.writei32(c: Cursor, value: number)
361
- cursor.tryalloc(c, 4)
362
- buffer.writeu32(c.buffer, c.offset, value :: any)
363
- c.offset += 4
364
- end
365
-
366
- function cursor.write_span(c: Cursor, value: number, span: number)
367
- if span <= 0xFF then
368
- cursor.writeu8(c, value)
369
- elseif span <= 0xFFFF then
370
- cursor.writeu16(c, value)
371
- elseif span <= 0xFFFFFF then
372
- cursor.writeu24(c, value)
373
- elseif span <= 0xFFFFFFFF then
374
- cursor.writeu32(c, value)
375
- else
376
- error "span too large"
377
- end
378
- end
379
-
380
- function cursor.read_buffer(c: Cursor, len: number)
381
- local retrieved = buffer.create(len)
382
- buffer.copy(retrieved, 0, c.buffer, c.offset - len, len)
383
- c.offset -= len
384
- return retrieved
385
- end
386
-
387
- function cursor.readu8(c: Cursor): number
388
- c.offset -= 1
389
- return buffer.readu8(c.buffer, c.offset)
390
- end
391
-
392
- function cursor.readu16(c: Cursor): number
393
- c.offset -= 2
394
- return buffer.readu16(c.buffer, c.offset)
395
- end
396
-
397
- function cursor.readu24(c: Cursor): number
398
- c.offset -= 3
399
- local one = buffer.readu8(c.buffer, c.offset)
400
- local two = buffer.readu16(c.buffer, c.offset + 1)
401
- return one + two * 256
402
- end
403
-
404
- function cursor.readu32(c: Cursor): number
405
- c.offset -= 4
406
- return buffer.readu32(c.buffer, c.offset)
407
- end
408
-
409
- function cursor.readu40(c: Cursor): number
410
- c.offset -= 5
411
- local one = buffer.readu8(c.buffer, c.offset)
412
- local two = buffer.readu32(c.buffer, c.offset + 1)
413
- return one + two * 256
414
- end
415
-
416
- function cursor.read_span(c: Cursor, span: number): number
417
- if span <= 0xFF then
418
- return cursor.readu8(c)
419
- elseif span <= 0xFFFF then
420
- return cursor.readu16(c)
421
- elseif span <= 0xFFFFFF then
422
- return cursor.readu24(c)
423
- elseif span <= 0xFFFFFFFF then
424
- return cursor.readu32(c)
425
- else
426
- error "span too large"
427
- end
428
- end
429
-
430
- function cursor.readi8(c: Cursor): number
431
- c.offset -= 1
432
- return buffer.readi8(c.buffer, c.offset)
433
- end
434
-
435
- function cursor.readi16(c: Cursor): number
436
- c.offset -= 2
437
- return buffer.readi16(c.buffer, c.offset)
438
- end
439
- function cursor.readi32(c: Cursor): number
440
- c.offset -= 4
441
- return buffer.readi32(c.buffer, c.offset)
442
- end
443
-
444
- function cursor.write_vlq(c: Cursor, value: number)
445
- local x0 = value // 1% 128
446
- local x1 = value // 128% 128
447
- local x2 = value // 16384% 128
448
- local x3 = value // 2097152% 128
449
-
450
- if x3 ~= 0 then
451
- cursor.tryalloc(c, 4)
452
- cursor.writeu32(c, x0 * 16777216+ x1 * 65536+ x2 * 256 + x3 + 128)
453
- elseif x2 ~= 0 then
454
- cursor.tryalloc(c, 3)
455
- cursor.writeu24(c, x0 * 65536+ x1 * 256 + x2 + 128)
456
- elseif x1 ~= 0 then
457
- cursor.tryalloc(c, 2)
458
- cursor.writeu16(c, x0 * 256 + x1 + 128)
459
- else
460
- cursor.tryalloc(c, 1)
461
- cursor.writeu8(c, x0 + 128)
462
- end
463
- end
464
-
465
- function cursor.read_vlq(c: Cursor): number
466
- local b = cursor.readu8(c)
467
- if b >= 128 then
468
- return b - 128
469
- end
470
- local x = b
471
-
472
- b = cursor.readu8(c)
473
- if b >= 128 then
474
- return x + (b - 128) * 128
475
- end
476
- x += b * 128
477
-
478
- b = cursor.readu8(c)
479
- if b >= 128 then
480
- return x + (b - 128) * 16384
481
- end
482
- x += b * 16384
483
-
484
- b = cursor.readu8(c)
485
- if b >= 128 then
486
- return x + (b - 128) * 2097152
487
- end
488
- x += b * 2097152
489
-
490
- error "vlq length too large"
491
- end
492
-
493
- function cursor.close(c: Cursor): buffer
494
- local final = buffer.create(c.offset)
495
- buffer.copy(final, 0, c.buffer, 0, c.offset)
496
- c.buffer = final
497
- return final
498
- end
499
-
500
- function utils.print_buffer(buf: buffer)
501
- local bytes = { string.byte(buffer.tostring(buf), 1, -1) }
502
- return `\{ {buffer.len(buf)}\n Buf: \{ {table.concat(bytes, " ")} \}`
503
- end
504
-
505
- utils.cursor = cursor
506
-
507
- local bitmask = {}
508
- bitmask.__index = bitmask
509
-
510
- export type Bitmask = {
511
- buffer: buffer,
512
- capacity: number,
513
- entries: number,
514
- } & typeof(bitmask)
515
-
516
- local BITS_PER_ENTRY = 32
517
- local BYTES_PER_ENTRY = 4
518
-
519
- function get_entry_bit(index: number): (number, number)
520
- local entry_index = math.floor(index / BITS_PER_ENTRY)
521
- local bit_position = index % BITS_PER_ENTRY
522
- return entry_index, bit_position
523
- end
524
-
525
- function bitmask.create(capacity: number?): Bitmask
526
- local entries_needed = math.ceil(capacity :: number / BITS_PER_ENTRY)
527
- local buffer_size = entries_needed * BYTES_PER_ENTRY
528
-
529
- local self = {
530
- buffer = buffer.create(buffer_size),
531
- capacity = capacity,
532
- entries = entries_needed,
533
- }
534
-
535
- return setmetatable(self, bitmask) :: any
536
- end
537
-
538
- function bitmask.from_set(indexes: { [any]: number }, filter: { [any]: boolean }, capacity: number?): Bitmask
539
- local newmask = bitmask.create(capacity or 32)
540
- for player in filter do
541
- local index = indexes[player]
542
- if index == nil then
543
- continue
544
- end
545
- bitmask.set(newmask, index)
546
- end
547
- return newmask
548
- end
549
-
550
- function bitmask.expand(self: Bitmask, capacity: number)
551
- if capacity <= self.capacity then
552
- return
553
- end
554
-
555
- local new_entries = math.ceil(capacity / BITS_PER_ENTRY)
556
- local new_buffer_size = new_entries * BYTES_PER_ENTRY
557
- local new_buffer = buffer.create(new_buffer_size)
558
-
559
- buffer.copy(new_buffer, 0, self.buffer, 0)
560
-
561
- for i = self.entries * BYTES_PER_ENTRY, new_buffer_size - 1 do
562
- buffer.writeu8(new_buffer, i, 0)
563
- end
564
-
565
- self.buffer = new_buffer
566
- self.capacity = capacity
567
- self.entries = new_entries
568
- end
569
-
570
- function bitmask.read(self: Bitmask, index: number): number
571
- if index >= self.entries then
572
- return 0
573
- end
574
- return buffer.readu32(self.buffer, index * BYTES_PER_ENTRY)
575
- end
576
-
577
- function bitmask.write(self: Bitmask, index: number, value: number)
578
- if index >= self.entries then
579
- --
580
- bitmask.expand(self, (index + 1) * BITS_PER_ENTRY)
581
- end
582
- buffer.writeu32(self.buffer, index * BYTES_PER_ENTRY, value)
583
- end
584
-
585
- -- BIT MANIPULATIONS
586
-
587
- function bitmask.set(self: Bitmask, index: number)
588
- if index < 0 then
589
- error "Bit index cannot be negative"
590
- end
591
-
592
- local entry_index, bit_position = get_entry_bit(index)
593
- local current_value = bitmask.read(self, entry_index)
594
- local new_value = bit32.bor(current_value, bit32.lshift(1, bit_position))
595
- bitmask.write(self, entry_index, new_value)
596
- end
597
-
598
- function bitmask.get(self: Bitmask, index: number): boolean
599
- if index < 0 then
600
- error "Bit index cannot be negative"
601
- end
602
-
603
- local entry_index, bit_position = get_entry_bit(index)
604
- if entry_index >= self.entries then
605
- return false
606
- end
607
-
608
- local current_value = bitmask.read(self, entry_index)
609
- return bit32.band(current_value, bit32.lshift(1, bit_position)) ~= 0
610
- end
611
-
612
- function bitmask.clear(self: Bitmask, index: number)
613
- if index < 0 then
614
- error "Bit index cannot be negative"
615
- end
616
-
617
- local entry_index, bit_position = get_entry_bit(index)
618
- if entry_index >= self.entries then
619
- return
620
- end
621
-
622
- local current_value = bitmask.read(self, entry_index)
623
- local mask = bit32.bnot(bit32.lshift(1, bit_position))
624
- local new_value = bit32.band(current_value, mask)
625
- bitmask.write(self, entry_index, new_value)
626
- end
627
-
628
- -- BITWISE OPERATIONS
629
-
630
- function bitmask.band(self: Bitmask, other: Bitmask): Bitmask
631
- local max_entries = math.max(self.entries, other.entries)
632
- local result = bitmask.create(max_entries * BITS_PER_ENTRY)
633
-
634
- for i = 0, max_entries - 1 do
635
- local value1 = bitmask.read(self, i)
636
- local value2 = bitmask.read(other, i)
637
- bitmask.write(result, i, bit32.band(value1, value2))
638
- end
639
-
640
- return result
641
- end
642
-
643
- function bitmask.bor(self: Bitmask, other: Bitmask): Bitmask
644
- local max_entries = math.max(self.entries, other.entries)
645
- local result = bitmask.create(max_entries * BITS_PER_ENTRY)
646
-
647
- for i = 0, max_entries - 1 do
648
- local value1 = bitmask.read(self, i)
649
- local value2 = bitmask.read(other, i)
650
- bitmask.write(result, i, bit32.bor(value1, value2))
651
- end
652
-
653
- return result
654
- end
655
-
656
- function bitmask.bxor(self: Bitmask, other: Bitmask): Bitmask
657
- local max_entries = math.max(self.entries, other.entries)
658
- local result = bitmask.create(max_entries * BITS_PER_ENTRY)
659
-
660
- for i = 0, max_entries - 1 do
661
- local value1 = bitmask.read(self, i)
662
- local value2 = bitmask.read(other, i)
663
- bitmask.write(result, i, bit32.bxor(value1, value2))
664
- end
665
-
666
- return result
667
- end
668
-
669
- function bitmask.bnot(self: Bitmask): Bitmask
670
- local result = bitmask.create(self.capacity)
671
-
672
- for i = 0, self.entries - 1 do
673
- local value = bitmask.read(self, i)
674
- bitmask.write(result, i, bit32.bnot(value))
675
- end
676
-
677
- return result
678
- end
679
-
680
- function bitmask.clone(self: Bitmask): Bitmask
681
- local result = bitmask.create(self.capacity)
682
- buffer.copy(result.buffer, 0, self.buffer, 0, self.entries * BYTES_PER_ENTRY)
683
- return result
684
- end
685
-
686
- function bitmask.remap(self: Bitmask, from: { [any]: number }, to: { [any]: number }, new_capacity: number?): Bitmask
687
- local result = bitmask.create(new_capacity or BITS_PER_ENTRY)
688
- for member, index in to do
689
- local old_index = from[member]
690
- if old_index then
691
- local old_bit = bitmask.get(self, old_index)
692
- if old_bit then
693
- bitmask.set(result, index)
694
- else
695
- bitmask.clear(result, index)
696
- end
697
- end
698
- end
699
- return result
700
- end
701
-
702
- function bitmask.lshift(self: Bitmask, n: number): Bitmask
703
- if n <= 0 then
704
- return bitmask.clone(self)
705
- end
706
-
707
- local entry_shift = math.floor(n / BITS_PER_ENTRY)
708
- local bit_shift = n % BITS_PER_ENTRY
709
-
710
- local result = bitmask.create(self.capacity + n)
711
-
712
- if bit_shift == 0 then
713
- for i = 0, self.entries - 1 do
714
- local value = bitmask.read(self, i)
715
- bitmask.write(result, i + entry_shift, value)
716
- end
717
- else
718
- local carry = 0
719
- for i = 0, self.entries - 1 do
720
- local value = bitmask.read(self, i)
721
- local shifted_value = bit32.lshift(value, bit_shift)
722
- local new_carry = bit32.rshift(value, BITS_PER_ENTRY - bit_shift)
723
-
724
- bitmask.write(result, i + entry_shift, bit32.bor(shifted_value, carry))
725
- carry = new_carry
726
- end
727
-
728
- if carry ~= 0 then
729
- bitmask.write(result, self.entries + entry_shift, carry)
730
- end
731
- end
732
-
733
- return result
734
- end
735
-
736
- function bitmask.rshift(self: Bitmask, n: number): Bitmask
737
- if n <= 0 then
738
- return bitmask.clone(self)
739
- end
740
-
741
- local entry_shift = math.floor(n / BITS_PER_ENTRY)
742
- local bit_shift = n % BITS_PER_ENTRY
743
-
744
- if entry_shift >= self.entries then
745
- return bitmask.create(32)
746
- end
747
-
748
- local result = bitmask.create(self.capacity)
749
-
750
- if bit_shift == 0 then
751
- for i = entry_shift, self.entries - 1 do
752
- local value = bitmask.read(self, i)
753
- bitmask.write(result, i - entry_shift, value)
754
- end
755
- else
756
- for i = entry_shift, self.entries - 1 do
757
- local value = bitmask.read(self, i)
758
- local shifted_value = bit32.rshift(value, bit_shift)
759
-
760
- local next_value = 0
761
- if i + 1 < self.entries then
762
- next_value = bitmask.read(self, i + 1)
763
- end
764
- local overflow = bit32.lshift(next_value, BITS_PER_ENTRY - bit_shift)
765
-
766
- bitmask.write(result, i - entry_shift, bit32.bor(shifted_value, overflow))
767
- end
768
- end
769
-
770
- return result
771
- end
772
-
773
- local function tobinary(n: number): string
774
- if n == 0 then
775
- return "0"
776
- end
777
-
778
- local result = ""
779
- while n > 0 do
780
- result = (n % 2) .. result
781
- n = math.floor(n / 2)
782
- end
783
- return string.rep("0", 8 - #result) .. result
784
- end
785
-
786
- local BYTES = table.create(6)
787
-
788
- function bitmask.tostring(self: Bitmask): string
789
- local buf = self.buffer
790
-
791
- local highest_entry = -1
792
- for i = self.entries - 1, 0, -1 do
793
- local value = buffer.readu32(buf, i * BYTES_PER_ENTRY)
794
- if value ~= 0 then
795
- highest_entry = i
796
- break
797
- end
798
- end
799
-
800
- if highest_entry == -1 then
801
- return ""
802
- end
803
-
804
- table.clear(BYTES)
805
- local str = ""
806
- for i = 0, highest_entry do
807
- str = str .. tobinary(buffer.readu32(buf, i * BYTES_PER_ENTRY))
808
- --table.insert(BYTES, buffer.readu32(buf, i * BYTES_PER_ENTRY))
809
- end
810
-
811
- --return table.concat(BYTES, "-")
812
- return str
77
+ -- without preregistration the replecs components live in the world itself;
78
+ -- created once the world is known (create or init), named and given the same
79
+ -- metadata the preregistered set gets
80
+ function utils.create_world_components(world: World): types.Components
81
+ local components = utils.create_components(utils.tag_factory(world), utils.component_factory(world))
82
+ utils.add_component_names(components, function(component, name)
83
+ common.add_name(world, component, name)
84
+ end)
85
+ jecs.meta(components.custom, jecs.Exclusive)
86
+ return components
813
87
  end
814
88
 
815
- utils.bitmask = {
816
- create = bitmask.create,
817
- from_set = bitmask.from_set,
818
- }
819
-
820
89
  function utils.is_client_valid(player: any): boolean
821
90
  if game then
822
91
  if typeof(player) == "Instance" then
@@ -828,43 +97,4 @@ function utils.is_client_valid(player: any): boolean
828
97
  return true
829
98
  end
830
99
 
831
- function utils.vlq_span(length: number): number
832
- if length < 0x80 then
833
- return 1
834
- elseif length < 0x4000 then
835
- return 2
836
- elseif length < 0x200000 then
837
- return 3
838
- else
839
- return 4
840
- end
841
- end
842
-
843
- function utils.number_span(n: number): number
844
- if n <= 0xFF then
845
- return 1
846
- elseif n <= 0xFFFF then
847
- return 2
848
- else
849
- return 4 -- cant read 24 bits
850
- end
851
- end
852
-
853
- function utils.read_number(buf: buffer, offset: number, span: number): (number, number)
854
- if span == 1 then
855
- return buffer.readu8(buf, offset), offset + 1
856
- elseif span == 2 then
857
- return buffer.readu16(buf, offset), offset + 2
858
- else
859
- return buffer.readu32(buf, offset), offset + 4
860
- end
861
- end
862
-
863
- function utils.setbit(mask: number, bit: number)
864
- return bit32.bor(mask, bit32.lshift(1, bit))
865
- end
866
- function utils.checkbit(mask: number, bit: number)
867
- return bit32.band(mask, bit32.lshift(1, bit)) ~= 0
868
- end
869
-
870
100
  return utils