155 lines
5.0 KiB
Lua
155 lines
5.0 KiB
Lua
table.unpack = table.unpack or unpack
|
|
string.pack = function(...) return love.data.pack("string", ...) end
|
|
string.unpack = love.data.unpack
|
|
string.packsize = string.packsize or love.data.getPackedSize
|
|
|
|
-- Lua data types: nil, boolean, number, string, function, userdata, thread, and table.
|
|
-- Not representable here: function, userdata, thread.
|
|
format = {
|
|
--[[ Poppy specific
|
|
0x81 = "remoteCall",
|
|
-- lua specific
|
|
0x02 = "shortString",
|
|
0x03 = "longString",
|
|
0x04 = "nil",
|
|
0x05 = "true",
|
|
0x06 = "false",
|
|
0x07 = "number",
|
|
-- love2d/poppy specific
|
|
0x48 = "colorAlpha",
|
|
0x49 = "color"]]--
|
|
}
|
|
format.decodeFunction = function(encoded, index)
|
|
local nameLength, index = string.unpack("<I1", encoded, index)
|
|
local name, index = string.unpack("<c".. nameLength, encoded, index)
|
|
if name == "init" then DEBUG = true end
|
|
local argNumber, index = string.unpack("<I1", encoded, index)
|
|
local clientID, index = string.unpack("<I2", encoded, index)
|
|
local arguments = {}
|
|
for i = 1, argNumber do
|
|
local argtype = ""
|
|
argType, index = string.unpack("<I1", encoded, index)
|
|
if argType == 0x02 then
|
|
local stringLength, nwString
|
|
stringLength, index = string.unpack("<I1", encoded, index)
|
|
nwString, index = string.unpack("<c"..stringLength, encoded, index)
|
|
arguments[i] = nwString
|
|
elseif argType == 0x03 then
|
|
local stringLength, nwString
|
|
stringLength, index = string.unpack("<I2", encoded, index)
|
|
nwString, index = string.unpack("<c"..stringLength, encoded, index)
|
|
arguments[i] = string
|
|
elseif argType == 0x04 then
|
|
arguments[i] = nil
|
|
elseif argType == 0x05 then
|
|
arguments[i] = true
|
|
elseif argType == 0x06 then
|
|
arguments[i] = false
|
|
elseif argType == 0x07 then
|
|
local number
|
|
number, index = string.unpack("<n", encoded, index)
|
|
arguments[i] = number
|
|
elseif argType == 0x48 then
|
|
local color = {}
|
|
color[1], color[2], color[3], color[4], index = string.unpack("<ffff", encoded, index)
|
|
arguments[i] = color
|
|
elseif argType == 0x49 then
|
|
local color = {nwType = "color"}
|
|
color[1], color[2], color[3], index = string.unpack("<fff", encoded, index)
|
|
arguments[i] = color
|
|
else
|
|
error("failed to decode argument " .. i .. " index is at " ..index.. " len is " .. encoded:len() .. "value is " .. argType)
|
|
end
|
|
end
|
|
return name, clientID, arguments
|
|
end
|
|
|
|
|
|
|
|
format.encodeFunction = function(name, clientID, ...)
|
|
assert(name and clientID)
|
|
-- Format
|
|
-- byte1 0x81 to indicate a function
|
|
-- byte2 length of the name of the function
|
|
-- byte3-byteN name of the function
|
|
-- byteN+1 number of arguments to the function
|
|
-- byteN+2 type of argument
|
|
-- byteN+3-byteM argument specific syntax
|
|
-- byteM+1 type of next argument
|
|
-- and so on
|
|
local encoded = "\x81"
|
|
encoded = encoded .. string.pack("<I1", name:len())
|
|
encoded = encoded .. name .. string.pack("<I1", select("#", ...))
|
|
-- can't use ipairs, it does stop on nil
|
|
-- can't use pairs, it ignores nil :D
|
|
encoded = encoded .. string.pack("<I2", clientID)
|
|
local args = { ... }
|
|
for i=1, select("#", ...) do
|
|
local value = args[i]
|
|
if type(value) == "function" or type(value) == "CFunction" or type(value) == "userdata"
|
|
or type(value) == "thread" then
|
|
error("unencodeable data passed! of type: " .. type(value))
|
|
elseif type(value) == "nil" then
|
|
encoded = encoded .. "\x04"
|
|
elseif type(value) == "boolean" then
|
|
if value then
|
|
encoded = encoded .. "\x05"
|
|
else
|
|
encoded = encoded .. "\x06"
|
|
end
|
|
elseif type(value) == "string" then
|
|
if value:len() > 255 then
|
|
encoded = encoded .. "\x03" .. string.pack("<I2", value:len()) .. value
|
|
else
|
|
encoded = encoded .. "\x02" .. string.pack("<I1", value:len()) .. value
|
|
end
|
|
elseif type(value) == "number" then
|
|
encoded = encoded .. "\x07" .. string.pack("<n", value)
|
|
elseif type(value) == "table" then
|
|
if value.nwType == "color" and #value == 3 then
|
|
encoded = encoded .. "\x49" .. string.pack("<fff", value[1], value[2], value[3])
|
|
elseif value.nwType == "color" and #value == 4 then
|
|
encoded = encoded .. "\x48" ..
|
|
string.pack("<ffff", value[1], value[2], value[3], value[4])
|
|
else
|
|
error("Got table but don't know how to encode it")
|
|
end
|
|
else
|
|
error("unimplemented type for encoding!")
|
|
end
|
|
end
|
|
|
|
return encoded
|
|
end
|
|
|
|
|
|
function format.testEncoder()
|
|
local testCases = {
|
|
Jeremeeeey = { true, true, nil, false, 69, "Jeremy stop that >:(" },
|
|
buildBlocks = { 32, 32, 64, 64, "longHashValueISwear" },
|
|
colorWorld = { {nwType = "color", 0.4, 0.4, 0.4 }, {nwType = "color", 0.4, 0.4, 0.4, 0.5}},
|
|
slangvariants = { "oy mate", "how ya doing", "sup brooo", "heya", "hey there ma dude" }
|
|
}
|
|
print("Running encoder tests...")
|
|
|
|
for name, value in pairs(testCases) do
|
|
local encoded = format.encodeFunction(name, 3, table.unpack(value))
|
|
local name, _, decodedArgs = format.decodeFunction(encoded)
|
|
|
|
local sucess = true
|
|
for iter= 1, #value do
|
|
local var = value[iter]
|
|
if var ~= decodedArgs[iter] and not type(var) == table then
|
|
sucess = false
|
|
end
|
|
end
|
|
if sucess then
|
|
print(name .. " suceeded!")
|
|
else
|
|
print(name .. " failed.")
|
|
end
|
|
end
|
|
end
|
|
|
|
return format
|