mirror of
https://github.com/lifestorm/wnsrc.git
synced 2025-12-17 13:53:45 +03:00
Upload
This commit is contained in:
30
lua/sam/libs/message_pack/COPYRIGHT
Normal file
30
lua/sam/libs/message_pack/COPYRIGHT
Normal 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)
|
||||
874
lua/sam/libs/message_pack/sh_messagepack.lua
Normal file
874
lua/sam/libs/message_pack/sh_messagepack.lua
Normal 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.
|
||||
--
|
||||
53
lua/sam/libs/sh_async_netstream.lua
Normal file
53
lua/sam/libs/sh_async_netstream.lua
Normal 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
111
lua/sam/libs/sh_globals.lua
Normal 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
157
lua/sam/libs/sh_mp.lua
Normal 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
|
||||
177
lua/sam/libs/sh_netstream.lua
Normal file
177
lua/sam/libs/sh_netstream.lua
Normal 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
458
lua/sam/libs/sh_pon.lua
Normal 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
|
||||
76
lua/sam/libs/sh_promises.lua
Normal file
76
lua/sam/libs/sh_promises.lua
Normal 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
94
lua/sam/libs/sh_types.lua
Normal 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
|
||||
191
lua/sam/libs/sql/databases/mysql.lua
Normal file
191
lua/sam/libs/sql/databases/mysql.lua
Normal 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
|
||||
148
lua/sam/libs/sql/databases/sqlite.lua
Normal file
148
lua/sam/libs/sql/databases/sqlite.lua
Normal 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
|
||||
152
lua/sam/libs/sql/sv_init.lua
Normal file
152
lua/sam/libs/sql/sv_init.lua
Normal 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
|
||||
Reference in New Issue
Block a user