@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.
- package/README.md +499 -357
- package/package.json +2 -2
- package/src/Types.luau +69 -27
- package/src/api/Group.luau +101 -106
- package/src/api/Packet.luau +191 -157
- package/src/api/Query.luau +223 -282
- package/src/api/Scope.luau +46 -57
- package/src/api/Signal.luau +104 -137
- package/src/codec/Base.luau +69 -20
- package/src/codec/composite/Array.luau +189 -201
- package/src/codec/composite/Map.luau +97 -341
- package/src/codec/composite/Optional.luau +27 -23
- package/src/codec/composite/Shared.luau +96 -65
- package/src/codec/composite/Struct.luau +201 -339
- package/src/codec/composite/Tagged.luau +64 -178
- package/src/codec/composite/Tuple.luau +81 -95
- package/src/codec/datatype/Buffer.luau +49 -21
- package/src/codec/datatype/CFrame.luau +207 -30
- package/src/codec/datatype/Color.luau +21 -11
- package/src/codec/datatype/Instance.luau +29 -19
- package/src/codec/datatype/IntVector.luau +33 -21
- package/src/codec/datatype/NumberRange.luau +19 -10
- package/src/codec/datatype/Ray.luau +26 -22
- package/src/codec/datatype/Rect.luau +20 -16
- package/src/codec/datatype/Region.luau +51 -45
- package/src/codec/datatype/Sequence.luau +64 -56
- package/src/codec/datatype/String.luau +89 -56
- package/src/codec/datatype/UDim.luau +40 -22
- package/src/codec/datatype/Vector.luau +181 -17
- package/src/codec/meta/Auto.luau +295 -253
- package/src/codec/meta/Bitfield.luau +104 -148
- package/src/codec/meta/Custom.luau +8 -4
- package/src/codec/meta/Enum.luau +29 -57
- package/src/codec/meta/Float.luau +64 -0
- package/src/codec/meta/Nothing.luau +9 -5
- package/src/codec/meta/Unknown.luau +44 -35
- package/src/codec/primitive/Bool.luau +16 -26
- package/src/codec/primitive/Float16.luau +58 -64
- package/src/codec/primitive/Int.luau +68 -0
- package/src/codec/primitive/Number.luau +21 -43
- package/src/codec/primitive/Varint.luau +67 -46
- package/src/index.d.ts +249 -306
- package/src/init.luau +332 -173
- package/src/internal/Baseline.luau +29 -24
- package/src/internal/Channel.luau +346 -161
- package/src/internal/Middleware.luau +60 -85
- package/src/internal/Pool.luau +19 -30
- package/src/internal/Registry.luau +61 -101
- package/src/transport/Bridge.luau +64 -43
- package/src/transport/Client.luau +60 -117
- package/src/transport/Gate.luau +282 -133
- package/src/transport/Reader.luau +159 -100
- package/src/transport/Server.luau +147 -292
- package/src/api/Namespace.luau +0 -251
- package/src/codec/meta/Quantized.luau +0 -174
package/src/api/Packet.luau
CHANGED
|
@@ -1,200 +1,234 @@
|
|
|
1
1
|
--!strict
|
|
2
2
|
--!optimize 2
|
|
3
|
-
-- Packet definition
|
|
3
|
+
-- Packet definition, send, on, once, wait, stats.
|
|
4
4
|
|
|
5
|
+
local Players = game:GetService("Players")
|
|
5
6
|
local RunService = game:GetService("RunService")
|
|
6
7
|
|
|
7
|
-
local
|
|
8
|
+
local Baseline = require(script.Parent.Parent.internal.Baseline)
|
|
9
|
+
local Channel = require(script.Parent.Parent.internal.Channel)
|
|
10
|
+
local Middleware = require(script.Parent.Parent.internal.Middleware)
|
|
8
11
|
local Registry = require(script.Parent.Parent.internal.Registry)
|
|
9
|
-
local Server = require(script.Parent.Parent.transport.Server)
|
|
10
|
-
local Signal = require(script.Parent.Signal)
|
|
11
12
|
local Types = require(script.Parent.Parent.Types)
|
|
12
13
|
|
|
13
|
-
type Connection = Types.Connection
|
|
14
|
-
type Codec<T> = Types.Codec<T>
|
|
15
|
-
type InternalCodec<T> = Types.InternalCodec<T>
|
|
16
|
-
type PacketConfig<T> = Types.PacketConfig<T>
|
|
17
|
-
|
|
18
14
|
-- Constants -----------------------------------------------------------
|
|
19
15
|
|
|
20
16
|
local IS_SERVER = RunService:IsServer()
|
|
21
17
|
|
|
22
|
-
local serverWriteTo = Server.writeTo
|
|
23
|
-
local serverWriteToAll = Server.writeToAll
|
|
24
|
-
local serverWriteToList = Server.writeToList
|
|
25
|
-
local serverWriteToAllExcept = Server.writeToAllExcept
|
|
26
|
-
local serverWriteToSet = Server.writeToSet
|
|
27
|
-
local clientWrite = Client.write
|
|
28
|
-
|
|
29
|
-
local DELTA_TARGETED = 1
|
|
30
|
-
local DELTA_BROADCAST = 2
|
|
31
|
-
|
|
32
18
|
-- Private -------------------------------------------------------------
|
|
33
19
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
-- Server-only metatable. Single send() dispatches on target type.
|
|
45
|
-
local ServerImpl = {}
|
|
46
|
-
ServerImpl.__index = ServerImpl
|
|
47
|
-
|
|
48
|
-
export type Packet = typeof(setmetatable({} :: PacketFields, ServerImpl))
|
|
49
|
-
|
|
50
|
-
function ServerImpl.listen(self: Packet, callback: (...any) -> ()): Connection
|
|
51
|
-
return self._signal:connect(callback)
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
function ServerImpl.once(self: Packet, callback: (...any) -> ()): Connection
|
|
55
|
-
return self._signal:once(callback)
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
function ServerImpl.wait(self: Packet): ...any
|
|
59
|
-
return self._signal:wait()
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
function ServerImpl.disconnectAll(self: Packet): ()
|
|
63
|
-
self._signal:disconnectAll()
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
local function checkDeltaMode(self: Packet, mode: number): ()
|
|
67
|
-
if not self._isDelta then
|
|
68
|
-
return
|
|
69
|
-
end
|
|
70
|
-
local current = self._deltaMode
|
|
71
|
-
if current == 0 then
|
|
72
|
-
self._deltaMode = mode
|
|
73
|
-
elseif current ~= mode then
|
|
74
|
-
error(`[Lync] Delta packet cannot mix targeted and broadcast: "{self._name}"`)
|
|
20
|
+
local function resolveTimestampMode(ts: string?): (number, number)
|
|
21
|
+
if ts == "frame" then
|
|
22
|
+
Channel.enableTimestamps()
|
|
23
|
+
return Channel.TS_FRAME, 2
|
|
24
|
+
elseif ts == "offset" then
|
|
25
|
+
Channel.enableTimestamps()
|
|
26
|
+
return Channel.TS_OFFSET, 3
|
|
27
|
+
elseif ts == "full" then
|
|
28
|
+
Channel.enableTimestamps()
|
|
29
|
+
return Channel.TS_FULL, 9
|
|
75
30
|
end
|
|
31
|
+
return Channel.TS_NONE, 1
|
|
76
32
|
end
|
|
77
33
|
|
|
78
|
-
|
|
79
|
-
if target == nil then
|
|
80
|
-
error("[Lync] Server packet:send requires a target")
|
|
81
|
-
end
|
|
34
|
+
-- Public --------------------------------------------------------------
|
|
82
35
|
|
|
83
|
-
|
|
84
|
-
local name = self._name
|
|
85
|
-
local codec = self._codec
|
|
86
|
-
local isUnreliable = self._isUnreliable
|
|
36
|
+
local Packet = {}
|
|
87
37
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
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
|
+
}
|
|
94
46
|
|
|
95
|
-
|
|
96
|
-
|
|
47
|
+
function Packet.define(
|
|
48
|
+
name: string,
|
|
49
|
+
codec: Types.InternalCodec<any>,
|
|
50
|
+
options: Types.PacketOptions?
|
|
51
|
+
): PacketHandle
|
|
52
|
+
local opts = options or {} :: Types.PacketOptions
|
|
53
|
+
local isUnreliable = opts.unreliable or false
|
|
97
54
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
checkDeltaMode(self, DELTA_BROADCAST)
|
|
101
|
-
serverWriteToAll(id, name, codec, data, isUnreliable)
|
|
102
|
-
return
|
|
55
|
+
if isUnreliable and (codec :: any)._isDelta then
|
|
56
|
+
error(`[Lync] Lync.packet: "{name}" cannot use delta codecs with unreliable transport`)
|
|
103
57
|
end
|
|
104
58
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
return
|
|
59
|
+
if (codec :: any)._hasUnknown and not opts.validate then
|
|
60
|
+
warn(
|
|
61
|
+
`[Lync] Lync.packet: "{name}" uses unknown codec without validate — data bypasses schema validation`
|
|
62
|
+
)
|
|
110
63
|
end
|
|
111
64
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
checkDeltaMode(self, DELTA_BROADCAST)
|
|
115
|
-
serverWriteToSet(target:getSet(), id, name, codec, data, isUnreliable)
|
|
116
|
-
return
|
|
65
|
+
if (codec :: any)._isDelta then
|
|
66
|
+
Baseline.markHasDelta()
|
|
117
67
|
end
|
|
118
68
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
serverWriteToList(target :: { Player }, id, name, codec, data, isUnreliable)
|
|
122
|
-
end
|
|
123
|
-
|
|
124
|
-
table.freeze(ServerImpl)
|
|
69
|
+
local tsMode, headerSize = resolveTimestampMode(opts.timestamp)
|
|
70
|
+
local needsGate = IS_SERVER
|
|
125
71
|
|
|
126
|
-
|
|
127
|
-
local ClientImpl = {}
|
|
128
|
-
ClientImpl.__index = ClientImpl
|
|
72
|
+
local openFn = Channel.resolveOpenFn(tsMode, name)
|
|
129
73
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
end
|
|
145
|
-
|
|
146
|
-
function ClientImpl.send(self: Packet, data: any): ()
|
|
147
|
-
clientWrite(self._id, self._name, self._codec, data, self._isUnreliable)
|
|
148
|
-
end
|
|
149
|
-
|
|
150
|
-
table.freeze(ClientImpl)
|
|
151
|
-
|
|
152
|
-
-- Public --------------------------------------------------------------
|
|
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
|
+
)
|
|
153
88
|
|
|
154
|
-
|
|
89
|
+
-- Lazy-require Server/Client to avoid circular dependency
|
|
90
|
+
local _server: any = nil
|
|
91
|
+
local _client: any = nil
|
|
155
92
|
|
|
156
|
-
function
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
error(`[Lync] Packet requires a value codec: "{name}"`)
|
|
93
|
+
local function getServer(): any
|
|
94
|
+
if not _server then
|
|
95
|
+
_server = require(script.Parent.Parent.transport.Server)
|
|
96
|
+
end
|
|
97
|
+
return _server
|
|
162
98
|
end
|
|
163
99
|
|
|
164
|
-
local
|
|
100
|
+
local function getClient(): any
|
|
101
|
+
if not _client then
|
|
102
|
+
_client = require(script.Parent.Parent.transport.Client)
|
|
103
|
+
end
|
|
104
|
+
return _client
|
|
105
|
+
end
|
|
165
106
|
|
|
166
|
-
|
|
167
|
-
|
|
107
|
+
local handle: any = {}
|
|
108
|
+
|
|
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
|
|
113
|
+
return
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
if IS_SERVER then
|
|
118
|
+
if target == nil then
|
|
119
|
+
error(`[Lync] Packet "{name}": server send requires a target`)
|
|
120
|
+
end
|
|
121
|
+
|
|
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
|
|
129
|
+
end
|
|
130
|
+
return
|
|
131
|
+
end
|
|
132
|
+
|
|
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
|
|
143
|
+
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
|
+
end
|
|
172
|
+
|
|
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
|
|
181
|
+
end
|
|
182
|
+
return
|
|
183
|
+
end
|
|
184
|
+
|
|
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
|
|
196
|
+
end
|
|
197
|
+
end
|
|
168
198
|
end
|
|
169
199
|
|
|
170
|
-
|
|
200
|
+
function handle.on(_self: PacketHandle, fn: (...any) -> ()): Types.Connection
|
|
201
|
+
return reg.signal:connect(fn)
|
|
202
|
+
end
|
|
171
203
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
)
|
|
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
|
|
181
212
|
|
|
182
|
-
|
|
213
|
+
function handle.wait(_self: PacketHandle): ...any
|
|
214
|
+
return reg.signal:wait()
|
|
215
|
+
end
|
|
183
216
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
_codec = reg.codec,
|
|
188
|
-
_isUnreliable = isUnreliable,
|
|
189
|
-
_isDelta = isDelta,
|
|
190
|
-
_deltaMode = 0,
|
|
191
|
-
_signal = signal,
|
|
192
|
-
}
|
|
217
|
+
function handle.name(_self: PacketHandle): string
|
|
218
|
+
return reg.name
|
|
219
|
+
end
|
|
193
220
|
|
|
194
|
-
|
|
195
|
-
return
|
|
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
|
+
}
|
|
196
229
|
end
|
|
197
|
-
|
|
230
|
+
|
|
231
|
+
return table.freeze(handle)
|
|
198
232
|
end
|
|
199
233
|
|
|
200
|
-
return table.freeze(
|
|
234
|
+
return table.freeze(Packet)
|