mirror of
https://github.com/lifestorm/wnsrc.git
synced 2025-12-17 21:53:46 +03:00
Upload
This commit is contained in:
190
lua/sam/importers/serverguard/main.lua
Normal file
190
lua/sam/importers/serverguard/main.lua
Normal file
@@ -0,0 +1,190 @@
|
||||
--[[
|
||||
| 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 sam, SQL = sam, sam.SQL
|
||||
|
||||
local von = include("sam/importers/serverguard/sam_von.lua")
|
||||
if not von then
|
||||
return sam.print("Download the importer folder again from gmodstore.")
|
||||
end
|
||||
|
||||
local no_bans_msg = "No bans to import from serverguard."
|
||||
local import_bans = function()
|
||||
SQL.TableExists("serverguard_bans", function(exists)
|
||||
if not exists then
|
||||
return sam.print(no_bans_msg)
|
||||
end
|
||||
|
||||
SQL.Query([[
|
||||
DELETE FROM `sam_bans`
|
||||
]])
|
||||
|
||||
SQL.Query([[
|
||||
INSERT INTO
|
||||
`sam_bans`(
|
||||
`id`,
|
||||
`steamid`,
|
||||
`reason`,
|
||||
`admin`,
|
||||
`unban_date`
|
||||
)
|
||||
SELECT
|
||||
`id`,
|
||||
`steam_id`,
|
||||
`reason`,
|
||||
'Console',
|
||||
`end_time`
|
||||
FROM
|
||||
`serverguard_bans`
|
||||
]], function()
|
||||
sam.print("Imported bans from serverguard.")
|
||||
end)
|
||||
end)
|
||||
end
|
||||
|
||||
local no_ranks_msg = "No ranks to import from serverguard."
|
||||
local import_ranks = function()
|
||||
SQL.TableExists("serverguard_ranks", function(exists)
|
||||
if not exists then
|
||||
return sam.print(no_ranks_msg)
|
||||
end
|
||||
|
||||
SQL.Query([[
|
||||
SELECT
|
||||
*
|
||||
FROM
|
||||
`serverguard_ranks`
|
||||
]], function(serverguard_ranks)
|
||||
for _, v in pairs(serverguard_ranks) do
|
||||
local name = v.unique_id
|
||||
|
||||
if not sam.ranks.is_rank(name) then
|
||||
sam.ranks.add_rank(name, "user", tonumber(v.immunity), tonumber(v.banlimit))
|
||||
end
|
||||
|
||||
local data = sam.isstring(v.data) and util.JSONToTable(v.data)
|
||||
local tools = sam.istable(data) and sam.istable(data.Restrictions) and sam.istable(data.Restrictions.Tools) and data.Restrictions.Tools
|
||||
|
||||
if not tools then continue end
|
||||
|
||||
for tool_name, value in pairs(tools) do
|
||||
if value == false then
|
||||
sam.ranks.take_permission(name, tool_name)
|
||||
else
|
||||
sam.ranks.give_permission(name, tool_name)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
sam.print("Imported ranks from serverguard.")
|
||||
end)
|
||||
end)
|
||||
end
|
||||
|
||||
local no_users_msg = "No users to import from serverguard."
|
||||
|
||||
local import_expires = function(data)
|
||||
if data and #data > 0 then
|
||||
local began = false
|
||||
for _, v in ipairs(data) do
|
||||
local ply_data = v.data and von.deserialize(v.data) or {}
|
||||
if not sam.isnumber(tonumber(ply_data.groupExpire)) then continue end
|
||||
|
||||
if not began then
|
||||
began = true
|
||||
SQL.Begin()
|
||||
end
|
||||
|
||||
SQL.FQuery([[
|
||||
UPDATE
|
||||
`sam_players`
|
||||
SET
|
||||
`expiry_date` = {1}
|
||||
WHERE
|
||||
`steamid` = {2}
|
||||
]], {tonumber(ply_data.groupExpire), v.steam_id})
|
||||
end
|
||||
SQL.Commit(function()
|
||||
sam.print("Imported users from serverguard.")
|
||||
end)
|
||||
else
|
||||
sam.print("Imported users from serverguard.")
|
||||
end
|
||||
end
|
||||
|
||||
local import_users = function()
|
||||
SQL.TableExists("serverguard_users", function(exists)
|
||||
if not exists then
|
||||
return sam.print(no_users_msg)
|
||||
end
|
||||
|
||||
SQL.Query([[
|
||||
DELETE FROM `sam_players`
|
||||
]])
|
||||
|
||||
SQL.Query([[
|
||||
INSERT INTO
|
||||
`sam_players`(
|
||||
`id`,
|
||||
`steamid`,
|
||||
`name`,
|
||||
`rank`,
|
||||
`expiry_date`,
|
||||
`first_join`,
|
||||
`last_join`,
|
||||
`play_time`
|
||||
)
|
||||
SELECT
|
||||
`id`,
|
||||
`steam_id`,
|
||||
`name`,
|
||||
`rank`,
|
||||
0,
|
||||
`last_played`,
|
||||
`last_played`,
|
||||
0
|
||||
FROM
|
||||
`serverguard_users`
|
||||
]], function()
|
||||
SQL.Query([[
|
||||
SELECT
|
||||
`steam_id`,
|
||||
`data`
|
||||
FROM
|
||||
`serverguard_users`
|
||||
]], import_expires)
|
||||
end)
|
||||
end)
|
||||
end
|
||||
|
||||
if not sam.ranks.ranks_loaded() then
|
||||
return sam.print("Server is connecting to the Database, try again when it connects.")
|
||||
end
|
||||
|
||||
for k, v in ipairs(player.GetAll()) do
|
||||
v:Kick("Importing data.")
|
||||
end
|
||||
|
||||
for k, v in pairs(sam.get_connected_players()) do
|
||||
sam.player.kick_id(k, "Importing data.")
|
||||
end
|
||||
|
||||
hook.Add("CheckPassword", "SAM.ImportingData", function()
|
||||
return false, "Importing data."
|
||||
end)
|
||||
|
||||
sam.print("Starting to import data from serverguard...")
|
||||
timer.Simple(0, function()
|
||||
import_bans()
|
||||
import_ranks()
|
||||
import_users()
|
||||
|
||||
hook.Remove("CheckPassword", "SAM.ImportingData")
|
||||
end)
|
||||
828
lua/sam/importers/serverguard/sam_von.lua
Normal file
828
lua/sam/importers/serverguard/sam_von.lua
Normal file
@@ -0,0 +1,828 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
--[[ vON 1.3.4
|
||||
|
||||
Copyright 2012-2014 Alexandru-Mihai Maftei
|
||||
aka Vercas
|
||||
|
||||
GitHub Repository:
|
||||
https://github.com/vercas/vON
|
||||
|
||||
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 (Vercas) if you publish your work based on (and/or using) this.
|
||||
|
||||
If you modify the code for any purpose, the above obligations still apply.
|
||||
If you make any interesting modifications, try forking the GitHub repository instead.
|
||||
|
||||
Instead of copying this code over for sharing, rather use the link:
|
||||
https://github.com/vercas/vON/blob/master/von.lua
|
||||
|
||||
The author may not be held responsible for any damage or losses directly or indirectly caused by
|
||||
the use of vON.
|
||||
|
||||
If you disagree with the above, don't use the code.
|
||||
|
||||
-----------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
Thanks to the following people for their contribution:
|
||||
- Divran Suggested improvements for making the code quicker.
|
||||
Suggested an excellent new way of deserializing strings.
|
||||
Lead me to finding an extreme flaw in string parsing.
|
||||
- pennerlord Provided some performance tests to help me improve the code.
|
||||
- Chessnut Reported bug with handling of nil values when deserializing array components.
|
||||
|
||||
- People who contributed on the GitHub repository by reporting bugs, posting fixes, etc.
|
||||
|
||||
-----------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
The vanilla types supported in this release of vON are:
|
||||
- table
|
||||
- number
|
||||
- boolean
|
||||
- string
|
||||
- nil
|
||||
|
||||
The Garry's Mod-specific types supported in this release are:
|
||||
- Vector
|
||||
- Angle
|
||||
+ Entities:
|
||||
- Entity
|
||||
- Vehicle
|
||||
- Weapon
|
||||
- NPC
|
||||
- Player
|
||||
- NextBot
|
||||
|
||||
These are the types one would normally serialize.
|
||||
|
||||
-----------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
New in this version:
|
||||
- Fixed addition of extra entity types. I messed up really badly.
|
||||
--]]
|
||||
|
||||
|
||||
|
||||
local _deserialize, _serialize, _d_meta, _s_meta, d_findVariable, s_anyVariable
|
||||
local sub, gsub, find, insert, concat, error, tonumber, tostring, type, next = string.sub, string.gsub, string.find, table.insert, table.concat, error, tonumber, tostring, type, next
|
||||
|
||||
|
||||
|
||||
--[[ This section contains localized functions which (de)serialize
|
||||
variables according to the types found. ]]
|
||||
|
||||
|
||||
|
||||
-- This is kept away from the table for speed.
|
||||
function d_findVariable(s, i, len, lastType, jobstate)
|
||||
local i, c, typeRead, val = i or 1
|
||||
|
||||
-- Keep looping through the string.
|
||||
while true do
|
||||
-- Stop at the end. Throw an error. This function MUST NOT meet the end!
|
||||
if i > len then
|
||||
error("vON: Reached end of string, cannot form proper variable.")
|
||||
end
|
||||
|
||||
-- Cache the character. Nobody wants to look for the same character ten times.
|
||||
c = sub(s, i, i)
|
||||
|
||||
-- If it just read a type definition, then a variable HAS to come after it.
|
||||
if typeRead then
|
||||
-- Attempt to deserialize a variable of the freshly read type.
|
||||
val, i = _deserialize[lastType](s, i, len, false, jobstate)
|
||||
-- Return the value read, the index of the last processed character, and the type of the last read variable.
|
||||
return val, i, lastType
|
||||
|
||||
-- @ means nil. It should not even appear in the output string of the serializer. Nils are useless to store.
|
||||
elseif c == "@" then
|
||||
return nil, i, lastType
|
||||
|
||||
-- $ means a table reference will follow - a number basically.
|
||||
elseif c == "$" then
|
||||
lastType = "table_reference"
|
||||
typeRead = true
|
||||
|
||||
-- n means a number will follow. Base 10... :C
|
||||
elseif c == "n" then
|
||||
lastType = "number"
|
||||
typeRead = true
|
||||
|
||||
-- b means boolean flags.
|
||||
elseif c == "b" then
|
||||
lastType = "boolean"
|
||||
typeRead = true
|
||||
|
||||
-- ' means the start of a string.
|
||||
elseif c == "'" then
|
||||
lastType = "string"
|
||||
typeRead = true
|
||||
|
||||
-- " means the start of a string prior to version 1.2.0.
|
||||
elseif c == "\"" then
|
||||
lastType = "oldstring"
|
||||
typeRead = true
|
||||
|
||||
-- { means the start of a table!
|
||||
elseif c == "{" then
|
||||
lastType = "table"
|
||||
typeRead = true
|
||||
|
||||
|
||||
--[[ Garry's Mod types go here ]]
|
||||
|
||||
-- e means an entity ID will follow.
|
||||
elseif c == "e" then
|
||||
lastType = "Entity"
|
||||
typeRead = true
|
||||
--[[
|
||||
-- c means a vehicle ID will follow.
|
||||
elseif c == "c" then
|
||||
lastType = "Vehicle"
|
||||
typeRead = true
|
||||
|
||||
-- w means a weapon entity ID will follow.
|
||||
elseif c == "w" then
|
||||
lastType = "Weapon"
|
||||
typeRead = true
|
||||
|
||||
-- x means a NPC ID will follow.
|
||||
elseif c == "x" then
|
||||
lastType = "NPC"
|
||||
typeRead = true
|
||||
--]]
|
||||
-- p means a player ID will follow.
|
||||
-- Kept for backwards compatibility.
|
||||
elseif c == "p" then
|
||||
lastType = "Entity"
|
||||
typeRead = true
|
||||
|
||||
-- v means a vector will follow. 3 numbers.
|
||||
elseif c == "v" then
|
||||
lastType = "Vector"
|
||||
typeRead = true
|
||||
|
||||
-- a means an Euler angle will follow. 3 numbers.
|
||||
elseif c == "a" then
|
||||
lastType = "Angle"
|
||||
typeRead = true
|
||||
|
||||
--[[ Garry's Mod types end here ]]
|
||||
|
||||
|
||||
-- If no type has been found, attempt to deserialize the last type read.
|
||||
elseif lastType then
|
||||
val, i = _deserialize[lastType](s, i, len, false, jobstate)
|
||||
return val, i, lastType
|
||||
|
||||
-- This will occur if the very first character in the vON code is wrong.
|
||||
else
|
||||
error("vON: Malformed data... Can't find a proper type definition. Char#" .. i .. ":" .. c)
|
||||
end
|
||||
|
||||
-- Move the pointer one step forward.
|
||||
i = i + 1
|
||||
end
|
||||
end
|
||||
|
||||
-- This is kept away from the table for speed.
|
||||
-- Yeah, ton of parameters.
|
||||
function s_anyVariable(data, lastType, isNumeric, isKey, isLast, jobstate)
|
||||
local tp = type(data)
|
||||
|
||||
if jobstate[1] and jobstate[2][data] then
|
||||
tp = "table_reference"
|
||||
end
|
||||
|
||||
-- Basically, if the type changes.
|
||||
if lastType ~= tp then
|
||||
-- Remember the new type. Caching the type is useless.
|
||||
lastType = tp
|
||||
|
||||
if _serialize[lastType] then
|
||||
-- Return the serialized data and the (new) last type.
|
||||
-- The second argument, which is true now, means that the data type was just changed.
|
||||
return _serialize[lastType](data, true, isNumeric, isKey, isLast, false, jobstate), lastType
|
||||
else
|
||||
error("vON: No serializer defined for type \"" .. lastType .. "\"!")
|
||||
end
|
||||
end
|
||||
|
||||
-- Otherwise, simply serialize the data.
|
||||
return _serialize[lastType](data, false, isNumeric, isKey, isLast, false, jobstate), lastType
|
||||
end
|
||||
|
||||
|
||||
|
||||
--[[ This section contains the tables with the functions necessary
|
||||
for decoding basic Lua data types. ]]
|
||||
|
||||
|
||||
|
||||
_deserialize = {
|
||||
-- Well, tables are very loose...
|
||||
-- The first table doesn't have to begin and end with { and }.
|
||||
["table"] = function(s, i, len, unnecessaryEnd, jobstate)
|
||||
local ret, numeric, i, c, lastType, val, ind, expectValue, key = {}, true, i or 1, nil, nil, nil, 1
|
||||
-- Locals, locals, locals, locals, locals, locals, locals, locals and locals.
|
||||
|
||||
if sub(s, i, i) == "#" then
|
||||
local e = find(s, "#", i + 2, true)
|
||||
|
||||
if e then
|
||||
local id = tonumber(sub(s, i + 1, e - 1))
|
||||
|
||||
if id then
|
||||
if jobstate[1][id] and not jobstate[2] then
|
||||
error("vON: There already is a table of reference #" .. id .. "! Missing an option maybe?")
|
||||
end
|
||||
|
||||
jobstate[1][id] = ret
|
||||
|
||||
i = e + 1
|
||||
else
|
||||
error("vON: Malformed table! Reference ID starting at char #" .. i .. " doesn't contain a number!")
|
||||
end
|
||||
else
|
||||
error("vON: Malformed table! Cannot find end of reference ID start at char #" .. i .. "!")
|
||||
end
|
||||
end
|
||||
|
||||
-- Keep looping.
|
||||
while true do
|
||||
-- Until it meets the end.
|
||||
if i > len then
|
||||
-- Yeah, if the end is unnecessary, it won't spit an error. The main chunk doesn't require an end, for example.
|
||||
if unnecessaryEnd then
|
||||
return ret, i
|
||||
|
||||
-- Otherwise, the data has to be damaged.
|
||||
else
|
||||
error("vON: Reached end of string, incomplete table definition.")
|
||||
end
|
||||
end
|
||||
|
||||
-- Cache the character.
|
||||
c = sub(s, i, i)
|
||||
--print(i, "table char:", c, tostring(unnecessaryEnd))
|
||||
|
||||
-- If it's the end of a table definition, return.
|
||||
if c == "}" then
|
||||
return ret, i
|
||||
|
||||
-- If it's the component separator, switch to key:value pairs.
|
||||
elseif c == "~" then
|
||||
numeric = false
|
||||
|
||||
elseif c == ";" then
|
||||
-- Lol, nothing!
|
||||
-- Remenant from numbers, for faster parsing.
|
||||
|
||||
-- OK, now, if it's on the numeric component, simply add everything encountered.
|
||||
elseif numeric then
|
||||
-- Find a variable and it's value
|
||||
val, i, lastType = d_findVariable(s, i, len, lastType, jobstate)
|
||||
-- Add it to the table.
|
||||
ret[ind] = val
|
||||
|
||||
ind = ind + 1
|
||||
|
||||
-- Otherwise, if it's the key:value component...
|
||||
else
|
||||
-- If a value is expected...
|
||||
if expectValue then
|
||||
-- Read it.
|
||||
val, i, lastType = d_findVariable(s, i, len, lastType, jobstate)
|
||||
-- Add it?
|
||||
ret[key] = val
|
||||
-- Clean up.
|
||||
expectValue, key = false, nil
|
||||
|
||||
-- If it's the separator...
|
||||
elseif c == ":" then
|
||||
-- Expect a value next.
|
||||
expectValue = true
|
||||
|
||||
-- But, if there's a key read already...
|
||||
elseif key then
|
||||
-- Then this is malformed.
|
||||
error("vON: Malformed table... Two keys declared successively? Char#" .. i .. ":" .. c)
|
||||
|
||||
-- Otherwise the key will be read.
|
||||
else
|
||||
-- I love multi-return and multi-assignement.
|
||||
key, i, lastType = d_findVariable(s, i, len, lastType, jobstate)
|
||||
end
|
||||
end
|
||||
|
||||
i = i + 1
|
||||
end
|
||||
|
||||
return nil, i
|
||||
end,
|
||||
|
||||
-- Just a number which points to a table.
|
||||
["table_reference"] = function(s, i, len, unnecessaryEnd, jobstate)
|
||||
local i, a = i or 1
|
||||
-- Locals, locals, locals, locals
|
||||
|
||||
a = find(s, "[;:}~]", i)
|
||||
|
||||
if a then
|
||||
local n = tonumber(sub(s, i, a - 1))
|
||||
|
||||
if n then
|
||||
return jobstate[1][n] or error("vON: Table reference does not point to a (yet) known table!"), a - 1
|
||||
else
|
||||
error("vON: Table reference definition does not contain a valid number!")
|
||||
end
|
||||
end
|
||||
|
||||
-- Using %D breaks identification of negative numbers. :(
|
||||
|
||||
error("vON: Number definition started... Found no end.")
|
||||
end,
|
||||
|
||||
|
||||
-- Numbers are weakly defined.
|
||||
-- The declaration is not very explicit. It'll do it's best to parse the number.
|
||||
-- Has various endings: \n, }, ~, : and ;, some of which will force the table deserializer to go one char backwards.
|
||||
["number"] = function(s, i, len, unnecessaryEnd, jobstate)
|
||||
local i, a = i or 1
|
||||
-- Locals, locals, locals, locals
|
||||
|
||||
a = find(s, "[;:}~]", i)
|
||||
|
||||
if a then
|
||||
return tonumber(sub(s, i, a - 1)) or error("vON: Number definition does not contain a valid number!"), a - 1
|
||||
end
|
||||
|
||||
-- Using %D breaks identification of negative numbers. :(
|
||||
|
||||
error("vON: Number definition started... Found no end.")
|
||||
end,
|
||||
|
||||
|
||||
-- A boolean is A SINGLE CHARACTER, either 1 for true or 0 for false.
|
||||
-- Any other attempt at boolean declaration will result in a failure.
|
||||
["boolean"] = function(s, i, len, unnecessaryEnd, jobstate)
|
||||
local c = sub(s,i,i)
|
||||
-- Only one character is needed.
|
||||
|
||||
-- If it's 1, then it's true
|
||||
if c == "1" then
|
||||
return true, i
|
||||
|
||||
-- If it's 0, then it's false.
|
||||
elseif c == "0" then
|
||||
return false, i
|
||||
end
|
||||
|
||||
-- Any other supposely "boolean" is just a sign of malformed data.
|
||||
error("vON: Invalid value on boolean type... Char#" .. i .. ": " .. c)
|
||||
end,
|
||||
|
||||
|
||||
-- Strings prior to 1.2.0
|
||||
["oldstring"] = function(s, i, len, unnecessaryEnd, jobstate)
|
||||
local res, i, a = "", i or 1
|
||||
-- Locals, locals, locals, locals
|
||||
|
||||
while true do
|
||||
a = find(s, "\"", i, true)
|
||||
|
||||
if a then
|
||||
if sub(s, a - 1, a - 1) == "\\" then
|
||||
res = res .. sub(s, i, a - 2) .. "\""
|
||||
i = a + 1
|
||||
else
|
||||
return res .. sub(s, i, a - 2), a
|
||||
end
|
||||
else
|
||||
error("vON: Old string definition started... Found no end.")
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
-- Strings after 1.2.0
|
||||
["string"] = function(s, i, len, unnecessaryEnd, jobstate)
|
||||
local res, i, a = "", i or 1
|
||||
-- Locals, locals, locals, locals
|
||||
|
||||
while true do
|
||||
a = find(s, "\"", i, true)
|
||||
|
||||
if a then
|
||||
if sub(s, a - 1, a - 1) == "\\" then
|
||||
res = res .. sub(s, i, a - 2) .. "\""
|
||||
i = a + 1
|
||||
else
|
||||
return res .. sub(s, i, a - 1), a
|
||||
end
|
||||
else
|
||||
error("vON: String definition started... Found no end.")
|
||||
end
|
||||
end
|
||||
end,
|
||||
}
|
||||
|
||||
|
||||
|
||||
_serialize = {
|
||||
-- Uh. Nothing to comment.
|
||||
-- Ton of parameters.
|
||||
-- Makes stuff faster than simply passing it around in locals.
|
||||
-- table.concat works better than normal concatenations WITH LARGE-ISH STRINGS ONLY.
|
||||
["table"] = function(data, mustInitiate, isNumeric, isKey, isLast, first, jobstate)
|
||||
--print(string.format("data: %s; mustInitiate: %s; isKey: %s; isLast: %s; nice: %s; indent: %s; first: %s", tostring(data), tostring(mustInitiate), tostring(isKey), tostring(isLast), tostring(nice), tostring(indent), tostring(first)))
|
||||
|
||||
local result, keyvals, len, keyvalsLen, keyvalsProgress, val, lastType, newIndent, indentString = {}, {}, #data, 0, 0
|
||||
-- Locals, locals, locals, locals, locals, locals, locals, locals, locals and locals.
|
||||
|
||||
-- First thing to be done is separate the numeric and key:value components of the given table in two tables.
|
||||
-- pairs(data) is slower than next, data as far as my tests tell me.
|
||||
for k, v in next, data do
|
||||
-- Skip the numeric keyz.
|
||||
if type(k) ~= "number" or k < 1 or k > len or (k % 1 ~= 0) then -- k % 1 == 0 is, as proven by personal benchmarks,
|
||||
keyvals[#keyvals + 1] = k -- the quickest way to check if a number is an integer.
|
||||
end -- k % 1 ~= 0 is the fastest way to check if a number
|
||||
end -- is NOT an integer. > is proven slower.
|
||||
|
||||
keyvalsLen = #keyvals
|
||||
|
||||
-- Main chunk - no initial character.
|
||||
if not first then
|
||||
result[#result + 1] = "{"
|
||||
end
|
||||
|
||||
if jobstate[1] and jobstate[1][data] then
|
||||
if jobstate[2][data] then
|
||||
error("vON: Table #" .. jobstate[1][data] .. " written twice..?")
|
||||
end
|
||||
|
||||
result[#result + 1] = "#"
|
||||
result[#result + 1] = jobstate[1][data]
|
||||
result[#result + 1] = "#"
|
||||
|
||||
jobstate[2][data] = true
|
||||
end
|
||||
|
||||
-- Add numeric values.
|
||||
if len > 0 then
|
||||
for i = 1, len do
|
||||
val, lastType = s_anyVariable(data[i], lastType, true, false, i == len and not first, jobstate)
|
||||
result[#result + 1] = val
|
||||
end
|
||||
end
|
||||
|
||||
-- If there are key:value pairs.
|
||||
if keyvalsLen > 0 then
|
||||
-- Insert delimiter.
|
||||
result[#result + 1] = "~"
|
||||
|
||||
-- Insert key:value pairs.
|
||||
for _i = 1, keyvalsLen do
|
||||
keyvalsProgress = keyvalsProgress + 1
|
||||
|
||||
val, lastType = s_anyVariable(keyvals[_i], lastType, false, true, false, jobstate)
|
||||
|
||||
result[#result + 1] = val..":"
|
||||
|
||||
val, lastType = s_anyVariable(data[keyvals[_i]], lastType, false, false, keyvalsProgress == keyvalsLen and not first, jobstate)
|
||||
|
||||
result[#result + 1] = val
|
||||
end
|
||||
end
|
||||
|
||||
-- Main chunk needs no ending character.
|
||||
if not first then
|
||||
result[#result + 1] = "}"
|
||||
end
|
||||
|
||||
return concat(result)
|
||||
end,
|
||||
|
||||
-- Number which points to table.
|
||||
["table_reference"] = function(data, mustInitiate, isNumeric, isKey, isLast, first, jobstate)
|
||||
data = jobstate[1][data]
|
||||
|
||||
-- If a number hasn't been written before, add the type prefix.
|
||||
if mustInitiate then
|
||||
if isKey or isLast then
|
||||
return "$"..data
|
||||
else
|
||||
return "$"..data..";"
|
||||
end
|
||||
end
|
||||
|
||||
if isKey or isLast then
|
||||
return data
|
||||
else
|
||||
return data..";"
|
||||
end
|
||||
end,
|
||||
|
||||
|
||||
-- Normal concatenations is a lot faster with small strings than table.concat
|
||||
-- Also, not so branched-ish.
|
||||
["number"] = function(data, mustInitiate, isNumeric, isKey, isLast, first, jobstate)
|
||||
-- If a number hasn't been written before, add the type prefix.
|
||||
if mustInitiate then
|
||||
if isKey or isLast then
|
||||
return "n"..data
|
||||
else
|
||||
return "n"..data..";"
|
||||
end
|
||||
end
|
||||
|
||||
if isKey or isLast then
|
||||
return data
|
||||
else
|
||||
return data..";"
|
||||
end
|
||||
end,
|
||||
|
||||
|
||||
-- I hope gsub is fast enough.
|
||||
["string"] = function(data, mustInitiate, isNumeric, isKey, isLast, first, jobstate)
|
||||
if sub(data, #data, #data) == "\\" then -- Hah, old strings fix this best.
|
||||
return "\"" .. gsub(data, "\"", "\\\"") .. "v\""
|
||||
end
|
||||
|
||||
return "'" .. gsub(data, "\"", "\\\"") .. "\""
|
||||
end,
|
||||
|
||||
|
||||
-- Fastest.
|
||||
["boolean"] = function(data, mustInitiate, isNumeric, isKey, isLast, first, jobstate)
|
||||
-- Prefix if we must.
|
||||
if mustInitiate then
|
||||
if data then
|
||||
return "b1"
|
||||
else
|
||||
return "b0"
|
||||
end
|
||||
end
|
||||
|
||||
if data then
|
||||
return "1"
|
||||
else
|
||||
return "0"
|
||||
end
|
||||
end,
|
||||
|
||||
|
||||
-- Fastest.
|
||||
["nil"] = function(data, mustInitiate, isNumeric, isKey, isLast, first, jobstate)
|
||||
return "@"
|
||||
end,
|
||||
}
|
||||
|
||||
|
||||
|
||||
--[[ This section handles additions necessary for Garry's Mod. ]]
|
||||
|
||||
|
||||
|
||||
if gmod then -- Luckily, a specific table named after the game is present in Garry's Mod.
|
||||
local Entity = Entity
|
||||
|
||||
|
||||
|
||||
local extra_deserialize = {
|
||||
-- Entities are stored simply by the ID. They're meant to be transfered, not stored anyway.
|
||||
-- Exactly like a number definition, except it begins with "e".
|
||||
["Entity"] = function(s, i, len, unnecessaryEnd, jobstate)
|
||||
local i, a = i or 1
|
||||
-- Locals, locals, locals, locals
|
||||
|
||||
a = find(s, "[;:}~]", i)
|
||||
|
||||
if a then
|
||||
return Entity(tonumber(sub(s, i, a - 1))), a - 1
|
||||
end
|
||||
|
||||
error("vON: Entity ID definition started... Found no end.")
|
||||
end,
|
||||
|
||||
|
||||
-- A pair of 3 numbers separated by a comma (,).
|
||||
["Vector"] = function(s, i, len, unnecessaryEnd, jobstate)
|
||||
local i, a, x, y, z = i or 1
|
||||
-- Locals, locals, locals, locals
|
||||
|
||||
a = find(s, ",", i)
|
||||
|
||||
if a then
|
||||
x = tonumber(sub(s, i, a - 1))
|
||||
i = a + 1
|
||||
end
|
||||
|
||||
a = find(s, ",", i)
|
||||
|
||||
if a then
|
||||
y = tonumber(sub(s, i, a - 1))
|
||||
i = a + 1
|
||||
end
|
||||
|
||||
a = find(s, "[;:}~]", i)
|
||||
|
||||
if a then
|
||||
z = tonumber(sub(s, i, a - 1))
|
||||
end
|
||||
|
||||
if x and y and z then
|
||||
return Vector(x, y, z), a - 1
|
||||
end
|
||||
|
||||
error("vON: Vector definition started... Found no end.")
|
||||
end,
|
||||
|
||||
|
||||
-- A pair of 3 numbers separated by a comma (,).
|
||||
["Angle"] = function(s, i, len, unnecessaryEnd, jobstate)
|
||||
local i, a, p, y, r = i or 1
|
||||
-- Locals, locals, locals, locals
|
||||
|
||||
a = find(s, ",", i)
|
||||
|
||||
if a then
|
||||
p = tonumber(sub(s, i, a - 1))
|
||||
i = a + 1
|
||||
end
|
||||
|
||||
a = find(s, ",", i)
|
||||
|
||||
if a then
|
||||
y = tonumber(sub(s, i, a - 1))
|
||||
i = a + 1
|
||||
end
|
||||
|
||||
a = find(s, "[;:}~]", i)
|
||||
|
||||
if a then
|
||||
r = tonumber(sub(s, i, a - 1))
|
||||
end
|
||||
|
||||
if p and y and r then
|
||||
return Angle(p, y, r), a - 1
|
||||
end
|
||||
|
||||
error("vON: Angle definition started... Found no end.")
|
||||
end,
|
||||
}
|
||||
|
||||
local extra_serialize = {
|
||||
-- Same as numbers, except they start with "e" instead of "n".
|
||||
["Entity"] = function(data, mustInitiate, isNumeric, isKey, isLast, first, jobstate)
|
||||
data = data:EntIndex()
|
||||
|
||||
if mustInitiate then
|
||||
if isKey or isLast then
|
||||
return "e"..data
|
||||
else
|
||||
return "e"..data..";"
|
||||
end
|
||||
end
|
||||
|
||||
if isKey or isLast then
|
||||
return data
|
||||
else
|
||||
return data..";"
|
||||
end
|
||||
end,
|
||||
|
||||
|
||||
-- 3 numbers separated by a comma.
|
||||
["Vector"] = function(data, mustInitiate, isNumeric, isKey, isLast, first, jobstate)
|
||||
if mustInitiate then
|
||||
if isKey or isLast then
|
||||
return "v"..data.x..","..data.y..","..data.z
|
||||
else
|
||||
return "v"..data.x..","..data.y..","..data.z..";"
|
||||
end
|
||||
end
|
||||
|
||||
if isKey or isLast then
|
||||
return data.x..","..data.y..","..data.z
|
||||
else
|
||||
return data.x..","..data.y..","..data.z..";"
|
||||
end
|
||||
end,
|
||||
|
||||
|
||||
-- 3 numbers separated by a comma.
|
||||
["Angle"] = function(data, mustInitiate, isNumeric, isKey, isLast, first, jobstate)
|
||||
if mustInitiate then
|
||||
if isKey or isLast then
|
||||
return "a"..data.p..","..data.y..","..data.r
|
||||
else
|
||||
return "a"..data.p..","..data.y..","..data.r..";"
|
||||
end
|
||||
end
|
||||
|
||||
if isKey or isLast then
|
||||
return data.p..","..data.y..","..data.r
|
||||
else
|
||||
return data.p..","..data.y..","..data.r..";"
|
||||
end
|
||||
end,
|
||||
}
|
||||
|
||||
for k, v in pairs(extra_serialize) do
|
||||
_serialize[k] = v
|
||||
end
|
||||
|
||||
for k, v in pairs(extra_deserialize) do
|
||||
_deserialize[k] = v
|
||||
end
|
||||
|
||||
local extraEntityTypes = { "Vehicle", "Weapon", "NPC", "Player", "NextBot" }
|
||||
|
||||
for i = 1, #extraEntityTypes do
|
||||
_serialize[extraEntityTypes[i]] = _serialize.Entity
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
--[[ This section exposes the functions of the library. ]]
|
||||
|
||||
|
||||
|
||||
local function checkTableForRecursion(tab, checked, assoc)
|
||||
local id = checked.ID
|
||||
|
||||
if not checked[tab] and not assoc[tab] then
|
||||
assoc[tab] = id
|
||||
checked.ID = id + 1
|
||||
else
|
||||
checked[tab] = true
|
||||
end
|
||||
|
||||
for k, v in pairs(tab) do
|
||||
if type(k) == "table" and not checked[k] then
|
||||
checkTableForRecursion(k, checked, assoc)
|
||||
end
|
||||
|
||||
if type(v) == "table" and not checked[v] then
|
||||
checkTableForRecursion(v, checked, assoc)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
local _s_table = _serialize.table
|
||||
local _d_table = _deserialize.table
|
||||
|
||||
_d_meta = {
|
||||
__call = function(self, str, allowIdRewriting)
|
||||
if type(str) == "string" then
|
||||
return _d_table(str, nil, #str, true, {{}, allowIdRewriting})
|
||||
end
|
||||
|
||||
error("vON: You must deserialize a string, not a "..type(str))
|
||||
end
|
||||
}
|
||||
_s_meta = {
|
||||
__call = function(self, data, checkRecursion)
|
||||
if type(data) == "table" then
|
||||
if checkRecursion then
|
||||
local assoc, checked = {}, {ID = 1}
|
||||
|
||||
checkTableForRecursion(data, checked, assoc)
|
||||
|
||||
return _s_table(data, nil, nil, nil, nil, true, {assoc, {}})
|
||||
end
|
||||
|
||||
return _s_table(data, nil, nil, nil, nil, true, {false})
|
||||
end
|
||||
|
||||
error("vON: You must serialize a table, not a "..type(data))
|
||||
end
|
||||
}
|
||||
|
||||
|
||||
|
||||
local von = {
|
||||
version = "1.3.4",
|
||||
versionNumber = 1003004, -- Reserving 3 digits per version component.
|
||||
|
||||
deserialize = setmetatable(_deserialize,_d_meta),
|
||||
serialize = setmetatable(_serialize,_s_meta)
|
||||
}
|
||||
|
||||
|
||||
|
||||
return von
|
||||
429
lua/sam/importers/ulx/main.lua
Normal file
429
lua/sam/importers/ulx/main.lua
Normal file
@@ -0,0 +1,429 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
-- PLEASE READ
|
||||
-- PLEASE READ
|
||||
-- PLEASE READ
|
||||
-- PLEASE READ
|
||||
|
||||
-- Set the timing module to import times from when importing users
|
||||
-- Supported modules: "utime"
|
||||
-- If your timing module is not here then STOP and make a support ticket so I can add support for it before you import your users
|
||||
local TIME_MODULE = "utime" -- Set this to nil if you don't want to import times
|
||||
|
||||
-- PLEASE READ
|
||||
-- PLEASE READ
|
||||
-- PLEASE READ
|
||||
-- PLEASE READ
|
||||
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
local sam, SQL = sam, sam.SQL
|
||||
|
||||
local ulib_unescape_backslash = function(s)
|
||||
return s:gsub("\\\\", "\\")
|
||||
end
|
||||
|
||||
local ulib_explode = function(separator, str, limit)
|
||||
local t = {}
|
||||
local curpos = 1
|
||||
while true do -- We have a break in the loop
|
||||
local newpos, endpos = str:find(separator, curpos) -- find the next separator in the string
|
||||
if newpos ~= nil then -- if found then..
|
||||
table.insert(t, str:sub(curpos, newpos - 1)) -- Save it in our table.
|
||||
curpos = endpos + 1 -- save just after where we found it for searching next time.
|
||||
else
|
||||
if limit and #t > limit then
|
||||
return t -- Reached limit
|
||||
end
|
||||
table.insert(t, str:sub(curpos)) -- Save what's left in our array.
|
||||
break
|
||||
end
|
||||
end
|
||||
return t
|
||||
end
|
||||
|
||||
local ulib_split_args = function(args, start_token, end_token)
|
||||
args = args:Trim()
|
||||
local argv = {}
|
||||
local curpos = 1 -- Our current position within the string
|
||||
local in_quote = false -- Is the text we're currently processing in a quote?
|
||||
start_token = start_token or "\""
|
||||
end_token = end_token or "\""
|
||||
local args_len = args:len()
|
||||
|
||||
while in_quote or curpos <= args_len do
|
||||
local quotepos = args:find(in_quote and end_token or start_token, curpos, true)
|
||||
|
||||
-- The string up to the quote, the whole string if no quote was found
|
||||
local prefix = args:sub(curpos, (quotepos or 0) - 1)
|
||||
if not in_quote then
|
||||
local trimmed = prefix:Trim()
|
||||
if trimmed ~= "" then -- Something to be had from this...
|
||||
local t = ulib_explode("%s+", trimmed)
|
||||
table.Add(argv, t)
|
||||
end
|
||||
else
|
||||
table.insert(argv, prefix)
|
||||
end
|
||||
|
||||
-- If a quote was found, reduce our position and note our state
|
||||
if quotepos ~= nil then
|
||||
curpos = quotepos + 1
|
||||
in_quote = not in_quote
|
||||
else -- Otherwise we've processed the whole string now
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
return argv, in_quote
|
||||
end
|
||||
|
||||
local ulib_parse_key_values = function(str, convert)
|
||||
local lines = ulib_explode("\r?\n", str)
|
||||
local parent_tables = {} -- Traces our way to root
|
||||
local current_table, n = {}, 0
|
||||
local is_insert_last_op = false
|
||||
local tmp_string = string.char(01, 02, 03) -- Replacement
|
||||
|
||||
for i, line in ipairs(lines) do
|
||||
local tokens = ulib_split_args((line:gsub("\\\"", tmp_string)))
|
||||
|
||||
for i, token in ipairs(tokens) do
|
||||
tokens[ i ] = ulib_unescape_backslash(token):gsub(tmp_string, "\"")
|
||||
end
|
||||
|
||||
local num_tokens = #tokens
|
||||
|
||||
if num_tokens == 1 then
|
||||
local token = tokens[ 1 ]
|
||||
if token == "{" then
|
||||
local new_table = {}
|
||||
if is_insert_last_op then
|
||||
current_table[ table.remove(current_table) ] = new_table
|
||||
else
|
||||
table.insert(current_table, new_table)
|
||||
end
|
||||
is_insert_last_op = false
|
||||
table.insert(parent_tables, current_table)
|
||||
current_table = new_table
|
||||
|
||||
elseif token == "}" then
|
||||
is_insert_last_op = false
|
||||
current_table = table.remove(parent_tables)
|
||||
if current_table == nil then
|
||||
return nil, "Mismatched recursive tables on line " .. i
|
||||
end
|
||||
|
||||
else
|
||||
is_insert_last_op = true
|
||||
table.insert(current_table, tokens[ 1 ])
|
||||
end
|
||||
|
||||
elseif num_tokens == 2 then
|
||||
is_insert_last_op = false
|
||||
if convert and tonumber(tokens[ 1 ]) then
|
||||
tokens[ 1 ] = tonumber(tokens[ 1 ])
|
||||
end
|
||||
|
||||
current_table[ tokens[ 1 ] ] = tokens[ 2 ]
|
||||
|
||||
elseif num_tokens > 2 then
|
||||
return nil, "Bad input on line " .. i
|
||||
end
|
||||
end
|
||||
|
||||
if #parent_tables ~= 0 then
|
||||
return nil, "Mismatched recursive tables"
|
||||
end
|
||||
|
||||
if convert and n == 1 and
|
||||
type(current_table.Out) == "table" then -- If we caught a stupid garry-wrapper
|
||||
|
||||
current_table = current_table.Out
|
||||
end
|
||||
|
||||
return current_table
|
||||
end
|
||||
|
||||
local ulib_remove_comment_header = function(data, comment_char)
|
||||
comment_char = comment_char or ";"
|
||||
local lines = ulib_explode("\r?\n", data)
|
||||
local end_comment_line = 0
|
||||
for _, line in ipairs(lines) do
|
||||
local trimmed = line:Trim()
|
||||
if trimmed == "" or trimmed:sub(1, 1) == comment_char then
|
||||
end_comment_line = end_comment_line + 1
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
local not_comment = table.concat(lines, "\n", end_comment_line + 1)
|
||||
return not_comment:Trim()
|
||||
end
|
||||
|
||||
local no_bans_msg = "No bans to import from ulx."
|
||||
local import_bans = function()
|
||||
sam.print("Importing bans...")
|
||||
|
||||
if not sql.TableExists("ulib_bans") then
|
||||
return sam.print(no_bans_msg)
|
||||
end
|
||||
|
||||
local bans = sql.Query("SELECT `steamid`, `unban`, `reason`, `admin` FROM `ulib_bans`")
|
||||
|
||||
if not sam.istable(bans) then
|
||||
return sam.print(no_bans_msg)
|
||||
end
|
||||
|
||||
local bans_count = #bans
|
||||
|
||||
if bans_count == 0 then
|
||||
return sam.print(no_bans_msg)
|
||||
end
|
||||
|
||||
local began, imported_count = false, 0
|
||||
|
||||
for i = 1, bans_count do
|
||||
local ban = bans[i]
|
||||
local steamid = ban.steamid
|
||||
|
||||
if sam.is_steamid64(steamid) then
|
||||
steamid = util.SteamIDFrom64(ban.steamid)
|
||||
end
|
||||
|
||||
if sam.is_steamid(steamid) then
|
||||
if not began then
|
||||
began = true
|
||||
SQL.Begin()
|
||||
SQL.Query([[
|
||||
DELETE FROM `sam_bans`
|
||||
]])
|
||||
end
|
||||
|
||||
local name, reason, admin, unban_date = ban.name, ban.reason, ban.admin, tonumber(ban.unban)
|
||||
|
||||
if name == "NULL" then
|
||||
name = ""
|
||||
end
|
||||
|
||||
if reason == "NULL" then
|
||||
reason = "none"
|
||||
end
|
||||
|
||||
if sam.isstring(admin) and admin ~= "NULL" and admin ~= "(Console)" then
|
||||
admin = admin:match("%(STEAM_%w:%w:%w*%)"):sub(2, -2)
|
||||
else
|
||||
admin = "Console"
|
||||
end
|
||||
|
||||
if not sam.isnumber(unban_date) or unban_date < 0 then
|
||||
unban_date = 0
|
||||
end
|
||||
|
||||
SQL.FQuery([[
|
||||
INSERT INTO
|
||||
`sam_bans`(
|
||||
`steamid`,
|
||||
`reason`,
|
||||
`admin`,
|
||||
`unban_date`
|
||||
)
|
||||
VALUES
|
||||
({1}, {2}, {3}, {4})
|
||||
]], {steamid, reason, admin, unban_date})
|
||||
|
||||
imported_count = imported_count + 1
|
||||
end
|
||||
end
|
||||
|
||||
if began then
|
||||
SQL.Commit(function()
|
||||
sam.print("Imported " .. imported_count .. " ban(s).")
|
||||
end)
|
||||
else
|
||||
sam.print(no_bans_msg)
|
||||
end
|
||||
end
|
||||
|
||||
local groups_path = "ulib/groups.txt"
|
||||
local no_ranks_msg = "No ranks to import from ulx."
|
||||
|
||||
local imported_ranks
|
||||
|
||||
local function add_rank(rank, info, ranks)
|
||||
if not sam.ranks.is_rank(rank) then
|
||||
local inherit = info.inherit_from
|
||||
if inherit and ranks[inherit] and not sam.ranks.is_rank(inherit) then
|
||||
add_rank(inherit, ranks[inherit], ranks)
|
||||
end
|
||||
imported_ranks = imported_ranks + 1
|
||||
sam.ranks.add_rank(rank, inherit)
|
||||
end
|
||||
end
|
||||
|
||||
local import_ranks = function()
|
||||
sam.print("Importing ranks...")
|
||||
|
||||
if not file.Exists(groups_path, "DATA") then
|
||||
return sam.print(no_ranks_msg)
|
||||
end
|
||||
|
||||
local ranks_text = file.Read(groups_path, "DATA")
|
||||
|
||||
if not sam.isstring(ranks_text) then
|
||||
return sam.print(no_ranks_msg)
|
||||
end
|
||||
|
||||
local ranks, err = ulib_parse_key_values(ulib_remove_comment_header(ranks_text, "/"))
|
||||
if not ranks then
|
||||
return sam.print("ULX ranks file was not formatted correctly, make a support ticket. (include the error message if there is one)" .. (err and (" | error: " .. err) or ""))
|
||||
end
|
||||
|
||||
imported_ranks = 0
|
||||
|
||||
for rank, info in pairs(ranks) do
|
||||
if not sam.ranks.is_rank(rank) then
|
||||
add_rank(rank, info, ranks)
|
||||
end
|
||||
end
|
||||
|
||||
if imported_ranks == 0 then
|
||||
sam.print(no_ranks_msg)
|
||||
else
|
||||
sam.print("Imported " .. imported_ranks .. " rank(s).")
|
||||
end
|
||||
end
|
||||
|
||||
local users_path = "ulib/users.txt"
|
||||
local no_users_msg = "No users to import from ulx."
|
||||
|
||||
local import_users = function()
|
||||
sam.print("Importing users...")
|
||||
|
||||
if not file.Exists(users_path, "DATA") then
|
||||
return sam.print(no_users_msg)
|
||||
end
|
||||
|
||||
local users_text = file.Read(users_path, "DATA")
|
||||
|
||||
if not sam.isstring(users_text) then
|
||||
return sam.print(no_users_msg)
|
||||
end
|
||||
|
||||
local users, err = ulib_parse_key_values(ulib_remove_comment_header(users_text, "/"))
|
||||
if not users then
|
||||
return sam.print("ULX users file was not formatted correctly, make a support ticket. (include the error message if there is one)" .. (err and (" | error: " .. err) or ""))
|
||||
end
|
||||
|
||||
local current_time = os.time()
|
||||
local imported_users = 0
|
||||
|
||||
local times = false
|
||||
|
||||
if TIME_MODULE == "utime" then
|
||||
local utime = sql.Query("SELECT `player`, `lastvisit`, `totaltime` FROM `utime`")
|
||||
if sam.istable(utime) then
|
||||
times = {}
|
||||
for i = 1, #utime do
|
||||
local v = utime[i]
|
||||
times[v.player] = v
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local began = false
|
||||
|
||||
for steamid, info in pairs(users) do
|
||||
if sam.is_steamid64(steamid) then
|
||||
steamid = util.SteamIDFrom64(steamid)
|
||||
end
|
||||
|
||||
if sam.is_steamid(steamid) then
|
||||
if not began then
|
||||
began = true
|
||||
SQL.Begin()
|
||||
SQL.Query([[
|
||||
DELETE FROM `sam_players`
|
||||
]])
|
||||
end
|
||||
|
||||
local first_join, last_join, play_time = current_time, current_time, 0
|
||||
|
||||
if times and TIME_MODULE == "utime" then
|
||||
local utime_user = times[util.CRC("gm_" .. steamid .. "_gm")]
|
||||
if utime_user then
|
||||
last_join, play_time = utime_user.lastvisit, math.floor(utime_user.totaltime)
|
||||
first_join = last_join
|
||||
end
|
||||
end
|
||||
|
||||
local rank = info.group
|
||||
if not rank or not sam.ranks.is_rank(rank) then
|
||||
rank = "user"
|
||||
end
|
||||
|
||||
SQL.FQuery([[
|
||||
INSERT INTO
|
||||
`sam_players`(
|
||||
`steamid`,
|
||||
`name`,
|
||||
`rank`,
|
||||
`expiry_date`,
|
||||
`first_join`,
|
||||
`last_join`,
|
||||
`play_time`
|
||||
)
|
||||
VALUES
|
||||
({1}, {2}, {3}, {4}, {5}, {6}, {7})
|
||||
]], {steamid, info.name or "", rank, 0, first_join, last_join, play_time})
|
||||
|
||||
imported_users = imported_users + 1
|
||||
end
|
||||
end
|
||||
|
||||
if began then
|
||||
SQL.Commit(function()
|
||||
sam.print("Imported " .. imported_users .. " user(s).")
|
||||
end)
|
||||
else
|
||||
sam.print(no_users_msg)
|
||||
end
|
||||
end
|
||||
|
||||
if not sam.ranks.ranks_loaded() then
|
||||
return sam.print("Server is connecting to the Database, try again when it connects.")
|
||||
end
|
||||
|
||||
for k, v in ipairs(player.GetAll()) do
|
||||
v:Kick("Importing data.")
|
||||
end
|
||||
|
||||
for k, v in pairs(sam.get_connected_players()) do
|
||||
sam.player.kick_id(k, "Importing data.")
|
||||
end
|
||||
|
||||
hook.Add("CheckPassword", "SAM.ImportingData", function()
|
||||
return false, "Importing data."
|
||||
end)
|
||||
|
||||
sam.print("Starting to import data from ulx...")
|
||||
timer.Simple(0, function()
|
||||
import_bans()
|
||||
import_ranks()
|
||||
import_users()
|
||||
|
||||
hook.Remove("CheckPassword", "SAM.ImportingData")
|
||||
end)
|
||||
213
lua/sam/importers/xadmin/main.lua
Normal file
213
lua/sam/importers/xadmin/main.lua
Normal file
@@ -0,0 +1,213 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
--
|
||||
-- CONFIG
|
||||
--
|
||||
|
||||
local UsersTableName = "xadminusers"
|
||||
local GroupsTableName = "xadmingroups"
|
||||
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
local sam, SQL = sam, sam.SQL
|
||||
|
||||
local no_bans_msg = "No bans to import from xadmin."
|
||||
local import_bans = function()
|
||||
SQL.TableExists("xadminbans", function(exists)
|
||||
if not exists then
|
||||
return sam.print(no_bans_msg)
|
||||
end
|
||||
|
||||
SQL.Query([[
|
||||
SELECT
|
||||
`SteamID`,
|
||||
`Admin`,
|
||||
`Reason`,
|
||||
`EndTime`
|
||||
FROM
|
||||
`xadminbans`
|
||||
]], function(xadmin_bans)
|
||||
SQL.Begin()
|
||||
|
||||
SQL.Query([[
|
||||
DELETE FROM `sam_bans`
|
||||
]])
|
||||
|
||||
local args, steamid, admin = {}, nil, nil
|
||||
for _, v in ipairs(xadmin_bans) do
|
||||
steamid, admin = util.SteamIDFrom64(v.SteamID), v.Admin
|
||||
|
||||
if admin == "CONSOLE" then
|
||||
admin = "Console"
|
||||
else
|
||||
admin = util.SteamIDFrom64(admin)
|
||||
end
|
||||
|
||||
args[1] = steamid
|
||||
args[2] = v.Reason
|
||||
args[3] = admin
|
||||
args[4] = v.EndTime
|
||||
|
||||
SQL.FQuery([[
|
||||
INSERT INTO
|
||||
`sam_bans`(
|
||||
`steamid`,
|
||||
`reason`,
|
||||
`admin`,
|
||||
`unban_date`
|
||||
)
|
||||
VALUES
|
||||
({1}, {2}, {3}, {4})
|
||||
]], args)
|
||||
end
|
||||
|
||||
SQL.Commit(function()
|
||||
sam.print("Imported bans from xadmin.")
|
||||
end)
|
||||
end)
|
||||
end):wait()
|
||||
end
|
||||
|
||||
local get_rank = function(rank)
|
||||
if rank == "Super Admin" then
|
||||
return "superadmin"
|
||||
elseif rank == "Admin" then
|
||||
return "admin"
|
||||
elseif rank == "Moderator" then
|
||||
return "moderator"
|
||||
elseif rank == "User" then
|
||||
return "user"
|
||||
end
|
||||
return rank
|
||||
end
|
||||
|
||||
local no_ranks_msg = "No ranks to import from xadmin."
|
||||
local import_ranks = function()
|
||||
SQL.TableExists(GroupsTableName, function(exists)
|
||||
if not exists then
|
||||
return sam.print(no_ranks_msg)
|
||||
end
|
||||
|
||||
SQL.Query(([[
|
||||
SELECT
|
||||
`Name`,
|
||||
`Power`
|
||||
FROM
|
||||
`%s`
|
||||
]]):format(GroupsTableName), function(xadmin_ranks)
|
||||
for _, v in ipairs(xadmin_ranks) do
|
||||
local name = get_rank(v.Name)
|
||||
|
||||
if not sam.ranks.is_rank(name) then
|
||||
sam.ranks.add_rank(name, "user", tonumber(v.Power), 20160)
|
||||
end
|
||||
end
|
||||
|
||||
sam.print("Imported ranks from xadmin.")
|
||||
end):wait()
|
||||
end):wait()
|
||||
end
|
||||
|
||||
local no_users_msg = "No users to import from xadmin."
|
||||
local import_users = function()
|
||||
SQL.TableExists(UsersTableName, function(exists)
|
||||
if not exists then
|
||||
return sam.print(no_users_msg)
|
||||
end
|
||||
|
||||
SQL.Query(([[
|
||||
SELECT
|
||||
`%s`.`SteamID`,
|
||||
`%s`.`AccessLevel`,
|
||||
IFNULL(SUM(`time`), 0) `total`
|
||||
FROM
|
||||
`%s`
|
||||
|
||||
LEFT OUTER JOIN `xadmintimetracking` `times`
|
||||
on `%s`.`SteamID` = `times`.`SteamID`
|
||||
|
||||
GROUP BY
|
||||
`%s`.`SteamID`
|
||||
]]):format(UsersTableName, UsersTableName, UsersTableName, UsersTableName, UsersTableName), function(xadmin_players)
|
||||
SQL.Begin()
|
||||
|
||||
SQL.Query([[
|
||||
DELETE FROM `sam_players`
|
||||
]])
|
||||
|
||||
local args = {}
|
||||
args[2] = ""
|
||||
args[4] = 0
|
||||
args[5] = os.time()
|
||||
args[6] = os.time()
|
||||
|
||||
for k, v in ipairs(xadmin_players) do
|
||||
args[1] = v.SteamID
|
||||
|
||||
local rank = get_rank(v.AccessLevel)
|
||||
if not sam.ranks.is_rank(rank) then
|
||||
rank = "user"
|
||||
end
|
||||
|
||||
args[3] = rank
|
||||
args[7] = v.total
|
||||
|
||||
SQL.FQuery([[
|
||||
INSERT INTO
|
||||
`sam_players`(
|
||||
`steamid`,
|
||||
`name`,
|
||||
`rank`,
|
||||
`expiry_date`,
|
||||
`first_join`,
|
||||
`last_join`,
|
||||
`play_time`
|
||||
)
|
||||
VALUES
|
||||
({1}, {2}, {3}, {4}, {5}, {6}, {7})
|
||||
]], args)
|
||||
end
|
||||
|
||||
SQL.Commit(function()
|
||||
sam.print("Imported users from xadmin.")
|
||||
end)
|
||||
end):wait()
|
||||
end):wait()
|
||||
end
|
||||
|
||||
if not sam.ranks.ranks_loaded() then
|
||||
return sam.print("Server is connecting to the Database, try again when it connects.")
|
||||
end
|
||||
|
||||
for k, v in ipairs(player.GetAll()) do
|
||||
v:Kick("Importing data.")
|
||||
end
|
||||
|
||||
for k, v in pairs(sam.get_connected_players()) do
|
||||
sam.player.kick_id(k, "Importing data.")
|
||||
end
|
||||
|
||||
hook.Add("CheckPassword", "SAM.ImportingData", function()
|
||||
return false, "Importing data."
|
||||
end)
|
||||
|
||||
sam.print("Starting to import data from xadmin...")
|
||||
timer.Simple(0, function()
|
||||
import_bans()
|
||||
import_ranks()
|
||||
import_users()
|
||||
|
||||
hook.Remove("CheckPassword", "SAM.ImportingData")
|
||||
end)
|
||||
Reference in New Issue
Block a user