This commit is contained in:
lifestorm
2024-08-04 23:12:27 +03:00
parent 8064ba84d8
commit 9c918c46e5
7081 changed files with 2173485 additions and 14 deletions

View File

@@ -0,0 +1,30 @@
lua-MessagePack License
--------------------------
lua-MessagePack is licensed under the terms of the MIT/X11 license reproduced below.
===============================================================================
Copyright (C) 2012-2019 Francois Perrad.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
===============================================================================
(end of COPYRIGHT)

View File

@@ -0,0 +1,874 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
if SAM_LOADED then return end
--
-- lua-MessagePack : <https://fperrad.frama.io/lua-MessagePack/>
--
local SIZEOF_NUMBER = string.pack and #string.pack('n', 0.0) or 8
local maxinteger
local mininteger
local assert = assert
local error = error
local pairs = pairs
local pcall = pcall
local setmetatable = setmetatable
local tostring = tostring
local char = string.char
local format = string.format
local floor = math.floor
local tointeger = floor
local frexp = math.frexp
local ldexp = math.ldexp
local huge = math.huge
local tconcat = table.concat
local type = sam.type
local isnumber = sam.isnumber
local _ENV = nil
local m = {}
--[[ debug only
local function hexadump (s)
return (s:gsub('.', function (c) return format('%02X ', c:byte()) end))
end
m.hexadump = hexadump
--]]
local function argerror(caller, narg, extramsg)
error("bad argument #" .. tostring(narg) .. " to " .. caller .. " (" .. extramsg .. ")")
end
local function typeerror(caller, narg, arg, tname)
argerror(caller, narg, tname .. " expected, got " .. type(arg))
end
local function checktype(caller, narg, arg, tname)
if type(arg) ~= tname then
typeerror(caller, narg, arg, tname)
end
end
local packers = setmetatable({}, {
__index = function(t, k)
if k == 1 then return end -- allows ipairs
error("pack '" .. k .. "' is unimplemented")
end
})
m.packers = packers
packers["nil"] = function(buffer)
buffer[#buffer + 1] = char(0xC0) -- nil
end
packers["boolean"] = function(buffer, bool)
if bool then
buffer[#buffer + 1] = char(0xC3) -- true
else
buffer[#buffer + 1] = char(0xC2) -- false
end
end
packers["string_compat"] = function(buffer, str)
local n = #str
if n <= 0x1F then
buffer[#buffer + 1] = char(0xA0 + n) -- fixstr
elseif n <= 0xFFFF then
buffer[#buffer + 1] = char(0xDA, floor(n / 0x100), n % 0x100) -- str16
elseif n <= 4294967295.0 then
buffer[#buffer + 1] = char(0xDB, floor(n / 0x1000000), floor(n / 0x10000) % 0x100, floor(n / 0x100) % 0x100, n % 0x100) -- str32
else
error"overflow in pack 'string_compat'"
end
buffer[#buffer + 1] = str
end
packers["_string"] = function(buffer, str)
local n = #str
if n <= 0x1F then
buffer[#buffer + 1] = char(0xA0 + n) -- fixstr
elseif n <= 0xFF then
buffer[#buffer + 1] = char(0xD9, n) -- str8
elseif n <= 0xFFFF then
buffer[#buffer + 1] = char(0xDA, floor(n / 0x100), n % 0x100) -- str16
elseif n <= 4294967295.0 then
buffer[#buffer + 1] = char(0xDB, floor(n / 0x1000000), floor(n / 0x10000) % 0x100, floor(n / 0x100) % 0x100, n % 0x100) -- str32
else
error("overflow in pack 'string'")
end
buffer[#buffer + 1] = str
end
packers["binary"] = function(buffer, str)
local n = #str
if n <= 0xFF then
buffer[#buffer + 1] = char(0xC4, n) -- bin8
elseif n <= 0xFFFF then
buffer[#buffer + 1] = char(0xC5, floor(n / 0x100), n % 0x100) -- bin16
elseif n <= 4294967295.0 then
buffer[#buffer + 1] = char(0xC6, floor(n / 0x1000000), floor(n / 0x10000) % 0x100, floor(n / 0x100) % 0x100, n % 0x100) -- bin32
else
error("overflow in pack 'binary'")
end
buffer[#buffer + 1] = str
end
local set_string = function(str)
if str == "string_compat" then
packers["string"] = packers["string_compat"]
elseif str == "string" then
packers["string"] = packers["_string"]
elseif str == "binary" then
packers["string"] = packers["binary"]
else
argerror("set_string", 1, "invalid option '" .. str .. "'")
end
end
m.set_string = set_string
packers["map"] = function(buffer, tbl, n)
if n <= 0x0F then
buffer[#buffer + 1] = char(0x80 + n) -- fixmap
elseif n <= 0xFFFF then
buffer[#buffer + 1] = char(0xDE, floor(n / 0x100), n % 0x100) -- map16
elseif n <= 4294967295.0 then
buffer[#buffer + 1] = char(0xDF, floor(n / 0x1000000), floor(n / 0x10000) % 0x100, floor(n / 0x100) % 0x100, n % 0x100) -- map32
else
error("overflow in pack 'map'")
end
for k, v in pairs(tbl) do
packers[type(k)](buffer, k)
packers[type(v)](buffer, v)
end
end
packers["array"] = function(buffer, tbl, n)
if n <= 0x0F then
buffer[#buffer + 1] = char(0x90 + n) -- fixarray
elseif n <= 0xFFFF then
buffer[#buffer + 1] = char(0xDC, floor(n / 0x100), n % 0x100) -- array16
elseif n <= 4294967295.0 then
buffer[#buffer + 1] = char(0xDD, floor(n / 0x1000000), floor(n / 0x10000) % 0x100, floor(n / 0x100) % 0x100, n % 0x100) -- array32
else
error("overflow in pack 'array'")
end
for i = 1, n do
local v = tbl[i]
packers[type(v)](buffer, v)
end
end
local set_array = function(array)
if array == "without_hole" then
packers["_table"] = function(buffer, tbl)
local is_map, n, max = false, 0, 0
for k in pairs(tbl) do
if isnumber(k) and k > 0 then
if k > max then
max = k
end
else
is_map = true
end
n = n + 1
end
-- there are holes
if max ~= n then
is_map = true
end
if is_map then
packers["map"](buffer, tbl, n)
else
packers["array"](buffer, tbl, n)
end
end
elseif array == "with_hole" then
packers["_table"] = function(buffer, tbl)
local is_map, n, max = false, 0, 0
for k in pairs(tbl) do
if isnumber(k) and k > 0 then
if k > max then
max = k
end
else
is_map = true
end
n = n + 1
end
if is_map then
packers["map"](buffer, tbl, n)
else
packers["array"](buffer, tbl, max)
end
end
elseif array == "always_as_map" then
packers["_table"] = function(buffer, tbl)
local n = 0
for k in pairs(tbl) do
n = n + 1
end
packers["map"](buffer, tbl, n)
end
else
argerror("set_array", 1, "invalid option '" .. array .. "'")
end
end
m.set_array = set_array
packers["table"] = function(buffer, tbl)
packers["_table"](buffer, tbl)
end
packers["unsigned"] = function(buffer, n)
if n >= 0 then
if n <= 0x7F then
buffer[#buffer + 1] = char(n) -- fixnum_pos
elseif n <= 0xFF then
buffer[#buffer + 1] = char(0xCC, n) -- uint8
elseif n <= 0xFFFF then
buffer[#buffer + 1] = char(0xCD, floor(n / 0x100), n % 0x100) -- uint16
elseif n <= 4294967295.0 then
buffer[#buffer + 1] = char(0xCE, floor(n / 0x1000000), floor(n / 0x10000) % 0x100, floor(n / 0x100) % 0x100, n % 0x100) -- uint32
else
buffer[#buffer + 1] = char(0xCF, 0, floor(n / 0x1000000000000) % 0x100, floor(n / 0x10000000000) % 0x100, floor(n / 0x100000000) % 0x100, floor(n / 0x1000000) % 0x100, floor(n / 0x10000) % 0x100, floor(n / 0x100) % 0x100, n % 0x100) -- uint64 -- only 53 bits from double
end
else
if n >= -0x20 then
buffer[#buffer + 1] = char(0x100 + n) -- fixnum_neg
elseif n >= -0x80 then
buffer[#buffer + 1] = char(0xD0, 0x100 + n) -- int8
elseif n >= -0x8000 then
n = 0x10000 + n
buffer[#buffer + 1] = char(0xD1, floor(n / 0x100), n % 0x100) -- int16
elseif n >= -0x80000000 then
n = 4294967296.0 + n
buffer[#buffer + 1] = char(0xD2, floor(n / 0x1000000), floor(n / 0x10000) % 0x100, floor(n / 0x100) % 0x100, n % 0x100) -- int32
else
buffer[#buffer + 1] = char(0xD3, 0xFF, floor(n / 0x1000000000000) % 0x100, floor(n / 0x10000000000) % 0x100, floor(n / 0x100000000) % 0x100, floor(n / 0x1000000) % 0x100, floor(n / 0x10000) % 0x100, floor(n / 0x100) % 0x100, n % 0x100) -- int64 -- only 53 bits from double
end
end
end
packers["signed"] = function(buffer, n)
if n >= 0 then
if n <= 0x7F then
buffer[#buffer + 1] = char(n) -- fixnum_pos
elseif n <= 0x7FFF then
buffer[#buffer + 1] = char(0xD1, floor(n / 0x100), n % 0x100) -- int16
elseif n <= 0x7FFFFFFF then
buffer[#buffer + 1] = char(0xD2, floor(n / 0x1000000), floor(n / 0x10000) % 0x100, floor(n / 0x100) % 0x100, n % 0x100) -- int32
else
buffer[#buffer + 1] = char(0xD3, 0, floor(n / 0x1000000000000) % 0x100, floor(n / 0x10000000000) % 0x100, floor(n / 0x100000000) % 0x100, floor(n / 0x1000000) % 0x100, floor(n / 0x10000) % 0x100, floor(n / 0x100) % 0x100, n % 0x100) -- int64 -- only 53 bits from double
end
else
if n >= -0x20 then
buffer[#buffer + 1] = char(0xE0 + 0x20 + n) -- fixnum_neg
elseif n >= -0x80 then
buffer[#buffer + 1] = char(0xD0, 0x100 + n) -- int8
elseif n >= -0x8000 then
n = 0x10000 + n
buffer[#buffer + 1] = char(0xD1, floor(n / 0x100), n % 0x100) -- int16
elseif n >= -0x80000000 then
n = 4294967296.0 + n
buffer[#buffer + 1] = char(0xD2, floor(n / 0x1000000), floor(n / 0x10000) % 0x100, floor(n / 0x100) % 0x100, n % 0x100) -- int32
else
buffer[#buffer + 1] = char(0xD3, 0xFF, floor(n / 0x1000000000000) % 0x100, floor(n / 0x10000000000) % 0x100, floor(n / 0x100000000) % 0x100, floor(n / 0x1000000) % 0x100, floor(n / 0x10000) % 0x100, floor(n / 0x100) % 0x100, n % 0x100) -- int64 -- only 53 bits from double
end
end
end
local set_integer = function(integer)
if integer == "unsigned" then
packers["integer"] = packers["unsigned"]
elseif integer == "signed" then
packers["integer"] = packers["signed"]
else
argerror("set_integer", 1, "invalid option '" .. integer .. "'")
end
end
m.set_integer = set_integer
packers["float"] = function(buffer, n)
local sign = 0
if n < 0.0 then
sign = 0x80
n = -n
end
local mant, expo = frexp(n)
if mant ~= mant then
buffer[#buffer + 1] = char(0xCA, 0xFF, 0x88, 0x00, 0x00) -- nan
elseif mant == huge or expo > 0x80 then
if sign == 0 then
buffer[#buffer + 1] = char(0xCA, 0x7F, 0x80, 0x00, 0x00) -- inf
else
buffer[#buffer + 1] = char(0xCA, 0xFF, 0x80, 0x00, 0x00) -- -inf
end
elseif (mant == 0.0 and expo == 0) or expo < -0x7E then
buffer[#buffer + 1] = char(0xCA, sign, 0x00, 0x00, 0x00) -- zero
else
expo = expo + 0x7E
mant = floor((mant * 2.0 - 1.0) * ldexp(0.5, 24))
buffer[#buffer + 1] = char(0xCA, sign + floor(expo / 0x2), (expo % 0x2) * 0x80 + floor(mant / 0x10000), floor(mant / 0x100) % 0x100, mant % 0x100)
end
end
packers["double"] = function(buffer, n)
local sign = 0
if n < 0.0 then
sign = 0x80
n = -n
end
local mant, expo = frexp(n)
if mant ~= mant then
buffer[#buffer + 1] = char(0xCB, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00) -- nan
elseif mant == huge or expo > 0x400 then
if sign == 0 then
buffer[#buffer + 1] = char(0xCB, 0x7F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00) -- inf
else
buffer[#buffer + 1] = char(0xCB, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00) -- -inf
end
elseif (mant == 0.0 and expo == 0) or expo < -0x3FE then
buffer[#buffer + 1] = char(0xCB, sign, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00) -- zero
else
expo = expo + 0x3FE
mant = floor((mant * 2.0 - 1.0) * ldexp(0.5, 53))
buffer[#buffer + 1] = char(0xCB, sign + floor(expo / 0x10), (expo % 0x10) * 0x10 + floor(mant / 0x1000000000000), floor(mant / 0x10000000000) % 0x100, floor(mant / 0x100000000) % 0x100, floor(mant / 0x1000000) % 0x100, floor(mant / 0x10000) % 0x100, floor(mant / 0x100) % 0x100, mant % 0x100)
end
end
local set_number = function(number)
if number == "float" then
packers["number"] = function(buffer, n)
if floor(n) == n and n < maxinteger and n > mininteger then
packers["integer"](buffer, n)
else
packers["float"](buffer, n)
end
end
elseif number == "double" then
packers["number"] = function(buffer, n)
if floor(n) == n and n < maxinteger and n > mininteger then
packers["integer"](buffer, n)
else
packers["double"](buffer, n)
end
end
else
argerror("set_number", 1, "invalid option '" .. number .. "'")
end
end
m.set_number = set_number
for k = 0, 4 do
local n = tointeger(2 ^ k)
local fixext = 0xD4 + k
packers["fixext" .. tostring(n)] = function(buffer, tag, data)
assert(#data == n, "bad length for fixext" .. tostring(n))
buffer[#buffer + 1] = char(fixext, tag < 0 and tag + 0x100 or tag)
buffer[#buffer + 1] = data
end
end
packers["ext"] = function(buffer, tag, data)
local n = #data
if n <= 0xFF then
buffer[#buffer + 1] = char(0xC7, n, tag < 0 and tag + 0x100 or tag) -- ext8
elseif n <= 0xFFFF then
buffer[#buffer + 1] = char(0xC8, floor(n / 0x100), n % 0x100, tag < 0 and tag + 0x100 or tag) -- ext16
elseif n <= 4294967295.0 then
buffer[#buffer + 1] = char(0xC9, floor(n / 0x1000000), floor(n / 0x10000) % 0x100, floor(n / 0x100) % 0x100, n % 0x100, tag < 0 and tag + 0x100 or tag) -- ext&32
else
error("overflow in pack 'ext'")
end
buffer[#buffer + 1] = data
end
function m.pack(data)
local buffer = {}
packers[type(data)](buffer, data)
return tconcat(buffer)
end
local unpackers -- forward declaration
local function unpack_cursor(c)
local s, i, j = c.s, c.i, c.j
if i > j then
c:underflow(i)
s, i, j = c.s, c.i, c.j
end
local val = s:byte(i)
c.i = i + 1
return unpackers[val](c, val)
end
m.unpack_cursor = unpack_cursor
local function unpack_str(c, n)
local s, i, j = c.s, c.i, c.j
local e = i + n - 1
if e > j or n < 0 then
c:underflow(e)
s, i, j = c.s, c.i, c.j
e = i + n - 1
end
c.i = i + n
return s:sub(i, e)
end
local function unpack_array(c, n)
local t = {}
for i = 1, n do
t[i] = unpack_cursor(c)
end
return t
end
local function unpack_map(c, n)
local t = {}
for i = 1, n do
local k = unpack_cursor(c)
local val = unpack_cursor(c)
if k == nil or k ~= k then
k = m.sentinel
end
if k ~= nil then
t[k] = val
end
end
return t
end
local function unpack_float(c)
local s, i, j = c.s, c.i, c.j
if i + 3 > j then
c:underflow(i + 3)
s, i, j = c.s, c.i, c.j
end
local b1, b2, b3, b4 = s:byte(i, i + 3)
local sign = b1 > 0x7F
local expo = (b1 % 0x80) * 0x2 + floor(b2 / 0x80)
local mant = ((b2 % 0x80) * 0x100 + b3) * 0x100 + b4
if sign then
sign = -1
else
sign = 1
end
local n
if mant == 0 and expo == 0 then
n = sign * 0.0
elseif expo == 0xFF then
if mant == 0 then
n = sign * huge
else
n = 0.0 / 0.0
end
else
n = sign * ldexp(1.0 + mant / 0x800000, expo - 0x7F)
end
c.i = i + 4
return n
end
local function unpack_double(c)
local s, i, j = c.s, c.i, c.j
if i + 7 > j then
c:underflow(i + 7)
s, i, j = c.s, c.i, c.j
end
local b1, b2, b3, b4, b5, b6, b7, b8 = s:byte(i, i + 7)
local sign = b1 > 0x7F
local expo = (b1 % 0x80) * 0x10 + floor(b2 / 0x10)
local mant = ((((((b2 % 0x10) * 0x100 + b3) * 0x100 + b4) * 0x100 + b5) * 0x100 + b6) * 0x100 + b7) * 0x100 + b8
if sign then
sign = -1
else
sign = 1
end
local n
if mant == 0 and expo == 0 then
n = sign * 0.0
elseif expo == 0x7FF then
if mant == 0 then
n = sign * huge
else
n = 0.0 / 0.0
end
else
n = sign * ldexp(1.0 + mant / 4503599627370496.0, expo - 0x3FF)
end
c.i = i + 8
return n
end
local function unpack_uint8(c)
local s, i, j = c.s, c.i, c.j
if i > j then
c:underflow(i)
s, i, j = c.s, c.i, c.j
end
local b1 = s:byte(i)
c.i = i + 1
return b1
end
local function unpack_uint16(c)
local s, i, j = c.s, c.i, c.j
if i + 1 > j then
c:underflow(i + 1)
s, i, j = c.s, c.i, c.j
end
local b1, b2 = s:byte(i, i + 1)
c.i = i + 2
return b1 * 0x100 + b2
end
local function unpack_uint32(c)
local s, i, j = c.s, c.i, c.j
if i + 3 > j then
c:underflow(i + 3)
s, i, j = c.s, c.i, c.j
end
local b1, b2, b3, b4 = s:byte(i, i + 3)
c.i = i + 4
return ((b1 * 0x100 + b2) * 0x100 + b3) * 0x100 + b4
end
local function unpack_uint64(c)
local s, i, j = c.s, c.i, c.j
if i + 7 > j then
c:underflow(i + 7)
s, i, j = c.s, c.i, c.j
end
local b1, b2, b3, b4, b5, b6, b7, b8 = s:byte(i, i + 7)
c.i = i + 8
return ((((((b1 * 0x100 + b2) * 0x100 + b3) * 0x100 + b4) * 0x100 + b5) * 0x100 + b6) * 0x100 + b7) * 0x100 + b8
end
local function unpack_int8(c)
local s, i, j = c.s, c.i, c.j
if i > j then
c:underflow(i)
s, i, j = c.s, c.i, c.j
end
local b1 = s:byte(i)
c.i = i + 1
if b1 < 0x80 then
return b1
else
return b1 - 0x100
end
end
local function unpack_int16(c)
local s, i, j = c.s, c.i, c.j
if i + 1 > j then
c:underflow(i + 1)
s, i, j = c.s, c.i, c.j
end
local b1, b2 = s:byte(i, i + 1)
c.i = i + 2
if b1 < 0x80 then
return b1 * 0x100 + b2
else
return ((b1 - 0xFF) * 0x100 + (b2 - 0xFF)) - 1
end
end
local function unpack_int32(c)
local s, i, j = c.s, c.i, c.j
if i + 3 > j then
c:underflow(i + 3)
s, i, j = c.s, c.i, c.j
end
local b1, b2, b3, b4 = s:byte(i, i + 3)
c.i = i + 4
if b1 < 0x80 then
return ((b1 * 0x100 + b2) * 0x100 + b3) * 0x100 + b4
else
return ((((b1 - 0xFF) * 0x100 + (b2 - 0xFF)) * 0x100 + (b3 - 0xFF)) * 0x100 + (b4 - 0xFF)) - 1
end
end
local function unpack_int64(c)
local s, i, j = c.s, c.i, c.j
if i + 7 > j then
c:underflow(i + 7)
s, i, j = c.s, c.i, c.j
end
local b1, b2, b3, b4, b5, b6, b7, b8 = s:byte(i, i + 7)
c.i = i + 8
if b1 < 0x80 then
return ((((((b1 * 0x100 + b2) * 0x100 + b3) * 0x100 + b4) * 0x100 + b5) * 0x100 + b6) * 0x100 + b7) * 0x100 + b8
else
return ((((((((b1 - 0xFF) * 0x100 + (b2 - 0xFF)) * 0x100 + (b3 - 0xFF)) * 0x100 + (b4 - 0xFF)) * 0x100 + (b5 - 0xFF)) * 0x100 + (b6 - 0xFF)) * 0x100 + (b7 - 0xFF)) * 0x100 + (b8 - 0xFF)) - 1
end
end
function m.build_ext(tag, data)
return nil
end
local function unpack_ext(c, n, tag)
local s, i, j = c.s, c.i, c.j
local e = i + n - 1
if e > j or n < 0 then
c:underflow(e)
s, i, j = c.s, c.i, c.j
e = i + n - 1
end
c.i = i + n
return m.build_ext(tag, s:sub(i, e))
end
local fn_1 = function(c, val) return val end
local fn_2 = function(c, val) return unpack_map(c, val % 0x10) end
local fn_3 = function(c, val) return unpack_array(c, val % 0x10) end
local fn_4 = function(c, val) return unpack_str(c, val % 0x20) end
local fn_5 = function(c, val) return val - 0x100 end
unpackers = setmetatable({
[0xC0] = function() return nil end,
[0xC2] = function() return false end,
[0xC3] = function() return true end,
[0xC4] = function(c) return unpack_str(c, unpack_uint8(c)) end, -- bin8
[0xC5] = function(c) return unpack_str(c, unpack_uint16(c)) end, -- bin16
[0xC6] = function(c) return unpack_str(c, unpack_uint32(c)) end, -- bin32
[0xC7] = function(c) return unpack_ext(c, unpack_uint8(c), unpack_int8(c)) end,
[0xC8] = function(c) return unpack_ext(c, unpack_uint16(c), unpack_int8(c)) end,
[0xC9] = function(c) return unpack_ext(c, unpack_uint32(c), unpack_int8(c)) end,
[0xCA] = unpack_float,
[0xCB] = unpack_double,
[0xCC] = unpack_uint8,
[0xCD] = unpack_uint16,
[0xCE] = unpack_uint32,
[0xCF] = unpack_uint64,
[0xD0] = unpack_int8,
[0xD1] = unpack_int16,
[0xD2] = unpack_int32,
[0xD3] = unpack_int64,
[0xD4] = function(c) return unpack_ext(c, 1, unpack_int8(c)) end,
[0xD5] = function(c) return unpack_ext(c, 2, unpack_int8(c)) end,
[0xD6] = function(c) return unpack_ext(c, 4, unpack_int8(c)) end,
[0xD7] = function(c) return unpack_ext(c, 8, unpack_int8(c)) end,
[0xD8] = function(c) return unpack_ext(c, 16, unpack_int8(c)) end,
[0xD9] = function(c) return unpack_str(c, unpack_uint8(c)) end,
[0xDA] = function(c) return unpack_str(c, unpack_uint16(c)) end,
[0xDB] = function(c) return unpack_str(c, unpack_uint32(c)) end,
[0xDC] = function(c) return unpack_array(c, unpack_uint16(c)) end,
[0xDD] = function(c) return unpack_array(c, unpack_uint32(c)) end,
[0xDE] = function(c) return unpack_map(c, unpack_uint16(c)) end,
[0xDF] = function(c) return unpack_map(c, unpack_uint32(c)) end
}, {
__index = function(t, k)
if k < 0xC0 then
if k < 0x80 then
return fn_1
elseif k < 0x90 then
return fn_2
elseif k < 0xA0 then
return fn_3
else
return fn_4
end
elseif k > 0xDF then
return fn_5
else
return function()
error("unpack '" .. format("%#x", k) .. "' is unimplemented")
end
end
end
})
local function cursor_string(str)
return {
s = str,
i = 1,
j = #str,
underflow = function()
error"missing bytes"
end
}
end
local function cursor_loader(ld)
return {
s = '',
i = 1,
j = 0,
underflow = function(self, e)
self.s = self.s:sub(self.i)
e = e - self.i + 1
self.i = 1
self.j = 0
while e > self.j do
local chunk = ld()
if not chunk then
error"missing bytes"
end
self.s = self.s .. chunk
self.j = #self.s
end
end
}
end
function m.unpack(s)
checktype("unpack", 1, s, "string")
local cursor = cursor_string(s)
local data = unpack_cursor(cursor)
if cursor.i <= cursor.j then
error("extra bytes")
end
return data
end
function m.unpacker(src)
if type(src) == "string" then
local cursor = cursor_string(src)
return function()
if cursor.i <= cursor.j then return cursor.i, unpack_cursor(cursor) end
end
elseif type(src) == "function" then
local cursor = cursor_loader(src)
return function()
if cursor.i > cursor.j then
pcall(cursor.underflow, cursor, cursor.i)
end
if cursor.i <= cursor.j then return true, unpack_cursor(cursor) end
end
else
argerror("unpacker", 1, "string or function expected, got " .. type(src))
end
end
set_string("string")
set_integer("unsigned")
if SIZEOF_NUMBER == 4 then
maxinteger = 16777215
mininteger = -maxinteger
m.small_lua = true
unpackers[0xCB] = nil -- double
unpackers[0xCF] = nil -- uint64
unpackers[0xD3] = nil -- int64
set_number("float")
else
maxinteger = 9007199254740991
mininteger = -maxinteger
set_number("double")
if SIZEOF_NUMBER > 8 then
m.long_double = true
end
end
set_array("always_as_map")
m._VERSION = "0.5.2"
m._DESCRIPTION = "lua-MessagePack : a pure Lua implementation"
m._COPYRIGHT = "Copyright (c) 2012-2019 Francois Perrad"
return m
--
-- This library is licensed under the terms of the MIT/X11 license,
-- like Lua itself.
--

View File

@@ -0,0 +1,53 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
if SAM_LOADED then return end
local netstream = sam.netstream
netstream.async = {}
if SERVER then
local IsValid = IsValid
function netstream.async.Hook(name, fn, check)
netstream.Hook(name, function(ply, i, ...)
if not sam.isnumber(i) then return end
local res = function(...)
if IsValid(ply) then
netstream.Start(ply, name, i, ...)
end
end
fn(res, ply, ...)
end, check)
end
else
local count = 0
local receivers = {}
local hook_fn = function(i, ...)
local receiver = receivers[i]
if receiver[2] then
receiver[2]()
end
receiver[1]:resolve(...)
receivers[i] = nil
end
function netstream.async.Start(name, func_to_call, ...)
local promise = sam.Promise.new()
count = count + 1
receivers[count] = {promise, func_to_call}
netstream.Hook(name, hook_fn)
if func_to_call then
func_to_call()
end
netstream.Start(name, count, ...)
return promise
end
end

111
lua/sam/libs/sh_globals.lua Normal file
View File

@@ -0,0 +1,111 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
if SAM_LOADED then return end
local sam, netstream = sam, sam.netstream
local globals
if SERVER then
globals = {}
local order = {}
local get_order_key = function(key)
for i = 1, #order do
if order[i] == key then
return i
end
end
end
function sam.set_global(key, value, force)
if force or globals[key] ~= value then
globals[key] = value
if value ~= nil then
if not get_order_key(key) then
table.insert(order, key)
end
else
local i = get_order_key(key)
if i then
table.remove(order, i)
end
end
netstream.Start(nil, "SetGlobal", key, value)
end
end
hook.Add("OnEntityCreated", "SAM.Globals", function(ent)
if ent:IsPlayer() and ent:IsValid() then
local delay = FrameTime() * 5
local first = true
for _, key in ipairs(order) do
if (key == "Ranks") then
for rank, value in pairs(globals[key]) do
timer.Simple(delay, function() netstream.Start(ent, "SendRank", rank, value) end)
delay = delay + FrameTime() * 2
end
timer.Simple(delay, function() netstream.Start(ent, "SendRank", "Last") end)
delay = delay + FrameTime() * 5
else
if (first) then
timer.Simple(delay, function() netstream.Start(ent, "SendGlobals", {[key] = globals[key]}, {key}) end)
first = false
else
timer.Simple(delay, function() netstream.Start(ent, "SetGlobal", key, globals[key]) end)
end
delay = delay + FrameTime() * 5
end
end
end
end)
end
if CLIENT then
function sam.set_global(key, value)
if globals then
globals[key] = value
hook.Call("SAM.ChangedGlobalVar", nil, key, value)
end
end
netstream.Hook("SetGlobal", sam.set_global)
netstream.Hook("SendGlobals", function(vars, order)
globals = vars
for _, key in ipairs(order) do
hook.Call("SAM.ChangedGlobalVar", nil, key, vars[key])
end
end)
netstream.Hook("SendRank", function(rank, value)
if (rank ~= "Last" and value) then
globals = globals or {}
globals["Ranks"] = globals["Ranks"] or {}
globals["Ranks"][rank] = value
elseif (rank == "Last") then
hook.Call("SAM.ChangedGlobalVar", nil, "Ranks", globals["Ranks"])
end
end)
end
function sam.get_global(key, default)
if globals then
local value = globals[key]
if value ~= nil then
return value
end
end
return default
end

157
lua/sam/libs/sh_mp.lua Normal file
View File

@@ -0,0 +1,157 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
if SAM_LOADED then return end
local sam = sam
local mp = sam.load_file("sam/libs/message_pack/sh_messagepack.lua")
local EXT_VECTOR = 1
local EXT_ANGLE = 2
local EXT_ENTITY = 3
local EXT_PLAYER = 4
local EXT_COLOR = 5
local EXT_CONSOLE = 6
mp.packers["Entity"] = function(buffer, ent)
local buf = {}
mp.packers["number"](buf, ent:EntIndex())
mp.packers["ext"](buffer, EXT_ENTITY, buf[1])
end
mp.packers["Vehicle"] = mp.packers["Entity"]
mp.packers["Weapon"] = mp.packers["Entity"]
mp.packers["NPC"] = mp.packers["Entity"]
mp.packers["NextBot"] = mp.packers["Entity"]
mp.packers["PhysObj"] = mp.packers["Entity"]
mp.packers["Player"] = function(buffer, ply)
local buf = {}
mp.packers["number"](buf, ply:UserID())
mp.packers["ext"](buffer, EXT_PLAYER, buf[1])
end
local VECTOR = {}
mp.packers["Vector"] = function(buffer, vec)
VECTOR[1] = vec.x
VECTOR[2] = vec.y
VECTOR[3] = vec.z
local buf = {}
mp.packers["_table"](buf, VECTOR)
mp.packers["ext"](buffer, EXT_VECTOR, table.concat(buf))
end
local ANGLE = {}
mp.packers["Angle"] = function(buffer, ang)
ANGLE[1] = ang.p
ANGLE[2] = ang.y
ANGLE[3] = ang.r
local buf = {}
mp.packers["_table"](buf, ANGLE)
mp.packers["ext"](buffer, EXT_ANGLE, table.concat(buf))
end
local COLOR = {}
mp.packers["Color"] = function(buffer, col)
COLOR[1] = col.r
COLOR[2] = col.g
COLOR[3] = col.b
COLOR[4] = col.a
local buf = {}
mp.packers["_table"](buf, COLOR)
mp.packers["ext"](buffer, EXT_COLOR, table.concat(buf))
end
mp.packers["console"] = function(buffer)
mp.packers["ext"](buffer, EXT_CONSOLE, "")
end
local Entity = Entity
local _Player
local Color = Color
local Vector = Vector
local Angle = Angle
local unpackers = {
[EXT_ENTITY] = function(v)
return Entity(v)
end,
[EXT_PLAYER] = function(v)
return _Player(v)
end,
[EXT_VECTOR] = function(v)
return Vector(v[1], v[2], v[3])
end,
[EXT_ANGLE] = function(v)
return Angle(v[1], v[2], v[3])
end,
[EXT_COLOR] = function(v)
return Color(v[1], v[2], v[3], v[4])
end,
[EXT_CONSOLE] = function(v)
return sam.console
end
}
local Player = Player
if CLIENT then
local players = {}
local Name = function(s)
return s.name
end
_Player = function(id)
local ply = Player(id)
if not IsValid(ply) then
local name = players[id]
if name then
return {
name = name,
Name = Name
}
end
end
return ply
end
hook.Add("OnEntityCreated", "SAM.GetPlayerName", function(ent)
if ent:IsPlayer() and ent:IsValid() then
ent.sam_userid = ent:UserID() -- userid is -1 in EntityRemoved?????
end
end)
hook.Add("EntityRemoved", "SAM.GetPlayerName", function(ent)
if not ent:IsPlayer() then return end
local id = ent.sam_userid
if not id then return end
players[id] = ent:Name()
timer.Simple(60, function()
if not IsValid(ent) then
players[id] = nil
end
end)
end)
else
_Player = Player
end
mp.build_ext = function(tag, data)
local f = mp.unpacker(data)
local _, v = f()
return unpackers[tag](v)
end
sam.mp = mp

View File

@@ -0,0 +1,177 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
if SAM_LOADED then return end
--[[
NetStream - 2.0.1
https://github.com/alexgrist/NetStream/blob/master/netstream2.lua
Alexander Grist-Hucker
http://www.revotech.org
]]--
--[[
if SERVER then
netstream.Hook("Hi", function(ply, ...) -- Third argument is called to check if the player has permission to send the net message before decoding
print(...)
end, function(ply)
if not ply:IsAdmin() then
return false
end
end)
-- OR
netstream.Hook("Hi", function(ply, ...)
print(...)
end)
netstream.Start(Entity(1), "Hi", "a", 1, {}, true, false, nil, "!") -- First argument player or table of players or any other argument to send to all players
netstream.Start({Entity(1), Entity(2)}, "Hi", "a", 1, {}, true, false, nil, "!")
netstream.Start(nil, "Hi", "a", 1, {}, true, false, nil, "!")
end
if CLIENT then
netstream.Hook("Hi", function(...)
print(...)
end)
netstream.Start("Hi", "a", 1, {}, true, false, nil, "!")
end
]]--
-- Config
local addonName = "SAM"
local mainTable = sam -- _G.netstream = netstream
local mp = sam.mp
--
local type = sam.type
local pcall = pcall
local unpack = unpack
local net = net
local table_maxn = table.maxn
local netStreamSend = addonName .. ".NetStreamDS.Sending"
local netstream = {}
if istable(mainTable) then
mainTable.netstream = netstream
end
local checks = {}
local receivers = {}
local concat = table.concat
local pack = function(t, n)
local buffer = {}
mp.packers["array"](buffer, t, n)
return concat(buffer)
end
if SERVER then
util.AddNetworkString(netStreamSend)
-- local str_sub = string.sub
-- local function Split(str, buffer, result)
-- if not result then
-- result = {}
-- end
-- if not buffer then
-- buffer = 32768
-- end
-- local len = #str
-- if len >= buffer then
-- result[#result + 1] = str_sub(str, 1, buffer - 1)
-- str = str_sub(str, buffer, len)
-- else
-- result[#result + 1] = str
-- return result
-- end
-- return Split(str, buffer, result)
-- end
local player_GetAll = player.GetAll
function netstream.Start(ply, name, ...)
local ply_type = type(ply)
if ply_type ~= "Player" and ply_type ~= "table" then
ply = player_GetAll()
end
local encoded_data = pack({...}, select("#", ...))
local length = #encoded_data
net.Start(netStreamSend)
net.WriteString(name)
net.WriteUInt(length, 17)
net.WriteData(encoded_data, length)
net.Send(ply)
end
function netstream.Hook(name, callback, check)
receivers[name] = callback
if type(check) == "function" then
checks[name] = check
end
end
net.Receive(netStreamSend, function(_, ply)
local name = net.ReadString()
local callback = receivers[name]
if not callback then return end
local length = net.ReadUInt(17)
local check = checks[name]
if check and check(ply, length) == false then return end
local data = net.ReadData(length)
local status
status, data = pcall(mp.unpack, data)
if not status or not sam.istable(data) then return end
callback(ply, unpack(data, 1, table_maxn(data)))
end)
else
checks = nil
function netstream.Start(name, ...)
local encoded_data = pack({...}, select("#", ...))
local length = #encoded_data
net.Start(netStreamSend)
net.WriteString(name)
net.WriteUInt(length, 17)
net.WriteData(encoded_data, length)
net.SendToServer()
end
function netstream.Hook(name, callback)
receivers[name] = callback
end
net.Receive(netStreamSend, function()
local callback = receivers[net.ReadString()]
if not callback then return end
local length = net.ReadUInt(17)
local data = net.ReadData(length)
data = mp.unpack(data)
callback(unpack(data, 1, table_maxn(data)))
end)
end
return netstream

458
lua/sam/libs/sh_pon.lua Normal file
View File

@@ -0,0 +1,458 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
if SAM_LOADED then return end
--[[
DEVELOPMENTAL VERSION;
VERSION 1.2.2
Copyright thelastpenguin™
You may use this for any purpose as long as:
- You don't remove this copyright notice.
- You don't claim this to be your own.
- You properly credit the author, thelastpenguin™, if you publish your work based on (and/or using) this.
If you modify the code for any purpose, the above still applies to the modified code.
The author is not held responsible for any damages incured from the use of pon, you use it at your own risk.
DATA TYPES SUPPORTED:
- tables - k,v - pointers
- strings - k,v - pointers
- numbers - k,v
- booleans- k,v
- Vectors - k,v
- Angles - k,v
- Entities- k,v
- Players - k,v
CHANGE LOG
V 1.1.0
- Added Vehicle, NPC, NextBot, Player, Weapon
V 1.2.0
- Added custom handling for k,v tables without any array component.
V 1.2.1
- fixed deserialization bug.
THANKS TO...
- VERCAS for the inspiration.
]]
local pon = {}
sam.pon = pon
do
local type = sam.type
local IsColor = IsColor
local tonumber = tonumber
local format = string.format
local encode = {}
local cacheSize = 0
encode['table'] = function(self, tbl, output, cache)
if cache[tbl] then
output[#output + 1] = format('(%x)', cache[tbl])
return
else
cacheSize = cacheSize + 1
cache[tbl] = cacheSize
end
local first = next(tbl, nil)
local predictedNumeric = 1
-- starts with a numeric dealio
if first == 1 then
output[#output + 1] = '{'
for k, v in next, tbl do
if k == predictedNumeric then
predictedNumeric = predictedNumeric + 1
local tv = type(v)
if tv == 'string' then
local pid = cache[v]
if pid then
output[#output + 1] = format('(%x)', pid)
else
cacheSize = cacheSize + 1
cache[v] = cacheSize
self.string(self, v, output, cache)
end
elseif IsColor(v) then
self.Color(self, v, output, cache)
else
self[tv](self, v, output, cache)
end
else
break
end
end
predictedNumeric = predictedNumeric - 1
else
predictedNumeric = nil
end
if predictedNumeric == nil then
output[#output + 1] = '[' -- no array component
else
output[#output + 1] = '~' -- array component came first so shit needs to happen
end
for k, v in next, tbl, predictedNumeric do
local tk, tv = type(k), type(v)
if not self[tk] or not self[tv] then continue end
-- WRITE KEY
if tk == 'string' then
local pid = cache[k]
if pid then
output[#output + 1] = format('(%x)', pid)
else
cacheSize = cacheSize + 1
cache[k] = cacheSize
self.string(self, k, output, cache)
end
elseif IsColor(v) then
self.Color(self, v, output, cache)
else
self[tk](self, k, output, cache)
end
-- WRITE VALUE
if tv == 'string' then
local pid = cache[v]
if pid then
output[#output + 1] = format('(%x)', pid)
else
cacheSize = cacheSize + 1
cache[v] = cacheSize
self.string(self, v, output, cache)
end
elseif IsColor(v) then
self.Color(self, v, output, cache)
else
self[tv](self, v, output, cache)
end
end
output[#output + 1] = '}'
end
-- ENCODE STRING
local gsub = string.gsub
encode['string'] = function(self, str, output)
--if tryCache(str, output then return end
local estr, count = gsub(str, ';', "\\;")
if count == 0 then
output[#output + 1] = '\'' .. str .. ';'
else
output[#output + 1] = '"' .. estr .. '";'
end
end
-- ENCODE NUMBER
encode['number'] = function(self, num, output)
if num % 1 == 0 then
if num < 0 then
output[#output + 1] = format('x%x;', -num)
else
output[#output + 1] = format('X%x;', num)
end
else
output[#output + 1] = tonumber(num) .. ';'
end
end
-- ENCODE BOOLEAN
encode['boolean'] = function(self, val, output)
output[#output + 1] = val and 't' or 'f'
end
-- ENCODE VECTOR
encode['Vector'] = function(self, val, output)
output[#output + 1] = ('v' .. val.x .. ',' .. val.y) .. (',' .. val.z .. ';')
end
-- ENCODE ANGLE
encode['Angle'] = function(self, val, output)
output[#output + 1] = ('a' .. val.p .. ',' .. val.y) .. (',' .. val.r .. ';')
end
encode['Entity'] = function(self, val, output)
output[#output + 1] = 'E' .. (IsValid(val) and (val:EntIndex() .. ';') or '#')
end
encode['Player'] = encode['Entity']
encode['Vehicle'] = encode['Entity']
encode['Weapon'] = encode['Entity']
encode['NPC'] = encode['Entity']
encode['NextBot'] = encode['Entity']
encode['PhysObj'] = encode['Entity']
encode['Color'] = function(self, val, output)
output[#output + 1] = ('C' .. val.r .. ',' .. val.g .. ',' .. val.b) .. (',' .. val.a .. ';')
end
encode['console'] = function(self, val, output)
output[#output + 1] = 's'
end
encode['nil'] = function(self, val, output)
output[#output + 1] = '?'
end
encode.__index = function(key)
ErrorNoHalt('Type: ' .. key .. ' can not be encoded. Encoded as as pass-over value.')
return encode['nil']
end
do
local concat = table.concat
function pon.encode(tbl)
local output = {nil, nil, nil, nil, nil, nil, nil, nil}
cacheSize = 0
encode['table'](encode, tbl, output, {})
return concat(output)
end
end
end
do
local tonumber = tonumber
local find, sub, gsub, Explode = string.find, string.sub, string.gsub, string.Explode
local Vector, Angle, Entity = Vector, Angle, Entity
local decode = {}
decode['{'] = function(self, index, str, cache)
local cur = {}
cache[#cache + 1] = cur
local k, v, tk, tv = 1, nil, nil, nil
while (true) do
tv = sub(str, index, index)
if not tv or tv == '~' then
index = index + 1
break
end
if tv == '}' then return index + 1, cur end
-- READ THE VALUE
index = index + 1
index, v = self[tv](self, index, str, cache)
cur[k] = v
k = k + 1
end
while (true) do
tk = sub(str, index, index)
if not tk or tk == '}' then
index = index + 1
break
end
-- READ THE KEY
index = index + 1
index, k = self[tk](self, index, str, cache)
-- READ THE VALUE
tv = sub(str, index, index)
index = index + 1
index, v = self[tv](self, index, str, cache)
cur[k] = v
end
return index, cur
end
decode['['] = function(self, index, str, cache)
local cur = {}
cache[#cache + 1] = cur
local k, v, tk, tv = 1, nil, nil, nil
while (true) do
tk = sub(str, index, index)
if not tk or tk == '}' then
index = index + 1
break
end
-- READ THE KEY
index = index + 1
index, k = self[tk](self, index, str, cache)
if not k then continue end
-- READ THE VALUE
tv = sub(str, index, index)
index = index + 1
if not self[tv] then
print('did not find type: ' .. tv)
end
index, v = self[tv](self, index, str, cache)
cur[k] = v
end
return index, cur
end
-- STRING
decode['"'] = function(self, index, str, cache)
local finish = find(str, '";', index, true)
local res = gsub(sub(str, index, finish - 1), '\\;', ';')
index = finish + 2
cache[#cache + 1] = res
return index, res
end
-- STRING NO ESCAPING NEEDED
decode['\''] = function(self, index, str, cache)
local finish = find(str, ';', index, true)
local res = sub(str, index, finish - 1)
index = finish + 1
cache[#cache + 1] = res
return index, res
end
-- NUMBER
decode['n'] = function(self, index, str)
index = index - 1
local finish = find(str, ';', index, true)
local num = tonumber(sub(str, index, finish - 1))
index = finish + 1
return index, num
end
decode['0'] = decode['n']
decode['1'] = decode['n']
decode['2'] = decode['n']
decode['3'] = decode['n']
decode['4'] = decode['n']
decode['5'] = decode['n']
decode['6'] = decode['n']
decode['7'] = decode['n']
decode['8'] = decode['n']
decode['9'] = decode['n']
decode['-'] = decode['n']
-- positive hex
decode['X'] = function(self, index, str)
local finish = find(str, ';', index, true)
local num = tonumber(sub(str, index, finish - 1), 16)
index = finish + 1
return index, num
end
-- negative hex
decode['x'] = function(self, index, str)
local finish = find(str, ';', index, true)
local num = -tonumber(sub(str, index, finish - 1), 16)
index = finish + 1
return index, num
end
-- POINTER
decode['('] = function(self, index, str, cache)
local finish = find(str, ')', index, true)
local num = tonumber(sub(str, index, finish - 1), 16)
index = finish + 1
return index, cache[num]
end
-- BOOLEAN. ONE DATA TYPE FOR YES, ANOTHER FOR NO.
decode['t'] = function(self, index) return index, true end
decode['f'] = function(self, index) return index, false end
-- VECTOR
decode['v'] = function(self, index, str)
local finish = find(str, ';', index, true)
local vecStr = sub(str, index, finish - 1)
index = finish + 1 -- update the index.
local segs = Explode(',', vecStr, false)
return index, Vector(tonumber(segs[1]), tonumber(segs[2]), tonumber(segs[3]))
end
-- ANGLE
decode['a'] = function(self, index, str)
local finish = find(str, ';', index, true)
local angStr = sub(str, index, finish - 1)
index = finish + 1 -- update the index.
local segs = Explode(',', angStr, false)
return index, Angle(tonumber(segs[1]), tonumber(segs[2]), tonumber(segs[3]))
end
-- ENTITY
decode['E'] = function(self, index, str)
if str[index] == '#' then
index = index + 1
return index, NULL
else
local finish = find(str, ';', index, true)
local num = tonumber(sub(str, index, finish - 1))
index = finish + 1
return index, Entity(num)
end
end
-- COLOR
decode['C'] = function(self, index, str)
local finish = find(str, ';', index, true)
local colStr = sub(str, index, finish - 1)
index = finish + 1 -- update the index.
local segs = Explode(',', colStr, false)
return index, Color(segs[1], segs[2], segs[3], segs[4])
end
-- PLAYER
decode['P'] = function(self, index, str)
local finish = find(str, ';', index, true)
local num = tonumber(sub(str, index, finish - 1))
index = finish + 1
return index, Entity(num) or NULL
end
-- NIL
decode['?'] = function(self, index) return index + 1, nil end
-- SAM CONSOLE
decode['s'] = function(self, index) return index, sam.console end
function pon.decode(data)
local _, res = decode[sub(data, 1, 1)](decode, 2, data, {})
return res
end
end

View File

@@ -0,0 +1,76 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
if SAM_LOADED then return end
-- not real promises, just really simple one
local isfunction = sam and sam.isfunction or isfunction
local null = {}
local Promise = {}
local PromiseMethods = {}
local Promise_meta = {__index = PromiseMethods}
function Promise.new()
return setmetatable({
value = null,
null = null
}, Promise_meta)
end
function Promise.IsPromise(v)
return getmetatable(v) == Promise_meta
end
function PromiseMethods:resolve(v)
if self.value ~= null then return end
if self.done_callback then
self.done_callback(v)
else
self.value = v
self.callback = 0
end
end
function PromiseMethods:reject(v)
if self.value ~= null then return end
if self.catch_callback then
self.catch_callback(v)
else
self.value = v
self.callback = 1
end
end
function PromiseMethods:done(func)
if isfunction(func) then
if self.value ~= null and self.callback == 0 then
func(self.value)
else
self.done_callback = func
end
end
return self
end
function PromiseMethods:catch(func)
if isfunction(func) then
if self.value ~= null and self.callback == 1 then
func(self.value)
else
self.catch_callback = func
end
end
return self
end
return Promise

94
lua/sam/libs/sh_types.lua Normal file
View File

@@ -0,0 +1,94 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
if SAM_LOADED then return end
-- https://gist.github.com/CapsAdmin/0d9c1e77d0fc22d910e182bfeb9812e5
local getmetatable = getmetatable
do
local types = {
["string"] = "",
["boolean"] = true,
["number"] = 0,
["function"] = function() end,
["thread"] = coroutine.create(getmetatable),
["Color"] = Color(0, 0, 0),
}
for k, v in pairs(types) do
if not getmetatable(v) then
debug.setmetatable(v, {MetaName = k})
else
getmetatable(v).MetaName = k
end
end
end
function sam.type(value)
if value == nil then
return "nil"
end
local meta = getmetatable(value)
if meta then
meta = meta.MetaName
if meta then
return meta
end
end
return "table"
end
do
local function add(name)
local new_name = name
if name == "bool" then
new_name = "boolean"
end
sam["is" .. name:lower()] = function(value)
local meta = getmetatable(value)
if meta and meta.MetaName == new_name then
return true
else
return false
end
end
end
add("string")
add("number")
add("bool")
add("function")
add("Angle")
add("Vector")
add("Panel")
add("Matrix")
end
function sam.isentity(value)
local meta = getmetatable(value)
if meta then
if meta.MetaName == "Entity" then
return true
end
meta = meta.MetaBaseClass
if meta then
return meta.MetaName == "Entity"
end
end
return false
end
sam.IsEntity = sam.isentity
local type = sam.type
function sam.istable(value)
return type(value) == "table"
end

View File

@@ -0,0 +1,191 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
local _SQL = sam.SQL
local _error = _SQL.Error
local traceback = debug.traceback
local _mysqloo, database = nil, nil
local SQL = {}
function SQL.Connect(callback, failed_callback, config)
if database then
local status = database:status()
if status == _mysqloo.DATABASE_CONNECTING or status == _mysqloo.DATABASE_CONNECTED then
return true
end
end
_SQL.SetConnected(false)
require("mysqloo")
if not mysqloo then
_error("mysqloo module doesn't exist, get it from https://github.com/FredyH/MySQLOO")
return false
end
_mysqloo = mysqloo
database = _mysqloo.connect(
config.Host,
config.Username,
config.Password,
config.Database,
config.Port
)
function database.onConnected()
callback()
end
function database.onConnectionFailed(_, error_text)
failed_callback(error_text)
end
database:connect()
return true
end
--
--
--
local transaction
local add_transaction = function(query)
transaction:addQuery(database:query(query))
end
function SQL.Begin()
transaction = database:createTransaction()
return add_transaction
end
function SQL.Commit(callback)
transaction.SQL_traceback = traceback("", 2)
transaction.onSuccess = callback
transaction.onError = transaction_onError
transaction:start()
transaction = nil
end
--
--
--
--
--
--
local on_query_success = function(query, data)
if query.SQL_first_row then
data = data[1]
end
query.SQL_callback(data, query.SQL_callback_obj)
end
local on_query_fail = function(query, error_text)
local status = database:status()
-- https://github.com/Kamshak/LibK/blob/master/lua/libk/server/sv_libk_database.lua#L129
if status == _mysqloo.DATABASE_NOT_CONNECTED or status == _mysqloo.DATABASE_CONNECTING or error_text:find("Lost connection to MySQL server during query", 1, true) then
_SQL.SetConnected(false)
SQL.Query(query.SQL_query_string, query.SQL_callback, query.SQL_first_row, query.SQL_callback_obj)
else
-- 3cb9b992975d0cc0ba1b28f92ab5d1b700a08080a59b058f1424736060a73552
_error("Query error: " .. error_text, query.SQL_traceback)
end
end
function SQL.Query(query, callback, first_row, callback_obj)
local status = database:status()
if status == _mysqloo.DATABASE_NOT_CONNECTED or status == _mysqloo.DATABASE_INTERNAL_ERROR then
_SQL.Connect()
database:wait()
end
local query_string = query
query = database:query(query)
query.SQL_query_string = query_string
if callback then
query.onSuccess = on_query_success
query.SQL_callback = callback
query.SQL_first_row = first_row
query.SQL_callback_obj = callback_obj
end
query.SQL_traceback = traceback("", 2)
query.onError = on_query_fail
query:start()
return query
end
-- local prepared_set_values = function(prepared_query, values)
-- for i = 1, #values do
-- local v = values[i]
-- local value_type = type(v)
-- if value_type == "string" then
-- prepared_query:setString(i, v)
-- elseif value_type == "number" then
-- prepared_query:setNumber(i, v)
-- else
-- error(
-- string.format(
-- "%s invalid type '%s' was passed to escape '%s'",
-- "(" .. SQL.GetAddonName() .. " | MySQL)",
-- value_type,
-- v
-- )
-- )
-- end
-- end
-- end
-- function SQL.Prepare(query, callback, first_row, callback_obj)
-- local prepared_query = database:prepare(query)
-- prepared_query.SetValues = prepared_set_values
-- if callback then
-- prepared_query.onSuccess = on_query_success
-- prepared_query.SQL_callback = callback
-- prepared_query.SQL_first_row = first_row
-- prepared_query.SQL_callback_obj = callback_obj
-- end
-- prepared_query.SQL_traceback = traceback("", 2)
-- prepared_query.onError = on_query_fail
-- return prepared_query
-- end
--
--
--
function SQL.EscapeString(value, no_quotes)
if no_quotes then
return database:escape(value)
else
return "'" .. database:escape(value) .. "'"
end
end
function SQL.TableExistsQuery(name)
return "SHOW TABLES LIKE " .. SQL.EscapeString(name)
end
return SQL

View File

@@ -0,0 +1,148 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
local _SQL = sam.SQL
local _error = sam.SQL.Error
local sql_query = sql.Query
local SQL = {}
function SQL.Connect(callback)
timer.Simple(0, callback)
return true
end
--
--
--
local transactions
local add_transaction = function(query)
table.insert(transactions, query)
end
function SQL.Begin()
transactions = {}
sql_query("BEGIN TRANSACTION")
return add_transaction
end
function SQL.Commit(callback)
for i = 1, #transactions do
if sql_query(transactions[i]) == false then
sql_query("ROLLBACK TRANSACTION")
transactions = nil
_error("Transaction error: " .. sql.LastError())
return
end
end
transactions = nil
sql_query("COMMIT TRANSACTION")
if callback then
callback()
end
end
--
--
--
--
--
--
local query_obj = {
wait = function() end -- mysqloo has query:wait()
}
function SQL.Query(query, callback, first_row, callback_obj)
local data = sql_query(query)
if data == false then
_error("Query error: " .. sql.LastError())
elseif callback then
if data == nil then
if not first_row then
data = {}
end
elseif first_row then
data = data[1]
end
callback(data, callback_obj)
end
return query_obj
end
-- local concat = table.concat
-- local prepared_set_values = function(prepared_query, values)
-- for i = 1, prepared_query.args_n do
-- prepared_query[prepared_query[-i]] = _SQL.Escape(values[i])
-- end
-- return concat(prepared_query, "", 1, prepared_query.n)
-- end
-- local prepared_start = function()
-- end
-- local sub, find = string.sub, string.find
-- function SQL.Prepare(query, callback, first_row, callback_obj)
-- local prepared_query = {}
-- prepared_query.wait = query_obj.wait
-- prepared_query.Start = prepared_start
-- prepared_query.SetValues = prepared_set_values
-- local count, args_n = 0, 0
-- local pos, start, _end = 0, nil, 0
-- while true do
-- start, _end = find(query, "?", _end + 1, true)
-- if not start then
-- break
-- end
-- if pos ~= start then
-- count = count + 1; prepared_query[count] = sub(query, pos, start - 1)
-- end
-- count = count + 1; prepared_query[count] = "NULL"
-- args_n = args_n - 1; prepared_query[args_n] = count
-- pos = _end + 1
-- end
-- if pos <= #query then
-- count = count + 1; prepared_query[count] = sub(query, pos)
-- end
-- prepared_query.n = count
-- prepared_query.args_n = abs(args_n)
-- return prepared_query
-- end
--
--
--
local SQLStr = SQLStr
function SQL.EscapeString(value, no_quotes)
return SQLStr(value, no_quotes)
end
function SQL.TableExistsQuery(name)
return "SELECT `name` FROM `sqlite_master` WHERE `name` = " .. SQL.EscapeString(name) .. " AND `type` = 'table'"
end
--
--
--
return SQL

View File

@@ -0,0 +1,152 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
if SAM_LOADED then return end
local format, isstring, istable, tonumber = string.format, sam.isstring, sam.istable, tonumber
local config = {}
local SQL, _SQL = {}, nil
function SQL.Print(...)
MsgC(
Color(255, 255, 255), "(",
Color(244, 67, 54), SQL.GetAddonName(),
Color(255, 255, 255), " | ",
Color(244, 67, 54), SQL.IsMySQL() and "MySQL" or "SQLite",
Color(255, 255, 255), ") ",
...
)
Msg("\n")
end
function SQL.Error(err, trace)
SQL.Print(err, trace or debug.traceback("", 2))
end
function SQL.Connect()
return _SQL.Connect(SQL.OnConnected, SQL.OnConnectionFailed, config)
end
do
local in_transaction, old_query = false, nil
function SQL.Begin()
if in_transaction then
return SQL.Error("transaction on going!")
end
in_transaction = true
SQL.Query, old_query = _SQL.Begin(), SQL.Query
end
function SQL.Commit(callback)
if not in_transaction then return end
in_transaction = false
SQL.Query, old_query = old_query, nil
return _SQL.Commit(callback)
end
end
local gsub = string.gsub
function SQL.FQuery(query, args, callback, first_row, callback_obj)
query = gsub(query, "{(%d)(f?)}", function(i, no_escape)
return SQL.Escape(args[tonumber(i)], no_escape ~= "")
end)
return SQL.Query(query, callback, first_row, callback_obj)
end
do
local table_exists = function(data, callback)
callback(data and true or false)
end
function SQL.TableExists(name, callback)
return SQL.Query(_SQL.TableExistsQuery(name), table_exists, true, callback)
end
end
function SQL.IsMySQL()
return config.MySQL == true
end
do
local connected = false
function SQL.IsConnected()
return connected
end
function SQL.SetConnected(is_connected)
connected = is_connected
end
end
function SQL.Escape(value, no_quotes)
local value_type = type(value)
if value_type == "string" then
return _SQL.EscapeString(value, no_quotes)
elseif value_type == "number" then
return value
else
error(
format(
"%s invalid type '%s' was passed to escape '%s'",
"(" .. SQL.GetAddonName() .. " | " .. (SQL.IsMySQL() and "MySQL" or "SQLite") .. ")",
value_type,
value
)
)
end
end
function SQL.OnConnected()
SQL.SetConnected(true)
hook.Call(SQL.GetAddonName() .. ".DatabaseConnected")
end
function SQL.OnConnectionFailed(error_text)
SQL.Error("Failed to connect to the server: " .. error_text)
hook.Call(SQL.GetAddonName() .. ".DatabaseConnectionFailed", nil, error_text)
end
function SQL.SetConfig(new_config)
if not istable(new_config) then return end
if new_config.MySQL == true then
for _, v in ipairs({"Host", "Username", "Password", "Database"}) do
if not isstring(new_config[v]) then
return SQL.Error(
format("config value for '%s' is invalid '%s' needs to be a string!", v, config[v])
)
end
end
new_config.Port = tonumber(new_config.Port) or 3306
_SQL = sam.load_file("sam/libs/sql/databases/mysql.lua", "sv_")
else
_SQL = sam.load_file("sam/libs/sql/databases/sqlite.lua", "sv_")
end
SQL.Query = _SQL.Query
config = new_config
end
do
local addon_name = "NO NAME"
function SQL.SetAddonName(name)
addon_name = name
end
function SQL.GetAddonName()
return addon_name
end
end
sam.SQL = SQL