@axpecter/lync 1.3.1 → 1.4.1
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 +250 -68
- package/package.json +1 -1
- package/src/Types.luau +13 -2
- package/src/api/Group.luau +77 -46
- package/src/api/Namespace.luau +13 -6
- package/src/api/Packet.luau +52 -30
- package/src/api/Query.luau +116 -90
- package/src/api/Scope.luau +73 -0
- package/src/api/Signal.luau +10 -4
- package/src/codec/Base.luau +7 -3
- package/src/codec/composite/Array.luau +18 -15
- package/src/codec/composite/Map.luau +45 -31
- package/src/codec/composite/Optional.luau +3 -2
- package/src/codec/composite/Shared.luau +7 -5
- package/src/codec/composite/Struct.luau +6 -4
- package/src/codec/composite/Tagged.luau +6 -6
- package/src/codec/composite/Tuple.luau +9 -7
- package/src/codec/datatype/Buffer.luau +3 -2
- package/src/codec/datatype/CFrame.luau +2 -1
- package/src/codec/datatype/Instance.luau +3 -2
- package/src/codec/datatype/Sequence.luau +3 -4
- package/src/codec/datatype/String.luau +3 -6
- package/src/codec/meta/Auto.luau +77 -72
- package/src/codec/meta/Bitfield.luau +5 -4
- package/src/codec/meta/Enum.luau +6 -5
- package/src/codec/meta/Quantized.luau +5 -4
- package/src/codec/meta/Unknown.luau +5 -1
- package/src/codec/primitive/Float16.luau +5 -4
- package/src/codec/primitive/Varint.luau +2 -2
- package/src/index.d.ts +65 -26
- package/src/init.luau +60 -42
- package/src/internal/Baseline.luau +6 -2
- package/src/internal/Channel.luau +11 -6
- package/src/internal/Middleware.luau +18 -8
- package/src/internal/Pool.luau +5 -5
- package/src/internal/Registry.luau +4 -4
- package/src/transport/Bridge.luau +4 -3
- package/src/transport/Client.luau +4 -3
- package/src/transport/Gate.luau +5 -5
- package/src/transport/Reader.luau +3 -3
- package/src/transport/Server.luau +14 -16
package/src/api/Namespace.luau
CHANGED
|
@@ -11,16 +11,16 @@ type Connection = Types.Connection
|
|
|
11
11
|
type PacketConfig<T> = Types.PacketConfig<T>
|
|
12
12
|
type QueryConfig<R, S> = Types.QueryConfig<R, S>
|
|
13
13
|
|
|
14
|
-
-- Constants
|
|
14
|
+
-- Constants ----------------------------------------------------------
|
|
15
15
|
|
|
16
16
|
local MAX_NAMESPACES = 64
|
|
17
17
|
|
|
18
|
-
-- State
|
|
18
|
+
-- State --------------------------------------------------------------
|
|
19
19
|
|
|
20
20
|
local _registered = {} :: { [string]: true }
|
|
21
21
|
local _count = 0
|
|
22
22
|
|
|
23
|
-
-- Private
|
|
23
|
+
-- Private ------------------------------------------------------------
|
|
24
24
|
|
|
25
25
|
type NamespaceConfig = {
|
|
26
26
|
packets: { [string]: PacketConfig<any> }?,
|
|
@@ -47,8 +47,6 @@ local function scopedHandler (
|
|
|
47
47
|
end
|
|
48
48
|
end
|
|
49
49
|
|
|
50
|
-
-- Namespace --------------------------------------------------------------
|
|
51
|
-
|
|
52
50
|
local NamespaceImpl = {}
|
|
53
51
|
NamespaceImpl.__index = NamespaceImpl
|
|
54
52
|
|
|
@@ -173,7 +171,9 @@ function NamespaceImpl.queryNames (self: any): { string }
|
|
|
173
171
|
return result
|
|
174
172
|
end
|
|
175
173
|
|
|
176
|
-
|
|
174
|
+
table.freeze (NamespaceImpl)
|
|
175
|
+
|
|
176
|
+
-- Public -------------------------------------------------------------
|
|
177
177
|
|
|
178
178
|
local Namespace = {}
|
|
179
179
|
|
|
@@ -194,6 +194,8 @@ function Namespace.define (name: string, config: NamespaceConfig): any
|
|
|
194
194
|
|
|
195
195
|
local packets = {} :: { [string]: any }
|
|
196
196
|
local queries = {} :: { [string]: any }
|
|
197
|
+
local packetsByShort = {} :: { [string]: any }
|
|
198
|
+
local queriesByShort = {} :: { [string]: any }
|
|
197
199
|
local fields = {} :: { [string]: any }
|
|
198
200
|
|
|
199
201
|
fields._name = name
|
|
@@ -207,6 +209,7 @@ function Namespace.define (name: string, config: NamespaceConfig): any
|
|
|
207
209
|
local fullName = prefixName (name, shortName)
|
|
208
210
|
local packet = Packet.define (fullName, packetConfig)
|
|
209
211
|
packets[fullName] = packet
|
|
212
|
+
packetsByShort[shortName] = packet
|
|
210
213
|
fields[shortName] = packet
|
|
211
214
|
end
|
|
212
215
|
end
|
|
@@ -216,10 +219,14 @@ function Namespace.define (name: string, config: NamespaceConfig): any
|
|
|
216
219
|
local fullName = prefixName (name, shortName)
|
|
217
220
|
local query = Query.define (fullName, queryConfig)
|
|
218
221
|
queries[fullName] = query
|
|
222
|
+
queriesByShort[shortName] = query
|
|
219
223
|
fields[shortName] = query
|
|
220
224
|
end
|
|
221
225
|
end
|
|
222
226
|
|
|
227
|
+
fields.packets = table.freeze (packetsByShort)
|
|
228
|
+
fields.queries = table.freeze (queriesByShort)
|
|
229
|
+
|
|
223
230
|
return setmetatable (fields, NamespaceImpl)
|
|
224
231
|
end
|
|
225
232
|
|
package/src/api/Packet.luau
CHANGED
|
@@ -11,9 +11,10 @@ local Signal = require (script.Parent.Signal)
|
|
|
11
11
|
local Types = require (script.Parent.Parent.Types)
|
|
12
12
|
|
|
13
13
|
type Connection = Types.Connection
|
|
14
|
+
type InternalCodec<T> = Types.InternalCodec<T>
|
|
14
15
|
type PacketConfig<T> = Types.PacketConfig<T>
|
|
15
16
|
|
|
16
|
-
-- Constants
|
|
17
|
+
-- Constants ----------------------------------------------------------
|
|
17
18
|
|
|
18
19
|
local IS_SERVER = RunService:IsServer ()
|
|
19
20
|
|
|
@@ -21,10 +22,13 @@ local serverWriteTo = Server.writeTo
|
|
|
21
22
|
local serverWriteToAll = Server.writeToAll
|
|
22
23
|
local serverWriteToList = Server.writeToList
|
|
23
24
|
local serverWriteToAllExcept = Server.writeToAllExcept
|
|
24
|
-
local
|
|
25
|
+
local serverWriteToSet = Server.writeToSet
|
|
25
26
|
local clientWrite = Client.write
|
|
26
27
|
|
|
27
|
-
|
|
28
|
+
local DELTA_TARGETED = 1
|
|
29
|
+
local DELTA_BROADCAST = 2
|
|
30
|
+
|
|
31
|
+
-- Private ------------------------------------------------------------
|
|
28
32
|
|
|
29
33
|
-- Shared methods (both contexts)
|
|
30
34
|
local SharedImpl = {}
|
|
@@ -45,13 +49,10 @@ function SharedImpl.disconnectAll (self: any): ()
|
|
|
45
49
|
self._signal:disconnectAll ()
|
|
46
50
|
end
|
|
47
51
|
|
|
48
|
-
-- Server-only metatable
|
|
52
|
+
-- Server-only metatable. Single send() dispatches on target type.
|
|
49
53
|
local ServerImpl = setmetatable ({}, { __index = SharedImpl })
|
|
50
54
|
ServerImpl.__index = ServerImpl
|
|
51
55
|
|
|
52
|
-
local DELTA_TARGETED = 1
|
|
53
|
-
local DELTA_BROADCAST = 2
|
|
54
|
-
|
|
55
56
|
local function checkDeltaMode (self: any, mode: number): ()
|
|
56
57
|
if not self._isDelta then
|
|
57
58
|
return
|
|
@@ -64,34 +65,55 @@ local function checkDeltaMode (self: any, mode: number): ()
|
|
|
64
65
|
end
|
|
65
66
|
end
|
|
66
67
|
|
|
67
|
-
function ServerImpl.
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
end
|
|
68
|
+
function ServerImpl.send (self: any, data: any, target: any?): ()
|
|
69
|
+
if target == nil then
|
|
70
|
+
error ("[Lync] Server packet:send requires a target")
|
|
71
|
+
end
|
|
71
72
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
73
|
+
local id = self._id
|
|
74
|
+
local name = self._name
|
|
75
|
+
local codec = self._codec
|
|
76
|
+
local isUnreliable = self._isUnreliable
|
|
76
77
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
78
|
+
-- Single player
|
|
79
|
+
if typeof (target) == "Instance" then
|
|
80
|
+
checkDeltaMode (self, DELTA_TARGETED)
|
|
81
|
+
serverWriteTo (target :: Player, id, name, codec, data, isUnreliable)
|
|
82
|
+
return
|
|
83
|
+
end
|
|
81
84
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
85
|
+
-- Must be a table from here
|
|
86
|
+
local tag = target._tag
|
|
87
|
+
|
|
88
|
+
-- Lync.all sentinel
|
|
89
|
+
if tag == "all" then
|
|
90
|
+
checkDeltaMode (self, DELTA_BROADCAST)
|
|
91
|
+
serverWriteToAll (id, name, codec, data, isUnreliable)
|
|
92
|
+
return
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
-- Lync.except(player, ...) descriptor
|
|
96
|
+
if tag == "except" then
|
|
97
|
+
checkDeltaMode (self, DELTA_BROADCAST)
|
|
98
|
+
serverWriteToAllExcept (target._set, id, name, codec, data, isUnreliable)
|
|
99
|
+
return
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
-- Group object
|
|
103
|
+
if tag == "group" then
|
|
104
|
+
checkDeltaMode (self, DELTA_BROADCAST)
|
|
105
|
+
serverWriteToSet (target:getSet (), id, name, codec, data, isUnreliable)
|
|
106
|
+
return
|
|
107
|
+
end
|
|
86
108
|
|
|
87
|
-
|
|
88
|
-
checkDeltaMode (self,
|
|
89
|
-
|
|
109
|
+
-- Player list (array)
|
|
110
|
+
checkDeltaMode (self, DELTA_TARGETED)
|
|
111
|
+
serverWriteToList (target :: { Player }, id, name, codec, data, isUnreliable)
|
|
90
112
|
end
|
|
91
113
|
|
|
92
114
|
table.freeze (ServerImpl)
|
|
93
115
|
|
|
94
|
-
-- Client-only metatable
|
|
116
|
+
-- Client-only metatable. Has send(), no target needed.
|
|
95
117
|
local ClientImpl = setmetatable ({}, { __index = SharedImpl })
|
|
96
118
|
ClientImpl.__index = ClientImpl
|
|
97
119
|
|
|
@@ -101,7 +123,7 @@ end
|
|
|
101
123
|
|
|
102
124
|
table.freeze (ClientImpl)
|
|
103
125
|
|
|
104
|
-
-- Public
|
|
126
|
+
-- Public -------------------------------------------------------------
|
|
105
127
|
|
|
106
128
|
local Packet = {}
|
|
107
129
|
|
|
@@ -115,7 +137,7 @@ function Packet.define (name: string, config: PacketConfig<any>): any
|
|
|
115
137
|
|
|
116
138
|
local isUnreliable = config.unreliable or false
|
|
117
139
|
|
|
118
|
-
if (config.value :: any)._isDelta and isUnreliable then
|
|
140
|
+
if (config.value :: InternalCodec<any>)._isDelta and isUnreliable then
|
|
119
141
|
error (`[Lync] Delta codec requires reliable delivery: "{name}"`)
|
|
120
142
|
end
|
|
121
143
|
|
|
@@ -131,7 +153,7 @@ function Packet.define (name: string, config: PacketConfig<any>): any
|
|
|
131
153
|
config.maxPayloadBytes
|
|
132
154
|
)
|
|
133
155
|
|
|
134
|
-
local isDelta = (config.value :: any)._isDelta == true
|
|
156
|
+
local isDelta = (config.value :: InternalCodec<any>)._isDelta == true
|
|
135
157
|
|
|
136
158
|
return setmetatable ({
|
|
137
159
|
_id = reg.id,
|
package/src/api/Query.luau
CHANGED
|
@@ -6,7 +6,6 @@ local Players = game:GetService ("Players")
|
|
|
6
6
|
local RunService = game:GetService ("RunService")
|
|
7
7
|
|
|
8
8
|
local Client = require (script.Parent.Parent.transport.Client)
|
|
9
|
-
local Group = require (script.Parent.Group)
|
|
10
9
|
local Registry = require (script.Parent.Parent.internal.Registry)
|
|
11
10
|
local Server = require (script.Parent.Parent.transport.Server)
|
|
12
11
|
local Signal = require (script.Parent.Signal)
|
|
@@ -15,14 +14,14 @@ local Types = require (script.Parent.Parent.Types)
|
|
|
15
14
|
type Connection = Types.Connection
|
|
16
15
|
type QueryConfig<R, S> = Types.QueryConfig<R, S>
|
|
17
16
|
|
|
18
|
-
-- Constants
|
|
17
|
+
-- Constants ----------------------------------------------------------
|
|
19
18
|
|
|
20
19
|
local IS_SERVER = RunService:IsServer ()
|
|
21
20
|
|
|
22
21
|
-- Wire ceiling: correlationId is u16 in Channel.writeQuery / Reader.process.
|
|
23
22
|
local POOL_SIZE = 65536
|
|
24
23
|
|
|
25
|
-
-- State
|
|
24
|
+
-- State --------------------------------------------------------------
|
|
26
25
|
|
|
27
26
|
type PendingQuery = {
|
|
28
27
|
thread: thread?,
|
|
@@ -34,7 +33,7 @@ local _pending = {} :: { [number]: PendingQuery }
|
|
|
34
33
|
local _nextId = 0
|
|
35
34
|
local _activeCount = 0
|
|
36
35
|
|
|
37
|
-
-- Private
|
|
36
|
+
-- Private ------------------------------------------------------------
|
|
38
37
|
|
|
39
38
|
local function allocCorrelation (): number
|
|
40
39
|
if _activeCount >= POOL_SIZE then
|
|
@@ -54,7 +53,9 @@ local function allocCorrelation (): number
|
|
|
54
53
|
return id
|
|
55
54
|
end
|
|
56
55
|
|
|
57
|
-
|
|
56
|
+
-- Decrements the active correlation counter. Does not free a specific slot;
|
|
57
|
+
-- that is handled by nil-ing _pending[id] at the call site.
|
|
58
|
+
local function releaseCorrelation (): ()
|
|
58
59
|
_activeCount -= 1
|
|
59
60
|
end
|
|
60
61
|
|
|
@@ -65,7 +66,7 @@ local function completeQuery (id: number, data: any): ()
|
|
|
65
66
|
end
|
|
66
67
|
|
|
67
68
|
_pending[id] = nil
|
|
68
|
-
|
|
69
|
+
releaseCorrelation ()
|
|
69
70
|
|
|
70
71
|
if entry.timeout then
|
|
71
72
|
task.cancel (entry.timeout)
|
|
@@ -82,90 +83,35 @@ local function onTimeout (correlation: number): ()
|
|
|
82
83
|
completeQuery (correlation, nil)
|
|
83
84
|
end
|
|
84
85
|
|
|
85
|
-
--
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
function QueryImpl.listen (self: any, callback: (...any) -> any): Connection
|
|
91
|
-
local respId = self._respReg.id
|
|
92
|
-
local respName = self._name
|
|
93
|
-
local respCodec = self._respReg.codec
|
|
94
|
-
|
|
95
|
-
if IS_SERVER then
|
|
96
|
-
return self._reqReg.signal:connect (
|
|
97
|
-
function (request: any, player: Player, correlation: number): ()
|
|
98
|
-
local ok, response = pcall (callback, request, player)
|
|
99
|
-
if not ok then
|
|
100
|
-
warn (`[Lync] Query handler error on "{respName}": {response}`)
|
|
101
|
-
end
|
|
102
|
-
|
|
103
|
-
if ok and response ~= nil then
|
|
104
|
-
Server.writeQuery (player, respId, respName, correlation, respCodec, response)
|
|
105
|
-
else
|
|
106
|
-
Server.writeQueryNil (player, respId, respName, correlation)
|
|
107
|
-
end
|
|
108
|
-
end
|
|
109
|
-
)
|
|
110
|
-
else
|
|
111
|
-
return self._reqReg.signal:connect (
|
|
112
|
-
function (request: any, _player: Player?, correlation: number): ()
|
|
113
|
-
local ok, response = pcall (callback, request)
|
|
114
|
-
if not ok then
|
|
115
|
-
warn (`[Lync] Query handler error on "{respName}": {response}`)
|
|
116
|
-
end
|
|
117
|
-
|
|
118
|
-
if ok and response ~= nil then
|
|
119
|
-
Client.writeQuery (respId, respName, correlation, respCodec, response)
|
|
120
|
-
else
|
|
121
|
-
Client.writeQueryNil (respId, respName, correlation)
|
|
122
|
-
end
|
|
123
|
-
end
|
|
124
|
-
)
|
|
86
|
+
-- Send a query to multiple players and yield. Returns { [Player]: response? }.
|
|
87
|
+
local function requestMulti (self: any, players: { Player }, data: any): { [Player]: any? }
|
|
88
|
+
if not IS_SERVER then
|
|
89
|
+
error ("[Lync] Multi-request is server-only")
|
|
125
90
|
end
|
|
126
|
-
end
|
|
127
91
|
|
|
128
|
-
|
|
129
|
-
if
|
|
130
|
-
|
|
92
|
+
local count = #players
|
|
93
|
+
if count == 0 then
|
|
94
|
+
return {}
|
|
131
95
|
end
|
|
132
96
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
97
|
+
if count == 1 then
|
|
98
|
+
-- Delegate to single-player path
|
|
99
|
+
local correlation = allocCorrelation ()
|
|
100
|
+
local thread = coroutine.running ()
|
|
101
|
+
local entry: PendingQuery = { thread = thread, timeout = nil }
|
|
102
|
+
_pending[correlation] = entry
|
|
138
103
|
|
|
139
|
-
if IS_SERVER then
|
|
140
104
|
Server.writeQuery (
|
|
141
|
-
|
|
105
|
+
players[1],
|
|
142
106
|
self._reqReg.id,
|
|
143
107
|
self._name,
|
|
144
108
|
correlation,
|
|
145
109
|
self._reqReg.codec,
|
|
146
|
-
|
|
110
|
+
data
|
|
147
111
|
)
|
|
148
|
-
else
|
|
149
|
-
Client.writeQuery (self._reqReg.id, self._name, correlation, self._reqReg.codec, request)
|
|
150
|
-
end
|
|
151
|
-
|
|
152
|
-
entry.timeout = task.delay (self._timeout, onTimeout, correlation)
|
|
153
|
-
return coroutine.yield ()
|
|
154
|
-
end
|
|
155
|
-
|
|
156
|
-
-- Send a query to multiple players and yield. Returns { [Player]: response? }.
|
|
157
|
-
local function invokeMulti (self: any, players: { Player }, request: any): { [Player]: any? }
|
|
158
|
-
if not IS_SERVER then
|
|
159
|
-
error ("[Lync] Multi-invoke is server-only")
|
|
160
|
-
end
|
|
161
|
-
|
|
162
|
-
local count = #players
|
|
163
|
-
if count == 0 then
|
|
164
|
-
return {}
|
|
165
|
-
end
|
|
166
112
|
|
|
167
|
-
|
|
168
|
-
local result =
|
|
113
|
+
entry.timeout = task.delay (self._timeout, onTimeout, correlation)
|
|
114
|
+
local result = coroutine.yield ()
|
|
169
115
|
return { [players[1]] = result }
|
|
170
116
|
end
|
|
171
117
|
|
|
@@ -187,8 +133,8 @@ local function invokeMulti (self: any, players: { Player }, request: any): { [Pl
|
|
|
187
133
|
|
|
188
134
|
local entry: PendingQuery = {
|
|
189
135
|
thread = nil,
|
|
190
|
-
callback = function (
|
|
191
|
-
results[player] =
|
|
136
|
+
callback = function (resp: any): ()
|
|
137
|
+
results[player] = resp
|
|
192
138
|
remaining -= 1
|
|
193
139
|
if remaining == 0 and not finished then
|
|
194
140
|
finished = true
|
|
@@ -200,7 +146,7 @@ local function invokeMulti (self: any, players: { Player }, request: any): { [Pl
|
|
|
200
146
|
|
|
201
147
|
_pending[correlation] = entry
|
|
202
148
|
|
|
203
|
-
Server.writeQuery (player, reqId, reqName, correlation, reqCodec,
|
|
149
|
+
Server.writeQuery (player, reqId, reqName, correlation, reqCodec, data)
|
|
204
150
|
end
|
|
205
151
|
|
|
206
152
|
local timeoutThread = task.delay (timeout, function (): ()
|
|
@@ -214,7 +160,7 @@ local function invokeMulti (self: any, players: { Player }, request: any): { [Pl
|
|
|
214
160
|
local entry = _pending[cid]
|
|
215
161
|
if entry then
|
|
216
162
|
_pending[cid] = nil
|
|
217
|
-
|
|
163
|
+
releaseCorrelation ()
|
|
218
164
|
end
|
|
219
165
|
end
|
|
220
166
|
|
|
@@ -232,25 +178,105 @@ local function invokeMulti (self: any, players: { Player }, request: any): { [Pl
|
|
|
232
178
|
return coroutine.yield ()
|
|
233
179
|
end
|
|
234
180
|
|
|
235
|
-
|
|
181
|
+
local QueryImpl = {}
|
|
182
|
+
QueryImpl.__index = QueryImpl
|
|
183
|
+
|
|
184
|
+
function QueryImpl.listen (self: any, callback: (...any) -> any): Connection
|
|
185
|
+
local respId = self._respReg.id
|
|
186
|
+
local respName = self._name
|
|
187
|
+
local respCodec = self._respReg.codec
|
|
188
|
+
|
|
189
|
+
if IS_SERVER then
|
|
190
|
+
return self._reqReg.signal:connect (
|
|
191
|
+
function (request: any, player: Player, correlation: number): ()
|
|
192
|
+
local ok, response = pcall (callback, request, player)
|
|
193
|
+
if not ok then
|
|
194
|
+
warn (`[Lync] Query handler error on "{respName}": {response}`)
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
if ok and response ~= nil then
|
|
198
|
+
Server.writeQuery (player, respId, respName, correlation, respCodec, response)
|
|
199
|
+
else
|
|
200
|
+
Server.writeQueryNil (player, respId, respName, correlation)
|
|
201
|
+
end
|
|
202
|
+
end
|
|
203
|
+
)
|
|
204
|
+
else
|
|
205
|
+
return self._reqReg.signal:connect (
|
|
206
|
+
function (request: any, _player: Player?, correlation: number): ()
|
|
207
|
+
local ok, response = pcall (callback, request)
|
|
208
|
+
if not ok then
|
|
209
|
+
warn (`[Lync] Query handler error on "{respName}": {response}`)
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
if ok and response ~= nil then
|
|
213
|
+
Client.writeQuery (respId, respName, correlation, respCodec, response)
|
|
214
|
+
else
|
|
215
|
+
Client.writeQueryNil (respId, respName, correlation)
|
|
216
|
+
end
|
|
217
|
+
end
|
|
218
|
+
)
|
|
219
|
+
end
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
-- Client: send request to server, yield until response.
|
|
223
|
+
function QueryImpl.request (self: any, data: any): any
|
|
224
|
+
if IS_SERVER then
|
|
225
|
+
error ("[Lync] query:request is client-only. Use query:requestFrom on server")
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
local correlation = allocCorrelation ()
|
|
229
|
+
local thread = coroutine.running ()
|
|
230
|
+
local entry: PendingQuery = { thread = thread, timeout = nil }
|
|
231
|
+
_pending[correlation] = entry
|
|
232
|
+
|
|
233
|
+
Client.writeQuery (self._reqReg.id, self._name, correlation, self._reqReg.codec, data)
|
|
234
|
+
|
|
235
|
+
entry.timeout = task.delay (self._timeout, onTimeout, correlation)
|
|
236
|
+
return coroutine.yield ()
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
-- Server: send request to one player, yield until response.
|
|
240
|
+
function QueryImpl.requestFrom (self: any, player: Player, data: any): any
|
|
241
|
+
if not IS_SERVER then
|
|
242
|
+
error ("[Lync] query:requestFrom is server-only. Use query:request on client")
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
local correlation = allocCorrelation ()
|
|
246
|
+
local thread = coroutine.running ()
|
|
247
|
+
local entry: PendingQuery = { thread = thread, timeout = nil }
|
|
248
|
+
_pending[correlation] = entry
|
|
249
|
+
|
|
250
|
+
Server.writeQuery (player, self._reqReg.id, self._name, correlation, self._reqReg.codec, data)
|
|
251
|
+
|
|
252
|
+
entry.timeout = task.delay (self._timeout, onTimeout, correlation)
|
|
253
|
+
return coroutine.yield ()
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
-- Server: send request to all players, yield until all respond or timeout.
|
|
257
|
+
function QueryImpl.requestAll (self: any, data: any): { [Player]: any? }
|
|
236
258
|
local players = Players:GetPlayers ()
|
|
237
|
-
return
|
|
259
|
+
return requestMulti (self, players, data)
|
|
238
260
|
end
|
|
239
261
|
|
|
240
|
-
|
|
241
|
-
|
|
262
|
+
-- Server: send request to a list of players.
|
|
263
|
+
function QueryImpl.requestList (self: any, players: { Player }, data: any): { [Player]: any? }
|
|
264
|
+
return requestMulti (self, players, data)
|
|
242
265
|
end
|
|
243
266
|
|
|
244
|
-
|
|
245
|
-
|
|
267
|
+
-- Server: send request to all players in a group.
|
|
268
|
+
function QueryImpl.requestGroup (self: any, group: any, data: any): { [Player]: any? }
|
|
269
|
+
local set = group:getSet ()
|
|
246
270
|
local players = {} :: { Player }
|
|
247
271
|
for player in set do
|
|
248
272
|
table.insert (players, player)
|
|
249
273
|
end
|
|
250
|
-
return
|
|
274
|
+
return requestMulti (self, players, data)
|
|
251
275
|
end
|
|
252
276
|
|
|
253
|
-
|
|
277
|
+
table.freeze (QueryImpl)
|
|
278
|
+
|
|
279
|
+
-- Public -------------------------------------------------------------
|
|
254
280
|
|
|
255
281
|
local Query = {}
|
|
256
282
|
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
--!strict
|
|
2
|
+
--!optimize 2
|
|
3
|
+
-- Batched connection lifecycle management.
|
|
4
|
+
|
|
5
|
+
-- Private ------------------------------------------------------------
|
|
6
|
+
|
|
7
|
+
local ScopeImpl = {}
|
|
8
|
+
ScopeImpl.__index = ScopeImpl
|
|
9
|
+
|
|
10
|
+
function ScopeImpl.add (self: any, conn: any): ()
|
|
11
|
+
if not conn then
|
|
12
|
+
return
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
local entries = self._entries
|
|
16
|
+
local count = self._count + 1
|
|
17
|
+
self._count = count
|
|
18
|
+
entries[count] = conn
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
function ScopeImpl.listen (self: any, source: any, callback: (...any) -> ()): ()
|
|
22
|
+
local conn = source:listen (callback)
|
|
23
|
+
local entries = self._entries
|
|
24
|
+
local count = self._count + 1
|
|
25
|
+
self._count = count
|
|
26
|
+
entries[count] = conn
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
function ScopeImpl.once (self: any, source: any, callback: (...any) -> ()): ()
|
|
30
|
+
local conn = source:once (callback)
|
|
31
|
+
local entries = self._entries
|
|
32
|
+
local count = self._count + 1
|
|
33
|
+
self._count = count
|
|
34
|
+
entries[count] = conn
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
function ScopeImpl.listenAll (self: any, namespace: any, callback: (...any) -> ()): ()
|
|
38
|
+
local conn = namespace:listenAll (callback)
|
|
39
|
+
local entries = self._entries
|
|
40
|
+
local count = self._count + 1
|
|
41
|
+
self._count = count
|
|
42
|
+
entries[count] = conn
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
function ScopeImpl.destroy (self: any): ()
|
|
46
|
+
local entries = self._entries
|
|
47
|
+
local count = self._count
|
|
48
|
+
|
|
49
|
+
for i = 1, count do
|
|
50
|
+
local conn = entries[i]
|
|
51
|
+
entries[i] = nil
|
|
52
|
+
|
|
53
|
+
if typeof (conn) == "RBXScriptConnection" then
|
|
54
|
+
conn:Disconnect ()
|
|
55
|
+
elseif conn.disconnect then
|
|
56
|
+
conn:disconnect ()
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
self._count = 0
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
table.freeze (ScopeImpl)
|
|
64
|
+
|
|
65
|
+
-- Public -------------------------------------------------------------
|
|
66
|
+
|
|
67
|
+
local Scope = {}
|
|
68
|
+
|
|
69
|
+
function Scope.create (): any
|
|
70
|
+
return setmetatable ({ _entries = {}, _count = 0 }, ScopeImpl)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
return table.freeze (Scope)
|
package/src/api/Signal.luau
CHANGED
|
@@ -6,12 +6,13 @@ local Types = require (script.Parent.Parent.Types)
|
|
|
6
6
|
|
|
7
7
|
type Connection = Types.Connection
|
|
8
8
|
|
|
9
|
-
--
|
|
9
|
+
-- Constants ----------------------------------------------------------
|
|
10
|
+
|
|
10
11
|
local STATE_DISCONNECTED = 0
|
|
11
12
|
local STATE_CONNECTED = 1
|
|
12
13
|
local STATE_ONCE = 2
|
|
13
14
|
|
|
14
|
-
-- Private
|
|
15
|
+
-- Private ------------------------------------------------------------
|
|
15
16
|
|
|
16
17
|
local _freeThread: thread? = nil
|
|
17
18
|
|
|
@@ -36,7 +37,9 @@ local function spawn (fn: (...any) -> (), ...: any): ()
|
|
|
36
37
|
task.spawn (_freeThread :: thread, fn, ...)
|
|
37
38
|
end
|
|
38
39
|
|
|
39
|
-
-- Entry doubles as the Connection handle
|
|
40
|
+
-- Entry doubles as the Connection handle: 1 alloc per listener instead of 2.
|
|
41
|
+
-- self: any — metatable typing via typeof(setmetatable) is not practical here
|
|
42
|
+
-- because Entry and Signal reference each other circularly.
|
|
40
43
|
local EntryImpl = {}
|
|
41
44
|
EntryImpl.__index = EntryImpl
|
|
42
45
|
|
|
@@ -213,7 +216,10 @@ function SignalImpl.disconnectAll (self: any): ()
|
|
|
213
216
|
self._count = 0
|
|
214
217
|
end
|
|
215
218
|
|
|
216
|
-
|
|
219
|
+
table.freeze (EntryImpl)
|
|
220
|
+
table.freeze (SignalImpl)
|
|
221
|
+
|
|
222
|
+
-- Public -------------------------------------------------------------
|
|
217
223
|
|
|
218
224
|
local Signal = {}
|
|
219
225
|
|
package/src/codec/Base.luau
CHANGED
|
@@ -3,9 +3,13 @@
|
|
|
3
3
|
-- Fixed-size codec factory. Every fixed-size codec calls Base.define once.
|
|
4
4
|
|
|
5
5
|
local Channel = require (script.Parent.Parent.internal.Channel)
|
|
6
|
+
local Types = require (script.Parent.Parent.Types)
|
|
7
|
+
|
|
8
|
+
type ChannelState = Types.ChannelState
|
|
9
|
+
|
|
6
10
|
local alloc = Channel.alloc
|
|
7
11
|
|
|
8
|
-
-- Public
|
|
12
|
+
-- Public -------------------------------------------------------------
|
|
9
13
|
|
|
10
14
|
local Base = {}
|
|
11
15
|
|
|
@@ -18,7 +22,7 @@ function Base.define <T>(
|
|
|
18
22
|
_size = size,
|
|
19
23
|
_directWrite = directWrite,
|
|
20
24
|
_directRead = directRead,
|
|
21
|
-
write = function (ch:
|
|
25
|
+
write = function (ch: ChannelState, value: T): ()
|
|
22
26
|
local c = ch.cursor
|
|
23
27
|
if c + size > ch.size then
|
|
24
28
|
alloc (ch, size)
|
|
@@ -39,7 +43,7 @@ function Base.zero (): any
|
|
|
39
43
|
_directRead = function (_b: buffer, _offset: number): any
|
|
40
44
|
return nil
|
|
41
45
|
end,
|
|
42
|
-
write = function (_ch:
|
|
46
|
+
write = function (_ch: ChannelState, _value: any): () end,
|
|
43
47
|
read = function (_src: buffer, _pos: number, _refs: { Instance }?): (any, number)
|
|
44
48
|
return nil, 0
|
|
45
49
|
end,
|