@trioforge/crucible 0.0.0-stage → 0.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/LICENSE +21 -0
- package/client/package.json +4 -0
- package/emit/package.json +4 -0
- package/out/all.d.ts +7 -0
- package/out/all.luau +2 -0
- package/out/attribute.d.ts +7 -0
- package/out/attribute.luau +7 -0
- package/out/client/index.d.ts +10 -0
- package/out/client/init.luau +55 -0
- package/out/configs.d.ts +37 -0
- package/out/configs.luau +46 -0
- package/out/crucible-behaviour.d.ts +16 -0
- package/out/crucible-behaviour.luau +78 -0
- package/out/crucible-object.d.ts +10 -0
- package/out/crucible-object.luau +69 -0
- package/out/data.d.ts +224 -0
- package/out/data.luau +97 -0
- package/out/emit/configs.d.ts +4 -0
- package/out/emit/configs.luau +22 -0
- package/out/emit/data.d.ts +6 -0
- package/out/emit/data.luau +19 -0
- package/out/emit/index.d.ts +45 -0
- package/out/emit/init.luau +101 -0
- package/out/emit/network.d.ts +6 -0
- package/out/emit/network.luau +36 -0
- package/out/emit/replicated.d.ts +4 -0
- package/out/emit/replicated.luau +13 -0
- package/out/index.d.ts +20 -0
- package/out/init.luau +34 -0
- package/out/inject.d.ts +1 -0
- package/out/inject.luau +7 -0
- package/out/internal/binding.d.ts +1 -0
- package/out/internal/binding.luau +615 -0
- package/out/internal/boot.d.ts +1 -0
- package/out/internal/boot.luau +562 -0
- package/out/internal/configs/limits.d.ts +10 -0
- package/out/internal/configs/limits.luau +25 -0
- package/out/internal/configs/port.d.ts +29 -0
- package/out/internal/configs/port.luau +99 -0
- package/out/internal/configs/runtime.d.ts +21 -0
- package/out/internal/configs/runtime.luau +981 -0
- package/out/internal/construction-claim.d.ts +1 -0
- package/out/internal/construction-claim.luau +26 -0
- package/out/internal/data/admission.d.ts +1 -0
- package/out/internal/data/admission.luau +673 -0
- package/out/internal/data/declarations.d.ts +1 -0
- package/out/internal/data/declarations.luau +384 -0
- package/out/internal/data/envelope.d.ts +1 -0
- package/out/internal/data/envelope.luau +318 -0
- package/out/internal/data/handles.d.ts +1 -0
- package/out/internal/data/handles.luau +255 -0
- package/out/internal/data/inbox-transforms.d.ts +1 -0
- package/out/internal/data/inbox-transforms.luau +458 -0
- package/out/internal/data/inbox.d.ts +1 -0
- package/out/internal/data/inbox.luau +437 -0
- package/out/internal/data/lease.d.ts +1 -0
- package/out/internal/data/lease.luau +304 -0
- package/out/internal/data/limits.d.ts +1 -0
- package/out/internal/data/limits.luau +234 -0
- package/out/internal/data/messages.d.ts +1 -0
- package/out/internal/data/messages.luau +69 -0
- package/out/internal/data/operation-id.d.ts +1 -0
- package/out/internal/data/operation-id.luau +61 -0
- package/out/internal/data/paths.d.ts +2 -0
- package/out/internal/data/paths.luau +323 -0
- package/out/internal/data/port.d.ts +1 -0
- package/out/internal/data/port.luau +290 -0
- package/out/internal/data/profiles.d.ts +1 -0
- package/out/internal/data/profiles.luau +862 -0
- package/out/internal/data/receipts.d.ts +1 -0
- package/out/internal/data/receipts.luau +190 -0
- package/out/internal/data/record-bindings.d.ts +1 -0
- package/out/internal/data/record-bindings.luau +92 -0
- package/out/internal/data/record-declarations.d.ts +1 -0
- package/out/internal/data/record-declarations.luau +140 -0
- package/out/internal/data/records.d.ts +1 -0
- package/out/internal/data/records.luau +400 -0
- package/out/internal/data/runtime.d.ts +1 -0
- package/out/internal/data/runtime.luau +918 -0
- package/out/internal/data/scheduler.d.ts +1 -0
- package/out/internal/data/scheduler.luau +507 -0
- package/out/internal/data/session.d.ts +1 -0
- package/out/internal/data/session.luau +234 -0
- package/out/internal/data/shutdown.d.ts +1 -0
- package/out/internal/data/shutdown.luau +91 -0
- package/out/internal/data/waiters.d.ts +1 -0
- package/out/internal/data/waiters.luau +65 -0
- package/out/internal/dense-list.d.ts +1 -0
- package/out/internal/dense-list.luau +155 -0
- package/out/internal/diagnostics.d.ts +1 -0
- package/out/internal/diagnostics.luau +29 -0
- package/out/internal/hooks.d.ts +1 -0
- package/out/internal/hooks.luau +53 -0
- package/out/internal/implementers.d.ts +1 -0
- package/out/internal/implementers.luau +119 -0
- package/out/internal/lifecycle.d.ts +1 -0
- package/out/internal/lifecycle.luau +912 -0
- package/out/internal/log-output.d.ts +1 -0
- package/out/internal/log-output.luau +106 -0
- package/out/internal/network/catalog.d.ts +26 -0
- package/out/internal/network/catalog.luau +182 -0
- package/out/internal/network/claims.d.ts +1 -0
- package/out/internal/network/claims.luau +154 -0
- package/out/internal/network/client-session.d.ts +1 -0
- package/out/internal/network/client-session.luau +403 -0
- package/out/internal/network/codec.d.ts +63 -0
- package/out/internal/network/codec.luau +1183 -0
- package/out/internal/network/envelope.d.ts +1 -0
- package/out/internal/network/envelope.luau +247 -0
- package/out/internal/network/limits.d.ts +26 -0
- package/out/internal/network/limits.luau +55 -0
- package/out/internal/network/port.d.ts +1 -0
- package/out/internal/network/port.luau +19 -0
- package/out/internal/network/roblox-network-port.d.ts +1 -0
- package/out/internal/network/roblox-network-port.luau +105 -0
- package/out/internal/network/schema.d.ts +72 -0
- package/out/internal/network/schema.luau +386 -0
- package/out/internal/network/server-session.d.ts +1 -0
- package/out/internal/network/server-session.luau +393 -0
- package/out/internal/network/session.d.ts +1 -0
- package/out/internal/network/session.luau +266 -0
- package/out/internal/port.d.ts +1 -0
- package/out/internal/port.luau +12 -0
- package/out/internal/reactive/context.d.ts +1 -0
- package/out/internal/reactive/context.luau +149 -0
- package/out/internal/reactive/flush.d.ts +1 -0
- package/out/internal/reactive/flush.luau +355 -0
- package/out/internal/reactive/graph.d.ts +1 -0
- package/out/internal/reactive/graph.luau +626 -0
- package/out/internal/reactive/limits.d.ts +1 -0
- package/out/internal/reactive/limits.luau +54 -0
- package/out/internal/reactive/ownership.d.ts +1 -0
- package/out/internal/reactive/ownership.luau +626 -0
- package/out/internal/registry.d.ts +1 -0
- package/out/internal/registry.luau +455 -0
- package/out/internal/roblox-port.d.ts +1 -0
- package/out/internal/roblox-port.luau +117 -0
- package/out/internal/runner.d.ts +1 -0
- package/out/internal/runner.luau +86 -0
- package/out/internal/scheduler.d.ts +1 -0
- package/out/internal/scheduler.luau +207 -0
- package/out/internal/state.d.ts +1 -0
- package/out/internal/state.luau +41 -0
- package/out/internal/sync/client-sync.d.ts +1 -0
- package/out/internal/sync/client-sync.luau +157 -0
- package/out/internal/sync/declarations.d.ts +1 -0
- package/out/internal/sync/declarations.luau +276 -0
- package/out/internal/sync/frame.d.ts +1 -0
- package/out/internal/sync/frame.luau +91 -0
- package/out/internal/sync/server-sync.d.ts +1 -0
- package/out/internal/sync/server-sync.luau +502 -0
- package/out/internal/sync/values.d.ts +1 -0
- package/out/internal/sync/values.luau +930 -0
- package/out/log-level.d.ts +7 -0
- package/out/log-level.luau +21 -0
- package/out/logging.d.ts +34 -0
- package/out/logging.luau +233 -0
- package/out/network.d.ts +66 -0
- package/out/network.luau +24 -0
- package/out/reactive.d.ts +76 -0
- package/out/reactive.luau +136 -0
- package/out/replicated.d.ts +38 -0
- package/out/replicated.luau +45 -0
- package/out/server/data.d.ts +54 -0
- package/out/server/data.luau +44 -0
- package/out/server/index.d.ts +18 -0
- package/out/server/init.luau +62 -0
- package/out/server/publish.d.ts +20 -0
- package/out/server/publish.luau +24 -0
- package/out/subsystem.d.ts +4 -0
- package/out/subsystem.luau +30 -0
- package/out/vide/index.d.ts +7 -0
- package/out/vide/init.luau +50 -0
- package/package.json +52 -5
- package/server/package.json +4 -0
- package/transformer/data.cjs +72 -0
- package/transformer/declarations.cjs +153 -0
- package/transformer/diagnostics.cjs +19 -0
- package/transformer/index.js +741 -0
- package/transformer/network.cjs +961 -0
- package/transformer/type-id.cjs +80 -0
- package/vide/package.json +4 -0
- package/README.md +0 -3
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
-- Compiled with roblox-ts v3.0.0
|
|
2
|
+
local TS = _G[script]
|
|
3
|
+
local runtimeDiagnostic = TS.import(script, script.Parent.Parent, "diagnostics").runtimeDiagnostic
|
|
4
|
+
local _catalog = TS.import(script, script.Parent, "catalog")
|
|
5
|
+
local definitionAt = _catalog.definitionAt
|
|
6
|
+
local definitionOf = _catalog.definitionOf
|
|
7
|
+
local discardIndices = _catalog.discardIndices
|
|
8
|
+
local seal = _catalog.seal
|
|
9
|
+
local _claims = TS.import(script, script.Parent, "claims")
|
|
10
|
+
local closeClaims = _claims.closeClaims
|
|
11
|
+
local freezeClaims = _claims.freezeClaims
|
|
12
|
+
local isLive = _claims.isLive
|
|
13
|
+
local openClaims = _claims.openClaims
|
|
14
|
+
local readyClaims = _claims.readyClaims
|
|
15
|
+
local receiverOf = _claims.receiverOf
|
|
16
|
+
local _envelope = TS.import(script, script.Parent, "envelope")
|
|
17
|
+
local argumentCount = _envelope.argumentCount
|
|
18
|
+
local controlPacket = _envelope.controlPacket
|
|
19
|
+
local decodeBody = _envelope.decodeBody
|
|
20
|
+
local encodeBody = _envelope.encodeBody
|
|
21
|
+
local failureReason = _envelope.failureReason
|
|
22
|
+
local frame = _envelope.frame
|
|
23
|
+
local missingInstance = _envelope.missingInstance
|
|
24
|
+
local openBody = _envelope.openBody
|
|
25
|
+
local readHeader = _envelope.readHeader
|
|
26
|
+
local L = TS.import(script, script.Parent, "limits")
|
|
27
|
+
local _session = TS.import(script, script.Parent, "session")
|
|
28
|
+
local newPeer = _session.newPeer
|
|
29
|
+
local Session = _session.Session
|
|
30
|
+
local FAIL_NAMES = { "overflow", "overloaded", "closing", "malformed" }
|
|
31
|
+
--* @internal
|
|
32
|
+
local toClient
|
|
33
|
+
local ServerSession
|
|
34
|
+
do
|
|
35
|
+
local super = Session
|
|
36
|
+
ServerSession = setmetatable({}, {
|
|
37
|
+
__tostring = function()
|
|
38
|
+
return "ServerSession"
|
|
39
|
+
end,
|
|
40
|
+
__index = super,
|
|
41
|
+
})
|
|
42
|
+
ServerSession.__index = ServerSession
|
|
43
|
+
function ServerSession.new(...)
|
|
44
|
+
local self = setmetatable({}, ServerSession)
|
|
45
|
+
return self:constructor(...) or self
|
|
46
|
+
end
|
|
47
|
+
function ServerSession:constructor(...)
|
|
48
|
+
super.constructor(self, ...)
|
|
49
|
+
self.peers = {}
|
|
50
|
+
self.order = {}
|
|
51
|
+
self.connections = {}
|
|
52
|
+
self.catalog = ""
|
|
53
|
+
self.published = false
|
|
54
|
+
self.reportedNoPeer = false
|
|
55
|
+
end
|
|
56
|
+
function ServerSession:open()
|
|
57
|
+
self.stage = 1
|
|
58
|
+
openClaims({
|
|
59
|
+
side = "server",
|
|
60
|
+
retired = function(claim)
|
|
61
|
+
return self:retired(claim)
|
|
62
|
+
end,
|
|
63
|
+
})
|
|
64
|
+
self.port.create(function(player, ...)
|
|
65
|
+
local args = { ... }
|
|
66
|
+
return self:receive(player, argumentCount(args), args[1], args[2])
|
|
67
|
+
end)
|
|
68
|
+
local _connections = self.connections
|
|
69
|
+
local _arg0 = self.port.onPlayerAdded(function(player)
|
|
70
|
+
return self:add(player)
|
|
71
|
+
end)
|
|
72
|
+
table.insert(_connections, _arg0)
|
|
73
|
+
local _connections_1 = self.connections
|
|
74
|
+
local _arg0_1 = self.port.onPlayerRemoving(function(player)
|
|
75
|
+
local _peers = self.peers
|
|
76
|
+
local _player = player
|
|
77
|
+
local peer = _peers[_player]
|
|
78
|
+
if peer ~= nil then
|
|
79
|
+
self["end"](self, peer)
|
|
80
|
+
end
|
|
81
|
+
end)
|
|
82
|
+
table.insert(_connections_1, _arg0_1)
|
|
83
|
+
for _, player in self.port.players() do
|
|
84
|
+
self:add(player)
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
function ServerSession:loaded()
|
|
88
|
+
self.catalog = seal()
|
|
89
|
+
self.stage = 2
|
|
90
|
+
end
|
|
91
|
+
function ServerSession:commit()
|
|
92
|
+
freezeClaims()
|
|
93
|
+
self.port.publish(L.PROTOCOL_VERSION, self.catalog)
|
|
94
|
+
self.published = true
|
|
95
|
+
self.stage = 3
|
|
96
|
+
end
|
|
97
|
+
function ServerSession:close()
|
|
98
|
+
if self.stage == 4 then
|
|
99
|
+
return nil
|
|
100
|
+
end
|
|
101
|
+
local committed = self.stage == 3
|
|
102
|
+
self.stage = 4
|
|
103
|
+
local closing = controlPacket(5, {}, 2)
|
|
104
|
+
local _array = {}
|
|
105
|
+
local _length = #_array
|
|
106
|
+
local _array_1 = self.order
|
|
107
|
+
table.move(_array_1, 1, #_array_1, _length + 1, _array)
|
|
108
|
+
for _, peer in _array do
|
|
109
|
+
if self.published then
|
|
110
|
+
pcall(function()
|
|
111
|
+
return self:fire(peer, closing)
|
|
112
|
+
end)
|
|
113
|
+
end
|
|
114
|
+
pcall(function()
|
|
115
|
+
return self["end"](self, peer)
|
|
116
|
+
end)
|
|
117
|
+
end
|
|
118
|
+
for _, disconnect in self.connections do
|
|
119
|
+
pcall(disconnect)
|
|
120
|
+
end
|
|
121
|
+
table.clear(self.connections)
|
|
122
|
+
pcall(function()
|
|
123
|
+
return self.port.destroy()
|
|
124
|
+
end)
|
|
125
|
+
closeClaims(not committed)
|
|
126
|
+
if not committed then
|
|
127
|
+
discardIndices()
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
function ServerSession:send(player, token, value)
|
|
131
|
+
local sendable = self:sendable()
|
|
132
|
+
local definition = toClient(token, "Network.send")
|
|
133
|
+
local body = encodeBody(definition.name, definition.input, "payload", value)
|
|
134
|
+
if not sendable then
|
|
135
|
+
return false
|
|
136
|
+
end
|
|
137
|
+
local _peers = self.peers
|
|
138
|
+
local _player = player
|
|
139
|
+
local peer = _peers[_player]
|
|
140
|
+
return peer ~= nil and self:deliver(peer, frame(body, 0, { definition.index }))
|
|
141
|
+
end
|
|
142
|
+
function ServerSession:broadcast(token, value)
|
|
143
|
+
local sendable = self:sendable()
|
|
144
|
+
local definition = toClient(token, "Network.broadcast")
|
|
145
|
+
local body = encodeBody(definition.name, definition.input, "payload", value)
|
|
146
|
+
if not sendable then
|
|
147
|
+
return nil
|
|
148
|
+
end
|
|
149
|
+
local packet = frame(body, 0, { definition.index })
|
|
150
|
+
local _array = {}
|
|
151
|
+
local _length = #_array
|
|
152
|
+
local _array_1 = self.order
|
|
153
|
+
table.move(_array_1, 1, #_array_1, _length + 1, _array)
|
|
154
|
+
for _, peer in _array do
|
|
155
|
+
self:deliver(peer, packet)
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
function ServerSession:fire(peer, packet)
|
|
159
|
+
self.port.fireClient(peer.player, packet.bytes, packet.sidecar)
|
|
160
|
+
end
|
|
161
|
+
ServerSession["end"] = function(self, peer)
|
|
162
|
+
if peer.state == 2 then
|
|
163
|
+
return false
|
|
164
|
+
end
|
|
165
|
+
local player = peer.player
|
|
166
|
+
if self.peers[player] == peer then
|
|
167
|
+
self.peers[player] = nil
|
|
168
|
+
end
|
|
169
|
+
local _order = self.order
|
|
170
|
+
local _peer = peer
|
|
171
|
+
local index = (table.find(_order, _peer) or 0) - 1
|
|
172
|
+
if index ~= -1 then
|
|
173
|
+
table.remove(self.order, index + 1)
|
|
174
|
+
end
|
|
175
|
+
return super["end"](self, peer)
|
|
176
|
+
end
|
|
177
|
+
function ServerSession:fail(peer, reason)
|
|
178
|
+
if peer.state == 2 then
|
|
179
|
+
return nil
|
|
180
|
+
end
|
|
181
|
+
local player = peer.player
|
|
182
|
+
runtimeDiagnostic("error", `Crucible network peer {player.Name} failed ({FAIL_NAMES[reason + 1]}); kicking`)
|
|
183
|
+
local packet = controlPacket(5, {}, reason)
|
|
184
|
+
pcall(function()
|
|
185
|
+
return self:fire(peer, packet)
|
|
186
|
+
end)
|
|
187
|
+
self["end"](self, peer)
|
|
188
|
+
pcall(function()
|
|
189
|
+
return self.port.kick(player, L.KICK_MESSAGE)
|
|
190
|
+
end)
|
|
191
|
+
end
|
|
192
|
+
function ServerSession:add(player)
|
|
193
|
+
local _condition = self.stage == 4
|
|
194
|
+
if not _condition then
|
|
195
|
+
local _peers = self.peers
|
|
196
|
+
local _player = player
|
|
197
|
+
_condition = _peers[_player] ~= nil
|
|
198
|
+
end
|
|
199
|
+
if _condition then
|
|
200
|
+
return nil
|
|
201
|
+
end
|
|
202
|
+
local peer = newPeer(player)
|
|
203
|
+
local _peers = self.peers
|
|
204
|
+
local _player = player
|
|
205
|
+
_peers[_player] = peer
|
|
206
|
+
local _exp = self.order
|
|
207
|
+
table.insert(_exp, peer)
|
|
208
|
+
end
|
|
209
|
+
function ServerSession:retired(claim)
|
|
210
|
+
local cleanups = {}
|
|
211
|
+
for _, peer in self.order do
|
|
212
|
+
for _1, entry in peer.running do
|
|
213
|
+
local request = entry.request
|
|
214
|
+
if entry.claim ~= claim or request == nil or entry.settled then
|
|
215
|
+
continue
|
|
216
|
+
end
|
|
217
|
+
entry.settled = true
|
|
218
|
+
self:fire(peer, controlPacket(3, { request.definition.index, request.nonce }, 0))
|
|
219
|
+
end
|
|
220
|
+
for i = #peer.cleanups - 1, 0, -1 do
|
|
221
|
+
local entry = peer.cleanups[i + 1]
|
|
222
|
+
if entry.claim ~= claim then
|
|
223
|
+
continue
|
|
224
|
+
end
|
|
225
|
+
local _cleanups = peer.cleanups
|
|
226
|
+
local _i = i
|
|
227
|
+
table.remove(_cleanups, _i + 1)
|
|
228
|
+
local _arg0 = { peer, entry }
|
|
229
|
+
table.insert(cleanups, _arg0)
|
|
230
|
+
end
|
|
231
|
+
end
|
|
232
|
+
for _, _binding in cleanups do
|
|
233
|
+
local peer = _binding[1]
|
|
234
|
+
local entry = _binding[2]
|
|
235
|
+
self:deferCleanup(peer, entry)
|
|
236
|
+
end
|
|
237
|
+
end
|
|
238
|
+
function ServerSession:reject(peer, key, what, detail)
|
|
239
|
+
local _rejected = peer.rejected
|
|
240
|
+
local _key = key
|
|
241
|
+
if _rejected[_key] ~= nil then
|
|
242
|
+
return nil
|
|
243
|
+
end
|
|
244
|
+
local _rejected_1 = peer.rejected
|
|
245
|
+
local _key_1 = key
|
|
246
|
+
_rejected_1[_key_1] = true
|
|
247
|
+
local reason = if detail == nil then "" else `: {detail}`
|
|
248
|
+
runtimeDiagnostic("warning", `Crucible dropped {what} from {peer.player.Name}{reason}`)
|
|
249
|
+
end
|
|
250
|
+
function ServerSession:receive(player, count, packet, sidecar)
|
|
251
|
+
local ok, err = pcall(function()
|
|
252
|
+
return self:dispatch(player, count, packet, sidecar)
|
|
253
|
+
end)
|
|
254
|
+
if not ok then
|
|
255
|
+
runtimeDiagnostic("error", `Crucible network receive failed: {tostring(err)}`)
|
|
256
|
+
end
|
|
257
|
+
end
|
|
258
|
+
function ServerSession:dispatch(player, count, packet, sidecar)
|
|
259
|
+
local _peers = self.peers
|
|
260
|
+
local _player = player
|
|
261
|
+
local peer = _peers[_player]
|
|
262
|
+
if peer == nil then
|
|
263
|
+
if self.reportedNoPeer then
|
|
264
|
+
return nil
|
|
265
|
+
end
|
|
266
|
+
self.reportedNoPeer = true
|
|
267
|
+
runtimeDiagnostic("warning", "Crucible dropped a network packet from a player with no peer")
|
|
268
|
+
return nil
|
|
269
|
+
end
|
|
270
|
+
if self.stage ~= 3 then
|
|
271
|
+
return self:reject(peer, "envelope", "a packet before the network commit")
|
|
272
|
+
end
|
|
273
|
+
local header = readHeader(count, packet, sidecar)
|
|
274
|
+
if header == nil then
|
|
275
|
+
return self:reject(peer, "envelope", "a malformed network packet")
|
|
276
|
+
end
|
|
277
|
+
if header.opcode == 4 then
|
|
278
|
+
if peer.state ~= 0 then
|
|
279
|
+
return self:reject(peer, "envelope", "a second READY")
|
|
280
|
+
end
|
|
281
|
+
return self:ready(peer)
|
|
282
|
+
end
|
|
283
|
+
if header.opcode == 5 then
|
|
284
|
+
local _condition = FAIL_NAMES[header.reason + 1]
|
|
285
|
+
if _condition == nil then
|
|
286
|
+
_condition = `unknown reason {header.reason}`
|
|
287
|
+
end
|
|
288
|
+
local reason = _condition
|
|
289
|
+
runtimeDiagnostic("error", `Crucible network peer {player.Name} sent FAIL ({reason}); kicking`)
|
|
290
|
+
self["end"](self, peer)
|
|
291
|
+
pcall(function()
|
|
292
|
+
return self.port.kick(player, L.KICK_MESSAGE)
|
|
293
|
+
end)
|
|
294
|
+
return nil
|
|
295
|
+
end
|
|
296
|
+
if header.opcode ~= 0 and header.opcode ~= 1 then
|
|
297
|
+
return self:reject(peer, "envelope", "a server-to-client packet")
|
|
298
|
+
end
|
|
299
|
+
if peer.state ~= 1 then
|
|
300
|
+
return self:reject(peer, "envelope", "a game packet before READY")
|
|
301
|
+
end
|
|
302
|
+
local definition = definitionAt(header.index)
|
|
303
|
+
if definition == nil then
|
|
304
|
+
return self:reject(peer, "envelope", "an unknown message index")
|
|
305
|
+
end
|
|
306
|
+
local event = header.opcode == 0
|
|
307
|
+
if definition.kind ~= (if event then "to-server" else "ask-server") then
|
|
308
|
+
return self:reject(peer, definition, `{definition.name} sent as the wrong kind of packet`)
|
|
309
|
+
end
|
|
310
|
+
local opened, reader = pcall(openBody, packet, sidecar, header)
|
|
311
|
+
if not opened then
|
|
312
|
+
return self:reject(peer, definition, definition.name, failureReason(reader))
|
|
313
|
+
end
|
|
314
|
+
if header.opcode == 0 then
|
|
315
|
+
local decoded, value = pcall(decodeBody, definition.input, "payload", reader)
|
|
316
|
+
if not decoded then
|
|
317
|
+
if not missingInstance(value) then
|
|
318
|
+
self:reject(peer, definition, definition.name, failureReason(value))
|
|
319
|
+
end
|
|
320
|
+
return nil
|
|
321
|
+
end
|
|
322
|
+
local receiver = receiverOf(definition)
|
|
323
|
+
if receiver == nil then
|
|
324
|
+
return self:unreceived(definition)
|
|
325
|
+
end
|
|
326
|
+
if peer.counted >= L.MAX_ACTIVE_HANDLERS then
|
|
327
|
+
return self:fail(peer, 1)
|
|
328
|
+
end
|
|
329
|
+
return self:start(peer, receiver, { player, value })
|
|
330
|
+
end
|
|
331
|
+
local nonce = header.nonce
|
|
332
|
+
if nonce <= peer.lastRequestNonce then
|
|
333
|
+
return self:reject(peer, definition, `{definition.name} with a nonce already used`)
|
|
334
|
+
end
|
|
335
|
+
peer.lastRequestNonce = nonce
|
|
336
|
+
local refuse = function(reason)
|
|
337
|
+
return self:fire(peer, controlPacket(3, { header.index, nonce }, reason))
|
|
338
|
+
end
|
|
339
|
+
local decoded, value = pcall(decodeBody, definition.input, "request", reader)
|
|
340
|
+
if not decoded then
|
|
341
|
+
if not missingInstance(value) then
|
|
342
|
+
self:reject(peer, definition, definition.name, failureReason(value))
|
|
343
|
+
end
|
|
344
|
+
return refuse(3)
|
|
345
|
+
end
|
|
346
|
+
local receiver = receiverOf(definition)
|
|
347
|
+
if receiver == nil then
|
|
348
|
+
return refuse(0)
|
|
349
|
+
end
|
|
350
|
+
if peer.counted >= L.MAX_ACTIVE_HANDLERS then
|
|
351
|
+
return refuse(2)
|
|
352
|
+
end
|
|
353
|
+
self:start(peer, receiver, { player, value }, {
|
|
354
|
+
definition = definition,
|
|
355
|
+
nonce = nonce,
|
|
356
|
+
})
|
|
357
|
+
end
|
|
358
|
+
function ServerSession:ready(peer)
|
|
359
|
+
peer.state = 1
|
|
360
|
+
self:flush(peer)
|
|
361
|
+
local player = peer.player
|
|
362
|
+
for _, claim in readyClaims() do
|
|
363
|
+
if peer.state ~= 1 then
|
|
364
|
+
return nil
|
|
365
|
+
end
|
|
366
|
+
if not isLive(claim) then
|
|
367
|
+
continue
|
|
368
|
+
end
|
|
369
|
+
local ok, value = self:runReady(peer, claim, claim.callback, player)
|
|
370
|
+
if not ok then
|
|
371
|
+
continue
|
|
372
|
+
end
|
|
373
|
+
if type(value) == "function" then
|
|
374
|
+
self:keep(peer, {
|
|
375
|
+
claim = claim,
|
|
376
|
+
cleanup = value,
|
|
377
|
+
})
|
|
378
|
+
elseif value ~= nil then
|
|
379
|
+
self:reportCallback(peer, claim, nil, `returned a {typeof(value)}; ClientReady callbacks return nothing or a cleanup function`)
|
|
380
|
+
end
|
|
381
|
+
end
|
|
382
|
+
end
|
|
383
|
+
end
|
|
384
|
+
function toClient(token, call)
|
|
385
|
+
local definition = definitionOf(token)
|
|
386
|
+
if definition == nil or definition.kind ~= "to-client" then
|
|
387
|
+
error(`{call} needs a message declared with toClient`, 0)
|
|
388
|
+
end
|
|
389
|
+
return definition
|
|
390
|
+
end
|
|
391
|
+
return {
|
|
392
|
+
ServerSession = ServerSession,
|
|
393
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
-- Compiled with roblox-ts v3.0.0
|
|
2
|
+
local TS = _G[script]
|
|
3
|
+
local runtimeDiagnostic = TS.import(script, script.Parent.Parent, "diagnostics").runtimeDiagnostic
|
|
4
|
+
local _lifecycle = TS.import(script, script.Parent.Parent, "lifecycle")
|
|
5
|
+
local defer = _lifecycle.defer
|
|
6
|
+
local within = _lifecycle.within
|
|
7
|
+
local _runner = TS.import(script, script.Parent.Parent, "runner")
|
|
8
|
+
local disown = _runner.disown
|
|
9
|
+
local own = _runner.own
|
|
10
|
+
local isLive = TS.import(script, script.Parent, "claims").isLive
|
|
11
|
+
local _envelope = TS.import(script, script.Parent, "envelope")
|
|
12
|
+
local controlPacket = _envelope.controlPacket
|
|
13
|
+
local encodeBody = _envelope.encodeBody
|
|
14
|
+
local frame = _envelope.frame
|
|
15
|
+
local L = TS.import(script, script.Parent, "limits")
|
|
16
|
+
--* @internal
|
|
17
|
+
--* @internal
|
|
18
|
+
--* @internal
|
|
19
|
+
--* @internal
|
|
20
|
+
--* @internal
|
|
21
|
+
--* @internal
|
|
22
|
+
--* @internal
|
|
23
|
+
local function newPeer(player)
|
|
24
|
+
return {
|
|
25
|
+
player = player,
|
|
26
|
+
state = 0,
|
|
27
|
+
queue = {},
|
|
28
|
+
queuedBytes = 0,
|
|
29
|
+
running = {},
|
|
30
|
+
counted = 0,
|
|
31
|
+
lastRequestNonce = 0,
|
|
32
|
+
cleanups = {},
|
|
33
|
+
rejected = {},
|
|
34
|
+
failedClaims = {},
|
|
35
|
+
}
|
|
36
|
+
end
|
|
37
|
+
local function traceback(err)
|
|
38
|
+
return debug.traceback(tostring(err), 2)
|
|
39
|
+
end
|
|
40
|
+
local function invoke(callback, argument)
|
|
41
|
+
return callback(argument)
|
|
42
|
+
end
|
|
43
|
+
-- compiler-types 3.0.0-types.0 does not declare Promise.is; the RuntimeLib's TS.Promise has it.
|
|
44
|
+
local function isPromise(value)
|
|
45
|
+
return (TS.Promise).is(value)
|
|
46
|
+
end
|
|
47
|
+
--* @internal
|
|
48
|
+
local Session
|
|
49
|
+
do
|
|
50
|
+
Session = {}
|
|
51
|
+
function Session:constructor(port)
|
|
52
|
+
self.port = port
|
|
53
|
+
self.stage = 0
|
|
54
|
+
self.lateFailures = {}
|
|
55
|
+
self.noReceiver = {}
|
|
56
|
+
end
|
|
57
|
+
function Session:sendable()
|
|
58
|
+
if self.stage == 0 or self.stage == 1 then
|
|
59
|
+
error("Crucible networking is not ready; send from a constructor, a hook, or later", 0)
|
|
60
|
+
end
|
|
61
|
+
return self.stage ~= 4
|
|
62
|
+
end
|
|
63
|
+
function Session:deliver(peer, packet)
|
|
64
|
+
if peer.state == 1 then
|
|
65
|
+
self:fire(peer, packet)
|
|
66
|
+
return true
|
|
67
|
+
end
|
|
68
|
+
if peer.state == 2 then
|
|
69
|
+
return false
|
|
70
|
+
end
|
|
71
|
+
if #peer.queue >= L.MAX_QUEUED_PACKETS or packet.charge > L.MAX_QUEUED_BYTES - peer.queuedBytes then
|
|
72
|
+
self:fail(peer, 0)
|
|
73
|
+
return false
|
|
74
|
+
end
|
|
75
|
+
local _queue = peer.queue
|
|
76
|
+
local _packet = packet
|
|
77
|
+
table.insert(_queue, _packet)
|
|
78
|
+
peer.queuedBytes += packet.charge
|
|
79
|
+
return true
|
|
80
|
+
end
|
|
81
|
+
function Session:flush(peer)
|
|
82
|
+
local _array = {}
|
|
83
|
+
local _length = #_array
|
|
84
|
+
local _array_1 = peer.queue
|
|
85
|
+
table.move(_array_1, 1, #_array_1, _length + 1, _array)
|
|
86
|
+
local queue = _array
|
|
87
|
+
table.clear(peer.queue)
|
|
88
|
+
peer.queuedBytes = 0
|
|
89
|
+
for _, packet in queue do
|
|
90
|
+
self:fire(peer, packet)
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
function Session:start(peer, claim, args, request)
|
|
94
|
+
local entry = {
|
|
95
|
+
claim = claim,
|
|
96
|
+
request = request,
|
|
97
|
+
done = false,
|
|
98
|
+
counted = true,
|
|
99
|
+
settled = false,
|
|
100
|
+
reported = false,
|
|
101
|
+
}
|
|
102
|
+
local _exp = peer.running
|
|
103
|
+
table.insert(_exp, entry)
|
|
104
|
+
peer.counted += 1
|
|
105
|
+
local thread = coroutine.create(function()
|
|
106
|
+
local ok, value = xpcall(claim.callback, traceback, unpack(args))
|
|
107
|
+
disown(coroutine.running())
|
|
108
|
+
self:finish(peer, entry, ok, value)
|
|
109
|
+
end)
|
|
110
|
+
own(thread, claim.owner)
|
|
111
|
+
self.port.resume(thread)
|
|
112
|
+
if not entry.done and peer.state ~= 2 then
|
|
113
|
+
entry.lifetime = self.port.delay(L.HANDLER_LIFETIME_SECONDS, function()
|
|
114
|
+
return self:overrun(peer, entry)
|
|
115
|
+
end)
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
function Session:uncount(peer, entry)
|
|
119
|
+
if not entry.counted then
|
|
120
|
+
return nil
|
|
121
|
+
end
|
|
122
|
+
entry.counted = false
|
|
123
|
+
peer.counted -= 1
|
|
124
|
+
end
|
|
125
|
+
function Session:overrun(peer, entry)
|
|
126
|
+
entry.lifetime = nil
|
|
127
|
+
if entry.done then
|
|
128
|
+
return nil
|
|
129
|
+
end
|
|
130
|
+
self:reportCallback(peer, entry.claim, entry, `still running after {L.HANDLER_LIFETIME_SECONDS} seconds`)
|
|
131
|
+
self:uncount(peer, entry)
|
|
132
|
+
end
|
|
133
|
+
function Session:finish(peer, entry, ok, value)
|
|
134
|
+
entry.done = true
|
|
135
|
+
local _result = entry.lifetime
|
|
136
|
+
if _result ~= nil then
|
|
137
|
+
_result()
|
|
138
|
+
end
|
|
139
|
+
entry.lifetime = nil
|
|
140
|
+
local _running = peer.running
|
|
141
|
+
local _entry = entry
|
|
142
|
+
local index = (table.find(_running, _entry) or 0) - 1
|
|
143
|
+
if index ~= -1 then
|
|
144
|
+
table.remove(peer.running, index + 1)
|
|
145
|
+
end
|
|
146
|
+
self:uncount(peer, entry)
|
|
147
|
+
local failure
|
|
148
|
+
local request = entry.request
|
|
149
|
+
if not ok then
|
|
150
|
+
failure = tostring(value)
|
|
151
|
+
elseif request == nil then
|
|
152
|
+
if value ~= nil then
|
|
153
|
+
local _value = value
|
|
154
|
+
failure = `returned a {typeof(_value)}; event callbacks return nothing`
|
|
155
|
+
end
|
|
156
|
+
elseif isPromise(value) then
|
|
157
|
+
failure = "returned a Promise; request callbacks return the response"
|
|
158
|
+
end
|
|
159
|
+
local replies = request ~= nil and not entry.settled and peer.state ~= 2
|
|
160
|
+
local packet
|
|
161
|
+
if replies and failure == nil then
|
|
162
|
+
local _binding = request
|
|
163
|
+
local definition = _binding.definition
|
|
164
|
+
local nonce = _binding.nonce
|
|
165
|
+
local encoded, result = pcall(function()
|
|
166
|
+
return frame(encodeBody(definition.name, definition.output, "response", value), 2, { definition.index, nonce })
|
|
167
|
+
end)
|
|
168
|
+
if encoded then
|
|
169
|
+
packet = result
|
|
170
|
+
else
|
|
171
|
+
failure = tostring(result)
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
if failure ~= nil then
|
|
175
|
+
self:reportCallback(peer, entry.claim, entry, failure)
|
|
176
|
+
end
|
|
177
|
+
if not replies then
|
|
178
|
+
return nil
|
|
179
|
+
end
|
|
180
|
+
entry.settled = true
|
|
181
|
+
self:fire(peer, packet or controlPacket(3, { request.definition.index, request.nonce }, 1))
|
|
182
|
+
end
|
|
183
|
+
function Session:reportCallback(peer, claim, entry, message)
|
|
184
|
+
if entry ~= nil then
|
|
185
|
+
if entry.reported then
|
|
186
|
+
return nil
|
|
187
|
+
end
|
|
188
|
+
entry.reported = true
|
|
189
|
+
end
|
|
190
|
+
local player = peer.player
|
|
191
|
+
local live = player ~= nil and peer.state ~= 2
|
|
192
|
+
local seen = if live then peer.failedClaims else self.lateFailures
|
|
193
|
+
local _claim = claim
|
|
194
|
+
if seen[_claim] ~= nil then
|
|
195
|
+
return nil
|
|
196
|
+
end
|
|
197
|
+
local _claim_1 = claim
|
|
198
|
+
seen[_claim_1] = true
|
|
199
|
+
runtimeDiagnostic("error", `{claim.label}{if live then ` for {player.Name}` else ""} failed: {message}`)
|
|
200
|
+
end
|
|
201
|
+
function Session:runReady(peer, claim, work, argument)
|
|
202
|
+
local result, value = within(claim.owner, nil, 8, invoke, work, argument)
|
|
203
|
+
if result == 0 then
|
|
204
|
+
return true, value
|
|
205
|
+
end
|
|
206
|
+
self:reportCallback(peer, claim, nil, tostring(value))
|
|
207
|
+
return false, nil
|
|
208
|
+
end
|
|
209
|
+
function Session:deferCleanup(peer, entry)
|
|
210
|
+
defer(function()
|
|
211
|
+
return self:runReady(peer, entry.claim, entry.cleanup, nil)
|
|
212
|
+
end)
|
|
213
|
+
end
|
|
214
|
+
function Session:keep(peer, entry)
|
|
215
|
+
if isLive(entry.claim) and peer.state == 1 then
|
|
216
|
+
local _cleanups = peer.cleanups
|
|
217
|
+
local _entry = entry
|
|
218
|
+
table.insert(_cleanups, _entry)
|
|
219
|
+
else
|
|
220
|
+
self:deferCleanup(peer, entry)
|
|
221
|
+
end
|
|
222
|
+
end
|
|
223
|
+
Session["end"] = function(self, peer)
|
|
224
|
+
if peer.state == 2 then
|
|
225
|
+
return false
|
|
226
|
+
end
|
|
227
|
+
peer.state = 2
|
|
228
|
+
table.clear(peer.queue)
|
|
229
|
+
peer.queuedBytes = 0
|
|
230
|
+
for _, entry in peer.running do
|
|
231
|
+
local _result = entry.lifetime
|
|
232
|
+
if _result ~= nil then
|
|
233
|
+
_result()
|
|
234
|
+
end
|
|
235
|
+
entry.lifetime = nil
|
|
236
|
+
end
|
|
237
|
+
table.clear(peer.running)
|
|
238
|
+
table.clear(peer.rejected)
|
|
239
|
+
table.clear(peer.failedClaims)
|
|
240
|
+
local _array = {}
|
|
241
|
+
local _length = #_array
|
|
242
|
+
local _array_1 = peer.cleanups
|
|
243
|
+
table.move(_array_1, 1, #_array_1, _length + 1, _array)
|
|
244
|
+
local cleanups = _array
|
|
245
|
+
table.clear(peer.cleanups)
|
|
246
|
+
for i = #cleanups - 1, 0, -1 do
|
|
247
|
+
self:deferCleanup(peer, cleanups[i + 1])
|
|
248
|
+
end
|
|
249
|
+
return true
|
|
250
|
+
end
|
|
251
|
+
function Session:unreceived(definition)
|
|
252
|
+
local _noReceiver = self.noReceiver
|
|
253
|
+
local _definition = definition
|
|
254
|
+
if _noReceiver[_definition] ~= nil then
|
|
255
|
+
return nil
|
|
256
|
+
end
|
|
257
|
+
local _noReceiver_1 = self.noReceiver
|
|
258
|
+
local _definition_1 = definition
|
|
259
|
+
_noReceiver_1[_definition_1] = true
|
|
260
|
+
runtimeDiagnostic("warning", `Crucible dropped {definition.name}: it has no live receiver`)
|
|
261
|
+
end
|
|
262
|
+
end
|
|
263
|
+
return {
|
|
264
|
+
newPeer = newPeer,
|
|
265
|
+
Session = Session,
|
|
266
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
-- Compiled with roblox-ts v3.0.0
|
|
2
|
+
--* @internal Ends one engine subscription. Idempotent.
|
|
3
|
+
--* @internal The RunService events the scheduler connects. `BindToRenderStep` lanes have their own entry.
|
|
4
|
+
--[[
|
|
5
|
+
*
|
|
6
|
+
* @internal
|
|
7
|
+
* Everything the runtime asks of the engine. Coroutine functions are not here: they are the Luau language,
|
|
8
|
+
* identical in Roblox and Lune. The runner cancels a yielded worker with `task.cancel` itself, because the pool
|
|
9
|
+
* works before any port is installed.
|
|
10
|
+
|
|
11
|
+
]]
|
|
12
|
+
return nil
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|