@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.
- package/README.md +109 -147
- package/package.json +1 -1
- package/src/Types.luau +34 -22
- package/src/api/Group.luau +40 -33
- package/src/api/Packet.luau +140 -66
- package/src/api/Query.luau +103 -65
- package/src/api/Scope.luau +26 -10
- package/src/api/Signal.luau +43 -52
- package/src/codec/Base.luau +28 -14
- package/src/codec/composite/Array.luau +296 -115
- package/src/codec/composite/Map.luau +377 -57
- package/src/codec/composite/Optional.luau +10 -2
- package/src/codec/composite/Shared.luau +134 -64
- package/src/codec/composite/Struct.luau +294 -43
- package/src/codec/composite/Tagged.luau +21 -16
- package/src/codec/composite/Tuple.luau +32 -15
- package/src/codec/datatype/Buffer.luau +7 -7
- package/src/codec/datatype/CFrame.luau +34 -122
- package/src/codec/datatype/Color.luau +10 -10
- package/src/codec/datatype/Instance.luau +15 -12
- package/src/codec/datatype/IntVector.luau +2 -2
- package/src/codec/datatype/NumberRange.luau +15 -8
- package/src/codec/datatype/Ray.luau +13 -14
- package/src/codec/datatype/Rect.luau +12 -12
- package/src/codec/datatype/Region.luau +13 -14
- package/src/codec/datatype/Sequence.luau +87 -65
- package/src/codec/datatype/String.luau +17 -10
- package/src/codec/datatype/UDim.luau +10 -8
- package/src/codec/datatype/Vector.luau +20 -59
- package/src/codec/meta/Auto.luau +94 -126
- package/src/codec/meta/Bitfield.luau +12 -14
- package/src/codec/meta/Custom.luau +3 -1
- package/src/codec/meta/DeltaScalar.luau +390 -0
- package/src/codec/meta/Enum.luau +9 -9
- package/src/codec/meta/Float.luau +6 -28
- package/src/codec/meta/Nothing.luau +1 -1
- package/src/codec/meta/Unknown.luau +10 -7
- package/src/codec/primitive/Bool.luau +6 -4
- package/src/codec/primitive/Float16.luau +5 -2
- package/src/codec/primitive/Int.luau +5 -6
- package/src/codec/primitive/Number.luau +6 -4
- package/src/codec/primitive/Signed.luau +2 -2
- package/src/codec/primitive/Varint.luau +76 -39
- package/src/codec/primitive/Zint.luau +99 -0
- package/src/index.d.ts +207 -53
- package/src/init.luau +116 -103
- package/src/internal/Baseline.luau +9 -1
- package/src/internal/Channel.luau +191 -157
- package/src/internal/Middleware.luau +22 -6
- package/src/internal/Pool.luau +12 -4
- package/src/internal/Registry.luau +25 -16
- package/src/internal/Transport.luau +1 -1
- package/src/transport/Bridge.luau +47 -33
- package/src/transport/Client.luau +25 -21
- package/src/transport/Gate.luau +227 -172
- package/src/transport/Reader.luau +174 -106
- package/src/transport/Server.luau +46 -57
- package/src/util/Array.luau +18 -0
- package/src/util/Buffer.luau +90 -0
- package/src/util/Constants.luau +30 -0
- package/src/util/Log.luau +68 -0
- package/src/util/Player.luau +14 -0
- package/src/util/Quantize.luau +84 -0
- package/src/util/Quat.luau +124 -0
- package/src/internal/Util.luau +0 -26
|
@@ -1,29 +1,27 @@
|
|
|
1
1
|
--!strict
|
|
2
2
|
--!native
|
|
3
|
-
-- Shared
|
|
3
|
+
-- Shared composite-codec helpers: delta flags, scratch pool, bool packing.
|
|
4
4
|
|
|
5
5
|
local Base = require(script.Parent.Parent.Base)
|
|
6
|
+
local Buf = require(script.Parent.Parent.Parent.util.Buffer)
|
|
7
|
+
local Channel = require(script.Parent.Parent.Parent.internal.Channel)
|
|
8
|
+
local Log = require(script.Parent.Parent.Parent.util.Log)
|
|
6
9
|
local Types = require(script.Parent.Parent.Parent.Types)
|
|
7
10
|
|
|
8
11
|
-- Constants --------------------------------------------------------------
|
|
9
12
|
|
|
10
13
|
--[[
|
|
11
|
-
Delta
|
|
12
|
-
0 UNCHANGED
|
|
13
|
-
1
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
segment index" then segCount + DELTA_FULL_OFFSET for full and
|
|
18
|
-
segCount + DELTA_MULTI_OFFSET for multi-dirty bitmap.
|
|
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
|
|
|
25
|
-
local INITIAL_SCRATCH = 1024
|
|
26
|
-
|
|
27
25
|
-- State ------------------------------------------------------------------
|
|
28
26
|
|
|
29
27
|
local _nextDeltaId = 0
|
|
@@ -35,29 +33,31 @@ local _scratchStack: { Types.ChannelState } = {}
|
|
|
35
33
|
local alloc = Base.alloc
|
|
36
34
|
local band = bit32.band
|
|
37
35
|
local bor = bit32.bor
|
|
38
|
-
local bxor = bit32.bxor
|
|
39
36
|
local lshift = bit32.lshift
|
|
40
37
|
local readu8 = buffer.readu8
|
|
41
|
-
local readu32 = buffer.readu32
|
|
42
38
|
local writeu8 = buffer.writeu8
|
|
39
|
+
local bufCopy = buffer.copy
|
|
40
|
+
local bufLen = buffer.len
|
|
41
|
+
local rangeEqual = Buf.rangeEqual
|
|
42
|
+
local snapshot = Buf.snapshot
|
|
43
43
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
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
61
|
end
|
|
62
62
|
|
|
63
63
|
-- Public -----------------------------------------------------------------
|
|
@@ -65,19 +65,39 @@ end
|
|
|
65
65
|
local Shared = {}
|
|
66
66
|
|
|
67
67
|
Shared.DELTA_UNCHANGED = DELTA_UNCHANGED
|
|
68
|
-
Shared.DELTA_FULL = DELTA_FULL
|
|
69
68
|
Shared.DELTA_FULL_OFFSET = DELTA_FULL_OFFSET
|
|
70
69
|
Shared.DELTA_MULTI_OFFSET = DELTA_MULTI_OFFSET
|
|
70
|
+
Shared.rangeEqual = rangeEqual
|
|
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
|
|
71
86
|
|
|
72
87
|
function Shared.allocDeltaId(): number
|
|
73
88
|
_nextDeltaId += 1
|
|
74
89
|
return _nextDeltaId
|
|
75
90
|
end
|
|
76
91
|
|
|
92
|
+
-- 8 bools per byte.
|
|
93
|
+
function Shared.boolBytes(n: number): number
|
|
94
|
+
return (n + 7) // 8
|
|
95
|
+
end
|
|
96
|
+
|
|
77
97
|
--[[
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
98
|
+
Stack-based scratch ChannelState pool. Re-entrant codec serialization
|
|
99
|
+
(a codec writing into scratch that triggers another codec's scratch
|
|
100
|
+
acquire) works without aliasing.
|
|
81
101
|
]]
|
|
82
102
|
function Shared.acquireScratch(): Types.ChannelState
|
|
83
103
|
_scratchDepth += 1
|
|
@@ -87,7 +107,7 @@ function Shared.acquireScratch(): Types.ChannelState
|
|
|
87
107
|
ch.refCount = 0
|
|
88
108
|
return ch
|
|
89
109
|
end
|
|
90
|
-
ch =
|
|
110
|
+
ch = Channel.create()
|
|
91
111
|
_scratchStack[_scratchDepth] = ch
|
|
92
112
|
return ch
|
|
93
113
|
end
|
|
@@ -96,35 +116,29 @@ function Shared.releaseScratch(): ()
|
|
|
96
116
|
_scratchDepth -= 1
|
|
97
117
|
end
|
|
98
118
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
119
|
+
--[[
|
|
120
|
+
Reset module-private state. Called by Sandbox in tests so that a thrown
|
|
121
|
+
codec.write (which skips releaseScratch and leaves depth inflated) can't
|
|
122
|
+
leak into the next test's scratch acquisition. Also resets the deltaId
|
|
123
|
+
counter so test ordering doesn't bleed.
|
|
124
|
+
]]
|
|
125
|
+
function Shared.reset(): ()
|
|
126
|
+
_scratchDepth = 0
|
|
127
|
+
_nextDeltaId = 0
|
|
128
|
+
for i = 1, #_scratchStack do
|
|
129
|
+
local ch = _scratchStack[i]
|
|
130
|
+
ch.cursor = 0
|
|
131
|
+
ch.refCount = 0
|
|
132
|
+
if ch.refCount > 0 then
|
|
133
|
+
table.clear(ch.refs)
|
|
111
134
|
end
|
|
112
|
-
|
|
113
|
-
end
|
|
114
|
-
return true
|
|
115
|
-
end
|
|
116
|
-
|
|
117
|
-
function Shared.snapshot(src: buffer, len: number): buffer
|
|
118
|
-
local out = buffer.create(len)
|
|
119
|
-
if len > 0 then
|
|
120
|
-
buffer.copy(out, 0, src, 0, len)
|
|
135
|
+
table.clear(ch.deltas)
|
|
121
136
|
end
|
|
122
|
-
return out
|
|
123
137
|
end
|
|
124
138
|
|
|
125
139
|
--[[
|
|
126
|
-
Split a struct schema into (dataKeys, dataCodecs, boolKeys),
|
|
127
|
-
|
|
140
|
+
Split a struct schema into (dataKeys, dataCodecs, boolKeys), each sorted
|
|
141
|
+
alphabetically for deterministic wire layout.
|
|
128
142
|
]]
|
|
129
143
|
function Shared.extractFields(
|
|
130
144
|
schema: { [string]: Types.InternalCodec<any> }
|
|
@@ -140,9 +154,7 @@ function Shared.extractFields(
|
|
|
140
154
|
end
|
|
141
155
|
end
|
|
142
156
|
|
|
143
|
-
|
|
144
|
-
error("[Lync] Lync.struct: requires at least one field")
|
|
145
|
-
end
|
|
157
|
+
Log.assert(#dataKeys > 0 or #boolKeys > 0, "requires at least one field")
|
|
146
158
|
|
|
147
159
|
table.sort(dataKeys)
|
|
148
160
|
table.sort(boolKeys)
|
|
@@ -174,9 +186,9 @@ function Shared.packBools(
|
|
|
174
186
|
if cursor + byteCount > ch.size then
|
|
175
187
|
alloc(ch, byteCount)
|
|
176
188
|
end
|
|
177
|
-
local b = ch.buff
|
|
178
189
|
|
|
179
190
|
local idx = 1
|
|
191
|
+
local b = ch.buff
|
|
180
192
|
for byteIdx = 0, byteCount - 1 do
|
|
181
193
|
local packed = 0
|
|
182
194
|
local remaining = boolCount - idx + 1
|
|
@@ -193,6 +205,39 @@ function Shared.packBools(
|
|
|
193
205
|
ch.cursor = cursor + byteCount
|
|
194
206
|
end
|
|
195
207
|
|
|
208
|
+
--[[
|
|
209
|
+
Integer-indexed bool-array pack. Split from packBools to skip the
|
|
210
|
+
per-bit string-key getter on the bool-array hot path.
|
|
211
|
+
]]
|
|
212
|
+
function Shared.packBoolArray(ch: Types.ChannelState, value: { boolean }, count: number): ()
|
|
213
|
+
if count == 0 then
|
|
214
|
+
return
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
local byteCount = (count + 7) // 8
|
|
218
|
+
local cursor = ch.cursor
|
|
219
|
+
if cursor + byteCount > ch.size then
|
|
220
|
+
alloc(ch, byteCount)
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
local idx = 1
|
|
224
|
+
local b = ch.buff
|
|
225
|
+
for byteIdx = 0, byteCount - 1 do
|
|
226
|
+
local packed = 0
|
|
227
|
+
local remaining = count - idx + 1
|
|
228
|
+
local limit = if remaining >= 8 then 8 else remaining
|
|
229
|
+
for bit = 0, limit - 1 do
|
|
230
|
+
if value[idx] then
|
|
231
|
+
packed = bor(packed, lshift(1, bit))
|
|
232
|
+
end
|
|
233
|
+
idx += 1
|
|
234
|
+
end
|
|
235
|
+
writeu8(b, cursor + byteIdx, packed)
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
ch.cursor = cursor + byteCount
|
|
239
|
+
end
|
|
240
|
+
|
|
196
241
|
function Shared.unpackBools(
|
|
197
242
|
src: buffer,
|
|
198
243
|
pos: number,
|
|
@@ -218,4 +263,29 @@ function Shared.unpackBools(
|
|
|
218
263
|
return byteCount
|
|
219
264
|
end
|
|
220
265
|
|
|
266
|
+
-- Fills `result[1..count]` in place.
|
|
267
|
+
function Shared.unpackBoolArray(
|
|
268
|
+
src: buffer,
|
|
269
|
+
pos: number,
|
|
270
|
+
count: number,
|
|
271
|
+
result: { boolean }
|
|
272
|
+
): number
|
|
273
|
+
if count == 0 then
|
|
274
|
+
return 0
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
local byteCount = (count + 7) // 8
|
|
278
|
+
local idx = 1
|
|
279
|
+
for byteIdx = 0, byteCount - 1 do
|
|
280
|
+
local byte = readu8(src, pos + byteIdx)
|
|
281
|
+
local remaining = count - idx + 1
|
|
282
|
+
local limit = if remaining >= 8 then 8 else remaining
|
|
283
|
+
for bit = 0, limit - 1 do
|
|
284
|
+
result[idx] = band(byte, lshift(1, bit)) ~= 0
|
|
285
|
+
idx += 1
|
|
286
|
+
end
|
|
287
|
+
end
|
|
288
|
+
return byteCount
|
|
289
|
+
end
|
|
290
|
+
|
|
221
291
|
return table.freeze(Shared)
|