@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,6 +1,6 @@
1
1
  --!strict
2
2
  --!optimize 2
3
- -- Packet definition, send, on, once, wait, stats.
3
+ -- Packet definition: send, on, once, wait, stats.
4
4
 
5
5
  local Players = game:GetService("Players")
6
6
  local RunService = game:GetService("RunService")
@@ -9,226 +9,237 @@ local Baseline = require(script.Parent.Parent.internal.Baseline)
9
9
  local Channel = require(script.Parent.Parent.internal.Channel)
10
10
  local Middleware = require(script.Parent.Parent.internal.Middleware)
11
11
  local Registry = require(script.Parent.Parent.internal.Registry)
12
+ local Transport = require(script.Parent.Parent.internal.Transport)
12
13
  local Types = require(script.Parent.Parent.Types)
14
+ local Util = require(script.Parent.Parent.internal.Util)
13
15
 
14
- -- Constants -----------------------------------------------------------
16
+ -- Constants --------------------------------------------------------------
15
17
 
16
18
  local IS_SERVER = RunService:IsServer()
17
19
 
18
- -- Private -------------------------------------------------------------
20
+ -- Private ----------------------------------------------------------------
19
21
 
20
- local function resolveTimestampMode(ts: string?): (number, number)
22
+ local isPlayer = Util.isPlayer
23
+
24
+ local function resolveTimestampMode(ts: ("frame" | "offset" | "full")?): (number, number)
21
25
  if ts == "frame" then
22
26
  Channel.enableTimestamps()
23
27
  return Channel.TS_FRAME, 2
24
- elseif ts == "offset" then
28
+ end
29
+ if ts == "offset" then
25
30
  Channel.enableTimestamps()
26
31
  return Channel.TS_OFFSET, 3
27
- elseif ts == "full" then
32
+ end
33
+ if ts == "full" then
28
34
  Channel.enableTimestamps()
29
35
  return Channel.TS_FULL, 9
30
36
  end
31
37
  return Channel.TS_NONE, 1
32
38
  end
33
39
 
34
- -- Public --------------------------------------------------------------
40
+ -- Public types -----------------------------------------------------------
41
+
42
+ export type PacketHandle<T> = {
43
+ send: (self: PacketHandle<T>, data: T, target: any?) -> (),
44
+ on: (
45
+ self: PacketHandle<T>,
46
+ fn: (data: T, sender: Player?, timestamp: number?) -> ()
47
+ ) -> Types.Connection,
48
+ once: (
49
+ self: PacketHandle<T>,
50
+ fn: (data: T, sender: Player?, timestamp: number?) -> ()
51
+ ) -> Types.Connection,
52
+ wait: (self: PacketHandle<T>) -> (T, Player?, number?),
53
+ name: (self: PacketHandle<T>) -> string,
54
+ stats: (self: PacketHandle<T>) -> Types.PacketStats,
55
+ }
35
56
 
36
- local Packet = {}
57
+ -- Public -----------------------------------------------------------------
37
58
 
38
- export type PacketHandle = {
39
- send: (self: PacketHandle, data: any, target: any?) -> (),
40
- on: (self: PacketHandle, fn: (...any) -> ()) -> Types.Connection,
41
- once: (self: PacketHandle, fn: (...any) -> ()) -> Types.Connection,
42
- wait: (self: PacketHandle) -> ...any,
43
- name: (self: PacketHandle) -> string,
44
- stats: (self: PacketHandle) -> Types.PacketStats,
45
- }
59
+ local Packet = {}
46
60
 
47
- function Packet.define(
61
+ function Packet.define<T>(
48
62
  name: string,
49
- codec: Types.InternalCodec<any>,
63
+ codec: Types.InternalCodec<T>,
50
64
  options: Types.PacketOptions?
51
- ): PacketHandle
52
- local opts = options or {} :: Types.PacketOptions
65
+ ): PacketHandle<T>
66
+ local opts = options or ({} :: Types.PacketOptions)
53
67
  local isUnreliable = opts.unreliable or false
54
68
 
55
- if isUnreliable and (codec :: any)._isDelta then
69
+ if isUnreliable and codec._isDelta then
56
70
  error(`[Lync] Lync.packet: "{name}" cannot use delta codecs with unreliable transport`)
57
71
  end
58
72
 
59
- if (codec :: any)._hasUnknown and not opts.validate then
73
+ if codec._hasUnknown and not opts.validate then
60
74
  warn(
61
- `[Lync] Lync.packet: "{name}" uses unknown codec without validate data bypasses schema validation`
75
+ `[Lync] Lync.packet: "{name}" uses unknown codec without validate; data bypasses schema validation`
62
76
  )
63
77
  end
64
78
 
65
- if (codec :: any)._isDelta then
79
+ if codec._isDelta then
66
80
  Baseline.markHasDelta()
67
81
  end
68
82
 
69
83
  local tsMode, headerSize = resolveTimestampMode(opts.timestamp)
70
- local needsGate = IS_SERVER
71
-
72
84
  local openFn = Channel.resolveOpenFn(tsMode, name)
73
85
 
74
- local reg = Registry.register(
75
- name,
76
- Registry.KIND_PACKET,
77
- codec,
78
- isUnreliable,
79
- nil,
80
- needsGate,
81
- headerSize,
82
- tsMode,
83
- openFn,
84
- opts.rateLimit,
85
- opts.validate,
86
- opts.maxPayloadBytes
87
- )
88
-
89
- -- Lazy-require Server/Client to avoid circular dependency
90
- local _server: any = nil
91
- local _client: any = nil
92
-
93
- local function getServer(): any
94
- if not _server then
95
- _server = require(script.Parent.Parent.transport.Server)
86
+ local reg = Registry.register({
87
+ name = name,
88
+ kind = Registry.KIND_PACKET,
89
+ codec = codec,
90
+ isUnreliable = isUnreliable,
91
+ partner = nil,
92
+ needsGate = IS_SERVER,
93
+ headerSize = headerSize,
94
+ timestampMode = tsMode,
95
+ openFn = openFn,
96
+ rateLimit = opts.rateLimit,
97
+ validate = opts.validate,
98
+ maxPayloadBytes = opts.maxPayloadBytes,
99
+ })
100
+
101
+ local function sendToPlayer(player: Player, data: any): ()
102
+ local ch = Transport.server().getChannel(player, isUnreliable)
103
+ Channel.writeBatch(ch, reg, data)
104
+ end
105
+
106
+ local function bumpFires(): ()
107
+ if Channel.statsEnabled() then
108
+ reg.fires += 1
96
109
  end
97
- return _server
98
110
  end
99
111
 
100
- local function getClient(): any
101
- if not _client then
102
- _client = require(script.Parent.Parent.transport.Client)
112
+ local function applySend(data: any, player: Player?): any?
113
+ if not Middleware.hasSendHooks() then
114
+ return data
103
115
  end
104
- return _client
116
+
117
+ local sendData = Middleware.runSend(data, name, player)
118
+ if typeof(sendData) == "table" and sendData._lyncDrop then
119
+ return nil
120
+ end
121
+ return sendData
105
122
  end
106
123
 
107
- local handle: any = {}
124
+ local function sendFromServer(data: any, target: any): ()
125
+ if target == nil then
126
+ error(`[Lync] Packet.send: "{name}" server send requires a target`)
127
+ end
108
128
 
109
- function handle.send(self: PacketHandle, data: any, target: any?): ()
110
- if Middleware.hasSendHooks() then
111
- data = Middleware.runSend(data, name, nil)
112
- if typeof(data) == "table" and (data :: any)._lyncDrop then
129
+ if isPlayer(target) then
130
+ local sendData = applySend(data, target :: Player)
131
+ if sendData == nil then
113
132
  return
114
133
  end
134
+ sendToPlayer(target :: Player, sendData)
135
+ bumpFires()
136
+ return
115
137
  end
116
138
 
117
- if IS_SERVER then
118
- if target == nil then
119
- error(`[Lync] Packet "{name}": server send requires a target`)
139
+ if typeof(target) == "table" then
140
+ local sendData = applySend(data, nil)
141
+ if sendData == nil then
142
+ return
120
143
  end
121
144
 
122
- local Server = getServer()
123
-
124
- if typeof(target) == "Instance" and target:IsA("Player") then
125
- local ch = Server.getChannel(target :: Player, isUnreliable)
126
- Channel.writeBatch(ch, reg, data)
127
- if Channel.statsEnabled() then
128
- reg.fires += 1
145
+ if target._lyncAll then
146
+ for _, player in Players:GetPlayers() do
147
+ sendToPlayer(player, sendData)
129
148
  end
149
+ bumpFires()
130
150
  return
131
151
  end
132
152
 
133
- if typeof(target) == "table" then
134
- local tbl = target :: any
135
-
136
- if tbl._lyncAll then
137
- for _, player in Players:GetPlayers() do
138
- local ch = Server.getChannel(player, isUnreliable)
139
- Channel.writeBatch(ch, reg, data)
140
- end
141
- if Channel.statsEnabled() then
142
- reg.fires += 1
153
+ if target._lyncExcept then
154
+ local excluded = target._excluded :: { [Player]: boolean }
155
+ for _, player in Players:GetPlayers() do
156
+ if not excluded[player] then
157
+ sendToPlayer(player, sendData)
143
158
  end
144
- return
145
- end
146
-
147
- if tbl._lyncExcept then
148
- local excluded = tbl._excluded :: { [Player]: boolean }
149
- for _, player in Players:GetPlayers() do
150
- if not excluded[player] then
151
- local ch = Server.getChannel(player, isUnreliable)
152
- Channel.writeBatch(ch, reg, data)
153
- end
154
- end
155
- if Channel.statsEnabled() then
156
- reg.fires += 1
157
- end
158
- return
159
- end
160
-
161
- if tbl._lyncGroup then
162
- local members = tbl._members :: { [Player]: boolean }
163
- for player in members do
164
- local ch = Server.getChannel(player, isUnreliable)
165
- Channel.writeBatch(ch, reg, data)
166
- end
167
- if Channel.statsEnabled() then
168
- reg.fires += 1
169
- end
170
- return
171
159
  end
160
+ bumpFires()
161
+ return
162
+ end
172
163
 
173
- for _, player in tbl do
174
- if typeof(player) == "Instance" and (player :: Instance):IsA("Player") then
175
- local ch = Server.getChannel(player :: Player, isUnreliable)
176
- Channel.writeBatch(ch, reg, data)
177
- end
178
- end
179
- if Channel.statsEnabled() then
180
- reg.fires += 1
164
+ if target._lyncGroup then
165
+ for player in target._members :: { [Player]: boolean } do
166
+ sendToPlayer(player, sendData)
181
167
  end
168
+ bumpFires()
182
169
  return
183
170
  end
184
171
 
185
- error(
186
- `[Lync] Packet "{name}": expected Player, table, Group, or Lync.all as target, got {typeof(
187
- target
188
- )}`
189
- )
190
- else
191
- local Client = getClient()
192
- local ch = Client.getChannel(isUnreliable)
193
- Channel.writeBatch(ch, reg, data)
194
- if Channel.statsEnabled() then
195
- reg.fires += 1
172
+ for _, player in target do
173
+ if isPlayer(player) then
174
+ sendToPlayer(player :: Player, sendData)
175
+ end
196
176
  end
177
+ bumpFires()
178
+ return
197
179
  end
198
- end
199
-
200
- function handle.on(_self: PacketHandle, fn: (...any) -> ()): Types.Connection
201
- return reg.signal:connect(fn)
202
- end
203
-
204
- function handle.once(_self: PacketHandle, fn: (...any) -> ()): Types.Connection
205
- local conn: Types.Connection
206
- conn = reg.signal:connect(function(...: any)
207
- conn:disconnect()
208
- fn(...)
209
- end)
210
- return conn
211
- end
212
180
 
213
- function handle.wait(_self: PacketHandle): ...any
214
- return reg.signal:wait()
181
+ error(
182
+ `[Lync] Packet.send: "{name}" expected Player, table, Group, or Lync.all as target, got {typeof(
183
+ target
184
+ )}`
185
+ )
215
186
  end
216
187
 
217
- function handle.name(_self: PacketHandle): string
218
- return reg.name
188
+ local function sendFromClient(data: any): ()
189
+ local sendData = applySend(data, nil)
190
+ if sendData == nil then
191
+ return
192
+ end
193
+ local ch = Transport.client().getChannel(isUnreliable)
194
+ Channel.writeBatch(ch, reg, sendData)
195
+ bumpFires()
219
196
  end
220
197
 
221
- function handle.stats(_self: PacketHandle): Types.PacketStats
222
- return {
223
- bytesSent = reg.bytesSent,
224
- bytesReceived = reg.bytesReceived,
225
- fires = reg.fires,
226
- recvFires = reg.recvFires,
227
- drops = reg.drops,
228
- }
229
- end
198
+ type Self = PacketHandle<T>
199
+ type Listener = (data: T, sender: Player?, timestamp: number?) -> ()
230
200
 
231
- return table.freeze(handle)
201
+ local handle = {
202
+ send = function(_self: Self, data: T, target: any?): ()
203
+ if IS_SERVER then
204
+ sendFromServer(data, target)
205
+ else
206
+ sendFromClient(data)
207
+ end
208
+ end,
209
+
210
+ on = function(_self: Self, fn: Listener): Types.Connection
211
+ return reg.signal:connect(fn :: any)
212
+ end,
213
+
214
+ once = function(_self: Self, fn: Listener): Types.Connection
215
+ local conn: Types.Connection
216
+ conn = reg.signal:connect(function(...: any)
217
+ conn:disconnect()
218
+ fn(...)
219
+ end)
220
+ return conn
221
+ end,
222
+
223
+ wait = function(_self: Self): (T, Player?, number?)
224
+ return reg.signal:wait()
225
+ end,
226
+
227
+ name = function(_self: Self): string
228
+ return reg.name
229
+ end,
230
+
231
+ stats = function(_self: Self): Types.PacketStats
232
+ return {
233
+ bytesSent = reg.bytesSent,
234
+ bytesReceived = reg.bytesReceived,
235
+ fires = reg.fires,
236
+ recvFires = reg.recvFires,
237
+ drops = reg.drops,
238
+ }
239
+ end,
240
+ }
241
+
242
+ return table.freeze(handle) :: PacketHandle<T>
232
243
  end
233
244
 
234
245
  return table.freeze(Packet)