@axpecter/lync 2.3.3 → 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 -317
  77. package/src/api/Query.luau +0 -338
  78. package/src/api/Scope.luau +0 -90
  79. package/src/api/Signal.luau +0 -193
  80. package/src/codec/Base.luau +0 -136
  81. package/src/codec/composite/Array.luau +0 -473
  82. package/src/codec/composite/Map.luau +0 -485
  83. package/src/codec/composite/Optional.luau +0 -54
  84. package/src/codec/composite/Shared.luau +0 -311
  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 -160
  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 -484
  120. package/src/internal/Middleware.luau +0 -100
  121. package/src/internal/Pool.luau +0 -66
  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 -233
  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
- local accepted = 0
213
-
214
- for _ = 1, count do
215
- if not isZeroSize and pos >= incomingLen then
216
- Log.warn(`codec for "{regName}" ran past frame end; aborting`)
217
- return false
218
- end
219
- local value, consumed = regCodec.read(incoming, pos, refs)
220
- if not isZeroSize and consumed == 0 then
221
- Log.warn(`codec for "{regName}" reported 0 bytes; aborting`)
222
- return false
223
- end
224
- -- Fixed-size codecs MUST report consumed == _size or `pos` desyncs silently.
225
- if sizeMeta and consumed ~= sizeMeta then
226
- Log.warn(
227
- `codec for "{regName}" consumed {consumed} bytes, expected {sizeMeta}; aborting`
228
- )
229
- return false
230
- end
231
- pos += consumed
232
- if pos > incomingLen then
233
- Log.warn(`codec for "{regName}" overran frame end; aborting`)
234
- return false
235
- end
236
-
237
- if maxPayload and (pos - payloadStart) > maxPayload then
238
- recordDrop(reg, statsEnabled, player, "maxPayloadBytes", value)
239
- return false
240
- end
241
-
242
- if
243
- doGate
244
- and not gateValue(reg, regCodec, value, player :: Player, statsEnabled, true)
245
- then
246
- continue
247
- end
248
-
249
- if hasRecvHooks then
250
- value = runReceive(value, regName, player)
251
- end
252
-
253
- accepted += 1
254
-
255
- -- tsValue is nil when mode == TS_NONE; pass through to skip a per-item branch.
256
- regSignal:fire(value, player, tsValue)
257
- end
258
-
259
- if statsEnabled then
260
- reg.recvFires += accepted
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,233 +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
- local function getOrCreateChannel(
36
- map: { [Player]: Types.ChannelState },
37
- player: Player
38
- ): Types.ChannelState
39
- local ch = map[player]
40
- if not ch then
41
- ch = Pool.acquire()
42
- map[player] = ch
43
- end
44
- return ch
45
- end
46
-
47
- -- Hot-swapped at Server.start; stats-off path is a tail-callable noop.
48
- local function noopStat(_player: Player, _byteLen: number): () end
49
-
50
- local function realBytesSent(player: Player, byteLen: number): ()
51
- local ps = _playerStats[player]
52
- if ps then
53
- ps.bytesSent += byteLen
54
- end
55
- end
56
-
57
- local function realBytesReceived(player: Player, byteLen: number): ()
58
- local ps = _playerStats[player]
59
- if ps then
60
- ps.bytesReceived += byteLen
61
- end
62
- end
63
-
64
- local addBytesSent: (Player, number) -> () = noopStat
65
- local addBytesReceived: (Player, number) -> () = noopStat
66
-
67
- local function flushReliable(player: Player): ()
68
- local rCh = _reliableChannels[player]
69
- if not rCh or rCh.cursor == 0 then
70
- return
71
- end
72
-
73
- local snapshot, refs, byteLen = sealAndDump(rCh)
74
- local xored = xorApply(snapshot, byteLen, rCh.prevDump, rCh.prevDumpLen)
75
- rCh.prevDump = snapshot
76
- rCh.prevDumpLen = byteLen
77
-
78
- Bridge.fireClient(player, xored, refs)
79
- resetCh(rCh)
80
- addBytesSent(player, byteLen)
81
- end
82
-
83
- local function flushUnreliable(player: Player): ()
84
- local uCh = _unreliableChannels[player]
85
- if not uCh or uCh.cursor == 0 then
86
- return
87
- end
88
-
89
- local snapshot, refs, byteLen = sealAndDump(uCh)
90
- Bridge.fireClientUnreliable(player, snapshot, refs)
91
- resetCh(uCh)
92
- addBytesSent(player, byteLen)
93
- end
94
-
95
- local function flushPlayer(player: Player): ()
96
- flushReliable(player)
97
- flushUnreliable(player)
98
- end
99
-
100
- local function handleIncomingReliable(player: Player, data: any, refs: any?): ()
101
- local incoming = Reader.decodeIncoming(data)
102
- if not incoming then
103
- return
104
- end
105
-
106
- local incomingLen = buffer.len(incoming)
107
- if not Gate.checkBandwidth(player, incomingLen) then
108
- return
109
- end
110
-
111
- local prev = _prevIncoming[player]
112
- local decoded = xorApply(incoming, incomingLen, prev, _prevIncomingLen[player])
113
-
114
- --[[
115
- Only adopt `decoded` as the next XOR baseline on success. A failed
116
- parse means the wire is suspect; reusing it would poison every
117
- subsequent packet.
118
- ]]
119
- if Reader.process(decoded, incomingLen, refs, player, true) then
120
- _prevIncoming[player] = decoded
121
- _prevIncomingLen[player] = incomingLen
122
- else
123
- _prevIncoming[player] = nil
124
- _prevIncomingLen[player] = nil
125
- end
126
-
127
- addBytesReceived(player, incomingLen)
128
- end
129
-
130
- local function handleIncomingUnreliable(player: Player, data: any, refs: any?): ()
131
- local incoming = Reader.decodeIncoming(data)
132
- if not incoming then
133
- return
134
- end
135
-
136
- local incomingLen = buffer.len(incoming)
137
- Reader.process(incoming, incomingLen, refs, player, true)
138
- addBytesReceived(player, incomingLen)
139
- end
140
-
141
- local function clearPlayerState(player: Player): ()
142
- local rCh = _reliableChannels[player]
143
- if rCh then
144
- _reliableChannels[player] = nil
145
- Pool.release(rCh)
146
- end
147
- local uCh = _unreliableChannels[player]
148
- if uCh then
149
- _unreliableChannels[player] = nil
150
- Pool.release(uCh)
151
- end
152
-
153
- _playerStats[player] = nil
154
- _prevIncoming[player] = nil
155
- _prevIncomingLen[player] = nil
156
-
157
- Gate.clearPlayer(player)
158
- Baseline.clearPlayer(player)
159
- end
160
-
161
- -- Public -----------------------------------------------------------------
162
-
163
- local Server = {}
164
-
165
- function Server.getChannel(player: Player, isUnreliable: boolean): Types.ChannelState
166
- return getOrCreateChannel(
167
- if isUnreliable then _unreliableChannels else _reliableChannels,
168
- player
169
- )
170
- end
171
-
172
- -- Pre-resolved variants for broadcast: skip the per-audience-member isUnreliable branch.
173
- function Server.getReliableChannel(player: Player): Types.ChannelState
174
- return getOrCreateChannel(_reliableChannels, player)
175
- end
176
-
177
- function Server.getUnreliableChannel(player: Player): Types.ChannelState
178
- return getOrCreateChannel(_unreliableChannels, player)
179
- end
180
-
181
- function Server.flush(): ()
182
- if Channel.hasTimestamps() then
183
- Channel.updateTimestamp()
184
- end
185
- for _, player in Players:GetPlayers() do
186
- flushPlayer(player)
187
- end
188
- end
189
-
190
- Server.flushPlayer = flushPlayer
191
-
192
- function Server.start(): ()
193
- local container = Instance.new("Folder")
194
- container.Name = CONTAINER_NAME
195
- container.Parent = ReplicatedStorage
196
-
197
- Bridge.setup(container)
198
-
199
- Bridge.reliable().OnServerEvent:Connect(handleIncomingReliable)
200
- Bridge.unreliable().OnServerEvent:Connect(handleIncomingUnreliable)
201
-
202
- if statsEnabled() then
203
- addBytesSent = realBytesSent
204
- addBytesReceived = realBytesReceived
205
- end
206
-
207
- Players.PlayerAdded:Connect(function(player: Player)
208
- if statsEnabled() then
209
- _playerStats[player] = { bytesSent = 0, bytesReceived = 0 }
210
- end
211
- end)
212
- Players.PlayerRemoving:Connect(clearPlayerState)
213
-
214
- -- Catch players who joined before Lync.start.
215
- if statsEnabled() then
216
- for _, player in Players:GetPlayers() do
217
- _playerStats[player] = { bytesSent = 0, bytesReceived = 0 }
218
- end
219
- end
220
- end
221
-
222
- function Server.getPlayerStats(player: Player): Types.PlayerStats?
223
- return _playerStats[player]
224
- end
225
-
226
- function Server.resetStats(): ()
227
- for _, ps in _playerStats do
228
- ps.bytesSent = 0
229
- ps.bytesReceived = 0
230
- end
231
- end
232
-
233
- 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)