@axpecter/lync 2.0.0 → 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 +475 -426
- package/package.json +1 -1
- package/src/Types.luau +63 -31
- package/src/api/Group.luau +101 -106
- package/src/api/Packet.luau +187 -186
- package/src/api/Query.luau +223 -284
- 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 +179 -270
- package/src/codec/composite/Map.luau +97 -347
- package/src/codec/composite/Optional.luau +27 -24
- package/src/codec/composite/Shared.luau +96 -65
- package/src/codec/composite/Struct.luau +200 -360
- package/src/codec/composite/Tagged.luau +62 -187
- package/src/codec/composite/Tuple.luau +79 -103
- 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 +28 -21
- 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 -36
- 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 -335
- package/src/init.luau +319 -207
- package/src/internal/Baseline.luau +29 -24
- package/src/internal/Channel.luau +333 -278
- package/src/internal/Middleware.luau +60 -85
- package/src/internal/Pool.luau +19 -30
- package/src/internal/Registry.luau +56 -113
- package/src/transport/Bridge.luau +64 -43
- package/src/transport/Client.luau +59 -170
- package/src/transport/Gate.luau +282 -142
- package/src/transport/Reader.luau +148 -140
- package/src/transport/Server.luau +138 -488
- package/src/api/Namespace.luau +0 -256
- package/src/codec/meta/Quantized.luau +0 -174
package/src/api/Packet.luau
CHANGED
|
@@ -1,233 +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
|
|
|
8
|
+
local Baseline = require(script.Parent.Parent.internal.Baseline)
|
|
7
9
|
local Channel = require(script.Parent.Parent.internal.Channel)
|
|
8
|
-
local
|
|
10
|
+
local Middleware = require(script.Parent.Parent.internal.Middleware)
|
|
9
11
|
local Registry = require(script.Parent.Parent.internal.Registry)
|
|
10
|
-
local Server = require(script.Parent.Parent.transport.Server)
|
|
11
|
-
local Signal = require(script.Parent.Signal)
|
|
12
12
|
local Types = require(script.Parent.Parent.Types)
|
|
13
13
|
|
|
14
|
-
type Connection = Types.Connection
|
|
15
|
-
type Codec<T> = Types.Codec<T>
|
|
16
|
-
type InternalCodec<T> = Types.InternalCodec<T>
|
|
17
|
-
type PacketConfig<T> = Types.PacketConfig<T>
|
|
18
|
-
type Registration = Types.Registration
|
|
19
|
-
|
|
20
14
|
-- Constants -----------------------------------------------------------
|
|
21
15
|
|
|
22
16
|
local IS_SERVER = RunService:IsServer()
|
|
23
17
|
|
|
24
|
-
local DELTA_TARGETED = 1
|
|
25
|
-
local DELTA_BROADCAST = 2
|
|
26
|
-
|
|
27
|
-
local TS_LOOKUP = {
|
|
28
|
-
frame = Channel.TS_FRAME,
|
|
29
|
-
offset = Channel.TS_OFFSET,
|
|
30
|
-
full = Channel.TS_FULL,
|
|
31
|
-
}
|
|
32
|
-
|
|
33
18
|
-- Private -------------------------------------------------------------
|
|
34
19
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
return
|
|
46
|
-
end
|
|
47
|
-
local current = self._deltaMode
|
|
48
|
-
if current == 0 then
|
|
49
|
-
self._deltaMode = mode
|
|
50
|
-
elseif current ~= mode then
|
|
51
|
-
error(`[Lync] Delta packet cannot mix targeted and broadcast: "{self._reg.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
|
|
52
30
|
end
|
|
31
|
+
return Channel.TS_NONE, 1
|
|
53
32
|
end
|
|
54
33
|
|
|
55
|
-
--
|
|
56
|
-
local ServerImpl = {}
|
|
57
|
-
ServerImpl.__index = ServerImpl
|
|
58
|
-
|
|
59
|
-
export type Packet = typeof(setmetatable({} :: PacketFields, ServerImpl))
|
|
60
|
-
|
|
61
|
-
function ServerImpl.listen(self: Packet, callback: (...any) -> ()): Connection
|
|
62
|
-
return self._signal:connect(callback)
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
function ServerImpl.once(self: Packet, callback: (...any) -> ()): Connection
|
|
66
|
-
return self._signal:once(callback)
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
function ServerImpl.wait(self: Packet): ...any
|
|
70
|
-
return self._signal:wait()
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
function ServerImpl.disconnectAll(self: Packet): ()
|
|
74
|
-
self._signal:disconnectAll()
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
function ServerImpl.send(self: Packet, data: any, target: any?): ()
|
|
78
|
-
if target == nil then
|
|
79
|
-
error("[Lync] Server packet:send requires a target")
|
|
80
|
-
end
|
|
34
|
+
-- Public --------------------------------------------------------------
|
|
81
35
|
|
|
82
|
-
|
|
83
|
-
local isUnreliable = self._isUnreliable
|
|
36
|
+
local Packet = {}
|
|
84
37
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
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
|
+
}
|
|
90
46
|
|
|
91
|
-
|
|
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
|
|
92
54
|
|
|
93
|
-
if
|
|
94
|
-
|
|
95
|
-
Server.writeToAll(reg, data, isUnreliable)
|
|
96
|
-
return
|
|
55
|
+
if isUnreliable and (codec :: any)._isDelta then
|
|
56
|
+
error(`[Lync] Lync.packet: "{name}" cannot use delta codecs with unreliable transport`)
|
|
97
57
|
end
|
|
98
58
|
|
|
99
|
-
if
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
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
|
+
)
|
|
103
63
|
end
|
|
104
64
|
|
|
105
|
-
if
|
|
106
|
-
|
|
107
|
-
Server.writeToSet(target:getSet(), reg, data, isUnreliable)
|
|
108
|
-
return
|
|
65
|
+
if (codec :: any)._isDelta then
|
|
66
|
+
Baseline.markHasDelta()
|
|
109
67
|
end
|
|
110
68
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
end
|
|
69
|
+
local tsMode, headerSize = resolveTimestampMode(opts.timestamp)
|
|
70
|
+
local needsGate = IS_SERVER
|
|
114
71
|
|
|
115
|
-
|
|
116
|
-
function ServerImpl.getBytesSent(self: Packet): number
|
|
117
|
-
return self._reg.bytesSent
|
|
118
|
-
end
|
|
119
|
-
|
|
120
|
-
function ServerImpl.getBytesReceived(self: Packet): number
|
|
121
|
-
return self._reg.bytesReceived
|
|
122
|
-
end
|
|
123
|
-
|
|
124
|
-
function ServerImpl.getFires(self: Packet): number
|
|
125
|
-
return self._reg.fires
|
|
126
|
-
end
|
|
127
|
-
|
|
128
|
-
function ServerImpl.getRecvFires(self: Packet): number
|
|
129
|
-
return self._reg.recvFires
|
|
130
|
-
end
|
|
72
|
+
local openFn = Channel.resolveOpenFn(tsMode, name)
|
|
131
73
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
function ClientImpl.once(self: Packet, callback: (...any) -> ()): Connection
|
|
147
|
-
return self._signal:once(callback)
|
|
148
|
-
end
|
|
149
|
-
|
|
150
|
-
function ClientImpl.wait(self: Packet): ...any
|
|
151
|
-
return self._signal:wait()
|
|
152
|
-
end
|
|
153
|
-
|
|
154
|
-
function ClientImpl.disconnectAll(self: Packet): ()
|
|
155
|
-
self._signal:disconnectAll()
|
|
156
|
-
end
|
|
157
|
-
|
|
158
|
-
function ClientImpl.send(self: Packet, data: any): ()
|
|
159
|
-
Client.write(self._reg, data, self._isUnreliable)
|
|
160
|
-
end
|
|
161
|
-
|
|
162
|
-
ClientImpl.getBytesSent = ServerImpl.getBytesSent
|
|
163
|
-
ClientImpl.getBytesReceived = ServerImpl.getBytesReceived
|
|
164
|
-
ClientImpl.getFires = ServerImpl.getFires
|
|
165
|
-
ClientImpl.getRecvFires = ServerImpl.getRecvFires
|
|
166
|
-
ClientImpl.getDrops = ServerImpl.getDrops
|
|
167
|
-
|
|
168
|
-
table.freeze(ClientImpl)
|
|
169
|
-
|
|
170
|
-
-- 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
|
+
)
|
|
171
88
|
|
|
172
|
-
|
|
89
|
+
-- Lazy-require Server/Client to avoid circular dependency
|
|
90
|
+
local _server: any = nil
|
|
91
|
+
local _client: any = nil
|
|
173
92
|
|
|
174
|
-
function
|
|
175
|
-
|
|
176
|
-
|
|
93
|
+
local function getServer(): any
|
|
94
|
+
if not _server then
|
|
95
|
+
_server = require(script.Parent.Parent.transport.Server)
|
|
96
|
+
end
|
|
97
|
+
return _server
|
|
177
98
|
end
|
|
178
|
-
if not config.value then
|
|
179
|
-
error(`[Lync] Packet requires a value codec: "{name}"`)
|
|
180
|
-
end
|
|
181
|
-
|
|
182
|
-
local isUnreliable = config.unreliable or false
|
|
183
99
|
|
|
184
|
-
|
|
185
|
-
|
|
100
|
+
local function getClient(): any
|
|
101
|
+
if not _client then
|
|
102
|
+
_client = require(script.Parent.Parent.transport.Client)
|
|
103
|
+
end
|
|
104
|
+
return _client
|
|
186
105
|
end
|
|
187
106
|
|
|
188
|
-
local
|
|
189
|
-
|
|
190
|
-
|
|
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
|
|
191
198
|
end
|
|
192
199
|
|
|
193
|
-
|
|
194
|
-
|
|
200
|
+
function handle.on(_self: PacketHandle, fn: (...any) -> ()): Types.Connection
|
|
201
|
+
return reg.signal:connect(fn)
|
|
195
202
|
end
|
|
196
203
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
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
|
|
202
211
|
end
|
|
203
212
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
name,
|
|
208
|
-
config.value,
|
|
209
|
-
isUnreliable,
|
|
210
|
-
signal,
|
|
211
|
-
config.rateLimit,
|
|
212
|
-
config.validate,
|
|
213
|
-
config.maxPayloadBytes,
|
|
214
|
-
timestampMode
|
|
215
|
-
)
|
|
216
|
-
|
|
217
|
-
local isDelta = (config.value :: InternalCodec<any>)._isDelta == true
|
|
213
|
+
function handle.wait(_self: PacketHandle): ...any
|
|
214
|
+
return reg.signal:wait()
|
|
215
|
+
end
|
|
218
216
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
_isDelta = isDelta,
|
|
223
|
-
_deltaMode = 0,
|
|
224
|
-
_signal = signal,
|
|
225
|
-
}
|
|
217
|
+
function handle.name(_self: PacketHandle): string
|
|
218
|
+
return reg.name
|
|
219
|
+
end
|
|
226
220
|
|
|
227
|
-
|
|
228
|
-
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
|
+
}
|
|
229
229
|
end
|
|
230
|
-
|
|
230
|
+
|
|
231
|
+
return table.freeze(handle)
|
|
231
232
|
end
|
|
232
233
|
|
|
233
|
-
return table.freeze(
|
|
234
|
+
return table.freeze(Packet)
|