@axpecter/lync 2.3.3 → 3.0.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/LICENSE +21 -0
- package/README.md +302 -299
- package/Types.luau +215 -0
- package/api/Define.luau +154 -0
- package/api/Lifecycle.luau +119 -0
- package/api/Packet.luau +108 -0
- package/api/Query.luau +149 -0
- package/api/Set.luau +189 -0
- package/channel/Blocks.luau +124 -0
- package/channel/Group.luau +118 -0
- package/channel/Link.luau +135 -0
- package/channel/Outbox.luau +261 -0
- package/channel/Recipients.luau +129 -0
- package/channel/Transport.luau +138 -0
- package/codec/Base.luau +236 -0
- package/codec/Composites.luau +128 -0
- package/codec/Datatypes.luau +162 -0
- package/codec/Legality.luau +61 -0
- package/codec/Scalars.luau +72 -0
- package/codec/Text.luau +89 -0
- package/codec/init.luau +39 -0
- package/index.d.ts +285 -0
- package/init.luau +91 -0
- package/kernel/Bits.luau +16 -0
- package/kernel/Catalog.luau +121 -0
- package/kernel/Heap.luau +80 -0
- package/kernel/Listeners.luau +95 -0
- package/kernel/Log.luau +197 -0
- package/kernel/Tally.luau +128 -0
- package/kernel/Threads.luau +44 -0
- package/kernel/Wide.luau +267 -0
- package/package.json +15 -32
- package/runtime/Boundary.luau +180 -0
- package/runtime/Dispatch.luau +91 -0
- package/runtime/Handles.luau +114 -0
- package/runtime/Handshake.luau +90 -0
- package/runtime/Pending.luau +196 -0
- package/runtime/Router.luau +379 -0
- package/runtime/Session.luau +731 -0
- package/shape/Compile.luau +340 -0
- package/shape/Folds.luau +332 -0
- package/shape/Frames.luau +170 -0
- package/shape/Grid.luau +169 -0
- package/shape/Ir.luau +540 -0
- package/shape/Joins.luau +125 -0
- package/shape/Legality.luau +273 -0
- package/shape/Lower.luau +419 -0
- package/shape/Order.luau +64 -0
- package/shape/Regions.luau +113 -0
- package/shape/Rotation.luau +472 -0
- package/shape/Serial.luau +258 -0
- package/shape/Words.luau +89 -0
- package/shape/emit/Block.luau +453 -0
- package/shape/emit/Column.luau +338 -0
- package/shape/emit/Leaf.luau +462 -0
- package/shape/emit/Word.luau +234 -0
- package/shape/emit/init.luau +222 -0
- package/shape/init.luau +78 -0
- package/state/Apply.luau +330 -0
- package/state/Audience.luau +126 -0
- package/state/Catchup.luau +218 -0
- package/state/Coalesce.luau +43 -0
- package/state/Fieldset.luau +177 -0
- package/state/Newest.luau +339 -0
- package/state/Plan.luau +441 -0
- package/state/Sections.luau +468 -0
- package/state/Store.luau +188 -0
- package/state/Sync.luau +762 -0
- package/wire/Bytes.luau +118 -0
- package/wire/Clock.luau +37 -0
- package/wire/Protocol.luau +110 -0
- package/wire/Sequence.luau +40 -0
- package/wire/Varint.luau +124 -0
- package/src/Types.luau +0 -180
- package/src/api/Group.luau +0 -156
- package/src/api/Packet.luau +0 -317
- package/src/api/Query.luau +0 -338
- package/src/api/Scope.luau +0 -90
- package/src/api/Signal.luau +0 -193
- package/src/codec/Base.luau +0 -136
- package/src/codec/composite/Array.luau +0 -473
- package/src/codec/composite/Map.luau +0 -485
- package/src/codec/composite/Optional.luau +0 -54
- package/src/codec/composite/Shared.luau +0 -311
- package/src/codec/composite/Struct.luau +0 -494
- package/src/codec/composite/Tagged.luau +0 -103
- package/src/codec/composite/Tuple.luau +0 -143
- package/src/codec/datatype/Buffer.luau +0 -66
- package/src/codec/datatype/CFrame.luau +0 -109
- package/src/codec/datatype/Color.luau +0 -32
- package/src/codec/datatype/Instance.luau +0 -52
- package/src/codec/datatype/IntVector.luau +0 -39
- package/src/codec/datatype/NumberRange.luau +0 -39
- package/src/codec/datatype/Ray.luau +0 -36
- package/src/codec/datatype/Rect.luau +0 -31
- package/src/codec/datatype/Region.luau +0 -62
- package/src/codec/datatype/Sequence.luau +0 -184
- package/src/codec/datatype/String.luau +0 -94
- package/src/codec/datatype/UDim.luau +0 -46
- package/src/codec/datatype/Vector.luau +0 -130
- package/src/codec/meta/Auto.luau +0 -318
- package/src/codec/meta/Bitfield.luau +0 -160
- package/src/codec/meta/Custom.luau +0 -33
- package/src/codec/meta/DeltaScalar.luau +0 -390
- package/src/codec/meta/Enum.luau +0 -50
- package/src/codec/meta/Float.luau +0 -38
- package/src/codec/meta/Nothing.luau +0 -13
- package/src/codec/meta/Unknown.luau +0 -41
- package/src/codec/primitive/Bool.luau +0 -26
- package/src/codec/primitive/Float16.luau +0 -99
- package/src/codec/primitive/Int.luau +0 -59
- package/src/codec/primitive/Number.luau +0 -24
- package/src/codec/primitive/Signed.luau +0 -32
- package/src/codec/primitive/Varint.luau +0 -165
- package/src/codec/primitive/Zint.luau +0 -99
- package/src/index.d.ts +0 -423
- package/src/init.luau +0 -362
- package/src/internal/Baseline.luau +0 -57
- package/src/internal/Channel.luau +0 -484
- package/src/internal/Middleware.luau +0 -100
- package/src/internal/Pool.luau +0 -66
- package/src/internal/Registry.luau +0 -119
- package/src/internal/Transport.luau +0 -28
- package/src/transport/Bridge.luau +0 -110
- package/src/transport/Client.luau +0 -97
- package/src/transport/Gate.luau +0 -488
- package/src/transport/Reader.luau +0 -331
- package/src/transport/Server.luau +0 -233
- package/src/util/Array.luau +0 -18
- package/src/util/Buffer.luau +0 -90
- package/src/util/Constants.luau +0 -30
- package/src/util/Log.luau +0 -68
- package/src/util/Player.luau +0 -14
- package/src/util/Quantize.luau +0 -84
- package/src/util/Quat.luau +0 -124
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
--!strict
|
|
2
|
-
--!optimize 2
|
|
3
|
-
-- Sequential 7-bit packet/query ID assignment.
|
|
4
|
-
|
|
5
|
-
local Log = require(script.Parent.Parent.util.Log)
|
|
6
|
-
local Signal = require(script.Parent.Parent.api.Signal)
|
|
7
|
-
local Types = require(script.Parent.Parent.Types)
|
|
8
|
-
|
|
9
|
-
-- Constants --------------------------------------------------------------
|
|
10
|
-
|
|
11
|
-
local KIND_PACKET = 0
|
|
12
|
-
local KIND_REQUEST = 1
|
|
13
|
-
local KIND_RESPONSE = 2
|
|
14
|
-
|
|
15
|
-
-- 7-bit id leaves the MSB free for the frame single/multi flag (see Constants.FRAME_MSB).
|
|
16
|
-
local MAX_ID = 127
|
|
17
|
-
|
|
18
|
-
-- State ------------------------------------------------------------------
|
|
19
|
-
|
|
20
|
-
local _nextId = 0
|
|
21
|
-
local _registrationsById: { [number]: Types.Registration } = {}
|
|
22
|
-
local _registrationsByName: { [string]: Types.Registration } = {}
|
|
23
|
-
|
|
24
|
-
-- Public -----------------------------------------------------------------
|
|
25
|
-
|
|
26
|
-
local Registry = {}
|
|
27
|
-
|
|
28
|
-
Registry.KIND_PACKET = KIND_PACKET
|
|
29
|
-
Registry.KIND_REQUEST = KIND_REQUEST
|
|
30
|
-
Registry.KIND_RESPONSE = KIND_RESPONSE
|
|
31
|
-
Registry.MAX_ID = MAX_ID
|
|
32
|
-
|
|
33
|
-
export type RegisterOptions = {
|
|
34
|
-
name: string,
|
|
35
|
-
kind: number,
|
|
36
|
-
codec: Types.InternalCodec<any>,
|
|
37
|
-
isUnreliable: boolean,
|
|
38
|
-
partner: number?,
|
|
39
|
-
needsGate: boolean,
|
|
40
|
-
headerSize: number,
|
|
41
|
-
timestampMode: number,
|
|
42
|
-
openFn: (ch: Types.ChannelState, id: number) -> (),
|
|
43
|
-
rateLimit: Types.RateLimitConfig?,
|
|
44
|
-
validate: Types.ValidateFn?,
|
|
45
|
-
maxPayloadBytes: number?,
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
function Registry.register(opts: RegisterOptions): Types.Registration
|
|
49
|
-
local nextCandidate = _nextId + 1
|
|
50
|
-
if nextCandidate > MAX_ID then
|
|
51
|
-
Log.error(`ID limit ({MAX_ID}) exceeded; cannot register "{opts.name}"`)
|
|
52
|
-
end
|
|
53
|
-
--[[
|
|
54
|
-
RESPONSE entries share their request's name with a "\0resp" suffix; only
|
|
55
|
-
request/packet names need uniqueness in the by-name index.
|
|
56
|
-
]]
|
|
57
|
-
if opts.kind ~= KIND_RESPONSE and _registrationsByName[opts.name] ~= nil then
|
|
58
|
-
Log.error(`duplicate name "{opts.name}"`)
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
_nextId = nextCandidate
|
|
62
|
-
|
|
63
|
-
local reg: Types.Registration = {
|
|
64
|
-
id = nextCandidate,
|
|
65
|
-
name = opts.name,
|
|
66
|
-
kind = opts.kind,
|
|
67
|
-
codec = opts.codec,
|
|
68
|
-
isUnreliable = opts.isUnreliable,
|
|
69
|
-
partner = opts.partner,
|
|
70
|
-
signal = Signal.create(),
|
|
71
|
-
rateLimit = opts.rateLimit,
|
|
72
|
-
validate = opts.validate,
|
|
73
|
-
needsGate = opts.needsGate,
|
|
74
|
-
maxPayloadBytes = opts.maxPayloadBytes,
|
|
75
|
-
timestampMode = opts.timestampMode,
|
|
76
|
-
headerSize = opts.headerSize,
|
|
77
|
-
_openFn = opts.openFn,
|
|
78
|
-
bytesSent = 0,
|
|
79
|
-
bytesReceived = 0,
|
|
80
|
-
fires = 0,
|
|
81
|
-
recvFires = 0,
|
|
82
|
-
drops = 0,
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
_registrationsById[nextCandidate] = reg
|
|
86
|
-
if opts.kind ~= KIND_RESPONSE then
|
|
87
|
-
_registrationsByName[opts.name] = reg
|
|
88
|
-
end
|
|
89
|
-
return reg
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
function Registry.get(id: number): Types.Registration?
|
|
93
|
-
return _registrationsById[id]
|
|
94
|
-
end
|
|
95
|
-
|
|
96
|
-
function Registry.getByName(name: string): Types.Registration?
|
|
97
|
-
return _registrationsByName[name]
|
|
98
|
-
end
|
|
99
|
-
|
|
100
|
-
function Registry.count(): number
|
|
101
|
-
return _nextId
|
|
102
|
-
end
|
|
103
|
-
|
|
104
|
-
-- IDs are sequential and never freed, so the table has no holes.
|
|
105
|
-
function Registry.all(): { Types.Registration }
|
|
106
|
-
local result = table.create(_nextId)
|
|
107
|
-
for i = 1, _nextId do
|
|
108
|
-
result[i] = _registrationsById[i]
|
|
109
|
-
end
|
|
110
|
-
return result
|
|
111
|
-
end
|
|
112
|
-
|
|
113
|
-
function Registry.reset(): ()
|
|
114
|
-
table.clear(_registrationsById)
|
|
115
|
-
table.clear(_registrationsByName)
|
|
116
|
-
_nextId = 0
|
|
117
|
-
end
|
|
118
|
-
|
|
119
|
-
return table.freeze(Registry)
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
--!strict
|
|
2
|
-
--!optimize 2
|
|
3
|
-
-- Lazy Server/Client require to break the api -> transport import cycle.
|
|
4
|
-
|
|
5
|
-
-- State ------------------------------------------------------------------
|
|
6
|
-
|
|
7
|
-
local _server: any = nil
|
|
8
|
-
local _client: any = nil
|
|
9
|
-
|
|
10
|
-
-- Public -----------------------------------------------------------------
|
|
11
|
-
|
|
12
|
-
local Transport = {}
|
|
13
|
-
|
|
14
|
-
function Transport.server(): any
|
|
15
|
-
if not _server then
|
|
16
|
-
_server = require(script.Parent.Parent.transport.Server)
|
|
17
|
-
end
|
|
18
|
-
return _server
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
function Transport.client(): any
|
|
22
|
-
if not _client then
|
|
23
|
-
_client = require(script.Parent.Parent.transport.Client)
|
|
24
|
-
end
|
|
25
|
-
return _client
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
return table.freeze(Transport)
|
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
--!strict
|
|
2
|
-
--!optimize 2
|
|
3
|
-
-- RemoteEvent / UnreliableRemoteEvent wrapper.
|
|
4
|
-
|
|
5
|
-
local RunService = game:GetService("RunService")
|
|
6
|
-
|
|
7
|
-
local Log = require(script.Parent.Parent.util.Log)
|
|
8
|
-
|
|
9
|
-
-- Constants --------------------------------------------------------------
|
|
10
|
-
|
|
11
|
-
local RELIABLE_NAME = "LyncReliable"
|
|
12
|
-
local UNRELIABLE_NAME = "LyncUnreliable"
|
|
13
|
-
|
|
14
|
-
-- State ------------------------------------------------------------------
|
|
15
|
-
|
|
16
|
-
local _reliable: RemoteEvent? = nil
|
|
17
|
-
local _unreliable: UnreliableRemoteEvent? = nil
|
|
18
|
-
local _isServer = RunService:IsServer()
|
|
19
|
-
|
|
20
|
-
-- Private ----------------------------------------------------------------
|
|
21
|
-
|
|
22
|
-
--[[
|
|
23
|
-
Captured to a local first so Log.error's `never` return narrows the
|
|
24
|
-
optional. Reading the module global directly wouldn't narrow.
|
|
25
|
-
]]
|
|
26
|
-
local function ensureReliable(): RemoteEvent
|
|
27
|
-
local r = _reliable
|
|
28
|
-
if not r then
|
|
29
|
-
Log.error("not set up; call Lync.start() first")
|
|
30
|
-
end
|
|
31
|
-
return r
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
local function ensureUnreliable(): UnreliableRemoteEvent
|
|
35
|
-
local u = _unreliable
|
|
36
|
-
if not u then
|
|
37
|
-
Log.error("not set up; call Lync.start() first")
|
|
38
|
-
end
|
|
39
|
-
return u
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
-- Drop the trailing arg when refs is empty: Roblox serializes empty tables as several wire bytes.
|
|
43
|
-
local function fireToServer(re: any, data: buffer, refs: { Instance }): ()
|
|
44
|
-
if #refs > 0 then
|
|
45
|
-
re:FireServer(data, refs)
|
|
46
|
-
else
|
|
47
|
-
re:FireServer(data)
|
|
48
|
-
end
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
local function fireToClient(re: any, player: Player, data: buffer, refs: { Instance }): ()
|
|
52
|
-
if #refs > 0 then
|
|
53
|
-
re:FireClient(player, data, refs)
|
|
54
|
-
else
|
|
55
|
-
re:FireClient(player, data)
|
|
56
|
-
end
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
-- Public -----------------------------------------------------------------
|
|
60
|
-
|
|
61
|
-
local Bridge = {}
|
|
62
|
-
|
|
63
|
-
function Bridge.setup(container: Instance): ()
|
|
64
|
-
if _isServer then
|
|
65
|
-
local re = Instance.new("RemoteEvent")
|
|
66
|
-
re.Name = RELIABLE_NAME
|
|
67
|
-
re.Parent = container
|
|
68
|
-
|
|
69
|
-
local ure = Instance.new("UnreliableRemoteEvent")
|
|
70
|
-
ure.Name = UNRELIABLE_NAME
|
|
71
|
-
ure.Parent = container
|
|
72
|
-
|
|
73
|
-
_reliable, _unreliable = re, ure
|
|
74
|
-
return
|
|
75
|
-
end
|
|
76
|
-
_reliable = container:WaitForChild(RELIABLE_NAME) :: RemoteEvent
|
|
77
|
-
_unreliable = container:WaitForChild(UNRELIABLE_NAME) :: UnreliableRemoteEvent
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
Bridge.reliable = ensureReliable
|
|
81
|
-
Bridge.unreliable = ensureUnreliable
|
|
82
|
-
|
|
83
|
-
function Bridge.fireServer(data: buffer, refs: { Instance }): ()
|
|
84
|
-
fireToServer(ensureReliable(), data, refs)
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
function Bridge.fireClient(player: Player, data: buffer, refs: { Instance }): ()
|
|
88
|
-
fireToClient(ensureReliable(), player, data, refs)
|
|
89
|
-
end
|
|
90
|
-
|
|
91
|
-
function Bridge.fireServerUnreliable(data: buffer, refs: { Instance }): ()
|
|
92
|
-
fireToServer(ensureUnreliable(), data, refs)
|
|
93
|
-
end
|
|
94
|
-
|
|
95
|
-
function Bridge.fireClientUnreliable(player: Player, data: buffer, refs: { Instance }): ()
|
|
96
|
-
fireToClient(ensureUnreliable(), player, data, refs)
|
|
97
|
-
end
|
|
98
|
-
|
|
99
|
-
-- Test injection point: harnesses substitute fake remotes.
|
|
100
|
-
function Bridge.attach(reliable: any, unreliable: any): ()
|
|
101
|
-
_reliable = reliable
|
|
102
|
-
_unreliable = unreliable
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
function Bridge.reset(): ()
|
|
106
|
-
_reliable = nil
|
|
107
|
-
_unreliable = nil
|
|
108
|
-
end
|
|
109
|
-
|
|
110
|
-
return table.freeze(Bridge)
|
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
--!strict
|
|
2
|
-
--!optimize 2
|
|
3
|
-
-- Client transport: single channel pair with outbound XOR delta.
|
|
4
|
-
|
|
5
|
-
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
|
6
|
-
|
|
7
|
-
local Bridge = require(script.Parent.Parent.transport.Bridge)
|
|
8
|
-
local Channel = require(script.Parent.Parent.internal.Channel)
|
|
9
|
-
local Reader = require(script.Parent.Parent.transport.Reader)
|
|
10
|
-
local Types = require(script.Parent.Parent.Types)
|
|
11
|
-
|
|
12
|
-
-- Constants --------------------------------------------------------------
|
|
13
|
-
|
|
14
|
-
local CONTAINER_NAME = "LyncRemotes"
|
|
15
|
-
|
|
16
|
-
-- State ------------------------------------------------------------------
|
|
17
|
-
|
|
18
|
-
local _reliable: Types.ChannelState = Channel.create()
|
|
19
|
-
local _unreliable: Types.ChannelState = Channel.create()
|
|
20
|
-
local _prevIncoming: buffer? = nil
|
|
21
|
-
local _prevIncomingLen: number = 0
|
|
22
|
-
|
|
23
|
-
-- Private ----------------------------------------------------------------
|
|
24
|
-
|
|
25
|
-
local xorApply = Channel.xorApply
|
|
26
|
-
local sealAndDump = Channel.sealAndDump
|
|
27
|
-
local resetCh = Channel.reset
|
|
28
|
-
|
|
29
|
-
local function handleIncomingReliable(data: any, refs: any?): ()
|
|
30
|
-
local incoming = Reader.decodeIncoming(data)
|
|
31
|
-
if not incoming then
|
|
32
|
-
return
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
local incomingLen = buffer.len(incoming)
|
|
36
|
-
local decoded = xorApply(incoming, incomingLen, _prevIncoming, _prevIncomingLen)
|
|
37
|
-
|
|
38
|
-
--[[
|
|
39
|
-
Mirror Server: only adopt `decoded` as the next baseline on success.
|
|
40
|
-
A failed parse means the wire is suspect; reusing it would poison
|
|
41
|
-
every subsequent packet.
|
|
42
|
-
]]
|
|
43
|
-
if Reader.process(decoded, incomingLen, refs, nil, false) then
|
|
44
|
-
_prevIncoming = decoded
|
|
45
|
-
_prevIncomingLen = incomingLen
|
|
46
|
-
else
|
|
47
|
-
_prevIncoming = nil
|
|
48
|
-
_prevIncomingLen = 0
|
|
49
|
-
end
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
local function handleIncomingUnreliable(data: any, refs: any?): ()
|
|
53
|
-
local incoming = Reader.decodeIncoming(data)
|
|
54
|
-
if not incoming then
|
|
55
|
-
return
|
|
56
|
-
end
|
|
57
|
-
Reader.process(incoming, buffer.len(incoming), refs, nil, false)
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
-- Public -----------------------------------------------------------------
|
|
61
|
-
|
|
62
|
-
local Client = {}
|
|
63
|
-
|
|
64
|
-
function Client.getChannel(isUnreliable: boolean): Types.ChannelState
|
|
65
|
-
return if isUnreliable then _unreliable else _reliable
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
function Client.flush(): ()
|
|
69
|
-
if Channel.hasTimestamps() then
|
|
70
|
-
Channel.updateTimestamp()
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
if _reliable.cursor > 0 then
|
|
74
|
-
local snapshot, refs, byteLen = sealAndDump(_reliable)
|
|
75
|
-
local xored = xorApply(snapshot, byteLen, _reliable.prevDump, _reliable.prevDumpLen)
|
|
76
|
-
_reliable.prevDump = snapshot
|
|
77
|
-
_reliable.prevDumpLen = byteLen
|
|
78
|
-
Bridge.fireServer(xored, refs)
|
|
79
|
-
resetCh(_reliable)
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
if _unreliable.cursor > 0 then
|
|
83
|
-
local snapshot, refs = sealAndDump(_unreliable)
|
|
84
|
-
Bridge.fireServerUnreliable(snapshot, refs)
|
|
85
|
-
resetCh(_unreliable)
|
|
86
|
-
end
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
function Client.start(): ()
|
|
90
|
-
local container = ReplicatedStorage:WaitForChild(CONTAINER_NAME)
|
|
91
|
-
Bridge.setup(container)
|
|
92
|
-
|
|
93
|
-
Bridge.reliable().OnClientEvent:Connect(handleIncomingReliable)
|
|
94
|
-
Bridge.unreliable().OnClientEvent:Connect(handleIncomingUnreliable)
|
|
95
|
-
end
|
|
96
|
-
|
|
97
|
-
return table.freeze(Client)
|