@axpecter/lync 2.0.0 → 2.1.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 (55) hide show
  1. package/README.md +475 -426
  2. package/package.json +1 -1
  3. package/src/Types.luau +63 -31
  4. package/src/api/Group.luau +101 -106
  5. package/src/api/Packet.luau +187 -186
  6. package/src/api/Query.luau +223 -284
  7. package/src/api/Scope.luau +46 -57
  8. package/src/api/Signal.luau +104 -137
  9. package/src/codec/Base.luau +69 -20
  10. package/src/codec/composite/Array.luau +179 -270
  11. package/src/codec/composite/Map.luau +97 -347
  12. package/src/codec/composite/Optional.luau +27 -24
  13. package/src/codec/composite/Shared.luau +96 -65
  14. package/src/codec/composite/Struct.luau +200 -360
  15. package/src/codec/composite/Tagged.luau +62 -187
  16. package/src/codec/composite/Tuple.luau +79 -103
  17. package/src/codec/datatype/Buffer.luau +49 -21
  18. package/src/codec/datatype/CFrame.luau +207 -30
  19. package/src/codec/datatype/Color.luau +21 -11
  20. package/src/codec/datatype/Instance.luau +28 -21
  21. package/src/codec/datatype/IntVector.luau +33 -21
  22. package/src/codec/datatype/NumberRange.luau +19 -10
  23. package/src/codec/datatype/Ray.luau +26 -22
  24. package/src/codec/datatype/Rect.luau +20 -16
  25. package/src/codec/datatype/Region.luau +51 -45
  26. package/src/codec/datatype/Sequence.luau +64 -56
  27. package/src/codec/datatype/String.luau +89 -56
  28. package/src/codec/datatype/UDim.luau +40 -22
  29. package/src/codec/datatype/Vector.luau +181 -17
  30. package/src/codec/meta/Auto.luau +295 -253
  31. package/src/codec/meta/Bitfield.luau +104 -148
  32. package/src/codec/meta/Custom.luau +8 -4
  33. package/src/codec/meta/Enum.luau +29 -57
  34. package/src/codec/meta/Float.luau +64 -0
  35. package/src/codec/meta/Nothing.luau +9 -5
  36. package/src/codec/meta/Unknown.luau +44 -36
  37. package/src/codec/primitive/Bool.luau +16 -26
  38. package/src/codec/primitive/Float16.luau +58 -64
  39. package/src/codec/primitive/Int.luau +68 -0
  40. package/src/codec/primitive/Number.luau +21 -43
  41. package/src/codec/primitive/Varint.luau +67 -46
  42. package/src/index.d.ts +249 -335
  43. package/src/init.luau +319 -207
  44. package/src/internal/Baseline.luau +29 -24
  45. package/src/internal/Channel.luau +333 -278
  46. package/src/internal/Middleware.luau +60 -85
  47. package/src/internal/Pool.luau +19 -30
  48. package/src/internal/Registry.luau +56 -113
  49. package/src/transport/Bridge.luau +64 -43
  50. package/src/transport/Client.luau +59 -170
  51. package/src/transport/Gate.luau +282 -142
  52. package/src/transport/Reader.luau +148 -140
  53. package/src/transport/Server.luau +138 -488
  54. package/src/api/Namespace.luau +0 -256
  55. package/src/codec/meta/Quantized.luau +0 -174
@@ -1,206 +1,95 @@
1
1
  --!strict
2
2
  --!optimize 2
3
- -- Client-side transport with batching, frame XOR on reliable.
3
+ -- Client-side transport: single channel pair, flush.
4
4
 
5
- local RunService = game:GetService("RunService")
6
-
7
- local Bridge = require(script.Parent.Bridge)
5
+ local Bridge = require(script.Parent.Parent.transport.Bridge)
8
6
  local Channel = require(script.Parent.Parent.internal.Channel)
9
- local Middleware = require(script.Parent.Parent.internal.Middleware)
10
- local Reader = require(script.Parent.Reader)
7
+ local Reader = require(script.Parent.Parent.transport.Reader)
11
8
  local Types = require(script.Parent.Parent.Types)
12
9
 
13
- type ChannelState = Types.ChannelState
14
- type Codec<T> = Types.Codec<T>
15
- type Registration = Types.Registration
16
-
17
10
  -- State ---------------------------------------------------------------
18
11
 
19
- local NOT_STARTED = "[Lync] Client not started. Call Lync.start() before sending"
20
-
21
- local _reliable = nil :: ChannelState?
22
- local _unreliable = nil :: ChannelState?
23
- local _prevRecv = nil :: buffer?
24
- local _isStarted = false
25
-
26
- -- Flush control
27
- local _flushRate = 60
28
- local _flushInterval = 1 / 60
29
- local _useAccumulator = false
30
- local _flushAccum = 0
31
- local _flushedThisFrame = false
12
+ local _reliable: Types.ChannelState = Channel.create()
13
+ local _unreliable: Types.ChannelState = Channel.create()
14
+ local _prevIncoming: buffer? = nil
15
+ local _prevIncomingLen = 0
32
16
 
33
- -- Timestamp
34
- local _frameCounter: number = 0
35
-
36
- -- Private -------------------------------------------------------------
37
-
38
- local function receive(data: any, refs: any, applyXor: boolean): ()
39
- local buf = Reader.decodeIncoming(data)
40
- if not buf then
41
- return
42
- end
17
+ -- Public --------------------------------------------------------------
43
18
 
44
- local raw: buffer
45
- if applyXor then
46
- raw = Channel.xorApply(buf, _prevRecv)
47
- _prevRecv = raw
48
- else
49
- raw = buf
50
- end
19
+ local Client = {}
51
20
 
52
- local safeRefs: { Instance }? = if typeof(refs) == "table" then refs else nil
53
- local ok, err = pcall(Reader.process, raw, safeRefs, nil, 0)
54
- if not ok then
55
- warn(`[Lync] Read failed: {err}`)
56
- end
21
+ function Client.getChannel(isUnreliable: boolean): Types.ChannelState
22
+ return if isUnreliable then _unreliable else _reliable
57
23
  end
58
24
 
59
- local function flushChannel(remote: any, ch: ChannelState, applyXor: boolean): ()
60
- if ch.cursor == 0 then
61
- return
25
+ function Client.flush(): ()
26
+ if Channel.hasTimestamps() then
27
+ Channel.updateTimestamp()
62
28
  end
63
29
 
64
- local raw, refs = Channel.sealAndDump(ch)
65
-
66
- if applyXor then
67
- local xored = Channel.xorApply(raw, ch.prevDump)
68
- ch.prevDump = raw
69
- remote:FireServer(xored, refs)
70
- else
71
- remote:FireServer(raw, refs)
30
+ -- Reliable
31
+ if _reliable.cursor > 0 then
32
+ local snapshot, refs, byteLen, _ = Channel.sealAndDump(_reliable)
33
+ Bridge.fireServer(snapshot, refs)
34
+ Channel.reset(_reliable)
72
35
  end
73
36
 
74
- Channel.reset(ch)
75
- end
76
-
77
- local function flush(): ()
78
- if Channel.hasTimestamps() then
79
- _frameCounter = (_frameCounter + 1) % 256
80
- Channel.updateTimestamp(_frameCounter, 0, os.clock())
37
+ -- Unreliable
38
+ if _unreliable.cursor > 0 then
39
+ local snapshot, refs, byteLen, _ = Channel.sealAndDump(_unreliable)
40
+ Bridge.fireServerUnreliable(snapshot, refs)
41
+ Channel.reset(_unreliable)
81
42
  end
82
-
83
- flushChannel(Bridge.reliable, _reliable :: ChannelState, true)
84
- flushChannel(Bridge.unreliable, _unreliable :: ChannelState, false)
85
43
  end
86
44
 
87
- -- Public --------------------------------------------------------------
88
-
89
- local Client = {}
90
-
91
45
  function Client.start(): ()
92
- if _isStarted then
93
- return
94
- end
95
- _isStarted = true
46
+ local container = game:GetService("ReplicatedStorage"):WaitForChild("LyncRemotes")
47
+ Bridge.setup(container)
96
48
 
97
- Bridge.setup()
49
+ local reliable = Bridge.reliable()
50
+ local unreliable = Bridge.unreliable()
98
51
 
99
- _reliable = Channel.create()
100
- _unreliable = Channel.create()
101
-
102
- Bridge.reliable.OnClientEvent:Connect(function(data: any, refs: any): ()
103
- receive(data, refs, true)
104
- end)
105
- Bridge.unreliable.OnClientEvent:Connect(function(data: any, refs: any): ()
106
- receive(data, refs, false)
107
- end)
108
-
109
- if _useAccumulator then
110
- RunService.Heartbeat:Connect(function(dt: number)
111
- if _flushedThisFrame then
112
- _flushedThisFrame = false
113
- return
114
- end
115
- _flushAccum += dt
116
- if _flushAccum < _flushInterval then
117
- return
118
- end
119
- _flushAccum -= _flushInterval
120
- flush()
121
- end)
122
- else
123
- RunService.Heartbeat:Connect(function()
124
- if _flushedThisFrame then
125
- _flushedThisFrame = false
126
- return
127
- end
128
- flush()
129
- end)
130
- end
131
- end
132
-
133
- function Client.write(reg: Registration, data: any, isUnreliable: boolean): ()
134
- if not _isStarted then
135
- error(NOT_STARTED)
136
- end
137
-
138
- local final: any
139
- if Middleware.hasSend then
140
- final = Middleware.runSend(data, reg.name, nil)
141
- if final == nil then
52
+ -- Incoming reliable (XOR encoded)
53
+ reliable.OnClientEvent:Connect(function(data: any, refs: any?)
54
+ local incoming = Reader.decodeIncoming(data)
55
+ if not incoming then
142
56
  return
143
57
  end
144
- else
145
- final = data
146
- end
147
58
 
148
- local ch = if isUnreliable then _unreliable :: ChannelState else _reliable :: ChannelState
149
- if Channel.statsEnabled() then
150
- local before = ch.cursor
151
- Channel.writeBatch(ch, reg, final)
152
- reg.bytesSent += ch.cursor - before
153
- reg.fires += 1
154
- else
155
- Channel.writeBatch(ch, reg, final)
156
- end
157
- end
158
-
159
- function Client.writeQuery(
160
- id: number,
161
- name: string,
162
- correlationId: number,
163
- codec: Codec<any>,
164
- data: any
165
- ): ()
166
- if not _isStarted then
167
- error(NOT_STARTED)
168
- end
59
+ local incomingLen = buffer.len(incoming)
169
60
 
170
- local final: any
171
- if Middleware.hasSend then
172
- final = Middleware.runSend(data, name, nil)
173
- if final == nil then
174
- return
61
+ -- XOR decode against previous frame
62
+ local decoded: buffer
63
+ if _prevIncoming then
64
+ decoded = Channel.xorApply(incoming, incomingLen, _prevIncoming, _prevIncomingLen)
65
+ else
66
+ decoded = incoming
175
67
  end
176
- else
177
- final = data
178
- end
179
68
 
180
- Channel.writeQuery(_reliable :: ChannelState, id, name, correlationId, codec, final)
181
- end
69
+ -- Store decoded (not XOR'd) for next frame's XOR base
70
+ _prevIncoming = decoded
71
+ _prevIncomingLen = incomingLen
182
72
 
183
- function Client.writeQueryNil(id: number, name: string, correlationId: number): ()
184
- if not _isStarted then
185
- error(NOT_STARTED)
186
- end
187
- Channel.writeQuery(_reliable :: ChannelState, id, name, correlationId, nil, nil)
188
- end
73
+ local ok, err = pcall(Reader.process, decoded, incomingLen, refs :: any, nil, false)
74
+ if not ok then
75
+ warn(`[Lync] Client: read error: {err}`)
76
+ end
77
+ end)
189
78
 
190
- function Client.flush(): ()
191
- _flushAccum = 0
192
- _flushedThisFrame = true
193
- flush()
194
- end
79
+ -- Incoming unreliable (no XOR)
80
+ unreliable.OnClientEvent:Connect(function(data: any, refs: any?)
81
+ local incoming = Reader.decodeIncoming(data)
82
+ if not incoming then
83
+ return
84
+ end
195
85
 
196
- function Client.setFlushRate(hz: number): ()
197
- _flushRate = math.clamp(hz, 1, 60)
198
- _flushInterval = 1 / _flushRate
199
- _useAccumulator = _flushRate < 60
200
- end
86
+ local incomingLen = buffer.len(incoming)
201
87
 
202
- function Client.getFlushRate(): number
203
- return _flushRate
88
+ local ok, err = pcall(Reader.process, incoming, incomingLen, refs :: any, nil, false)
89
+ if not ok then
90
+ warn(`[Lync] Client: read error (unreliable): {err}`)
91
+ end
92
+ end)
204
93
  end
205
94
 
206
95
  return table.freeze(Client)