@axpecter/lync 1.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 (52) hide show
  1. package/README.md +300 -0
  2. package/package.json +38 -0
  3. package/src/Types.luau +63 -0
  4. package/src/api/Group.luau +126 -0
  5. package/src/api/Namespace.luau +226 -0
  6. package/src/api/Packet.luau +147 -0
  7. package/src/api/Query.luau +295 -0
  8. package/src/api/Signal.luau +224 -0
  9. package/src/codec/Base.luau +49 -0
  10. package/src/codec/composite/Array.luau +275 -0
  11. package/src/codec/composite/Map.luau +395 -0
  12. package/src/codec/composite/Optional.luau +47 -0
  13. package/src/codec/composite/Shared.luau +151 -0
  14. package/src/codec/composite/Struct.luau +440 -0
  15. package/src/codec/composite/Tagged.luau +222 -0
  16. package/src/codec/composite/Tuple.luau +143 -0
  17. package/src/codec/datatype/Buffer.luau +44 -0
  18. package/src/codec/datatype/CFrame.luau +51 -0
  19. package/src/codec/datatype/Color.luau +22 -0
  20. package/src/codec/datatype/Instance.luau +48 -0
  21. package/src/codec/datatype/IntVector.luau +25 -0
  22. package/src/codec/datatype/NumberRange.luau +14 -0
  23. package/src/codec/datatype/Ray.luau +27 -0
  24. package/src/codec/datatype/Rect.luau +21 -0
  25. package/src/codec/datatype/Region.luau +58 -0
  26. package/src/codec/datatype/Sequence.luau +129 -0
  27. package/src/codec/datatype/String.luau +87 -0
  28. package/src/codec/datatype/UDim.luau +27 -0
  29. package/src/codec/datatype/Vector.luau +25 -0
  30. package/src/codec/meta/Auto.luau +353 -0
  31. package/src/codec/meta/Bitfield.luau +191 -0
  32. package/src/codec/meta/Custom.luau +27 -0
  33. package/src/codec/meta/Enum.luau +80 -0
  34. package/src/codec/meta/Nothing.luau +9 -0
  35. package/src/codec/meta/Quantized.luau +170 -0
  36. package/src/codec/meta/Unknown.luau +35 -0
  37. package/src/codec/primitive/Bool.luau +30 -0
  38. package/src/codec/primitive/Float16.luau +111 -0
  39. package/src/codec/primitive/Number.luau +48 -0
  40. package/src/codec/primitive/Varint.luau +76 -0
  41. package/src/index.d.ts +279 -0
  42. package/src/init.luau +161 -0
  43. package/src/internal/Baseline.luau +41 -0
  44. package/src/internal/Channel.luau +235 -0
  45. package/src/internal/Middleware.luau +109 -0
  46. package/src/internal/Pool.luau +68 -0
  47. package/src/internal/Registry.luau +146 -0
  48. package/src/transport/Bridge.luau +66 -0
  49. package/src/transport/Client.luau +151 -0
  50. package/src/transport/Gate.luau +222 -0
  51. package/src/transport/Reader.luau +175 -0
  52. package/src/transport/Server.luau +364 -0
package/src/index.d.ts ADDED
@@ -0,0 +1,279 @@
1
+ // Type declarations for Lync networking library.
2
+
3
+ // -- Utility types -----------------------------------------------------
4
+
5
+ // Expands mapped types in hover tooltips.
6
+ type Prettify<T> = { [K in keyof T]: T[K] } & {};
7
+
8
+ // -- Codec -------------------------------------------------------------
9
+
10
+ // Opaque codec handle. Carries the serialized type at the type level.
11
+ export interface Codec<T> {
12
+ /** @hidden @deprecated Do not use. Only for type metadata. */
13
+ readonly _nominal_Codec: T;
14
+ }
15
+
16
+ // Extracts the value type from a codec.
17
+ export type InferCodec<C> = C extends Codec<infer T> ? T : never;
18
+
19
+ // Maps a record of codecs to a record of their value types.
20
+ type InferSchema<S extends Record<string, Codec<unknown>>> = Prettify<{
21
+ [K in keyof S]: InferCodec<S[K]>;
22
+ }>;
23
+
24
+ // Maps a tuple of codecs to a tuple of their value types.
25
+ type InferTuple<T extends readonly Codec<unknown>[]> = {
26
+ [K in keyof T]: InferCodec<T[K]>;
27
+ };
28
+
29
+ // Infers the discriminated union from a tagged variant map.
30
+ type InferTagged<
31
+ Tag extends string,
32
+ V extends Record<string, Codec<unknown>>,
33
+ > = {
34
+ [K in keyof V & string]: Prettify<InferCodec<V[K]> & { [T in Tag]: K }>;
35
+ }[keyof V & string];
36
+
37
+ // -- Connection --------------------------------------------------------
38
+
39
+ export interface Connection {
40
+ readonly connected: boolean;
41
+ disconnect(this: Connection): void;
42
+ }
43
+
44
+ // -- Config ------------------------------------------------------------
45
+
46
+ export interface RateLimitConfig {
47
+ maxPerSecond: number;
48
+ burstAllowance?: number;
49
+ }
50
+
51
+ export interface BoolFieldSpec {
52
+ type: "bool";
53
+ }
54
+
55
+ export interface UintFieldSpec {
56
+ type: "uint";
57
+ width: number;
58
+ }
59
+
60
+ export interface IntFieldSpec {
61
+ type: "int";
62
+ width: number;
63
+ }
64
+
65
+ export type FieldSpec = BoolFieldSpec | UintFieldSpec | IntFieldSpec;
66
+
67
+ type InferFieldSpec<F extends FieldSpec> = F extends BoolFieldSpec
68
+ ? boolean
69
+ : number;
70
+
71
+ type InferBitfield<S extends Record<string, FieldSpec>> = Prettify<{
72
+ [K in keyof S]: InferFieldSpec<S[K]>;
73
+ }>;
74
+
75
+ // -- Packet ------------------------------------------------------------
76
+
77
+ export interface PacketConfig<T> {
78
+ value: Codec<T>;
79
+ unreliable?: boolean;
80
+ rateLimit?: RateLimitConfig;
81
+ validate?: (data: T, player: Player) => LuaTuple<[boolean, string?]>;
82
+ maxPayloadBytes?: number;
83
+ }
84
+
85
+ // Server methods throw on client and vice versa.
86
+ export interface Packet<T> {
87
+ sendTo(this: Packet<T>, data: T, player: Player): void;
88
+ sendToAll(this: Packet<T>, data: T): void;
89
+ sendToAllExcept(this: Packet<T>, data: T, except: Player): void;
90
+ sendToList(this: Packet<T>, data: T, players: Player[]): void;
91
+ sendToGroup(this: Packet<T>, data: T, groupName: string): void;
92
+ send(this: Packet<T>, data: T): void;
93
+ listen(this: Packet<T>, callback: (data: T, sender: Player | undefined) => void): Connection;
94
+ once(this: Packet<T>, callback: (data: T, sender: Player | undefined) => void): Connection;
95
+ wait(this: Packet<T>): LuaTuple<[T, Player | undefined]>;
96
+ disconnectAll(this: Packet<T>): void;
97
+ }
98
+
99
+ // -- Query -------------------------------------------------------------
100
+
101
+ export interface QueryConfig<Req, Resp> {
102
+ request: Codec<Req>;
103
+ response: Codec<Resp>;
104
+ timeout?: number;
105
+ rateLimit?: RateLimitConfig;
106
+ validate?: (data: Req, player: Player) => LuaTuple<[boolean, string?]>;
107
+ }
108
+
109
+ export interface Query<Req, Resp> {
110
+ listen(
111
+ this: Query<Req, Resp>,
112
+ callback: (request: Req, player: Player) => Resp | undefined,
113
+ ): Connection;
114
+ invoke(this: Query<Req, Resp>, request: Req, player?: Player): Resp | undefined;
115
+ invokeAll(this: Query<Req, Resp>, request: Req): Map<Player, Resp | undefined>;
116
+ invokeList(
117
+ this: Query<Req, Resp>,
118
+ request: Req,
119
+ players: Player[],
120
+ ): Map<Player, Resp | undefined>;
121
+ invokeGroup(
122
+ this: Query<Req, Resp>,
123
+ request: Req,
124
+ groupName: string,
125
+ ): Map<Player, Resp | undefined>;
126
+ }
127
+
128
+ // -- Namespace ---------------------------------------------------------
129
+
130
+ export interface NamespaceConfig {
131
+ packets?: Record<string, PacketConfig<unknown>>;
132
+ queries?: Record<string, QueryConfig<unknown, unknown>>;
133
+ }
134
+
135
+ type InferPackets<P extends Record<string, PacketConfig<unknown>>> = {
136
+ [K in keyof P]: P[K] extends PacketConfig<infer T> ? Packet<T> : never;
137
+ };
138
+
139
+ type InferQueries<Q extends Record<string, QueryConfig<unknown, unknown>>> = {
140
+ [K in keyof Q]: Q[K] extends QueryConfig<infer Req, infer Resp>
141
+ ? Query<Req, Resp>
142
+ : never;
143
+ };
144
+
145
+ export interface Namespace {
146
+ listenAll(
147
+ this: Namespace,
148
+ callback: (name: string, data: unknown, sender: Player | undefined) => void,
149
+ ): Connection;
150
+ onSend(
151
+ this: Namespace,
152
+ handler: (data: unknown, name: string, player: Player | undefined) => unknown | undefined,
153
+ ): () => void;
154
+ onReceive(
155
+ this: Namespace,
156
+ handler: (data: unknown, name: string, player: Player | undefined) => unknown | undefined,
157
+ ): () => void;
158
+ disconnectAll(this: Namespace): void;
159
+ destroy(this: Namespace): void;
160
+ packetNames(this: Namespace): string[];
161
+ queryNames(this: Namespace): string[];
162
+ }
163
+
164
+ // -- Lync --------------------------------------------------------------
165
+
166
+ declare namespace Lync {
167
+ // Lifecycle
168
+ export const VERSION: string;
169
+ export const version: string;
170
+ export function start(): void;
171
+
172
+ // Definition
173
+ export function definePacket<T>(name: string, config: PacketConfig<T>): Packet<T>;
174
+ export function defineQuery<Req, Resp>(
175
+ name: string,
176
+ config: QueryConfig<Req, Resp>,
177
+ ): Query<Req, Resp>;
178
+ export function defineNamespace<
179
+ P extends Record<string, PacketConfig<unknown>> = {},
180
+ Q extends Record<string, QueryConfig<unknown, unknown>> = {},
181
+ >(
182
+ name: string,
183
+ config: { packets?: P; queries?: Q },
184
+ ): Namespace & InferPackets<P> & InferQueries<Q>;
185
+
186
+ // Primitives
187
+ export const u8: Codec<number>;
188
+ export const u16: Codec<number>;
189
+ export const u32: Codec<number>;
190
+ export const i8: Codec<number>;
191
+ export const i16: Codec<number>;
192
+ export const i32: Codec<number>;
193
+ export const f32: Codec<number>;
194
+ export const f64: Codec<number>;
195
+ export const bool: Codec<boolean>;
196
+ export const f16: Codec<number>;
197
+
198
+ // Datatypes
199
+ const string: Codec<string>;
200
+ export { string };
201
+ export const vec2: Codec<Vector2>;
202
+ export const vec3: Codec<Vector3>;
203
+ export const cframe: Codec<CFrame>;
204
+ export const color3: Codec<Color3>;
205
+ export const inst: Codec<Instance>;
206
+ export const buff: Codec<buffer>;
207
+ export const udim: Codec<UDim>;
208
+ export const udim2: Codec<UDim2>;
209
+ export const numberRange: Codec<NumberRange>;
210
+ export const rect: Codec<Rect>;
211
+ export const vec2int16: Codec<Vector2int16>;
212
+ export const vec3int16: Codec<Vector3int16>;
213
+ export const region3: Codec<Region3>;
214
+ export const region3int16: Codec<Region3int16>;
215
+ export const ray: Codec<Ray>;
216
+ export const numberSequence: Codec<NumberSequence>;
217
+ export const colorSequence: Codec<ColorSequence>;
218
+
219
+ // Composites
220
+ export function struct<S extends Record<string, Codec<unknown>>>(schema: S): Codec<InferSchema<S>>;
221
+ export function deltaStruct<S extends Record<string, Codec<unknown>>>(schema: S): Codec<InferSchema<S>>;
222
+ export function array<T>(element: Codec<T>, maxCount?: number): Codec<T[]>;
223
+ export function deltaArray<T>(element: Codec<T>, maxCount?: number): Codec<T[]>;
224
+ export function map<K extends defined, V>(key: Codec<K>, value: Codec<V>, maxCount?: number): Codec<Map<K, V>>;
225
+ export function deltaMap<K extends defined, V>(key: Codec<K>, value: Codec<V>, maxCount?: number): Codec<Map<K, V>>;
226
+ export function optional<T>(inner: Codec<T>): Codec<T | undefined>;
227
+
228
+ // Meta
229
+ function _enum<T extends string>(...values: T[]): Codec<T>;
230
+ export { _enum as enum };
231
+ export function quantizedFloat(min: number, max: number, precision: number): Codec<number>;
232
+ export function quantizedVec3(min: number, max: number, precision: number): Codec<Vector3>;
233
+ export function bitfield<S extends Record<string, FieldSpec>>(schema: S): Codec<InferBitfield<S>>;
234
+ export function tagged<Tag extends string, V extends Record<string, Codec<unknown>>>(
235
+ tagField: Tag,
236
+ variants: V,
237
+ ): Codec<InferTagged<Tag, V>>;
238
+ export function tuple<T extends Codec<unknown>[]>(...codecs: T): Codec<InferTuple<T>>;
239
+ export function custom<T>(
240
+ size: number,
241
+ write: (b: buffer, offset: number, value: T) => void,
242
+ read: (b: buffer, offset: number) => T,
243
+ ): Codec<T>;
244
+ export function boundedString(maxLength: number): Codec<string>;
245
+ export const nothing: Codec<undefined>;
246
+ export const unknown: Codec<unknown>;
247
+ export const auto: Codec<unknown>;
248
+
249
+ // Hooks
250
+ export function onDrop(
251
+ callback: (player: Player, reason: string, packetName: string, data: unknown) => void,
252
+ ): () => void;
253
+ export function onSend(
254
+ handler: (data: unknown, name: string, player: Player | undefined) => unknown | undefined,
255
+ ): () => void;
256
+ export function onReceive(
257
+ handler: (data: unknown, name: string, player: Player | undefined) => unknown | undefined,
258
+ ): () => void;
259
+
260
+ // Groups
261
+ export function createGroup(name: string): void;
262
+ export function destroyGroup(name: string): void;
263
+ export function addToGroup(name: string, player: Player): boolean;
264
+ export function removeFromGroup(name: string, player: Player): boolean;
265
+ export function hasInGroup(name: string, player: Player): boolean;
266
+ export function getGroupSet(name: string): ReadonlyMap<Player, true>;
267
+ export function groupCount(name: string): number;
268
+ export function forEachInGroup(name: string, fn: (player: Player) => void): void;
269
+
270
+ // Configuration
271
+ export function setChannelMaxSize(bytes: number): void;
272
+ export function setValidationDepth(depth: number): void;
273
+ export function setPoolSize(count: number): void;
274
+
275
+ // Introspection
276
+ export function queryPendingCount(): number;
277
+ }
278
+
279
+ export default Lync;
package/src/init.luau ADDED
@@ -0,0 +1,161 @@
1
+ --!strict
2
+ --!optimize 2
3
+ -- Public API.
4
+
5
+ local RunService = game:GetService ("RunService")
6
+
7
+ -- Codec: primitive
8
+ local BoolCodec = require (script.codec.primitive.Bool)
9
+ local Float16 = require (script.codec.primitive.Float16)
10
+ local Number = require (script.codec.primitive.Number)
11
+
12
+ -- Codec: datatype
13
+ local Buffer = require (script.codec.datatype.Buffer)
14
+ local CFrameCodec = require (script.codec.datatype.CFrame)
15
+ local Color = require (script.codec.datatype.Color)
16
+ local InstanceCodec = require (script.codec.datatype.Instance)
17
+ local IntVector = require (script.codec.datatype.IntVector)
18
+ local NumberRangeCodec = require (script.codec.datatype.NumberRange)
19
+ local RayCodec = require (script.codec.datatype.Ray)
20
+ local RectCodec = require (script.codec.datatype.Rect)
21
+ local Region = require (script.codec.datatype.Region)
22
+ local Sequence = require (script.codec.datatype.Sequence)
23
+ local String = require (script.codec.datatype.String)
24
+ local UDimCodec = require (script.codec.datatype.UDim)
25
+ local Vector = require (script.codec.datatype.Vector)
26
+
27
+ -- Codec: composite
28
+ local Array = require (script.codec.composite.Array)
29
+ local Map = require (script.codec.composite.Map)
30
+ local Optional = require (script.codec.composite.Optional)
31
+ local Struct = require (script.codec.composite.Struct)
32
+ local Tagged = require (script.codec.composite.Tagged)
33
+ local Tuple = require (script.codec.composite.Tuple)
34
+
35
+ -- Codec: meta
36
+ local Auto = require (script.codec.meta.Auto)
37
+ local Bitfield = require (script.codec.meta.Bitfield)
38
+ local Custom = require (script.codec.meta.Custom)
39
+ local EnumCodec = require (script.codec.meta.Enum)
40
+ local Nothing = require (script.codec.meta.Nothing)
41
+ local Quantized = require (script.codec.meta.Quantized)
42
+ local Unknown = require (script.codec.meta.Unknown)
43
+
44
+ -- Internal
45
+ local Channel = require (script.internal.Channel)
46
+ local Gate = require (script.transport.Gate)
47
+ local Middleware = require (script.internal.Middleware)
48
+ local Pool = require (script.internal.Pool)
49
+
50
+ -- API
51
+ local Group = require (script.api.Group)
52
+ local Namespace = require (script.api.Namespace)
53
+ local Packet = require (script.api.Packet)
54
+ local Query = require (script.api.Query)
55
+
56
+ -- Transport
57
+ local Client = require (script.transport.Client)
58
+ local Server = require (script.transport.Server)
59
+
60
+ -- Public -----------------------------------------------------------------
61
+
62
+ local function start (): ()
63
+ if RunService:IsServer () then
64
+ Server.start ()
65
+ else
66
+ Client.start ()
67
+ end
68
+ end
69
+
70
+ local Lync = {
71
+ VERSION = "1.3.0",
72
+ version = "1.3.0",
73
+
74
+ -- Lifecycle
75
+ start = start,
76
+
77
+ -- Definition
78
+ definePacket = Packet.define,
79
+ defineQuery = Query.define,
80
+ defineNamespace = Namespace.define,
81
+
82
+ -- Primitives
83
+ u8 = Number.u8,
84
+ u16 = Number.u16,
85
+ u32 = Number.u32,
86
+ i8 = Number.i8,
87
+ i16 = Number.i16,
88
+ i32 = Number.i32,
89
+ f32 = Number.f32,
90
+ f64 = Number.f64,
91
+ bool = BoolCodec.bool,
92
+ f16 = Float16.f16,
93
+
94
+ -- Datatypes
95
+ string = String.string,
96
+ boundedString = String.bounded,
97
+ vec2 = Vector.vec2,
98
+ vec3 = Vector.vec3,
99
+ cframe = CFrameCodec.cframe,
100
+ color3 = Color.color3,
101
+ inst = InstanceCodec.inst,
102
+ buff = Buffer.buff,
103
+ udim = UDimCodec.udim,
104
+ udim2 = UDimCodec.udim2,
105
+ numberRange = NumberRangeCodec.numberRange,
106
+ rect = RectCodec.rect,
107
+ vec2int16 = IntVector.vec2int16,
108
+ vec3int16 = IntVector.vec3int16,
109
+ region3 = Region.region3,
110
+ region3int16 = Region.region3int16,
111
+ ray = RayCodec.ray,
112
+ numberSequence = Sequence.numberSequence,
113
+ colorSequence = Sequence.colorSequence,
114
+
115
+ -- Composites
116
+ struct = Struct.struct,
117
+ deltaStruct = Struct.deltaStruct,
118
+ deltaArray = Array.deltaArray,
119
+ deltaMap = Map.deltaMap,
120
+ array = Array.array,
121
+ map = Map.map,
122
+ optional = Optional.optional,
123
+ tuple = Tuple.define,
124
+ tagged = Tagged.define,
125
+
126
+ -- Meta
127
+ enum = EnumCodec.define,
128
+ quantizedFloat = Quantized.float,
129
+ quantizedVec3 = Quantized.vec3,
130
+ bitfield = Bitfield.define,
131
+ custom = Custom.define,
132
+
133
+ nothing = Nothing.nothing,
134
+ unknown = Unknown.unknown,
135
+ auto = Auto.auto,
136
+
137
+ -- Hooks
138
+ onDrop = Gate.onDrop,
139
+ onSend = Middleware.addSend,
140
+ onReceive = Middleware.addReceive,
141
+
142
+ -- Groups
143
+ createGroup = Group.create,
144
+ destroyGroup = Group.destroy,
145
+ addToGroup = Group.add,
146
+ removeFromGroup = Group.remove,
147
+ hasInGroup = Group.has,
148
+ getGroupSet = Group.getSet,
149
+ groupCount = Group.count,
150
+ forEachInGroup = Group.forEach,
151
+
152
+ -- Configuration (call before start)
153
+ setChannelMaxSize = Channel.setMaxSize,
154
+ setValidationDepth = Gate.setMaxDepth,
155
+ setPoolSize = Pool.setMaxSize,
156
+
157
+ -- Introspection
158
+ queryPendingCount = Query.pendingCount,
159
+ }
160
+
161
+ return table.freeze (Lync)
@@ -0,0 +1,41 @@
1
+ --!strict
2
+ --!optimize 2
3
+ -- Read-side baseline cache keyed by source (player or client sentinel).
4
+
5
+ -- State ------------------------------------------------------------------
6
+
7
+ local _readKey = false :: any
8
+ local _readCaches = {} :: { [any]: { [number]: any } }
9
+
10
+ -- Public -----------------------------------------------------------------
11
+
12
+ local Baseline = {}
13
+
14
+ Baseline.hasDelta = false
15
+
16
+ function Baseline.setReadKey (key: any): ()
17
+ _readKey = key
18
+ end
19
+
20
+ function Baseline.getCache (deltaId: number): any
21
+ local map = _readCaches[_readKey]
22
+ return map and map[deltaId]
23
+ end
24
+
25
+ function Baseline.setCache (deltaId: number, data: any): ()
26
+ if not Baseline.hasDelta then
27
+ Baseline.hasDelta = true
28
+ end
29
+ local map = _readCaches[_readKey]
30
+ if not map then
31
+ map = {}
32
+ _readCaches[_readKey] = map
33
+ end
34
+ map[deltaId] = data
35
+ end
36
+
37
+ function Baseline.clearSource (key: any): ()
38
+ _readCaches[key] = nil
39
+ end
40
+
41
+ return Baseline