@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,28 +1,41 @@
1
1
  --!strict
2
2
  --!native
3
- -- Dense prefix varint. Single-branch decode, range up to 2^32 - 1.
3
+ -- Dense prefix varint over [0, 2^32 - 1]. Single-branch decode.
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
 
8
10
  -- Constants --------------------------------------------------------------
9
11
 
10
12
  --[[
11
- Wire layout (first byte determines length):
12
- 0x00..0xBF 1 byte value = b0 [0..191]
13
- 0xC0..0xDF 2 bytes value = (b0 & 0x1F)<<8 | b1 + 192 [192..8383]
14
- 0xE0..0xEF 3 bytes value = (b0 & 0x0F)<<16 | u16 + 8384 [8384..1056959]
15
- 0xF0..0xFF 5 bytes value = u32 [..0xFFFFFFFF]
13
+ Wire layout (first byte tag selects length):
14
+ 0x00..0xBF 1 byte value = b0 [0..191]
15
+ 0xC0..0xDF 2 bytes value = (b0 & 0x1F)<<8 | b1 + 192 [192..8383]
16
+ 0xE0..0xEF 3 bytes value = (b0 & 0x0F)<<16 | u16 + 8384 [8384..1056959]
17
+ 0xF0..0xFF 5 bytes value = u32 [..0xFFFFFFFF]
16
18
  ]]
17
19
  local INLINE_MAX = 0xBF
20
+ local TWO_TAG = 0xC0
21
+ local TWO_END = 0xDF
22
+ local TWO_MASK = 0x1F
23
+ local THREE_TAG = 0xE0
24
+ local THREE_END = 0xEF
25
+ local THREE_MASK = 0x0F
26
+ local FIVE_TAG = 0xF0
18
27
  local TWO_MAX = 8383
19
28
  local THREE_MAX = 1056959
20
29
  local TWO_BIAS = 192
21
30
  local THREE_BIAS = 8384
22
31
 
32
+ local U8_MAX = Constants.U8_MAX
33
+ local U16_MAX = Constants.U16_MAX
34
+ local U32_MAX = Constants.U32_MAX
35
+
23
36
  -- Private ----------------------------------------------------------------
24
37
 
25
- local alloc = Base.alloc
38
+ local ensure = Base.ensure
26
39
  local band = bit32.band
27
40
  local bor = bit32.bor
28
41
  local rshift = bit32.rshift
@@ -39,85 +52,109 @@ local Varint = {}
39
52
 
40
53
  Varint.INLINE_MAX = INLINE_MAX
41
54
 
42
- function Varint.write(ch: Types.ChannelState, value: number): ()
43
- if value < 0 or value > 0xFFFFFFFF or value % 1 ~= 0 then
44
- error(`[Lync] Varint.write: value must be an integer in [0, 4294967295], got {value}`)
55
+ -- Wire byte count for a value, without encoding it. Used by cost heuristics.
56
+ function Varint.length(value: number): number
57
+ if value <= INLINE_MAX then
58
+ return 1
59
+ elseif value <= TWO_MAX then
60
+ return 2
61
+ elseif value <= THREE_MAX then
62
+ return 3
45
63
  end
64
+ return 5
65
+ end
46
66
 
47
- local cursor = ch.cursor
67
+ function Varint.write(ch: Types.ChannelState, value: number): ()
68
+ if value < 0 or value > U32_MAX or value % 1 ~= 0 then
69
+ Log.error(`value must be an integer in [0, {U32_MAX}], got {value}`)
70
+ end
48
71
 
49
72
  if value <= INLINE_MAX then
50
- if cursor + 1 > ch.size then
51
- alloc(ch, 1)
52
- end
73
+ ensure(ch, 1)
74
+ local cursor = ch.cursor
53
75
  writeu8(ch.buff, cursor, value)
54
76
  ch.cursor = cursor + 1
55
77
  return
56
78
  end
57
79
 
58
80
  if value <= TWO_MAX then
59
- if cursor + 2 > ch.size then
60
- alloc(ch, 2)
61
- end
81
+ ensure(ch, 2)
82
+ local cursor = ch.cursor
62
83
  local adjusted = value - TWO_BIAS
63
84
  local b = ch.buff
64
- writeu8(b, cursor, bor(0xC0, rshift(adjusted, 8)))
65
- writeu8(b, cursor + 1, band(adjusted, 0xFF))
85
+ writeu8(b, cursor, bor(TWO_TAG, rshift(adjusted, 8)))
86
+ writeu8(b, cursor + 1, band(adjusted, U8_MAX))
66
87
  ch.cursor = cursor + 2
67
88
  return
68
89
  end
69
90
 
70
91
  if value <= THREE_MAX then
71
- if cursor + 3 > ch.size then
72
- alloc(ch, 3)
73
- end
92
+ ensure(ch, 3)
93
+ local cursor = ch.cursor
74
94
  local adjusted = value - THREE_BIAS
75
95
  local b = ch.buff
76
- writeu8(b, cursor, bor(0xE0, rshift(adjusted, 16)))
77
- writeu16(b, cursor + 1, band(adjusted, 0xFFFF))
96
+ writeu8(b, cursor, bor(THREE_TAG, rshift(adjusted, 16)))
97
+ writeu16(b, cursor + 1, band(adjusted, U16_MAX))
78
98
  ch.cursor = cursor + 3
79
99
  return
80
100
  end
81
101
 
82
- if cursor + 5 > ch.size then
83
- alloc(ch, 5)
84
- end
102
+ ensure(ch, 5)
103
+ local cursor = ch.cursor
85
104
  local b = ch.buff
86
- writeu8(b, cursor, 0xF0)
105
+ writeu8(b, cursor, FIVE_TAG)
87
106
  writeu32(b, cursor + 1, value)
88
107
  ch.cursor = cursor + 5
89
108
  end
90
109
 
110
+ --[[
111
+ Returns (value, bytesConsumed). On insufficient bytes returns (0, 0) so
112
+ the transport can abort the frame instead of letting the buffer access
113
+ raise — required for recovery from truncated/desynced incoming buffers.
114
+ ]]
91
115
  function Varint.read(src: buffer, pos: number): (number, number)
116
+ local available = buffer.len(src) - pos
117
+ if available < 1 then
118
+ return 0, 0
119
+ end
92
120
  local b0 = readu8(src, pos)
93
121
  if b0 <= INLINE_MAX then
94
122
  return b0, 1
95
123
  end
96
- if b0 <= 0xDF then
97
- return band(b0, 0x1F) * 256 + readu8(src, pos + 1) + TWO_BIAS, 2
124
+ if b0 <= TWO_END then
125
+ if available < 2 then
126
+ return 0, 0
127
+ end
128
+ return band(b0, TWO_MASK) * 256 + readu8(src, pos + 1) + TWO_BIAS, 2
129
+ end
130
+ if b0 <= THREE_END then
131
+ if available < 3 then
132
+ return 0, 0
133
+ end
134
+ return band(b0, THREE_MASK) * 65536 + readu16(src, pos + 1) + THREE_BIAS, 3
98
135
  end
99
- if b0 <= 0xEF then
100
- return band(b0, 0x0F) * 65536 + readu16(src, pos + 1) + THREE_BIAS, 3
136
+ if available < 5 then
137
+ return 0, 0
101
138
  end
102
139
  return readu32(src, pos + 1), 5
103
140
  end
104
141
 
105
- -- Encode a value already known to fit in INLINE_MAX (single byte).
142
+ -- Caller-asserted: value is known to fit in INLINE_MAX.
106
143
  function Varint.writeInline(ch: Types.ChannelState, value: number): ()
144
+ ensure(ch, 1)
107
145
  local cursor = ch.cursor
108
- if cursor + 1 > ch.size then
109
- alloc(ch, 1)
110
- end
111
146
  writeu8(ch.buff, cursor, value)
112
147
  ch.cursor = cursor + 1
113
148
  end
114
149
 
115
150
  --[[
116
- Decode a length prefix that uses the single-byte fast path for
117
- lengths in [0, INLINE_MAX] and the full varint encoding above that.
118
- Used by Buffer, String, and Auto's string branch.
151
+ Length-prefix decode that fast-paths the [0, INLINE_MAX] single-byte form
152
+ before falling through to full varint. Used by Buffer, String, and Auto.
119
153
  ]]
120
154
  function Varint.readLengthPrefix(src: buffer, pos: number): (number, number)
155
+ if buffer.len(src) - pos < 1 then
156
+ return 0, 0
157
+ end
121
158
  local b0 = readu8(src, pos)
122
159
  if b0 <= INLINE_MAX then
123
160
  return b0, 1
@@ -0,0 +1,99 @@
1
+ --!strict
2
+ --!native
3
+ -- Signed varint via zigzag mapping. Small magnitudes pack in 1 byte.
4
+
5
+ local Log = require(script.Parent.Parent.Parent.util.Log)
6
+ local Types = require(script.Parent.Parent.Parent.Types)
7
+ local Varint = require(script.Parent.Parent.primitive.Varint)
8
+
9
+ -- Constants --------------------------------------------------------------
10
+
11
+ --[[
12
+ Zigzag fold maps signed values onto unsigned varint space:
13
+ n >= 0 -> 2n
14
+ n < 0 -> -2n - 1
15
+ Inverse: low bit selects sign, shift down 1 bit.
16
+
17
+ Wire ranges (using Varint dense form):
18
+ 1 byte: [-96, 95]
19
+ 2 bytes: [-4192, 4191]
20
+ 3 bytes: [-528480, 528479]
21
+ 5 bytes: full i32
22
+ ]]
23
+ local I32_MIN = -0x80000000
24
+ local I32_MAX = 0x7FFFFFFF
25
+
26
+ -- Private ----------------------------------------------------------------
27
+
28
+ local floor = math.floor
29
+ local band = bit32.band
30
+ local varintWrite = Varint.write
31
+ local varintRead = Varint.read
32
+
33
+ -- Signed -> unsigned. Hot path; called per write of every delta scalar.
34
+ local function encode(value: number): number
35
+ if value >= 0 then
36
+ return value * 2
37
+ end
38
+ return value * -2 - 1
39
+ end
40
+
41
+ -- Inverse of encode. Even -> n/2; odd -> -((n+1)/2). Branchless on the half.
42
+ local function decode(raw: number): number
43
+ local low = band(raw, 1)
44
+ local half = (raw - low) / 2
45
+ return if low == 1 then -half - 1 else half
46
+ end
47
+
48
+ -- Public -----------------------------------------------------------------
49
+
50
+ local Zint = {}
51
+
52
+ Zint.encode = encode
53
+ Zint.decode = decode
54
+
55
+ --[[
56
+ Variable-length signed integer in [I32_MIN, I32_MAX]. Optional [min, max]
57
+ bounds gate input at write time so out-of-range payloads error early
58
+ rather than corrupting downstream decoders.
59
+ ]]
60
+ function Zint.zint(min: number?, max: number?): Types.InternalCodec<number>
61
+ local lo = min or I32_MIN
62
+ local hi = max or I32_MAX
63
+ if lo > hi then
64
+ Log.error(`min ({lo}) must be <= max ({hi})`)
65
+ end
66
+ if floor(lo) ~= lo or floor(hi) ~= hi then
67
+ Log.error("bounds must be integers")
68
+ end
69
+ if lo < I32_MIN or hi > I32_MAX then
70
+ Log.error(`range [{lo}, {hi}] exceeds i32 bounds`)
71
+ end
72
+
73
+ return table.freeze({
74
+ _typeCheck = "number",
75
+ _isInteger = true,
76
+ _min = lo,
77
+ _max = hi,
78
+
79
+ write = function(ch: Types.ChannelState, value: number): ()
80
+ if value < lo or value > hi then
81
+ Log.error(`value {value} out of range [{lo}, {hi}]`)
82
+ end
83
+ if floor(value) ~= value then
84
+ Log.error(`value {value} must be an integer`)
85
+ end
86
+ varintWrite(ch, encode(value))
87
+ end,
88
+
89
+ read = function(src: buffer, pos: number, _refs: { Instance }?): (number, number)
90
+ local raw, consumed = varintRead(src, pos)
91
+ if consumed == 0 then
92
+ Log.error("truncated zint")
93
+ end
94
+ return decode(raw), consumed
95
+ end,
96
+ }) :: Types.InternalCodec<number>
97
+ end
98
+
99
+ return table.freeze(Zint)