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