@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/package.json
CHANGED
package/src/Types.luau
CHANGED
|
@@ -7,11 +7,16 @@ export type ChannelState = {
|
|
|
7
7
|
cursor: number,
|
|
8
8
|
size: number,
|
|
9
9
|
refs: { Instance },
|
|
10
|
+
refCount: number,
|
|
10
11
|
lastId: number,
|
|
11
12
|
countPos: number,
|
|
12
13
|
itemCount: number,
|
|
13
|
-
|
|
14
|
+
singleMode: boolean,
|
|
15
|
+
singlePos: number,
|
|
16
|
+
deltas: { [number]: any },
|
|
14
17
|
prevDump: buffer?,
|
|
18
|
+
prevDumpLen: number,
|
|
19
|
+
currentPacket: string?,
|
|
15
20
|
}
|
|
16
21
|
|
|
17
22
|
export type Codec<T> = {
|
|
@@ -19,7 +24,6 @@ export type Codec<T> = {
|
|
|
19
24
|
read: (src: buffer, pos: number, refs: { Instance }?) -> (T, number),
|
|
20
25
|
}
|
|
21
26
|
|
|
22
|
-
-- Extended codec exposing internal fast-path metadata used by composite codecs.
|
|
23
27
|
export type InternalCodec<T> = {
|
|
24
28
|
write: (ch: ChannelState, value: T) -> (),
|
|
25
29
|
read: (src: buffer, pos: number, refs: { Instance }?) -> (T, number),
|
|
@@ -28,49 +32,46 @@ export type InternalCodec<T> = {
|
|
|
28
32
|
_directRead: ((b: buffer, offset: number) -> T)?,
|
|
29
33
|
_isDelta: boolean?,
|
|
30
34
|
_isBool: boolean?,
|
|
35
|
+
_hasUnknown: boolean?,
|
|
36
|
+
_min: number?,
|
|
37
|
+
_max: number?,
|
|
38
|
+
_isInteger: boolean?,
|
|
39
|
+
_schema: { [string]: InternalCodec<any> }?,
|
|
40
|
+
_typeCheck: string?,
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export type RateLimitState = {
|
|
44
|
+
tokens: number,
|
|
45
|
+
lastRefill: number,
|
|
46
|
+
lastAccepted: number,
|
|
31
47
|
}
|
|
32
48
|
|
|
33
49
|
export type RateLimitConfig = {
|
|
34
|
-
maxPerSecond: number
|
|
35
|
-
|
|
50
|
+
maxPerSecond: number?,
|
|
51
|
+
burst: number?,
|
|
52
|
+
cooldown: number?,
|
|
36
53
|
}
|
|
37
54
|
|
|
38
|
-
export type
|
|
39
|
-
value: Codec<T>,
|
|
55
|
+
export type PacketOptions = {
|
|
40
56
|
unreliable: boolean?,
|
|
41
57
|
rateLimit: RateLimitConfig?,
|
|
42
|
-
validate: ((data:
|
|
58
|
+
validate: ((data: any, player: Player) -> (boolean, string?))?,
|
|
43
59
|
maxPayloadBytes: number?,
|
|
44
|
-
timestamp:
|
|
60
|
+
timestamp: string?,
|
|
45
61
|
}
|
|
46
62
|
|
|
47
|
-
export type
|
|
48
|
-
request: Codec<Req>,
|
|
49
|
-
response: Codec<Resp>,
|
|
63
|
+
export type QueryOptions = {
|
|
50
64
|
timeout: number?,
|
|
51
65
|
rateLimit: RateLimitConfig?,
|
|
52
|
-
validate: ((data:
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
export type NamespaceConfig = {
|
|
56
|
-
packets: { [string]: PacketConfig<any> }?,
|
|
57
|
-
queries: { [string]: QueryConfig<any, any> }?,
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
-- Minimal signal interface for Registration. Avoids circular dependency
|
|
61
|
-
-- with Signal.luau while typing the two methods consumers actually call.
|
|
62
|
-
export type SignalLike = {
|
|
63
|
-
fire: (self: SignalLike, ...any) -> (),
|
|
64
|
-
connect: (self: SignalLike, callback: (...any) -> ()) -> Connection,
|
|
66
|
+
validate: ((data: any, player: Player) -> (boolean, string?))?,
|
|
65
67
|
}
|
|
66
68
|
|
|
67
69
|
export type Registration = {
|
|
68
70
|
id: number,
|
|
69
71
|
name: string,
|
|
70
|
-
baseName: string,
|
|
71
|
-
codec: Codec<any>,
|
|
72
|
-
isUnreliable: boolean,
|
|
73
72
|
kind: number,
|
|
73
|
+
codec: InternalCodec<any>,
|
|
74
|
+
isUnreliable: boolean,
|
|
74
75
|
partner: number?,
|
|
75
76
|
signal: SignalLike,
|
|
76
77
|
rateLimit: RateLimitConfig?,
|
|
@@ -78,9 +79,8 @@ export type Registration = {
|
|
|
78
79
|
needsGate: boolean,
|
|
79
80
|
maxPayloadBytes: number?,
|
|
80
81
|
timestampMode: number,
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
-- Stats counters (mutable, incremented at runtime)
|
|
82
|
+
headerSize: number,
|
|
83
|
+
_openFn: (ch: ChannelState, id: number) -> (),
|
|
84
84
|
bytesSent: number,
|
|
85
85
|
bytesReceived: number,
|
|
86
86
|
fires: number,
|
|
@@ -88,9 +88,41 @@ export type Registration = {
|
|
|
88
88
|
drops: number,
|
|
89
89
|
}
|
|
90
90
|
|
|
91
|
+
export type SignalLike = {
|
|
92
|
+
fire: (self: SignalLike, ...any) -> (),
|
|
93
|
+
connect: (self: SignalLike, callback: (...any) -> ()) -> Connection,
|
|
94
|
+
}
|
|
95
|
+
|
|
91
96
|
export type Connection = {
|
|
92
|
-
disconnect: (self: Connection) -> (),
|
|
93
97
|
connected: boolean,
|
|
98
|
+
disconnect: (self: Connection) -> (),
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export type ConfigureOptions = {
|
|
102
|
+
channelMaxSize: number?,
|
|
103
|
+
validationDepth: number?,
|
|
104
|
+
poolSize: number?,
|
|
105
|
+
bandwidthLimit: {
|
|
106
|
+
softLimit: number,
|
|
107
|
+
maxStrikes: number,
|
|
108
|
+
}?,
|
|
109
|
+
globalRateLimit: {
|
|
110
|
+
maxPerSecond: number,
|
|
111
|
+
}?,
|
|
112
|
+
stats: boolean?,
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export type PacketStats = {
|
|
116
|
+
bytesSent: number,
|
|
117
|
+
bytesReceived: number,
|
|
118
|
+
fires: number,
|
|
119
|
+
recvFires: number,
|
|
120
|
+
drops: number,
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export type PlayerStats = {
|
|
124
|
+
bytesSent: number,
|
|
125
|
+
bytesReceived: number,
|
|
94
126
|
}
|
|
95
127
|
|
|
96
128
|
return nil
|
package/src/api/Group.luau
CHANGED
|
@@ -1,164 +1,159 @@
|
|
|
1
1
|
--!strict
|
|
2
2
|
--!optimize 2
|
|
3
|
-
-- Named player sets with auto-cleanup on PlayerRemoving.
|
|
3
|
+
-- Named player sets with __iter, auto-cleanup on PlayerRemoving.
|
|
4
4
|
|
|
5
5
|
local Players = game:GetService("Players")
|
|
6
6
|
|
|
7
|
+
local Types = require(script.Parent.Parent.Types)
|
|
8
|
+
|
|
7
9
|
-- State ---------------------------------------------------------------
|
|
8
10
|
|
|
9
|
-
local _groups
|
|
10
|
-
local
|
|
11
|
-
local
|
|
11
|
+
local _groups: { [string]: any } = {}
|
|
12
|
+
local _playerCleanup: { [Player]: { any } } = {}
|
|
13
|
+
local _cleanupConnected = false
|
|
12
14
|
|
|
13
15
|
-- Private -------------------------------------------------------------
|
|
14
16
|
|
|
15
|
-
local function
|
|
16
|
-
|
|
17
|
-
if not memberships then
|
|
17
|
+
local function ensureCleanup(): ()
|
|
18
|
+
if _cleanupConnected then
|
|
18
19
|
return
|
|
19
20
|
end
|
|
21
|
+
_cleanupConnected = true
|
|
20
22
|
|
|
21
|
-
|
|
22
|
-
local
|
|
23
|
-
if
|
|
24
|
-
|
|
25
|
-
_counts[name] -= 1
|
|
23
|
+
Players.PlayerRemoving:Connect(function(player: Player)
|
|
24
|
+
local groups = _playerCleanup[player]
|
|
25
|
+
if not groups then
|
|
26
|
+
return
|
|
26
27
|
end
|
|
27
|
-
end
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
for _, group in groups do
|
|
30
|
+
group._members[player] = nil
|
|
31
|
+
group._count -= 1
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
_playerCleanup[player] = nil
|
|
35
|
+
end)
|
|
30
36
|
end
|
|
31
37
|
|
|
32
|
-
|
|
38
|
+
-- Public --------------------------------------------------------------
|
|
33
39
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
40
|
+
local Group = {}
|
|
41
|
+
|
|
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 },
|
|
37
50
|
}
|
|
38
51
|
|
|
39
|
-
local
|
|
40
|
-
|
|
52
|
+
local GroupMeta = {}
|
|
53
|
+
GroupMeta.__index = GroupMeta
|
|
41
54
|
|
|
42
|
-
|
|
55
|
+
function GroupMeta.__iter(self: any): () -> (Player?, boolean?)
|
|
56
|
+
local members = self._members
|
|
57
|
+
local key: Player? = nil
|
|
43
58
|
|
|
44
|
-
function
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
59
|
+
return function(): (Player?, boolean?)
|
|
60
|
+
local nextKey, nextVal = next(members, key)
|
|
61
|
+
key = nextKey
|
|
62
|
+
if nextKey then
|
|
63
|
+
return nextKey, nextVal
|
|
64
|
+
end
|
|
65
|
+
return nil, nil
|
|
49
66
|
end
|
|
67
|
+
end
|
|
50
68
|
|
|
51
|
-
|
|
69
|
+
function GroupMeta.add(self: any, player: Player): boolean
|
|
70
|
+
if self._members[player] then
|
|
52
71
|
return false
|
|
53
72
|
end
|
|
54
73
|
|
|
55
|
-
|
|
56
|
-
|
|
74
|
+
self._members[player] = true
|
|
75
|
+
self._count += 1
|
|
57
76
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
77
|
+
-- Track for auto-cleanup
|
|
78
|
+
local cleanup = _playerCleanup[player]
|
|
79
|
+
if not cleanup then
|
|
80
|
+
cleanup = {}
|
|
81
|
+
_playerCleanup[player] = cleanup
|
|
62
82
|
end
|
|
63
|
-
|
|
83
|
+
table.insert(cleanup, self)
|
|
64
84
|
|
|
65
85
|
return true
|
|
66
86
|
end
|
|
67
87
|
|
|
68
|
-
function
|
|
69
|
-
|
|
70
|
-
local set = _groups[name]
|
|
71
|
-
if not set then
|
|
72
|
-
error(`[Lync] Group has been destroyed: "{name}"`)
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
if not set[player] then
|
|
88
|
+
function GroupMeta.remove(self: any, player: Player): boolean
|
|
89
|
+
if not self._members[player] then
|
|
76
90
|
return false
|
|
77
91
|
end
|
|
78
92
|
|
|
79
|
-
|
|
80
|
-
|
|
93
|
+
self._members[player] = nil
|
|
94
|
+
self._count -= 1
|
|
81
95
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
96
|
+
-- Remove from cleanup tracking
|
|
97
|
+
local cleanup = _playerCleanup[player]
|
|
98
|
+
if cleanup then
|
|
99
|
+
local idx = table.find(cleanup, self)
|
|
100
|
+
if idx then
|
|
101
|
+
local last = #cleanup
|
|
102
|
+
cleanup[idx] = cleanup[last]
|
|
103
|
+
cleanup[last] = nil
|
|
104
|
+
end
|
|
85
105
|
end
|
|
86
106
|
|
|
87
107
|
return true
|
|
88
108
|
end
|
|
89
109
|
|
|
90
|
-
function
|
|
91
|
-
|
|
92
|
-
local set = _groups[name]
|
|
93
|
-
if not set then
|
|
94
|
-
error(`[Lync] Group has been destroyed: "{name}"`)
|
|
95
|
-
end
|
|
96
|
-
return set[player] == true
|
|
97
|
-
end
|
|
98
|
-
|
|
99
|
-
function GroupImpl.count(self: Group): number
|
|
100
|
-
local name = self._name
|
|
101
|
-
if not _groups[name] then
|
|
102
|
-
error(`[Lync] Group has been destroyed: "{name}"`)
|
|
103
|
-
end
|
|
104
|
-
return _counts[name]
|
|
110
|
+
function GroupMeta.has(self: any, player: Player): boolean
|
|
111
|
+
return self._members[player] == true
|
|
105
112
|
end
|
|
106
113
|
|
|
107
|
-
function
|
|
108
|
-
|
|
109
|
-
local set = _groups[name]
|
|
110
|
-
if not set then
|
|
111
|
-
error(`[Lync] Group has been destroyed: "{name}"`)
|
|
112
|
-
end
|
|
113
|
-
for player in set do
|
|
114
|
-
fn(player)
|
|
115
|
-
end
|
|
116
|
-
end
|
|
117
|
-
|
|
118
|
-
function GroupImpl.getSet(self: Group): { [Player]: true }
|
|
119
|
-
local name = self._name
|
|
120
|
-
local set = _groups[name]
|
|
121
|
-
if not set then
|
|
122
|
-
error(`[Lync] Group has been destroyed: "{name}"`)
|
|
123
|
-
end
|
|
124
|
-
return set
|
|
114
|
+
function GroupMeta.count(self: any): number
|
|
115
|
+
return self._count
|
|
125
116
|
end
|
|
126
117
|
|
|
127
|
-
function
|
|
118
|
+
function GroupMeta.destroy(self: any): ()
|
|
128
119
|
local name = self._name
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
for player in
|
|
135
|
-
local
|
|
136
|
-
if
|
|
137
|
-
|
|
120
|
+
if name then
|
|
121
|
+
_groups[name] = nil
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
-- Remove all members from cleanup tracking
|
|
125
|
+
for player in self._members do
|
|
126
|
+
local cleanup = _playerCleanup[player]
|
|
127
|
+
if cleanup then
|
|
128
|
+
local idx = table.find(cleanup, self)
|
|
129
|
+
if idx then
|
|
130
|
+
local last = #cleanup
|
|
131
|
+
cleanup[idx] = cleanup[last]
|
|
132
|
+
cleanup[last] = nil
|
|
133
|
+
end
|
|
138
134
|
end
|
|
139
135
|
end
|
|
140
136
|
|
|
141
|
-
|
|
142
|
-
|
|
137
|
+
table.clear(self._members)
|
|
138
|
+
self._count = 0
|
|
143
139
|
end
|
|
144
140
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
-- Public --------------------------------------------------------------
|
|
148
|
-
|
|
149
|
-
local GroupModule = {}
|
|
150
|
-
|
|
151
|
-
function GroupModule.create(name: string): Group
|
|
141
|
+
function Group.create(name: string): GroupHandle
|
|
152
142
|
if _groups[name] then
|
|
153
|
-
error(`[Lync]
|
|
143
|
+
error(`[Lync] Lync.group: "{name}" already exists`)
|
|
154
144
|
end
|
|
155
|
-
_groups[name] = {}
|
|
156
|
-
_counts[name] = 0
|
|
157
145
|
|
|
158
|
-
|
|
159
|
-
|
|
146
|
+
ensureCleanup()
|
|
147
|
+
|
|
148
|
+
local group = setmetatable({
|
|
149
|
+
_lyncGroup = true,
|
|
150
|
+
_members = {} :: { [Player]: boolean },
|
|
151
|
+
_count = 0,
|
|
160
152
|
_name = name,
|
|
161
|
-
},
|
|
153
|
+
}, GroupMeta)
|
|
154
|
+
|
|
155
|
+
_groups[name] = group
|
|
156
|
+
return group :: any
|
|
162
157
|
end
|
|
163
158
|
|
|
164
|
-
return table.freeze(
|
|
159
|
+
return table.freeze(Group)
|