@axpecter/lync 2.3.1 → 2.3.3

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.
@@ -11,14 +11,14 @@ local Types = require(script.Parent.Parent.Parent.Types)
11
11
  -- Constants --------------------------------------------------------------
12
12
 
13
13
  --[[
14
- Delta flag space, shared across deltaStruct/deltaArray/deltaMap:
15
- 0 UNCHANGED (decoder reuses cache)
16
- 1 FULL (full payload follows)
17
- Struct's per-segment scheme uses [1..segCount] as a single-dirty-segment
18
- index, then segCount + DELTA_FULL_OFFSET / + DELTA_MULTI_OFFSET.
14
+ Delta flag base shared by deltaStruct's per-segment scheme:
15
+ 0 UNCHANGED
16
+ 1..segCount single dirty segment k
17
+ segCount + FULL_OFFSET FULL payload
18
+ segCount + MULTI_OFFSET MULTI: bitmap + dirty segs in order
19
+ deltaArray and deltaMap manage their own flag spaces.
19
20
  ]]
20
21
  local DELTA_UNCHANGED = 0
21
- local DELTA_FULL = 1
22
22
  local DELTA_FULL_OFFSET = 1
23
23
  local DELTA_MULTI_OFFSET = 2
24
24
 
@@ -37,9 +37,29 @@ local lshift = bit32.lshift
37
37
  local readu8 = buffer.readu8
38
38
  local writeu8 = buffer.writeu8
39
39
  local bufCopy = buffer.copy
40
+ local bufLen = buffer.len
40
41
  local rangeEqual = Buf.rangeEqual
41
42
  local snapshot = Buf.snapshot
42
43
 
44
+ --[[
45
+ Reuse `existing` when it's already large enough, else snapshot via
46
+ Buf.snapshot. Avoids per-write buffer allocations on delta caches that
47
+ hover at a stable size.
48
+ ]]
49
+ local function copyToBuf(existing: buffer?, src: buffer, srcOff: number, len: number): buffer
50
+ if existing and bufLen(existing) >= len then
51
+ bufCopy(existing, 0, src, srcOff, len)
52
+ return existing
53
+ end
54
+ return snapshot(src, len, srcOff)
55
+ end
56
+
57
+ -- Update a `{raw, len}` cache shape from scratch bytes; reuses raw via copyToBuf.
58
+ local function refreshCache(cache: any, src: buffer, len: number): ()
59
+ cache.raw = copyToBuf(cache.raw, src, 0, len)
60
+ cache.len = len
61
+ end
62
+
43
63
  -- Public -----------------------------------------------------------------
44
64
 
45
65
  local Shared = {}
@@ -49,6 +69,20 @@ Shared.DELTA_FULL_OFFSET = DELTA_FULL_OFFSET
49
69
  Shared.DELTA_MULTI_OFFSET = DELTA_MULTI_OFFSET
50
70
  Shared.rangeEqual = rangeEqual
51
71
  Shared.snapshot = snapshot
72
+ Shared.refreshCache = refreshCache
73
+ Shared.copyToBuf = copyToBuf
74
+
75
+ -- True when `c` itself is a delta codec OR contains one in its tree.
76
+ function Shared.containsDelta(c: Types.InternalCodec<any>): boolean
77
+ return c._isDelta == true or c._hasDelta == true
78
+ end
79
+
80
+ -- Common bounds check for variable-length container codecs.
81
+ function Shared.enforceMaxCount(len: number, maxCount: number?, label: string?): ()
82
+ if maxCount and len > maxCount then
83
+ Log.error(`{label or "count"} {len} exceeds max {maxCount}`)
84
+ end
85
+ end
52
86
 
53
87
  function Shared.allocDeltaId(): number
54
88
  _nextDeltaId += 1
@@ -63,7 +97,9 @@ end
63
97
  --[[
64
98
  Stack-based scratch ChannelState pool. Re-entrant codec serialization
65
99
  (a codec writing into scratch that triggers another codec's scratch
66
- acquire) works without aliasing.
100
+ acquire) works without aliasing. Full scrub on reuse so any codec that
101
+ reads framing fields (lastId/singleMode/itemCount/countPos) on scratch
102
+ sees a clean state, not stale bytes from the previous owner.
67
103
  ]]
68
104
  function Shared.acquireScratch(): Types.ChannelState
69
105
  _scratchDepth += 1
@@ -71,6 +107,15 @@ function Shared.acquireScratch(): Types.ChannelState
71
107
  if ch then
72
108
  ch.cursor = 0
73
109
  ch.refCount = 0
110
+ ch.lastId = -1
111
+ ch.countPos = -1
112
+ ch.itemCount = 0
113
+ ch.singleMode = false
114
+ ch.singlePos = 0
115
+ ch.currentPacket = nil
116
+ if next(ch.deltas) ~= nil then
117
+ table.clear(ch.deltas)
118
+ end
74
119
  return ch
75
120
  end
76
121
  ch = Channel.create()
@@ -82,6 +127,26 @@ function Shared.releaseScratch(): ()
82
127
  _scratchDepth -= 1
83
128
  end
84
129
 
130
+ --[[
131
+ Reset module-private state. Called by Sandbox in tests so that a thrown
132
+ codec.write (which skips releaseScratch and leaves depth inflated) can't
133
+ leak into the next test's scratch acquisition. Also resets the deltaId
134
+ counter so test ordering doesn't bleed.
135
+ ]]
136
+ function Shared.reset(): ()
137
+ _scratchDepth = 0
138
+ _nextDeltaId = 0
139
+ for i = 1, #_scratchStack do
140
+ local ch = _scratchStack[i]
141
+ ch.cursor = 0
142
+ ch.refCount = 0
143
+ if ch.refCount > 0 then
144
+ table.clear(ch.refs)
145
+ end
146
+ table.clear(ch.deltas)
147
+ end
148
+ end
149
+
85
150
  --[[
86
151
  Split a struct schema into (dataKeys, dataCodecs, boolKeys), each sorted
87
152
  alphabetically for deterministic wire layout.
@@ -117,25 +182,27 @@ function Shared.extractFields(
117
182
  return dataKeys, dataCodecs, boolKeys
118
183
  end
119
184
 
185
+ -- `byteCount` is `(boolCount + 7) // 8`; callers with it cached pass it through.
120
186
  function Shared.packBools(
121
187
  ch: Types.ChannelState,
122
188
  value: { [string]: any },
123
189
  boolKeys: { string },
124
- boolCount: number
190
+ boolCount: number,
191
+ byteCount: number?
125
192
  ): ()
126
193
  if boolCount == 0 then
127
194
  return
128
195
  end
129
196
 
130
- local byteCount = (boolCount + 7) // 8
197
+ local bc = byteCount or (boolCount + 7) // 8
131
198
  local cursor = ch.cursor
132
- if cursor + byteCount > ch.size then
133
- alloc(ch, byteCount)
199
+ if cursor + bc > ch.size then
200
+ alloc(ch, bc)
134
201
  end
135
202
 
136
203
  local idx = 1
137
204
  local b = ch.buff
138
- for byteIdx = 0, byteCount - 1 do
205
+ for byteIdx = 0, bc - 1 do
139
206
  local packed = 0
140
207
  local remaining = boolCount - idx + 1
141
208
  local limit = if remaining >= 8 then 8 else remaining
@@ -148,27 +215,32 @@ function Shared.packBools(
148
215
  writeu8(b, cursor + byteIdx, packed)
149
216
  end
150
217
 
151
- ch.cursor = cursor + byteCount
218
+ ch.cursor = cursor + bc
152
219
  end
153
220
 
154
221
  --[[
155
222
  Integer-indexed bool-array pack. Split from packBools to skip the
156
223
  per-bit string-key getter on the bool-array hot path.
157
224
  ]]
158
- function Shared.packBoolArray(ch: Types.ChannelState, value: { boolean }, count: number): ()
225
+ function Shared.packBoolArray(
226
+ ch: Types.ChannelState,
227
+ value: { boolean },
228
+ count: number,
229
+ byteCount: number?
230
+ ): ()
159
231
  if count == 0 then
160
232
  return
161
233
  end
162
234
 
163
- local byteCount = (count + 7) // 8
235
+ local bc = byteCount or (count + 7) // 8
164
236
  local cursor = ch.cursor
165
- if cursor + byteCount > ch.size then
166
- alloc(ch, byteCount)
237
+ if cursor + bc > ch.size then
238
+ alloc(ch, bc)
167
239
  end
168
240
 
169
241
  local idx = 1
170
242
  local b = ch.buff
171
- for byteIdx = 0, byteCount - 1 do
243
+ for byteIdx = 0, bc - 1 do
172
244
  local packed = 0
173
245
  local remaining = count - idx + 1
174
246
  local limit = if remaining >= 8 then 8 else remaining
@@ -181,7 +253,7 @@ function Shared.packBoolArray(ch: Types.ChannelState, value: { boolean }, count:
181
253
  writeu8(b, cursor + byteIdx, packed)
182
254
  end
183
255
 
184
- ch.cursor = cursor + byteCount
256
+ ch.cursor = cursor + bc
185
257
  end
186
258
 
187
259
  function Shared.unpackBools(
@@ -189,15 +261,16 @@ function Shared.unpackBools(
189
261
  pos: number,
190
262
  boolKeys: { string },
191
263
  boolCount: number,
192
- result: { [string]: any }
264
+ result: { [string]: any },
265
+ byteCount: number?
193
266
  ): number
194
267
  if boolCount == 0 then
195
268
  return 0
196
269
  end
197
270
 
198
- local byteCount = (boolCount + 7) // 8
271
+ local bc = byteCount or (boolCount + 7) // 8
199
272
  local idx = 1
200
- for byteIdx = 0, byteCount - 1 do
273
+ for byteIdx = 0, bc - 1 do
201
274
  local byte = readu8(src, pos + byteIdx)
202
275
  local remaining = boolCount - idx + 1
203
276
  local limit = if remaining >= 8 then 8 else remaining
@@ -206,7 +279,7 @@ function Shared.unpackBools(
206
279
  idx += 1
207
280
  end
208
281
  end
209
- return byteCount
282
+ return bc
210
283
  end
211
284
 
212
285
  -- Fills `result[1..count]` in place.
@@ -214,15 +287,16 @@ function Shared.unpackBoolArray(
214
287
  src: buffer,
215
288
  pos: number,
216
289
  count: number,
217
- result: { boolean }
290
+ result: { boolean },
291
+ byteCount: number?
218
292
  ): number
219
293
  if count == 0 then
220
294
  return 0
221
295
  end
222
296
 
223
- local byteCount = (count + 7) // 8
297
+ local bc = byteCount or (count + 7) // 8
224
298
  local idx = 1
225
- for byteIdx = 0, byteCount - 1 do
299
+ for byteIdx = 0, bc - 1 do
226
300
  local byte = readu8(src, pos + byteIdx)
227
301
  local remaining = count - idx + 1
228
302
  local limit = if remaining >= 8 then 8 else remaining
@@ -231,82 +305,7 @@ function Shared.unpackBoolArray(
231
305
  idx += 1
232
306
  end
233
307
  end
234
- return byteCount
235
- end
236
-
237
- --[[
238
- Build a byte-equality delta codec around any inner codec. Wire:
239
- [DELTA_UNCHANGED] 1 byte
240
- [DELTA_FULL] <inner-encoded payload> 1 + N bytes
241
- Used by deltaArray and deltaMap. The FULL path encodes once into scratch
242
- then bufCopies into the channel — avoids a double encode.
243
- ]]
244
- function Shared.makeUnchangedOrFullDelta(
245
- inner: Types.InternalCodec<any>,
246
- deltaId: number,
247
- Baseline: {
248
- getCache: (number) -> any,
249
- setCache: (number, any) -> (),
250
- }
251
- ): Types.InternalCodec<any>
252
- return table.freeze({
253
- _isDelta = true,
254
-
255
- write = function(ch: Types.ChannelState, value: any): ()
256
- local scratch = Shared.acquireScratch()
257
- inner.write(scratch, value)
258
- local scratchLen = scratch.cursor
259
-
260
- local cache = ch.deltas[deltaId]
261
- if
262
- cache
263
- and scratchLen == cache.len
264
- and rangeEqual(scratch.buff, 0, cache.raw, 0, scratchLen)
265
- then
266
- local cursor = ch.cursor
267
- if cursor + 1 > ch.size then
268
- alloc(ch, 1)
269
- end
270
- writeu8(ch.buff, cursor, DELTA_UNCHANGED)
271
- ch.cursor = cursor + 1
272
- Shared.releaseScratch()
273
- return
274
- end
275
-
276
- local cursor = ch.cursor
277
- if cursor + 1 + scratchLen > ch.size then
278
- alloc(ch, 1 + scratchLen)
279
- end
280
- local b = ch.buff
281
- writeu8(b, cursor, DELTA_FULL)
282
- if scratchLen > 0 then
283
- bufCopy(b, cursor + 1, scratch.buff, 0, scratchLen)
284
- end
285
- ch.cursor = cursor + 1 + scratchLen
286
-
287
- local snap = snapshot(scratch.buff, scratchLen)
288
- if cache then
289
- cache.raw = snap
290
- cache.len = scratchLen
291
- else
292
- ch.deltas[deltaId] = { raw = snap, len = scratchLen }
293
- end
294
- Shared.releaseScratch()
295
- end,
296
-
297
- read = function(src: buffer, pos: number, refs: { Instance }?): (any, number)
298
- if readu8(src, pos) == DELTA_UNCHANGED then
299
- local cached = Baseline.getCache(deltaId)
300
- if not cached then
301
- Log.error("UNCHANGED flag before any FULL frame; baseline missing")
302
- end
303
- return cached, 1
304
- end
305
- local value, consumed = inner.read(src, pos + 1, refs)
306
- Baseline.setCache(deltaId, value)
307
- return value, 1 + consumed
308
- end,
309
- })
308
+ return bc
310
309
  end
311
310
 
312
311
  return table.freeze(Shared)
@@ -55,6 +55,7 @@ local packBools = Shared.packBools
55
55
  local unpackBools = Shared.unpackBools
56
56
  local rangeEqual = Shared.rangeEqual
57
57
  local snapshot = Shared.snapshot
58
+ local refreshCache = Shared.refreshCache
58
59
  local acquireScratch = Shared.acquireScratch
59
60
  local releaseScratch = Shared.releaseScratch
60
61
  local allocDeltaId = Shared.allocDeltaId
@@ -89,14 +90,18 @@ function Struct.struct(schema: { [string]: Types.InternalCodec<any> }): Types.In
89
90
  local boolCount = #boolKeys
90
91
  local boolBytes = Shared.boolBytes(boolCount)
91
92
 
92
- -- Single pass: detect all-direct fast-write path + propagate _hasUnknown.
93
+ -- Single pass: detect all-direct fast-write path + propagate _hasUnknown / _hasDelta.
93
94
  local allDirect, fixedSize = true, 0
94
95
  local hasUnknown = false
96
+ local hasDelta = false
95
97
  for i = 1, dataCount do
96
98
  local c = dataCodecs[i]
97
99
  if c._hasUnknown then
98
100
  hasUnknown = true
99
101
  end
102
+ if Shared.containsDelta(c) then
103
+ hasDelta = true
104
+ end
100
105
  if allDirect then
101
106
  if c._size and c._directWrite and c._directRead then
102
107
  fixedSize += c._size
@@ -160,7 +165,7 @@ function Struct.struct(schema: { [string]: Types.InternalCodec<any> }): Types.In
160
165
  result[dataKeys[i]] = directReads[i](b, off + offsets[i])
161
166
  end
162
167
  if boolCount > 0 then
163
- unpackBools(b, off + fixedSize, boolKeys, boolCount, result)
168
+ unpackBools(b, off + fixedSize, boolKeys, boolCount, result, boolBytes)
164
169
  end
165
170
  return result
166
171
  end,
@@ -176,7 +181,7 @@ function Struct.struct(schema: { [string]: Types.InternalCodec<any> }): Types.In
176
181
  end
177
182
  ch.cursor = cursor + fixedSize
178
183
  if boolCount > 0 then
179
- packBools(ch, value, boolKeys, boolCount)
184
+ packBools(ch, value, boolKeys, boolCount, boolBytes)
180
185
  end
181
186
  end,
182
187
 
@@ -186,7 +191,7 @@ function Struct.struct(schema: { [string]: Types.InternalCodec<any> }): Types.In
186
191
  result[dataKeys[i]] = directReads[i](src, pos + offsets[i])
187
192
  end
188
193
  if boolCount > 0 then
189
- unpackBools(src, pos + fixedSize, boolKeys, boolCount, result)
194
+ unpackBools(src, pos + fixedSize, boolKeys, boolCount, result, boolBytes)
190
195
  end
191
196
  return result, totalFixed
192
197
  end,
@@ -194,6 +199,9 @@ function Struct.struct(schema: { [string]: Types.InternalCodec<any> }): Types.In
194
199
  if hasUnknown then
195
200
  codec._hasUnknown = true
196
201
  end
202
+ if hasDelta then
203
+ codec._hasDelta = true
204
+ end
197
205
  return table.freeze(codec)
198
206
  end
199
207
 
@@ -205,7 +213,7 @@ function Struct.struct(schema: { [string]: Types.InternalCodec<any> }): Types.In
205
213
  dataCodecs[i].write(ch, value[dataKeys[i]])
206
214
  end
207
215
  if boolCount > 0 then
208
- packBools(ch, value, boolKeys, boolCount)
216
+ packBools(ch, value, boolKeys, boolCount, boolBytes)
209
217
  end
210
218
  end,
211
219
 
@@ -218,7 +226,7 @@ function Struct.struct(schema: { [string]: Types.InternalCodec<any> }): Types.In
218
226
  total += consumed
219
227
  end
220
228
  if boolCount > 0 then
221
- total += unpackBools(src, pos + total, boolKeys, boolCount, result)
229
+ total += unpackBools(src, pos + total, boolKeys, boolCount, result, boolBytes)
222
230
  end
223
231
  return result, total
224
232
  end,
@@ -226,6 +234,9 @@ function Struct.struct(schema: { [string]: Types.InternalCodec<any> }): Types.In
226
234
  if hasUnknown then
227
235
  codec._hasUnknown = true
228
236
  end
237
+ if hasDelta then
238
+ codec._hasDelta = true
239
+ end
229
240
  return table.freeze(codec)
230
241
  end
231
242
 
@@ -305,7 +316,7 @@ function Struct.deltaStruct(
305
316
  refs: { Instance }?
306
317
  ): number
307
318
  if hasBoolSeg and segIdx == boolSegIdx then
308
- return unpackBools(src, pos, boolKeys, boolCount, target)
319
+ return unpackBools(src, pos, boolKeys, boolCount, target, boolBytes)
309
320
  end
310
321
  local v, consumed = dataCodecs[segIdx].read(src, pos, refs)
311
322
  target[dataKeys[segIdx]] = v
@@ -350,7 +361,7 @@ function Struct.deltaStruct(
350
361
  prev = cur
351
362
  end
352
363
  if hasBoolSeg then
353
- packBools(scratch, value, boolKeys, boolCount)
364
+ packBools(scratch, value, boolKeys, boolCount, boolBytes)
354
365
  segOff[boolSegIdx] = prev
355
366
  segLen[boolSegIdx] = scratch.cursor - prev
356
367
  end
@@ -421,8 +432,7 @@ function Struct.deltaStruct(
421
432
  end
422
433
  end
423
434
 
424
- cache.raw = snapshot(scratch.buff, scratchLen)
425
- cache.len = scratchLen;
435
+ refreshCache(cache, scratch.buff, scratchLen);
426
436
  (cache :: any).segOff = segOff;
427
437
  (cache :: any).segLen = segLen
428
438
  releaseScratch()
@@ -4,6 +4,7 @@
4
4
 
5
5
  local Channel = require(script.Parent.Parent.Parent.internal.Channel)
6
6
  local Log = require(script.Parent.Parent.Parent.util.Log)
7
+ local Shared = require(script.Parent.Parent.composite.Shared)
7
8
  local Types = require(script.Parent.Parent.Parent.Types)
8
9
 
9
10
  -- Private ----------------------------------------------------------------
@@ -37,6 +38,7 @@ function Tagged.define(
37
38
  local nameToTag: { [string]: number } = {}
38
39
  local tagToCodec = table.create(variantCount)
39
40
  local hasUnknown = false
41
+ local hasDelta = false
40
42
 
41
43
  for i = 1, variantCount do
42
44
  local name = names[i]
@@ -46,6 +48,9 @@ function Tagged.define(
46
48
  if codec._hasUnknown then
47
49
  hasUnknown = true
48
50
  end
51
+ if Shared.containsDelta(codec) then
52
+ hasDelta = true
53
+ end
49
54
  end
50
55
 
51
56
  table.freeze(names)
@@ -89,6 +94,9 @@ function Tagged.define(
89
94
  if hasUnknown then
90
95
  codec._hasUnknown = true
91
96
  end
97
+ if hasDelta then
98
+ codec._hasDelta = true
99
+ end
92
100
  return table.freeze(codec)
93
101
  end
94
102
 
@@ -4,6 +4,7 @@
4
4
 
5
5
  local Base = require(script.Parent.Parent.Base)
6
6
  local Log = require(script.Parent.Parent.Parent.util.Log)
7
+ local Shared = require(script.Parent.Parent.composite.Shared)
7
8
  local Types = require(script.Parent.Parent.Parent.Types)
8
9
 
9
10
  -- Private ----------------------------------------------------------------
@@ -19,13 +20,17 @@ function Tuple.define(...: Types.InternalCodec<any>): Types.InternalCodec<any>
19
20
  local count = #codecs
20
21
  Log.assert(count > 0, "requires at least one codec")
21
22
 
22
- -- Single pass: detect all-direct fast path + propagate _hasUnknown.
23
+ -- Single pass: detect all-direct fast path + propagate _hasUnknown / _hasDelta.
23
24
  local allDirect, totalSize, hasUnknown = true, 0, false
25
+ local hasDelta = false
24
26
  for i = 1, count do
25
27
  local c = codecs[i]
26
28
  if c._hasUnknown then
27
29
  hasUnknown = true
28
30
  end
31
+ if Shared.containsDelta(c) then
32
+ hasDelta = true
33
+ end
29
34
  if allDirect then
30
35
  if c._size and c._directWrite and c._directRead then
31
36
  totalSize += c._size
@@ -96,6 +101,9 @@ function Tuple.define(...: Types.InternalCodec<any>): Types.InternalCodec<any>
96
101
  if hasUnknown then
97
102
  codec._hasUnknown = true
98
103
  end
104
+ if hasDelta then
105
+ codec._hasDelta = true
106
+ end
99
107
  return table.freeze(codec)
100
108
  end
101
109
 
@@ -126,6 +134,9 @@ function Tuple.define(...: Types.InternalCodec<any>): Types.InternalCodec<any>
126
134
  if hasUnknown then
127
135
  codec._hasUnknown = true
128
136
  end
137
+ if hasDelta then
138
+ codec._hasDelta = true
139
+ end
129
140
  return table.freeze(codec)
130
141
  end
131
142
 
@@ -23,9 +23,7 @@ local function writeBuffer(ch: Types.ChannelState, value: buffer): ()
23
23
  end
24
24
  local b = ch.buff
25
25
  buffer.writeu8(b, cursor, len)
26
- if len > 0 then
27
- buffer.copy(b, cursor + 1, value, 0, len)
28
- end
26
+ buffer.copy(b, cursor + 1, value, 0, len)
29
27
  ch.cursor = cursor + 1 + len
30
28
  return
31
29
  end
@@ -3,6 +3,7 @@
3
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,10 +11,6 @@ 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
@@ -21,19 +18,10 @@ local writef32 = buffer.writef32
21
18
  local readf32 = buffer.readf32
22
19
  local writeu32 = buffer.writeu32
23
20
  local readu32 = buffer.readu32
24
-
25
21
  local sqrt = math.sqrt
26
- local cos = math.cos
27
- local sin = math.sin
28
- local abs = math.abs
29
- local round = math.round
30
- local acos = math.acos
31
- local clamp = math.clamp
32
-
33
- local band = bit32.band
34
- local bor = bit32.bor
35
- local lshift = bit32.lshift
36
- local rshift = bit32.rshift
22
+ local quatPack = Quat.pack
23
+ local quatUnpack = Quat.unpack
24
+ local quatFromCFrame = Quat.fromCFrame
37
25
 
38
26
  local function writeLossless(b: buffer, off: number, value: CFrame): ()
39
27
  local pos = value.Position
@@ -82,102 +70,14 @@ local function writeCompressed(b: buffer, off: number, value: CFrame): ()
82
70
  writef32(b, off, pos.X)
83
71
  writef32(b, off + 4, pos.Y)
84
72
  writef32(b, off + 8, pos.Z)
85
-
86
- local axis, angle = value:ToAxisAngle()
87
- local h = angle * 0.5
88
- local s = sin(h)
89
- local qx = axis.X * s
90
- local qy = axis.Y * s
91
- local qz = axis.Z * s
92
- local qw = cos(h)
93
-
94
- -- Smallest-three: drop the largest |component|; track index alongside maxVal.
95
- local ax, ay, az, aw = abs(qx), abs(qy), abs(qz), abs(qw)
96
- local largest, maxVal = 3, aw
97
- if ax > maxVal then
98
- largest, maxVal = 0, ax
99
- end
100
- if ay > maxVal then
101
- largest, maxVal = 1, ay
102
- end
103
- if az > maxVal then
104
- largest, maxVal = 2, az
105
- end
106
-
107
- --[[
108
- Force the dropped component non-negative so the decoder's
109
- +sqrt(1 - a^2 - b^2 - c^2) reconstructs the right sign. Dispatch on
110
- `largest` instead of building a 4-element table per call.
111
- ]]
112
- local a: number, bComp: number, c: number
113
- if largest == 0 then
114
- if qx < 0 then
115
- qy, qz, qw = -qy, -qz, -qw
116
- end
117
- a, bComp, c = qy, qz, qw
118
- elseif largest == 1 then
119
- if qy < 0 then
120
- qx, qz, qw = -qx, -qz, -qw
121
- end
122
- a, bComp, c = qx, qz, qw
123
- elseif largest == 2 then
124
- if qz < 0 then
125
- qx, qy, qw = -qx, -qy, -qw
126
- end
127
- a, bComp, c = qx, qy, qw
128
- else
129
- if qw < 0 then
130
- qx, qy, qz = -qx, -qy, -qz
131
- end
132
- a, bComp, c = qx, qy, qz
133
- end
134
-
135
- local qa = clamp(round((a + INV_SQRT2) * Q_SCALE), 0, 1023)
136
- local qb = clamp(round((bComp + INV_SQRT2) * Q_SCALE), 0, 1023)
137
- local qc = clamp(round((c + INV_SQRT2) * Q_SCALE), 0, 1023)
138
-
139
- writeu32(b, off + 12, bor(lshift(largest, 30), lshift(qa, 20), lshift(qb, 10), qc))
73
+ writeu32(b, off + 12, quatPack(quatFromCFrame(value)))
140
74
  end
141
75
 
142
76
  local function readCompressed(b: buffer, off: number): CFrame
143
77
  local px = readf32(b, off)
144
78
  local py = readf32(b, off + 4)
145
79
  local pz = readf32(b, off + 8)
146
-
147
- local packed = readu32(b, off + 12)
148
- local largest = rshift(packed, 30)
149
- local qa = band(rshift(packed, 20), 0x3FF)
150
- local qb = band(rshift(packed, 10), 0x3FF)
151
- local qc = band(packed, 0x3FF)
152
-
153
- local a = qa * Q_INV - INV_SQRT2
154
- local bComp = qb * Q_INV - INV_SQRT2
155
- local c = qc * Q_INV - INV_SQRT2
156
-
157
- local sqSum = a * a + bComp * bComp + c * c
158
- local d = sqrt(if sqSum < 1 then 1 - sqSum else 0)
159
-
160
- -- Mirror encoder: dropped index gets `d`, others receive (a, bComp, c).
161
- local qx: number, qy: number, qz: number, qw: number
162
- if largest == 0 then
163
- qx, qy, qz, qw = d, a, bComp, c
164
- elseif largest == 1 then
165
- qx, qy, qz, qw = a, d, bComp, c
166
- elseif largest == 2 then
167
- qx, qy, qz, qw = a, bComp, d, c
168
- else
169
- qx, qy, qz, qw = a, bComp, c, d
170
- end
171
-
172
- local origin = CFrame.new(px, py, pz)
173
- local sqLen = qx * qx + qy * qy + qz * qz
174
- if sqLen < EPSILON_SQ then
175
- return origin
176
- end
177
-
178
- local angle = 2 * acos(clamp(qw, -1, 1))
179
- local inv = 1 / sqrt(sqLen)
180
- return origin * CFrame.fromAxisAngle(Vector3.new(qx * inv, qy * inv, qz * inv), angle)
80
+ return CFrame.new(px, py, pz) * quatUnpack(readu32(b, off + 12))
181
81
  end
182
82
 
183
83
  local function compressedFactory(_self): Types.InternalCodec<CFrame>