@axpecter/lync 2.2.1 → 2.3.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.
Files changed (65) hide show
  1. package/README.md +109 -147
  2. package/package.json +1 -1
  3. package/src/Types.luau +34 -22
  4. package/src/api/Group.luau +40 -33
  5. package/src/api/Packet.luau +140 -66
  6. package/src/api/Query.luau +103 -65
  7. package/src/api/Scope.luau +26 -10
  8. package/src/api/Signal.luau +43 -52
  9. package/src/codec/Base.luau +28 -14
  10. package/src/codec/composite/Array.luau +296 -115
  11. package/src/codec/composite/Map.luau +377 -57
  12. package/src/codec/composite/Optional.luau +10 -2
  13. package/src/codec/composite/Shared.luau +134 -64
  14. package/src/codec/composite/Struct.luau +294 -43
  15. package/src/codec/composite/Tagged.luau +21 -16
  16. package/src/codec/composite/Tuple.luau +32 -15
  17. package/src/codec/datatype/Buffer.luau +7 -7
  18. package/src/codec/datatype/CFrame.luau +34 -122
  19. package/src/codec/datatype/Color.luau +10 -10
  20. package/src/codec/datatype/Instance.luau +15 -12
  21. package/src/codec/datatype/IntVector.luau +2 -2
  22. package/src/codec/datatype/NumberRange.luau +15 -8
  23. package/src/codec/datatype/Ray.luau +13 -14
  24. package/src/codec/datatype/Rect.luau +12 -12
  25. package/src/codec/datatype/Region.luau +13 -14
  26. package/src/codec/datatype/Sequence.luau +87 -65
  27. package/src/codec/datatype/String.luau +17 -10
  28. package/src/codec/datatype/UDim.luau +10 -8
  29. package/src/codec/datatype/Vector.luau +20 -59
  30. package/src/codec/meta/Auto.luau +94 -126
  31. package/src/codec/meta/Bitfield.luau +12 -14
  32. package/src/codec/meta/Custom.luau +3 -1
  33. package/src/codec/meta/DeltaScalar.luau +390 -0
  34. package/src/codec/meta/Enum.luau +9 -9
  35. package/src/codec/meta/Float.luau +6 -28
  36. package/src/codec/meta/Nothing.luau +1 -1
  37. package/src/codec/meta/Unknown.luau +10 -7
  38. package/src/codec/primitive/Bool.luau +6 -4
  39. package/src/codec/primitive/Float16.luau +5 -2
  40. package/src/codec/primitive/Int.luau +5 -6
  41. package/src/codec/primitive/Number.luau +6 -4
  42. package/src/codec/primitive/Signed.luau +2 -2
  43. package/src/codec/primitive/Varint.luau +76 -39
  44. package/src/codec/primitive/Zint.luau +99 -0
  45. package/src/index.d.ts +207 -53
  46. package/src/init.luau +116 -103
  47. package/src/internal/Baseline.luau +9 -1
  48. package/src/internal/Channel.luau +191 -157
  49. package/src/internal/Middleware.luau +22 -6
  50. package/src/internal/Pool.luau +12 -4
  51. package/src/internal/Registry.luau +25 -16
  52. package/src/internal/Transport.luau +1 -1
  53. package/src/transport/Bridge.luau +47 -33
  54. package/src/transport/Client.luau +25 -21
  55. package/src/transport/Gate.luau +227 -172
  56. package/src/transport/Reader.luau +174 -106
  57. package/src/transport/Server.luau +46 -57
  58. package/src/util/Array.luau +18 -0
  59. package/src/util/Buffer.luau +90 -0
  60. package/src/util/Constants.luau +30 -0
  61. package/src/util/Log.luau +68 -0
  62. package/src/util/Player.luau +14 -0
  63. package/src/util/Quantize.luau +84 -0
  64. package/src/util/Quat.luau +124 -0
  65. package/src/internal/Util.luau +0 -26
@@ -1,29 +1,29 @@
1
1
  --!strict
2
- --!optimize 2
2
+ --!native
3
3
  -- Raw buffer codec with dense-prefix-varint length prefix.
4
4
 
5
5
  local Base = require(script.Parent.Parent.Base)
6
+ local Log = require(script.Parent.Parent.Parent.util.Log)
6
7
  local Types = require(script.Parent.Parent.Parent.Types)
7
8
  local Varint = require(script.Parent.Parent.primitive.Varint)
8
9
 
9
10
  -- Private ----------------------------------------------------------------
10
11
 
11
12
  local alloc = Base.alloc
12
- local INLINE = Varint.INLINE_MAX
13
+ local INLINE_MAX = Varint.INLINE_MAX
13
14
 
14
15
  local function writeBuffer(ch: Types.ChannelState, value: buffer): ()
15
16
  local len = buffer.len(value)
16
17
  local cursor = ch.cursor
17
18
 
18
- if len <= INLINE then
19
+ -- Single-byte length fast path skips the full varint encode.
20
+ if len <= INLINE_MAX then
19
21
  if cursor + 1 + len > ch.size then
20
22
  alloc(ch, 1 + len)
21
23
  end
22
24
  local b = ch.buff
23
25
  buffer.writeu8(b, cursor, len)
24
- if len > 0 then
25
- buffer.copy(b, cursor + 1, value, 0, len)
26
- end
26
+ buffer.copy(b, cursor + 1, value, 0, len)
27
27
  ch.cursor = cursor + 1 + len
28
28
  return
29
29
  end
@@ -45,7 +45,7 @@ local function readBuffer(src: buffer, pos: number, _refs: { Instance }?): (buff
45
45
 
46
46
  local dataStart = pos + lenBytes
47
47
  if dataStart + len > buffer.len(src) then
48
- error("[Lync] Buffer.read: length exceeds remaining buffer")
48
+ Log.error(`length {len}B exceeds remaining buffer`)
49
49
  end
50
50
 
51
51
  local out = buffer.create(len)
@@ -1,8 +1,9 @@
1
1
  --!strict
2
2
  --!native
3
- -- CFrame codec with __call factory for smallest-three quaternion compression.
3
+ -- CFrame codec. Default lossless (24B); __call yields smallest-three quat (16B).
4
4
 
5
5
  local Base = require(script.Parent.Parent.Base)
6
+ local Quat = require(script.Parent.Parent.Parent.util.Quat)
6
7
  local Types = require(script.Parent.Parent.Parent.Types)
7
8
 
8
9
  -- Constants --------------------------------------------------------------
@@ -10,51 +11,43 @@ local Types = require(script.Parent.Parent.Parent.Types)
10
11
  local EPSILON = 2.4e-7
11
12
  local EPSILON_SQ = EPSILON * EPSILON
12
13
 
13
- local INV_SQRT2 = 1 / math.sqrt(2)
14
- local Q_SCALE = 1023 / (2 * INV_SQRT2)
15
- local Q_INV = (2 * INV_SQRT2) / 1023
16
-
17
14
  -- Private ----------------------------------------------------------------
18
15
 
19
16
  local alloc = Base.alloc
17
+ local writef32 = buffer.writef32
18
+ local readf32 = buffer.readf32
19
+ local writeu32 = buffer.writeu32
20
+ local readu32 = buffer.readu32
20
21
  local sqrt = math.sqrt
21
- local cos = math.cos
22
- local sin = math.sin
23
- local abs = math.abs
24
- local round = math.round
25
- local acos = math.acos
26
- local clamp = math.clamp
27
-
28
- local band = bit32.band
29
- local bor = bit32.bor
30
- local lshift = bit32.lshift
31
- local rshift = bit32.rshift
22
+ local quatPack = Quat.pack
23
+ local quatUnpack = Quat.unpack
24
+ local quatFromCFrame = Quat.fromCFrame
32
25
 
33
26
  local function writeLossless(b: buffer, off: number, value: CFrame): ()
34
27
  local pos = value.Position
35
- buffer.writef32(b, off, pos.X)
36
- buffer.writef32(b, off + 4, pos.Y)
37
- buffer.writef32(b, off + 8, pos.Z)
28
+ writef32(b, off, pos.X)
29
+ writef32(b, off + 4, pos.Y)
30
+ writef32(b, off + 8, pos.Z)
38
31
 
39
32
  local axis, angle = value:ToAxisAngle()
40
33
  if angle < EPSILON then
41
- buffer.writef32(b, off + 12, 0)
42
- buffer.writef32(b, off + 16, 0)
43
- buffer.writef32(b, off + 20, 0)
34
+ writef32(b, off + 12, 0)
35
+ writef32(b, off + 16, 0)
36
+ writef32(b, off + 20, 0)
44
37
  return
45
38
  end
46
- buffer.writef32(b, off + 12, axis.X * angle)
47
- buffer.writef32(b, off + 16, axis.Y * angle)
48
- buffer.writef32(b, off + 20, axis.Z * angle)
39
+ writef32(b, off + 12, axis.X * angle)
40
+ writef32(b, off + 16, axis.Y * angle)
41
+ writef32(b, off + 20, axis.Z * angle)
49
42
  end
50
43
 
51
44
  local function readLossless(b: buffer, off: number): CFrame
52
- local px = buffer.readf32(b, off)
53
- local py = buffer.readf32(b, off + 4)
54
- local pz = buffer.readf32(b, off + 8)
55
- local rx = buffer.readf32(b, off + 12)
56
- local ry = buffer.readf32(b, off + 16)
57
- local rz = buffer.readf32(b, off + 20)
45
+ local px = readf32(b, off)
46
+ local py = readf32(b, off + 4)
47
+ local pz = readf32(b, off + 8)
48
+ local rx = readf32(b, off + 12)
49
+ local ry = readf32(b, off + 16)
50
+ local rz = readf32(b, off + 20)
58
51
 
59
52
  local sqLen = rx * rx + ry * ry + rz * rz
60
53
  if sqLen < EPSILON_SQ then
@@ -68,104 +61,23 @@ local function readLossless(b: buffer, off: number): CFrame
68
61
  end
69
62
 
70
63
  --[[
71
- Compressed wire layout (16 bytes total):
64
+ Compressed wire (16B):
72
65
  [0..11] position 3x f32
73
- [12..15] packed [largest:2][a:10][b:10][c:10] smallest-three quat
66
+ [12..15] packed [largest:2][a:10][b:10][c:10] (smallest-three quat)
74
67
  ]]
75
68
  local function writeCompressed(b: buffer, off: number, value: CFrame): ()
76
69
  local pos = value.Position
77
- buffer.writef32(b, off, pos.X)
78
- buffer.writef32(b, off + 4, pos.Y)
79
- buffer.writef32(b, off + 8, pos.Z)
80
-
81
- local axis, angle = value:ToAxisAngle()
82
- local h = angle * 0.5
83
- local s = sin(h)
84
- local qx = axis.X * s
85
- local qy = axis.Y * s
86
- local qz = axis.Z * s
87
- local qw = cos(h)
88
-
89
- local ax, ay, az, aw = abs(qx), abs(qy), abs(qz), abs(qw)
90
- local largest, maxVal = 3, aw
91
- if ax > maxVal then
92
- largest, maxVal = 0, ax
93
- end
94
- if ay > maxVal then
95
- largest, maxVal = 1, ay
96
- end
97
- if az > maxVal then
98
- largest = 2
99
- end
100
-
101
- local sign: number
102
- if largest == 0 then
103
- sign = if qx < 0 then -1 else 1
104
- elseif largest == 1 then
105
- sign = if qy < 0 then -1 else 1
106
- elseif largest == 2 then
107
- sign = if qz < 0 then -1 else 1
108
- else
109
- sign = if qw < 0 then -1 else 1
110
- end
111
- qx, qy, qz, qw = qx * sign, qy * sign, qz * sign, qw * sign
112
-
113
- local a, bComp, c: number
114
- if largest == 0 then
115
- a, bComp, c = qy, qz, qw
116
- elseif largest == 1 then
117
- a, bComp, c = qx, qz, qw
118
- elseif largest == 2 then
119
- a, bComp, c = qx, qy, qw
120
- else
121
- a, bComp, c = qx, qy, qz
122
- end
123
-
124
- local qa = clamp(round((a + INV_SQRT2) * Q_SCALE), 0, 1023)
125
- local qb = clamp(round((bComp + INV_SQRT2) * Q_SCALE), 0, 1023)
126
- local qc = clamp(round((c + INV_SQRT2) * Q_SCALE), 0, 1023)
127
-
128
- buffer.writeu32(b, off + 12, bor(lshift(largest, 30), lshift(qa, 20), lshift(qb, 10), qc))
70
+ writef32(b, off, pos.X)
71
+ writef32(b, off + 4, pos.Y)
72
+ writef32(b, off + 8, pos.Z)
73
+ writeu32(b, off + 12, quatPack(quatFromCFrame(value)))
129
74
  end
130
75
 
131
76
  local function readCompressed(b: buffer, off: number): CFrame
132
- local px = buffer.readf32(b, off)
133
- local py = buffer.readf32(b, off + 4)
134
- local pz = buffer.readf32(b, off + 8)
135
-
136
- local packed = buffer.readu32(b, off + 12)
137
- local largest = rshift(packed, 30)
138
- local qa = band(rshift(packed, 20), 0x3FF)
139
- local qb = band(rshift(packed, 10), 0x3FF)
140
- local qc = band(packed, 0x3FF)
141
-
142
- local a = qa * Q_INV - INV_SQRT2
143
- local bComp = qb * Q_INV - INV_SQRT2
144
- local c = qc * Q_INV - INV_SQRT2
145
-
146
- local sqSum = a * a + bComp * bComp + c * c
147
- local d = sqrt(if sqSum < 1 then 1 - sqSum else 0)
148
-
149
- local qx, qy, qz, qw: number
150
- if largest == 0 then
151
- qx, qy, qz, qw = d, a, bComp, c
152
- elseif largest == 1 then
153
- qx, qy, qz, qw = a, d, bComp, c
154
- elseif largest == 2 then
155
- qx, qy, qz, qw = a, bComp, d, c
156
- else
157
- qx, qy, qz, qw = a, bComp, c, d
158
- end
159
-
160
- local origin = CFrame.new(px, py, pz)
161
- if qx * qx + qy * qy + qz * qz < EPSILON_SQ then
162
- return origin
163
- end
164
-
165
- local len = sqrt(qx * qx + qy * qy + qz * qz)
166
- local angle = 2 * acos(clamp(qw, -1, 1))
167
- local inv = 1 / len
168
- return origin * CFrame.fromAxisAngle(Vector3.new(qx * inv, qy * inv, qz * inv), angle)
77
+ local px = readf32(b, off)
78
+ local py = readf32(b, off + 4)
79
+ local pz = readf32(b, off + 8)
80
+ return CFrame.new(px, py, pz) * quatUnpack(readu32(b, off + 12))
169
81
  end
170
82
 
171
83
  local function compressedFactory(_self): Types.InternalCodec<CFrame>
@@ -1,26 +1,26 @@
1
1
  --!strict
2
- --!optimize 2
3
- -- Color3 codec. 3 bytes, R/G/B u8 per channel, clamped to [0, 1].
2
+ --!native
3
+ -- Color3 codec. 3 bytes (R/G/B u8 per channel), clamped to [0, 1].
4
4
 
5
5
  local Base = require(script.Parent.Parent.Base)
6
+ local Constants = require(script.Parent.Parent.Parent.util.Constants)
6
7
 
7
8
  -- Private ----------------------------------------------------------------
8
9
 
10
+ local U8_MAX = Constants.U8_MAX
11
+ local writeu8 = buffer.writeu8
12
+ local readu8 = buffer.readu8
9
13
  local round = math.round
10
14
  local clamp = math.clamp
11
15
 
12
16
  local function writeColor3(b: buffer, off: number, value: Color3): ()
13
- buffer.writeu8(b, off, round(clamp(value.R, 0, 1) * 255))
14
- buffer.writeu8(b, off + 1, round(clamp(value.G, 0, 1) * 255))
15
- buffer.writeu8(b, off + 2, round(clamp(value.B, 0, 1) * 255))
17
+ writeu8(b, off, round(clamp(value.R, 0, 1) * U8_MAX))
18
+ writeu8(b, off + 1, round(clamp(value.G, 0, 1) * U8_MAX))
19
+ writeu8(b, off + 2, round(clamp(value.B, 0, 1) * U8_MAX))
16
20
  end
17
21
 
18
22
  local function readColor3(b: buffer, off: number): Color3
19
- return Color3.fromRGB(
20
- buffer.readu8(b, off),
21
- buffer.readu8(b, off + 1),
22
- buffer.readu8(b, off + 2)
23
- )
23
+ return Color3.fromRGB(readu8(b, off), readu8(b, off + 1), readu8(b, off + 2))
24
24
  end
25
25
 
26
26
  -- Public -----------------------------------------------------------------
@@ -1,8 +1,9 @@
1
1
  --!strict
2
- --!optimize 2
3
- -- Instance codec via sidecar reference array.
2
+ --!native
3
+ -- Instance codec via the channel's sidecar reference array.
4
4
 
5
5
  local Channel = require(script.Parent.Parent.Parent.internal.Channel)
6
+ local Log = require(script.Parent.Parent.Parent.util.Log)
6
7
  local Types = require(script.Parent.Parent.Parent.Types)
7
8
 
8
9
  -- Private ----------------------------------------------------------------
@@ -15,18 +16,23 @@ local function writeInstance(ch: Types.ChannelState, value: Instance): ()
15
16
  end
16
17
 
17
18
  local function readInstance(src: buffer, pos: number, refs: { Instance }?): (Instance, number)
18
- if not refs then
19
- error("[Lync] Instance.read: refs array is required")
19
+ local r = refs
20
+ if not r then
21
+ Log.error("refs array is required")
20
22
  end
21
23
 
22
24
  local idx = readu16(src, pos)
23
- if idx < 1 or idx > #refs then
24
- error(`[Lync] Instance.read: ref index {idx} out of bounds`)
25
+ if idx < 1 or idx > #r then
26
+ Log.error(`ref index {idx} out of bounds`)
25
27
  end
26
28
 
27
- local inst = refs[idx]
29
+ --[[
30
+ Crafted clients can name a slot we never wrote; reject non-Instances.
31
+ Unknown codec skips this since it can legitimately hold any sidecar value.
32
+ ]]
33
+ local inst = r[idx]
28
34
  if typeof(inst) ~= "Instance" then
29
- error("[Lync] Instance.read: ref is not an Instance")
35
+ Log.error("ref is not an Instance")
30
36
  end
31
37
  return inst, 2
32
38
  end
@@ -35,10 +41,7 @@ end
35
41
 
36
42
  local InstanceCodec = {}
37
43
 
38
- --[[
39
- No _directWrite/_directRead: write needs ch.refs, so structs/arrays
40
- cannot use the all-direct fast path with this codec.
41
- ]]
44
+ -- No _directWrite/_directRead: write needs ch.refs (no fast path).
42
45
  InstanceCodec.inst = table.freeze({
43
46
  _size = 2,
44
47
  _typeCheck = "Instance",
@@ -1,6 +1,6 @@
1
1
  --!strict
2
- --!optimize 2
3
- -- Vector2int16 (4 bytes) and Vector3int16 (6 bytes) codecs.
2
+ --!native
3
+ -- Vector2int16 (4B) and Vector3int16 (6B) codecs.
4
4
 
5
5
  local Base = require(script.Parent.Parent.Base)
6
6
  local Signed = require(script.Parent.Parent.primitive.Signed)
@@ -1,22 +1,29 @@
1
1
  --!strict
2
- --!optimize 2
3
- -- NumberRange codec. 8 bytes: Min f32 + Max f32.
2
+ --!native
3
+ -- NumberRange codec. 8B: Min f32 + Max f32.
4
4
 
5
5
  local Base = require(script.Parent.Parent.Base)
6
+ local Log = require(script.Parent.Parent.Parent.util.Log)
6
7
 
7
8
  -- Private ----------------------------------------------------------------
8
9
 
10
+ local writef32 = buffer.writef32
11
+ local readf32 = buffer.readf32
12
+
9
13
  local function writeNumberRange(b: buffer, off: number, value: NumberRange): ()
10
- buffer.writef32(b, off, value.Min)
11
- buffer.writef32(b, off + 4, value.Max)
14
+ writef32(b, off, value.Min)
15
+ writef32(b, off + 4, value.Max)
12
16
  end
13
17
 
18
+ --[[
19
+ Reject min > max instead of silently swapping. A swap masks a desync;
20
+ erroring aborts the frame so the transport can reset its baseline.
21
+ ]]
14
22
  local function readNumberRange(b: buffer, off: number): NumberRange
15
- local minV = buffer.readf32(b, off)
16
- local maxV = buffer.readf32(b, off + 4)
17
- -- NumberRange.new requires min <= max; swap on corruption rather than throw.
23
+ local minV = readf32(b, off)
24
+ local maxV = readf32(b, off + 4)
18
25
  if minV > maxV then
19
- minV, maxV = maxV, minV
26
+ Log.error(`min ({minV}) > max ({maxV})`)
20
27
  end
21
28
  return NumberRange.new(minV, maxV)
22
29
  end
@@ -1,30 +1,29 @@
1
1
  --!strict
2
- --!optimize 2
3
- -- Ray codec. 24 bytes: Origin (3x f32) + Direction (3x f32).
2
+ --!native
3
+ -- Ray codec. 24B: Origin (3x f32) + Direction (3x f32).
4
4
 
5
5
  local Base = require(script.Parent.Parent.Base)
6
6
 
7
7
  -- Private ----------------------------------------------------------------
8
8
 
9
+ local writef32 = buffer.writef32
10
+ local readf32 = buffer.readf32
11
+
9
12
  local function writeRay(b: buffer, off: number, value: Ray): ()
10
13
  local o = value.Origin
11
14
  local d = value.Direction
12
- buffer.writef32(b, off, o.X)
13
- buffer.writef32(b, off + 4, o.Y)
14
- buffer.writef32(b, off + 8, o.Z)
15
- buffer.writef32(b, off + 12, d.X)
16
- buffer.writef32(b, off + 16, d.Y)
17
- buffer.writef32(b, off + 20, d.Z)
15
+ writef32(b, off, o.X)
16
+ writef32(b, off + 4, o.Y)
17
+ writef32(b, off + 8, o.Z)
18
+ writef32(b, off + 12, d.X)
19
+ writef32(b, off + 16, d.Y)
20
+ writef32(b, off + 20, d.Z)
18
21
  end
19
22
 
20
23
  local function readRay(b: buffer, off: number): Ray
21
24
  return Ray.new(
22
- Vector3.new(buffer.readf32(b, off), buffer.readf32(b, off + 4), buffer.readf32(b, off + 8)),
23
- Vector3.new(
24
- buffer.readf32(b, off + 12),
25
- buffer.readf32(b, off + 16),
26
- buffer.readf32(b, off + 20)
27
- )
25
+ Vector3.new(readf32(b, off), readf32(b, off + 4), readf32(b, off + 8)),
26
+ Vector3.new(readf32(b, off + 12), readf32(b, off + 16), readf32(b, off + 20))
28
27
  )
29
28
  end
30
29
 
@@ -1,25 +1,25 @@
1
1
  --!strict
2
- --!optimize 2
3
- -- Rect codec. 16 bytes: 4x f32 (Min.X, Min.Y, Max.X, Max.Y).
2
+ --!native
3
+ -- Rect codec. 16B: 4x f32 (Min.X, Min.Y, Max.X, Max.Y).
4
4
 
5
5
  local Base = require(script.Parent.Parent.Base)
6
6
 
7
7
  -- Private ----------------------------------------------------------------
8
8
 
9
+ local writef32 = buffer.writef32
10
+ local readf32 = buffer.readf32
11
+
9
12
  local function writeRect(b: buffer, off: number, value: Rect): ()
10
- buffer.writef32(b, off, value.Min.X)
11
- buffer.writef32(b, off + 4, value.Min.Y)
12
- buffer.writef32(b, off + 8, value.Max.X)
13
- buffer.writef32(b, off + 12, value.Max.Y)
13
+ local minV = value.Min
14
+ local maxV = value.Max
15
+ writef32(b, off, minV.X)
16
+ writef32(b, off + 4, minV.Y)
17
+ writef32(b, off + 8, maxV.X)
18
+ writef32(b, off + 12, maxV.Y)
14
19
  end
15
20
 
16
21
  local function readRect(b: buffer, off: number): Rect
17
- return Rect.new(
18
- buffer.readf32(b, off),
19
- buffer.readf32(b, off + 4),
20
- buffer.readf32(b, off + 8),
21
- buffer.readf32(b, off + 12)
22
- )
22
+ return Rect.new(readf32(b, off), readf32(b, off + 4), readf32(b, off + 8), readf32(b, off + 12))
23
23
  end
24
24
 
25
25
  -- Public -----------------------------------------------------------------
@@ -1,36 +1,35 @@
1
1
  --!strict
2
- --!optimize 2
3
- -- Region3 (24 bytes) and Region3int16 (12 bytes) codecs.
2
+ --!native
3
+ -- Region3 (24B) and Region3int16 (12B) codecs.
4
4
 
5
5
  local Base = require(script.Parent.Parent.Base)
6
6
  local Signed = require(script.Parent.Parent.primitive.Signed)
7
7
 
8
8
  -- Private ----------------------------------------------------------------
9
9
 
10
+ local writef32 = buffer.writef32
11
+ local readf32 = buffer.readf32
10
12
  local writeI16 = Signed.writeI16
11
13
  local readi16 = buffer.readi16
12
14
 
15
+ -- Region3 has no Min/Max accessors; reconstruct from CFrame.Position +/- Size/2.
13
16
  local function writeRegion3(b: buffer, off: number, value: Region3): ()
14
17
  local pos = value.CFrame.Position
15
18
  local half = value.Size * 0.5
16
19
  local minV = pos - half
17
20
  local maxV = pos + half
18
- buffer.writef32(b, off, minV.X)
19
- buffer.writef32(b, off + 4, minV.Y)
20
- buffer.writef32(b, off + 8, minV.Z)
21
- buffer.writef32(b, off + 12, maxV.X)
22
- buffer.writef32(b, off + 16, maxV.Y)
23
- buffer.writef32(b, off + 20, maxV.Z)
21
+ writef32(b, off, minV.X)
22
+ writef32(b, off + 4, minV.Y)
23
+ writef32(b, off + 8, minV.Z)
24
+ writef32(b, off + 12, maxV.X)
25
+ writef32(b, off + 16, maxV.Y)
26
+ writef32(b, off + 20, maxV.Z)
24
27
  end
25
28
 
26
29
  local function readRegion3(b: buffer, off: number): Region3
27
30
  return Region3.new(
28
- Vector3.new(buffer.readf32(b, off), buffer.readf32(b, off + 4), buffer.readf32(b, off + 8)),
29
- Vector3.new(
30
- buffer.readf32(b, off + 12),
31
- buffer.readf32(b, off + 16),
32
- buffer.readf32(b, off + 20)
33
- )
31
+ Vector3.new(readf32(b, off), readf32(b, off + 4), readf32(b, off + 8)),
32
+ Vector3.new(readf32(b, off + 12), readf32(b, off + 16), readf32(b, off + 20))
34
33
  )
35
34
  end
36
35