@axpecter/lync 1.5.2 → 2.1.0

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 (55) hide show
  1. package/README.md +499 -357
  2. package/package.json +2 -2
  3. package/src/Types.luau +69 -27
  4. package/src/api/Group.luau +101 -106
  5. package/src/api/Packet.luau +191 -157
  6. package/src/api/Query.luau +223 -282
  7. package/src/api/Scope.luau +46 -57
  8. package/src/api/Signal.luau +104 -137
  9. package/src/codec/Base.luau +69 -20
  10. package/src/codec/composite/Array.luau +189 -201
  11. package/src/codec/composite/Map.luau +97 -341
  12. package/src/codec/composite/Optional.luau +27 -23
  13. package/src/codec/composite/Shared.luau +96 -65
  14. package/src/codec/composite/Struct.luau +201 -339
  15. package/src/codec/composite/Tagged.luau +64 -178
  16. package/src/codec/composite/Tuple.luau +81 -95
  17. package/src/codec/datatype/Buffer.luau +49 -21
  18. package/src/codec/datatype/CFrame.luau +207 -30
  19. package/src/codec/datatype/Color.luau +21 -11
  20. package/src/codec/datatype/Instance.luau +29 -19
  21. package/src/codec/datatype/IntVector.luau +33 -21
  22. package/src/codec/datatype/NumberRange.luau +19 -10
  23. package/src/codec/datatype/Ray.luau +26 -22
  24. package/src/codec/datatype/Rect.luau +20 -16
  25. package/src/codec/datatype/Region.luau +51 -45
  26. package/src/codec/datatype/Sequence.luau +64 -56
  27. package/src/codec/datatype/String.luau +89 -56
  28. package/src/codec/datatype/UDim.luau +40 -22
  29. package/src/codec/datatype/Vector.luau +181 -17
  30. package/src/codec/meta/Auto.luau +295 -253
  31. package/src/codec/meta/Bitfield.luau +104 -148
  32. package/src/codec/meta/Custom.luau +8 -4
  33. package/src/codec/meta/Enum.luau +29 -57
  34. package/src/codec/meta/Float.luau +64 -0
  35. package/src/codec/meta/Nothing.luau +9 -5
  36. package/src/codec/meta/Unknown.luau +44 -35
  37. package/src/codec/primitive/Bool.luau +16 -26
  38. package/src/codec/primitive/Float16.luau +58 -64
  39. package/src/codec/primitive/Int.luau +68 -0
  40. package/src/codec/primitive/Number.luau +21 -43
  41. package/src/codec/primitive/Varint.luau +67 -46
  42. package/src/index.d.ts +249 -306
  43. package/src/init.luau +332 -173
  44. package/src/internal/Baseline.luau +29 -24
  45. package/src/internal/Channel.luau +346 -161
  46. package/src/internal/Middleware.luau +60 -85
  47. package/src/internal/Pool.luau +19 -30
  48. package/src/internal/Registry.luau +61 -101
  49. package/src/transport/Bridge.luau +64 -43
  50. package/src/transport/Client.luau +60 -117
  51. package/src/transport/Gate.luau +282 -133
  52. package/src/transport/Reader.luau +159 -100
  53. package/src/transport/Server.luau +147 -292
  54. package/src/api/Namespace.luau +0 -251
  55. package/src/codec/meta/Quantized.luau +0 -174
@@ -1,251 +0,0 @@
1
- --!strict
2
- --!optimize 2
3
- -- Scoped packet/query groups with batch ops and local middleware.
4
-
5
- local Middleware = require(script.Parent.Parent.internal.Middleware)
6
- local Packet = require(script.Parent.Packet)
7
- local Query = require(script.Parent.Query)
8
- local Types = require(script.Parent.Parent.Types)
9
-
10
- type Connection = Types.Connection
11
- type PacketConfig<T> = Types.PacketConfig<T>
12
- type QueryConfig<R, S> = Types.QueryConfig<R, S>
13
-
14
- -- Constants -----------------------------------------------------------
15
-
16
- local MAX_NAMESPACES = 64
17
-
18
- -- State ---------------------------------------------------------------
19
-
20
- local _registered = {} :: { [string]: true }
21
- local _count = 0
22
-
23
- -- Private -------------------------------------------------------------
24
-
25
- type NamespaceConfig = Types.NamespaceConfig
26
-
27
- type NamespaceFields = {
28
- _name: string,
29
- _packets: { [string]: Packet.Packet },
30
- _queries: { [string]: Query.Query },
31
- _tracked: { Connection },
32
- _removers: { () -> () },
33
- packets: { [string]: Packet.Packet },
34
- queries: { [string]: Query.Query },
35
- }
36
-
37
- local function prefixName(nsName: string, name: string): string
38
- return `{nsName}.{name}`
39
- end
40
-
41
- -- Wraps a middleware handler so it only fires for packets in this namespace.
42
- local function scopedHandler(
43
- nsName: string,
44
- handler: (data: any, name: string, player: Player?) -> any?
45
- ): (data: any, name: string, player: Player?) -> any?
46
- local prefix = nsName .. "."
47
- local prefixLen = #prefix
48
-
49
- return function(data: any, name: string, player: Player?): any?
50
- if string.sub(name, 1, prefixLen) ~= prefix then
51
- return data
52
- end
53
- return handler(data, name, player)
54
- end
55
- end
56
-
57
- local NamespaceImpl = {}
58
- NamespaceImpl.__index = NamespaceImpl
59
-
60
- export type Namespace = typeof(setmetatable({} :: NamespaceFields, NamespaceImpl))
61
-
62
- -- Listens on every packet in this namespace. Returns a Connection.
63
- function NamespaceImpl.listenAll(
64
- self: Namespace,
65
- callback: (name: string, data: any, sender: Player?) -> ()
66
- ): Connection
67
- local connections = {} :: { Connection }
68
- local prefix = self._name .. "."
69
- local prefixLen = #prefix
70
-
71
- for fullName, packet in self._packets do
72
- local shortName = string.sub(fullName, prefixLen + 1)
73
- local conn = packet:listen(function(data: any, sender: Player?): ()
74
- callback(shortName, data, sender)
75
- end)
76
- table.insert(connections, conn)
77
- table.insert(self._tracked, conn)
78
- end
79
-
80
- local bundle: Connection
81
- bundle = {
82
- connected = true,
83
- disconnect = function(self: Connection): ()
84
- if not self.connected then
85
- return
86
- end
87
- self.connected = false
88
-
89
- for _, inner in connections do
90
- if inner.connected then
91
- inner:disconnect()
92
- end
93
- end
94
- end,
95
- }
96
-
97
- return bundle
98
- end
99
-
100
- -- Disconnects every listenAll connection. Does not remove scoped middleware.
101
- function NamespaceImpl.disconnectAll(self: Namespace): ()
102
- for _, conn in self._tracked do
103
- if conn.connected then
104
- conn:disconnect()
105
- end
106
- end
107
- table.clear(self._tracked)
108
- end
109
-
110
- -- Registers send middleware scoped to this namespace. Returns a remover.
111
- function NamespaceImpl.onSend(
112
- self: Namespace,
113
- handler: (data: any, name: string, player: Player?) -> any?
114
- ): () -> ()
115
- local wrapped = scopedHandler(self._name, handler)
116
- local remover = Middleware.addSend(wrapped)
117
- table.insert(self._removers, remover)
118
-
119
- return function(): ()
120
- remover()
121
- local idx = table.find(self._removers, remover)
122
- if idx then
123
- table.remove(self._removers, idx)
124
- end
125
- end
126
- end
127
-
128
- -- Registers receive middleware scoped to this namespace. Returns a remover.
129
- function NamespaceImpl.onReceive(
130
- self: Namespace,
131
- handler: (data: any, name: string, player: Player?) -> any?
132
- ): () -> ()
133
- local wrapped = scopedHandler(self._name, handler)
134
- local remover = Middleware.addReceive(wrapped)
135
- table.insert(self._removers, remover)
136
-
137
- return function(): ()
138
- remover()
139
- local idx = table.find(self._removers, remover)
140
- if idx then
141
- table.remove(self._removers, idx)
142
- end
143
- end
144
- end
145
-
146
- -- Kills all listeners and removes all scoped middleware. Full cleanup.
147
- function NamespaceImpl.destroy(self: Namespace): ()
148
- self:disconnectAll()
149
-
150
- for _, remover in self._removers do
151
- remover()
152
- end
153
- table.clear(self._removers)
154
- end
155
-
156
- -- Returns every packet name(without prefix) in this namespace.
157
- function NamespaceImpl.packetNames(self: Namespace): { string }
158
- local result = {} :: { string }
159
- local prefix = self._name .. "."
160
- local prefixLen = #prefix
161
-
162
- for fullName in self._packets do
163
- table.insert(result, string.sub(fullName, prefixLen + 1))
164
- end
165
-
166
- table.sort(result)
167
- return result
168
- end
169
-
170
- -- Returns every query name(without prefix) in this namespace.
171
- function NamespaceImpl.queryNames(self: Namespace): { string }
172
- local result = {} :: { string }
173
- local prefix = self._name .. "."
174
- local prefixLen = #prefix
175
-
176
- for fullName in self._queries do
177
- table.insert(result, string.sub(fullName, prefixLen + 1))
178
- end
179
-
180
- table.sort(result)
181
- return result
182
- end
183
-
184
- table.freeze(NamespaceImpl)
185
-
186
- -- Public --------------------------------------------------------------
187
-
188
- local NamespaceModule = {}
189
-
190
- -- Defines a namespace. Names are auto-prefixed to prevent collisions.
191
- function NamespaceModule.define(name: string, config: NamespaceConfig): Namespace
192
- if #name == 0 then
193
- error("[Lync] Namespace name must not be empty")
194
- end
195
- if _registered[name] then
196
- error(`[Lync] Duplicate namespace: "{name}"`)
197
- end
198
- if _count >= MAX_NAMESPACES then
199
- error(`[Lync] Namespace limit reached: {MAX_NAMESPACES}`)
200
- end
201
-
202
- _count += 1
203
- _registered[name] = true
204
-
205
- local packets = {} :: { [string]: Packet.Packet }
206
- local queries = {} :: { [string]: Query.Query }
207
- local packetsByShort = {} :: { [string]: Packet.Packet }
208
- local queriesByShort = {} :: { [string]: Query.Query }
209
-
210
- if config.packets then
211
- for shortName, packetConfig in config.packets do
212
- local fullName = prefixName(name, shortName)
213
- local packet = Packet.define(fullName, packetConfig)
214
- packets[fullName] = packet
215
- packetsByShort[shortName] = packet
216
- end
217
- end
218
-
219
- if config.queries then
220
- for shortName, queryConfig in config.queries do
221
- local fullName = prefixName(name, shortName)
222
- local query = Query.define(fullName, queryConfig)
223
- queries[fullName] = query
224
- queriesByShort[shortName] = query
225
- end
226
- end
227
-
228
- local nsFields: NamespaceFields = {
229
- _name = name,
230
- _packets = packets,
231
- _queries = queries,
232
- _tracked = {} :: { Connection },
233
- _removers = {} :: { () -> () },
234
- packets = table.freeze(packetsByShort),
235
- queries = table.freeze(queriesByShort),
236
- }
237
-
238
- -- Inject dynamic short-name accessors (ns.Hit, ns.Stats, etc.)
239
- -- These bypass the typed fields; consumers should prefer ns.packets.X / ns.queries.X.
240
- local raw = nsFields :: any
241
- for shortName, packet in packetsByShort do
242
- raw[shortName] = packet
243
- end
244
- for shortName, query in queriesByShort do
245
- raw[shortName] = query
246
- end
247
-
248
- return setmetatable(nsFields, NamespaceImpl)
249
- end
250
-
251
- return table.freeze(NamespaceModule)
@@ -1,174 +0,0 @@
1
- --!strict
2
- --!native
3
- -- Fixed-point compression. Maps float ranges to integer ranges.
4
-
5
- local Channel = require(script.Parent.Parent.Parent.internal.Channel)
6
- local Types = require(script.Parent.Parent.Parent.Types)
7
-
8
- type ChannelState = Types.ChannelState
9
- type Codec<T> = Types.Codec<T>
10
-
11
- local alloc = Channel.alloc
12
-
13
- -- Constants -----------------------------------------------------------
14
-
15
- local clamp = math.clamp
16
- local round = math.round
17
- local ceil = math.ceil
18
- local min = math.min
19
- local max = math.max
20
-
21
- local U32_MAX = 4294967295
22
-
23
- -- Private -------------------------------------------------------------
24
-
25
- local function selectIO(bytes: number): ((b: buffer, offset: number, v: number) -> (), (
26
- b: buffer,
27
- offset: number
28
- ) -> number)
29
- if bytes == 1 then
30
- return buffer.writeu8, buffer.readu8
31
- end
32
- if bytes == 2 then
33
- return buffer.writeu16, buffer.readu16
34
- end
35
- return buffer.writeu32, buffer.readu32
36
- end
37
-
38
- local function selectWidth(maxInt: number): number
39
- if maxInt <= 255 then
40
- return 1
41
- end
42
- if maxInt <= 65535 then
43
- return 2
44
- end
45
- return 4
46
- end
47
-
48
- -- Public --------------------------------------------------------------
49
-
50
- local Quantized = {}
51
-
52
- -- Shared validation and precomputation for both float and vec3 quantizers.
53
- local function setup(
54
- minVal: number,
55
- maxVal: number,
56
- precision: number
57
- ): (number?, number?, number?, any?, any?, number?, number?)
58
- if minVal > maxVal then
59
- error(`[Lync] Quantized min > max: {minVal} > {maxVal}`)
60
- end
61
- if precision <= 0 then
62
- error(`[Lync] Quantized precision must be positive: {precision}`)
63
- end
64
-
65
- local delta = maxVal - minVal
66
- if delta == 0 then
67
- return nil
68
- end
69
-
70
- local maxInt = min(U32_MAX, max(1, ceil(delta / precision)))
71
- local bytes = selectWidth(maxInt)
72
- local wfn, rfn = selectIO(bytes)
73
- local invDelta = 1 / delta
74
- local invMaxInt = delta / maxInt
75
-
76
- return delta, maxInt, bytes, wfn, rfn, invDelta, invMaxInt
77
- end
78
-
79
- function Quantized.float(minVal: number, maxVal: number, precision: number): Codec<number>
80
- local delta, maxInt, bytes, wfn, rfn, invDelta, invMaxInt = setup(minVal, maxVal, precision)
81
- if not delta then
82
- return table.freeze({
83
- _size = 0,
84
- _directWrite = function(_b: buffer, _offset: number, _value: number): () end,
85
- _directRead = function(_b: buffer, _offset: number): number
86
- return minVal
87
- end,
88
- write = function(_ch: ChannelState, _value: number): () end,
89
- read = function(_src: buffer, _pos: number, _refs: { Instance }?): (number, number)
90
- return minVal, 0
91
- end,
92
- })
93
- end
94
-
95
- return table.freeze({
96
- _size = bytes,
97
- _directWrite = function(b: buffer, offset: number, value: number): ()
98
- wfn(b, offset, round(clamp((value - minVal) * invDelta, 0, 1) * maxInt))
99
- end,
100
- _directRead = function(b: buffer, offset: number): number
101
- return rfn(b, offset) * invMaxInt + minVal
102
- end,
103
- write = function(ch: ChannelState, value: number): ()
104
- local c = ch.cursor
105
- if c + bytes > ch.size then
106
- alloc(ch, bytes)
107
- end
108
- wfn(ch.buff, c, round(clamp((value - minVal) * invDelta, 0, 1) * maxInt))
109
- ch.cursor = c + bytes
110
- end,
111
- read = function(src: buffer, pos: number, _refs: { Instance }?): (number, number)
112
- return rfn(src, pos) * invMaxInt + minVal, bytes
113
- end,
114
- })
115
- end
116
-
117
- function Quantized.vec3(minVal: number, maxVal: number, precision: number): Codec<Vector3>
118
- local delta, maxInt, compBytes, wfn, rfn, invDelta, invMaxInt = setup(minVal, maxVal, precision)
119
- if not delta then
120
- local val = Vector3.new(minVal, minVal, minVal)
121
- return table.freeze({
122
- _size = 0,
123
- _directWrite = function(_b: buffer, _offset: number, _value: Vector3): () end,
124
- _directRead = function(_b: buffer, _offset: number): Vector3
125
- return val
126
- end,
127
- write = function(_ch: ChannelState, _value: Vector3): () end,
128
- read = function(_src: buffer, _pos: number, _refs: { Instance }?): (Vector3, number)
129
- return val, 0
130
- end,
131
- })
132
- end
133
-
134
- local totalBytes = compBytes * 3
135
- local stride = compBytes
136
- local stride2 = compBytes * 2
137
-
138
- return table.freeze({
139
- _size = totalBytes,
140
- _directWrite = function(b: buffer, offset: number, value: Vector3): ()
141
- wfn(b, offset, round(clamp((value.X - minVal) * invDelta, 0, 1) * maxInt))
142
- wfn(b, offset + stride, round(clamp((value.Y - minVal) * invDelta, 0, 1) * maxInt))
143
- wfn(b, offset + stride2, round(clamp((value.Z - minVal) * invDelta, 0, 1) * maxInt))
144
- end,
145
- _directRead = function(b: buffer, offset: number): Vector3
146
- return Vector3.new(
147
- rfn(b, offset) * invMaxInt + minVal,
148
- rfn(b, offset + stride) * invMaxInt + minVal,
149
- rfn(b, offset + stride2) * invMaxInt + minVal
150
- )
151
- end,
152
- write = function(ch: ChannelState, value: Vector3): ()
153
- local c = ch.cursor
154
- if c + totalBytes > ch.size then
155
- alloc(ch, totalBytes)
156
- end
157
- local b = ch.buff
158
- wfn(b, c, round(clamp((value.X - minVal) * invDelta, 0, 1) * maxInt))
159
- wfn(b, c + stride, round(clamp((value.Y - minVal) * invDelta, 0, 1) * maxInt))
160
- wfn(b, c + stride2, round(clamp((value.Z - minVal) * invDelta, 0, 1) * maxInt))
161
- ch.cursor = c + totalBytes
162
- end,
163
- read = function(src: buffer, pos: number, _refs: { Instance }?): (Vector3, number)
164
- return Vector3.new(
165
- rfn(src, pos) * invMaxInt + minVal,
166
- rfn(src, pos + stride) * invMaxInt + minVal,
167
- rfn(src, pos + stride2) * invMaxInt + minVal
168
- ),
169
- totalBytes
170
- end,
171
- })
172
- end
173
-
174
- return table.freeze(Quantized)