@trioforge/crucible 0.1.0 → 0.3.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.
Files changed (145) hide show
  1. package/maths/spline/package.json +4 -0
  2. package/out/client/index.d.ts +7 -0
  3. package/out/client/init.luau +36 -1
  4. package/out/configs.d.ts +37 -0
  5. package/out/configs.luau +46 -0
  6. package/out/data.d.ts +224 -0
  7. package/out/data.luau +97 -0
  8. package/out/emit/configs.d.ts +4 -0
  9. package/out/emit/configs.luau +22 -0
  10. package/out/emit/data.d.ts +6 -0
  11. package/out/emit/data.luau +19 -0
  12. package/out/emit/index.d.ts +5 -1
  13. package/out/emit/init.luau +23 -7
  14. package/out/emit/network.d.ts +6 -0
  15. package/out/emit/network.luau +36 -0
  16. package/out/emit/replicated.d.ts +4 -0
  17. package/out/emit/replicated.luau +13 -0
  18. package/out/index.d.ts +8 -0
  19. package/out/init.luau +23 -0
  20. package/out/internal/binding.luau +5 -0
  21. package/out/internal/boot.luau +112 -8
  22. package/out/internal/configs/limits.d.ts +10 -0
  23. package/out/internal/configs/limits.luau +25 -0
  24. package/out/internal/configs/port.d.ts +29 -0
  25. package/out/internal/configs/port.luau +99 -0
  26. package/out/internal/configs/runtime.d.ts +21 -0
  27. package/out/internal/configs/runtime.luau +981 -0
  28. package/out/internal/data/admission.d.ts +1 -0
  29. package/out/internal/data/admission.luau +673 -0
  30. package/out/internal/data/declarations.d.ts +1 -0
  31. package/out/internal/data/declarations.luau +384 -0
  32. package/out/internal/data/envelope.d.ts +1 -0
  33. package/out/internal/data/envelope.luau +318 -0
  34. package/out/internal/data/handles.d.ts +1 -0
  35. package/out/internal/data/handles.luau +255 -0
  36. package/out/internal/data/inbox-transforms.d.ts +1 -0
  37. package/out/internal/data/inbox-transforms.luau +458 -0
  38. package/out/internal/data/inbox.d.ts +1 -0
  39. package/out/internal/data/inbox.luau +437 -0
  40. package/out/internal/data/lease.d.ts +1 -0
  41. package/out/internal/data/lease.luau +304 -0
  42. package/out/internal/data/limits.d.ts +1 -0
  43. package/out/internal/data/limits.luau +234 -0
  44. package/out/internal/data/messages.d.ts +1 -0
  45. package/out/internal/data/messages.luau +69 -0
  46. package/out/internal/data/operation-id.d.ts +1 -0
  47. package/out/internal/data/operation-id.luau +61 -0
  48. package/out/internal/data/paths.d.ts +2 -0
  49. package/out/internal/data/paths.luau +323 -0
  50. package/out/internal/data/port.d.ts +1 -0
  51. package/out/internal/data/port.luau +290 -0
  52. package/out/internal/data/profiles.d.ts +1 -0
  53. package/out/internal/data/profiles.luau +862 -0
  54. package/out/internal/data/receipts.d.ts +1 -0
  55. package/out/internal/data/receipts.luau +190 -0
  56. package/out/internal/data/record-bindings.d.ts +1 -0
  57. package/out/internal/data/record-bindings.luau +92 -0
  58. package/out/internal/data/record-declarations.d.ts +1 -0
  59. package/out/internal/data/record-declarations.luau +140 -0
  60. package/out/internal/data/records.d.ts +1 -0
  61. package/out/internal/data/records.luau +400 -0
  62. package/out/internal/data/runtime.d.ts +1 -0
  63. package/out/internal/data/runtime.luau +918 -0
  64. package/out/internal/data/scheduler.d.ts +1 -0
  65. package/out/internal/data/scheduler.luau +507 -0
  66. package/out/internal/data/session.d.ts +1 -0
  67. package/out/internal/data/session.luau +234 -0
  68. package/out/internal/data/shutdown.d.ts +1 -0
  69. package/out/internal/data/shutdown.luau +91 -0
  70. package/out/internal/data/waiters.d.ts +1 -0
  71. package/out/internal/data/waiters.luau +65 -0
  72. package/out/internal/lifecycle.luau +45 -0
  73. package/out/internal/network/catalog.d.ts +26 -0
  74. package/out/internal/network/catalog.luau +182 -0
  75. package/out/internal/network/claims.d.ts +1 -0
  76. package/out/internal/network/claims.luau +146 -0
  77. package/out/internal/network/client-session.d.ts +1 -0
  78. package/out/internal/network/client-session.luau +405 -0
  79. package/out/internal/network/codec.d.ts +63 -0
  80. package/out/internal/network/codec.luau +1183 -0
  81. package/out/internal/network/envelope.d.ts +1 -0
  82. package/out/internal/network/envelope.luau +247 -0
  83. package/out/internal/network/limits.d.ts +26 -0
  84. package/out/internal/network/limits.luau +55 -0
  85. package/out/internal/network/port.d.ts +1 -0
  86. package/out/internal/network/port.luau +19 -0
  87. package/out/internal/network/roblox-network-port.d.ts +1 -0
  88. package/out/internal/network/roblox-network-port.luau +105 -0
  89. package/out/internal/network/schema.d.ts +72 -0
  90. package/out/internal/network/schema.luau +386 -0
  91. package/out/internal/network/server-session.d.ts +1 -0
  92. package/out/internal/network/server-session.luau +395 -0
  93. package/out/internal/network/session.d.ts +1 -0
  94. package/out/internal/network/session.luau +266 -0
  95. package/out/internal/reactive/context.d.ts +1 -0
  96. package/out/internal/reactive/context.luau +149 -0
  97. package/out/internal/reactive/flush.d.ts +1 -0
  98. package/out/internal/reactive/flush.luau +355 -0
  99. package/out/internal/reactive/graph.d.ts +1 -0
  100. package/out/internal/reactive/graph.luau +626 -0
  101. package/out/internal/reactive/limits.d.ts +1 -0
  102. package/out/internal/reactive/limits.luau +54 -0
  103. package/out/internal/reactive/ownership.d.ts +1 -0
  104. package/out/internal/reactive/ownership.luau +626 -0
  105. package/out/internal/registry.luau +10 -1
  106. package/out/internal/sync/client-sync.d.ts +1 -0
  107. package/out/internal/sync/client-sync.luau +157 -0
  108. package/out/internal/sync/declarations.d.ts +1 -0
  109. package/out/internal/sync/declarations.luau +276 -0
  110. package/out/internal/sync/frame.d.ts +1 -0
  111. package/out/internal/sync/frame.luau +91 -0
  112. package/out/internal/sync/server-sync.d.ts +1 -0
  113. package/out/internal/sync/server-sync.luau +502 -0
  114. package/out/internal/sync/values.d.ts +1 -0
  115. package/out/internal/sync/values.luau +930 -0
  116. package/out/maths/spline/curve.d.ts +35 -0
  117. package/out/maths/spline/curve.luau +1122 -0
  118. package/out/maths/spline/index.d.ts +2 -0
  119. package/out/maths/spline/init.luau +8 -0
  120. package/out/network.d.ts +66 -0
  121. package/out/network.luau +24 -0
  122. package/out/reactive.d.ts +76 -0
  123. package/out/reactive.luau +136 -0
  124. package/out/replicated.d.ts +38 -0
  125. package/out/replicated.luau +45 -0
  126. package/out/server/data.d.ts +54 -0
  127. package/out/server/data.luau +44 -0
  128. package/out/server/index.d.ts +17 -0
  129. package/out/server/init.luau +58 -4
  130. package/out/server/publish.d.ts +20 -0
  131. package/out/server/publish.luau +24 -0
  132. package/out/testing/index.d.ts +38 -0
  133. package/out/testing/init.luau +189 -0
  134. package/out/util/random/index.d.ts +24 -0
  135. package/out/util/random/init.luau +301 -0
  136. package/out/vide/index.d.ts +7 -0
  137. package/out/vide/init.luau +50 -0
  138. package/package.json +28 -2
  139. package/testing/package.json +4 -0
  140. package/transformer/data.cjs +72 -0
  141. package/transformer/declarations.cjs +153 -0
  142. package/transformer/index.js +87 -23
  143. package/transformer/network.cjs +961 -0
  144. package/util/random/package.json +4 -0
  145. package/vide/package.json +4 -0
@@ -0,0 +1,395 @@
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 = function()
60
+ return "server"
61
+ end,
62
+ retired = function(claim)
63
+ return self:retired(claim)
64
+ end,
65
+ })
66
+ self.port.create(function(player, ...)
67
+ local args = { ... }
68
+ return self:receive(player, argumentCount(args), args[1], args[2])
69
+ end)
70
+ local _connections = self.connections
71
+ local _arg0 = self.port.onPlayerAdded(function(player)
72
+ return self:add(player)
73
+ end)
74
+ table.insert(_connections, _arg0)
75
+ local _connections_1 = self.connections
76
+ local _arg0_1 = self.port.onPlayerRemoving(function(player)
77
+ local _peers = self.peers
78
+ local _player = player
79
+ local peer = _peers[_player]
80
+ if peer ~= nil then
81
+ self["end"](self, peer)
82
+ end
83
+ end)
84
+ table.insert(_connections_1, _arg0_1)
85
+ for _, player in self.port.players() do
86
+ self:add(player)
87
+ end
88
+ end
89
+ function ServerSession:loaded()
90
+ self.catalog = seal()
91
+ self.stage = 2
92
+ end
93
+ function ServerSession:commit()
94
+ freezeClaims()
95
+ self.port.publish(L.PROTOCOL_VERSION, self.catalog)
96
+ self.published = true
97
+ self.stage = 3
98
+ end
99
+ function ServerSession:close()
100
+ if self.stage == 4 then
101
+ return nil
102
+ end
103
+ local committed = self.stage == 3
104
+ self.stage = 4
105
+ local closing = controlPacket(5, {}, 2)
106
+ local _array = {}
107
+ local _length = #_array
108
+ local _array_1 = self.order
109
+ table.move(_array_1, 1, #_array_1, _length + 1, _array)
110
+ for _, peer in _array do
111
+ if self.published then
112
+ pcall(function()
113
+ return self:fire(peer, closing)
114
+ end)
115
+ end
116
+ pcall(function()
117
+ return self["end"](self, peer)
118
+ end)
119
+ end
120
+ for _, disconnect in self.connections do
121
+ pcall(disconnect)
122
+ end
123
+ table.clear(self.connections)
124
+ pcall(function()
125
+ return self.port.destroy()
126
+ end)
127
+ closeClaims(not committed)
128
+ if not committed then
129
+ discardIndices()
130
+ end
131
+ end
132
+ function ServerSession:send(player, token, value)
133
+ local sendable = self:sendable()
134
+ local definition = toClient(token, "Network.send")
135
+ local body = encodeBody(definition.name, definition.input, "payload", value)
136
+ if not sendable then
137
+ return false
138
+ end
139
+ local _peers = self.peers
140
+ local _player = player
141
+ local peer = _peers[_player]
142
+ return peer ~= nil and self:deliver(peer, frame(body, 0, { definition.index }))
143
+ end
144
+ function ServerSession:broadcast(token, value)
145
+ local sendable = self:sendable()
146
+ local definition = toClient(token, "Network.broadcast")
147
+ local body = encodeBody(definition.name, definition.input, "payload", value)
148
+ if not sendable then
149
+ return nil
150
+ end
151
+ local packet = frame(body, 0, { definition.index })
152
+ local _array = {}
153
+ local _length = #_array
154
+ local _array_1 = self.order
155
+ table.move(_array_1, 1, #_array_1, _length + 1, _array)
156
+ for _, peer in _array do
157
+ self:deliver(peer, packet)
158
+ end
159
+ end
160
+ function ServerSession:fire(peer, packet)
161
+ self.port.fireClient(peer.player, packet.bytes, packet.sidecar)
162
+ end
163
+ ServerSession["end"] = function(self, peer)
164
+ if peer.state == 2 then
165
+ return false
166
+ end
167
+ local player = peer.player
168
+ if self.peers[player] == peer then
169
+ self.peers[player] = nil
170
+ end
171
+ local _order = self.order
172
+ local _peer = peer
173
+ local index = (table.find(_order, _peer) or 0) - 1
174
+ if index ~= -1 then
175
+ table.remove(self.order, index + 1)
176
+ end
177
+ return super["end"](self, peer)
178
+ end
179
+ function ServerSession:fail(peer, reason)
180
+ if peer.state == 2 then
181
+ return nil
182
+ end
183
+ local player = peer.player
184
+ runtimeDiagnostic("error", `Crucible network peer {player.Name} failed ({FAIL_NAMES[reason + 1]}); kicking`)
185
+ local packet = controlPacket(5, {}, reason)
186
+ pcall(function()
187
+ return self:fire(peer, packet)
188
+ end)
189
+ self["end"](self, peer)
190
+ pcall(function()
191
+ return self.port.kick(player, L.KICK_MESSAGE)
192
+ end)
193
+ end
194
+ function ServerSession:add(player)
195
+ local _condition = self.stage == 4
196
+ if not _condition then
197
+ local _peers = self.peers
198
+ local _player = player
199
+ _condition = _peers[_player] ~= nil
200
+ end
201
+ if _condition then
202
+ return nil
203
+ end
204
+ local peer = newPeer(player)
205
+ local _peers = self.peers
206
+ local _player = player
207
+ _peers[_player] = peer
208
+ local _exp = self.order
209
+ table.insert(_exp, peer)
210
+ end
211
+ function ServerSession:retired(claim)
212
+ local cleanups = {}
213
+ for _, peer in self.order do
214
+ for _1, entry in peer.running do
215
+ local request = entry.request
216
+ if entry.claim ~= claim or request == nil or entry.settled then
217
+ continue
218
+ end
219
+ entry.settled = true
220
+ self:fire(peer, controlPacket(3, { request.definition.index, request.nonce }, 0))
221
+ end
222
+ for i = #peer.cleanups - 1, 0, -1 do
223
+ local entry = peer.cleanups[i + 1]
224
+ if entry.claim ~= claim then
225
+ continue
226
+ end
227
+ local _cleanups = peer.cleanups
228
+ local _i = i
229
+ table.remove(_cleanups, _i + 1)
230
+ local _arg0 = { peer, entry }
231
+ table.insert(cleanups, _arg0)
232
+ end
233
+ end
234
+ for _, _binding in cleanups do
235
+ local peer = _binding[1]
236
+ local entry = _binding[2]
237
+ self:deferCleanup(peer, entry)
238
+ end
239
+ end
240
+ function ServerSession:reject(peer, key, what, detail)
241
+ local _rejected = peer.rejected
242
+ local _key = key
243
+ if _rejected[_key] ~= nil then
244
+ return nil
245
+ end
246
+ local _rejected_1 = peer.rejected
247
+ local _key_1 = key
248
+ _rejected_1[_key_1] = true
249
+ local reason = if detail == nil then "" else `: {detail}`
250
+ runtimeDiagnostic("warning", `Crucible dropped {what} from {peer.player.Name}{reason}`)
251
+ end
252
+ function ServerSession:receive(player, count, packet, sidecar)
253
+ local ok, err = pcall(function()
254
+ return self:dispatch(player, count, packet, sidecar)
255
+ end)
256
+ if not ok then
257
+ runtimeDiagnostic("error", `Crucible network receive failed: {tostring(err)}`)
258
+ end
259
+ end
260
+ function ServerSession:dispatch(player, count, packet, sidecar)
261
+ local _peers = self.peers
262
+ local _player = player
263
+ local peer = _peers[_player]
264
+ if peer == nil then
265
+ if self.reportedNoPeer then
266
+ return nil
267
+ end
268
+ self.reportedNoPeer = true
269
+ runtimeDiagnostic("warning", "Crucible dropped a network packet from a player with no peer")
270
+ return nil
271
+ end
272
+ if self.stage ~= 3 then
273
+ return self:reject(peer, "envelope", "a packet before the network commit")
274
+ end
275
+ local header = readHeader(count, packet, sidecar)
276
+ if header == nil then
277
+ return self:reject(peer, "envelope", "a malformed network packet")
278
+ end
279
+ if header.opcode == 4 then
280
+ if peer.state ~= 0 then
281
+ return self:reject(peer, "envelope", "a second READY")
282
+ end
283
+ return self:ready(peer)
284
+ end
285
+ if header.opcode == 5 then
286
+ local _condition = FAIL_NAMES[header.reason + 1]
287
+ if _condition == nil then
288
+ _condition = `unknown reason {header.reason}`
289
+ end
290
+ local reason = _condition
291
+ runtimeDiagnostic("error", `Crucible network peer {player.Name} sent FAIL ({reason}); kicking`)
292
+ self["end"](self, peer)
293
+ pcall(function()
294
+ return self.port.kick(player, L.KICK_MESSAGE)
295
+ end)
296
+ return nil
297
+ end
298
+ if header.opcode ~= 0 and header.opcode ~= 1 then
299
+ return self:reject(peer, "envelope", "a server-to-client packet")
300
+ end
301
+ if peer.state ~= 1 then
302
+ return self:reject(peer, "envelope", "a game packet before READY")
303
+ end
304
+ local definition = definitionAt(header.index)
305
+ if definition == nil then
306
+ return self:reject(peer, "envelope", "an unknown message index")
307
+ end
308
+ local event = header.opcode == 0
309
+ if definition.kind ~= (if event then "to-server" else "ask-server") then
310
+ return self:reject(peer, definition, `{definition.name} sent as the wrong kind of packet`)
311
+ end
312
+ local opened, reader = pcall(openBody, packet, sidecar, header)
313
+ if not opened then
314
+ return self:reject(peer, definition, definition.name, failureReason(reader))
315
+ end
316
+ if header.opcode == 0 then
317
+ local decoded, value = pcall(decodeBody, definition.input, "payload", reader)
318
+ if not decoded then
319
+ if not missingInstance(value) then
320
+ self:reject(peer, definition, definition.name, failureReason(value))
321
+ end
322
+ return nil
323
+ end
324
+ local receiver = receiverOf(definition)
325
+ if receiver == nil then
326
+ return self:unreceived(definition)
327
+ end
328
+ if peer.counted >= L.MAX_ACTIVE_HANDLERS then
329
+ return self:fail(peer, 1)
330
+ end
331
+ return self:start(peer, receiver, { player, value })
332
+ end
333
+ local nonce = header.nonce
334
+ if nonce <= peer.lastRequestNonce then
335
+ return self:reject(peer, definition, `{definition.name} with a nonce already used`)
336
+ end
337
+ peer.lastRequestNonce = nonce
338
+ local refuse = function(reason)
339
+ return self:fire(peer, controlPacket(3, { header.index, nonce }, reason))
340
+ end
341
+ local decoded, value = pcall(decodeBody, definition.input, "request", reader)
342
+ if not decoded then
343
+ if not missingInstance(value) then
344
+ self:reject(peer, definition, definition.name, failureReason(value))
345
+ end
346
+ return refuse(3)
347
+ end
348
+ local receiver = receiverOf(definition)
349
+ if receiver == nil then
350
+ return refuse(0)
351
+ end
352
+ if peer.counted >= L.MAX_ACTIVE_HANDLERS then
353
+ return refuse(2)
354
+ end
355
+ self:start(peer, receiver, { player, value }, {
356
+ definition = definition,
357
+ nonce = nonce,
358
+ })
359
+ end
360
+ function ServerSession:ready(peer)
361
+ peer.state = 1
362
+ self:flush(peer)
363
+ local player = peer.player
364
+ for _, claim in readyClaims() do
365
+ if peer.state ~= 1 then
366
+ return nil
367
+ end
368
+ if not isLive(claim) then
369
+ continue
370
+ end
371
+ local ok, value = self:runReady(peer, claim, claim.callback, player)
372
+ if not ok then
373
+ continue
374
+ end
375
+ if type(value) == "function" then
376
+ self:keep(peer, {
377
+ claim = claim,
378
+ cleanup = value,
379
+ })
380
+ elseif value ~= nil then
381
+ self:reportCallback(peer, claim, nil, `returned a {typeof(value)}; ClientReady callbacks return nothing or a cleanup function`)
382
+ end
383
+ end
384
+ end
385
+ end
386
+ function toClient(token, call)
387
+ local definition = definitionOf(token)
388
+ if definition == nil or definition.kind ~= "to-client" then
389
+ error(`{call} needs a message declared with toClient`, 0)
390
+ end
391
+ return definition
392
+ end
393
+ return {
394
+ ServerSession = ServerSession,
395
+ }
@@ -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 {};