@skating/swiftpacket 0.1.4
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.
- package/LICENSE +21 -0
- package/README.md +123 -0
- package/package.json +31 -0
- package/src/client.luau +472 -0
- package/src/configuration.luau +74 -0
- package/src/cursor.luau +18 -0
- package/src/index.d.ts +122 -0
- package/src/init.luau +199 -0
- package/src/packet.luau +186 -0
- package/src/rate_limit.luau +38 -0
- package/src/registry.luau +40 -0
- package/src/schema.luau +1606 -0
- package/src/server.luau +691 -0
- package/src/signal.luau +145 -0
- package/src/thread_pool.luau +37 -0
- package/src/wire.luau +218 -0
package/src/schema.luau
ADDED
|
@@ -0,0 +1,1606 @@
|
|
|
1
|
+
--!strict
|
|
2
|
+
--!optimize 2
|
|
3
|
+
|
|
4
|
+
--[[
|
|
5
|
+
Author: @skaterstudios
|
|
6
|
+
Website: skaterstudios.com
|
|
7
|
+
GitHub: github.com/skatingii/SwiftPacket
|
|
8
|
+
Discord Server: discord.gg/skaterstudios
|
|
9
|
+
|
|
10
|
+
Licensed under the MIT License. You may use, modify, redistribute and sell
|
|
11
|
+
this system freely, as long as this notice and the LICENSE file stay with it.
|
|
12
|
+
]]
|
|
13
|
+
|
|
14
|
+
export type Cursor = {
|
|
15
|
+
Buffer: buffer,
|
|
16
|
+
Length: number,
|
|
17
|
+
Offset: number,
|
|
18
|
+
Instances: { any },
|
|
19
|
+
InstancesOffset: number,
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
local ActiveCursor: Cursor? = nil
|
|
23
|
+
local ActiveBuffer: buffer = buffer.create(0)
|
|
24
|
+
local BufferLength = 0
|
|
25
|
+
local BufferOffset = 0
|
|
26
|
+
local Instances: { any } = {}
|
|
27
|
+
local InstancesOffset = 0
|
|
28
|
+
local Untrusted = false
|
|
29
|
+
local Writing = "a value"
|
|
30
|
+
|
|
31
|
+
const function WriteFailure(Message: string): never
|
|
32
|
+
if Writing == "" then
|
|
33
|
+
error(`[swiftpacket] {Message}`, 0)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
error(`[swiftpacket] could not write {Writing}: {Message}`, 0)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
const function NewCursor(Size: number?): Cursor
|
|
40
|
+
const Length = Size or 128
|
|
41
|
+
|
|
42
|
+
return {
|
|
43
|
+
Buffer = buffer.create(Length),
|
|
44
|
+
Length = Length,
|
|
45
|
+
Offset = 0,
|
|
46
|
+
Instances = {},
|
|
47
|
+
InstancesOffset = 0,
|
|
48
|
+
}
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
const function Import(Target: Cursor)
|
|
52
|
+
ActiveCursor = Target
|
|
53
|
+
ActiveBuffer = Target.Buffer
|
|
54
|
+
BufferLength = Target.Length
|
|
55
|
+
BufferOffset = Target.Offset
|
|
56
|
+
Instances = Target.Instances
|
|
57
|
+
InstancesOffset = Target.InstancesOffset
|
|
58
|
+
Untrusted = false
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
const function Export(): Cursor
|
|
62
|
+
const Target = ActiveCursor
|
|
63
|
+
|
|
64
|
+
if Target == nil then
|
|
65
|
+
error("[swiftpacket] there is no cursor to export, the active one is read only", 0)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
Target.Buffer = ActiveBuffer
|
|
69
|
+
Target.Length = BufferLength
|
|
70
|
+
Target.Offset = BufferOffset
|
|
71
|
+
Target.InstancesOffset = InstancesOffset
|
|
72
|
+
|
|
73
|
+
return Target
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
const function Load(
|
|
77
|
+
Source: buffer,
|
|
78
|
+
SourceInstances: { any },
|
|
79
|
+
IsUntrusted: boolean,
|
|
80
|
+
Offset: number,
|
|
81
|
+
StartInstances: number
|
|
82
|
+
)
|
|
83
|
+
ActiveCursor = nil
|
|
84
|
+
ActiveBuffer = Source
|
|
85
|
+
BufferLength = buffer.len(Source)
|
|
86
|
+
BufferOffset = Offset
|
|
87
|
+
Instances = SourceInstances
|
|
88
|
+
InstancesOffset = StartInstances
|
|
89
|
+
Untrusted = IsUntrusted
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
const function Reset(Target: Cursor)
|
|
93
|
+
Target.Offset = 0
|
|
94
|
+
|
|
95
|
+
if Target.InstancesOffset > 0 then
|
|
96
|
+
Target.InstancesOffset = 0
|
|
97
|
+
table.clear(Target.Instances)
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
const function Take(Target: Cursor): (buffer, { any }?)
|
|
102
|
+
const Truncated = buffer.create(Target.Offset)
|
|
103
|
+
buffer.copy(Truncated, 0, Target.Buffer, 0, Target.Offset)
|
|
104
|
+
|
|
105
|
+
if Target.InstancesOffset == 0 then
|
|
106
|
+
return Truncated, nil
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
return Truncated, table.move(Target.Instances, 1, Target.InstancesOffset, 1, table.create(Target.InstancesOffset))
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
const function Ended(): boolean
|
|
113
|
+
return BufferOffset >= BufferLength
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
const function Remaining(): number
|
|
117
|
+
return BufferLength - BufferOffset
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
const function RemainingInstances(): number
|
|
121
|
+
return #Instances - InstancesOffset
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
const function Allocate(Bytes: number)
|
|
125
|
+
const TargetLength = BufferOffset + Bytes
|
|
126
|
+
|
|
127
|
+
if BufferLength >= TargetLength then
|
|
128
|
+
return
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
while BufferLength < TargetLength do
|
|
132
|
+
BufferLength *= 2
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
const Grown = buffer.create(BufferLength)
|
|
136
|
+
buffer.copy(Grown, 0, ActiveBuffer, 0, BufferOffset)
|
|
137
|
+
ActiveBuffer = Grown
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
const function Append(Source: Cursor)
|
|
141
|
+
Allocate(Source.Offset)
|
|
142
|
+
buffer.copy(ActiveBuffer, BufferOffset, Source.Buffer, 0, Source.Offset)
|
|
143
|
+
BufferOffset += Source.Offset
|
|
144
|
+
|
|
145
|
+
for Index = 1, Source.InstancesOffset do
|
|
146
|
+
InstancesOffset += 1
|
|
147
|
+
Instances[InstancesOffset] = Source.Instances[Index]
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
const function CheckFloat(Value: number): number
|
|
152
|
+
if Untrusted and (Value ~= Value or Value == math.huge or Value == -math.huge) then
|
|
153
|
+
error("[swiftpacket] rejected a non-finite number", 0)
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
return Value
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
const function ReadU8(): number
|
|
160
|
+
const Value = buffer.readu8(ActiveBuffer, BufferOffset)
|
|
161
|
+
BufferOffset += 1
|
|
162
|
+
|
|
163
|
+
return Value
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
const function WriteU8(Value: number)
|
|
167
|
+
buffer.writeu8(ActiveBuffer, BufferOffset, Value)
|
|
168
|
+
BufferOffset += 1
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
const function ReadI8(): number
|
|
172
|
+
const Value = buffer.readi8(ActiveBuffer, BufferOffset)
|
|
173
|
+
BufferOffset += 1
|
|
174
|
+
|
|
175
|
+
return Value
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
const function WriteI8(Value: number)
|
|
179
|
+
buffer.writei8(ActiveBuffer, BufferOffset, Value)
|
|
180
|
+
BufferOffset += 1
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
const function ReadU16(): number
|
|
184
|
+
const Value = buffer.readu16(ActiveBuffer, BufferOffset)
|
|
185
|
+
BufferOffset += 2
|
|
186
|
+
|
|
187
|
+
return Value
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
const function WriteU16(Value: number)
|
|
191
|
+
buffer.writeu16(ActiveBuffer, BufferOffset, Value)
|
|
192
|
+
BufferOffset += 2
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
const function ReadI16(): number
|
|
196
|
+
const Value = buffer.readi16(ActiveBuffer, BufferOffset)
|
|
197
|
+
BufferOffset += 2
|
|
198
|
+
|
|
199
|
+
return Value
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
const function WriteI16(Value: number)
|
|
203
|
+
buffer.writei16(ActiveBuffer, BufferOffset, Value)
|
|
204
|
+
BufferOffset += 2
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
const function ReadU24(): number
|
|
208
|
+
const Value = buffer.readbits(ActiveBuffer, BufferOffset * 8, 24)
|
|
209
|
+
BufferOffset += 3
|
|
210
|
+
|
|
211
|
+
return Value
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
const function WriteU24(Value: number)
|
|
215
|
+
buffer.writebits(ActiveBuffer, BufferOffset * 8, 24, Value)
|
|
216
|
+
BufferOffset += 3
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
const function ReadI24(): number
|
|
220
|
+
const Value = buffer.readbits(ActiveBuffer, BufferOffset * 8, 24) - 8388608
|
|
221
|
+
BufferOffset += 3
|
|
222
|
+
|
|
223
|
+
return Value
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
const function WriteI24(Value: number)
|
|
227
|
+
buffer.writebits(ActiveBuffer, BufferOffset * 8, 24, Value + 8388608)
|
|
228
|
+
BufferOffset += 3
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
const function ReadU32(): number
|
|
232
|
+
const Value = buffer.readu32(ActiveBuffer, BufferOffset)
|
|
233
|
+
BufferOffset += 4
|
|
234
|
+
|
|
235
|
+
return Value
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
const function WriteU32(Value: number)
|
|
239
|
+
buffer.writeu32(ActiveBuffer, BufferOffset, Value)
|
|
240
|
+
BufferOffset += 4
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
const function ReadI32(): number
|
|
244
|
+
const Value = buffer.readi32(ActiveBuffer, BufferOffset)
|
|
245
|
+
BufferOffset += 4
|
|
246
|
+
|
|
247
|
+
return Value
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
const function WriteI32(Value: number)
|
|
251
|
+
buffer.writei32(ActiveBuffer, BufferOffset, Value)
|
|
252
|
+
BufferOffset += 4
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
const function ReadF32(): number
|
|
256
|
+
const Value = buffer.readf32(ActiveBuffer, BufferOffset)
|
|
257
|
+
BufferOffset += 4
|
|
258
|
+
|
|
259
|
+
return CheckFloat(Value)
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
const function WriteF32(Value: number)
|
|
263
|
+
buffer.writef32(ActiveBuffer, BufferOffset, Value)
|
|
264
|
+
BufferOffset += 4
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
const function ReadF64(): number
|
|
268
|
+
const Value = buffer.readf64(ActiveBuffer, BufferOffset)
|
|
269
|
+
BufferOffset += 8
|
|
270
|
+
|
|
271
|
+
return CheckFloat(Value)
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
const function WriteF64(Value: number)
|
|
275
|
+
buffer.writef64(ActiveBuffer, BufferOffset, Value)
|
|
276
|
+
BufferOffset += 8
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
const function ReadBits(BitOffset: number, Count: number): number
|
|
280
|
+
return buffer.readbits(ActiveBuffer, BufferOffset * 8 + BitOffset, Count)
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
const function WriteBits(BitOffset: number, Count: number, Value: number)
|
|
284
|
+
buffer.writebits(ActiveBuffer, BufferOffset * 8 + BitOffset, Count, Value)
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
const function Skip(Bytes: number)
|
|
288
|
+
BufferOffset += Bytes
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
const function ReadVarint(): number
|
|
292
|
+
local Value = 0
|
|
293
|
+
local Scale = 1
|
|
294
|
+
|
|
295
|
+
for Index = 1, 4 do
|
|
296
|
+
const Byte = buffer.readu8(ActiveBuffer, BufferOffset)
|
|
297
|
+
BufferOffset += 1
|
|
298
|
+
|
|
299
|
+
if Index == 4 or Byte < 128 then
|
|
300
|
+
return Value + Byte * Scale
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
Value += (Byte - 128) * Scale
|
|
304
|
+
Scale *= 128
|
|
305
|
+
end
|
|
306
|
+
|
|
307
|
+
return Value
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
const function WriteVarint(Value: number)
|
|
311
|
+
if Value < 0 or Value >= 268435456 or Value % 1 ~= 0 then
|
|
312
|
+
WriteFailure(`length {Value} must be a whole number from 0 to 268435455`)
|
|
313
|
+
end
|
|
314
|
+
|
|
315
|
+
local Left = Value
|
|
316
|
+
|
|
317
|
+
while Left >= 128 do
|
|
318
|
+
buffer.writeu8(ActiveBuffer, BufferOffset, Left % 128 + 128)
|
|
319
|
+
BufferOffset += 1
|
|
320
|
+
Left //= 128
|
|
321
|
+
end
|
|
322
|
+
|
|
323
|
+
buffer.writeu8(ActiveBuffer, BufferOffset, Left)
|
|
324
|
+
BufferOffset += 1
|
|
325
|
+
end
|
|
326
|
+
|
|
327
|
+
const function ReadString(Length: number): string
|
|
328
|
+
const Value = buffer.readstring(ActiveBuffer, BufferOffset, Length)
|
|
329
|
+
BufferOffset += Length
|
|
330
|
+
|
|
331
|
+
return Value
|
|
332
|
+
end
|
|
333
|
+
|
|
334
|
+
const function WriteString(Value: string)
|
|
335
|
+
buffer.writestring(ActiveBuffer, BufferOffset, Value)
|
|
336
|
+
BufferOffset += #Value
|
|
337
|
+
end
|
|
338
|
+
|
|
339
|
+
const function ReadBuffer(Length: number): buffer
|
|
340
|
+
const Value = buffer.create(Length)
|
|
341
|
+
buffer.copy(Value, 0, ActiveBuffer, BufferOffset, Length)
|
|
342
|
+
BufferOffset += Length
|
|
343
|
+
|
|
344
|
+
return Value
|
|
345
|
+
end
|
|
346
|
+
|
|
347
|
+
const function WriteBuffer(Value: buffer)
|
|
348
|
+
buffer.copy(ActiveBuffer, BufferOffset, Value)
|
|
349
|
+
BufferOffset += buffer.len(Value)
|
|
350
|
+
end
|
|
351
|
+
|
|
352
|
+
const function ReadInstance(): Instance?
|
|
353
|
+
InstancesOffset += 1
|
|
354
|
+
|
|
355
|
+
const Value = Instances[InstancesOffset]
|
|
356
|
+
|
|
357
|
+
if typeof(Value) == "Instance" then
|
|
358
|
+
return Value
|
|
359
|
+
end
|
|
360
|
+
|
|
361
|
+
return nil
|
|
362
|
+
end
|
|
363
|
+
|
|
364
|
+
const function WriteInstance(Value: Instance?)
|
|
365
|
+
InstancesOffset += 1
|
|
366
|
+
Instances[InstancesOffset] = if Value == nil then false else Value
|
|
367
|
+
end
|
|
368
|
+
|
|
369
|
+
const function WriteId(Id: number)
|
|
370
|
+
if Id < 128 then
|
|
371
|
+
Allocate(1)
|
|
372
|
+
buffer.writeu8(ActiveBuffer, BufferOffset, Id)
|
|
373
|
+
BufferOffset += 1
|
|
374
|
+
else
|
|
375
|
+
Allocate(4)
|
|
376
|
+
WriteVarint(Id)
|
|
377
|
+
end
|
|
378
|
+
end
|
|
379
|
+
|
|
380
|
+
const CursorLibrary = {
|
|
381
|
+
New = NewCursor,
|
|
382
|
+
Import = Import,
|
|
383
|
+
Export = Export,
|
|
384
|
+
Load = Load,
|
|
385
|
+
Reset = Reset,
|
|
386
|
+
Take = Take,
|
|
387
|
+
Ended = Ended,
|
|
388
|
+
Remaining = Remaining,
|
|
389
|
+
RemainingInstances = RemainingInstances,
|
|
390
|
+
Allocate = Allocate,
|
|
391
|
+
Append = Append,
|
|
392
|
+
CheckFloat = CheckFloat,
|
|
393
|
+
ReadU8 = ReadU8,
|
|
394
|
+
WriteU8 = WriteU8,
|
|
395
|
+
ReadI8 = ReadI8,
|
|
396
|
+
WriteI8 = WriteI8,
|
|
397
|
+
ReadU16 = ReadU16,
|
|
398
|
+
WriteU16 = WriteU16,
|
|
399
|
+
ReadI16 = ReadI16,
|
|
400
|
+
WriteI16 = WriteI16,
|
|
401
|
+
ReadU24 = ReadU24,
|
|
402
|
+
WriteU24 = WriteU24,
|
|
403
|
+
ReadI24 = ReadI24,
|
|
404
|
+
WriteI24 = WriteI24,
|
|
405
|
+
ReadU32 = ReadU32,
|
|
406
|
+
WriteU32 = WriteU32,
|
|
407
|
+
ReadI32 = ReadI32,
|
|
408
|
+
WriteI32 = WriteI32,
|
|
409
|
+
ReadF32 = ReadF32,
|
|
410
|
+
WriteF32 = WriteF32,
|
|
411
|
+
ReadF64 = ReadF64,
|
|
412
|
+
WriteF64 = WriteF64,
|
|
413
|
+
ReadBits = ReadBits,
|
|
414
|
+
WriteBits = WriteBits,
|
|
415
|
+
Skip = Skip,
|
|
416
|
+
ReadVarint = ReadVarint,
|
|
417
|
+
WriteVarint = WriteVarint,
|
|
418
|
+
WriteId = WriteId,
|
|
419
|
+
ReadString = ReadString,
|
|
420
|
+
WriteString = WriteString,
|
|
421
|
+
ReadBuffer = ReadBuffer,
|
|
422
|
+
WriteBuffer = WriteBuffer,
|
|
423
|
+
ReadInstance = ReadInstance,
|
|
424
|
+
WriteInstance = WriteInstance,
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
function CursorLibrary.Truncate(): (buffer, { any }?)
|
|
428
|
+
return Take(Export())
|
|
429
|
+
end
|
|
430
|
+
|
|
431
|
+
function CursorLibrary.Position(): (number, number)
|
|
432
|
+
return BufferOffset, InstancesOffset
|
|
433
|
+
end
|
|
434
|
+
|
|
435
|
+
export type Schema = {
|
|
436
|
+
Read: () -> any,
|
|
437
|
+
Write: (Value: any) -> (),
|
|
438
|
+
MinimumSize: number,
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
export type Arguments = { n: number, [number]: any }
|
|
442
|
+
|
|
443
|
+
const Schema = {}
|
|
444
|
+
|
|
445
|
+
const Registered: { [any]: boolean } = setmetatable({}, { __mode = "k" })
|
|
446
|
+
|
|
447
|
+
function Schema.Define(Read: () -> any, Write: (Value: any) -> (), MinimumSize: number): Schema
|
|
448
|
+
const Definition: Schema = {
|
|
449
|
+
Read = Read,
|
|
450
|
+
Write = Write,
|
|
451
|
+
MinimumSize = MinimumSize,
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
Registered[Definition] = true
|
|
455
|
+
|
|
456
|
+
return Definition
|
|
457
|
+
end
|
|
458
|
+
|
|
459
|
+
function Schema.Is(Value: any): boolean
|
|
460
|
+
return Registered[Value] == true
|
|
461
|
+
end
|
|
462
|
+
|
|
463
|
+
const Define = Schema.Define
|
|
464
|
+
|
|
465
|
+
const function CheckCount(Count: number, MinimumSize: number, MaximumCount: number?)
|
|
466
|
+
if MaximumCount and Count > MaximumCount then
|
|
467
|
+
error(`[swiftpacket] count {Count} is over the maximum of {MaximumCount}`, 0)
|
|
468
|
+
end
|
|
469
|
+
|
|
470
|
+
if MinimumSize > 0 then
|
|
471
|
+
if Count * MinimumSize > Remaining() then
|
|
472
|
+
error(`[swiftpacket] count {Count} is larger than the data left in the batch`, 0)
|
|
473
|
+
end
|
|
474
|
+
elseif Count > Remaining() + RemainingInstances() then
|
|
475
|
+
error(`[swiftpacket] count {Count} is larger than the data left in the batch`, 0)
|
|
476
|
+
end
|
|
477
|
+
end
|
|
478
|
+
|
|
479
|
+
const function CheckLength(Length: number, MaximumLength: number?)
|
|
480
|
+
if MaximumLength and Length > MaximumLength then
|
|
481
|
+
error(`[swiftpacket] length {Length} is over the maximum of {MaximumLength}`, 0)
|
|
482
|
+
end
|
|
483
|
+
|
|
484
|
+
if Length > Remaining() then
|
|
485
|
+
error(`[swiftpacket] length {Length} is larger than the data left in the batch`, 0)
|
|
486
|
+
end
|
|
487
|
+
end
|
|
488
|
+
|
|
489
|
+
const function CountEntries(Value: { [any]: any }): number
|
|
490
|
+
local Count = 0
|
|
491
|
+
|
|
492
|
+
for Key in Value do
|
|
493
|
+
Count += 1
|
|
494
|
+
end
|
|
495
|
+
|
|
496
|
+
return Count
|
|
497
|
+
end
|
|
498
|
+
|
|
499
|
+
const function FloatCodec(ExponentBits: number, MantissaBits: number)
|
|
500
|
+
const Bias = 2 ^ (ExponentBits - 1) - 1
|
|
501
|
+
const MaximumExponent = 2 ^ ExponentBits - 1
|
|
502
|
+
const MantissaScale = 2 ^ MantissaBits
|
|
503
|
+
const SignScale = 2 ^ (ExponentBits + MantissaBits)
|
|
504
|
+
const SubnormalScale = 2 ^ (1 - Bias - MantissaBits)
|
|
505
|
+
|
|
506
|
+
const function Encode(Value: number): number
|
|
507
|
+
if Value ~= Value then
|
|
508
|
+
return MaximumExponent * MantissaScale + 1
|
|
509
|
+
end
|
|
510
|
+
|
|
511
|
+
local Sign = 0
|
|
512
|
+
local Magnitude = Value
|
|
513
|
+
|
|
514
|
+
if Magnitude < 0 or (Magnitude == 0 and 1 / Magnitude < 0) then
|
|
515
|
+
Sign = SignScale
|
|
516
|
+
Magnitude = -Magnitude
|
|
517
|
+
end
|
|
518
|
+
|
|
519
|
+
if Magnitude == 0 then
|
|
520
|
+
return Sign
|
|
521
|
+
end
|
|
522
|
+
|
|
523
|
+
if Magnitude == math.huge then
|
|
524
|
+
return Sign + MaximumExponent * MantissaScale
|
|
525
|
+
end
|
|
526
|
+
|
|
527
|
+
const Mantissa, Exponent = math.frexp(Magnitude)
|
|
528
|
+
local Biased = Exponent - 1 + Bias
|
|
529
|
+
local Fraction: number
|
|
530
|
+
|
|
531
|
+
if Biased <= 0 then
|
|
532
|
+
Fraction = math.round(Magnitude / SubnormalScale)
|
|
533
|
+
Biased = 0
|
|
534
|
+
|
|
535
|
+
if Fraction >= MantissaScale then
|
|
536
|
+
Fraction = 0
|
|
537
|
+
Biased = 1
|
|
538
|
+
end
|
|
539
|
+
else
|
|
540
|
+
Fraction = math.round((Mantissa * 2 - 1) * MantissaScale)
|
|
541
|
+
|
|
542
|
+
if Fraction >= MantissaScale then
|
|
543
|
+
Fraction = 0
|
|
544
|
+
Biased += 1
|
|
545
|
+
end
|
|
546
|
+
end
|
|
547
|
+
|
|
548
|
+
if Biased >= MaximumExponent then
|
|
549
|
+
return Sign + MaximumExponent * MantissaScale
|
|
550
|
+
end
|
|
551
|
+
|
|
552
|
+
return Sign + Biased * MantissaScale + Fraction
|
|
553
|
+
end
|
|
554
|
+
|
|
555
|
+
const function Decode(Bits: number): number
|
|
556
|
+
const Fraction = Bits % MantissaScale
|
|
557
|
+
const Biased = (Bits // MantissaScale) % (MaximumExponent + 1)
|
|
558
|
+
const Sign = if Bits >= SignScale then -1 else 1
|
|
559
|
+
|
|
560
|
+
if Biased == MaximumExponent then
|
|
561
|
+
return CheckFloat(if Fraction == 0 then Sign * math.huge else 0 / 0)
|
|
562
|
+
end
|
|
563
|
+
|
|
564
|
+
if Biased == 0 then
|
|
565
|
+
return Sign * Fraction * SubnormalScale
|
|
566
|
+
end
|
|
567
|
+
|
|
568
|
+
return Sign * (1 + Fraction / MantissaScale) * 2 ^ (Biased - Bias)
|
|
569
|
+
end
|
|
570
|
+
|
|
571
|
+
return Encode, Decode
|
|
572
|
+
end
|
|
573
|
+
|
|
574
|
+
const EncodeF16, DecodeF16 = FloatCodec(5, 10)
|
|
575
|
+
const EncodeF24, DecodeF24 = FloatCodec(6, 17)
|
|
576
|
+
|
|
577
|
+
const function ReadF16(): number
|
|
578
|
+
return DecodeF16(ReadU16())
|
|
579
|
+
end
|
|
580
|
+
|
|
581
|
+
const function WriteF16(Value: number)
|
|
582
|
+
WriteU16(EncodeF16(Value))
|
|
583
|
+
end
|
|
584
|
+
|
|
585
|
+
const function ReadF24(): number
|
|
586
|
+
return DecodeF24(ReadU24())
|
|
587
|
+
end
|
|
588
|
+
|
|
589
|
+
const function WriteF24(Value: number)
|
|
590
|
+
WriteU24(EncodeF24(Value))
|
|
591
|
+
end
|
|
592
|
+
|
|
593
|
+
const RotationScale = 65535 / math.sqrt(2)
|
|
594
|
+
const RotationOffset = 32767.5
|
|
595
|
+
|
|
596
|
+
const function WriteRotation(Value: CFrame)
|
|
597
|
+
const Axis, Angle = Value:ToAxisAngle()
|
|
598
|
+
const Sine = math.sin(Angle / 2)
|
|
599
|
+
const Components = { Axis.X * Sine, Axis.Y * Sine, Axis.Z * Sine, math.cos(Angle / 2) }
|
|
600
|
+
|
|
601
|
+
local Largest = 1
|
|
602
|
+
|
|
603
|
+
for Index = 2, 4 do
|
|
604
|
+
if math.abs(Components[Index]) > math.abs(Components[Largest]) then
|
|
605
|
+
Largest = Index
|
|
606
|
+
end
|
|
607
|
+
end
|
|
608
|
+
|
|
609
|
+
const Flip = if Components[Largest] < 0 then -1 else 1
|
|
610
|
+
|
|
611
|
+
WriteU8(Largest - 1)
|
|
612
|
+
|
|
613
|
+
for Index = 1, 4 do
|
|
614
|
+
if Index ~= Largest then
|
|
615
|
+
WriteU16(math.clamp(math.round(Components[Index] * Flip * RotationScale + RotationOffset), 0, 65535))
|
|
616
|
+
end
|
|
617
|
+
end
|
|
618
|
+
end
|
|
619
|
+
|
|
620
|
+
const function ReadRotation(): (number, number, number, number)
|
|
621
|
+
const Largest = ReadU8() + 1
|
|
622
|
+
|
|
623
|
+
if Largest > 4 then
|
|
624
|
+
error("[swiftpacket] rejected an invalid rotation", 0)
|
|
625
|
+
end
|
|
626
|
+
|
|
627
|
+
const Components = { 0, 0, 0, 0 }
|
|
628
|
+
local Sum = 0
|
|
629
|
+
|
|
630
|
+
for Index = 1, 4 do
|
|
631
|
+
if Index ~= Largest then
|
|
632
|
+
const Component = (ReadU16() - RotationOffset) / RotationScale
|
|
633
|
+
Components[Index] = Component
|
|
634
|
+
Sum += Component * Component
|
|
635
|
+
end
|
|
636
|
+
end
|
|
637
|
+
|
|
638
|
+
Components[Largest] = math.sqrt(math.max(0, 1 - Sum))
|
|
639
|
+
|
|
640
|
+
return Components[1], Components[2], Components[3], Components[4]
|
|
641
|
+
end
|
|
642
|
+
|
|
643
|
+
const function WriteNumberSequence(Value: NumberSequence)
|
|
644
|
+
const Keypoints = Value.Keypoints
|
|
645
|
+
|
|
646
|
+
Allocate(4 + #Keypoints * 12)
|
|
647
|
+
WriteVarint(#Keypoints)
|
|
648
|
+
|
|
649
|
+
for Index = 1, #Keypoints do
|
|
650
|
+
const Keypoint = Keypoints[Index]
|
|
651
|
+
|
|
652
|
+
WriteF32(Keypoint.Time)
|
|
653
|
+
WriteF32(Keypoint.Value)
|
|
654
|
+
WriteF32(Keypoint.Envelope)
|
|
655
|
+
end
|
|
656
|
+
end
|
|
657
|
+
|
|
658
|
+
const function ReadNumberSequence(): NumberSequence
|
|
659
|
+
const Count = ReadVarint()
|
|
660
|
+
CheckCount(Count, 12, 20)
|
|
661
|
+
|
|
662
|
+
const Keypoints: { NumberSequenceKeypoint } = {}
|
|
663
|
+
|
|
664
|
+
for Index = 1, Count do
|
|
665
|
+
Keypoints[Index] = NumberSequenceKeypoint.new(ReadF32(), ReadF32(), ReadF32())
|
|
666
|
+
end
|
|
667
|
+
|
|
668
|
+
return NumberSequence.new(Keypoints)
|
|
669
|
+
end
|
|
670
|
+
|
|
671
|
+
const function WriteColorSequence(Value: ColorSequence)
|
|
672
|
+
const Keypoints = Value.Keypoints
|
|
673
|
+
|
|
674
|
+
Allocate(4 + #Keypoints * 7)
|
|
675
|
+
WriteVarint(#Keypoints)
|
|
676
|
+
|
|
677
|
+
for Index = 1, #Keypoints do
|
|
678
|
+
const Keypoint = Keypoints[Index]
|
|
679
|
+
|
|
680
|
+
WriteF32(Keypoint.Time)
|
|
681
|
+
WriteU8(math.round(Keypoint.Value.R * 255))
|
|
682
|
+
WriteU8(math.round(Keypoint.Value.G * 255))
|
|
683
|
+
WriteU8(math.round(Keypoint.Value.B * 255))
|
|
684
|
+
end
|
|
685
|
+
end
|
|
686
|
+
|
|
687
|
+
const function ReadColorSequence(): ColorSequence
|
|
688
|
+
const Count = ReadVarint()
|
|
689
|
+
CheckCount(Count, 7, 20)
|
|
690
|
+
|
|
691
|
+
const Keypoints: { ColorSequenceKeypoint } = {}
|
|
692
|
+
|
|
693
|
+
for Index = 1, Count do
|
|
694
|
+
Keypoints[Index] = ColorSequenceKeypoint.new(ReadF32(), Color3.fromRGB(ReadU8(), ReadU8(), ReadU8()))
|
|
695
|
+
end
|
|
696
|
+
|
|
697
|
+
return ColorSequence.new(Keypoints)
|
|
698
|
+
end
|
|
699
|
+
|
|
700
|
+
Schema.Nil = Define(function()
|
|
701
|
+
return nil
|
|
702
|
+
end, function() end, 0)
|
|
703
|
+
|
|
704
|
+
Schema.Boolean = Define(function()
|
|
705
|
+
return ReadU8() ~= 0
|
|
706
|
+
end, function(Value: boolean)
|
|
707
|
+
Allocate(1)
|
|
708
|
+
WriteU8(if Value then 1 else 0)
|
|
709
|
+
end, 1)
|
|
710
|
+
|
|
711
|
+
Schema.U8 = Define(ReadU8, function(Value: number)
|
|
712
|
+
Allocate(1)
|
|
713
|
+
WriteU8(Value)
|
|
714
|
+
end, 1)
|
|
715
|
+
|
|
716
|
+
Schema.U16 = Define(ReadU16, function(Value: number)
|
|
717
|
+
Allocate(2)
|
|
718
|
+
WriteU16(Value)
|
|
719
|
+
end, 2)
|
|
720
|
+
|
|
721
|
+
Schema.U24 = Define(ReadU24, function(Value: number)
|
|
722
|
+
Allocate(3)
|
|
723
|
+
WriteU24(Value)
|
|
724
|
+
end, 3)
|
|
725
|
+
|
|
726
|
+
Schema.U32 = Define(ReadU32, function(Value: number)
|
|
727
|
+
Allocate(4)
|
|
728
|
+
WriteU32(Value)
|
|
729
|
+
end, 4)
|
|
730
|
+
|
|
731
|
+
Schema.I8 = Define(ReadI8, function(Value: number)
|
|
732
|
+
Allocate(1)
|
|
733
|
+
WriteI8(Value)
|
|
734
|
+
end, 1)
|
|
735
|
+
|
|
736
|
+
Schema.I16 = Define(ReadI16, function(Value: number)
|
|
737
|
+
Allocate(2)
|
|
738
|
+
WriteI16(Value)
|
|
739
|
+
end, 2)
|
|
740
|
+
|
|
741
|
+
Schema.I24 = Define(ReadI24, function(Value: number)
|
|
742
|
+
Allocate(3)
|
|
743
|
+
WriteI24(Value)
|
|
744
|
+
end, 3)
|
|
745
|
+
|
|
746
|
+
Schema.I32 = Define(ReadI32, function(Value: number)
|
|
747
|
+
Allocate(4)
|
|
748
|
+
WriteI32(Value)
|
|
749
|
+
end, 4)
|
|
750
|
+
|
|
751
|
+
Schema.F16 = Define(ReadF16, function(Value: number)
|
|
752
|
+
Allocate(2)
|
|
753
|
+
WriteF16(Value)
|
|
754
|
+
end, 2)
|
|
755
|
+
|
|
756
|
+
Schema.F24 = Define(ReadF24, function(Value: number)
|
|
757
|
+
Allocate(3)
|
|
758
|
+
WriteF24(Value)
|
|
759
|
+
end, 3)
|
|
760
|
+
|
|
761
|
+
Schema.F32 = Define(ReadF32, function(Value: number)
|
|
762
|
+
Allocate(4)
|
|
763
|
+
WriteF32(Value)
|
|
764
|
+
end, 4)
|
|
765
|
+
|
|
766
|
+
Schema.F64 = Define(ReadF64, function(Value: number)
|
|
767
|
+
Allocate(8)
|
|
768
|
+
WriteF64(Value)
|
|
769
|
+
end, 8)
|
|
770
|
+
|
|
771
|
+
Schema.String = Define(function()
|
|
772
|
+
const Length = ReadVarint()
|
|
773
|
+
CheckLength(Length)
|
|
774
|
+
|
|
775
|
+
return ReadString(Length)
|
|
776
|
+
end, function(Value: string)
|
|
777
|
+
Allocate(4 + #Value)
|
|
778
|
+
WriteVarint(#Value)
|
|
779
|
+
WriteString(Value)
|
|
780
|
+
end, 1)
|
|
781
|
+
|
|
782
|
+
Schema.Buffer = Define(function()
|
|
783
|
+
const Length = ReadVarint()
|
|
784
|
+
CheckLength(Length)
|
|
785
|
+
|
|
786
|
+
return ReadBuffer(Length)
|
|
787
|
+
end, function(Value: buffer)
|
|
788
|
+
Allocate(4 + buffer.len(Value))
|
|
789
|
+
WriteVarint(buffer.len(Value))
|
|
790
|
+
WriteBuffer(Value)
|
|
791
|
+
end, 1)
|
|
792
|
+
|
|
793
|
+
Schema.Instance = Define(ReadInstance, WriteInstance, 0)
|
|
794
|
+
|
|
795
|
+
Schema.Vector2 = Define(function()
|
|
796
|
+
return Vector2.new(ReadF32(), ReadF32())
|
|
797
|
+
end, function(Value: Vector2)
|
|
798
|
+
Allocate(8)
|
|
799
|
+
WriteF32(Value.X)
|
|
800
|
+
WriteF32(Value.Y)
|
|
801
|
+
end, 8)
|
|
802
|
+
|
|
803
|
+
Schema.Vector2F16 = Define(function()
|
|
804
|
+
return Vector2.new(ReadF16(), ReadF16())
|
|
805
|
+
end, function(Value: Vector2)
|
|
806
|
+
Allocate(4)
|
|
807
|
+
WriteF16(Value.X)
|
|
808
|
+
WriteF16(Value.Y)
|
|
809
|
+
end, 4)
|
|
810
|
+
|
|
811
|
+
Schema.Vector2I16 = Define(function()
|
|
812
|
+
return Vector2.new(ReadI16(), ReadI16())
|
|
813
|
+
end, function(Value: Vector2)
|
|
814
|
+
Allocate(4)
|
|
815
|
+
WriteI16(math.round(Value.X))
|
|
816
|
+
WriteI16(math.round(Value.Y))
|
|
817
|
+
end, 4)
|
|
818
|
+
|
|
819
|
+
Schema.Vector3 = Define(function()
|
|
820
|
+
return Vector3.new(ReadF32(), ReadF32(), ReadF32())
|
|
821
|
+
end, function(Value: Vector3)
|
|
822
|
+
Allocate(12)
|
|
823
|
+
WriteF32(Value.X)
|
|
824
|
+
WriteF32(Value.Y)
|
|
825
|
+
WriteF32(Value.Z)
|
|
826
|
+
end, 12)
|
|
827
|
+
|
|
828
|
+
Schema.Vector3F24 = Define(function()
|
|
829
|
+
return Vector3.new(ReadF24(), ReadF24(), ReadF24())
|
|
830
|
+
end, function(Value: Vector3)
|
|
831
|
+
Allocate(9)
|
|
832
|
+
WriteF24(Value.X)
|
|
833
|
+
WriteF24(Value.Y)
|
|
834
|
+
WriteF24(Value.Z)
|
|
835
|
+
end, 9)
|
|
836
|
+
|
|
837
|
+
Schema.Vector3F16 = Define(function()
|
|
838
|
+
return Vector3.new(ReadF16(), ReadF16(), ReadF16())
|
|
839
|
+
end, function(Value: Vector3)
|
|
840
|
+
Allocate(6)
|
|
841
|
+
WriteF16(Value.X)
|
|
842
|
+
WriteF16(Value.Y)
|
|
843
|
+
WriteF16(Value.Z)
|
|
844
|
+
end, 6)
|
|
845
|
+
|
|
846
|
+
Schema.Vector3I16 = Define(function()
|
|
847
|
+
return Vector3.new(ReadI16(), ReadI16(), ReadI16())
|
|
848
|
+
end, function(Value: Vector3)
|
|
849
|
+
Allocate(6)
|
|
850
|
+
WriteI16(math.round(Value.X))
|
|
851
|
+
WriteI16(math.round(Value.Y))
|
|
852
|
+
WriteI16(math.round(Value.Z))
|
|
853
|
+
end, 6)
|
|
854
|
+
|
|
855
|
+
Schema.CFrame = Define(function()
|
|
856
|
+
const X, Y, Z = ReadF32(), ReadF32(), ReadF32()
|
|
857
|
+
const QuaternionX, QuaternionY, QuaternionZ, QuaternionW = ReadRotation()
|
|
858
|
+
|
|
859
|
+
return CFrame.new(X, Y, Z, QuaternionX, QuaternionY, QuaternionZ, QuaternionW)
|
|
860
|
+
end, function(Value: CFrame)
|
|
861
|
+
Allocate(19)
|
|
862
|
+
WriteF32(Value.X)
|
|
863
|
+
WriteF32(Value.Y)
|
|
864
|
+
WriteF32(Value.Z)
|
|
865
|
+
WriteRotation(Value)
|
|
866
|
+
end, 19)
|
|
867
|
+
|
|
868
|
+
Schema.CFrameF24 = Define(function()
|
|
869
|
+
const X, Y, Z = ReadF24(), ReadF24(), ReadF24()
|
|
870
|
+
const QuaternionX, QuaternionY, QuaternionZ, QuaternionW = ReadRotation()
|
|
871
|
+
|
|
872
|
+
return CFrame.new(X, Y, Z, QuaternionX, QuaternionY, QuaternionZ, QuaternionW)
|
|
873
|
+
end, function(Value: CFrame)
|
|
874
|
+
Allocate(16)
|
|
875
|
+
WriteF24(Value.X)
|
|
876
|
+
WriteF24(Value.Y)
|
|
877
|
+
WriteF24(Value.Z)
|
|
878
|
+
WriteRotation(Value)
|
|
879
|
+
end, 16)
|
|
880
|
+
|
|
881
|
+
Schema.Color3 = Define(function()
|
|
882
|
+
return Color3.fromRGB(ReadU8(), ReadU8(), ReadU8())
|
|
883
|
+
end, function(Value: Color3)
|
|
884
|
+
Allocate(3)
|
|
885
|
+
WriteU8(math.round(math.clamp(Value.R, 0, 1) * 255))
|
|
886
|
+
WriteU8(math.round(math.clamp(Value.G, 0, 1) * 255))
|
|
887
|
+
WriteU8(math.round(math.clamp(Value.B, 0, 1) * 255))
|
|
888
|
+
end, 3)
|
|
889
|
+
|
|
890
|
+
Schema.BrickColor = Define(function()
|
|
891
|
+
return BrickColor.new(ReadU16())
|
|
892
|
+
end, function(Value: BrickColor)
|
|
893
|
+
Allocate(2)
|
|
894
|
+
WriteU16(Value.Number)
|
|
895
|
+
end, 2)
|
|
896
|
+
|
|
897
|
+
Schema.UDim = Define(function()
|
|
898
|
+
return UDim.new(ReadF32(), ReadI32())
|
|
899
|
+
end, function(Value: UDim)
|
|
900
|
+
Allocate(8)
|
|
901
|
+
WriteF32(Value.Scale)
|
|
902
|
+
WriteI32(Value.Offset)
|
|
903
|
+
end, 8)
|
|
904
|
+
|
|
905
|
+
Schema.UDim2 = Define(function()
|
|
906
|
+
return UDim2.new(ReadF32(), ReadI32(), ReadF32(), ReadI32())
|
|
907
|
+
end, function(Value: UDim2)
|
|
908
|
+
Allocate(16)
|
|
909
|
+
WriteF32(Value.X.Scale)
|
|
910
|
+
WriteI32(Value.X.Offset)
|
|
911
|
+
WriteF32(Value.Y.Scale)
|
|
912
|
+
WriteI32(Value.Y.Offset)
|
|
913
|
+
end, 16)
|
|
914
|
+
|
|
915
|
+
Schema.Rect = Define(function()
|
|
916
|
+
return Rect.new(ReadF32(), ReadF32(), ReadF32(), ReadF32())
|
|
917
|
+
end, function(Value: Rect)
|
|
918
|
+
Allocate(16)
|
|
919
|
+
WriteF32(Value.Min.X)
|
|
920
|
+
WriteF32(Value.Min.Y)
|
|
921
|
+
WriteF32(Value.Max.X)
|
|
922
|
+
WriteF32(Value.Max.Y)
|
|
923
|
+
end, 16)
|
|
924
|
+
|
|
925
|
+
Schema.NumberRange = Define(function()
|
|
926
|
+
return NumberRange.new(ReadF32(), ReadF32())
|
|
927
|
+
end, function(Value: NumberRange)
|
|
928
|
+
Allocate(8)
|
|
929
|
+
WriteF32(Value.Min)
|
|
930
|
+
WriteF32(Value.Max)
|
|
931
|
+
end, 8)
|
|
932
|
+
|
|
933
|
+
Schema.NumberSequence = Define(ReadNumberSequence, WriteNumberSequence, 1)
|
|
934
|
+
|
|
935
|
+
Schema.ColorSequence = Define(ReadColorSequence, WriteColorSequence, 1)
|
|
936
|
+
|
|
937
|
+
Schema.DateTime = Define(function()
|
|
938
|
+
return DateTime.fromUnixTimestampMillis(ReadF64())
|
|
939
|
+
end, function(Value: DateTime)
|
|
940
|
+
Allocate(8)
|
|
941
|
+
WriteF64(Value.UnixTimestampMillis)
|
|
942
|
+
end, 8)
|
|
943
|
+
|
|
944
|
+
const AnyReads: { [number]: (Depth: number) -> any } = {}
|
|
945
|
+
const AnyWrites: { [string]: (Value: any, Depth: number) -> () } = {}
|
|
946
|
+
local EnumsByName: { [string]: Enum }? = nil
|
|
947
|
+
|
|
948
|
+
const function ReadAnyAt(Depth: number): any
|
|
949
|
+
const Tag = ReadU8()
|
|
950
|
+
const Reader = AnyReads[Tag]
|
|
951
|
+
|
|
952
|
+
if Reader == nil then
|
|
953
|
+
error(`[swiftpacket] rejected an unknown value tag {Tag}`, 0)
|
|
954
|
+
end
|
|
955
|
+
|
|
956
|
+
return Reader(Depth)
|
|
957
|
+
end
|
|
958
|
+
|
|
959
|
+
const function WriteAnyAt(Value: any, Depth: number)
|
|
960
|
+
const Kind = typeof(Value)
|
|
961
|
+
const Writer = AnyWrites[Kind]
|
|
962
|
+
|
|
963
|
+
if Writer == nil then
|
|
964
|
+
WriteFailure(`cannot send a value of type {Kind}`)
|
|
965
|
+
end
|
|
966
|
+
|
|
967
|
+
Writer(Value, Depth)
|
|
968
|
+
end
|
|
969
|
+
|
|
970
|
+
const function WriteTag(Tag: number, Bytes: number)
|
|
971
|
+
Allocate(1 + Bytes)
|
|
972
|
+
WriteU8(Tag)
|
|
973
|
+
end
|
|
974
|
+
|
|
975
|
+
const function BuildEnums(): { [string]: Enum }
|
|
976
|
+
const Built: { [string]: Enum } = {}
|
|
977
|
+
const Enums = Enum:GetEnums()
|
|
978
|
+
|
|
979
|
+
for Index = 1, #Enums do
|
|
980
|
+
Built[tostring(Enums[Index])] = Enums[Index]
|
|
981
|
+
end
|
|
982
|
+
|
|
983
|
+
return Built
|
|
984
|
+
end
|
|
985
|
+
|
|
986
|
+
const function FindEnum(Name: string): Enum
|
|
987
|
+
const Lookup = EnumsByName or BuildEnums()
|
|
988
|
+
EnumsByName = Lookup
|
|
989
|
+
|
|
990
|
+
const EnumType = Lookup[Name]
|
|
991
|
+
|
|
992
|
+
if EnumType == nil then
|
|
993
|
+
error(`[swiftpacket] rejected an unknown enum type {Name}`, 0)
|
|
994
|
+
end
|
|
995
|
+
|
|
996
|
+
return EnumType
|
|
997
|
+
end
|
|
998
|
+
|
|
999
|
+
AnyReads[0] = function()
|
|
1000
|
+
return nil
|
|
1001
|
+
end
|
|
1002
|
+
|
|
1003
|
+
AnyWrites["nil"] = function()
|
|
1004
|
+
WriteTag(0, 0)
|
|
1005
|
+
end
|
|
1006
|
+
|
|
1007
|
+
AnyReads[1] = function()
|
|
1008
|
+
return false
|
|
1009
|
+
end
|
|
1010
|
+
|
|
1011
|
+
AnyReads[2] = function()
|
|
1012
|
+
return true
|
|
1013
|
+
end
|
|
1014
|
+
|
|
1015
|
+
AnyWrites.boolean = function(Value: boolean)
|
|
1016
|
+
WriteTag(if Value then 2 else 1, 0)
|
|
1017
|
+
end
|
|
1018
|
+
|
|
1019
|
+
AnyReads[3] = ReadU8
|
|
1020
|
+
AnyReads[4] = ReadU16
|
|
1021
|
+
AnyReads[5] = ReadU32
|
|
1022
|
+
|
|
1023
|
+
AnyReads[6] = function()
|
|
1024
|
+
return -ReadU8()
|
|
1025
|
+
end
|
|
1026
|
+
|
|
1027
|
+
AnyReads[7] = function()
|
|
1028
|
+
return -ReadU16()
|
|
1029
|
+
end
|
|
1030
|
+
|
|
1031
|
+
AnyReads[8] = function()
|
|
1032
|
+
return -ReadU32()
|
|
1033
|
+
end
|
|
1034
|
+
|
|
1035
|
+
AnyReads[9] = ReadF64
|
|
1036
|
+
|
|
1037
|
+
AnyWrites.number = function(Value: number)
|
|
1038
|
+
if Value % 1 ~= 0 or math.abs(Value) >= 4294967296 then
|
|
1039
|
+
WriteTag(9, 8)
|
|
1040
|
+
WriteF64(Value)
|
|
1041
|
+
elseif Value >= 0 then
|
|
1042
|
+
if Value < 256 then
|
|
1043
|
+
WriteTag(3, 1)
|
|
1044
|
+
WriteU8(Value)
|
|
1045
|
+
elseif Value < 65536 then
|
|
1046
|
+
WriteTag(4, 2)
|
|
1047
|
+
WriteU16(Value)
|
|
1048
|
+
else
|
|
1049
|
+
WriteTag(5, 4)
|
|
1050
|
+
WriteU32(Value)
|
|
1051
|
+
end
|
|
1052
|
+
else
|
|
1053
|
+
const Magnitude = -Value
|
|
1054
|
+
|
|
1055
|
+
if Magnitude < 256 then
|
|
1056
|
+
WriteTag(6, 1)
|
|
1057
|
+
WriteU8(Magnitude)
|
|
1058
|
+
elseif Magnitude < 65536 then
|
|
1059
|
+
WriteTag(7, 2)
|
|
1060
|
+
WriteU16(Magnitude)
|
|
1061
|
+
else
|
|
1062
|
+
WriteTag(8, 4)
|
|
1063
|
+
WriteU32(Magnitude)
|
|
1064
|
+
end
|
|
1065
|
+
end
|
|
1066
|
+
end
|
|
1067
|
+
|
|
1068
|
+
const function AnyDatatype(Tag: number, Kind: string, Datatype: Schema)
|
|
1069
|
+
const Read, Write = Datatype.Read, Datatype.Write
|
|
1070
|
+
|
|
1071
|
+
AnyReads[Tag] = function()
|
|
1072
|
+
return Read()
|
|
1073
|
+
end
|
|
1074
|
+
|
|
1075
|
+
AnyWrites[Kind] = function(Value: any)
|
|
1076
|
+
WriteTag(Tag, 0)
|
|
1077
|
+
Write(Value)
|
|
1078
|
+
end
|
|
1079
|
+
end
|
|
1080
|
+
|
|
1081
|
+
AnyDatatype(10, "string", Schema.String)
|
|
1082
|
+
AnyDatatype(11, "buffer", Schema.Buffer)
|
|
1083
|
+
AnyDatatype(12, "Instance", Schema.Instance)
|
|
1084
|
+
AnyDatatype(13, "Vector2", Schema.Vector2)
|
|
1085
|
+
AnyDatatype(14, "Vector3", Schema.Vector3)
|
|
1086
|
+
AnyDatatype(15, "CFrame", Schema.CFrame)
|
|
1087
|
+
AnyDatatype(16, "Color3", Schema.Color3)
|
|
1088
|
+
AnyDatatype(17, "BrickColor", Schema.BrickColor)
|
|
1089
|
+
AnyDatatype(18, "UDim", Schema.UDim)
|
|
1090
|
+
AnyDatatype(19, "UDim2", Schema.UDim2)
|
|
1091
|
+
AnyDatatype(20, "Rect", Schema.Rect)
|
|
1092
|
+
AnyDatatype(21, "NumberRange", Schema.NumberRange)
|
|
1093
|
+
AnyDatatype(22, "NumberSequence", Schema.NumberSequence)
|
|
1094
|
+
AnyDatatype(23, "ColorSequence", Schema.ColorSequence)
|
|
1095
|
+
AnyDatatype(24, "DateTime", Schema.DateTime)
|
|
1096
|
+
|
|
1097
|
+
AnyReads[25] = function()
|
|
1098
|
+
const EnumType = FindEnum(Schema.String.Read())
|
|
1099
|
+
const Item = EnumType:FromValue(ReadU16())
|
|
1100
|
+
|
|
1101
|
+
if Item == nil then
|
|
1102
|
+
error(`[swiftpacket] rejected an unknown {tostring(EnumType)} value`, 0)
|
|
1103
|
+
end
|
|
1104
|
+
|
|
1105
|
+
return Item
|
|
1106
|
+
end
|
|
1107
|
+
|
|
1108
|
+
AnyWrites.EnumItem = function(Value: EnumItem)
|
|
1109
|
+
WriteTag(25, 0)
|
|
1110
|
+
Schema.String.Write(tostring(Value.EnumType))
|
|
1111
|
+
Allocate(2)
|
|
1112
|
+
WriteU16(Value.Value)
|
|
1113
|
+
end
|
|
1114
|
+
|
|
1115
|
+
AnyReads[26] = function(Depth: number)
|
|
1116
|
+
if Depth >= 16 then
|
|
1117
|
+
error("[swiftpacket] table nesting is deeper than 16 levels", 0)
|
|
1118
|
+
end
|
|
1119
|
+
|
|
1120
|
+
const Count = ReadVarint()
|
|
1121
|
+
CheckCount(Count, 2)
|
|
1122
|
+
|
|
1123
|
+
const Value = {}
|
|
1124
|
+
|
|
1125
|
+
for Index = 1, Count do
|
|
1126
|
+
const Key = ReadAnyAt(Depth + 1)
|
|
1127
|
+
const Entry = ReadAnyAt(Depth + 1)
|
|
1128
|
+
|
|
1129
|
+
if Key == nil or Key ~= Key then
|
|
1130
|
+
error(`[swiftpacket] rejected an invalid key in table entry {Index}`, 0)
|
|
1131
|
+
end
|
|
1132
|
+
|
|
1133
|
+
Value[Key] = Entry
|
|
1134
|
+
end
|
|
1135
|
+
|
|
1136
|
+
return Value
|
|
1137
|
+
end
|
|
1138
|
+
|
|
1139
|
+
AnyWrites.table = function(Value: { [any]: any }, Depth: number)
|
|
1140
|
+
if Depth >= 16 then
|
|
1141
|
+
WriteFailure("table nesting is deeper than 16 levels")
|
|
1142
|
+
end
|
|
1143
|
+
|
|
1144
|
+
WriteTag(26, 4)
|
|
1145
|
+
WriteVarint(CountEntries(Value))
|
|
1146
|
+
|
|
1147
|
+
for Key, Entry in Value do
|
|
1148
|
+
WriteAnyAt(Key, Depth + 1)
|
|
1149
|
+
WriteAnyAt(Entry, Depth + 1)
|
|
1150
|
+
end
|
|
1151
|
+
end
|
|
1152
|
+
|
|
1153
|
+
Schema.Any = Define(function()
|
|
1154
|
+
return ReadAnyAt(0)
|
|
1155
|
+
end, function(Value: any)
|
|
1156
|
+
WriteAnyAt(Value, 0)
|
|
1157
|
+
end, 1)
|
|
1158
|
+
|
|
1159
|
+
function Schema.Charset(Characters: string): Schema
|
|
1160
|
+
if #Characters < 2 or #Characters > 256 then
|
|
1161
|
+
error("[swiftpacket] a charset needs from 2 to 256 characters", 2)
|
|
1162
|
+
end
|
|
1163
|
+
|
|
1164
|
+
const Bits = math.ceil(math.log(#Characters, 2))
|
|
1165
|
+
const Lookup: { [string]: number } = {}
|
|
1166
|
+
const Alphabet: { string } = {}
|
|
1167
|
+
|
|
1168
|
+
for Index = 1, #Characters do
|
|
1169
|
+
const Character = string.sub(Characters, Index, Index)
|
|
1170
|
+
|
|
1171
|
+
if Lookup[Character] then
|
|
1172
|
+
error(`[swiftpacket] charset repeats the character "{Character}"`, 2)
|
|
1173
|
+
end
|
|
1174
|
+
|
|
1175
|
+
Lookup[Character] = Index - 1
|
|
1176
|
+
Alphabet[Index] = Character
|
|
1177
|
+
end
|
|
1178
|
+
|
|
1179
|
+
return Define(function()
|
|
1180
|
+
const Length = ReadVarint()
|
|
1181
|
+
const Bytes = math.ceil(Length * Bits / 8)
|
|
1182
|
+
CheckLength(Bytes)
|
|
1183
|
+
|
|
1184
|
+
const Output: { string } = {}
|
|
1185
|
+
|
|
1186
|
+
for Index = 1, Length do
|
|
1187
|
+
const Character = Alphabet[ReadBits((Index - 1) * Bits, Bits) + 1]
|
|
1188
|
+
|
|
1189
|
+
if Character == nil then
|
|
1190
|
+
error("[swiftpacket] rejected a character outside the charset", 0)
|
|
1191
|
+
end
|
|
1192
|
+
|
|
1193
|
+
Output[Index] = Character
|
|
1194
|
+
end
|
|
1195
|
+
|
|
1196
|
+
Skip(Bytes)
|
|
1197
|
+
|
|
1198
|
+
return table.concat(Output)
|
|
1199
|
+
end, function(Value: string)
|
|
1200
|
+
const Length = #Value
|
|
1201
|
+
const Bytes = math.ceil(Length * Bits / 8)
|
|
1202
|
+
|
|
1203
|
+
Allocate(4 + Bytes)
|
|
1204
|
+
WriteVarint(Length)
|
|
1205
|
+
|
|
1206
|
+
for Index = 1, Length do
|
|
1207
|
+
const Character = string.sub(Value, Index, Index)
|
|
1208
|
+
const Code = Lookup[Character]
|
|
1209
|
+
|
|
1210
|
+
if Code == nil then
|
|
1211
|
+
WriteFailure(`"{Character}" is not in the charset`)
|
|
1212
|
+
end
|
|
1213
|
+
|
|
1214
|
+
WriteBits((Index - 1) * Bits, Bits, Code)
|
|
1215
|
+
end
|
|
1216
|
+
|
|
1217
|
+
Skip(Bytes)
|
|
1218
|
+
end, 1)
|
|
1219
|
+
end
|
|
1220
|
+
|
|
1221
|
+
Schema.Characters = Schema.Charset(" .0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz")
|
|
1222
|
+
|
|
1223
|
+
const function Compile(Parameter: any): Schema
|
|
1224
|
+
if Registered[Parameter] then
|
|
1225
|
+
return Parameter
|
|
1226
|
+
end
|
|
1227
|
+
|
|
1228
|
+
if type(Parameter) ~= "table" then
|
|
1229
|
+
error(`[swiftpacket] {tostring(Parameter)} is not a swiftpacket type`, 0)
|
|
1230
|
+
end
|
|
1231
|
+
|
|
1232
|
+
if #Parameter == 1 and next(Parameter, 1) == nil then
|
|
1233
|
+
return Schema.Array(Parameter[1])
|
|
1234
|
+
end
|
|
1235
|
+
|
|
1236
|
+
return Schema.Struct(Parameter)
|
|
1237
|
+
end
|
|
1238
|
+
|
|
1239
|
+
Schema.Compile = Compile
|
|
1240
|
+
|
|
1241
|
+
function Schema.Array(Element: any, MaximumLength: number?): Schema
|
|
1242
|
+
const Item = Compile(Element)
|
|
1243
|
+
const ReadItem, WriteItem = Item.Read, Item.Write
|
|
1244
|
+
const ItemSize = Item.MinimumSize
|
|
1245
|
+
|
|
1246
|
+
return Define(function()
|
|
1247
|
+
const Length = ReadVarint()
|
|
1248
|
+
CheckCount(Length, ItemSize, MaximumLength)
|
|
1249
|
+
|
|
1250
|
+
const Values = {}
|
|
1251
|
+
|
|
1252
|
+
for Index = 1, Length do
|
|
1253
|
+
Values[Index] = ReadItem()
|
|
1254
|
+
end
|
|
1255
|
+
|
|
1256
|
+
return Values
|
|
1257
|
+
end, function(Values: { any })
|
|
1258
|
+
const Length = #Values
|
|
1259
|
+
|
|
1260
|
+
if MaximumLength and Length > MaximumLength then
|
|
1261
|
+
WriteFailure(`array length {Length} is over the maximum of {MaximumLength}`)
|
|
1262
|
+
end
|
|
1263
|
+
|
|
1264
|
+
Allocate(4)
|
|
1265
|
+
WriteVarint(Length)
|
|
1266
|
+
|
|
1267
|
+
for Index = 1, Length do
|
|
1268
|
+
WriteItem(Values[Index])
|
|
1269
|
+
end
|
|
1270
|
+
end, 1)
|
|
1271
|
+
end
|
|
1272
|
+
|
|
1273
|
+
function Schema.Map(Key: any, Value: any, MaximumCount: number?): Schema
|
|
1274
|
+
const KeySchema, ValueSchema = Compile(Key), Compile(Value)
|
|
1275
|
+
const ReadKey, WriteKey = KeySchema.Read, KeySchema.Write
|
|
1276
|
+
const ReadValue, WriteValue = ValueSchema.Read, ValueSchema.Write
|
|
1277
|
+
const EntrySize = KeySchema.MinimumSize + ValueSchema.MinimumSize
|
|
1278
|
+
|
|
1279
|
+
return Define(function()
|
|
1280
|
+
const Count = ReadVarint()
|
|
1281
|
+
CheckCount(Count, EntrySize, MaximumCount)
|
|
1282
|
+
|
|
1283
|
+
const Values = {}
|
|
1284
|
+
|
|
1285
|
+
for Index = 1, Count do
|
|
1286
|
+
const EntryKey = ReadKey()
|
|
1287
|
+
const EntryValue = ReadValue()
|
|
1288
|
+
|
|
1289
|
+
if EntryKey == nil or EntryKey ~= EntryKey then
|
|
1290
|
+
error(`[swiftpacket] rejected an invalid key in map entry {Index}`, 0)
|
|
1291
|
+
end
|
|
1292
|
+
|
|
1293
|
+
Values[EntryKey] = EntryValue
|
|
1294
|
+
end
|
|
1295
|
+
|
|
1296
|
+
return Values
|
|
1297
|
+
end, function(Values: { [any]: any })
|
|
1298
|
+
const Count = CountEntries(Values)
|
|
1299
|
+
|
|
1300
|
+
if MaximumCount and Count > MaximumCount then
|
|
1301
|
+
WriteFailure(`map count {Count} is over the maximum of {MaximumCount}`)
|
|
1302
|
+
end
|
|
1303
|
+
|
|
1304
|
+
Allocate(4)
|
|
1305
|
+
WriteVarint(Count)
|
|
1306
|
+
|
|
1307
|
+
for EntryKey, EntryValue in Values do
|
|
1308
|
+
WriteKey(EntryKey)
|
|
1309
|
+
WriteValue(EntryValue)
|
|
1310
|
+
end
|
|
1311
|
+
end, 1)
|
|
1312
|
+
end
|
|
1313
|
+
|
|
1314
|
+
function Schema.Struct(Shape: { [any]: any }): Schema
|
|
1315
|
+
const Keys: { string } = {}
|
|
1316
|
+
|
|
1317
|
+
for Key in Shape do
|
|
1318
|
+
if type(Key) ~= "string" then
|
|
1319
|
+
error(`[swiftpacket] struct key {tostring(Key)} must be a string`, 0)
|
|
1320
|
+
end
|
|
1321
|
+
|
|
1322
|
+
table.insert(Keys, Key)
|
|
1323
|
+
end
|
|
1324
|
+
|
|
1325
|
+
table.sort(Keys)
|
|
1326
|
+
|
|
1327
|
+
const Readers: { () -> any } = {}
|
|
1328
|
+
const Writers: { (Value: any) -> () } = {}
|
|
1329
|
+
local MinimumSize = 0
|
|
1330
|
+
|
|
1331
|
+
for Index, Key in Keys do
|
|
1332
|
+
const Field = Compile(Shape[Key])
|
|
1333
|
+
Readers[Index] = Field.Read
|
|
1334
|
+
Writers[Index] = Field.Write
|
|
1335
|
+
MinimumSize += Field.MinimumSize
|
|
1336
|
+
end
|
|
1337
|
+
|
|
1338
|
+
return Define(function()
|
|
1339
|
+
const Values = {}
|
|
1340
|
+
|
|
1341
|
+
for Index, Reader in Readers do
|
|
1342
|
+
Values[Keys[Index]] = Reader()
|
|
1343
|
+
end
|
|
1344
|
+
|
|
1345
|
+
return Values
|
|
1346
|
+
end, function(Values: { [string]: any })
|
|
1347
|
+
for Index, Writer in Writers do
|
|
1348
|
+
Writer(Values[Keys[Index]])
|
|
1349
|
+
end
|
|
1350
|
+
end, MinimumSize)
|
|
1351
|
+
end
|
|
1352
|
+
|
|
1353
|
+
function Schema.Optional(Inner: any): Schema
|
|
1354
|
+
const InnerSchema = Compile(Inner)
|
|
1355
|
+
const ReadInner, WriteInner = InnerSchema.Read, InnerSchema.Write
|
|
1356
|
+
|
|
1357
|
+
return Define(function()
|
|
1358
|
+
if ReadU8() == 0 then
|
|
1359
|
+
return nil
|
|
1360
|
+
end
|
|
1361
|
+
|
|
1362
|
+
return ReadInner()
|
|
1363
|
+
end, function(Value: any)
|
|
1364
|
+
Allocate(1)
|
|
1365
|
+
|
|
1366
|
+
if Value == nil then
|
|
1367
|
+
WriteU8(0)
|
|
1368
|
+
else
|
|
1369
|
+
WriteU8(1)
|
|
1370
|
+
WriteInner(Value)
|
|
1371
|
+
end
|
|
1372
|
+
end, 1)
|
|
1373
|
+
end
|
|
1374
|
+
|
|
1375
|
+
function Schema.Static(Values: { any }): Schema
|
|
1376
|
+
const Count = #Values
|
|
1377
|
+
|
|
1378
|
+
if Count < 1 or Count > 65536 then
|
|
1379
|
+
error("[swiftpacket] a static list needs from 1 to 65536 values", 2)
|
|
1380
|
+
end
|
|
1381
|
+
|
|
1382
|
+
const Indices: { [any]: number } = {}
|
|
1383
|
+
|
|
1384
|
+
for Index, Value in Values do
|
|
1385
|
+
Indices[Value] = Index - 1
|
|
1386
|
+
end
|
|
1387
|
+
|
|
1388
|
+
const Wide = Count > 256
|
|
1389
|
+
|
|
1390
|
+
return Define(function()
|
|
1391
|
+
const Value = Values[(if Wide then ReadU16() else ReadU8()) + 1]
|
|
1392
|
+
|
|
1393
|
+
if Value == nil then
|
|
1394
|
+
error("[swiftpacket] rejected an index outside the static list", 0)
|
|
1395
|
+
end
|
|
1396
|
+
|
|
1397
|
+
return Value
|
|
1398
|
+
end, function(Value: any)
|
|
1399
|
+
const Index = Indices[Value]
|
|
1400
|
+
|
|
1401
|
+
if Index == nil then
|
|
1402
|
+
WriteFailure(`{tostring(Value)} is not in the static list`)
|
|
1403
|
+
end
|
|
1404
|
+
|
|
1405
|
+
if Wide then
|
|
1406
|
+
Allocate(2)
|
|
1407
|
+
WriteU16(Index)
|
|
1408
|
+
else
|
|
1409
|
+
Allocate(1)
|
|
1410
|
+
WriteU8(Index)
|
|
1411
|
+
end
|
|
1412
|
+
end, if Wide then 2 else 1)
|
|
1413
|
+
end
|
|
1414
|
+
|
|
1415
|
+
function Schema.Flags(Names: { string }): Schema
|
|
1416
|
+
const Count = #Names
|
|
1417
|
+
|
|
1418
|
+
if Count < 1 or Count > 64 then
|
|
1419
|
+
error("[swiftpacket] flags need from 1 to 64 names", 2)
|
|
1420
|
+
end
|
|
1421
|
+
|
|
1422
|
+
const Bytes = math.ceil(Count / 8)
|
|
1423
|
+
|
|
1424
|
+
return Define(function()
|
|
1425
|
+
const Values: { [string]: boolean } = {}
|
|
1426
|
+
|
|
1427
|
+
for Index, Name in Names do
|
|
1428
|
+
Values[Name] = ReadBits(Index - 1, 1) == 1
|
|
1429
|
+
end
|
|
1430
|
+
|
|
1431
|
+
Skip(Bytes)
|
|
1432
|
+
|
|
1433
|
+
return Values
|
|
1434
|
+
end, function(Values: { [string]: boolean })
|
|
1435
|
+
Allocate(Bytes)
|
|
1436
|
+
|
|
1437
|
+
for Index, Name in Names do
|
|
1438
|
+
WriteBits(Index - 1, 1, if Values[Name] then 1 else 0)
|
|
1439
|
+
end
|
|
1440
|
+
|
|
1441
|
+
Skip(Bytes)
|
|
1442
|
+
end, Bytes)
|
|
1443
|
+
end
|
|
1444
|
+
|
|
1445
|
+
function Schema.Range(Inner: any, Minimum: number, Maximum: number): Schema
|
|
1446
|
+
const InnerSchema = Compile(Inner)
|
|
1447
|
+
const ReadInner, WriteInner = InnerSchema.Read, InnerSchema.Write
|
|
1448
|
+
|
|
1449
|
+
if Minimum > Maximum then
|
|
1450
|
+
error("[swiftpacket] range minimum is larger than its maximum", 2)
|
|
1451
|
+
end
|
|
1452
|
+
|
|
1453
|
+
return Define(function()
|
|
1454
|
+
const Value = ReadInner()
|
|
1455
|
+
|
|
1456
|
+
if type(Value) ~= "number" or Value < Minimum or Value > Maximum then
|
|
1457
|
+
error(`[swiftpacket] rejected {tostring(Value)} outside the range {Minimum} to {Maximum}`, 0)
|
|
1458
|
+
end
|
|
1459
|
+
|
|
1460
|
+
return Value
|
|
1461
|
+
end, function(Value: number)
|
|
1462
|
+
if Value < Minimum or Value > Maximum then
|
|
1463
|
+
WriteFailure(`{Value} is outside the range {Minimum} to {Maximum}`)
|
|
1464
|
+
end
|
|
1465
|
+
|
|
1466
|
+
WriteInner(Value)
|
|
1467
|
+
end, InnerSchema.MinimumSize)
|
|
1468
|
+
end
|
|
1469
|
+
|
|
1470
|
+
function Schema.InstanceOf(ClassName: string): Schema
|
|
1471
|
+
return Define(function()
|
|
1472
|
+
const Value = ReadInstance()
|
|
1473
|
+
|
|
1474
|
+
if Value and Value:IsA(ClassName) then
|
|
1475
|
+
return Value
|
|
1476
|
+
end
|
|
1477
|
+
|
|
1478
|
+
return nil
|
|
1479
|
+
end, function(Value: Instance?)
|
|
1480
|
+
if Value and not Value:IsA(ClassName) then
|
|
1481
|
+
WriteFailure(`{Value:GetFullName()} is not a {ClassName}`)
|
|
1482
|
+
end
|
|
1483
|
+
|
|
1484
|
+
WriteInstance(Value)
|
|
1485
|
+
end, 0)
|
|
1486
|
+
end
|
|
1487
|
+
|
|
1488
|
+
function Schema.EnumItem(EnumType: Enum): Schema
|
|
1489
|
+
return Define(function()
|
|
1490
|
+
const Item = EnumType:FromValue(ReadU16())
|
|
1491
|
+
|
|
1492
|
+
if Item == nil then
|
|
1493
|
+
error(`[swiftpacket] rejected an unknown {tostring(EnumType)} value`, 0)
|
|
1494
|
+
end
|
|
1495
|
+
|
|
1496
|
+
return Item
|
|
1497
|
+
end, function(Value: EnumItem)
|
|
1498
|
+
if Value.EnumType ~= EnumType then
|
|
1499
|
+
WriteFailure(`{tostring(Value)} is not a {tostring(EnumType)}`)
|
|
1500
|
+
end
|
|
1501
|
+
|
|
1502
|
+
Allocate(2)
|
|
1503
|
+
WriteU16(Value.Value)
|
|
1504
|
+
end, 2)
|
|
1505
|
+
end
|
|
1506
|
+
|
|
1507
|
+
function Schema.CompileList(Parameters: Arguments): { Schema }
|
|
1508
|
+
const Compiled: { Schema } = {}
|
|
1509
|
+
|
|
1510
|
+
for Index = 1, Parameters.n do
|
|
1511
|
+
Compiled[Index] = Compile(Parameters[Index])
|
|
1512
|
+
end
|
|
1513
|
+
|
|
1514
|
+
return Compiled
|
|
1515
|
+
end
|
|
1516
|
+
|
|
1517
|
+
const function WriteValues(Schemas: { Schema }, ...: any)
|
|
1518
|
+
const Count = #Schemas
|
|
1519
|
+
|
|
1520
|
+
if Count == 1 then
|
|
1521
|
+
Schemas[1].Write((...))
|
|
1522
|
+
elseif Count == 2 then
|
|
1523
|
+
const First, Second = ...
|
|
1524
|
+
|
|
1525
|
+
Schemas[1].Write(First)
|
|
1526
|
+
Schemas[2].Write(Second)
|
|
1527
|
+
elseif Count > 2 then
|
|
1528
|
+
const Values = { ... }
|
|
1529
|
+
|
|
1530
|
+
for Index = 1, Count do
|
|
1531
|
+
Schemas[Index].Write(Values[Index])
|
|
1532
|
+
end
|
|
1533
|
+
end
|
|
1534
|
+
end
|
|
1535
|
+
|
|
1536
|
+
function Schema.WriteEvent(Target: Cursor, Id: number, Name: string, Schemas: { Schema }, ...: any)
|
|
1537
|
+
Writing = Name
|
|
1538
|
+
Import(Target)
|
|
1539
|
+
WriteId(Id)
|
|
1540
|
+
WriteValues(Schemas, ...)
|
|
1541
|
+
Export()
|
|
1542
|
+
end
|
|
1543
|
+
|
|
1544
|
+
function Schema.WriteRequest(Target: Cursor, Id: number, CallIndex: number, Name: string, Schemas: { Schema }, ...: any)
|
|
1545
|
+
Writing = Name
|
|
1546
|
+
Import(Target)
|
|
1547
|
+
WriteId(Id)
|
|
1548
|
+
Allocate(2)
|
|
1549
|
+
WriteU16(CallIndex)
|
|
1550
|
+
WriteValues(Schemas, ...)
|
|
1551
|
+
Export()
|
|
1552
|
+
end
|
|
1553
|
+
|
|
1554
|
+
function Schema.WriteBody(Target: Cursor, Name: string, Schemas: { Schema }, ...: any)
|
|
1555
|
+
Writing = Name
|
|
1556
|
+
Reset(Target)
|
|
1557
|
+
Import(Target)
|
|
1558
|
+
WriteValues(Schemas, ...)
|
|
1559
|
+
Export()
|
|
1560
|
+
end
|
|
1561
|
+
|
|
1562
|
+
function Schema.WriteArguments(Schemas: { Schema }, Values: Arguments, Offset: number, Name: string)
|
|
1563
|
+
Writing = Name
|
|
1564
|
+
|
|
1565
|
+
for Index, Definition in Schemas do
|
|
1566
|
+
Definition.Write(Values[Index + Offset])
|
|
1567
|
+
end
|
|
1568
|
+
end
|
|
1569
|
+
|
|
1570
|
+
const SerializeScratch = NewCursor()
|
|
1571
|
+
|
|
1572
|
+
function Schema.Serialize(Name: string, Schemas: { Schema }, ...: any): (buffer, { any }?)
|
|
1573
|
+
Schema.WriteBody(SerializeScratch, Name, Schemas, ...)
|
|
1574
|
+
|
|
1575
|
+
const Data, Attached = Take(SerializeScratch)
|
|
1576
|
+
Reset(SerializeScratch)
|
|
1577
|
+
|
|
1578
|
+
return Data, Attached
|
|
1579
|
+
end
|
|
1580
|
+
|
|
1581
|
+
function Schema.Deserialize(Schemas: { Schema }, Source: buffer, SourceInstances: { any }): ...any
|
|
1582
|
+
Load(Source, SourceInstances, false, 0, 0)
|
|
1583
|
+
|
|
1584
|
+
const Count = #Schemas
|
|
1585
|
+
|
|
1586
|
+
if Count == 1 then
|
|
1587
|
+
return Schemas[1].Read()
|
|
1588
|
+
elseif Count == 2 then
|
|
1589
|
+
const First = Schemas[1].Read()
|
|
1590
|
+
const Second = Schemas[2].Read()
|
|
1591
|
+
|
|
1592
|
+
return First, Second
|
|
1593
|
+
end
|
|
1594
|
+
|
|
1595
|
+
const Values = table.create(Count)
|
|
1596
|
+
|
|
1597
|
+
for Index = 1, Count do
|
|
1598
|
+
Values[Index] = Schemas[Index].Read()
|
|
1599
|
+
end
|
|
1600
|
+
|
|
1601
|
+
return table.unpack(Values, 1, Count)
|
|
1602
|
+
end
|
|
1603
|
+
|
|
1604
|
+
Schema.Cursor = CursorLibrary
|
|
1605
|
+
|
|
1606
|
+
return Schema
|