@axpecter/lync 2.3.2 → 3.0.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 (135) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +302 -299
  3. package/Types.luau +215 -0
  4. package/api/Define.luau +154 -0
  5. package/api/Lifecycle.luau +119 -0
  6. package/api/Packet.luau +108 -0
  7. package/api/Query.luau +149 -0
  8. package/api/Set.luau +189 -0
  9. package/channel/Blocks.luau +124 -0
  10. package/channel/Group.luau +118 -0
  11. package/channel/Link.luau +135 -0
  12. package/channel/Outbox.luau +261 -0
  13. package/channel/Recipients.luau +129 -0
  14. package/channel/Transport.luau +138 -0
  15. package/codec/Base.luau +236 -0
  16. package/codec/Composites.luau +128 -0
  17. package/codec/Datatypes.luau +162 -0
  18. package/codec/Legality.luau +61 -0
  19. package/codec/Scalars.luau +72 -0
  20. package/codec/Text.luau +89 -0
  21. package/codec/init.luau +39 -0
  22. package/index.d.ts +285 -0
  23. package/init.luau +91 -0
  24. package/kernel/Bits.luau +16 -0
  25. package/kernel/Catalog.luau +121 -0
  26. package/kernel/Heap.luau +80 -0
  27. package/kernel/Listeners.luau +95 -0
  28. package/kernel/Log.luau +197 -0
  29. package/kernel/Tally.luau +128 -0
  30. package/kernel/Threads.luau +44 -0
  31. package/kernel/Wide.luau +267 -0
  32. package/package.json +15 -32
  33. package/runtime/Boundary.luau +180 -0
  34. package/runtime/Dispatch.luau +91 -0
  35. package/runtime/Handles.luau +114 -0
  36. package/runtime/Handshake.luau +90 -0
  37. package/runtime/Pending.luau +196 -0
  38. package/runtime/Router.luau +379 -0
  39. package/runtime/Session.luau +731 -0
  40. package/shape/Compile.luau +340 -0
  41. package/shape/Folds.luau +332 -0
  42. package/shape/Frames.luau +170 -0
  43. package/shape/Grid.luau +169 -0
  44. package/shape/Ir.luau +540 -0
  45. package/shape/Joins.luau +125 -0
  46. package/shape/Legality.luau +273 -0
  47. package/shape/Lower.luau +419 -0
  48. package/shape/Order.luau +64 -0
  49. package/shape/Regions.luau +113 -0
  50. package/shape/Rotation.luau +472 -0
  51. package/shape/Serial.luau +258 -0
  52. package/shape/Words.luau +89 -0
  53. package/shape/emit/Block.luau +453 -0
  54. package/shape/emit/Column.luau +338 -0
  55. package/shape/emit/Leaf.luau +462 -0
  56. package/shape/emit/Word.luau +234 -0
  57. package/shape/emit/init.luau +222 -0
  58. package/shape/init.luau +78 -0
  59. package/state/Apply.luau +330 -0
  60. package/state/Audience.luau +126 -0
  61. package/state/Catchup.luau +218 -0
  62. package/state/Coalesce.luau +43 -0
  63. package/state/Fieldset.luau +177 -0
  64. package/state/Newest.luau +339 -0
  65. package/state/Plan.luau +441 -0
  66. package/state/Sections.luau +468 -0
  67. package/state/Store.luau +188 -0
  68. package/state/Sync.luau +762 -0
  69. package/wire/Bytes.luau +118 -0
  70. package/wire/Clock.luau +37 -0
  71. package/wire/Protocol.luau +110 -0
  72. package/wire/Sequence.luau +40 -0
  73. package/wire/Varint.luau +124 -0
  74. package/src/Types.luau +0 -180
  75. package/src/api/Group.luau +0 -156
  76. package/src/api/Packet.luau +0 -319
  77. package/src/api/Query.luau +0 -338
  78. package/src/api/Scope.luau +0 -90
  79. package/src/api/Signal.luau +0 -188
  80. package/src/codec/Base.luau +0 -136
  81. package/src/codec/composite/Array.luau +0 -456
  82. package/src/codec/composite/Map.luau +0 -469
  83. package/src/codec/composite/Optional.luau +0 -54
  84. package/src/codec/composite/Shared.luau +0 -291
  85. package/src/codec/composite/Struct.luau +0 -494
  86. package/src/codec/composite/Tagged.luau +0 -103
  87. package/src/codec/composite/Tuple.luau +0 -143
  88. package/src/codec/datatype/Buffer.luau +0 -66
  89. package/src/codec/datatype/CFrame.luau +0 -109
  90. package/src/codec/datatype/Color.luau +0 -32
  91. package/src/codec/datatype/Instance.luau +0 -52
  92. package/src/codec/datatype/IntVector.luau +0 -39
  93. package/src/codec/datatype/NumberRange.luau +0 -39
  94. package/src/codec/datatype/Ray.luau +0 -36
  95. package/src/codec/datatype/Rect.luau +0 -31
  96. package/src/codec/datatype/Region.luau +0 -62
  97. package/src/codec/datatype/Sequence.luau +0 -184
  98. package/src/codec/datatype/String.luau +0 -94
  99. package/src/codec/datatype/UDim.luau +0 -46
  100. package/src/codec/datatype/Vector.luau +0 -130
  101. package/src/codec/meta/Auto.luau +0 -318
  102. package/src/codec/meta/Bitfield.luau +0 -147
  103. package/src/codec/meta/Custom.luau +0 -33
  104. package/src/codec/meta/DeltaScalar.luau +0 -390
  105. package/src/codec/meta/Enum.luau +0 -50
  106. package/src/codec/meta/Float.luau +0 -38
  107. package/src/codec/meta/Nothing.luau +0 -13
  108. package/src/codec/meta/Unknown.luau +0 -41
  109. package/src/codec/primitive/Bool.luau +0 -26
  110. package/src/codec/primitive/Float16.luau +0 -99
  111. package/src/codec/primitive/Int.luau +0 -59
  112. package/src/codec/primitive/Number.luau +0 -24
  113. package/src/codec/primitive/Signed.luau +0 -32
  114. package/src/codec/primitive/Varint.luau +0 -165
  115. package/src/codec/primitive/Zint.luau +0 -99
  116. package/src/index.d.ts +0 -423
  117. package/src/init.luau +0 -362
  118. package/src/internal/Baseline.luau +0 -57
  119. package/src/internal/Channel.luau +0 -390
  120. package/src/internal/Middleware.luau +0 -100
  121. package/src/internal/Pool.luau +0 -65
  122. package/src/internal/Registry.luau +0 -119
  123. package/src/internal/Transport.luau +0 -28
  124. package/src/transport/Bridge.luau +0 -110
  125. package/src/transport/Client.luau +0 -97
  126. package/src/transport/Gate.luau +0 -488
  127. package/src/transport/Reader.luau +0 -331
  128. package/src/transport/Server.luau +0 -211
  129. package/src/util/Array.luau +0 -18
  130. package/src/util/Buffer.luau +0 -90
  131. package/src/util/Constants.luau +0 -30
  132. package/src/util/Log.luau +0 -68
  133. package/src/util/Player.luau +0 -14
  134. package/src/util/Quantize.luau +0 -84
  135. package/src/util/Quat.luau +0 -124
@@ -1,331 +0,0 @@
1
- --!strict
2
- --!native
3
- -- Inbound buffer parser. Returns false on malformed wire so the transport can drop its XOR baseline.
4
-
5
- local Baseline = require(script.Parent.Parent.internal.Baseline)
6
- local Channel = require(script.Parent.Parent.internal.Channel)
7
- local Constants = require(script.Parent.Parent.util.Constants)
8
- local Gate = require(script.Parent.Parent.transport.Gate)
9
- local Log = require(script.Parent.Parent.util.Log)
10
- local Middleware = require(script.Parent.Parent.internal.Middleware)
11
- local Registry = require(script.Parent.Parent.internal.Registry)
12
- local Types = require(script.Parent.Parent.Types)
13
- local Varint = require(script.Parent.Parent.codec.primitive.Varint)
14
-
15
- -- Constants --------------------------------------------------------------
16
-
17
- local KIND_PACKET = Registry.KIND_PACKET
18
- local KIND_REQUEST = Registry.KIND_REQUEST
19
- local KIND_RESPONSE = Registry.KIND_RESPONSE
20
-
21
- local TS_FRAME = Channel.TS_FRAME
22
- local TS_OFFSET = Channel.TS_OFFSET
23
- local TS_FULL = Channel.TS_FULL
24
-
25
- local FRAME_MSB = Constants.FRAME_MSB
26
- local FRAME_ID_MASK = Constants.FRAME_ID_MASK
27
-
28
- -- Private ----------------------------------------------------------------
29
-
30
- local band = bit32.band
31
- local readu8 = buffer.readu8
32
- local readu16 = buffer.readu16
33
- local readf64 = buffer.readf64
34
- local registryGet = Registry.get
35
- local checkGlobal = Gate.checkGlobalRateLimit
36
- local checkRate = Gate.checkRateLimit
37
- local validateGate = Gate.validate
38
- local fireDrop = Middleware.fireDrop
39
- local runReceive = Middleware.runReceive
40
- local varintRead = Varint.read
41
-
42
- local function recordDrop(
43
- reg: Types.Registration,
44
- statsEnabled: boolean,
45
- player: Player?,
46
- reason: string,
47
- value: any
48
- ): ()
49
- if statsEnabled then
50
- reg.drops += 1
51
- end
52
- if player then
53
- fireDrop(player, reason, reg.name, value)
54
- end
55
- end
56
-
57
- --[[
58
- Server gate pipeline. Returns true to deliver, false on rate-limit,
59
- schema-validate, or custom-validate rejection. `runGlobal` lets the
60
- response path skip the global per-player limit.
61
- ]]
62
- local function gateValue(
63
- reg: Types.Registration,
64
- regCodec: Types.InternalCodec<any>,
65
- value: any,
66
- player: Player,
67
- statsEnabled: boolean,
68
- runGlobal: boolean
69
- ): boolean
70
- -- Both global and per-packet drops use the "rate" reason; collapsed into one branch.
71
- if (runGlobal and not checkGlobal(player)) or not checkRate(reg, player) then
72
- recordDrop(reg, statsEnabled, player, "rate", value)
73
- return false
74
- end
75
-
76
- local validateReason = validateGate(value, regCodec)
77
- if validateReason then
78
- recordDrop(reg, statsEnabled, player, `validation: {validateReason}`, value)
79
- return false
80
- end
81
-
82
- if reg.validate then
83
- local valid, validReason = reg.validate(value, player)
84
- if not valid then
85
- recordDrop(
86
- reg,
87
- statsEnabled,
88
- player,
89
- if validReason then `validate: {validReason}` else "validate",
90
- value
91
- )
92
- return false
93
- end
94
- end
95
- return true
96
- end
97
-
98
- -- Public -----------------------------------------------------------------
99
-
100
- local Reader = {}
101
-
102
- --[[
103
- Sanity-check an inbound payload. Size cap is delegated to Roblox's ~1MB
104
- RemoteEvent ceiling: the receiver may not have called Lync.configure
105
- with the same channelMaxSize as the sender (independent VMs, independent
106
- module state), so a local cap here would reject legitimate frames.
107
- ]]
108
- function Reader.decodeIncoming(data: any): buffer?
109
- if typeof(data) ~= "buffer" then
110
- return nil
111
- end
112
- local b = data :: buffer
113
- if buffer.len(b) == 0 then
114
- return nil
115
- end
116
- return b
117
- end
118
-
119
- --[[
120
- Returns true on full success, false if a malformed frame aborted the
121
- parse. Transport callers use this to decide whether to keep the per-peer
122
- XOR baseline: false means the buffer is suspect and would permanently
123
- desync the channel if reused as the next XOR mask.
124
- ]]
125
- function Reader.process(
126
- incoming: buffer,
127
- incomingLen: number,
128
- refs: { Instance }?,
129
- player: Player?,
130
- isServer: boolean
131
- ): boolean
132
- if Baseline.hasDelta() then
133
- Baseline.setReadKey(player or false)
134
- end
135
-
136
- local statsEnabled = Channel.statsEnabled()
137
- local hasRecvHooks = Middleware.hasReceiveHooks()
138
- local pos = 0
139
-
140
- while pos < incomingLen do
141
- local frameStart = pos
142
- local raw = readu8(incoming, pos)
143
- pos += 1
144
-
145
- local msb = band(raw, FRAME_MSB) ~= 0
146
- local id = band(raw, FRAME_ID_MASK)
147
-
148
- local reg = registryGet(id)
149
- if not reg then
150
- Log.warn(`unknown packet ID {id} at byte {pos - 1}`)
151
- return false
152
- end
153
-
154
- local kind = reg.kind
155
- if kind == KIND_PACKET then
156
- local count: number
157
- if msb then
158
- count = 1
159
- else
160
- if pos + 2 > incomingLen then
161
- Log.warn("truncated multi-frame header")
162
- return false
163
- end
164
- count = readu16(incoming, pos)
165
- pos += 2
166
- end
167
-
168
- local tsMode = reg.timestampMode
169
- local tsValue: number? = nil
170
- if tsMode == TS_FRAME then
171
- if pos + 1 > incomingLen then
172
- Log.warn("truncated timestamp")
173
- return false
174
- end
175
- tsValue = readu8(incoming, pos)
176
- pos += 1
177
- elseif tsMode == TS_OFFSET then
178
- if pos + 2 > incomingLen then
179
- Log.warn("truncated timestamp")
180
- return false
181
- end
182
- tsValue = readu16(incoming, pos)
183
- pos += 2
184
- elseif tsMode == TS_FULL then
185
- if pos + 8 > incomingLen then
186
- Log.warn("truncated timestamp")
187
- return false
188
- end
189
- tsValue = readf64(incoming, pos)
190
- pos += 8
191
- end
192
-
193
- --[[
194
- Fixed-size codec: a count exceeding remaining bytes is
195
- unambiguously corrupt. Abort to keep the cursor on a frame
196
- boundary so the transport can reset cleanly.
197
- ]]
198
- local regCodec = reg.codec
199
- local sizeMeta = regCodec._size
200
- if sizeMeta and count * sizeMeta > incomingLen - pos then
201
- Log.warn(`"{reg.name}" count {count} exceeds remaining bytes; aborting`)
202
- return false
203
- end
204
-
205
- local maxPayload = reg.maxPayloadBytes
206
- local payloadStart = pos
207
- local doGate = isServer and reg.needsGate and player ~= nil
208
- local regSignal = reg.signal
209
- local regName = reg.name
210
- -- Lync.nothing reads zero bytes; bypass the pos/consumed gates that assume forward progress.
211
- local isZeroSize = sizeMeta == 0
212
-
213
- for _ = 1, count do
214
- if not isZeroSize and pos >= incomingLen then
215
- Log.warn(`codec for "{regName}" ran past frame end; aborting`)
216
- return false
217
- end
218
- local value, consumed = regCodec.read(incoming, pos, refs)
219
- if not isZeroSize and consumed == 0 then
220
- Log.warn(`codec for "{regName}" reported 0 bytes; aborting`)
221
- return false
222
- end
223
- -- Fixed-size codecs MUST report consumed == _size or `pos` desyncs silently.
224
- if sizeMeta and consumed ~= sizeMeta then
225
- Log.warn(
226
- `codec for "{regName}" consumed {consumed} bytes, expected {sizeMeta}; aborting`
227
- )
228
- return false
229
- end
230
- pos += consumed
231
- if pos > incomingLen then
232
- Log.warn(`codec for "{regName}" overran frame end; aborting`)
233
- return false
234
- end
235
-
236
- if maxPayload and (pos - payloadStart) > maxPayload then
237
- recordDrop(reg, statsEnabled, player, "maxPayloadBytes", value)
238
- return false
239
- end
240
-
241
- if
242
- doGate
243
- and not gateValue(reg, regCodec, value, player :: Player, statsEnabled, true)
244
- then
245
- continue
246
- end
247
-
248
- if hasRecvHooks then
249
- value = runReceive(value, regName, player)
250
- end
251
-
252
- if statsEnabled then
253
- reg.recvFires += 1
254
- end
255
-
256
- -- tsValue is nil when mode == TS_NONE; pass through to skip a per-item branch.
257
- regSignal:fire(value, player, tsValue)
258
- end
259
-
260
- if statsEnabled then
261
- reg.bytesReceived += (pos - frameStart)
262
- end
263
- elseif kind == KIND_REQUEST or kind == KIND_RESPONSE then
264
- local corrId, corrBytes = varintRead(incoming, pos)
265
- if corrBytes == 0 then
266
- Log.warn(`truncated correlation id for "{reg.name}"; aborting`)
267
- return false
268
- end
269
- pos += corrBytes
270
-
271
- if msb then
272
- if statsEnabled then
273
- reg.recvFires += 1
274
- reg.bytesReceived += (pos - frameStart)
275
- end
276
- reg.signal:fire(nil, player, corrId)
277
- else
278
- local regCodec = reg.codec
279
- -- Mirror the packet path: 0-byte response codecs (Lync.nothing) bypass the gates.
280
- local qIsZeroSize = regCodec._size == 0
281
- if not qIsZeroSize and pos >= incomingLen then
282
- Log.warn(`query "{reg.name}" body missing; aborting`)
283
- return false
284
- end
285
- local value, consumed = regCodec.read(incoming, pos, refs)
286
- if not qIsZeroSize and consumed == 0 then
287
- Log.warn(`query codec for "{reg.name}" reported 0 bytes; aborting`)
288
- return false
289
- end
290
- pos += consumed
291
- if pos > incomingLen then
292
- Log.warn(`query "{reg.name}" overran frame end; aborting`)
293
- return false
294
- end
295
-
296
- --[[
297
- Server gates REQUEST and RESPONSE frames opted into
298
- needsGate so a malicious client can't bypass via the
299
- response channel.
300
- ]]
301
- if
302
- isServer
303
- and reg.needsGate
304
- and player
305
- and not gateValue(reg, regCodec, value, player, statsEnabled, false)
306
- then
307
- if statsEnabled then
308
- reg.bytesReceived += (pos - frameStart)
309
- end
310
- continue
311
- end
312
-
313
- if hasRecvHooks then
314
- value = runReceive(value, reg.name, player)
315
- end
316
-
317
- if statsEnabled then
318
- reg.recvFires += 1
319
- reg.bytesReceived += (pos - frameStart)
320
- end
321
- reg.signal:fire(value, player, corrId)
322
- end
323
- end
324
- end
325
- return true
326
- end
327
-
328
- Reader.setSilent = Log.setSilent
329
- Reader.reset = Log.reset
330
-
331
- return table.freeze(Reader)
@@ -1,211 +0,0 @@
1
- --!strict
2
- --!optimize 2
3
- -- Server transport: per-player channels, broadcast, flush.
4
-
5
- local Players = game:GetService("Players")
6
- local ReplicatedStorage = game:GetService("ReplicatedStorage")
7
-
8
- local Baseline = require(script.Parent.Parent.internal.Baseline)
9
- local Bridge = require(script.Parent.Parent.transport.Bridge)
10
- local Channel = require(script.Parent.Parent.internal.Channel)
11
- local Gate = require(script.Parent.Parent.transport.Gate)
12
- local Pool = require(script.Parent.Parent.internal.Pool)
13
- local Reader = require(script.Parent.Parent.transport.Reader)
14
- local Types = require(script.Parent.Parent.Types)
15
-
16
- -- Constants --------------------------------------------------------------
17
-
18
- local CONTAINER_NAME = "LyncRemotes"
19
-
20
- -- State ------------------------------------------------------------------
21
-
22
- local _reliableChannels: { [Player]: Types.ChannelState } = {}
23
- local _unreliableChannels: { [Player]: Types.ChannelState } = {}
24
- local _playerStats: { [Player]: Types.PlayerStats } = {}
25
- local _prevIncoming: { [Player]: buffer } = {}
26
- local _prevIncomingLen: { [Player]: number } = {}
27
-
28
- -- Private ----------------------------------------------------------------
29
-
30
- local statsEnabled = Channel.statsEnabled
31
- local xorApply = Channel.xorApply
32
- local sealAndDump = Channel.sealAndDump
33
- local resetCh = Channel.reset
34
-
35
- type StatsField = "bytesSent" | "bytesReceived"
36
-
37
- local function getOrCreateChannel(
38
- map: { [Player]: Types.ChannelState },
39
- player: Player
40
- ): Types.ChannelState
41
- local ch = map[player]
42
- if not ch then
43
- ch = Pool.acquire()
44
- map[player] = ch
45
- end
46
- return ch
47
- end
48
-
49
- -- Skip the table read when stats are off; the hot path needs no branch.
50
- local function addStat(player: Player, field: StatsField, byteLen: number): ()
51
- if statsEnabled() then
52
- local ps = _playerStats[player]
53
- if ps then
54
- ps[field] += byteLen
55
- end
56
- end
57
- end
58
-
59
- local function flushReliable(player: Player): ()
60
- local rCh = _reliableChannels[player]
61
- if not rCh or rCh.cursor == 0 then
62
- return
63
- end
64
-
65
- local snapshot, refs, byteLen = sealAndDump(rCh)
66
- local xored = xorApply(snapshot, byteLen, rCh.prevDump, rCh.prevDumpLen)
67
- rCh.prevDump = snapshot
68
- rCh.prevDumpLen = byteLen
69
-
70
- Bridge.fireClient(player, xored, refs)
71
- resetCh(rCh)
72
- addStat(player, "bytesSent", byteLen)
73
- end
74
-
75
- local function flushUnreliable(player: Player): ()
76
- local uCh = _unreliableChannels[player]
77
- if not uCh or uCh.cursor == 0 then
78
- return
79
- end
80
-
81
- local snapshot, refs, byteLen = sealAndDump(uCh)
82
- Bridge.fireClientUnreliable(player, snapshot, refs)
83
- resetCh(uCh)
84
- addStat(player, "bytesSent", byteLen)
85
- end
86
-
87
- local function flushPlayer(player: Player): ()
88
- flushReliable(player)
89
- flushUnreliable(player)
90
- end
91
-
92
- local function handleIncomingReliable(player: Player, data: any, refs: any?): ()
93
- local incoming = Reader.decodeIncoming(data)
94
- if not incoming then
95
- return
96
- end
97
-
98
- local incomingLen = buffer.len(incoming)
99
- if not Gate.checkBandwidth(player, incomingLen) then
100
- return
101
- end
102
-
103
- local prev = _prevIncoming[player]
104
- local decoded = xorApply(incoming, incomingLen, prev, _prevIncomingLen[player])
105
-
106
- --[[
107
- Only adopt `decoded` as the next XOR baseline on success. A failed
108
- parse means the wire is suspect; reusing it would poison every
109
- subsequent packet.
110
- ]]
111
- if Reader.process(decoded, incomingLen, refs, player, true) then
112
- _prevIncoming[player] = decoded
113
- _prevIncomingLen[player] = incomingLen
114
- else
115
- _prevIncoming[player] = nil
116
- _prevIncomingLen[player] = nil
117
- end
118
-
119
- addStat(player, "bytesReceived", incomingLen)
120
- end
121
-
122
- local function handleIncomingUnreliable(player: Player, data: any, refs: any?): ()
123
- local incoming = Reader.decodeIncoming(data)
124
- if not incoming then
125
- return
126
- end
127
-
128
- local incomingLen = buffer.len(incoming)
129
- Reader.process(incoming, incomingLen, refs, player, true)
130
- addStat(player, "bytesReceived", incomingLen)
131
- end
132
-
133
- local function clearPlayerState(player: Player): ()
134
- local rCh = _reliableChannels[player]
135
- if rCh then
136
- _reliableChannels[player] = nil
137
- Pool.release(rCh)
138
- end
139
- local uCh = _unreliableChannels[player]
140
- if uCh then
141
- _unreliableChannels[player] = nil
142
- Pool.release(uCh)
143
- end
144
-
145
- _playerStats[player] = nil
146
- _prevIncoming[player] = nil
147
- _prevIncomingLen[player] = nil
148
-
149
- Gate.clearPlayer(player)
150
- Baseline.clearPlayer(player)
151
- end
152
-
153
- -- Public -----------------------------------------------------------------
154
-
155
- local Server = {}
156
-
157
- function Server.getChannel(player: Player, isUnreliable: boolean): Types.ChannelState
158
- return getOrCreateChannel(
159
- if isUnreliable then _unreliableChannels else _reliableChannels,
160
- player
161
- )
162
- end
163
-
164
- function Server.flush(): ()
165
- if Channel.hasTimestamps() then
166
- Channel.updateTimestamp()
167
- end
168
- for _, player in Players:GetPlayers() do
169
- flushPlayer(player)
170
- end
171
- end
172
-
173
- Server.flushPlayer = flushPlayer
174
-
175
- function Server.start(): ()
176
- local container = Instance.new("Folder")
177
- container.Name = CONTAINER_NAME
178
- container.Parent = ReplicatedStorage
179
-
180
- Bridge.setup(container)
181
-
182
- Bridge.reliable().OnServerEvent:Connect(handleIncomingReliable)
183
- Bridge.unreliable().OnServerEvent:Connect(handleIncomingUnreliable)
184
-
185
- Players.PlayerAdded:Connect(function(player: Player)
186
- if statsEnabled() then
187
- _playerStats[player] = { bytesSent = 0, bytesReceived = 0 }
188
- end
189
- end)
190
- Players.PlayerRemoving:Connect(clearPlayerState)
191
-
192
- -- Catch players who joined before Lync.start.
193
- if statsEnabled() then
194
- for _, player in Players:GetPlayers() do
195
- _playerStats[player] = { bytesSent = 0, bytesReceived = 0 }
196
- end
197
- end
198
- end
199
-
200
- function Server.getPlayerStats(player: Player): Types.PlayerStats?
201
- return _playerStats[player]
202
- end
203
-
204
- function Server.resetStats(): ()
205
- for _, ps in _playerStats do
206
- ps.bytesSent = 0
207
- ps.bytesReceived = 0
208
- end
209
- end
210
-
211
- return table.freeze(Server)
@@ -1,18 +0,0 @@
1
- --!strict
2
- --!optimize 2
3
- -- O(1) array swap-remove. Breaks insertion order.
4
-
5
- -- Public -----------------------------------------------------------------
6
-
7
- local Array = {}
8
-
9
- -- Reorders. Caller-tracked counts must decrement separately.
10
- function Array.swapRemove<T>(arr: { T }, idx: number): ()
11
- local last = #arr
12
- if idx ~= last then
13
- arr[idx] = arr[last]
14
- end
15
- arr[last] = nil
16
- end
17
-
18
- return table.freeze(Array)
@@ -1,90 +0,0 @@
1
- --!strict
2
- --!native
3
- -- Word-aligned XOR and equality helpers for Channel and composite deltas.
4
-
5
- -- Private ----------------------------------------------------------------
6
-
7
- local band = bit32.band
8
- local bxor = bit32.bxor
9
- local readu8 = buffer.readu8
10
- local readu32 = buffer.readu32
11
- local writeu8 = buffer.writeu8
12
- local writeu32 = buffer.writeu32
13
- local bufCopy = buffer.copy
14
- local bufCreate = buffer.create
15
- local minN = math.min
16
-
17
- -- Public -----------------------------------------------------------------
18
-
19
- local Buf = {}
20
-
21
- -- 8-byte unrolled compare; 4-byte step then byte tail for remainder.
22
- function Buf.rangeEqual(a: buffer, offA: number, b: buffer, offB: number, len: number): boolean
23
- local aligned8 = band(len, -8)
24
- local i = 0
25
- while i < aligned8 do
26
- if
27
- readu32(a, offA + i) ~= readu32(b, offB + i)
28
- or readu32(a, offA + i + 4) ~= readu32(b, offB + i + 4)
29
- then
30
- return false
31
- end
32
- i += 8
33
- end
34
- if i + 4 <= len then
35
- if readu32(a, offA + i) ~= readu32(b, offB + i) then
36
- return false
37
- end
38
- i += 4
39
- end
40
- while i < len do
41
- if readu8(a, offA + i) ~= readu8(b, offB + i) then
42
- return false
43
- end
44
- i += 1
45
- end
46
- return true
47
- end
48
-
49
- function Buf.snapshot(src: buffer, len: number, srcOff: number?): buffer
50
- local out = bufCreate(len)
51
- bufCopy(out, 0, src, srcOff or 0, len)
52
- return out
53
- end
54
-
55
- --[[
56
- XOR `current` against `previous` into a fresh curLen buffer. Returns
57
- `current` unchanged when previous is nil so first-frame callers don't
58
- branch. Overlap is 8-byte unrolled; tail is bulk-copied.
59
- ]]
60
- function Buf.xorApply(current: buffer, curLen: number, previous: buffer?, prevLen: number?): buffer
61
- if not previous then
62
- return current
63
- end
64
- local pLen = prevLen or 0
65
-
66
- local result = bufCreate(curLen)
67
- local overlap = minN(curLen, pLen)
68
-
69
- local aligned8 = band(overlap, -8)
70
- local i = 0
71
- while i < aligned8 do
72
- writeu32(result, i, bxor(readu32(current, i), readu32(previous, i)))
73
- writeu32(result, i + 4, bxor(readu32(current, i + 4), readu32(previous, i + 4)))
74
- i += 8
75
- end
76
- if i + 4 <= overlap then
77
- writeu32(result, i, bxor(readu32(current, i), readu32(previous, i)))
78
- i += 4
79
- end
80
- while i < overlap do
81
- writeu8(result, i, bxor(readu8(current, i), readu8(previous, i)))
82
- i += 1
83
- end
84
- if curLen > overlap then
85
- bufCopy(result, overlap, current, overlap, curLen - overlap)
86
- end
87
- return result
88
- end
89
-
90
- return table.freeze(Buf)
@@ -1,30 +0,0 @@
1
- --!strict
2
- --!optimize 2
3
- -- Wire-format constants and integer limits shared across codecs.
4
-
5
- -- Public -----------------------------------------------------------------
6
-
7
- local Constants = {}
8
-
9
- Constants.U8_MAX = 0xFF
10
- Constants.U16_MAX = 0xFFFF
11
- Constants.U32_MAX = 0xFFFFFFFF
12
-
13
- Constants.I8_MIN = -0x80
14
- Constants.I8_MAX = 0x7F
15
- Constants.I16_MIN = -0x8000
16
- Constants.I16_MAX = 0x7FFF
17
- Constants.I32_MIN = -0x80000000
18
- Constants.I32_MAX = 0x7FFFFFFF
19
-
20
- --[[
21
- Frame header byte: MSB = single-item (no count cell); cleared = multi-item
22
- (u16 count follows). Low 7 bits = registration id (caps registry at 128).
23
- ]]
24
- Constants.FRAME_MSB = 0x80
25
- Constants.FRAME_ID_MASK = 0x7F
26
-
27
- -- u16 count cell.
28
- Constants.MAX_BATCH_ITEMS = 0xFFFF
29
-
30
- return table.freeze(Constants)