@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,8 +1,10 @@
1
1
  --!strict
2
- --!optimize 2
2
+ --!native
3
3
  -- NumberSequence (12B/keypoint) and ColorSequence (7B/keypoint) codecs.
4
4
 
5
5
  local Base = require(script.Parent.Parent.Base)
6
+ local Constants = require(script.Parent.Parent.Parent.util.Constants)
7
+ local Log = require(script.Parent.Parent.Parent.util.Log)
6
8
  local Types = require(script.Parent.Parent.Parent.Types)
7
9
  local Varint = require(script.Parent.Parent.primitive.Varint)
8
10
 
@@ -14,34 +16,88 @@ local MAX_KEYPOINTS = 20
14
16
 
15
17
  -- Private ----------------------------------------------------------------
16
18
 
19
+ local U8_MAX = Constants.U8_MAX
17
20
  local alloc = Base.alloc
21
+ local writef32 = buffer.writef32
22
+ local readf32 = buffer.readf32
23
+ local writeu8 = buffer.writeu8
24
+ local readu8 = buffer.readu8
18
25
  local round = math.round
19
26
  local clamp = math.clamp
20
-
21
- local function writeNumberSequence(ch: Types.ChannelState, value: NumberSequence): ()
22
- local keypoints = value.Keypoints
23
- local count = #keypoints
24
- Varint.write(ch, count)
27
+ local varintRead = Varint.read
28
+ local varintWrite = Varint.write
29
+
30
+ --[[
31
+ Common write prelude: count cap check, varint count, payload alloc.
32
+ Returns (cursor, b) for the per-keypoint writer; (nil, nil) when count
33
+ is 0 so callers short-circuit.
34
+ ]]
35
+ local function beginSeqWrite(
36
+ ch: Types.ChannelState,
37
+ label: string,
38
+ count: number,
39
+ kpBytes: number
40
+ ): (number?, buffer?)
41
+ if count > MAX_KEYPOINTS then
42
+ Log.error(`{label}.write: keypoint count {count} exceeds Roblox limit {MAX_KEYPOINTS}`)
43
+ end
44
+ varintWrite(ch, count)
25
45
  if count == 0 then
26
- return
46
+ return nil, nil
27
47
  end
28
48
 
29
- local bytes = count * NUMSEQ_KP_BYTES
49
+ local bytes = count * kpBytes
30
50
  local cursor = ch.cursor
31
51
  if cursor + bytes > ch.size then
32
52
  alloc(ch, bytes)
33
53
  end
34
- local b = ch.buff
54
+ ch.cursor = cursor + bytes
55
+ return cursor, ch.buff
56
+ end
35
57
 
36
- local off = cursor
58
+ --[[
59
+ Common read prelude: varint count, cap check, bounds check. Returns
60
+ (count, dataStart, lenBytes) for the per-keypoint reader; (0, _, lenBytes)
61
+ when payload is empty.
62
+ ]]
63
+ local function beginSeqRead(
64
+ src: buffer,
65
+ pos: number,
66
+ label: string,
67
+ kpBytes: number
68
+ ): (number, number, number)
69
+ local count, lenBytes = varintRead(src, pos)
70
+ if count == 0 then
71
+ return 0, pos + lenBytes, lenBytes
72
+ end
73
+ if count > MAX_KEYPOINTS then
74
+ Log.error(`{label}.read: keypoint count {count} exceeds Roblox limit {MAX_KEYPOINTS}`)
75
+ end
76
+
77
+ local bytes = count * kpBytes
78
+ local dataStart = pos + lenBytes
79
+ if dataStart + bytes > buffer.len(src) then
80
+ Log.error(`{label}.read: payload {bytes}B exceeds remaining buffer`)
81
+ end
82
+ return count, dataStart, lenBytes
83
+ end
84
+
85
+ local function writeNumberSequence(ch: Types.ChannelState, value: NumberSequence): ()
86
+ local keypoints = value.Keypoints
87
+ local count = #keypoints
88
+ local cursor, b = beginSeqWrite(ch, "NumberSequence", count, NUMSEQ_KP_BYTES)
89
+ if not cursor then
90
+ return
91
+ end
92
+ local off = cursor :: number
93
+ local buf = b :: buffer
37
94
  for i = 1, count do
38
95
  local kp = keypoints[i]
39
- buffer.writef32(b, off, kp.Time)
40
- buffer.writef32(b, off + 4, kp.Value)
41
- buffer.writef32(b, off + 8, kp.Envelope)
96
+ writef32(buf, off, kp.Time)
97
+ writef32(buf, off + 4, kp.Value)
98
+ writef32(buf, off + 8, kp.Envelope)
42
99
  off += NUMSEQ_KP_BYTES
43
100
  end
44
- ch.cursor = cursor + bytes
45
101
  end
46
102
 
47
103
  local function readNumberSequence(
@@ -49,61 +105,42 @@ local function readNumberSequence(
49
105
  pos: number,
50
106
  _refs: { Instance }?
51
107
  ): (NumberSequence, number)
52
- local count, lenBytes = Varint.read(src, pos)
108
+ local count, dataStart, lenBytes = beginSeqRead(src, pos, "NumberSequence", NUMSEQ_KP_BYTES)
53
109
  if count == 0 then
54
110
  return NumberSequence.new(0), lenBytes
55
111
  end
56
- if count > MAX_KEYPOINTS then
57
- error(
58
- `[Lync] NumberSequence.read: keypoint count {count} exceeds Roblox limit {MAX_KEYPOINTS}`
59
- )
60
- end
61
-
62
- local bytes = count * NUMSEQ_KP_BYTES
63
- local dataStart = pos + lenBytes
64
- if dataStart + bytes > buffer.len(src) then
65
- error("[Lync] NumberSequence.read: data exceeds buffer")
66
- end
67
112
 
68
113
  local keypoints = table.create(count)
69
114
  local off = dataStart
70
115
  for i = 1, count do
71
116
  keypoints[i] = NumberSequenceKeypoint.new(
72
- buffer.readf32(src, off),
73
- buffer.readf32(src, off + 4),
74
- buffer.readf32(src, off + 8)
117
+ readf32(src, off),
118
+ readf32(src, off + 4),
119
+ readf32(src, off + 8)
75
120
  )
76
121
  off += NUMSEQ_KP_BYTES
77
122
  end
78
- return NumberSequence.new(keypoints), lenBytes + bytes
123
+ return NumberSequence.new(keypoints), lenBytes + count * NUMSEQ_KP_BYTES
79
124
  end
80
125
 
81
126
  local function writeColorSequence(ch: Types.ChannelState, value: ColorSequence): ()
82
127
  local keypoints = value.Keypoints
83
128
  local count = #keypoints
84
- Varint.write(ch, count)
85
- if count == 0 then
129
+ local cursor, b = beginSeqWrite(ch, "ColorSequence", count, COLSEQ_KP_BYTES)
130
+ if not cursor then
86
131
  return
87
132
  end
88
-
89
- local bytes = count * COLSEQ_KP_BYTES
90
- local cursor = ch.cursor
91
- if cursor + bytes > ch.size then
92
- alloc(ch, bytes)
93
- end
94
- local b = ch.buff
95
-
96
- local off = cursor
133
+ local off = cursor :: number
134
+ local buf = b :: buffer
97
135
  for i = 1, count do
98
136
  local kp = keypoints[i]
99
137
  local c = kp.Value
100
- buffer.writef32(b, off, kp.Time)
101
- buffer.writeu8(b, off + 4, round(clamp(c.R, 0, 1) * 255))
102
- buffer.writeu8(b, off + 5, round(clamp(c.G, 0, 1) * 255))
103
- buffer.writeu8(b, off + 6, round(clamp(c.B, 0, 1) * 255))
138
+ writef32(buf, off, kp.Time)
139
+ writeu8(buf, off + 4, round(clamp(c.R, 0, 1) * U8_MAX))
140
+ writeu8(buf, off + 5, round(clamp(c.G, 0, 1) * U8_MAX))
141
+ writeu8(buf, off + 6, round(clamp(c.B, 0, 1) * U8_MAX))
104
142
  off += COLSEQ_KP_BYTES
105
143
  end
106
- ch.cursor = cursor + bytes
107
144
  end
108
145
 
109
146
  local function readColorSequence(
@@ -111,36 +148,21 @@ local function readColorSequence(
111
148
  pos: number,
112
149
  _refs: { Instance }?
113
150
  ): (ColorSequence, number)
114
- local count, lenBytes = Varint.read(src, pos)
151
+ local count, dataStart, lenBytes = beginSeqRead(src, pos, "ColorSequence", COLSEQ_KP_BYTES)
115
152
  if count == 0 then
116
153
  return ColorSequence.new(Color3.new()), lenBytes
117
154
  end
118
- if count > MAX_KEYPOINTS then
119
- error(
120
- `[Lync] ColorSequence.read: keypoint count {count} exceeds Roblox limit {MAX_KEYPOINTS}`
121
- )
122
- end
123
-
124
- local bytes = count * COLSEQ_KP_BYTES
125
- local dataStart = pos + lenBytes
126
- if dataStart + bytes > buffer.len(src) then
127
- error("[Lync] ColorSequence.read: data exceeds buffer")
128
- end
129
155
 
130
156
  local keypoints = table.create(count)
131
157
  local off = dataStart
132
158
  for i = 1, count do
133
159
  keypoints[i] = ColorSequenceKeypoint.new(
134
- buffer.readf32(src, off),
135
- Color3.fromRGB(
136
- buffer.readu8(src, off + 4),
137
- buffer.readu8(src, off + 5),
138
- buffer.readu8(src, off + 6)
139
- )
160
+ readf32(src, off),
161
+ Color3.fromRGB(readu8(src, off + 4), readu8(src, off + 5), readu8(src, off + 6))
140
162
  )
141
163
  off += COLSEQ_KP_BYTES
142
164
  end
143
- return ColorSequence.new(keypoints), lenBytes + bytes
165
+ return ColorSequence.new(keypoints), lenBytes + count * COLSEQ_KP_BYTES
144
166
  end
145
167
 
146
168
  -- Public -----------------------------------------------------------------
@@ -1,21 +1,23 @@
1
1
  --!strict
2
2
  --!native
3
- -- Variable-length UTF-8 string codec with __call factory for bounded variant.
3
+ -- UTF-8 string codec. __call yields a length-bounded variant.
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 writeString(ch: Types.ChannelState, value: string): ()
15
16
  local 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
@@ -47,23 +49,28 @@ local function readString(src: buffer, pos: number, _refs: { Instance }?): (stri
47
49
 
48
50
  local dataStart = pos + lenBytes
49
51
  if dataStart + len > buffer.len(src) then
50
- error("[Lync] String.read: length exceeds remaining buffer")
52
+ Log.error(`length {len}B exceeds remaining buffer`)
51
53
  end
52
54
  return buffer.readstring(src, dataStart, len), lenBytes + len
53
55
  end
54
56
 
57
+ -- _maxStringLength lets Gate.validate reject oversized values send-side.
55
58
  local function boundedFactory(_self, maxLength: number): Types.InternalCodec<string>
56
- if maxLength <= 0 then
57
- error("[Lync] Lync.string: maxLength must be positive")
58
- end
59
+ Log.assert(maxLength > 0, "maxLength must be positive")
59
60
 
60
61
  return table.freeze({
61
62
  _typeCheck = "string",
62
- write = writeString,
63
+ _maxStringLength = maxLength,
64
+ write = function(ch: Types.ChannelState, value: string): ()
65
+ if #value > maxLength then
66
+ Log.error(`length {#value} exceeds max {maxLength}`)
67
+ end
68
+ writeString(ch, value)
69
+ end,
63
70
  read = function(src: buffer, pos: number, _refs: { Instance }?): (string, number)
64
71
  local len, lenBytes = readLengthPrefix(src, pos)
65
72
  if len > maxLength then
66
- error(`[Lync] String.read: length {len} exceeds max {maxLength}`)
73
+ Log.error(`length {len} exceeds max {maxLength}`)
67
74
  end
68
75
  if len == 0 then
69
76
  return "", lenBytes
@@ -71,7 +78,7 @@ local function boundedFactory(_self, maxLength: number): Types.InternalCodec<str
71
78
 
72
79
  local dataStart = pos + lenBytes
73
80
  if dataStart + len > buffer.len(src) then
74
- error("[Lync] String.read: length exceeds remaining buffer")
81
+ Log.error(`length {len}B exceeds remaining buffer`)
75
82
  end
76
83
  return buffer.readstring(src, dataStart, len), lenBytes + len
77
84
  end,
@@ -1,36 +1,38 @@
1
1
  --!strict
2
- --!optimize 2
3
- -- UDim (8 bytes) and UDim2 (16 bytes) codecs. Scale is f32, Offset is i32.
2
+ --!native
3
+ -- UDim (8B) and UDim2 (16B) codecs. Scale = f32, Offset = i32.
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 writeI32 = Signed.writeI32
11
13
  local readi32 = buffer.readi32
12
14
 
13
15
  local function writeUDim(b: buffer, off: number, value: UDim): ()
14
- buffer.writef32(b, off, value.Scale)
16
+ writef32(b, off, value.Scale)
15
17
  writeI32(b, off + 4, value.Offset)
16
18
  end
17
19
 
18
20
  local function readUDim(b: buffer, off: number): UDim
19
- return UDim.new(buffer.readf32(b, off), readi32(b, off + 4))
21
+ return UDim.new(readf32(b, off), readi32(b, off + 4))
20
22
  end
21
23
 
22
24
  local function writeUDim2(b: buffer, off: number, value: UDim2): ()
23
25
  local x, y = value.X, value.Y
24
- buffer.writef32(b, off, x.Scale)
26
+ writef32(b, off, x.Scale)
25
27
  writeI32(b, off + 4, x.Offset)
26
- buffer.writef32(b, off + 8, y.Scale)
28
+ writef32(b, off + 8, y.Scale)
27
29
  writeI32(b, off + 12, y.Offset)
28
30
  end
29
31
 
30
32
  local function readUDim2(b: buffer, off: number): UDim2
31
33
  return UDim2.new(
32
- UDim.new(buffer.readf32(b, off), readi32(b, off + 4)),
33
- UDim.new(buffer.readf32(b, off + 8), readi32(b, off + 12))
34
+ UDim.new(readf32(b, off), readi32(b, off + 4)),
35
+ UDim.new(readf32(b, off + 8), readi32(b, off + 12))
34
36
  )
35
37
  end
36
38
 
@@ -1,75 +1,36 @@
1
1
  --!strict
2
- --!optimize 2
3
- -- Vector2 and Vector3 codecs with __call factory for quantized variants.
2
+ --!native
3
+ -- Vector2 / Vector3 codecs. __call yields a quantized variant.
4
4
 
5
5
  local Base = require(script.Parent.Parent.Base)
6
+ local Quantize = require(script.Parent.Parent.Parent.util.Quantize)
6
7
  local Types = require(script.Parent.Parent.Parent.Types)
7
8
 
8
9
  -- Private ----------------------------------------------------------------
9
10
 
10
11
  local alloc = Base.alloc
11
- local ceil = math.ceil
12
+ local writef32 = buffer.writef32
13
+ local readf32 = buffer.readf32
12
14
  local clamp = math.clamp
13
15
  local round = math.round
14
- local maxN = math.max
15
- local minN = math.min
16
-
17
- --[[
18
- Pick the narrowest u8/u16/u32 wire form for a quantized component
19
- range. Returns (compBytes, writeFn, readFn, scale, invScale).
20
- ]]
21
- local function quantizeSetup(
22
- apiName: string,
23
- rangeMin: number,
24
- rangeMax: number,
25
- precision: number
26
- ): (
27
- number,
28
- (buffer, number, number) -> (),
29
- (buffer, number) -> number,
30
- number,
31
- number
32
- )
33
- if rangeMin > rangeMax then
34
- error(`[Lync] {apiName}: min must be <= max`)
35
- end
36
- if precision <= 0 then
37
- error(`[Lync] {apiName}: precision must be positive`)
38
- end
39
-
40
- local delta = rangeMax - rangeMin
41
- local maxInt = minN(0xFFFFFFFF, maxN(1, ceil(delta / precision)))
42
-
43
- if maxInt <= 0xFF then
44
- return 1, buffer.writeu8, buffer.readu8, maxInt / delta, delta / maxInt
45
- end
46
- if maxInt <= 0xFFFF then
47
- return 2, buffer.writeu16, buffer.readu16, maxInt / delta, delta / maxInt
48
- end
49
- return 4, buffer.writeu32, buffer.readu32, maxInt / delta, delta / maxInt
50
- end
51
16
 
52
17
  local function writeVec2(b: buffer, off: number, value: Vector2): ()
53
- buffer.writef32(b, off, value.X)
54
- buffer.writef32(b, off + 4, value.Y)
18
+ writef32(b, off, value.X)
19
+ writef32(b, off + 4, value.Y)
55
20
  end
56
21
 
57
22
  local function readVec2(b: buffer, off: number): Vector2
58
- return Vector2.new(buffer.readf32(b, off), buffer.readf32(b, off + 4))
23
+ return Vector2.new(readf32(b, off), readf32(b, off + 4))
59
24
  end
60
25
 
61
26
  local function writeVec3(b: buffer, off: number, value: Vector3): ()
62
- buffer.writef32(b, off, value.X)
63
- buffer.writef32(b, off + 4, value.Y)
64
- buffer.writef32(b, off + 8, value.Z)
27
+ writef32(b, off, value.X)
28
+ writef32(b, off + 4, value.Y)
29
+ writef32(b, off + 8, value.Z)
65
30
  end
66
31
 
67
32
  local function readVec3(b: buffer, off: number): Vector3
68
- return Vector3.new(
69
- buffer.readf32(b, off),
70
- buffer.readf32(b, off + 4),
71
- buffer.readf32(b, off + 8)
72
- )
33
+ return Vector3.new(readf32(b, off), readf32(b, off + 4), readf32(b, off + 8))
73
34
  end
74
35
 
75
36
  local function quantizeVec2(
@@ -78,14 +39,14 @@ local function quantizeVec2(
78
39
  rangeMax: number,
79
40
  precision: number
80
41
  ): Types.InternalCodec<Vector2>
42
+ -- Degenerate range: emit nothing, decode to the constant.
81
43
  if rangeMax - rangeMin == 0 then
82
44
  return Base.constant(Vector2.new(rangeMin, rangeMin))
83
45
  end
84
46
 
85
- local compBytes, wfn, rfn, scale, invScale =
86
- quantizeSetup("Lync.vec2", rangeMin, rangeMax, precision)
47
+ local compBytes, wfn, rfn, scale, invScale, delta =
48
+ Quantize.setup("Lync.vec2", rangeMin, rangeMax, precision)
87
49
  local totalSize = compBytes * 2
88
- local delta = rangeMax - rangeMin
89
50
 
90
51
  return Base.define(totalSize, function(b: buffer, off: number, value: Vector2): ()
91
52
  wfn(b, off, round(clamp(value.X - rangeMin, 0, delta) * scale))
@@ -108,20 +69,20 @@ local function quantizeVec3(
108
69
  return Base.constant(Vector3.new(rangeMin, rangeMin, rangeMin))
109
70
  end
110
71
 
111
- local compBytes, wfn, rfn, scale, invScale =
112
- quantizeSetup("Lync.vec3", rangeMin, rangeMax, precision)
72
+ local compBytes, wfn, rfn, scale, invScale, delta =
73
+ Quantize.setup("Lync.vec3", rangeMin, rangeMax, precision)
113
74
  local totalSize = compBytes * 3
114
- local delta = rangeMax - rangeMin
75
+ local off2 = compBytes * 2
115
76
 
116
77
  return Base.define(totalSize, function(b: buffer, off: number, value: Vector3): ()
117
78
  wfn(b, off, round(clamp(value.X - rangeMin, 0, delta) * scale))
118
79
  wfn(b, off + compBytes, round(clamp(value.Y - rangeMin, 0, delta) * scale))
119
- wfn(b, off + compBytes * 2, round(clamp(value.Z - rangeMin, 0, delta) * scale))
80
+ wfn(b, off + off2, round(clamp(value.Z - rangeMin, 0, delta) * scale))
120
81
  end, function(b: buffer, off: number): Vector3
121
82
  return Vector3.new(
122
83
  rfn(b, off) * invScale + rangeMin,
123
84
  rfn(b, off + compBytes) * invScale + rangeMin,
124
- rfn(b, off + compBytes * 2) * invScale + rangeMin
85
+ rfn(b, off + off2) * invScale + rangeMin
125
86
  )
126
87
  end, { _typeCheck = "Vector3", _min = rangeMin, _max = rangeMax })
127
88
  end