@axpecter/lync 1.5.2 → 2.1.0

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 (55) hide show
  1. package/README.md +499 -357
  2. package/package.json +2 -2
  3. package/src/Types.luau +69 -27
  4. package/src/api/Group.luau +101 -106
  5. package/src/api/Packet.luau +191 -157
  6. package/src/api/Query.luau +223 -282
  7. package/src/api/Scope.luau +46 -57
  8. package/src/api/Signal.luau +104 -137
  9. package/src/codec/Base.luau +69 -20
  10. package/src/codec/composite/Array.luau +189 -201
  11. package/src/codec/composite/Map.luau +97 -341
  12. package/src/codec/composite/Optional.luau +27 -23
  13. package/src/codec/composite/Shared.luau +96 -65
  14. package/src/codec/composite/Struct.luau +201 -339
  15. package/src/codec/composite/Tagged.luau +64 -178
  16. package/src/codec/composite/Tuple.luau +81 -95
  17. package/src/codec/datatype/Buffer.luau +49 -21
  18. package/src/codec/datatype/CFrame.luau +207 -30
  19. package/src/codec/datatype/Color.luau +21 -11
  20. package/src/codec/datatype/Instance.luau +29 -19
  21. package/src/codec/datatype/IntVector.luau +33 -21
  22. package/src/codec/datatype/NumberRange.luau +19 -10
  23. package/src/codec/datatype/Ray.luau +26 -22
  24. package/src/codec/datatype/Rect.luau +20 -16
  25. package/src/codec/datatype/Region.luau +51 -45
  26. package/src/codec/datatype/Sequence.luau +64 -56
  27. package/src/codec/datatype/String.luau +89 -56
  28. package/src/codec/datatype/UDim.luau +40 -22
  29. package/src/codec/datatype/Vector.luau +181 -17
  30. package/src/codec/meta/Auto.luau +295 -253
  31. package/src/codec/meta/Bitfield.luau +104 -148
  32. package/src/codec/meta/Custom.luau +8 -4
  33. package/src/codec/meta/Enum.luau +29 -57
  34. package/src/codec/meta/Float.luau +64 -0
  35. package/src/codec/meta/Nothing.luau +9 -5
  36. package/src/codec/meta/Unknown.luau +44 -35
  37. package/src/codec/primitive/Bool.luau +16 -26
  38. package/src/codec/primitive/Float16.luau +58 -64
  39. package/src/codec/primitive/Int.luau +68 -0
  40. package/src/codec/primitive/Number.luau +21 -43
  41. package/src/codec/primitive/Varint.luau +67 -46
  42. package/src/index.d.ts +249 -306
  43. package/src/init.luau +332 -173
  44. package/src/internal/Baseline.luau +29 -24
  45. package/src/internal/Channel.luau +346 -161
  46. package/src/internal/Middleware.luau +60 -85
  47. package/src/internal/Pool.luau +19 -30
  48. package/src/internal/Registry.luau +61 -101
  49. package/src/transport/Bridge.luau +64 -43
  50. package/src/transport/Client.luau +60 -117
  51. package/src/transport/Gate.luau +282 -133
  52. package/src/transport/Reader.luau +159 -100
  53. package/src/transport/Server.luau +147 -292
  54. package/src/api/Namespace.luau +0 -251
  55. package/src/codec/meta/Quantized.luau +0 -174
@@ -1,52 +1,229 @@
1
1
  --!strict
2
2
  --!native
3
- -- Axis-angle CFrame codec. Zero axis at identity for clean deltas.
3
+ -- CFrame codec with __call for smallest-three compressed variant.
4
4
 
5
5
  local Base = require(script.Parent.Parent.Base)
6
6
 
7
- local sqrt = math.sqrt
7
+ -- Constants -----------------------------------------------------------
8
8
 
9
- -- f32 machine epsilon * 2 to absorb round-trip noise.
10
9
  local EPSILON = 2.4e-7
10
+ local EPSILON_SQ = EPSILON * EPSILON
11
+ local SQRT = math.sqrt
12
+ local COS = math.cos
13
+ local SIN = math.sin
14
+ local ABS = math.abs
15
+ local ROUND = math.round
16
+ local ACOS = math.acos
11
17
 
12
- local function writeCFrame(b: buffer, c: number, value: CFrame): ()
13
- local position = value.Position
14
- local axis, angle = value:ToAxisAngle()
18
+ -- Smallest-three quantization constants
19
+ local INV_SQRT2 = 1 / SQRT(2)
20
+ local Q_SCALE = 1023 / (2 * INV_SQRT2)
21
+ local Q_INV = (2 * INV_SQRT2) / 1023
22
+
23
+ local band = bit32.band
24
+ local bor = bit32.bor
25
+ local lshift = bit32.lshift
26
+ local rshift = bit32.rshift
27
+
28
+ -- Private: Lossless axis-angle (24 bytes) -----------------------------
15
29
 
16
- buffer.writef32(b, c, position.X)
17
- buffer.writef32(b, c + 4, position.Y)
18
- buffer.writef32(b, c + 8, position.Z)
30
+ local function writeLossless(b: buffer, off: number, value: CFrame): ()
31
+ local pos = value.Position
32
+ buffer.writef32(b, off, pos.X)
33
+ buffer.writef32(b, off + 4, pos.Y)
34
+ buffer.writef32(b, off + 8, pos.Z)
19
35
 
36
+ local axis, angle = value:ToAxisAngle()
20
37
  if angle < EPSILON then
21
- buffer.writef32(b, c + 12, 0)
22
- buffer.writef32(b, c + 16, 0)
23
- buffer.writef32(b, c + 20, 0)
38
+ buffer.writef32(b, off + 12, 0)
39
+ buffer.writef32(b, off + 16, 0)
40
+ buffer.writef32(b, off + 20, 0)
24
41
  else
25
- buffer.writef32(b, c + 12, axis.X * angle)
26
- buffer.writef32(b, c + 16, axis.Y * angle)
27
- buffer.writef32(b, c + 20, axis.Z * angle)
42
+ buffer.writef32(b, off + 12, axis.X * angle)
43
+ buffer.writef32(b, off + 16, axis.Y * angle)
44
+ buffer.writef32(b, off + 20, axis.Z * angle)
28
45
  end
29
46
  end
30
47
 
31
- local function readCFrame(b: buffer, pos: number): CFrame
32
- local px = buffer.readf32(b, pos)
33
- local py = buffer.readf32(b, pos + 4)
34
- local pz = buffer.readf32(b, pos + 8)
35
- local rx = buffer.readf32(b, pos + 12)
36
- local ry = buffer.readf32(b, pos + 16)
37
- local rz = buffer.readf32(b, pos + 20)
48
+ local function readLossless(b: buffer, off: number): CFrame
49
+ local px = buffer.readf32(b, off)
50
+ local py = buffer.readf32(b, off + 4)
51
+ local pz = buffer.readf32(b, off + 8)
52
+ local rx = buffer.readf32(b, off + 12)
53
+ local ry = buffer.readf32(b, off + 16)
54
+ local rz = buffer.readf32(b, off + 20)
38
55
 
39
- local angle = sqrt(rx * rx + ry * ry + rz * rz)
40
- local origin = CFrame.new(px, py, pz)
56
+ local sqLen = rx * rx + ry * ry + rz * rz
57
+ if sqLen < EPSILON_SQ then
58
+ return CFrame.new(px, py, pz)
59
+ end
41
60
 
42
- if angle < EPSILON then
61
+ local angle = SQRT(sqLen)
62
+ local inv = 1 / angle
63
+ return CFrame.new(px, py, pz)
64
+ * CFrame.fromAxisAngle(Vector3.new(rx * inv, ry * inv, rz * inv), angle)
65
+ end
66
+
67
+ -- Private: Smallest-three compressed (16 bytes) -----------------------
68
+
69
+ local function writeCompressed(b: buffer, off: number, value: CFrame): ()
70
+ -- Position: 3x f32
71
+ local pos = value.Position
72
+ buffer.writef32(b, off, pos.X)
73
+ buffer.writef32(b, off + 4, pos.Y)
74
+ buffer.writef32(b, off + 8, pos.Z)
75
+
76
+ --[[
77
+ Convert CFrame rotation to quaternion via axis-angle.
78
+ Then apply smallest-three: drop the largest component,
79
+ quantize the other three into 10 bits each, pack into u32.
80
+ ]]
81
+ local axis, angle = value:ToAxisAngle()
82
+ local halfAngle = angle * 0.5
83
+ local s = SIN(halfAngle)
84
+ local qx = axis.X * s
85
+ local qy = axis.Y * s
86
+ local qz = axis.Z * s
87
+ local qw = COS(halfAngle)
88
+
89
+ -- Find largest component
90
+ local ax, ay, az, aw = ABS(qx), ABS(qy), ABS(qz), ABS(qw)
91
+ local largest = 3
92
+ local maxVal = aw
93
+
94
+ if ax > maxVal then
95
+ largest = 0
96
+ maxVal = ax
97
+ end
98
+ if ay > maxVal then
99
+ largest = 1
100
+ maxVal = ay
101
+ end
102
+ if az > maxVal then
103
+ largest = 2
104
+ maxVal = az
105
+ end
106
+
107
+ -- Negate quaternion if largest component is negative
108
+ local sign: number
109
+ if largest == 0 then
110
+ sign = if qx < 0 then -1 else 1
111
+ elseif largest == 1 then
112
+ sign = if qy < 0 then -1 else 1
113
+ elseif largest == 2 then
114
+ sign = if qz < 0 then -1 else 1
115
+ else
116
+ sign = if qw < 0 then -1 else 1
117
+ end
118
+ qx *= sign
119
+ qy *= sign
120
+ qz *= sign
121
+ qw *= sign
122
+
123
+ -- Select the three smallest components
124
+ local a, b2, c: number
125
+ if largest == 0 then
126
+ a, b2, c = qy, qz, qw
127
+ elseif largest == 1 then
128
+ a, b2, c = qx, qz, qw
129
+ elseif largest == 2 then
130
+ a, b2, c = qx, qy, qw
131
+ else
132
+ a, b2, c = qx, qy, qz
133
+ end
134
+
135
+ -- Quantize from [-1/sqrt(2), 1/sqrt(2)] to [0, 1023]
136
+ local qa = ROUND((a + INV_SQRT2) * Q_SCALE)
137
+ local qb = ROUND((b2 + INV_SQRT2) * Q_SCALE)
138
+ local qc = ROUND((c + INV_SQRT2) * Q_SCALE)
139
+
140
+ -- Clamp to [0, 1023]
141
+ qa = if qa < 0 then 0 elseif qa > 1023 then 1023 else qa
142
+ qb = if qb < 0 then 0 elseif qb > 1023 then 1023 else qb
143
+ qc = if qc < 0 then 0 elseif qc > 1023 then 1023 else qc
144
+
145
+ -- Pack: [index:2][a:10][b:10][c:10] = 32 bits
146
+ local packed = bor(lshift(largest, 30), lshift(qa, 20), lshift(qb, 10), qc)
147
+ buffer.writeu32(b, off + 12, packed)
148
+ end
149
+
150
+ local function readCompressed(b: buffer, off: number): CFrame
151
+ local px = buffer.readf32(b, off)
152
+ local py = buffer.readf32(b, off + 4)
153
+ local pz = buffer.readf32(b, off + 8)
154
+
155
+ local packed = buffer.readu32(b, off + 12)
156
+ local largest = rshift(packed, 30)
157
+ local qa = band(rshift(packed, 20), 0x3FF)
158
+ local qb = band(rshift(packed, 10), 0x3FF)
159
+ local qc = band(packed, 0x3FF)
160
+
161
+ -- Dequantize from [0, 1023] to [-1/sqrt(2), 1/sqrt(2)]
162
+ local a = qa * Q_INV - INV_SQRT2
163
+ local b2 = qb * Q_INV - INV_SQRT2
164
+ local c = qc * Q_INV - INV_SQRT2
165
+
166
+ -- Reconstruct largest component
167
+ local sqSum = a * a + b2 * b2 + c * c
168
+ local d = SQRT(if sqSum < 1 then 1 - sqSum else 0)
169
+
170
+ -- Place components
171
+ local qx, qy, qz, qw: number
172
+ if largest == 0 then
173
+ qx, qy, qz, qw = d, a, b2, c
174
+ elseif largest == 1 then
175
+ qx, qy, qz, qw = a, d, b2, c
176
+ elseif largest == 2 then
177
+ qx, qy, qz, qw = a, b2, d, c
178
+ else
179
+ qx, qy, qz, qw = a, b2, c, d
180
+ end
181
+
182
+ -- Build CFrame from position + quaternion
183
+ local origin = CFrame.new(px, py, pz)
184
+ if qx * qx + qy * qy + qz * qz < EPSILON_SQ then
43
185
  return origin
44
186
  end
45
187
 
46
- local inv = 1 / angle
47
- return origin * CFrame.fromAxisAngle(Vector3.new(rx * inv, ry * inv, rz * inv), angle)
188
+ -- Convert quaternion to axis-angle for CFrame construction
189
+ local len = SQRT(qx * qx + qy * qy + qz * qz)
190
+ local angle = 2 * ACOS(if qw > 1 then 1 elseif qw < -1 then -1 else qw)
191
+ local inv = 1 / len
192
+ return origin * CFrame.fromAxisAngle(Vector3.new(qx * inv, qy * inv, qz * inv), angle)
193
+ end
194
+
195
+ -- __call factory for compressed variant
196
+ local function compressedFactory(_self: any): any
197
+ return Base.define(16, writeCompressed, readCompressed, {
198
+ _typeCheck = "CFrame",
199
+ })
48
200
  end
49
201
 
50
- return table.freeze({
51
- cframe = Base.define(24, writeCFrame, readCFrame),
52
- })
202
+ -- Public --------------------------------------------------------------
203
+
204
+ local CFrameCodec = {}
205
+
206
+ CFrameCodec.cframe = setmetatable(
207
+ {
208
+ _size = 24,
209
+ _directWrite = writeLossless,
210
+ _directRead = readLossless,
211
+ _typeCheck = "CFrame",
212
+
213
+ write = function(ch: Types.ChannelState, value: CFrame): ()
214
+ local cursor = ch.cursor
215
+ if cursor + 24 > ch.size then
216
+ alloc(ch, 24)
217
+ end
218
+ writeLossless(ch.buff, cursor, value)
219
+ ch.cursor = cursor + 24
220
+ end,
221
+
222
+ read = function(src: buffer, pos: number, _refs: { Instance }?): (CFrame, number)
223
+ return readLossless(src, pos), 24
224
+ end,
225
+ } :: any,
226
+ { __call = compressedFactory }
227
+ )
228
+
229
+ return table.freeze(CFrameCodec)
@@ -1,18 +1,28 @@
1
1
  --!strict
2
- --!native
3
- -- Color3 codec. 3 bytes, 0-255 per channel, clamped.
2
+ --!optimize 2
3
+ -- Color3 codec. 3 bytes, RGB u8 per channel, clamped.
4
4
 
5
5
  local Base = require(script.Parent.Parent.Base)
6
6
 
7
+ -- Private -------------------------------------------------------------
8
+
7
9
  local round = math.round
8
10
  local clamp = math.clamp
9
11
 
10
- return table.freeze({
11
- color3 = Base.define(3, function(b: buffer, o: number, v: Color3): ()
12
- buffer.writeu8(b, o, round(clamp(v.R, 0, 1) * 255))
13
- buffer.writeu8(b, o + 1, round(clamp(v.G, 0, 1) * 255))
14
- buffer.writeu8(b, o + 2, round(clamp(v.B, 0, 1) * 255))
15
- end, function(b: buffer, o: number): Color3
16
- return Color3.fromRGB(buffer.readu8(b, o), buffer.readu8(b, o + 1), buffer.readu8(b, o + 2))
17
- end),
18
- })
12
+ -- Public --------------------------------------------------------------
13
+
14
+ local ColorCodec = {}
15
+
16
+ ColorCodec.color3 = Base.define(3, function(b: buffer, off: number, value: Color3): ()
17
+ buffer.writeu8(b, off, round(clamp(value.R, 0, 1) * 255))
18
+ buffer.writeu8(b, off + 1, round(clamp(value.G, 0, 1) * 255))
19
+ buffer.writeu8(b, off + 2, round(clamp(value.B, 0, 1) * 255))
20
+ end, function(b: buffer, off: number): Color3
21
+ return Color3.fromRGB(
22
+ buffer.readu8(b, off),
23
+ buffer.readu8(b, off + 1),
24
+ buffer.readu8(b, off + 2)
25
+ )
26
+ end, { _typeCheck = "Color3" })
27
+
28
+ return table.freeze(ColorCodec)
@@ -1,49 +1,59 @@
1
1
  --!strict
2
- --!native
2
+ --!optimize 2
3
3
  -- Instance codec via sidecar reference array.
4
4
 
5
- local Channel = require(script.Parent.Parent.Parent.internal.Channel)
5
+ local Base = require(script.Parent.Parent.Base)
6
6
  local Types = require(script.Parent.Parent.Parent.Types)
7
7
 
8
- type ChannelState = Types.ChannelState
8
+ -- Private -------------------------------------------------------------
9
9
 
10
- local alloc = Channel.alloc
10
+ local alloc = Base.alloc
11
+ local writeu16 = buffer.writeu16
12
+ local readu16 = buffer.readu16
11
13
 
12
14
  -- Public --------------------------------------------------------------
13
15
 
14
16
  local InstanceCodec = {}
15
17
 
18
+ -- No _directWrite/_directRead: write needs ch.refs, so structs can't use the all-direct path
16
19
  InstanceCodec.inst = table.freeze({
17
20
  _size = 2,
18
- write = function(ch: ChannelState, value: Instance): ()
19
- local refs = ch.refs
20
- local idx = #refs + 1
21
- if idx > 65535 then
22
- error(`[Lync] Instance ref overflow: {idx} exceeds u16 max`)
21
+ _typeCheck = "Instance",
22
+
23
+ write = function(ch: Types.ChannelState, value: Instance): ()
24
+ local idx = ch.refCount + 1
25
+ if idx > 0xFFFF then
26
+ error("[Lync] Instance: ref overflow (>65535)")
23
27
  end
24
28
 
25
- refs[idx] = value
29
+ ch.refs[idx] = value
30
+ ch.refCount = idx
26
31
 
27
- local c = ch.cursor
28
- if c + 2 > ch.size then
32
+ local cursor = ch.cursor
33
+ if cursor + 2 > ch.size then
29
34
  alloc(ch, 2)
30
35
  end
31
- buffer.writeu16(ch.buff, c, idx)
32
- ch.cursor = c + 2
36
+ writeu16(ch.buff, cursor, idx)
37
+ ch.cursor = cursor + 2
33
38
  end,
39
+
34
40
  read = function(src: buffer, pos: number, refs: { Instance }?): (Instance, number)
35
- local idx = buffer.readu16(src, pos)
36
41
  if not refs then
37
- error("[Lync] Instance read requires refs array")
42
+ error("[Lync] Instance: read requires refs array")
43
+ end
44
+
45
+ local idx = readu16(src, pos)
46
+ if idx < 1 or idx > #refs then
47
+ error(`[Lync] Instance: ref index {idx} out of bounds`)
38
48
  end
39
49
 
40
50
  local inst = refs[idx]
41
- if not inst then
42
- error(`[Lync] Instance ref index out of bounds: {idx}`)
51
+ if typeof(inst) ~= "Instance" then
52
+ error("[Lync] Instance: invalid ref (expected Instance)")
43
53
  end
44
54
 
45
55
  return inst, 2
46
56
  end,
47
- })
57
+ } :: any)
48
58
 
49
59
  return table.freeze(InstanceCodec)
@@ -1,25 +1,37 @@
1
1
  --!strict
2
- --!native
3
- -- Vector2int16(4B) and Vector3int16(6B) codecs.
2
+ --!optimize 2
3
+ -- Vector2int16 (4 bytes) and Vector3int16 (6 bytes) codecs.
4
4
 
5
5
  local Base = require(script.Parent.Parent.Base)
6
6
 
7
- return table.freeze({
8
- vec2int16 = Base.define(4, function(b: buffer, o: number, v: Vector2int16): ()
9
- buffer.writei16(b, o, v.X)
10
- buffer.writei16(b, o + 2, v.Y)
11
- end, function(b: buffer, o: number): Vector2int16
12
- return Vector2int16.new(buffer.readi16(b, o), buffer.readi16(b, o + 2))
13
- end),
14
- vec3int16 = Base.define(6, function(b: buffer, o: number, v: Vector3int16): ()
15
- buffer.writei16(b, o, v.X)
16
- buffer.writei16(b, o + 2, v.Y)
17
- buffer.writei16(b, o + 4, v.Z)
18
- end, function(b: buffer, o: number): Vector3int16
19
- return Vector3int16.new(
20
- buffer.readi16(b, o),
21
- buffer.readi16(b, o + 2),
22
- buffer.readi16(b, o + 4)
23
- )
24
- end),
25
- })
7
+ -- Private -------------------------------------------------------------
8
+
9
+ local function writeI16(b: buffer, off: number, v: number): ()
10
+ buffer.writeu16(b, off, if v < 0 then v + 0x10000 else v)
11
+ end
12
+
13
+ local function readI16(b: buffer, off: number): number
14
+ local raw = buffer.readu16(b, off)
15
+ return if raw >= 0x8000 then raw - 0x10000 else raw
16
+ end
17
+
18
+ -- Public --------------------------------------------------------------
19
+
20
+ local IntVectorCodec = {}
21
+
22
+ IntVectorCodec.vec2int16 = Base.define(4, function(b: buffer, off: number, value: Vector2int16): ()
23
+ writeI16(b, off, value.X)
24
+ writeI16(b, off + 2, value.Y)
25
+ end, function(b: buffer, off: number): Vector2int16
26
+ return Vector2int16.new(readI16(b, off), readI16(b, off + 2))
27
+ end, { _typeCheck = "Vector2int16" })
28
+
29
+ IntVectorCodec.vec3int16 = Base.define(6, function(b: buffer, off: number, value: Vector3int16): ()
30
+ writeI16(b, off, value.X)
31
+ writeI16(b, off + 2, value.Y)
32
+ writeI16(b, off + 4, value.Z)
33
+ end, function(b: buffer, off: number): Vector3int16
34
+ return Vector3int16.new(readI16(b, off), readI16(b, off + 2), readI16(b, off + 4))
35
+ end, { _typeCheck = "Vector3int16" })
36
+
37
+ return table.freeze(IntVectorCodec)
@@ -1,14 +1,23 @@
1
1
  --!strict
2
- --!native
3
- -- NumberRange codec. 8 bytes: min f32 + max f32.
2
+ --!optimize 2
3
+ -- NumberRange codec. 8 bytes: Min f32 + Max f32.
4
4
 
5
5
  local Base = require(script.Parent.Parent.Base)
6
6
 
7
- return table.freeze({
8
- numberRange = Base.define(8, function(b: buffer, o: number, v: NumberRange): ()
9
- buffer.writef32(b, o, v.Min)
10
- buffer.writef32(b, o + 4, v.Max)
11
- end, function(b: buffer, o: number): NumberRange
12
- return NumberRange.new(buffer.readf32(b, o), buffer.readf32(b, o + 4))
13
- end),
14
- })
7
+ -- Public --------------------------------------------------------------
8
+
9
+ local NumberRangeCodec = {}
10
+
11
+ NumberRangeCodec.numberRange = Base.define(
12
+ 8,
13
+ function(b: buffer, off: number, value: NumberRange): ()
14
+ buffer.writef32(b, off, value.Min)
15
+ buffer.writef32(b, off + 4, value.Max)
16
+ end,
17
+ function(b: buffer, off: number): NumberRange
18
+ return NumberRange.new(buffer.readf32(b, off), buffer.readf32(b, off + 4))
19
+ end,
20
+ { _typeCheck = "NumberRange" }
21
+ )
22
+
23
+ return table.freeze(NumberRangeCodec)
@@ -1,27 +1,31 @@
1
1
  --!strict
2
- --!native
3
- -- Ray codec. 24 bytes: origin vec3 + direction vec3.
2
+ --!optimize 2
3
+ -- Ray codec. 24 bytes: origin + direction as 6x f32.
4
4
 
5
5
  local Base = require(script.Parent.Parent.Base)
6
6
 
7
- return table.freeze({
8
- ray = Base.define(24, function(b: buffer, o: number, v: Ray): ()
9
- local origin = v.Origin
10
- local direction = v.Direction
11
- buffer.writef32(b, o, origin.X)
12
- buffer.writef32(b, o + 4, origin.Y)
13
- buffer.writef32(b, o + 8, origin.Z)
14
- buffer.writef32(b, o + 12, direction.X)
15
- buffer.writef32(b, o + 16, direction.Y)
16
- buffer.writef32(b, o + 20, direction.Z)
17
- end, function(b: buffer, o: number): Ray
18
- return Ray.new(
19
- Vector3.new(buffer.readf32(b, o), buffer.readf32(b, o + 4), buffer.readf32(b, o + 8)),
20
- Vector3.new(
21
- buffer.readf32(b, o + 12),
22
- buffer.readf32(b, o + 16),
23
- buffer.readf32(b, o + 20)
24
- )
7
+ -- Public --------------------------------------------------------------
8
+
9
+ local RayCodec = {}
10
+
11
+ RayCodec.ray = Base.define(24, function(b: buffer, off: number, value: Ray): ()
12
+ local o = value.Origin
13
+ local d = value.Direction
14
+ buffer.writef32(b, off, o.X)
15
+ buffer.writef32(b, off + 4, o.Y)
16
+ buffer.writef32(b, off + 8, o.Z)
17
+ buffer.writef32(b, off + 12, d.X)
18
+ buffer.writef32(b, off + 16, d.Y)
19
+ buffer.writef32(b, off + 20, d.Z)
20
+ end, function(b: buffer, off: number): Ray
21
+ 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)
25
27
  )
26
- end),
27
- })
28
+ )
29
+ end, { _typeCheck = "Ray" })
30
+
31
+ return table.freeze(RayCodec)
@@ -1,21 +1,25 @@
1
1
  --!strict
2
- --!native
2
+ --!optimize 2
3
3
  -- Rect codec. 16 bytes: 4x f32.
4
4
 
5
5
  local Base = require(script.Parent.Parent.Base)
6
6
 
7
- return table.freeze({
8
- rect = Base.define(16, function(b: buffer, o: number, v: Rect): ()
9
- buffer.writef32(b, o, v.Min.X)
10
- buffer.writef32(b, o + 4, v.Min.Y)
11
- buffer.writef32(b, o + 8, v.Max.X)
12
- buffer.writef32(b, o + 12, v.Max.Y)
13
- end, function(b: buffer, o: number): Rect
14
- return Rect.new(
15
- buffer.readf32(b, o),
16
- buffer.readf32(b, o + 4),
17
- buffer.readf32(b, o + 8),
18
- buffer.readf32(b, o + 12)
19
- )
20
- end),
21
- })
7
+ -- Public --------------------------------------------------------------
8
+
9
+ local RectCodec = {}
10
+
11
+ RectCodec.rect = Base.define(16, function(b: buffer, off: number, value: Rect): ()
12
+ buffer.writef32(b, off, value.Min.X)
13
+ buffer.writef32(b, off + 4, value.Min.Y)
14
+ buffer.writef32(b, off + 8, value.Max.X)
15
+ buffer.writef32(b, off + 12, value.Max.Y)
16
+ end, function(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
+ )
23
+ end, { _typeCheck = "Rect" })
24
+
25
+ return table.freeze(RectCodec)