@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,156 +0,0 @@
1
- --!strict
2
- --!optimize 2
3
- -- Named player sets with __iter and auto-cleanup on PlayerRemoving.
4
-
5
- local Players = game:GetService("Players")
6
-
7
- local Array = require(script.Parent.Parent.util.Array)
8
- local Log = require(script.Parent.Parent.util.Log)
9
-
10
- -- Public types -----------------------------------------------------------
11
-
12
- export type GroupHandle = {
13
- add: (self: GroupHandle, player: Player) -> boolean,
14
- remove: (self: GroupHandle, player: Player) -> boolean,
15
- has: (self: GroupHandle, player: Player) -> boolean,
16
- count: (self: GroupHandle) -> number,
17
- destroy: (self: GroupHandle) -> (),
18
- _lyncKind: "group",
19
- _members: { [Player]: boolean },
20
- }
21
-
22
- type GroupInternal = GroupHandle & { _count: number, _name: string }
23
-
24
- -- State ------------------------------------------------------------------
25
-
26
- local _groups: { [string]: GroupInternal } = {}
27
- -- Reverse index used by PlayerRemoving so we don't scan every group on disconnect.
28
- local _playerCleanup: { [Player]: { Group } } = {}
29
- local _cleanupConnected = false
30
-
31
- -- Private ----------------------------------------------------------------
32
-
33
- local swapRemove = Array.swapRemove
34
-
35
- -- Connect once on the first Group.create; subsequent creates reuse the same connection.
36
- local function ensureCleanup(): ()
37
- if _cleanupConnected then
38
- return
39
- end
40
- _cleanupConnected = true
41
-
42
- Players.PlayerRemoving:Connect(function(player: Player)
43
- local groups = _playerCleanup[player]
44
- if not groups then
45
- return
46
- end
47
- for _, group in groups do
48
- group._members[player] = nil
49
- group._count -= 1
50
- end
51
- _playerCleanup[player] = nil
52
- end)
53
- end
54
-
55
- local function untrackCleanup(player: Player, group: GroupInternal): ()
56
- local cleanup = _playerCleanup[player]
57
- if not cleanup then
58
- return
59
- end
60
- local idx = table.find(cleanup, group)
61
- if idx then
62
- swapRemove(cleanup, idx)
63
- end
64
- end
65
-
66
- -- Public -----------------------------------------------------------------
67
-
68
- local Group = {}
69
-
70
- local GroupMeta = {}
71
- GroupMeta.__index = GroupMeta
72
-
73
- -- __iter lets `for player in group do` skip the explicit :members() call.
74
- function GroupMeta.__iter(self: GroupInternal): (any, any, any)
75
- return next, self._members, nil
76
- end
77
-
78
- function GroupMeta.add(self: GroupInternal, player: Player): boolean
79
- if self._members[player] then
80
- return false
81
- end
82
-
83
- self._members[player] = true
84
- self._count += 1
85
-
86
- local cleanup = _playerCleanup[player]
87
- if not cleanup then
88
- cleanup = {}
89
- _playerCleanup[player] = cleanup
90
- end
91
- table.insert(cleanup, self)
92
- return true
93
- end
94
-
95
- function GroupMeta.remove(self: GroupInternal, player: Player): boolean
96
- if not self._members[player] then
97
- return false
98
- end
99
-
100
- self._members[player] = nil
101
- self._count -= 1
102
- untrackCleanup(player, self)
103
- return true
104
- end
105
-
106
- function GroupMeta.has(self: GroupInternal, player: Player): boolean
107
- return self._members[player] == true
108
- end
109
-
110
- function GroupMeta.count(self: GroupInternal): number
111
- return self._count
112
- end
113
-
114
- function GroupMeta.destroy(self: GroupInternal): ()
115
- if _groups[self._name] == self then
116
- _groups[self._name] = nil
117
- end
118
-
119
- for player in self._members do
120
- untrackCleanup(player, self)
121
- end
122
-
123
- table.clear(self._members)
124
- self._count = 0
125
- end
126
-
127
- table.freeze(GroupMeta)
128
-
129
- function Group.create(name: string): GroupHandle
130
- if _groups[name] then
131
- Log.error(`"{name}" already exists`)
132
- end
133
-
134
- ensureCleanup()
135
-
136
- local group = setmetatable({
137
- _lyncKind = "group" :: "group",
138
- _members = {} :: { [Player]: boolean },
139
- _count = 0,
140
- _name = name,
141
- }, GroupMeta) :: any
142
-
143
- _groups[name] = group
144
- return group
145
- end
146
-
147
- function Group.reset(): ()
148
- for _, group in _groups do
149
- table.clear(group._members)
150
- group._count = 0
151
- end
152
- table.clear(_groups)
153
- table.clear(_playerCleanup)
154
- end
155
-
156
- return table.freeze(Group)
@@ -1,319 +0,0 @@
1
- --!strict
2
- --!optimize 2
3
- -- Packet definition: send, on, once, wait, stats.
4
-
5
- local Players = game:GetService("Players")
6
- local RunService = game:GetService("RunService")
7
-
8
- local Baseline = require(script.Parent.Parent.internal.Baseline)
9
- local Channel = require(script.Parent.Parent.internal.Channel)
10
- local Log = require(script.Parent.Parent.util.Log)
11
- local Middleware = require(script.Parent.Parent.internal.Middleware)
12
- local Player = require(script.Parent.Parent.util.Player)
13
- local Registry = require(script.Parent.Parent.internal.Registry)
14
- local Shared = require(script.Parent.Parent.codec.composite.Shared)
15
- local Transport = require(script.Parent.Parent.internal.Transport)
16
- local Types = require(script.Parent.Parent.Types)
17
-
18
- -- Constants --------------------------------------------------------------
19
-
20
- local IS_SERVER = RunService:IsServer()
21
-
22
- -- mode: TS_* tag; headerSize: 1 (frame byte) + timestamp bytes (1, 2, or 8).
23
- local TS_MODES: { [string]: { mode: number, headerSize: number } } = table.freeze({
24
- frame = table.freeze({ mode = Channel.TS_FRAME, headerSize = 2 }),
25
- offset = table.freeze({ mode = Channel.TS_OFFSET, headerSize = 3 }),
26
- full = table.freeze({ mode = Channel.TS_FULL, headerSize = 9 }),
27
- })
28
-
29
- local EMPTY_OPTIONS: Types.PacketOptions = table.freeze({})
30
-
31
- -- Private ----------------------------------------------------------------
32
-
33
- local isPlayer = Player.is
34
-
35
- local function resolveTimestampMode(ts: ("frame" | "offset" | "full")?): (number, number)
36
- if ts == nil then
37
- return Channel.TS_NONE, 1
38
- end
39
- local entry = TS_MODES[ts]
40
- Channel.enableTimestamps()
41
- return entry.mode, entry.headerSize
42
- end
43
-
44
- -- Public types -----------------------------------------------------------
45
-
46
- export type PacketHandle<T> = {
47
- send: (self: PacketHandle<T>, data: T, target: any?) -> (),
48
- on: (
49
- self: PacketHandle<T>,
50
- fn: (data: T, sender: Player?, timestamp: number?) -> ()
51
- ) -> Types.Connection,
52
- once: (
53
- self: PacketHandle<T>,
54
- fn: (data: T, sender: Player?, timestamp: number?) -> ()
55
- ) -> Types.Connection,
56
- wait: (self: PacketHandle<T>) -> (T, Player?, number?),
57
- name: (self: PacketHandle<T>) -> string,
58
- stats: (self: PacketHandle<T>) -> Types.PacketStats,
59
- }
60
-
61
- -- Public -----------------------------------------------------------------
62
-
63
- local Packet = {}
64
-
65
- function Packet.define<T>(
66
- name: string,
67
- codec: Types.InternalCodec<T>,
68
- options: Types.PacketOptions?
69
- ): PacketHandle<T>
70
- local opts = options or EMPTY_OPTIONS
71
- local isUnreliable = opts.unreliable or false
72
-
73
- -- Delta + unreliable is unsafe: a dropped frame permanently desyncs the receiver baseline.
74
- if isUnreliable and codec._isDelta then
75
- Log.error(
76
- `"{name}" delta codecs need reliable transport (lost packets desync the baseline)`
77
- )
78
- end
79
-
80
- if codec._hasUnknown and not opts.validate then
81
- Log.warn(`"{name}" uses unknown codec without validate; data bypasses schema validation`)
82
- end
83
-
84
- if codec._isDelta then
85
- Baseline.markHasDelta()
86
- end
87
-
88
- local tsMode, headerSize = resolveTimestampMode(opts.timestamp)
89
- local openFn = Channel.resolveOpenFn(tsMode, name)
90
-
91
- local reg = Registry.register({
92
- name = name,
93
- kind = Registry.KIND_PACKET,
94
- codec = codec,
95
- isUnreliable = isUnreliable,
96
- partner = nil,
97
- needsGate = IS_SERVER,
98
- headerSize = headerSize,
99
- timestampMode = tsMode,
100
- openFn = openFn,
101
- rateLimit = opts.rateLimit,
102
- validate = opts.validate,
103
- maxPayloadBytes = opts.maxPayloadBytes,
104
- })
105
-
106
- local function sendToPlayer(player: Player, data: any): ()
107
- local ch = Transport.server().getChannel(player, isUnreliable)
108
- Channel.writeBatch(ch, reg, data)
109
- end
110
-
111
- local function bumpFires(): ()
112
- if Channel.statsEnabled() then
113
- reg.fires += 1
114
- end
115
- end
116
-
117
- --[[
118
- Run the send middleware chain. Returns (dropped, value). A nil value
119
- is a legitimate payload (Lync.nothing); only the explicit Lync.DROP
120
- sentinel or a hook returning DROP triggers the drop branch.
121
- ]]
122
- local function applySend(data: any, player: Player?): (boolean, any)
123
- if not Middleware.hasSendHooks() then
124
- return false, data
125
- end
126
- local sendData = Middleware.runSend(data, name, player)
127
- if typeof(sendData) == "table" and sendData._lyncKind == "drop" then
128
- return true, nil
129
- end
130
- return false, sendData
131
- end
132
-
133
- -- Non-delta codecs are stateless wire-encoders, so broadcast can encode
134
- -- once and bufCopy the payload to every player. Falls through if the
135
- -- encoded payload includes ref indices (the indices would need rewriting
136
- -- per channel, which no codec exposes).
137
- local canEncodeOnce = not codec._isDelta and not codec._hasDelta
138
-
139
- local function broadcast(players: { Player }, data: any): ()
140
- local count = #players
141
- if count == 0 then
142
- bumpFires()
143
- return
144
- end
145
-
146
- if canEncodeOnce then
147
- local scratch = Shared.acquireScratch()
148
- scratch.currentPacket = name
149
- codec.write(scratch, data)
150
- scratch.currentPacket = nil
151
- if scratch.refCount == 0 then
152
- local payload = scratch.buff
153
- local payloadLen = scratch.cursor
154
- local server = Transport.server()
155
- -- Channel.writeBatchEncoded is hot-swapped by enableStats; re-read per call.
156
- local writeBatchEncoded = Channel.writeBatchEncoded
157
- for i = 1, count do
158
- writeBatchEncoded(
159
- server.getChannel(players[i], isUnreliable),
160
- reg,
161
- payload,
162
- payloadLen
163
- )
164
- end
165
- Shared.releaseScratch()
166
- bumpFires()
167
- return
168
- end
169
- Shared.releaseScratch()
170
- end
171
-
172
- for i = 1, count do
173
- sendToPlayer(players[i], data)
174
- end
175
- bumpFires()
176
- end
177
-
178
- --[[
179
- Resolve a target table into a { Player } list. Returns nil for unknown
180
- sentinel kinds; the caller errors with the original target type.
181
- ]]
182
- local function resolveAudience(target: any): { Player }?
183
- local kind = target._lyncKind
184
- if kind == "all" then
185
- return Players:GetPlayers()
186
- end
187
-
188
- if kind == "except" then
189
- local excluded = target._excluded :: { [Player]: boolean }
190
- local all = Players:GetPlayers()
191
- local list = table.create(#all)
192
- local n = 0
193
- for _, player in all do
194
- if not excluded[player] then
195
- n += 1
196
- list[n] = player
197
- end
198
- end
199
- return list
200
- end
201
-
202
- if kind == "group" then
203
- local members = target._members :: { [Player]: boolean }
204
- local list: { Player } = {}
205
- local n = 0
206
- for player in members do
207
- n += 1
208
- list[n] = player
209
- end
210
- return list
211
- end
212
-
213
- if kind == nil then
214
- -- Plain { Player } array. Validate entries on the way to a clean list.
215
- local list: { Player } = {}
216
- local n = 0
217
- for _, player in target do
218
- if isPlayer(player) then
219
- n += 1
220
- list[n] = player :: Player
221
- end
222
- end
223
- return list
224
- end
225
-
226
- return nil
227
- end
228
-
229
- local function sendToTarget(data: any, target: any): ()
230
- if isPlayer(target) then
231
- local dropped, sendData = applySend(data, target :: Player)
232
- if dropped then
233
- return
234
- end
235
- sendToPlayer(target :: Player, sendData)
236
- bumpFires()
237
- return
238
- end
239
-
240
- if typeof(target) == "table" then
241
- local dropped, sendData = applySend(data, nil)
242
- if dropped then
243
- return
244
- end
245
- local audience = resolveAudience(target)
246
- if audience then
247
- broadcast(audience, sendData)
248
- return
249
- end
250
- end
251
-
252
- Log.error(`"{name}" expected Player, table, Group, or Lync.all, got {typeof(target)}`)
253
- end
254
-
255
- local function sendFromServer(data: any, target: any): ()
256
- if target == nil then
257
- Log.error(`"{name}" server send requires a target`)
258
- end
259
- sendToTarget(data, target)
260
- end
261
-
262
- local function sendFromClient(data: any): ()
263
- local dropped, sendData = applySend(data, nil)
264
- if dropped then
265
- return
266
- end
267
- local ch = Transport.client().getChannel(isUnreliable)
268
- Channel.writeBatch(ch, reg, sendData)
269
- bumpFires()
270
- end
271
-
272
- type Self = PacketHandle<T>
273
- type Listener = (data: T, sender: Player?, timestamp: number?) -> ()
274
-
275
- local handle = {
276
- send = function(_self: Self, data: T, target: any?): ()
277
- if IS_SERVER then
278
- sendFromServer(data, target)
279
- else
280
- sendFromClient(data)
281
- end
282
- end,
283
-
284
- on = function(_self: Self, fn: Listener): Types.Connection
285
- return reg.signal:connect(fn :: any)
286
- end,
287
-
288
- once = function(_self: Self, fn: Listener): Types.Connection
289
- local conn: Types.Connection
290
- conn = reg.signal:connect(function(...: any)
291
- conn:disconnect()
292
- fn(...)
293
- end)
294
- return conn
295
- end,
296
-
297
- wait = function(_self: Self): (T, Player?, number?)
298
- return reg.signal:wait()
299
- end,
300
-
301
- name = function(_self: Self): string
302
- return reg.name
303
- end,
304
-
305
- stats = function(_self: Self): Types.PacketStats
306
- return {
307
- bytesSent = reg.bytesSent,
308
- bytesReceived = reg.bytesReceived,
309
- fires = reg.fires,
310
- recvFires = reg.recvFires,
311
- drops = reg.drops,
312
- }
313
- end,
314
- }
315
-
316
- return table.freeze(handle) :: PacketHandle<T>
317
- end
318
-
319
- return table.freeze(Packet)