@axpecter/lync 2.1.2 → 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.
- package/README.md +241 -349
- package/package.json +1 -1
- package/src/Types.luau +53 -13
- package/src/api/Group.luau +41 -51
- package/src/api/Packet.luau +145 -143
- package/src/api/Query.luau +204 -202
- package/src/api/Scope.luau +36 -38
- package/src/api/Signal.luau +68 -94
- package/src/codec/Base.luau +43 -23
- package/src/codec/composite/Array.luau +161 -152
- package/src/codec/composite/Map.luau +37 -53
- package/src/codec/composite/Optional.luau +15 -21
- package/src/codec/composite/Shared.luau +78 -41
- package/src/codec/composite/Struct.luau +64 -125
- package/src/codec/composite/Tagged.luau +15 -25
- package/src/codec/composite/Tuple.luau +15 -20
- package/src/codec/datatype/Buffer.luau +44 -51
- package/src/codec/datatype/CFrame.luau +72 -104
- package/src/codec/datatype/Color.luau +14 -10
- package/src/codec/datatype/Instance.luau +32 -42
- package/src/codec/datatype/IntVector.luau +24 -22
- package/src/codec/datatype/NumberRange.luau +21 -12
- package/src/codec/datatype/Ray.luau +13 -7
- package/src/codec/datatype/Rect.luau +13 -7
- package/src/codec/datatype/Region.luau +25 -22
- package/src/codec/datatype/Sequence.luau +144 -118
- package/src/codec/datatype/String.luau +29 -59
- package/src/codec/datatype/UDim.luau +29 -30
- package/src/codec/datatype/Vector.luau +89 -105
- package/src/codec/meta/Auto.luau +194 -246
- package/src/codec/meta/Bitfield.luau +37 -36
- package/src/codec/meta/Custom.luau +10 -10
- package/src/codec/meta/Enum.luau +8 -11
- package/src/codec/meta/Float.luau +16 -20
- package/src/codec/meta/Nothing.luau +2 -2
- package/src/codec/meta/Unknown.luau +22 -32
- package/src/codec/primitive/Bool.luau +9 -5
- package/src/codec/primitive/Float16.luau +13 -23
- package/src/codec/primitive/Int.luau +20 -28
- package/src/codec/primitive/Number.luau +6 -10
- package/src/codec/primitive/Signed.luau +32 -0
- package/src/codec/primitive/Varint.luau +59 -28
- package/src/index.d.ts +8 -2
- package/src/init.luau +118 -143
- package/src/internal/Baseline.luau +17 -18
- package/src/internal/Channel.luau +143 -212
- package/src/internal/Middleware.luau +37 -47
- package/src/internal/Pool.luau +10 -10
- package/src/internal/Registry.luau +38 -34
- package/src/internal/Transport.luau +28 -0
- package/src/internal/Util.luau +26 -0
- package/src/transport/Bridge.luau +32 -24
- package/src/transport/Client.luau +51 -53
- package/src/transport/Gate.luau +183 -113
- package/src/transport/Reader.luau +95 -66
- package/src/transport/Server.luau +130 -125
package/package.json
CHANGED
package/src/Types.luau
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
--!strict
|
|
2
|
-
--!optimize 2
|
|
3
2
|
-- Shared type definitions for the Lync networking library.
|
|
4
3
|
|
|
5
4
|
export type ChannelState = {
|
|
@@ -13,17 +12,27 @@ export type ChannelState = {
|
|
|
13
12
|
itemCount: number,
|
|
14
13
|
singleMode: boolean,
|
|
15
14
|
singlePos: number,
|
|
16
|
-
deltas: { [number]:
|
|
15
|
+
deltas: { [number]: DeltaCacheEntry },
|
|
17
16
|
prevDump: buffer?,
|
|
18
17
|
prevDumpLen: number,
|
|
19
18
|
currentPacket: string?,
|
|
20
19
|
}
|
|
21
20
|
|
|
21
|
+
export type DeltaCacheEntry = {
|
|
22
|
+
raw: buffer,
|
|
23
|
+
len: number,
|
|
24
|
+
}
|
|
25
|
+
|
|
22
26
|
export type Codec<T> = {
|
|
23
27
|
write: (ch: ChannelState, value: T) -> (),
|
|
24
28
|
read: (src: buffer, pos: number, refs: { Instance }?) -> (T, number),
|
|
25
29
|
}
|
|
26
30
|
|
|
31
|
+
--[[
|
|
32
|
+
InternalCodec carries optional metadata used by Gate (validation),
|
|
33
|
+
Reader (max-item bound), Auto (type dispatch), and composite codecs
|
|
34
|
+
(direct write/read fast path).
|
|
35
|
+
]]
|
|
27
36
|
export type InternalCodec<T> = {
|
|
28
37
|
write: (ch: ChannelState, value: T) -> (),
|
|
29
38
|
read: (src: buffer, pos: number, refs: { Instance }?) -> (T, number),
|
|
@@ -38,6 +47,25 @@ export type InternalCodec<T> = {
|
|
|
38
47
|
_isInteger: boolean?,
|
|
39
48
|
_schema: { [string]: InternalCodec<any> }?,
|
|
40
49
|
_typeCheck: string?,
|
|
50
|
+
--[[
|
|
51
|
+
Composite-codec metadata. Gate uses these to recurse element /
|
|
52
|
+
variant validation rather than fall through to a generic NaN scan.
|
|
53
|
+
]]
|
|
54
|
+
_isOptional: boolean?,
|
|
55
|
+
_inner: InternalCodec<any>?,
|
|
56
|
+
_isTagged: boolean?,
|
|
57
|
+
_variants: { [string]: InternalCodec<any> }?,
|
|
58
|
+
_tagField: string?,
|
|
59
|
+
_isArray: boolean?,
|
|
60
|
+
_element: InternalCodec<any>?,
|
|
61
|
+
_maxCount: number?,
|
|
62
|
+
_isMap: boolean?,
|
|
63
|
+
_keyCodec: InternalCodec<any>?,
|
|
64
|
+
_valueCodec: InternalCodec<any>?,
|
|
65
|
+
_isTuple: boolean?,
|
|
66
|
+
_elements: { InternalCodec<any> }?,
|
|
67
|
+
_isEnum: boolean?,
|
|
68
|
+
_enumValues: { [string]: number }?,
|
|
41
69
|
}
|
|
42
70
|
|
|
43
71
|
export type RateLimitState = {
|
|
@@ -46,24 +74,30 @@ export type RateLimitState = {
|
|
|
46
74
|
lastAccepted: number,
|
|
47
75
|
}
|
|
48
76
|
|
|
77
|
+
--[[
|
|
78
|
+
Token-bucket (maxPerSecond + optional burst) or cooldown (cooldown
|
|
79
|
+
seconds between accepts). Mixing both forms is undefined.
|
|
80
|
+
]]
|
|
49
81
|
export type RateLimitConfig = {
|
|
50
82
|
maxPerSecond: number?,
|
|
51
83
|
burst: number?,
|
|
52
84
|
cooldown: number?,
|
|
53
85
|
}
|
|
54
86
|
|
|
87
|
+
export type ValidateFn = (data: any, player: Player) -> (boolean, string?)
|
|
88
|
+
|
|
55
89
|
export type PacketOptions = {
|
|
56
90
|
unreliable: boolean?,
|
|
57
91
|
rateLimit: RateLimitConfig?,
|
|
58
|
-
validate:
|
|
92
|
+
validate: ValidateFn?,
|
|
59
93
|
maxPayloadBytes: number?,
|
|
60
|
-
timestamp:
|
|
94
|
+
timestamp: ("frame" | "offset" | "full")?,
|
|
61
95
|
}
|
|
62
96
|
|
|
63
97
|
export type QueryOptions = {
|
|
64
98
|
timeout: number?,
|
|
65
99
|
rateLimit: RateLimitConfig?,
|
|
66
|
-
validate:
|
|
100
|
+
validate: ValidateFn?,
|
|
67
101
|
}
|
|
68
102
|
|
|
69
103
|
export type Registration = {
|
|
@@ -75,7 +109,7 @@ export type Registration = {
|
|
|
75
109
|
partner: number?,
|
|
76
110
|
signal: SignalLike,
|
|
77
111
|
rateLimit: RateLimitConfig?,
|
|
78
|
-
validate:
|
|
112
|
+
validate: ValidateFn?,
|
|
79
113
|
needsGate: boolean,
|
|
80
114
|
maxPayloadBytes: number?,
|
|
81
115
|
timestampMode: number,
|
|
@@ -90,7 +124,12 @@ export type Registration = {
|
|
|
90
124
|
|
|
91
125
|
export type SignalLike = {
|
|
92
126
|
fire: (self: SignalLike, ...any) -> (),
|
|
127
|
+
fireSync: (self: SignalLike, ...any) -> (),
|
|
93
128
|
connect: (self: SignalLike, callback: (...any) -> ()) -> Connection,
|
|
129
|
+
once: (self: SignalLike, callback: (...any) -> ()) -> Connection,
|
|
130
|
+
wait: (self: SignalLike) -> ...any,
|
|
131
|
+
count: (self: SignalLike) -> number,
|
|
132
|
+
hasListeners: (self: SignalLike) -> boolean,
|
|
94
133
|
}
|
|
95
134
|
|
|
96
135
|
export type Connection = {
|
|
@@ -102,13 +141,8 @@ export type ConfigureOptions = {
|
|
|
102
141
|
channelMaxSize: number?,
|
|
103
142
|
validationDepth: number?,
|
|
104
143
|
poolSize: number?,
|
|
105
|
-
bandwidthLimit: {
|
|
106
|
-
|
|
107
|
-
maxStrikes: number,
|
|
108
|
-
}?,
|
|
109
|
-
globalRateLimit: {
|
|
110
|
-
maxPerSecond: number,
|
|
111
|
-
}?,
|
|
144
|
+
bandwidthLimit: { softLimit: number, maxStrikes: number }?,
|
|
145
|
+
globalRateLimit: { maxPerSecond: number }?,
|
|
112
146
|
stats: boolean?,
|
|
113
147
|
}
|
|
114
148
|
|
|
@@ -125,4 +159,10 @@ export type PlayerStats = {
|
|
|
125
159
|
bytesReceived: number,
|
|
126
160
|
}
|
|
127
161
|
|
|
162
|
+
--[[
|
|
163
|
+
Server keys baselines per Player; client uses `false` since booleans
|
|
164
|
+
are valid table keys but Players never collide with that.
|
|
165
|
+
]]
|
|
166
|
+
export type BaselineKey = Player | false
|
|
167
|
+
|
|
128
168
|
return nil
|
package/src/api/Group.luau
CHANGED
|
@@ -4,15 +4,31 @@
|
|
|
4
4
|
|
|
5
5
|
local Players = game:GetService("Players")
|
|
6
6
|
|
|
7
|
-
local
|
|
7
|
+
local Util = require(script.Parent.Parent.internal.Util)
|
|
8
8
|
|
|
9
|
-
--
|
|
9
|
+
-- Public types -----------------------------------------------------------
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
export type GroupHandle = {
|
|
12
|
+
add: (self: GroupHandle, player: Player) -> boolean,
|
|
13
|
+
remove: (self: GroupHandle, player: Player) -> boolean,
|
|
14
|
+
has: (self: GroupHandle, player: Player) -> boolean,
|
|
15
|
+
count: (self: GroupHandle) -> number,
|
|
16
|
+
destroy: (self: GroupHandle) -> (),
|
|
17
|
+
_lyncGroup: boolean,
|
|
18
|
+
_members: { [Player]: boolean },
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
type Group = GroupHandle & { _count: number, _name: string }
|
|
22
|
+
|
|
23
|
+
-- State ------------------------------------------------------------------
|
|
24
|
+
|
|
25
|
+
local _groups: { [string]: Group } = {}
|
|
26
|
+
local _playerCleanup: { [Player]: { Group } } = {}
|
|
13
27
|
local _cleanupConnected = false
|
|
14
28
|
|
|
15
|
-
-- Private
|
|
29
|
+
-- Private ----------------------------------------------------------------
|
|
30
|
+
|
|
31
|
+
local swapRemove = Util.swapRemove
|
|
16
32
|
|
|
17
33
|
local function ensureCleanup(): ()
|
|
18
34
|
if _cleanupConnected then
|
|
@@ -25,48 +41,30 @@ local function ensureCleanup(): ()
|
|
|
25
41
|
if not groups then
|
|
26
42
|
return
|
|
27
43
|
end
|
|
28
|
-
|
|
29
44
|
for _, group in groups do
|
|
30
45
|
group._members[player] = nil
|
|
31
46
|
group._count -= 1
|
|
32
47
|
end
|
|
33
|
-
|
|
34
48
|
_playerCleanup[player] = nil
|
|
35
49
|
end)
|
|
36
50
|
end
|
|
37
51
|
|
|
38
|
-
-- Public
|
|
52
|
+
-- Public -----------------------------------------------------------------
|
|
39
53
|
|
|
40
54
|
local Group = {}
|
|
41
55
|
|
|
42
|
-
export type GroupHandle = {
|
|
43
|
-
add: (self: GroupHandle, player: Player) -> boolean,
|
|
44
|
-
remove: (self: GroupHandle, player: Player) -> boolean,
|
|
45
|
-
has: (self: GroupHandle, player: Player) -> boolean,
|
|
46
|
-
count: (self: GroupHandle) -> number,
|
|
47
|
-
destroy: (self: GroupHandle) -> (),
|
|
48
|
-
_lyncGroup: boolean,
|
|
49
|
-
_members: { [Player]: boolean },
|
|
50
|
-
}
|
|
51
|
-
|
|
52
56
|
local GroupMeta = {}
|
|
53
57
|
GroupMeta.__index = GroupMeta
|
|
54
58
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
key = nextKey
|
|
62
|
-
if nextKey then
|
|
63
|
-
return nextKey, nextVal
|
|
64
|
-
end
|
|
65
|
-
return nil, nil
|
|
66
|
-
end
|
|
59
|
+
--[[
|
|
60
|
+
__iter returns the standard 3-tuple iterator so `for player in group do`
|
|
61
|
+
uses Luau's builtin path (luaH_next) with zero closure allocation.
|
|
62
|
+
]]
|
|
63
|
+
function GroupMeta.__iter(self: Group): (any, any, any)
|
|
64
|
+
return next, self._members, nil
|
|
67
65
|
end
|
|
68
66
|
|
|
69
|
-
function GroupMeta.add(self:
|
|
67
|
+
function GroupMeta.add(self: Group, player: Player): boolean
|
|
70
68
|
if self._members[player] then
|
|
71
69
|
return false
|
|
72
70
|
end
|
|
@@ -74,18 +72,16 @@ function GroupMeta.add(self: any, player: Player): boolean
|
|
|
74
72
|
self._members[player] = true
|
|
75
73
|
self._count += 1
|
|
76
74
|
|
|
77
|
-
-- Track for auto-cleanup
|
|
78
75
|
local cleanup = _playerCleanup[player]
|
|
79
76
|
if not cleanup then
|
|
80
77
|
cleanup = {}
|
|
81
78
|
_playerCleanup[player] = cleanup
|
|
82
79
|
end
|
|
83
80
|
table.insert(cleanup, self)
|
|
84
|
-
|
|
85
81
|
return true
|
|
86
82
|
end
|
|
87
83
|
|
|
88
|
-
function GroupMeta.remove(self:
|
|
84
|
+
function GroupMeta.remove(self: Group, player: Player): boolean
|
|
89
85
|
if not self._members[player] then
|
|
90
86
|
return false
|
|
91
87
|
end
|
|
@@ -93,43 +89,35 @@ function GroupMeta.remove(self: any, player: Player): boolean
|
|
|
93
89
|
self._members[player] = nil
|
|
94
90
|
self._count -= 1
|
|
95
91
|
|
|
96
|
-
-- Remove from cleanup tracking
|
|
97
92
|
local cleanup = _playerCleanup[player]
|
|
98
93
|
if cleanup then
|
|
99
94
|
local idx = table.find(cleanup, self)
|
|
100
95
|
if idx then
|
|
101
|
-
|
|
102
|
-
cleanup[idx] = cleanup[last]
|
|
103
|
-
cleanup[last] = nil
|
|
96
|
+
swapRemove(cleanup, idx)
|
|
104
97
|
end
|
|
105
98
|
end
|
|
106
|
-
|
|
107
99
|
return true
|
|
108
100
|
end
|
|
109
101
|
|
|
110
|
-
function GroupMeta.has(self:
|
|
102
|
+
function GroupMeta.has(self: Group, player: Player): boolean
|
|
111
103
|
return self._members[player] == true
|
|
112
104
|
end
|
|
113
105
|
|
|
114
|
-
function GroupMeta.count(self:
|
|
106
|
+
function GroupMeta.count(self: Group): number
|
|
115
107
|
return self._count
|
|
116
108
|
end
|
|
117
109
|
|
|
118
|
-
function GroupMeta.destroy(self:
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
_groups[name] = nil
|
|
110
|
+
function GroupMeta.destroy(self: Group): ()
|
|
111
|
+
if _groups[self._name] == self then
|
|
112
|
+
_groups[self._name] = nil
|
|
122
113
|
end
|
|
123
114
|
|
|
124
|
-
-- Remove all members from cleanup tracking
|
|
125
115
|
for player in self._members do
|
|
126
116
|
local cleanup = _playerCleanup[player]
|
|
127
117
|
if cleanup then
|
|
128
118
|
local idx = table.find(cleanup, self)
|
|
129
119
|
if idx then
|
|
130
|
-
|
|
131
|
-
cleanup[idx] = cleanup[last]
|
|
132
|
-
cleanup[last] = nil
|
|
120
|
+
swapRemove(cleanup, idx)
|
|
133
121
|
end
|
|
134
122
|
end
|
|
135
123
|
end
|
|
@@ -138,6 +126,8 @@ function GroupMeta.destroy(self: any): ()
|
|
|
138
126
|
self._count = 0
|
|
139
127
|
end
|
|
140
128
|
|
|
129
|
+
table.freeze(GroupMeta)
|
|
130
|
+
|
|
141
131
|
function Group.create(name: string): GroupHandle
|
|
142
132
|
if _groups[name] then
|
|
143
133
|
error(`[Lync] Lync.group: "{name}" already exists`)
|
|
@@ -150,10 +140,10 @@ function Group.create(name: string): GroupHandle
|
|
|
150
140
|
_members = {} :: { [Player]: boolean },
|
|
151
141
|
_count = 0,
|
|
152
142
|
_name = name,
|
|
153
|
-
}, GroupMeta)
|
|
143
|
+
}, GroupMeta) :: any
|
|
154
144
|
|
|
155
145
|
_groups[name] = group
|
|
156
|
-
return group
|
|
146
|
+
return group
|
|
157
147
|
end
|
|
158
148
|
|
|
159
149
|
return table.freeze(Group)
|