mirror of
https://github.com/imezx/Warp.git
synced 2026-03-18 00:44:16 +00:00
rewrite(phase2): unreliable
This commit is contained in:
parent
b9bc52385c
commit
6bc31cb363
4 changed files with 541 additions and 225 deletions
|
|
@ -67,31 +67,50 @@ local T_COLSEQ = 0xF2 -- ColorSequence
|
||||||
local T_NUMSEQ = 0xF3 -- NumberSequence
|
local T_NUMSEQ = 0xF3 -- NumberSequence
|
||||||
|
|
||||||
local TYPED_READERS = {
|
local TYPED_READERS = {
|
||||||
[1] = function(b, o) return buffer.readu8(b, o), o + 1 end,
|
[1] = function(b, o)
|
||||||
[2] = function(b, o) return buffer.readi8(b, o), o + 1 end,
|
return buffer.readu8(b, o), o + 1
|
||||||
[3] = function(b, o) return buffer.readu16(b, o), o + 2 end,
|
end,
|
||||||
[4] = function(b, o) return buffer.readi16(b, o), o + 2 end,
|
[2] = function(b, o)
|
||||||
[5] = function(b, o) return buffer.readu32(b, o), o + 4 end,
|
return buffer.readi8(b, o), o + 1
|
||||||
[6] = function(b, o) return buffer.readi32(b, o), o + 4 end,
|
end,
|
||||||
[7] = function(b, o) return buffer.readf32(b, o), o + 4 end,
|
[3] = function(b, o)
|
||||||
[8] = function(b, o) return buffer.readf64(b, o), o + 8 end,
|
return buffer.readu16(b, o), o + 2
|
||||||
|
end,
|
||||||
|
[4] = function(b, o)
|
||||||
|
return buffer.readi16(b, o), o + 2
|
||||||
|
end,
|
||||||
|
[5] = function(b, o)
|
||||||
|
return buffer.readu32(b, o), o + 4
|
||||||
|
end,
|
||||||
|
[6] = function(b, o)
|
||||||
|
return buffer.readi32(b, o), o + 4
|
||||||
|
end,
|
||||||
|
[7] = function(b, o)
|
||||||
|
return buffer.readf32(b, o), o + 4
|
||||||
|
end,
|
||||||
|
[8] = function(b, o)
|
||||||
|
return buffer.readf64(b, o), o + 8
|
||||||
|
end,
|
||||||
}
|
}
|
||||||
|
|
||||||
local F16_MANTISSA_BITS = 1024
|
local F16_MANTISSA_BITS = 1024
|
||||||
local F16_DENORM do
|
local F16_DENORM
|
||||||
|
do
|
||||||
F16_DENORM = table.create(1024)
|
F16_DENORM = table.create(1024)
|
||||||
F16_DENORM[1] = 0
|
F16_DENORM[1] = 0
|
||||||
for m = 1, 1023 do
|
for m = 1, 1023 do
|
||||||
F16_DENORM[m + 1] = math.ldexp(m / F16_MANTISSA_BITS, -14)
|
F16_DENORM[m + 1] = math.ldexp(m / F16_MANTISSA_BITS, -14)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
local F16_EXP2 do
|
local F16_EXP2
|
||||||
|
do
|
||||||
F16_EXP2 = table.create(31)
|
F16_EXP2 = table.create(31)
|
||||||
for e = 1, 30 do
|
for e = 1, 30 do
|
||||||
F16_EXP2[e] = math.ldexp(1, e - 15)
|
F16_EXP2[e] = math.ldexp(1, e - 15)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
local F16_NORM_MANTISSA do
|
local F16_NORM_MANTISSA
|
||||||
|
do
|
||||||
F16_NORM_MANTISSA = table.create(1024)
|
F16_NORM_MANTISSA = table.create(1024)
|
||||||
for m = 0, 1023 do
|
for m = 0, 1023 do
|
||||||
F16_NORM_MANTISSA[m + 1] = 1 + m / F16_MANTISSA_BITS
|
F16_NORM_MANTISSA[m + 1] = 1 + m / F16_MANTISSA_BITS
|
||||||
|
|
@ -100,10 +119,18 @@ end
|
||||||
local F32TOF16_SUBNORM_POW2 = { 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024 }
|
local F32TOF16_SUBNORM_POW2 = { 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024 }
|
||||||
|
|
||||||
local function f32ToF16(value: number): number
|
local function f32ToF16(value: number): number
|
||||||
if value ~= value then return 0x7E00 end
|
if value ~= value then
|
||||||
if value == math.huge then return 0x7C00 end
|
return 0x7E00
|
||||||
if value == -math.huge then return 0xFC00 end
|
end
|
||||||
if value == 0 then return 0 end
|
if value == math.huge then
|
||||||
|
return 0x7C00
|
||||||
|
end
|
||||||
|
if value == -math.huge then
|
||||||
|
return 0xFC00
|
||||||
|
end
|
||||||
|
if value == 0 then
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
|
||||||
local sign = 0
|
local sign = 0
|
||||||
if value < 0 then
|
if value < 0 then
|
||||||
|
|
@ -115,7 +142,9 @@ local function f32ToF16(value: number): number
|
||||||
exponent += 14
|
exponent += 14
|
||||||
|
|
||||||
if exponent <= 0 then
|
if exponent <= 0 then
|
||||||
if exponent < -10 then return sign end
|
if exponent < -10 then
|
||||||
|
return sign
|
||||||
|
end
|
||||||
local scale = F32TOF16_SUBNORM_POW2[10 + exponent] or bit32.lshift(1, 10 + exponent)
|
local scale = F32TOF16_SUBNORM_POW2[10 + exponent] or bit32.lshift(1, 10 + exponent)
|
||||||
mantissa = math.floor(mantissa * scale + 0.5)
|
mantissa = math.floor(mantissa * scale + 0.5)
|
||||||
return bit32.bor(sign, mantissa)
|
return bit32.bor(sign, mantissa)
|
||||||
|
|
@ -127,7 +156,9 @@ local function f32ToF16(value: number): number
|
||||||
if mantissa == F16_MANTISSA_BITS then
|
if mantissa == F16_MANTISSA_BITS then
|
||||||
mantissa = 0
|
mantissa = 0
|
||||||
exponent += 1
|
exponent += 1
|
||||||
if exponent >= 31 then return bit32.bor(sign, 0x7C00) end
|
if exponent >= 31 then
|
||||||
|
return bit32.bor(sign, 0x7C00)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
return bit32.bor(sign, bit32.lshift(exponent, 10), mantissa)
|
return bit32.bor(sign, bit32.lshift(exponent, 10), mantissa)
|
||||||
end
|
end
|
||||||
|
|
@ -150,10 +181,18 @@ local function f16ToF32(bits: number): number
|
||||||
end
|
end
|
||||||
|
|
||||||
local function varUIntSize(value: number): number
|
local function varUIntSize(value: number): number
|
||||||
if value < 0x80 then return 1 end
|
if value < 0x80 then
|
||||||
if value < 0x4000 then return 2 end
|
return 1
|
||||||
if value < 0x200000 then return 3 end
|
end
|
||||||
if value < 0x10000000 then return 4 end
|
if value < 0x4000 then
|
||||||
|
return 2
|
||||||
|
end
|
||||||
|
if value < 0x200000 then
|
||||||
|
return 3
|
||||||
|
end
|
||||||
|
if value < 0x10000000 then
|
||||||
|
return 4
|
||||||
|
end
|
||||||
return 5
|
return 5
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -191,7 +230,9 @@ end
|
||||||
|
|
||||||
local function ensureSpace(w: Writer, bytes: number)
|
local function ensureSpace(w: Writer, bytes: number)
|
||||||
local needed = w.cursor + bytes
|
local needed = w.cursor + bytes
|
||||||
if needed <= w.capacity then return end
|
if needed <= w.capacity then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
local newCap = w.capacity
|
local newCap = w.capacity
|
||||||
while newCap < needed do
|
while newCap < needed do
|
||||||
|
|
@ -357,17 +398,27 @@ end
|
||||||
-- is the table a homogeneous number array
|
-- is the table a homogeneous number array
|
||||||
local function analyzeNumberArray(t: { any }): (boolean, string?, number)
|
local function analyzeNumberArray(t: { any }): (boolean, string?, number)
|
||||||
local count = #t
|
local count = #t
|
||||||
if count == 0 then return false, nil, 0 end
|
if count == 0 then
|
||||||
|
return false, nil, 0
|
||||||
|
end
|
||||||
|
|
||||||
local minVal, maxVal = math.huge, -math.huge
|
local minVal, maxVal = math.huge, -math.huge
|
||||||
local allInt = true
|
local allInt = true
|
||||||
|
|
||||||
for i = 1, count do
|
for i = 1, count do
|
||||||
local v = t[i]
|
local v = t[i]
|
||||||
if type(v) ~= "number" then return false, nil, count end
|
if type(v) ~= "number" then
|
||||||
if v ~= math.floor(v) then allInt = false end
|
return false, nil, count
|
||||||
if v < minVal then minVal = v end
|
end
|
||||||
if v > maxVal then maxVal = v end
|
if v ~= math.floor(v) then
|
||||||
|
allInt = false
|
||||||
|
end
|
||||||
|
if v < minVal then
|
||||||
|
minVal = v
|
||||||
|
end
|
||||||
|
if v > maxVal then
|
||||||
|
maxVal = v
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if not allInt then
|
if not allInt then
|
||||||
|
|
@ -391,8 +442,14 @@ end
|
||||||
local TYPED_CODES = { u8 = 1, i8 = 2, u16 = 3, i16 = 4, u32 = 5, i32 = 6, f32 = 7, f64 = 8 }
|
local TYPED_CODES = { u8 = 1, i8 = 2, u16 = 3, i16 = 4, u32 = 5, i32 = 6, f32 = 7, f64 = 8 }
|
||||||
local TYPED_SIZES = { u8 = 1, i8 = 1, u16 = 2, i16 = 2, u32 = 4, i32 = 4, f32 = 4, f64 = 8 }
|
local TYPED_SIZES = { u8 = 1, i8 = 1, u16 = 2, i16 = 2, u32 = 4, i32 = 4, f32 = 4, f64 = 8 }
|
||||||
local TYPED_WRITERS = {
|
local TYPED_WRITERS = {
|
||||||
u8 = buffer.writeu8, i8 = buffer.writei8, u16 = buffer.writeu16, i16 = buffer.writei16,
|
u8 = buffer.writeu8,
|
||||||
u32 = buffer.writeu32, i32 = buffer.writei32, f32 = buffer.writef32, f64 = buffer.writef64,
|
i8 = buffer.writei8,
|
||||||
|
u16 = buffer.writeu16,
|
||||||
|
i16 = buffer.writei16,
|
||||||
|
u32 = buffer.writeu32,
|
||||||
|
i32 = buffer.writei32,
|
||||||
|
f32 = buffer.writef32,
|
||||||
|
f64 = buffer.writef64,
|
||||||
}
|
}
|
||||||
|
|
||||||
local function packTable(w: Writer, t: { [any]: any })
|
local function packTable(w: Writer, t: { [any]: any })
|
||||||
|
|
@ -403,7 +460,9 @@ local function packTable(w: Writer, t: {[any]: any})
|
||||||
for k in t do
|
for k in t do
|
||||||
count += 1
|
count += 1
|
||||||
if type(k) == "number" and k > 0 and k == math.floor(k) then
|
if type(k) == "number" and k > 0 and k == math.floor(k) then
|
||||||
if k > maxIdx then maxIdx = k end
|
if k > maxIdx then
|
||||||
|
maxIdx = k
|
||||||
|
end
|
||||||
else
|
else
|
||||||
isArray = false
|
isArray = false
|
||||||
end
|
end
|
||||||
|
|
@ -667,18 +726,40 @@ unpackValue = function(buf: buffer, pos: number, refs: {any}?): (any, number)
|
||||||
return t - 0x80 - 32, pos
|
return t - 0x80 - 32, pos
|
||||||
end
|
end
|
||||||
|
|
||||||
if t == T_NIL then return nil, pos end
|
if t == T_NIL then
|
||||||
if t == T_FALSE then return false, pos end
|
return nil, pos
|
||||||
if t == T_TRUE then return true, pos end
|
end
|
||||||
|
if t == T_FALSE then
|
||||||
|
return false, pos
|
||||||
|
end
|
||||||
|
if t == T_TRUE then
|
||||||
|
return true, pos
|
||||||
|
end
|
||||||
|
|
||||||
if t == T_U8 then return buffer.readu8(buf, pos), pos + 1 end
|
if t == T_U8 then
|
||||||
if t == T_U16 then return buffer.readu16(buf, pos), pos + 2 end
|
return buffer.readu8(buf, pos), pos + 1
|
||||||
if t == T_U32 then return buffer.readu32(buf, pos), pos + 4 end
|
end
|
||||||
if t == T_I8 then return buffer.readi8(buf, pos), pos + 1 end
|
if t == T_U16 then
|
||||||
if t == T_I16 then return buffer.readi16(buf, pos), pos + 2 end
|
return buffer.readu16(buf, pos), pos + 2
|
||||||
if t == T_I32 then return buffer.readi32(buf, pos), pos + 4 end
|
end
|
||||||
if t == T_F32 then return buffer.readf32(buf, pos), pos + 4 end
|
if t == T_U32 then
|
||||||
if t == T_F64 then return buffer.readf64(buf, pos), pos + 8 end
|
return buffer.readu32(buf, pos), pos + 4
|
||||||
|
end
|
||||||
|
if t == T_I8 then
|
||||||
|
return buffer.readi8(buf, pos), pos + 1
|
||||||
|
end
|
||||||
|
if t == T_I16 then
|
||||||
|
return buffer.readi16(buf, pos), pos + 2
|
||||||
|
end
|
||||||
|
if t == T_I32 then
|
||||||
|
return buffer.readi32(buf, pos), pos + 4
|
||||||
|
end
|
||||||
|
if t == T_F32 then
|
||||||
|
return buffer.readf32(buf, pos), pos + 4
|
||||||
|
end
|
||||||
|
if t == T_F64 then
|
||||||
|
return buffer.readf64(buf, pos), pos + 8
|
||||||
|
end
|
||||||
|
|
||||||
-- inline str len (0-15)
|
-- inline str len (0-15)
|
||||||
if t >= T_STR_BASE and t <= T_STR_BASE + 15 then
|
if t >= T_STR_BASE and t <= T_STR_BASE + 15 then
|
||||||
|
|
@ -695,7 +776,8 @@ unpackValue = function(buf: buffer, pos: number, refs: {any}?): (any, number)
|
||||||
return buffer.readstring(buf, pos + 2, n), pos + 2 + n
|
return buffer.readstring(buf, pos + 2, n), pos + 2 + n
|
||||||
end
|
end
|
||||||
if t == T_STRVAR then
|
if t == T_STRVAR then
|
||||||
local n; n, pos = readVarUInt(buf, pos)
|
local n
|
||||||
|
n, pos = readVarUInt(buf, pos)
|
||||||
return buffer.readstring(buf, pos, n), pos + n
|
return buffer.readstring(buf, pos, n), pos + n
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -710,7 +792,8 @@ unpackValue = function(buf: buffer, pos: number, refs: {any}?): (any, number)
|
||||||
end
|
end
|
||||||
|
|
||||||
if t == T_ARR8 then
|
if t == T_ARR8 then
|
||||||
local count = buffer.readu8(buf, pos); pos += 1
|
local count = buffer.readu8(buf, pos)
|
||||||
|
pos += 1
|
||||||
local arr = table.create(count)
|
local arr = table.create(count)
|
||||||
for i = 1, count do
|
for i = 1, count do
|
||||||
arr[i], pos = unpackValue(buf, pos, refs)
|
arr[i], pos = unpackValue(buf, pos, refs)
|
||||||
|
|
@ -718,7 +801,8 @@ unpackValue = function(buf: buffer, pos: number, refs: {any}?): (any, number)
|
||||||
return arr, pos
|
return arr, pos
|
||||||
end
|
end
|
||||||
if t == T_ARR16 then
|
if t == T_ARR16 then
|
||||||
local count = buffer.readu16(buf, pos); pos += 2
|
local count = buffer.readu16(buf, pos)
|
||||||
|
pos += 2
|
||||||
local arr = table.create(count)
|
local arr = table.create(count)
|
||||||
for i = 1, count do
|
for i = 1, count do
|
||||||
arr[i], pos = unpackValue(buf, pos, refs)
|
arr[i], pos = unpackValue(buf, pos, refs)
|
||||||
|
|
@ -726,7 +810,8 @@ unpackValue = function(buf: buffer, pos: number, refs: {any}?): (any, number)
|
||||||
return arr, pos
|
return arr, pos
|
||||||
end
|
end
|
||||||
if t == T_ARRVAR then
|
if t == T_ARRVAR then
|
||||||
local count; count, pos = readVarUInt(buf, pos)
|
local count
|
||||||
|
count, pos = readVarUInt(buf, pos)
|
||||||
local arr = table.create(count)
|
local arr = table.create(count)
|
||||||
for i = 1, count do
|
for i = 1, count do
|
||||||
arr[i], pos = unpackValue(buf, pos, refs)
|
arr[i], pos = unpackValue(buf, pos, refs)
|
||||||
|
|
@ -748,7 +833,8 @@ unpackValue = function(buf: buffer, pos: number, refs: {any}?): (any, number)
|
||||||
end
|
end
|
||||||
|
|
||||||
if t == T_MAP8 then
|
if t == T_MAP8 then
|
||||||
local count = buffer.readu8(buf, pos); pos += 1
|
local count = buffer.readu8(buf, pos)
|
||||||
|
pos += 1
|
||||||
local map = {}
|
local map = {}
|
||||||
for _ = 1, count do
|
for _ = 1, count do
|
||||||
local k, v
|
local k, v
|
||||||
|
|
@ -759,7 +845,8 @@ unpackValue = function(buf: buffer, pos: number, refs: {any}?): (any, number)
|
||||||
return map, pos
|
return map, pos
|
||||||
end
|
end
|
||||||
if t == T_MAP16 then
|
if t == T_MAP16 then
|
||||||
local count = buffer.readu16(buf, pos); pos += 2
|
local count = buffer.readu16(buf, pos)
|
||||||
|
pos += 2
|
||||||
local map = {}
|
local map = {}
|
||||||
for _ = 1, count do
|
for _ = 1, count do
|
||||||
local k, v
|
local k, v
|
||||||
|
|
@ -770,7 +857,8 @@ unpackValue = function(buf: buffer, pos: number, refs: {any}?): (any, number)
|
||||||
return map, pos
|
return map, pos
|
||||||
end
|
end
|
||||||
if t == T_MAPVAR then
|
if t == T_MAPVAR then
|
||||||
local count; count, pos = readVarUInt(buf, pos)
|
local count
|
||||||
|
count, pos = readVarUInt(buf, pos)
|
||||||
local map = {}
|
local map = {}
|
||||||
for _ = 1, count do
|
for _ = 1, count do
|
||||||
local k, v
|
local k, v
|
||||||
|
|
@ -783,8 +871,10 @@ unpackValue = function(buf: buffer, pos: number, refs: {any}?): (any, number)
|
||||||
|
|
||||||
-- typed array
|
-- typed array
|
||||||
if t == T_TYPED_ARR then
|
if t == T_TYPED_ARR then
|
||||||
local subtype = buffer.readu8(buf, pos); pos += 1
|
local subtype = buffer.readu8(buf, pos)
|
||||||
local count; count, pos = readVarUInt(buf, pos)
|
pos += 1
|
||||||
|
local count
|
||||||
|
count, pos = readVarUInt(buf, pos)
|
||||||
local reader = TYPED_READERS[subtype]
|
local reader = TYPED_READERS[subtype]
|
||||||
local arr = table.create(count)
|
local arr = table.create(count)
|
||||||
for i = 1, count do
|
for i = 1, count do
|
||||||
|
|
@ -858,12 +948,14 @@ unpackValue = function(buf: buffer, pos: number, refs: {any}?): (any, number)
|
||||||
end
|
end
|
||||||
|
|
||||||
if t == T_INSTANCE then
|
if t == T_INSTANCE then
|
||||||
local idx; idx, pos = readVarUInt(buf, pos)
|
local idx
|
||||||
|
idx, pos = readVarUInt(buf, pos)
|
||||||
return refs and refs[idx] or nil, pos
|
return refs and refs[idx] or nil, pos
|
||||||
end
|
end
|
||||||
|
|
||||||
if t == T_ENUMITEM then
|
if t == T_ENUMITEM then
|
||||||
local nameLen; nameLen, pos = readVarUInt(buf, pos)
|
local nameLen
|
||||||
|
nameLen, pos = readVarUInt(buf, pos)
|
||||||
local enumName = buffer.readstring(buf, pos, nameLen)
|
local enumName = buffer.readstring(buf, pos, nameLen)
|
||||||
pos += nameLen
|
pos += nameLen
|
||||||
local val = buffer.readu16(buf, pos)
|
local val = buffer.readu16(buf, pos)
|
||||||
|
|
@ -871,7 +963,8 @@ unpackValue = function(buf: buffer, pos: number, refs: {any}?): (any, number)
|
||||||
end
|
end
|
||||||
|
|
||||||
if t == T_ENUM then
|
if t == T_ENUM then
|
||||||
local nameLen; nameLen, pos = readVarUInt(buf, pos)
|
local nameLen
|
||||||
|
nameLen, pos = readVarUInt(buf, pos)
|
||||||
local enumName = buffer.readstring(buf, pos, nameLen)
|
local enumName = buffer.readstring(buf, pos, nameLen)
|
||||||
return (Enum :: any)[enumName], pos + nameLen
|
return (Enum :: any)[enumName], pos + nameLen
|
||||||
end
|
end
|
||||||
|
|
@ -892,9 +985,12 @@ unpackValue = function(buf: buffer, pos: number, refs: {any}?): (any, number)
|
||||||
|
|
||||||
if t == T_RECT then
|
if t == T_RECT then
|
||||||
return Rect.new(
|
return Rect.new(
|
||||||
buffer.readf32(buf, pos), buffer.readf32(buf, pos + 4),
|
buffer.readf32(buf, pos),
|
||||||
buffer.readf32(buf, pos + 8), buffer.readf32(buf, pos + 12)
|
buffer.readf32(buf, pos + 4),
|
||||||
), pos + 16
|
buffer.readf32(buf, pos + 8),
|
||||||
|
buffer.readf32(buf, pos + 12)
|
||||||
|
),
|
||||||
|
pos + 16
|
||||||
end
|
end
|
||||||
|
|
||||||
if t == T_NUMBERRANGE then
|
if t == T_NUMBERRANGE then
|
||||||
|
|
@ -905,11 +1001,13 @@ unpackValue = function(buf: buffer, pos: number, refs: {any}?): (any, number)
|
||||||
return Ray.new(
|
return Ray.new(
|
||||||
Vector3.new(buffer.readf32(buf, pos), buffer.readf32(buf, pos + 4), buffer.readf32(buf, pos + 8)),
|
Vector3.new(buffer.readf32(buf, pos), buffer.readf32(buf, pos + 4), buffer.readf32(buf, pos + 8)),
|
||||||
Vector3.new(buffer.readf32(buf, pos + 12), buffer.readf32(buf, pos + 16), buffer.readf32(buf, pos + 20))
|
Vector3.new(buffer.readf32(buf, pos + 12), buffer.readf32(buf, pos + 16), buffer.readf32(buf, pos + 20))
|
||||||
), pos + 24
|
),
|
||||||
|
pos + 24
|
||||||
end
|
end
|
||||||
|
|
||||||
if t == T_COLSEQ then
|
if t == T_COLSEQ then
|
||||||
local count = buffer.readu8(buf, pos); pos += 1
|
local count = buffer.readu8(buf, pos)
|
||||||
|
pos += 1
|
||||||
local keypoints = table.create(count)
|
local keypoints = table.create(count)
|
||||||
for i = 1, count do
|
for i = 1, count do
|
||||||
local time = buffer.readf32(buf, pos)
|
local time = buffer.readf32(buf, pos)
|
||||||
|
|
@ -923,7 +1021,8 @@ unpackValue = function(buf: buffer, pos: number, refs: {any}?): (any, number)
|
||||||
end
|
end
|
||||||
|
|
||||||
if t == T_NUMSEQ then
|
if t == T_NUMSEQ then
|
||||||
local count = buffer.readu8(buf, pos); pos += 1
|
local count = buffer.readu8(buf, pos)
|
||||||
|
pos += 1
|
||||||
local keypoints = table.create(count)
|
local keypoints = table.create(count)
|
||||||
for i = 1, count do
|
for i = 1, count do
|
||||||
local time = buffer.readf32(buf, pos)
|
local time = buffer.readf32(buf, pos)
|
||||||
|
|
@ -936,7 +1035,8 @@ unpackValue = function(buf: buffer, pos: number, refs: {any}?): (any, number)
|
||||||
end
|
end
|
||||||
|
|
||||||
if t == T_BUFFER then
|
if t == T_BUFFER then
|
||||||
local len; len, pos = readVarUInt(buf, pos)
|
local len
|
||||||
|
len, pos = readVarUInt(buf, pos)
|
||||||
local b = buffer.create(len)
|
local b = buffer.create(len)
|
||||||
buffer.copy(b, 0, buf, pos, len)
|
buffer.copy(b, 0, buf, pos, len)
|
||||||
return b, pos + len
|
return b, pos + len
|
||||||
|
|
@ -999,32 +1099,81 @@ function Schema.struct(fields: {[string]: SchemaType}): SchemaType
|
||||||
for k, v in fields do
|
for k, v in fields do
|
||||||
table.insert(orderedFields, { key = k, schema = v })
|
table.insert(orderedFields, { key = k, schema = v })
|
||||||
end
|
end
|
||||||
table.sort(orderedFields, function(a, b) return a.key < b.key end)
|
table.sort(orderedFields, function(a, b)
|
||||||
|
return a.key < b.key
|
||||||
|
end)
|
||||||
return { type = "struct", fields = orderedFields }
|
return { type = "struct", fields = orderedFields }
|
||||||
end
|
end
|
||||||
|
|
||||||
local function compilePacker(s: SchemaType): (Writer, any) -> ()
|
local function compilePacker(s: SchemaType): (Writer, any) -> ()
|
||||||
if s.type == "u8" then return wByte end
|
if s.type == "u8" then
|
||||||
if s.type == "i8" then return function(w, v) ensureSpace(w, 1) buffer.writei8(w.buf, w.cursor, v) w.cursor += 1 end end
|
return wByte
|
||||||
if s.type == "u16" then return wU16 end
|
end
|
||||||
if s.type == "i16" then return wI16 end
|
if s.type == "i8" then
|
||||||
if s.type == "u32" then return wU32 end
|
return function(w, v)
|
||||||
if s.type == "i32" then return wI32 end
|
ensureSpace(w, 1)
|
||||||
if s.type == "f32" then return wF32 end
|
buffer.writei8(w.buf, w.cursor, v)
|
||||||
if s.type == "f64" then return wF64 end
|
w.cursor += 1
|
||||||
if s.type == "f16" then return wF16 end
|
end
|
||||||
if s.type == "boolean" then return function(w, v) wByte(w, v and 1 or 0) end end
|
end
|
||||||
if s.type == "string" then return function(w, v) local len = #v wVarUInt(w, len) wString(w, v) end end
|
if s.type == "u16" then
|
||||||
|
return wU16
|
||||||
|
end
|
||||||
|
if s.type == "i16" then
|
||||||
|
return wI16
|
||||||
|
end
|
||||||
|
if s.type == "u32" then
|
||||||
|
return wU32
|
||||||
|
end
|
||||||
|
if s.type == "i32" then
|
||||||
|
return wI32
|
||||||
|
end
|
||||||
|
if s.type == "f32" then
|
||||||
|
return wF32
|
||||||
|
end
|
||||||
|
if s.type == "f64" then
|
||||||
|
return wF64
|
||||||
|
end
|
||||||
|
if s.type == "f16" then
|
||||||
|
return wF16
|
||||||
|
end
|
||||||
|
if s.type == "boolean" then
|
||||||
|
return function(w, v)
|
||||||
|
wByte(w, v and 1 or 0)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if s.type == "string" then
|
||||||
|
return function(w, v)
|
||||||
|
local len = #v
|
||||||
|
wVarUInt(w, len)
|
||||||
|
wString(w, v)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
if s.type == "vector3" then return function(w, v) wF16(w, f32ToF16(v.X)) wF16(w, f32ToF16(v.Y)) wF16(w, f32ToF16(v.Z)) end end
|
if s.type == "vector3" then
|
||||||
if s.type == "vector2" then return function(w, v) wF16(w, f32ToF16(v.X)) wF16(w, f32ToF16(v.Y)) end end
|
return function(w, v)
|
||||||
|
wF16(w, f32ToF16(v.X))
|
||||||
|
wF16(w, f32ToF16(v.Y))
|
||||||
|
wF16(w, f32ToF16(v.Z))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if s.type == "vector2" then
|
||||||
|
return function(w, v)
|
||||||
|
wF16(w, f32ToF16(v.X))
|
||||||
|
wF16(w, f32ToF16(v.Y))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
if s.type == "cframe" then
|
if s.type == "cframe" then
|
||||||
return function(w, v)
|
return function(w, v)
|
||||||
local pos = v.Position
|
local pos = v.Position
|
||||||
local rx, ry, rz = v:ToOrientation()
|
local rx, ry, rz = v:ToOrientation()
|
||||||
wF16(w, f32ToF16(pos.X)) wF16(w, f32ToF16(pos.Y)) wF16(w, f32ToF16(pos.Z))
|
wF16(w, f32ToF16(pos.X))
|
||||||
wF16(w, f32ToF16(rx)) wF16(w, f32ToF16(ry)) wF16(w, f32ToF16(rz))
|
wF16(w, f32ToF16(pos.Y))
|
||||||
|
wF16(w, f32ToF16(pos.Z))
|
||||||
|
wF16(w, f32ToF16(rx))
|
||||||
|
wF16(w, f32ToF16(ry))
|
||||||
|
wF16(w, f32ToF16(rz))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -1036,7 +1185,12 @@ local function compilePacker(s: SchemaType): (Writer, any) -> ()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if s.type == "instance" then return function(w, v) table.insert(w.refs, v) wVarUInt(w, #w.refs) end end
|
if s.type == "instance" then
|
||||||
|
return function(w, v)
|
||||||
|
table.insert(w.refs, v)
|
||||||
|
wVarUInt(w, #w.refs)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
if s.type == "struct" then
|
if s.type == "struct" then
|
||||||
local fields = {}
|
local fields = {}
|
||||||
|
|
@ -1044,10 +1198,14 @@ local function compilePacker(s: SchemaType): (Writer, any) -> ()
|
||||||
table.insert(fields, { key = field.key, packer = compilePacker(field.schema) })
|
table.insert(fields, { key = field.key, packer = compilePacker(field.schema) })
|
||||||
end
|
end
|
||||||
return function(w, v)
|
return function(w, v)
|
||||||
if type(v) ~= "table" then error(`Expected table for struct, got {typeof(v)}`) end
|
if type(v) ~= "table" then
|
||||||
|
error(`Expected table for struct, got {typeof(v)}`)
|
||||||
|
end
|
||||||
for _, f in fields do
|
for _, f in fields do
|
||||||
local val = v[f.key]
|
local val = v[f.key]
|
||||||
if val == nil then error(`Schema Error: Missing required field '{f.key}'`) end
|
if val == nil then
|
||||||
|
error(`Schema Error: Missing required field '{f.key}'`)
|
||||||
|
end
|
||||||
f.packer(w, val)
|
f.packer(w, val)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
@ -1056,11 +1214,15 @@ local function compilePacker(s: SchemaType): (Writer, any) -> ()
|
||||||
if s.type == "array" then
|
if s.type == "array" then
|
||||||
local itemPacker = compilePacker(s.item)
|
local itemPacker = compilePacker(s.item)
|
||||||
return function(w, v)
|
return function(w, v)
|
||||||
if type(v) ~= "table" then error(`Expected table for array, got {typeof(v)}`) end
|
if type(v) ~= "table" then
|
||||||
|
error(`Expected table for array, got {typeof(v)}`)
|
||||||
|
end
|
||||||
local len = #v
|
local len = #v
|
||||||
wVarUInt(w, len)
|
wVarUInt(w, len)
|
||||||
for i = 1, len do
|
for i = 1, len do
|
||||||
if v[i] == nil then error(`Schema Error: Array item at index {i} is nil`) end
|
if v[i] == nil then
|
||||||
|
error(`Schema Error: Array item at index {i} is nil`)
|
||||||
|
end
|
||||||
itemPacker(w, v[i])
|
itemPacker(w, v[i])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
@ -1071,7 +1233,9 @@ local function compilePacker(s: SchemaType): (Writer, any) -> ()
|
||||||
local valPacker = compilePacker(s.value)
|
local valPacker = compilePacker(s.value)
|
||||||
return function(w, v)
|
return function(w, v)
|
||||||
local count = 0
|
local count = 0
|
||||||
for _ in v do count += 1 end
|
for _ in v do
|
||||||
|
count += 1
|
||||||
|
end
|
||||||
wVarUInt(w, count)
|
wVarUInt(w, count)
|
||||||
for k, val in v do
|
for k, val in v do
|
||||||
keyPacker(w, k)
|
keyPacker(w, k)
|
||||||
|
|
@ -1096,19 +1260,60 @@ local function compilePacker(s: SchemaType): (Writer, any) -> ()
|
||||||
end
|
end
|
||||||
|
|
||||||
local function compileReader(s: SchemaType): (buffer, number, { any }?) -> (any, number)
|
local function compileReader(s: SchemaType): (buffer, number, { any }?) -> (any, number)
|
||||||
if s.type == "u8" then return function(b, c) return buffer.readu8(b, c), c + 1 end end
|
if s.type == "u8" then
|
||||||
if s.type == "i8" then return function(b, c) return buffer.readi8(b, c), c + 1 end end
|
return function(b, c)
|
||||||
if s.type == "u16" then return function(b, c) return buffer.readu16(b, c), c + 2 end end
|
return buffer.readu8(b, c), c + 1
|
||||||
if s.type == "i16" then return function(b, c) return buffer.readi16(b, c), c + 2 end end
|
end
|
||||||
if s.type == "u32" then return function(b, c) return buffer.readu32(b, c), c + 4 end end
|
end
|
||||||
if s.type == "i32" then return function(b, c) return buffer.readi32(b, c), c + 4 end end
|
if s.type == "i8" then
|
||||||
if s.type == "f32" then return function(b, c) return buffer.readf32(b, c), c + 4 end end
|
return function(b, c)
|
||||||
if s.type == "f64" then return function(b, c) return buffer.readf64(b, c), c + 8 end end
|
return buffer.readi8(b, c), c + 1
|
||||||
if s.type == "f16" then return function(b, c) return f16ToF32(buffer.readu16(b, c)), c + 2 end end
|
end
|
||||||
if s.type == "boolean" then return function(b, c) return buffer.readu8(b, c) ~= 0, c + 1 end end
|
end
|
||||||
|
if s.type == "u16" then
|
||||||
|
return function(b, c)
|
||||||
|
return buffer.readu16(b, c), c + 2
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if s.type == "i16" then
|
||||||
|
return function(b, c)
|
||||||
|
return buffer.readi16(b, c), c + 2
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if s.type == "u32" then
|
||||||
|
return function(b, c)
|
||||||
|
return buffer.readu32(b, c), c + 4
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if s.type == "i32" then
|
||||||
|
return function(b, c)
|
||||||
|
return buffer.readi32(b, c), c + 4
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if s.type == "f32" then
|
||||||
|
return function(b, c)
|
||||||
|
return buffer.readf32(b, c), c + 4
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if s.type == "f64" then
|
||||||
|
return function(b, c)
|
||||||
|
return buffer.readf64(b, c), c + 8
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if s.type == "f16" then
|
||||||
|
return function(b, c)
|
||||||
|
return f16ToF32(buffer.readu16(b, c)), c + 2
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if s.type == "boolean" then
|
||||||
|
return function(b, c)
|
||||||
|
return buffer.readu8(b, c) ~= 0, c + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
if s.type == "string" then
|
if s.type == "string" then
|
||||||
return function(b, c)
|
return function(b, c)
|
||||||
local len; len, c = readVarUInt(b, c)
|
local len
|
||||||
|
len, c = readVarUInt(b, c)
|
||||||
return buffer.readstring(b, c, len), c + len
|
return buffer.readstring(b, c, len), c + len
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
@ -1151,7 +1356,8 @@ local function compileReader(s: SchemaType): (buffer, number, {any}?) -> (any, n
|
||||||
end
|
end
|
||||||
if s.type == "instance" then
|
if s.type == "instance" then
|
||||||
return function(b, c, refs)
|
return function(b, c, refs)
|
||||||
local idx; idx, c = readVarUInt(b, c)
|
local idx
|
||||||
|
idx, c = readVarUInt(b, c)
|
||||||
return refs and refs[idx] or nil, c
|
return refs and refs[idx] or nil, c
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
@ -1173,7 +1379,8 @@ local function compileReader(s: SchemaType): (buffer, number, {any}?) -> (any, n
|
||||||
if s.type == "array" then
|
if s.type == "array" then
|
||||||
local itemReader = compileReader(s.item)
|
local itemReader = compileReader(s.item)
|
||||||
return function(b, c, refs)
|
return function(b, c, refs)
|
||||||
local len; len, c = readVarUInt(b, c)
|
local len
|
||||||
|
len, c = readVarUInt(b, c)
|
||||||
local arr = table.create(len)
|
local arr = table.create(len)
|
||||||
for i = 1, len do
|
for i = 1, len do
|
||||||
arr[i], c = itemReader(b, c, refs)
|
arr[i], c = itemReader(b, c, refs)
|
||||||
|
|
@ -1186,7 +1393,8 @@ local function compileReader(s: SchemaType): (buffer, number, {any}?) -> (any, n
|
||||||
local keyReader = compileReader(s.key)
|
local keyReader = compileReader(s.key)
|
||||||
local valReader = compileReader(s.value)
|
local valReader = compileReader(s.value)
|
||||||
return function(b, c, refs)
|
return function(b, c, refs)
|
||||||
local count; count, c = readVarUInt(b, c)
|
local count
|
||||||
|
count, c = readVarUInt(b, c)
|
||||||
local map = {}
|
local map = {}
|
||||||
for _ = 1, count do
|
for _ = 1, count do
|
||||||
local k, val
|
local k, val
|
||||||
|
|
@ -1211,7 +1419,9 @@ local function compileReader(s: SchemaType): (buffer, number, {any}?) -> (any, n
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return function(_, c) return nil, c end
|
return function(_, c)
|
||||||
|
return nil, c
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function packStrict(w: Writer, s: SchemaType, v: any)
|
local function packStrict(w: Writer, s: SchemaType, v: any)
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ local RunService = game:GetService("RunService")
|
||||||
local Thread = require("./Thread")
|
local Thread = require("./Thread")
|
||||||
local Buffer = require("./Buffer")
|
local Buffer = require("./Buffer")
|
||||||
local Event: RemoteEvent = script.Parent:WaitForChild("Event")
|
local Event: RemoteEvent = script.Parent:WaitForChild("Event")
|
||||||
local Function: RemoteFunction = script.Parent:WaitForChild("Function")
|
local UnreliableEvent: UnreliableRemoteEvent = script.Parent:WaitForChild("UnreliableEvent")
|
||||||
local deltaT: number, cycle: number = 0, 1 / 61
|
local deltaT: number, cycle: number = 0, 1 / 61
|
||||||
local writer: Buffer.Writer = Buffer.createWriter()
|
local writer: Buffer.Writer = Buffer.createWriter()
|
||||||
|
|
||||||
|
|
@ -17,10 +17,11 @@ type Connection = {
|
||||||
}
|
}
|
||||||
type Event = {
|
type Event = {
|
||||||
remote: string,
|
remote: string,
|
||||||
fn: (Player, ...any?) -> (...any?),
|
fn: (Player, ...any?) -> ...any?,
|
||||||
}
|
}
|
||||||
|
|
||||||
local queueEvent: { { any } } = {}
|
local queueEvent: { { any } } = {}
|
||||||
|
local queueUnreliableEvent: { { any } } = {}
|
||||||
local eventListeners: { Event } = {}
|
local eventListeners: { Event } = {}
|
||||||
local eventSchemas: { [string]: Buffer.SchemaType } = {}
|
local eventSchemas: { [string]: Buffer.SchemaType } = {}
|
||||||
|
|
||||||
|
|
@ -31,7 +32,7 @@ Client.useSchema = function(remoteName: string, schema: Buffer.SchemaType)
|
||||||
eventSchemas[remoteName] = schema
|
eventSchemas[remoteName] = schema
|
||||||
end
|
end
|
||||||
|
|
||||||
Client.Connect = function(remoteName: string, fn: (Player, ...any?) -> (...any?)): Connection
|
Client.Connect = function(remoteName: string, fn: (Player, ...any?) -> ...any?): Connection
|
||||||
local detail = {
|
local detail = {
|
||||||
remote = remoteName,
|
remote = remoteName,
|
||||||
fn = fn,
|
fn = fn,
|
||||||
|
|
@ -40,7 +41,9 @@ Client.Connect = function(remoteName: string, fn: (Player, ...any?) -> (...any?)
|
||||||
return {
|
return {
|
||||||
Connected = true,
|
Connected = true,
|
||||||
Disconnect = function(self: Connection)
|
Disconnect = function(self: Connection)
|
||||||
if not self.Connected then return end
|
if not self.Connected then
|
||||||
|
return
|
||||||
|
end
|
||||||
self.Connected = false
|
self.Connected = false
|
||||||
local idx = table.find(eventListeners, detail)
|
local idx = table.find(eventListeners, detail)
|
||||||
if idx then
|
if idx then
|
||||||
|
|
@ -81,10 +84,10 @@ Client.Destroy = function(remoteName: string)
|
||||||
Client.DisconnectAll(remoteName)
|
Client.DisconnectAll(remoteName)
|
||||||
end
|
end
|
||||||
|
|
||||||
Client.Fire = function(remoteName: string, ...: any?)
|
Client.Fire = function(remoteName: string, reliable: boolean, ...: any?)
|
||||||
table.insert(queueEvent, {
|
table.insert(reliable and queueEvent or queueUnreliableEvent, {
|
||||||
remoteName,
|
remoteName,
|
||||||
{ ... } :: any
|
{ ... } :: any,
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -101,21 +104,23 @@ Client.Invoke = function(remoteName: string, timeout: number?, ...: any?): ...an
|
||||||
task.spawn(pending, nil)
|
task.spawn(pending, nil)
|
||||||
pendingInvokes[id] = nil
|
pendingInvokes[id] = nil
|
||||||
end)
|
end)
|
||||||
|
|
||||||
table.insert(queueEvent, {
|
table.insert(queueEvent, {
|
||||||
"\0",
|
"\0",
|
||||||
{ remoteName, id, { ... } :: any } :: any
|
{ remoteName, id, { ... } :: any } :: any,
|
||||||
})
|
})
|
||||||
return coroutine.yield()
|
return coroutine.yield()
|
||||||
end
|
end
|
||||||
|
|
||||||
if RunService:IsClient() then
|
if RunService:IsClient() then
|
||||||
Event.OnClientEvent:Connect(function(b: buffer, ref: { Instance? })
|
local function processIncoming(b: buffer, ref: { Instance }?, handleInvokes: boolean)
|
||||||
if type(b) ~= "buffer" then return end
|
if type(b) ~= "buffer" then
|
||||||
|
return
|
||||||
|
end
|
||||||
local contents = Buffer.readEvents(b, ref, eventSchemas)
|
local contents = Buffer.readEvents(b, ref, eventSchemas)
|
||||||
for _, content in contents do
|
for _, content in contents do
|
||||||
local remote = content[1]
|
local remote = content[1]
|
||||||
local content = content[2]
|
local content = content[2]
|
||||||
|
if handleInvokes then
|
||||||
if remote == "\1" then
|
if remote == "\1" then
|
||||||
local id = content[1]
|
local id = content[1]
|
||||||
local results = content[2]
|
local results = content[2]
|
||||||
|
|
@ -126,8 +131,10 @@ if RunService:IsClient() then
|
||||||
end
|
end
|
||||||
continue
|
continue
|
||||||
end
|
end
|
||||||
if #eventListeners == 0 then continue end
|
|
||||||
if remote == "\0" then
|
if remote == "\0" then
|
||||||
|
if #eventListeners == 0 then
|
||||||
|
continue
|
||||||
|
end
|
||||||
local remoteName = content[1]
|
local remoteName = content[1]
|
||||||
local id = content[2]
|
local id = content[2]
|
||||||
local args = content[3]
|
local args = content[3]
|
||||||
|
|
@ -137,7 +144,7 @@ if RunService:IsClient() then
|
||||||
local results = { connection.fn(table.unpack(args)) }
|
local results = { connection.fn(table.unpack(args)) }
|
||||||
table.insert(queueEvent, {
|
table.insert(queueEvent, {
|
||||||
"\1",
|
"\1",
|
||||||
{ id, results } :: any
|
{ id, results } :: any,
|
||||||
})
|
})
|
||||||
end)
|
end)
|
||||||
break
|
break
|
||||||
|
|
@ -145,17 +152,36 @@ if RunService:IsClient() then
|
||||||
end
|
end
|
||||||
continue
|
continue
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
if #eventListeners == 0 then
|
||||||
|
continue
|
||||||
|
end
|
||||||
for _, connection in eventListeners do
|
for _, connection in eventListeners do
|
||||||
if connection.remote ~= remote then continue end
|
if connection.remote ~= remote then
|
||||||
|
continue
|
||||||
|
end
|
||||||
Thread(connection.fn, table.unpack(content))
|
Thread(connection.fn, table.unpack(content))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
Event.OnClientEvent:Connect(function(b: buffer, ref: { Instance }?)
|
||||||
|
processIncoming(b, ref, true)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
UnreliableEvent.OnClientEvent:Connect(function(b: buffer, ref: { Instance }?)
|
||||||
|
processIncoming(b, ref, false)
|
||||||
|
end)
|
||||||
|
|
||||||
RunService.PostSimulation:Connect(function(d: number)
|
RunService.PostSimulation:Connect(function(d: number)
|
||||||
deltaT += d
|
deltaT += d
|
||||||
if deltaT < cycle then return end
|
if deltaT < cycle then
|
||||||
|
return
|
||||||
|
end
|
||||||
deltaT = 0
|
deltaT = 0
|
||||||
if #queueEvent == 0 then return end
|
|
||||||
|
-- reliable
|
||||||
|
if #queueEvent > 0 then
|
||||||
Buffer.writeEvents(writer, queueEvent, eventSchemas)
|
Buffer.writeEvents(writer, queueEvent, eventSchemas)
|
||||||
do
|
do
|
||||||
local buf, ref = Buffer.buildWithRefs(writer)
|
local buf, ref = Buffer.buildWithRefs(writer)
|
||||||
|
|
@ -167,6 +193,21 @@ if RunService:IsClient() then
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
table.clear(queueEvent)
|
table.clear(queueEvent)
|
||||||
|
end
|
||||||
|
-- unreliable
|
||||||
|
if #queueUnreliableEvent > 0 then
|
||||||
|
Buffer.writeEvents(writer, queueUnreliableEvent, eventSchemas)
|
||||||
|
do
|
||||||
|
local buf, ref = Buffer.buildWithRefs(writer)
|
||||||
|
Buffer.reset(writer)
|
||||||
|
if not ref or #ref == 0 then
|
||||||
|
UnreliableEvent:FireServer(buf)
|
||||||
|
else
|
||||||
|
UnreliableEvent:FireServer(buf, ref)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
table.clear(queueUnreliableEvent)
|
||||||
|
end
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ local RunService = game:GetService("RunService")
|
||||||
local Thread = require("./Thread")
|
local Thread = require("./Thread")
|
||||||
local Buffer = require("./Buffer")
|
local Buffer = require("./Buffer")
|
||||||
local Event: RemoteEvent = script.Parent:WaitForChild("Event")
|
local Event: RemoteEvent = script.Parent:WaitForChild("Event")
|
||||||
local Function: RemoteFunction = script.Parent:WaitForChild("Function")
|
local UnreliableEvent: UnreliableRemoteEvent = script.Parent:WaitForChild("UnreliableEvent")
|
||||||
local deltaT: number, cycle: number = 0, 1 / 61
|
local deltaT: number, cycle: number = 0, 1 / 61
|
||||||
local writer: Buffer.Writer = Buffer.createWriter()
|
local writer: Buffer.Writer = Buffer.createWriter()
|
||||||
|
|
||||||
|
|
@ -18,12 +18,15 @@ type Connection = {
|
||||||
}
|
}
|
||||||
type Event = {
|
type Event = {
|
||||||
remote: string,
|
remote: string,
|
||||||
fn: (Player, ...any?) -> (...any?),
|
fn: (Player, ...any?) -> ...any?,
|
||||||
}
|
}
|
||||||
|
|
||||||
local queueEvent: {
|
local queueEvent: {
|
||||||
[Player]: { { any } },
|
[Player]: { { any } },
|
||||||
} = {}
|
} = {}
|
||||||
|
local queueUnreliableEvent: {
|
||||||
|
[Player]: { { any } },
|
||||||
|
} = {}
|
||||||
local eventListeners: { Event } = {}
|
local eventListeners: { Event } = {}
|
||||||
local eventSchemas: { [string]: Buffer.SchemaType } = {}
|
local eventSchemas: { [string]: Buffer.SchemaType } = {}
|
||||||
local players_ready: { Player } = {}
|
local players_ready: { Player } = {}
|
||||||
|
|
@ -35,7 +38,7 @@ Server.useSchema = function(remoteName: string, schema: Buffer.SchemaType)
|
||||||
eventSchemas[remoteName] = schema
|
eventSchemas[remoteName] = schema
|
||||||
end
|
end
|
||||||
|
|
||||||
Server.Connect = function(remoteName: string, fn: (Player, ...any?) -> (...any?)): Connection
|
Server.Connect = function(remoteName: string, fn: (Player, ...any?) -> ...any?): Connection
|
||||||
local detail = {
|
local detail = {
|
||||||
remote = remoteName,
|
remote = remoteName,
|
||||||
fn = fn,
|
fn = fn,
|
||||||
|
|
@ -44,7 +47,9 @@ Server.Connect = function(remoteName: string, fn: (Player, ...any?) -> (...any?)
|
||||||
return {
|
return {
|
||||||
Connected = true,
|
Connected = true,
|
||||||
Disconnect = function(self: Connection)
|
Disconnect = function(self: Connection)
|
||||||
if not self.Connected then return end
|
if not self.Connected then
|
||||||
|
return
|
||||||
|
end
|
||||||
self.Connected = false
|
self.Connected = false
|
||||||
local idx = table.find(eventListeners, detail)
|
local idx = table.find(eventListeners, detail)
|
||||||
if idx then
|
if idx then
|
||||||
|
|
@ -86,12 +91,13 @@ Server.Destroy = function(remoteName: string)
|
||||||
end
|
end
|
||||||
|
|
||||||
Server.Fire = function(remoteName: string, reliable: boolean, player: Player, ...: any?)
|
Server.Fire = function(remoteName: string, reliable: boolean, player: Player, ...: any?)
|
||||||
if not queueEvent[player] then
|
local targetQueue = reliable and queueEvent or queueUnreliableEvent
|
||||||
queueEvent[player] = {} :: any
|
if not targetQueue[player] then
|
||||||
|
targetQueue[player] = {} :: any
|
||||||
end
|
end
|
||||||
table.insert(queueEvent[player], {
|
table.insert(targetQueue[player], {
|
||||||
remoteName,
|
remoteName,
|
||||||
{ ... } :: any
|
{ ... } :: any,
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -114,21 +120,26 @@ Server.Invoke = function(remoteName: string, player: Player, timeout: number?, .
|
||||||
task.spawn(pending, nil)
|
task.spawn(pending, nil)
|
||||||
pendingInvokes[id] = nil
|
pendingInvokes[id] = nil
|
||||||
end)
|
end)
|
||||||
|
if not queueEvent[player] then
|
||||||
|
queueEvent[player] = {} :: any
|
||||||
|
end
|
||||||
table.insert(queueEvent[player], {
|
table.insert(queueEvent[player], {
|
||||||
"\0",
|
"\0",
|
||||||
{ remoteName, id, { ... } :: any } :: any
|
{ remoteName, id, { ... } :: any } :: any,
|
||||||
})
|
})
|
||||||
return coroutine.yield()
|
return coroutine.yield()
|
||||||
end
|
end
|
||||||
|
|
||||||
if RunService:IsServer() then
|
if RunService:IsServer() then
|
||||||
Event.OnServerEvent:Connect(function(player: Player, b: buffer, ref: { Instance? })
|
local function processIncoming(player: Player, b: buffer, ref: { Instance }?, handleInvokes: boolean)
|
||||||
if type(b) ~= "buffer" then return end
|
if type(b) ~= "buffer" then
|
||||||
|
return
|
||||||
|
end
|
||||||
local contents = Buffer.readEvents(b, ref, eventSchemas)
|
local contents = Buffer.readEvents(b, ref, eventSchemas)
|
||||||
for _, content in contents do
|
for _, content in contents do
|
||||||
local remote = content[1]
|
local remote = content[1]
|
||||||
local content = content[2]
|
local content = content[2]
|
||||||
|
if handleInvokes then
|
||||||
if remote == "\1" then
|
if remote == "\1" then
|
||||||
local id = content[1]
|
local id = content[1]
|
||||||
local results = content[2]
|
local results = content[2]
|
||||||
|
|
@ -139,8 +150,10 @@ if RunService:IsServer() then
|
||||||
end
|
end
|
||||||
continue
|
continue
|
||||||
end
|
end
|
||||||
if #eventListeners == 0 then continue end
|
|
||||||
if remote == "\0" then
|
if remote == "\0" then
|
||||||
|
if #eventListeners == 0 then
|
||||||
|
continue
|
||||||
|
end
|
||||||
local remoteName = content[1]
|
local remoteName = content[1]
|
||||||
local id = content[2]
|
local id = content[2]
|
||||||
local args = content[3]
|
local args = content[3]
|
||||||
|
|
@ -148,9 +161,12 @@ if RunService:IsServer() then
|
||||||
if connection.remote == remoteName then
|
if connection.remote == remoteName then
|
||||||
Thread(function()
|
Thread(function()
|
||||||
local results = { connection.fn(table.unpack(args)) }
|
local results = { connection.fn(table.unpack(args)) }
|
||||||
|
if not queueEvent[player] then
|
||||||
|
queueEvent[player] = {} :: any
|
||||||
|
end
|
||||||
table.insert(queueEvent[player], {
|
table.insert(queueEvent[player], {
|
||||||
"\1",
|
"\1",
|
||||||
{ id, results } :: any
|
{ id, results } :: any,
|
||||||
})
|
})
|
||||||
end)
|
end)
|
||||||
break
|
break
|
||||||
|
|
@ -158,18 +174,39 @@ if RunService:IsServer() then
|
||||||
end
|
end
|
||||||
continue
|
continue
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
if #eventListeners == 0 then
|
||||||
|
continue
|
||||||
|
end
|
||||||
for _, connection in eventListeners do
|
for _, connection in eventListeners do
|
||||||
if connection.remote ~= remote then continue end
|
if connection.remote ~= remote then
|
||||||
|
continue
|
||||||
|
end
|
||||||
Thread(connection.fn, player, table.unpack(content))
|
Thread(connection.fn, player, table.unpack(content))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
Event.OnServerEvent:Connect(function(player: Player, b: buffer, ref: { Instance }?)
|
||||||
|
processIncoming(player, b, ref, true)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
UnreliableEvent.OnServerEvent:Connect(function(player: Player, b: buffer, ref: { Instance }?)
|
||||||
|
processIncoming(player, b, ref, false)
|
||||||
|
end)
|
||||||
|
|
||||||
RunService.PostSimulation:Connect(function(d: number)
|
RunService.PostSimulation:Connect(function(d: number)
|
||||||
deltaT += d
|
deltaT += d
|
||||||
if deltaT < cycle then return end
|
if deltaT < cycle then
|
||||||
|
return
|
||||||
|
end
|
||||||
deltaT = 0
|
deltaT = 0
|
||||||
|
|
||||||
|
-- reliable
|
||||||
for player: Player, content in queueEvent do
|
for player: Player, content in queueEvent do
|
||||||
if #content == 0 or player.Parent ~= Players then continue end
|
if #content == 0 or player.Parent ~= Players then
|
||||||
|
continue
|
||||||
|
end
|
||||||
Buffer.writeEvents(writer, content, eventSchemas)
|
Buffer.writeEvents(writer, content, eventSchemas)
|
||||||
do
|
do
|
||||||
local buf, ref = Buffer.buildWithRefs(writer)
|
local buf, ref = Buffer.buildWithRefs(writer)
|
||||||
|
|
@ -182,7 +219,25 @@ if RunService:IsServer() then
|
||||||
end
|
end
|
||||||
table.clear(queueEvent[player])
|
table.clear(queueEvent[player])
|
||||||
end
|
end
|
||||||
|
-- unreliable
|
||||||
|
for player: Player, content in queueUnreliableEvent do
|
||||||
|
if #content == 0 or player.Parent ~= Players then
|
||||||
|
continue
|
||||||
|
end
|
||||||
|
Buffer.writeEvents(writer, content, eventSchemas)
|
||||||
|
do
|
||||||
|
local buf, ref = Buffer.buildWithRefs(writer)
|
||||||
|
Buffer.reset(writer)
|
||||||
|
if not ref or #ref == 0 then
|
||||||
|
UnreliableEvent:FireClient(player, buf)
|
||||||
|
else
|
||||||
|
UnreliableEvent:FireClient(player, buf, ref)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
table.clear(queueUnreliableEvent[player])
|
||||||
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
local function onAdded(player: Player)
|
local function onAdded(player: Player)
|
||||||
if not table.find(players_ready, player) then
|
if not table.find(players_ready, player) then
|
||||||
table.insert(players_ready, player)
|
table.insert(players_ready, player)
|
||||||
|
|
@ -190,6 +245,9 @@ if RunService:IsServer() then
|
||||||
if not queueEvent[player] then
|
if not queueEvent[player] then
|
||||||
queueEvent[player] = {} :: any
|
queueEvent[player] = {} :: any
|
||||||
end
|
end
|
||||||
|
if not queueUnreliableEvent[player] then
|
||||||
|
queueUnreliableEvent[player] = {} :: any
|
||||||
|
end
|
||||||
end
|
end
|
||||||
Players.PlayerAdded:Connect(onAdded)
|
Players.PlayerAdded:Connect(onAdded)
|
||||||
Players.PlayerRemoving:Connect(function(player: Player)
|
Players.PlayerRemoving:Connect(function(player: Player)
|
||||||
|
|
@ -198,6 +256,10 @@ if RunService:IsServer() then
|
||||||
table.clear(queueEvent[player])
|
table.clear(queueEvent[player])
|
||||||
queueEvent[player] = nil
|
queueEvent[player] = nil
|
||||||
end
|
end
|
||||||
|
if queueUnreliableEvent[player] then
|
||||||
|
table.clear(queueUnreliableEvent[player])
|
||||||
|
queueUnreliableEvent[player] = nil
|
||||||
|
end
|
||||||
end)
|
end)
|
||||||
for _, player: Player in ipairs(Players:GetPlayers()) do
|
for _, player: Player in ipairs(Players:GetPlayers()) do
|
||||||
onAdded(player)
|
onAdded(player)
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,9 @@ if game.RunService:IsServer() then
|
||||||
if not script:FindFirstChild("Event") then
|
if not script:FindFirstChild("Event") then
|
||||||
Instance.new("RemoteEvent", script).Name = "Event"
|
Instance.new("RemoteEvent", script).Name = "Event"
|
||||||
end
|
end
|
||||||
|
if not script:FindFirstChild("UnreliableEvent") then
|
||||||
|
Instance.new("UnreliableRemoteEvent", script).Name = "UnreliableEvent"
|
||||||
|
end
|
||||||
if not script:FindFirstChild("Function") then
|
if not script:FindFirstChild("Function") then
|
||||||
Instance.new("RemoteFunction", script).Name = "Function"
|
Instance.new("RemoteFunction", script).Name = "Function"
|
||||||
end
|
end
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue