@axpecter/lync 2.1.2 → 2.2.1

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 (56) hide show
  1. package/README.md +241 -349
  2. package/package.json +1 -1
  3. package/src/Types.luau +53 -13
  4. package/src/api/Group.luau +41 -51
  5. package/src/api/Packet.luau +163 -152
  6. package/src/api/Query.luau +224 -211
  7. package/src/api/Scope.luau +36 -38
  8. package/src/api/Signal.luau +68 -94
  9. package/src/codec/Base.luau +43 -23
  10. package/src/codec/composite/Array.luau +161 -152
  11. package/src/codec/composite/Map.luau +37 -53
  12. package/src/codec/composite/Optional.luau +15 -21
  13. package/src/codec/composite/Shared.luau +78 -41
  14. package/src/codec/composite/Struct.luau +64 -125
  15. package/src/codec/composite/Tagged.luau +15 -25
  16. package/src/codec/composite/Tuple.luau +15 -20
  17. package/src/codec/datatype/Buffer.luau +44 -51
  18. package/src/codec/datatype/CFrame.luau +72 -104
  19. package/src/codec/datatype/Color.luau +14 -10
  20. package/src/codec/datatype/Instance.luau +32 -42
  21. package/src/codec/datatype/IntVector.luau +24 -22
  22. package/src/codec/datatype/NumberRange.luau +21 -12
  23. package/src/codec/datatype/Ray.luau +13 -7
  24. package/src/codec/datatype/Rect.luau +13 -7
  25. package/src/codec/datatype/Region.luau +25 -22
  26. package/src/codec/datatype/Sequence.luau +144 -118
  27. package/src/codec/datatype/String.luau +29 -59
  28. package/src/codec/datatype/UDim.luau +29 -30
  29. package/src/codec/datatype/Vector.luau +89 -105
  30. package/src/codec/meta/Auto.luau +194 -246
  31. package/src/codec/meta/Bitfield.luau +37 -36
  32. package/src/codec/meta/Custom.luau +10 -10
  33. package/src/codec/meta/Enum.luau +8 -11
  34. package/src/codec/meta/Float.luau +16 -20
  35. package/src/codec/meta/Nothing.luau +2 -2
  36. package/src/codec/meta/Unknown.luau +22 -32
  37. package/src/codec/primitive/Bool.luau +9 -5
  38. package/src/codec/primitive/Float16.luau +13 -23
  39. package/src/codec/primitive/Int.luau +20 -28
  40. package/src/codec/primitive/Number.luau +6 -10
  41. package/src/codec/primitive/Signed.luau +32 -0
  42. package/src/codec/primitive/Varint.luau +59 -28
  43. package/src/index.d.ts +8 -2
  44. package/src/init.luau +133 -143
  45. package/src/internal/Baseline.luau +17 -18
  46. package/src/internal/Channel.luau +143 -212
  47. package/src/internal/Middleware.luau +37 -47
  48. package/src/internal/Pool.luau +10 -10
  49. package/src/internal/Registry.luau +38 -34
  50. package/src/internal/Transport.luau +28 -0
  51. package/src/internal/Util.luau +26 -0
  52. package/src/transport/Bridge.luau +32 -24
  53. package/src/transport/Client.luau +51 -53
  54. package/src/transport/Gate.luau +183 -113
  55. package/src/transport/Reader.luau +95 -66
  56. package/src/transport/Server.luau +130 -125
@@ -1,16 +1,14 @@
1
1
  --!strict
2
2
  --!native
3
- -- Variable-length string codec with __call for bounded variant.
3
+ -- Variable-length UTF-8 string codec with __call factory for bounded variant.
4
4
 
5
5
  local Base = require(script.Parent.Parent.Base)
6
6
  local Types = require(script.Parent.Parent.Parent.Types)
7
7
  local Varint = require(script.Parent.Parent.primitive.Varint)
8
8
 
9
- -- Private -------------------------------------------------------------
9
+ -- Private ----------------------------------------------------------------
10
10
 
11
11
  local alloc = Base.alloc
12
- local writeu8 = buffer.writeu8
13
- local readu8 = buffer.readu8
14
12
  local INLINE = Varint.INLINE_MAX
15
13
 
16
14
  local function writeString(ch: Types.ChannelState, value: string): ()
@@ -18,100 +16,72 @@ local function writeString(ch: Types.ChannelState, value: string): ()
18
16
  local cursor = ch.cursor
19
17
 
20
18
  if len <= INLINE then
21
- -- Short strings (<= 191 bytes) use a single-byte prefix, avoiding Varint.write overhead
22
19
  if cursor + 1 + len > ch.size then
23
20
  alloc(ch, 1 + len)
24
21
  end
25
22
  local b = ch.buff
26
- writeu8(b, cursor, len)
23
+ buffer.writeu8(b, cursor, len)
27
24
  if len > 0 then
28
25
  buffer.writestring(b, cursor + 1, value)
29
26
  end
30
27
  ch.cursor = cursor + 1 + len
31
- else
32
- -- Long strings need multi-byte length encoding
33
- Varint.write(ch, len)
34
- cursor = ch.cursor
35
- if cursor + len > ch.size then
36
- alloc(ch, len)
37
- end
38
- buffer.writestring(ch.buff, cursor, value)
39
- ch.cursor = cursor + len
28
+ return
40
29
  end
41
- end
42
30
 
43
- local function readString(src: buffer, pos: number, _refs: { Instance }?): (string, number)
44
- local b0 = readu8(src, pos)
45
- local len: number
46
- local lenBytes: number
47
-
48
- if b0 <= INLINE then
49
- len = b0
50
- lenBytes = 1
51
- else
52
- len, lenBytes = Varint.read(src, pos)
31
+ Varint.write(ch, len)
32
+ cursor = ch.cursor
33
+ if cursor + len > ch.size then
34
+ alloc(ch, len)
53
35
  end
36
+ buffer.writestring(ch.buff, cursor, value)
37
+ ch.cursor = cursor + len
38
+ end
54
39
 
40
+ local readLengthPrefix = Varint.readLengthPrefix
41
+
42
+ local function readString(src: buffer, pos: number, _refs: { Instance }?): (string, number)
43
+ local len, lenBytes = readLengthPrefix(src, pos)
55
44
  if len == 0 then
56
45
  return "", lenBytes
57
46
  end
58
47
 
59
48
  local dataStart = pos + lenBytes
60
49
  if dataStart + len > buffer.len(src) then
61
- error("[Lync] String: length exceeds remaining buffer")
50
+ error("[Lync] String.read: length exceeds remaining buffer")
62
51
  end
63
-
64
52
  return buffer.readstring(src, dataStart, len), lenBytes + len
65
53
  end
66
54
 
67
- -- Bounded variant shares the write function to avoid per-call closure allocation
68
- local function boundedFactory(_self: any, maxLength: number): Types.InternalCodec<string>
55
+ local function boundedFactory(_self, maxLength: number): Types.InternalCodec<string>
69
56
  if maxLength <= 0 then
70
57
  error("[Lync] Lync.string: maxLength must be positive")
71
58
  end
72
59
 
73
60
  return table.freeze({
61
+ _typeCheck = "string",
74
62
  write = writeString,
75
-
76
- read = function(src: buffer, pos: number, refs: { Instance }?): (string, number)
77
- local b0 = readu8(src, pos)
78
- local len: number
79
- local lenBytes: number
80
-
81
- if b0 <= INLINE then
82
- len = b0
83
- lenBytes = 1
84
- else
85
- len, lenBytes = Varint.read(src, pos)
86
- end
87
-
63
+ read = function(src: buffer, pos: number, _refs: { Instance }?): (string, number)
64
+ local len, lenBytes = readLengthPrefix(src, pos)
88
65
  if len > maxLength then
89
- error(`[Lync] String: length {len} exceeds max {maxLength}`)
66
+ error(`[Lync] String.read: length {len} exceeds max {maxLength}`)
90
67
  end
91
-
92
68
  if len == 0 then
93
69
  return "", lenBytes
94
70
  end
95
71
 
96
72
  local dataStart = pos + lenBytes
97
73
  if dataStart + len > buffer.len(src) then
98
- error("[Lync] String: length exceeds remaining buffer")
74
+ error("[Lync] String.read: length exceeds remaining buffer")
99
75
  end
100
-
101
76
  return buffer.readstring(src, dataStart, len), lenBytes + len
102
77
  end,
103
- } :: any)
78
+ })
104
79
  end
105
80
 
106
- -- Public --------------------------------------------------------------
107
-
108
- local StringCodec = setmetatable(
109
- {
110
- write = writeString,
111
- read = readString,
112
- _typeCheck = "string",
113
- } :: any,
114
- { __call = boundedFactory }
115
- )
81
+ -- Public -----------------------------------------------------------------
116
82
 
117
- return StringCodec
83
+ return table.freeze(setmetatable({
84
+ _typeCheck = "string",
85
+ write = writeString,
86
+ read = readString,
87
+ }, table.freeze({ __call = boundedFactory })))
@@ -1,45 +1,44 @@
1
1
  --!strict
2
2
  --!optimize 2
3
- -- UDim (8 bytes) and UDim2 (16 bytes) codecs.
3
+ -- UDim (8 bytes) and UDim2 (16 bytes) codecs. Scale is f32, Offset is i32.
4
4
 
5
5
  local Base = require(script.Parent.Parent.Base)
6
+ local Signed = require(script.Parent.Parent.primitive.Signed)
6
7
 
7
- -- Public --------------------------------------------------------------
8
+ -- Private ----------------------------------------------------------------
8
9
 
9
- local UDimCodec = {}
10
+ local writeI32 = Signed.writeI32
11
+ local readi32 = buffer.readi32
10
12
 
11
- UDimCodec.udim = Base.define(8, function(b: buffer, off: number, value: UDim): ()
13
+ local function writeUDim(b: buffer, off: number, value: UDim): ()
12
14
  buffer.writef32(b, off, value.Scale)
13
- buffer.writeu32(
14
- b,
15
- off + 4,
16
- if value.Offset < 0 then value.Offset + 0x100000000 else value.Offset
17
- )
18
- end, function(b: buffer, off: number): UDim
19
- local rawOff = buffer.readu32(b, off + 4)
20
- return UDim.new(
21
- buffer.readf32(b, off),
22
- if rawOff >= 0x80000000 then rawOff - 0x100000000 else rawOff
23
- )
24
- end, { _typeCheck = "UDim" })
15
+ writeI32(b, off + 4, value.Offset)
16
+ end
25
17
 
26
- UDimCodec.udim2 = Base.define(16, function(b: buffer, off: number, value: UDim2): ()
27
- local x = value.X
28
- local y = value.Y
18
+ local function readUDim(b: buffer, off: number): UDim
19
+ return UDim.new(buffer.readf32(b, off), readi32(b, off + 4))
20
+ end
21
+
22
+ local function writeUDim2(b: buffer, off: number, value: UDim2): ()
23
+ local x, y = value.X, value.Y
29
24
  buffer.writef32(b, off, x.Scale)
30
- buffer.writeu32(b, off + 4, if x.Offset < 0 then x.Offset + 0x100000000 else x.Offset)
25
+ writeI32(b, off + 4, x.Offset)
31
26
  buffer.writef32(b, off + 8, y.Scale)
32
- buffer.writeu32(b, off + 12, if y.Offset < 0 then y.Offset + 0x100000000 else y.Offset)
33
- end, function(b: buffer, off: number): UDim2
34
- local xOff = buffer.readu32(b, off + 4)
35
- local yOff = buffer.readu32(b, off + 12)
27
+ writeI32(b, off + 12, y.Offset)
28
+ end
29
+
30
+ local function readUDim2(b: buffer, off: number): UDim2
36
31
  return UDim2.new(
37
- UDim.new(buffer.readf32(b, off), if xOff >= 0x80000000 then xOff - 0x100000000 else xOff),
38
- UDim.new(
39
- buffer.readf32(b, off + 8),
40
- if yOff >= 0x80000000 then yOff - 0x100000000 else yOff
41
- )
32
+ UDim.new(buffer.readf32(b, off), readi32(b, off + 4)),
33
+ UDim.new(buffer.readf32(b, off + 8), readi32(b, off + 12))
42
34
  )
43
- end, { _typeCheck = "UDim2" })
35
+ end
36
+
37
+ -- Public -----------------------------------------------------------------
38
+
39
+ local UDimCodec = {}
40
+
41
+ UDimCodec.udim = Base.define(8, writeUDim, readUDim, { _typeCheck = "UDim" })
42
+ UDimCodec.udim2 = Base.define(16, writeUDim2, readUDim2, { _typeCheck = "UDim2" })
44
43
 
45
44
  return table.freeze(UDimCodec)
@@ -1,22 +1,25 @@
1
1
  --!strict
2
2
  --!optimize 2
3
- -- Vector2 and Vector3 codecs with __call for quantized variants.
3
+ -- Vector2 and Vector3 codecs with __call factory for quantized variants.
4
4
 
5
5
  local Base = require(script.Parent.Parent.Base)
6
+ local Types = require(script.Parent.Parent.Parent.Types)
6
7
 
7
- -- Private -------------------------------------------------------------
8
+ -- Private ----------------------------------------------------------------
8
9
 
10
+ local alloc = Base.alloc
9
11
  local ceil = math.ceil
10
12
  local clamp = math.clamp
11
13
  local round = math.round
12
- local max = math.max
13
- local min = math.min
14
+ local maxN = math.max
15
+ local minN = math.min
14
16
 
15
17
  --[[
16
- Shared quantization setup used by both vec2/vec3 __call and Float.luau.
17
- Returns compBytes, writeFn, readFn, scale, invScale.
18
+ Pick the narrowest u8/u16/u32 wire form for a quantized component
19
+ range. Returns (compBytes, writeFn, readFn, scale, invScale).
18
20
  ]]
19
21
  local function quantizeSetup(
22
+ apiName: string,
20
23
  rangeMin: number,
21
24
  rangeMax: number,
22
25
  precision: number
@@ -28,40 +31,24 @@ local function quantizeSetup(
28
31
  number
29
32
  )
30
33
  if rangeMin > rangeMax then
31
- error("[Lync] Lync.vec2/vec3: min must be <= max")
34
+ error(`[Lync] {apiName}: min must be <= max`)
32
35
  end
33
36
  if precision <= 0 then
34
- error("[Lync] Lync.vec2/vec3: precision must be positive")
37
+ error(`[Lync] {apiName}: precision must be positive`)
35
38
  end
36
39
 
37
40
  local delta = rangeMax - rangeMin
38
- local maxInt = min(0xFFFFFFFF, max(1, ceil(delta / precision)))
39
-
40
- local compBytes: number
41
- local wfn: (buffer, number, number) -> ()
42
- local rfn: (buffer, number) -> number
41
+ local maxInt = minN(0xFFFFFFFF, maxN(1, ceil(delta / precision)))
43
42
 
44
43
  if maxInt <= 0xFF then
45
- compBytes = 1
46
- wfn = buffer.writeu8
47
- rfn = buffer.readu8
48
- elseif maxInt <= 0xFFFF then
49
- compBytes = 2
50
- wfn = buffer.writeu16
51
- rfn = buffer.readu16
52
- else
53
- compBytes = 4
54
- wfn = buffer.writeu32
55
- rfn = buffer.readu32
44
+ return 1, buffer.writeu8, buffer.readu8, maxInt / delta, delta / maxInt
56
45
  end
57
-
58
- local scale = maxInt / delta
59
- local invScale = delta / maxInt
60
- return compBytes, wfn, rfn, scale, invScale
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
61
50
  end
62
51
 
63
- -- Vec2 ----------------------------------------------------------------
64
-
65
52
  local function writeVec2(b: buffer, off: number, value: Vector2): ()
66
53
  buffer.writef32(b, off, value.X)
67
54
  buffer.writef32(b, off + 4, value.Y)
@@ -71,29 +58,6 @@ local function readVec2(b: buffer, off: number): Vector2
71
58
  return Vector2.new(buffer.readf32(b, off), buffer.readf32(b, off + 4))
72
59
  end
73
60
 
74
- local function quantizeVec2(_self: any, rangeMin: number, rangeMax: number, precision: number): any
75
- local delta = rangeMax - rangeMin
76
- if delta == 0 then
77
- local constant = Vector2.new(rangeMin, rangeMin)
78
- return Base.zero() :: any -- constant value, zero bytes
79
- end
80
-
81
- local compBytes, wfn, rfn, scale, invScale = quantizeSetup(rangeMin, rangeMax, precision)
82
- local totalSize = compBytes * 2
83
-
84
- return Base.define(totalSize, function(b: buffer, off: number, value: Vector2): ()
85
- wfn(b, off, round(clamp(value.X - rangeMin, 0, delta) * scale))
86
- wfn(b, off + compBytes, round(clamp(value.Y - rangeMin, 0, delta) * scale))
87
- end, function(b: buffer, off: number): Vector2
88
- return Vector2.new(
89
- rfn(b, off) * invScale + rangeMin,
90
- rfn(b, off + compBytes) * invScale + rangeMin
91
- )
92
- end, { _typeCheck = "Vector2", _min = rangeMin, _max = rangeMax })
93
- end
94
-
95
- -- Vec3 ----------------------------------------------------------------
96
-
97
61
  local function writeVec3(b: buffer, off: number, value: Vector3): ()
98
62
  buffer.writef32(b, off, value.X)
99
63
  buffer.writef32(b, off + 4, value.Y)
@@ -108,14 +72,46 @@ local function readVec3(b: buffer, off: number): Vector3
108
72
  )
109
73
  end
110
74
 
111
- local function quantizeVec3(_self: any, rangeMin: number, rangeMax: number, precision: number): any
75
+ local function quantizeVec2(
76
+ _self,
77
+ rangeMin: number,
78
+ rangeMax: number,
79
+ precision: number
80
+ ): Types.InternalCodec<Vector2>
81
+ if rangeMax - rangeMin == 0 then
82
+ return Base.constant(Vector2.new(rangeMin, rangeMin))
83
+ end
84
+
85
+ local compBytes, wfn, rfn, scale, invScale =
86
+ quantizeSetup("Lync.vec2", rangeMin, rangeMax, precision)
87
+ local totalSize = compBytes * 2
112
88
  local delta = rangeMax - rangeMin
113
- if delta == 0 then
114
- return Base.zero() :: any
89
+
90
+ return Base.define(totalSize, function(b: buffer, off: number, value: Vector2): ()
91
+ wfn(b, off, round(clamp(value.X - rangeMin, 0, delta) * scale))
92
+ wfn(b, off + compBytes, round(clamp(value.Y - rangeMin, 0, delta) * scale))
93
+ end, function(b: buffer, off: number): Vector2
94
+ return Vector2.new(
95
+ rfn(b, off) * invScale + rangeMin,
96
+ rfn(b, off + compBytes) * invScale + rangeMin
97
+ )
98
+ end, { _typeCheck = "Vector2", _min = rangeMin, _max = rangeMax })
99
+ end
100
+
101
+ local function quantizeVec3(
102
+ _self,
103
+ rangeMin: number,
104
+ rangeMax: number,
105
+ precision: number
106
+ ): Types.InternalCodec<Vector3>
107
+ if rangeMax - rangeMin == 0 then
108
+ return Base.constant(Vector3.new(rangeMin, rangeMin, rangeMin))
115
109
  end
116
110
 
117
- local compBytes, wfn, rfn, scale, invScale = quantizeSetup(rangeMin, rangeMax, precision)
111
+ local compBytes, wfn, rfn, scale, invScale =
112
+ quantizeSetup("Lync.vec3", rangeMin, rangeMax, precision)
118
113
  local totalSize = compBytes * 3
114
+ local delta = rangeMax - rangeMin
119
115
 
120
116
  return Base.define(totalSize, function(b: buffer, off: number, value: Vector3): ()
121
117
  wfn(b, off, round(clamp(value.X - rangeMin, 0, delta) * scale))
@@ -130,56 +126,44 @@ local function quantizeVec3(_self: any, rangeMin: number, rangeMax: number, prec
130
126
  end, { _typeCheck = "Vector3", _min = rangeMin, _max = rangeMax })
131
127
  end
132
128
 
133
- -- Public --------------------------------------------------------------
129
+ -- Public -----------------------------------------------------------------
134
130
 
135
131
  local VectorCodec = {}
136
132
 
137
- VectorCodec.vec2 = setmetatable(
138
- {
139
- _size = 8,
140
- _directWrite = writeVec2,
141
- _directRead = readVec2,
142
- _typeCheck = "Vector2",
143
-
144
- write = function(ch: Types.ChannelState, value: Vector2): ()
145
- local cursor = ch.cursor
146
- if cursor + 8 > ch.size then
147
- alloc(ch, 8)
148
- end
149
- writeVec2(ch.buff, cursor, value)
150
- ch.cursor = cursor + 8
151
- end,
152
-
153
- read = function(src: buffer, pos: number, _refs: { Instance }?): (Vector2, number)
154
- return readVec2(src, pos), 8
155
- end,
156
- } :: any,
157
- { __call = quantizeVec2 }
158
- )
159
-
160
- VectorCodec.vec3 = setmetatable(
161
- {
162
- _size = 12,
163
- _directWrite = writeVec3,
164
- _directRead = readVec3,
165
- _typeCheck = "Vector3",
166
-
167
- write = function(ch: Types.ChannelState, value: Vector3): ()
168
- local cursor = ch.cursor
169
- if cursor + 12 > ch.size then
170
- alloc(ch, 12)
171
- end
172
- writeVec3(ch.buff, cursor, value)
173
- ch.cursor = cursor + 12
174
- end,
175
-
176
- read = function(src: buffer, pos: number, _refs: { Instance }?): (Vector3, number)
177
- return readVec3(src, pos), 12
178
- end,
179
- } :: any,
180
- { __call = quantizeVec3 }
181
- )
182
-
183
- VectorCodec.quantizeSetup = quantizeSetup
133
+ VectorCodec.vec2 = table.freeze(setmetatable({
134
+ _size = 8,
135
+ _directWrite = writeVec2,
136
+ _directRead = readVec2,
137
+ _typeCheck = "Vector2",
138
+ write = function(ch: Types.ChannelState, value: Vector2): ()
139
+ local cursor = ch.cursor
140
+ if cursor + 8 > ch.size then
141
+ alloc(ch, 8)
142
+ end
143
+ writeVec2(ch.buff, cursor, value)
144
+ ch.cursor = cursor + 8
145
+ end,
146
+ read = function(src: buffer, pos: number, _refs: { Instance }?): (Vector2, number)
147
+ return readVec2(src, pos), 8
148
+ end,
149
+ }, table.freeze({ __call = quantizeVec2 })))
150
+
151
+ VectorCodec.vec3 = table.freeze(setmetatable({
152
+ _size = 12,
153
+ _directWrite = writeVec3,
154
+ _directRead = readVec3,
155
+ _typeCheck = "Vector3",
156
+ write = function(ch: Types.ChannelState, value: Vector3): ()
157
+ local cursor = ch.cursor
158
+ if cursor + 12 > ch.size then
159
+ alloc(ch, 12)
160
+ end
161
+ writeVec3(ch.buff, cursor, value)
162
+ ch.cursor = cursor + 12
163
+ end,
164
+ read = function(src: buffer, pos: number, _refs: { Instance }?): (Vector3, number)
165
+ return readVec3(src, pos), 12
166
+ end,
167
+ }, table.freeze({ __call = quantizeVec3 })))
184
168
 
185
169
  return table.freeze(VectorCodec)