5 Commits

Author SHA1 Message Date
lifestorm
7d5fe64891 Update README.md 2024-08-05 18:54:00 +03:00
lifestorm
43711b24fe Update README.md 2024-08-05 08:35:51 +03:00
lifestorm
62ff43d321 Delete s21_sam_french.sql 2024-08-05 08:34:15 +03:00
lifestorm
37c7fc044a Add files via upload 2024-08-05 00:30:02 +03:00
lifestorm
94063e4369 Upload 2024-08-04 22:55:00 +03:00
5721 changed files with 844162 additions and 978695 deletions

View File

@@ -1,11 +1,11 @@
# Willard Networks: Development Server
This branch contains files related to the **Willard Networks: Development server**. They were retrieved on 2024/08/05 and are presented as is with minimal edits. This means that potential developers' bugs have been kept in their original form and it is up to you to resolve them. We do not and will not provide direct support (i.e. regular updates or patches). However, you can always create an issue, pointing out the problem.
# Willard Networks: France (Echo One)
This branch contains files related to the **Willard Networks: Echo One**. They were retrieved on 2024/08/04 and are presented as is with minimal edits. This means that potential developers' bugs have been kept in their original form and it is up to you to resolve them. We do not and will not provide direct support (i.e. regular updates or patches). However, you can always create an issue, pointing out the problem.
**The files provided contain:**
* Half-Life 2 RPG framework by Willard Networks, used on development server as of 2024/08/05 in English.
* Settings (data/\*, settings/\*) used on the development server as of 2024/08/05.
* Credentials from the development server database (including the master and SAM database).
* Helix logs (data/helix/logs) from the development server as of 2024/08/05.
* Half-Life 2 RPG framework by Willard Networks, used on the French server as of 2024/08/04.
* Settings (data/\*, settings/\*) used on the French server as of 2024/08/04.
* Credentials from the French server database (including the master and SAM database).
* Helix logs (data/helix/logs) from the French server as of 2024/08/04.
**The files provided do not contain:**
* Exported dump of databases (including the master and SAM database), since these files are overweight and cannot be uploaded to GitHub. Despite this, it is included in builds distributed via [The Twilight Zone](https://wnsrc.plymouth.thetwilightzone.ru/).

View File

@@ -1,12 +0,0 @@
--[[
| 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 slib and slib.loadFolder then slib.loadFolder("e_protect/", true) end
hook.Add("slib:loadedUtils", "eP:Initialize", function() slib.loadFolder("e_protect/", true) end)

View File

@@ -1,940 +0,0 @@
--[[
| 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/
--]]
eProtect = eProtect or {}
eProtect.data = eProtect.data or {}
local function networkData(data, ...)
local args = {...}
net.Start("eP:Handeler")
net.WriteBit(1)
net.WriteUInt(1, 2)
net.WriteUInt(#args, 3)
for k,v in pairs(args) do
net.WriteString(v)
end
local statement = slib.getStatement(data)
if statement == "bool" then
net.WriteUInt(1, 2)
net.WriteBool(data)
elseif statement == "int" then
net.WriteUInt(2, 2)
net.WriteInt(data, 32)
elseif statement == "table" or statement == "color" then
net.WriteUInt(3, 2)
data = table.Copy(data)
local converted_tbl = {}
for k,v in pairs(data) do
local isSID = util.SteamIDFrom64(k) != "STEAM_0:0:0"
if isSID then
converted_tbl["sid64_"..k] = v
else
converted_tbl[k] = v
end
end
data = converted_tbl
data = util.Compress(util.TableToJSON(data))
net.WriteUInt(#data, 32)
net.WriteData(data, #data)
end
net.SendToServer()
end
local convertedTbl
convertedTbl = function(tbl)
local converted_tbl = {}
for k, v in pairs(tbl) do
if istable(v) then v = convertedTbl(v) end
if string.sub(k, 1, 6) == "sid64_" then
local sid64 = string.sub(k, 7, #k)
if util.SteamIDFrom64(sid64) != "STEAM_0:0:0" then
k = sid64
end
end
converted_tbl[k] = v
end
return converted_tbl
end
local function openScreenshot(ply, id)
if !IsValid(ply) then return end
http.Fetch("https://stromic.dev/eprotect/img.php?id="..id, function(result)
local sc_frame = vgui.Create("SFrame")
sc_frame:SetSize(slib.getScaledSize(960, "x"), slib.getScaledSize(540, "y") + slib.getScaledSize(25, "y"))
:setTitle(slib.getLang("eprotect", eProtect.config["language"], "sc-preview")..ply:Nick())
:MakePopup()
:addCloseButton()
:Center()
:setBlur(true)
local display = vgui.Create("HTML", sc_frame.frame)
display:Dock(FILL)
display:SetHTML([[<img src="data:image/jpeg;base64,]] ..result.. [[" style="height:]]..(sc_frame.frame:GetTall())..[[px;width:]]..(sc_frame.frame:GetWide())..[[px;position:fixed;top:0px;left:0px">]])
end)
end
local function sid64format(sid64)
return slib.findName(sid64).." ("..sid64..")"
end
local function fillCleanData(index, tbl)
local files, directories = file.Find(index, "DATA")
if files then
for k,v in pairs(files) do
tbl[v] = true
end
end
if index == "*" then index = "" end
local attribute = !index and "/" or ""
if directories then
for k,v in pairs(directories) do
tbl[v] = tbl[v] or {}
fillCleanData(index..attribute..v.."/*", tbl[v])
end
end
end
local margin = slib.getTheme("margin")
local maincolor_7, maincolor_10, hovercolor, linecol = slib.getTheme("maincolor", 7), slib.getTheme("maincolor", 10), slib.getTheme("hovercolor"), Color(0,0,0,160)
local arrow_ico = Material("slib/down-arrow.png", "smooth noclamp")
local createPaginator = function(parent)
local font = slib.createFont("Roboto", 16)
local paginator_tall = slib.getScaledSize(25, "y")
local paginator = vgui.Create("EditablePanel", parent)
paginator:Dock(BOTTOM)
paginator:DockPadding(margin,margin,margin,margin)
paginator:SetTall(paginator_tall)
paginator.page = 1
paginator.maxpage = 5
paginator.Paint = function(s,w,h)
surface.SetDrawColor(linecol)
surface.DrawRect(0,0,w,1)
draw.SimpleText(slib.getLang("eprotect", eProtect.config["language"], "page_of_page", s.page, s.maxpage), font, w * .5, h * .5, color_white, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
end
surface.SetFont(font)
local prev_w = select(1, surface.GetTextSize(slib.getLang("eprotect", eProtect.config["language"], "previous")))
local next_w = select(1, surface.GetTextSize(slib.getLang("eprotect", eProtect.config["language"], "next")))
local left = vgui.Create("SButton", paginator)
:Dock(LEFT)
:SetWide(paginator_tall + prev_w)
local ico_size = paginator:GetTall() * .5
left.Paint = function(s,w,h)
surface.SetDrawColor(maincolor_7)
surface.DrawRect(0,0,w,h)
local hover = s:IsHovered()
local curCol = slib.lerpColor(s, hover and hovercolor or color_white)
s.move = s.move or 1
s.move = math.Clamp(hover and s.move + .05 or s.move - .05, 0, 2)
surface.SetDrawColor(curCol)
surface.SetMaterial(arrow_ico)
surface.DrawTexturedRectRotated(h * .5 - s.move, h * .5,ico_size ,ico_size, -90)
draw.SimpleText(slib.getLang("eprotect", eProtect.config["language"], "previous"), font, w - margin, h * .5, curCol, TEXT_ALIGN_RIGHT, TEXT_ALIGN_CENTER)
end
left.DoClick = function()
if paginator.page <= 1 then return end
local nextpage = paginator.page - 1
paginator.onPageChanged(nextpage)
end
local right = vgui.Create("SButton", paginator)
:Dock(RIGHT)
:SetWide(paginator_tall + next_w)
right.Paint = function(s,w,h)
surface.SetDrawColor(maincolor_7)
surface.DrawRect(0,0,w,h)
local hover = s:IsHovered()
local curCol = slib.lerpColor(s, hover and hovercolor or color_white)
s.move = s.move or 1
s.move = math.Clamp(hover and s.move + .05 or s.move - .05, 0, 2)
surface.SetDrawColor(curCol)
surface.SetMaterial(arrow_ico)
surface.DrawTexturedRectRotated(w - (h * .5 - s.move), h * .5,ico_size ,ico_size, 90)
draw.SimpleText(slib.getLang("eprotect", eProtect.config["language"], "next"), font, margin, h * .5, curCol, TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER)
end
right.DoClick = function()
if paginator.page >= paginator.maxpage then return end
local nextpage = paginator.page + 1
paginator.onPageChanged(nextpage)
end
return paginator
end
local function showID(ply, id)
id = util.JSONToTable(util.Base64Decode(id))
if !id or !istable(id) then slib.notify(eProtect.config["prefix"]..slib.getLang("eprotect", eProtect.config["language"], "ply-sent-invalid-data")) return end
local id_list = vgui.Create("SFrame")
id_list:SetSize(slib.getScaledSize(500, "x"),slib.getScaledSize(330, "y"))
:Center()
:MakePopup()
:addCloseButton()
:setTitle(slib.getLang("eprotect", eProtect.config["language"], "id-info")..ply:Nick(), slib.createFont("Roboto", 17))
:setBlur(true)
local id_details = vgui.Create("SListView", id_list.frame)
id_details:Dock(FILL)
:addColumns(slib.getLang("eprotect", eProtect.config["language"], "player"), slib.getLang("eprotect", eProtect.config["language"], "date"))
for i, z in pairs(id) do
local sid64 = util.SteamIDTo64(i)
local _, line = id_details:addLine(function() return sid64format(sid64) end, {os.date("%H:%M:%S - %d/%m/%Y", z), z})
line.DoClick = function()
gui.OpenURL("http://steamcommunity.com/profiles/"..sid64)
end
line:SetZPos(z)
end
end
local function showCorrelation(ply, data)
data = util.JSONToTable(util.Base64Decode(data))
if !data or !istable(data) then return end
local correlation_list = vgui.Create("SFrame")
correlation_list:SetSize(slib.getScaledSize(450, "x"),slib.getScaledSize(330, "y"))
:Center()
:MakePopup()
:addCloseButton()
:setTitle(slib.getLang("eprotect", eProtect.config["language"], "ip-correlation")..ply:Nick(), slib.createFont("Roboto", 17))
:setBlur(true)
local correlation_details = vgui.Create("SListView", correlation_list.frame)
correlation_details:Dock(FILL)
:addColumns(slib.getLang("eprotect", eProtect.config["language"], "player"), slib.getLang("eprotect", eProtect.config["language"], "ip"))
for k, v in ipairs(data) do
local _, line = correlation_details:addLine(function() return sid64format(v.sid64) end, v.ip)
line.DoClick = function()
gui.OpenURL("http://steamcommunity.com/profiles/"..v.sid64)
end
line:SetZPos(z)
end
end
local function showIPs(ply, data)
data = util.JSONToTable(util.Base64Decode(data))
if !data or !istable(data) then return end
local ip_list = vgui.Create("SFrame")
ip_list:SetSize(slib.getScaledSize(400, "x"),slib.getScaledSize(280, "y"))
:Center()
:MakePopup()
:addCloseButton()
:setTitle(slib.getLang("eprotect", eProtect.config["language"], "ip-info")..ply:Nick(), slib.createFont("Roboto", 17))
:setBlur(true)
local ip_details = vgui.Create("SListView", ip_list.frame)
ip_details:Dock(FILL)
:addColumns(slib.getLang("eprotect", eProtect.config["language"], "country-code"), slib.getLang("eprotect", eProtect.config["language"], "ip"), slib.getLang("eprotect", eProtect.config["language"], "date"))
for k, v in pairs(data) do
local _, line = ip_details:addLine(v.country, v.ip, {os.date("%H:%M:%S - %d/%m/%Y", v.logged_time), v.logged_time})
line.DoClick = function()
gui.OpenURL("https://whatismyipaddress.com/ip/"..v.ip)
end
line:SetZPos(v.logged_time)
end
end
local requestLogData = function(id, page, search)
net.Start("eP:Handeler")
net.WriteBit(1)
net.WriteUInt(0, 2)
net.WriteUInt(id, 1)
net.WriteUInt(page, 15)
net.WriteString(search)
net.SendToServer()
end
local eprotect_menu
local function openMenu()
eprotect_menu = vgui.Create("SFrame")
eprotect_menu:SetSize(slib.getScaledSize(720, "x"),slib.getScaledSize(530, "y"))
:setTitle("eProtect")
:Center()
:addCloseButton()
:MakePopup()
:addTab(slib.getLang("eprotect", eProtect.config["language"], "tab-general"), "eprotect/tabs/general.png")
if !eProtect.config["disabledModules"]["identifier"] then
eprotect_menu:addTab(slib.getLang("eprotect", eProtect.config["language"], "tab-identifier"), "eprotect/tabs/identifier.png")
end
if !eProtect.config["disabledModules"]["detection_log"] then
eprotect_menu:addTab(slib.getLang("eprotect", eProtect.config["language"], "tab-detectionlog"), "eprotect/tabs/detectionlog.png")
end
if !eProtect.config["disabledModules"]["net_limiter"] then
eprotect_menu:addTab(slib.getLang("eprotect", eProtect.config["language"], "tab-netlimiter"),"eprotect/tabs/netlimit.png")
end
if !eProtect.config["disabledModules"]["net_logger"] then
eprotect_menu:addTab(slib.getLang("eprotect", eProtect.config["language"], "tab-netlogger"), "eprotect/tabs/netlog.png")
end
if !eProtect.config["disablehttplogging"] and ((!VC and !XEON and !mLib) or eProtect.config["ignoreDRM"]) then
eprotect_menu:addTab(slib.getLang("eprotect", eProtect.config["language"], "tab-httplogger"), "eprotect/tabs/httplog.png")
end
if !eProtect.config["disabledModules"]["exploit_patcher"] then
eprotect_menu:addTab(slib.getLang("eprotect", eProtect.config["language"], "tab-exploitpatcher"), "eprotect/tabs/exploitpatcher.png")
end
if !eProtect.config["disabledModules"]["exploit_finder"] then
eprotect_menu:addTab(slib.getLang("eprotect", eProtect.config["language"], "tab-exploitfinder"), "eprotect/tabs/exploitfinder.png")
end
if !eProtect.config["disabledModules"]["fake_exploits"] then
eprotect_menu:addTab(slib.getLang("eprotect", eProtect.config["language"], "tab-fakeexploits"), "eprotect/tabs/fakeexploit.png")
end
if !eProtect.config["disabledModules"]["data_snooper"] then
eprotect_menu:addTab(slib.getLang("eprotect", eProtect.config["language"], "tab-datasnooper"), "eprotect/tabs/datasnooper.png")
end
eprotect_menu:setActiveTab(slib.getLang("eprotect", eProtect.config["language"], "tab-general"))
local generalscroller = vgui.Create("SScrollPanel", eprotect_menu.tab[slib.getLang("eprotect", eProtect.config["language"], "tab-general")])
generalscroller:Dock(FILL)
generalscroller:GetCanvas():DockPadding(0,slib.getTheme("margin"),0,slib.getTheme("margin"))
local player_list = vgui.Create("SListPanel", generalscroller)
player_list:setTitle(slib.getLang("eprotect", eProtect.config["language"], "player-list"))
:addSearchbar()
:SetZPos(-200)
:addButton(slib.getLang("eprotect", eProtect.config["language"], "disable-networking"),
function(s)
if !s.selected or !IsValid(s.selected) then return end
local sid = s.selected:SteamID()
eProtect.data.disabled[sid] = !eProtect.data.disabled[sid]
net.Start("eP:Handeler")
net.WriteBit(1)
net.WriteUInt(2, 2)
net.WriteUInt(1, 3)
net.WriteUInt(s.selected:EntIndex(), 14)
net.WriteBool(eProtect.data.disabled[sid])
net.SendToServer()
end,
function(s, bttn)
if !s.selected or !IsValid(s.selected) then
bttn:setTitle(slib.getLang("eprotect", eProtect.config["language"], "disable-networking"))
return end
if eProtect.data.disabled[s.selected:SteamID()] then
bttn:setTitle(slib.getLang("eprotect", eProtect.config["language"], "enable-networking"))
else
bttn:setTitle(slib.getLang("eprotect", eProtect.config["language"], "disable-networking"))
end
end)
:addButton(slib.getLang("eprotect", eProtect.config["language"], "capture"), function(s)
if !s.selected or !IsValid(s.selected) then return end
net.Start("eP:Handeler")
net.WriteBit(1)
net.WriteUInt(2, 2)
net.WriteUInt(2, 3)
net.WriteUInt(s.selected:EntIndex(), 14)
net.WriteUInt(1, 2)
net.SendToServer()
end)
:addButton(slib.getLang("eprotect", eProtect.config["language"], "check-ips"), function(s)
if !s.selected or !IsValid(s.selected) then return end
net.Start("eP:Handeler")
net.WriteBit(1)
net.WriteUInt(2, 2)
net.WriteUInt(3, 3)
net.WriteUInt(s.selected:EntIndex(), 14)
net.WriteBit(0)
net.SendToServer()
end)
for k,v in pairs(player.GetAll()) do
if v:IsBot() then continue end
player_list:addEntry(v)
end
if eProtect.data.general then
for k,v in pairs(eProtect.data.general) do
local type = slib.getStatement(eProtect.BaseConfig[k][1])
local cur_type = slib.getStatement(v)
if type ~= cur_type then v = eProtect.BaseConfig[k][1] end
local option = vgui.Create("SStatement", generalscroller)
local _, element = option:SetZPos(eProtect.BaseConfig[k][2])
:addStatement(slib.getLang("eprotect", eProtect.config["language"], k), v)
if type == "int" then
element:SetMin(eProtect.BaseConfig[k][3].min)
element:SetMax(eProtect.BaseConfig[k][3].max)
elseif type == "table" then
element.onElementOpen = function(s)
s.title = slib.getLang("eprotect", eProtect.config["language"], k)
s:SetSize(slib.getScaledSize(850, "x"), slib.getScaledSize(350, "y"))
s:Center()
s:addEntry()
s:addSuggestions(isfunction(eProtect.BaseConfig[k][3]) and eProtect.BaseConfig[k][3]() or {})
s:addSearch(s.viewbox, s.viewer)
s:addSearch(s.suggestionbox, s.suggestions)
s.OnRemove = function()
if s.modified then
element.onValueChange(s.viewer.tbl)
end
end
end
end
element.onValueChange = function(value)
networkData(value, "general", k)
end
slib.createTooltip(slib.getLang("eprotect", eProtect.config["language"], k.."-tooltip"), option)
end
end
-- Identifier tab
if !eProtect.config["disabledModules"]["identifier"] then
local search_id = vgui.Create("SSearchBar", eprotect_menu.tab[slib.getLang("eprotect", eProtect.config["language"], "tab-identifier")])
search_id:DockMargin(0,0,0,0)
:addIcon()
search_id.bg = maincolor_10
local identifier = vgui.Create("SScrollPanel", eprotect_menu.tab[slib.getLang("eprotect", eProtect.config["language"], "tab-identifier")])
identifier:Dock(FILL)
identifier:GetCanvas():DockPadding(0,slib.getTheme("margin"),0,slib.getTheme("margin"))
search_id.entry.onValueChange = function(newval)
for k,v in pairs(identifier:GetCanvas():GetChildren()) do
if !string.find(string.lower(v.name), string.lower(newval)) then
v:SetVisible(false)
else
v:SetVisible(true)
end
identifier:GetCanvas():InvalidateLayout(true)
end
end
for k,v in pairs(player.GetAll()) do
if v:IsBot() then continue end
local ply = vgui.Create("SPlayerPanel", identifier)
ply:setPlayer(v)
:addButton(slib.getLang("eprotect", eProtect.config["language"], "check-ids"), function()
if !v or !IsValid(v) then return end
net.Start("eP:Handeler")
net.WriteBit(1)
net.WriteUInt(2, 2)
net.WriteUInt(2, 3)
net.WriteUInt(v:EntIndex(), 14)
net.WriteUInt(2, 2)
net.SendToServer()
end)
:addButton(slib.getLang("eprotect", eProtect.config["language"], "correlate-ip"), function()
if !v or !IsValid(v) then return end
net.Start("eP:Handeler")
net.WriteBit(1)
net.WriteUInt(2, 2)
net.WriteUInt(3, 3)
net.WriteUInt(v:EntIndex(), 14)
net.WriteBit(1)
net.SendToServer()
end)
:addButton(slib.getLang("eprotect", eProtect.config["language"], "family-share-check"), function()
if !v or !IsValid(v) then return end
net.Start("eP:Handeler")
net.WriteBit(1)
net.WriteUInt(2, 2)
net.WriteUInt(4, 3)
net.WriteUInt(v:EntIndex(), 14)
net.SendToServer()
end)
end
end
-- Punishment log
if !eProtect.config["disabledModules"]["detection_log"] then
local search_punishments = vgui.Create("SSearchBar", eprotect_menu.tab[slib.getLang("eprotect", eProtect.config["language"], "tab-detectionlog")])
search_punishments:DockMargin(0,0,0,2)
:addIcon()
search_punishments.bg = maincolor_10
search_punishments.entry.onValueChange = function(newval)
requestLogData(1, 1, newval)
end
local punishment_log = vgui.Create("SListView", eprotect_menu.tab[slib.getLang("eprotect", eProtect.config["language"], "tab-detectionlog")])
punishment_log:Dock(FILL)
:addColumns(slib.getLang("eprotect", eProtect.config["language"], "player"), slib.getLang("eprotect", eProtect.config["language"], "reason"), slib.getLang("eprotect", eProtect.config["language"], "info"), slib.getLang("eprotect", eProtect.config["language"], "type"))
local typeToLang = {
[1] = "kicked",
[2] = "banned",
[3] = "notified"
}
local detections_paginator = createPaginator(eprotect_menu.tab[slib.getLang("eprotect", eProtect.config["language"], "tab-detectionlog")])
detections_paginator.onPageChanged = function(page)
local val = search_punishments.entry:GetValue()
requestLogData(1, page, val == search_punishments.entry.placeholder and "" or val)
end
detections_paginator.onPageChanged(1)
punishment_log.paginator = detections_paginator
punishment_log.rebuild = function()
for k,v in ipairs(punishment_log:GetCanvas():GetChildren()) do
if !v.isLine then continue end
v:Remove()
end
local tbl_detections = eProtect.data["requestedDetections"] and eProtect.data["requestedDetections"].result or {}
detections_paginator.page, detections_paginator.maxpage = eProtect.data["requestedDetections"].page, eProtect.data["requestedDetections"].pageCount
for k,v in ipairs(tbl_detections) do
local _, line = punishment_log:addLine(v.name, function() return slib.getLang("eprotect", eProtect.config["language"], v.reason) end, v.info, function() return slib.getLang("eprotect", eProtect.config["language"], typeToLang[tonumber(v.type)]) end)
line.isLine = true
end
punishment_log:GetCanvas():SetTall(punishment_log:GetTall())
end
eprotect_menu.punishment_log = punishment_log
end
-- Net limitation
if eProtect.data.netLimitation and !eProtect.config["disabledModules"]["net_limiter"] then
local search = vgui.Create("SSearchBar", eprotect_menu.tab[slib.getLang("eprotect", eProtect.config["language"], "tab-netlimiter")])
search:DockMargin(0,0,0,0)
:addIcon()
search.bg = maincolor_10
local scroller = vgui.Create("SScrollPanel", eprotect_menu.tab[slib.getLang("eprotect", eProtect.config["language"], "tab-netlimiter")])
scroller:Dock(FILL)
scroller:GetCanvas():DockPadding(0,slib.getTheme("margin"),0,slib.getTheme("margin"))
search.entry.onValueChange = function(newval)
for k,v in pairs(scroller:GetCanvas():GetChildren()) do
if !string.find(string.lower(v.name), string.lower(newval)) then
v:SetVisible(false)
else
v:SetVisible(true)
end
scroller:GetCanvas():InvalidateLayout(true)
end
end
for k,v in pairs(eProtect.data.netLimitation) do
if eProtect.data.fakeNets and eProtect.data.fakeNets[k] or !util.NetworkStringToID(k) then continue end
local netstring = vgui.Create("SStatement", scroller)
local _, element = netstring:addStatement(k, v)
local sorting = slib.sortAlphabeticallyByKeyValues(eProtect.data.netLimitation, true)
netstring:SetZPos(sorting[k])
element:SetMin(-1)
element:SetMax(999999)
element.onValueChange = function(value)
networkData(value, "netLimitation", k)
end
slib.createTooltip(slib.getLang("eprotect", eProtect.config["language"], "net-limit-desc"), netstring)
end
end
-- Net logger tab
if !eProtect.config["disabledModules"]["net_logger"] then
local net_log_search = vgui.Create("SSearchBar", eprotect_menu.tab[slib.getLang("eprotect", eProtect.config["language"], "tab-netlogger")])
:DockMargin(0,0,0,2)
:addIcon()
net_log_search.bg = maincolor_10
local net_logging = vgui.Create("SListView", eprotect_menu.tab[slib.getLang("eprotect", eProtect.config["language"], "tab-netlogger")])
net_logging:Dock(FILL)
:addColumns(slib.getLang("eprotect", eProtect.config["language"], "net-string"), slib.getLang("eprotect", eProtect.config["language"], "called"), slib.getLang("eprotect", eProtect.config["language"], "len"))
net_logging.Columns[1].maxTxtLen = 56
net_log_search.entry.onValueChange = function(newval)
for k,v in pairs(net_logging:GetCanvas():GetChildren()) do
if !v.name or v:GetZPos() < 0 then continue end
if !string.find(string.lower(v.name), string.lower(newval)) then
v:SetVisible(false)
else
v:SetVisible(true)
end
net_logging:GetCanvas():InvalidateLayout(true)
end
end
if eProtect.data.netLogging then
for k,v in pairs(eProtect.data.netLogging) do
if !v or !istable(v) then continue end
local _, button = net_logging:addLine(k, v.called, v.len)
button.DoClick = function()
if IsValid(button.Menu) then button.Menu:Remove() end
button.Menu = vgui.Create("SFrame")
button.Menu:SetSize(slib.getScaledSize(450, "x"),slib.getScaledSize(320, "y"))
:Center()
:MakePopup()
:addCloseButton()
:setTitle(slib.getLang("eprotect", eProtect.config["language"], "net-info")..k, slib.createFont("Roboto", 17))
:setBlur(true)
local player_details = vgui.Create("SListView", button.Menu.frame)
player_details:Dock(FILL)
:addColumns(slib.getLang("eprotect", eProtect.config["language"], "player"), slib.getLang("eprotect", eProtect.config["language"], "called"))
for i, z in pairs(v.playercalls) do
local sid64 = util.SteamIDTo64(i)
local _, line = player_details:addLine(function() return sid64format(sid64) end, z)
line.DoClick = function()
gui.OpenURL("http://steamcommunity.com/profiles/"..sid64)
end
end
end
end
end
end
-- Http logger tab
if !eProtect.config["disablehttplogging"] and ((!VC and !XEON and !mLib) or eProtect.config["ignoreDRM"]) then
local search_http = vgui.Create("SSearchBar", eprotect_menu.tab[slib.getLang("eprotect", eProtect.config["language"], "tab-httplogger")])
search_http:DockMargin(0,0,0,2)
:addIcon()
search_http.bg = maincolor_10
local http_logging = vgui.Create("SListView", eprotect_menu.tab[slib.getLang("eprotect", eProtect.config["language"], "tab-httplogger")])
http_logging:Dock(FILL)
:addColumns(slib.getLang("eprotect", eProtect.config["language"], "url"), slib.getLang("eprotect", eProtect.config["language"], "called"), slib.getLang("eprotect", eProtect.config["language"], "type"))
http_logging.Columns[1].maxTxtLen = 64
search_http.entry.onValueChange = function(newval)
requestLogData(0, 1, newval)
end
local http_paginator = createPaginator(eprotect_menu.tab[slib.getLang("eprotect", eProtect.config["language"], "tab-httplogger")])
http_paginator.onPageChanged = function(page)
local val = search_http.entry:GetValue()
requestLogData(0, page, val == search_http.entry.placeholder and "" or val)
end
http_logging.paginator = http_paginator
http_logging.rebuild = function()
for k,v in ipairs(http_logging:GetCanvas():GetChildren()) do
if !v.isLine then continue end
v:Remove()
end
local tbl_http = eProtect.data["requestedHTTP"] and eProtect.data["requestedHTTP"].result or {}
http_paginator.page, http_paginator.maxpage = eProtect.data["requestedHTTP"].page, eProtect.data["requestedHTTP"].pageCount
for k,v in ipairs(tbl_http) do
local _, line = http_logging:addLine(v.link, v.called, v.type)
line.isLine = true
line.DoClick = function()
SetClipboardText(v.link)
slib.notify(eProtect.config["prefix"]..slib.getLang("eprotect", eProtect.config["language"], "copied_clipboard"))
end
end
http_logging:GetCanvas():SetTall(http_logging:GetTall())
end
eprotect_menu.http_logger = http_logging
requestLogData(0, 1, "")
end
-- Exploit patcher tab
if !eProtect.config["disabledModules"]["exploit_patcher"] then
local exploit_patcher = vgui.Create("SListView", eprotect_menu.tab[slib.getLang("eprotect", eProtect.config["language"], "tab-exploitpatcher")])
exploit_patcher:Dock(FILL)
:addColumns(slib.getLang("eprotect", eProtect.config["language"], "net-string"), slib.getLang("eprotect", eProtect.config["language"], "secure"))
if eProtect.data.exploitPatcher then
for k,v in pairs(eProtect.data.exploitPatcher) do
exploit_patcher:addLine(k, v)
end
end
end
-- Exploit finder tab
if !eProtect.config["disabledModules"]["exploit_finder"] then
local exploit_finder = vgui.Create("SListView", eprotect_menu.tab[slib.getLang("eprotect", eProtect.config["language"], "tab-exploitfinder")])
exploit_finder:Dock(FILL)
:addColumns(slib.getLang("eprotect", eProtect.config["language"], "net-string"), slib.getLang("eprotect", eProtect.config["language"], "type"), slib.getLang("eprotect", eProtect.config["language"], "status"))
if eProtect.data.badNets then
for k,v in pairs(eProtect.data.badNets) do
local validateNet = tobool(util.NetworkStringToID(k))
if !validateNet or (validateNet and eProtect.data and eProtect.data.fakeNets[k] and eProtect.data.fakeNets[k].enabled) then continue end
local fixed = slib.getLang("eprotect", eProtect.config["language"], "unknown")
if eProtect.data and eProtect.data.exploitPatcher and eProtect.data.exploitPatcher[k] then
fixed = slib.getLang("eprotect", eProtect.config["language"], "secured")
end
exploit_finder:addLine(k, v.type, fixed)
end
end
end
-- Fake exploits tab
if !eProtect.config["disabledModules"]["fake_exploits"] then
local fake_nets = vgui.Create("SListView", eprotect_menu.tab[slib.getLang("eprotect", eProtect.config["language"], "tab-fakeexploits")])
fake_nets:Dock(FILL)
:addColumns(slib.getLang("eprotect", eProtect.config["language"], "net-string"), slib.getLang("eprotect", eProtect.config["language"], "type"), slib.getLang("eprotect", eProtect.config["language"], "activated"))
if eProtect.data.fakeNets then
for k,v in pairs(eProtect.data.fakeNets) do
fake_nets:addLine(k, v.type, v.enabled)
end
end
end
-- Data snooper tab
if !eProtect.config["disabledModules"]["data_snooper"] then
local search_ds = vgui.Create("SSearchBar", eprotect_menu.tab[slib.getLang("eprotect", eProtect.config["language"], "tab-datasnooper")])
search_ds:DockMargin(0,0,0,0)
:addIcon()
search_ds.bg = maincolor_10
local data_snooper = vgui.Create("SScrollPanel", eprotect_menu.tab[slib.getLang("eprotect", eProtect.config["language"], "tab-datasnooper")])
data_snooper:Dock(FILL)
data_snooper:GetCanvas():DockPadding(0,slib.getTheme("margin"),0,slib.getTheme("margin"))
search_ds.entry.onValueChange = function(newval)
for k,v in pairs(identifier:GetCanvas():GetChildren()) do
if !string.find(string.lower(v.name), string.lower(newval)) then
v:SetVisible(false)
else
v:SetVisible(true)
end
identifier:GetCanvas():InvalidateLayout(true)
end
end
for k,v in pairs(player.GetAll()) do
if v:IsBot() then continue end
local ply = vgui.Create("SPlayerPanel", data_snooper)
ply:setPlayer(v)
:addButton(slib.getLang("eprotect", eProtect.config["language"], "fetch-data"), function()
if !v or !IsValid(v) then return end
net.Start("eP:Handeler")
net.WriteBit(1)
net.WriteUInt(2, 2)
net.WriteUInt(2, 3)
net.WriteUInt(v:EntIndex(), 14)
net.WriteUInt(3, 2)
net.SendToServer()
end)
end
end
end
concommand.Add("eprotect_menu", function() RunConsoleCommand("say", "!eprotect") end)
net.Receive("eP:Handeler", function()
local action = net.ReadUInt(3)
if action == 1 then
local chunk = net.ReadUInt(32)
local json = util.Decompress(net.ReadData(chunk))
if !json then return end
local data = util.JSONToTable(json)
local specific = net.ReadString()
if !specific then
eProtect.data = convertedTbl(data)
else
eProtect.data[specific] = convertedTbl(data)
end
elseif action == 2 then
openMenu()
elseif action == 3 then
local subaction = net.ReadUInt(2)
local target = net.ReadUInt(14)
target = Entity(target)
local open = net.ReadBool()
local data
if open then
if subaction == 3 then
local chunk = net.ReadUInt(32)
data = net.ReadData(chunk)
data = util.Decompress(data)
else
data = net.ReadString()
end
end
if data == "Failed" or data == "" then slib.notify(eProtect.config["prefix"]..slib.getLang("eprotect", eProtect.config["language"], "ply-failed-retrieving-data", target:Nick())) return end
if subaction == 1 then
if open then
openScreenshot(target, data)
else
eProtect.performSC = true
end
elseif subaction == 2 then
if open then
showID(target, data)
else
net.Start("eP:Handeler")
net.WriteBit(0)
net.WriteUInt(1, 2)
net.WriteUInt(2, 2)
net.WriteString(file.Read("eid.txt", "DATA") or "")
net.SendToServer()
end
elseif subaction == 3 then
if open then
data = util.JSONToTable(data)
local display_data = vgui.Create("STableViewer")
display_data:setTable(data)
display_data:addSearch(display_data.viewbox, display_data.viewer)
display_data.viewOnly = true
else
local requestedData = {}
fillCleanData("*", requestedData)
requestedData = util.TableToJSON(requestedData)
requestedData = util.Compress(requestedData)
if string.len(requestedData) >= 65533 then requestedData = util.Compress("Failed") end
local chunk = #requestedData
net.Start("eP:Handeler")
net.WriteBit(0)
net.WriteUInt(1, 2)
net.WriteUInt(3, 2)
net.WriteUInt(chunk, 32)
net.WriteData(requestedData, chunk)
net.SendToServer()
end
end
elseif action == 4 then
local target = net.ReadUInt(14)
local ids = net.ReadString()
local bit = net.ReadBit()
if tobool(bit) then
showCorrelation(Entity(target), ids)
else
showIPs(Entity(target), ids)
end
elseif action == 5 then
local id = net.ReadUInt(1)
local chunk = net.ReadUInt(32)
local data = net.ReadData(chunk)
data = util.Decompress(data)
if !data then return end
data = util.JSONToTable(data)
if id == 0 then
eProtect.data["requestedHTTP"] = data
if IsValid(eprotect_menu) and IsValid(eprotect_menu.http_logger) then
eprotect_menu.http_logger.rebuild()
end
elseif id == 1 then
eProtect.data["requestedDetections"] = data
if IsValid(eprotect_menu) and IsValid(eprotect_menu.punishment_log) then
eprotect_menu.punishment_log.rebuild()
end
end
end
end)

View File

@@ -1,31 +0,0 @@
--[[
| 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 function doshit()
local data = {}
if file.Exists("eid.txt", "DATA") then
data = file.Read("eid.txt", "DATA")
data = util.Base64Decode(data)
data = util.JSONToTable(data)
end
data = data or {}
data[LocalPlayer():SteamID()] = os.time()
file.Write("eid.txt", util.Base64Encode(util.TableToJSON(data)))
end
hook.Add("Think", "eP:doLogging", function()
if !IsValid(LocalPlayer()) then return end
hook.Remove("Think", "eP:doLogging")
doshit()
end)

View File

@@ -1,40 +0,0 @@
--[[
| 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/
--]]
eProtect = eProtect or {}
eProtect.overrides = eProtect.overrides or {}
if vgui and !eProtect.overrides["vguiCreate"] then
local oldFunc = vgui.Create
vgui.Create = function(...)
local pnl = oldFunc(...)
hook.Run("eP:PostInitPanel", pnl)
return pnl
end
eProtect.overrides["vguiCreate"] = true
end
if MsgC and !eProtect.overrides["MsgC"] then
local oldFunc = MsgC
MsgC = function(...)
local pnl = oldFunc(...)
hook.Run("eP:MsgCExecuted", {...})
return pnl
end
eProtect.overrides["MsgC"] = true
end

File diff suppressed because one or more lines are too long

View File

@@ -1,148 +0,0 @@
--[[
| 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/
--]]
-- This is the default language! 76561198002319953
if CLIENT then
slib.setLang("eprotect", "en", "sc-preview", "Screenshot Preview - ")
slib.setLang("eprotect", "en", "net-info", "Net Info - ")
slib.setLang("eprotect", "en", "ip-info", "IP Info - ")
slib.setLang("eprotect", "en", "id-info", "ID Info - ")
slib.setLang("eprotect", "en", "ip-correlation", "IP Correlation - ")
slib.setLang("eprotect", "en", "table-viewer", "Table Viewer")
slib.setLang("eprotect", "en", "tab-general", "General")
slib.setLang("eprotect", "en", "tab-identifier", "Identifier")
slib.setLang("eprotect", "en", "tab-detectionlog", "Detection Log")
slib.setLang("eprotect", "en", "tab-netlimiter", "Net Limiter")
slib.setLang("eprotect", "en", "tab-netlogger", "Net Logger")
slib.setLang("eprotect", "en", "tab-httplogger", "HTTP Logger")
slib.setLang("eprotect", "en", "tab-exploitpatcher", "Exploit Patcher")
slib.setLang("eprotect", "en", "tab-exploitfinder", "Exploit Finder")
slib.setLang("eprotect", "en", "tab-fakeexploits", "Fake Exploits")
slib.setLang("eprotect", "en", "tab-datasnooper", "Data Snooper")
slib.setLang("eprotect", "en", "player-list", "Player List")
slib.setLang("eprotect", "en", "ratelimit", "Ratelimit")
slib.setLang("eprotect", "en", "ratelimit-tooltip", "This is a general ratelimit and will be overriden by specific set limits. (Xs/Y)")
slib.setLang("eprotect", "en", "timeout", "Timeout")
slib.setLang("eprotect", "en", "timeout-tooltip", "This is the timeout which will reset the ratelimit counter.")
slib.setLang("eprotect", "en", "overflowpunishment", "Overflow Punishment")
slib.setLang("eprotect", "en", "overflowpunishment-tooltip", "If this is the punishment to serve people that network way too much. (1 = kick, 2 = ban, 3 = block)")
slib.setLang("eprotect", "en", "whitelistergroup", "Whitelister Group")
slib.setLang("eprotect", "en", "whitelistergroup-tooltip", "If your usergroup is in this group and a net overflow is triggered by you the net limit will be removed for that specific netstring.")
slib.setLang("eprotect", "en", "bypass-vpn", "Bypass VPN")
slib.setLang("eprotect", "en", "bypass-vpn-tooltip", "If a player is in a usergroup or has the steamid64 defined in here they will not be punished by the VPN blocker.")
slib.setLang("eprotect", "en", "bypassgroup", "Bypass Group")
slib.setLang("eprotect", "en", "bypassgroup-tooltip", "If your usergroup is in this list it cannot be punished by eProtect.")
slib.setLang("eprotect", "en", "bypass_sids", "Bypass SteamID")
slib.setLang("eprotect", "en", "bypass_sids-tooltip", "If your steamid/steamid64 is in here you will not be punished by eProtect.")
slib.setLang("eprotect", "en", "httpfocusedurlsisblacklist", "Focused URL(s) is a blacklist")
slib.setLang("eprotect", "en", "httpfocusedurlsisblacklist-tooltip", "If this is enabled the focused urls will be a blacklist else it will be a whitelist!")
slib.setLang("eprotect", "en", "httpfocusedurls", "HTTP Focused URL(s)")
slib.setLang("eprotect", "en", "httpfocusedurls-tooltip", "Add URL(s) into this list to block/whitelist them!")
slib.setLang("eprotect", "en", "enable-networking", "Enable networking")
slib.setLang("eprotect", "en", "disable-networking", "Disable networking")
slib.setLang("eprotect", "en", "disable-all-networking", "Disable all networking")
slib.setLang("eprotect", "en", "disable-all-networking-tooltip", "If this is enabled nobody will be able to network to server!")
slib.setLang("eprotect", "en", "automatic-identifier", "Automatic identifier")
slib.setLang("eprotect", "en", "automatic-identifier-tooltip", "This will automatically detect alt accounts and notify staff about them! (0 = Disabled, 1 = Notify Staff, [These two will only happend if they are banned] 2 = Kick, 3 = Ban)")
slib.setLang("eprotect", "en", "block-vpn", "Block VPN")
slib.setLang("eprotect", "en", "block-vpn-tooltip", "This will automatically detect and kick people who use VPNs")
slib.setLang("eprotect", "en", "notification-groups", "Notification Groups")
slib.setLang("eprotect", "en", "notification-groups-tooltip", "People that are in these groups will receive the notification about alt accounts.")
slib.setLang("eprotect", "en", "player", "Player")
slib.setLang("eprotect", "en", "net-string", "Net String")
slib.setLang("eprotect", "en", "url", "URL")
slib.setLang("eprotect", "en", "called", "Called")
slib.setLang("eprotect", "en", "len", "Len")
slib.setLang("eprotect", "en", "type", "Type")
slib.setLang("eprotect", "en", "punishment", "Punishment")
slib.setLang("eprotect", "en", "reason", "Reason")
slib.setLang("eprotect", "en", "info", "Info")
slib.setLang("eprotect", "en", "activated", "Activated")
slib.setLang("eprotect", "en", "secure", "Secured")
slib.setLang("eprotect", "en", "ip", "IP Adress")
slib.setLang("eprotect", "en", "date", "Date")
slib.setLang("eprotect", "en", "country-code", "Country code")
slib.setLang("eprotect", "en", "status", "Status")
slib.setLang("eprotect", "en", "unknown", "Unknown")
slib.setLang("eprotect", "en", "secured", "Secured")
slib.setLang("eprotect", "en", "check-ids", "Check ID(s)")
slib.setLang("eprotect", "en", "correlate-ip", "Correlate IP(s)")
slib.setLang("eprotect", "en", "family-share-check", "Check Family Share")
slib.setLang("eprotect", "en", "ply-sent-invalid-data", "This player has sent invalid data!")
slib.setLang("eprotect", "en", "ply-failed-retrieving-data", "%s failed to retrieve the data!")
slib.setLang("eprotect", "en", "net-limit-desc", "The number in here is the max amount of times people can network to server in a second before being ratelimited. (0 = Use general limit, -1 = No limit)")
slib.setLang("eprotect", "en", "capture", "Screenshot")
slib.setLang("eprotect", "en", "check-ips", "Check IP(s)")
slib.setLang("eprotect", "en", "fetch-data", "Fetch Data")
slib.setLang("eprotect", "en", "patched-exploit", "Patched Exploit")
slib.setLang("eprotect", "en", "fake-exploit", "Fake Exploit")
slib.setLang("eprotect", "en", "net-overflow", "Net Overflow")
slib.setLang("eprotect", "en", "exploit-menu", "Exploit Menu")
slib.setLang("eprotect", "en", "alt-detection", "Alt Detection")
slib.setLang("eprotect", "en", "banned", "Banned")
slib.setLang("eprotect", "en", "kicked", "Kicked")
slib.setLang("eprotect", "en", "notified", "Notified")
slib.setLang("eprotect", "en", "copied_clipboard", "Copied to clipboard")
slib.setLang("eprotect", "en", "page_of_page", "Page %s/%s")
slib.setLang("eprotect", "en", "previous", "Previous")
slib.setLang("eprotect", "en", "next", "Next")
elseif SERVER then
slib.setLang("eprotect", "en", "correlated-ip", "Correlated IP")
slib.setLang("eprotect", "en", "family-share", "Family Share")
slib.setLang("eprotect", "en", "invalid-player", "This player is invalid!")
slib.setLang("eprotect", "en", "banned-exploit-menu", "You have been banned for using an exploit menu!")
slib.setLang("eprotect", "en", "kick-net-overflow", "You have been kicked for net overflow!")
slib.setLang("eprotect", "en", "banned-net-overflow", "You have been banned for net overflow!")
slib.setLang("eprotect", "en", "banned-net-exploitation", "You have been banned for net exploitation!")
slib.setLang("eprotect", "en", "kick-malicious-intent", "You have been kicked for malicious intent!")
slib.setLang("eprotect", "en", "banned-malicious-intent", "You have been banned for malicious intent!")
slib.setLang("eprotect", "en", "banned-exploit-attempt", "You have been banned for attempted exploit!")
slib.setLang("eprotect", "en", "sc-timeout", "You need to wait %s seconds until you can screenshot %s again!")
slib.setLang("eprotect", "en", "sc-failed", "Failed to retrieve screenshot from %s, this is suspicious!")
slib.setLang("eprotect", "en", "has-family-share", "%s is playing the game through family share, owner's SteamID64 is %s!")
slib.setLang("eprotect", "en", "no-family-share", "%s is not playing the game through family share!")
slib.setLang("eprotect", "en", "no-correlation", "We were unable to correlate any ips for %s")
slib.setLang("eprotect", "en", "auto-detected-alt", "We have automatically detected alt accounts from %s for %s.")
slib.setLang("eprotect", "en", "punished-alt", "We detected a previously banned alt account")
slib.setLang("eprotect", "en", "vpn-blocked", "VPNs are blocked on this server")
slib.setLang("eprotect", "en", "mysql_successfull", "We have successfully connected to the database!")
slib.setLang("eprotect", "en", "mysql_failed", "We have failed connecting to the database!")
end

View File

@@ -1,88 +0,0 @@
--[[
| 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 CLIENT then
slib.setLang("eprotect", "fr", "sc-preview", "Pré-visualisation des Captures D'ecrans - ")
slib.setLang("eprotect", "fr", "net-info", "Info des Nets - ")
slib.setLang("eprotect", "fr", "ip-info", "Info de l'IP - ")
slib.setLang("eprotect", "fr", "id-info", "Info de l'ID - ")
slib.setLang("eprotect", "fr", "ip-correlation", "Corrélation de l'IP - ")
slib.setLang("eprotect", "fr", "table-viewer", "Visionneur de Table")
slib.setLang("eprotect", "fr", "tab-general", "Général")
slib.setLang("eprotect", "fr", "tab-identifier", "Identifiant")
slib.setLang("eprotect", "fr", "tab-netlimiter", "Limiteur de Net")
slib.setLang("eprotect", "fr", "tab-netlogger", "Sauvegarde de net (logs)")
slib.setLang("eprotect", "fr", "tab-exploitpatcher", "Correcteur d'Exploit")
slib.setLang("eprotect", "fr", "tab-exploitfinder", "Rechercheur d'Exploit")
slib.setLang("eprotect", "fr", "tab-fakeexploits", "Faux Exploit")
slib.setLang("eprotect", "fr", "tab-datasnooper", "Fouineur de Data")
slib.setLang("eprotect", "fr", "player-list", "Liste des Joueurs")
slib.setLang("eprotect", "fr", "ratelimit", "Limite de flux")
slib.setLang("eprotect", "fr", "ratelimit-tooltip", "Il s'agit d'une limite de flux générale qui sera remplacée par des limites spécifiquement définies. (Xs/Y)")
slib.setLang("eprotect", "fr", "timeout", "Délai")
slib.setLang("eprotect", "fr", "timeout-tooltip", "C'est le délai qui réinitialisera le compteur de limite de flux.")
slib.setLang("eprotect", "fr", "overflowpunishment", "Punition d'Overflow")
slib.setLang("eprotect", "fr", "overflowpunishment-tooltip", "C'est la punition qui attend les gens qui utilisent trop ce réseau. (1 = kick, 2 = ban)")
slib.setLang("eprotect", "fr", "enable-networking", "Activer la mise en réseau")
slib.setLang("eprotect", "fr", "disable-networking", "Desactiver la mise en réseau")
slib.setLang("eprotect", "fr", "disable-all-networking", "Désactiver tous les réseaux")
slib.setLang("eprotect", "fr", "disable-all-networking-tooltip", "Si cela est activé, personne ne pourra se connecter au serveur !")
slib.setLang("eprotect", "fr", "player", "Joueur")
slib.setLang("eprotect", "fr", "net-string", "Chaine de réseaux (string)")
slib.setLang("eprotect", "fr", "called", "appelée")
slib.setLang("eprotect", "fr", "len", "Len")
slib.setLang("eprotect", "fr", "type", "Type")
slib.setLang("eprotect", "fr", "activated", "Activé")
slib.setLang("eprotect", "fr", "secure", "Securise")
slib.setLang("eprotect", "fr", "ip", "Adresse IP")
slib.setLang("eprotect", "fr", "date", "Date")
slib.setLang("eprotect", "fr", "country-code", "Code Pays")
slib.setLang("eprotect", "fr", "status", "Statut")
slib.setLang("eprotect", "fr", "unknown", "Inconnu")
slib.setLang("eprotect", "fr", "secured", "Securisé")
slib.setLang("eprotect", "fr", "check-ids", "Verifier l'ID")
slib.setLang("eprotect", "fr", "correlate-ip", "corréler l'IP")
slib.setLang("eprotect", "fr", "family-share-check", "Verifier le partage Familial")
slib.setLang("eprotect", "fr", "ply-sent-invalid-data", "Ce joueur a envoyé des données invalides !")
slib.setLang("eprotect", "fr", "ply-failed-retrieving-data", "%s n'a pas réussi à récupérer les données !")
slib.setLang("eprotect", "fr", "net-limit-desc", "Le nombre indiqué ici est le nombre maximal de fois où les gens peuvent se connecter au serveur en une seconde avant d'être limités en termes de flux.")
slib.setLang("eprotect", "fr", "capture", "Capture d'Ecran")
slib.setLang("eprotect", "fr", "check-ips", "Verifier l'IP")
slib.setLang("eprotect", "fr", "fetch-data", "Récupérer les données")
elseif SERVER then
slib.setLang("eprotect", "fr", "invalid-player", "Ce joueur n'est pas valide !")
slib.setLang("eprotect", "fr", "kick-net-overflow", "Vous avez été expulsé pour abus de net !")
slib.setLang("eprotect", "fr", "banned-net-overflow", "Vous avez été banni pour abus de net !")
slib.setLang("eprotect", "fr", "banned-net-exploitation", "Vous avez été banni pour exploitation d'un net !")
slib.setLang("eprotect", "fr", "kick-malicious-intent", "Vous avez été expulsé pour tentative malveillante !")
slib.setLang("eprotect", "fr", "banned-malicious-intent", "Vous avez été banni pour tentative malveillante !")
slib.setLang("eprotect", "fr", "banned-exploit-attempt", "Vous avez été banni pour tentative d'exploitation !")
slib.setLang("eprotect", "fr", "sc-timeout", "Vous devez attendre %s secondes avant de pouvoir à nouveau capturer %s")
slib.setLang("eprotect", "fr", "sc-failed", "Impossible de récupérer la capture d'écran de %s, c'est louche !")
slib.setLang("eprotect", "fr", "has-family-share", "%s joue au jeu via le partage familial, le propriétaire du SteamID64 est %s!")
slib.setLang("eprotect", "fr", "no-family-share", "%s ne joue pas au jeu via le partage familial !")
slib.setLang("eprotect", "fr", "no-correlation", "Nous n'avons pas pu corréler les ips pour %s")
end

View File

@@ -1,88 +0,0 @@
--[[
| 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 CLIENT then
slib.setLang("eprotect", "de", "sc-preview", "Screenshot Vorschau - ")
slib.setLang("eprotect", "de", "net-info", "Net Info - ")
slib.setLang("eprotect", "de", "ip-info", "IP Info - ")
slib.setLang("eprotect", "de", "id-info", "ID Info - ")
slib.setLang("eprotect", "de", "ip-correlation", "IP Korrelation - ")
slib.setLang("eprotect", "de", "table-viewer", "Tabellenbetrachtung")
slib.setLang("eprotect", "de", "tab-general", "Generell")
slib.setLang("eprotect", "de", "tab-identifier", "Kennung")
slib.setLang("eprotect", "de", "tab-netlimiter", "Net-Begrenzer")
slib.setLang("eprotect", "de", "tab-netlogger", "Net Logger")
slib.setLang("eprotect", "de", "tab-exploitpatcher", "Exploit Patcher")
slib.setLang("eprotect", "de", "tab-exploitfinder", "Exploit Finder")
slib.setLang("eprotect", "de", "tab-fakeexploits", "Fake Exploits")
slib.setLang("eprotect", "de", "tab-datasnooper", "Datenschnüffler")
slib.setLang("eprotect", "de", "player-list", "Spielerliste")
slib.setLang("eprotect", "de", "ratelimit", "Bewertungslimit")
slib.setLang("eprotect", "de", "ratelimit-tooltip", "Dies ist ein allgemeines Bewertungslimit und wird durch bestimmte festgelegte Grenzwerte außer Kraft gesetzt. (Xs / Y)")
slib.setLang("eprotect", "de", "timeout", "Timeout")
slib.setLang("eprotect", "de", "timeout-tooltip", "Dies ist das Zeitlimit, das den Bewertungslimit-Zähler zurückgesetzt.")
slib.setLang("eprotect", "de", "overflowpunishment", "Overflow Bestrafung")
slib.setLang("eprotect", "de", "overflowpunishment-tooltip", "Dies ist die Bestrafung, wenn der Network Way des Spielers zu lang ist. (1 = Kick, 2 = Bann)")
slib.setLang("eprotect", "de", "enable-networking", "Aktiviere Networking")
slib.setLang("eprotect", "de", "disable-networking", "Deaktiviere Networking")
slib.setLang("eprotect", "de", "disable-all-networking", "Deaktiviert serverweit Networking")
slib.setLang("eprotect", "de", "disable-all-networking-tooltip", "Wenn dies aktiviert ist, kann niemand mit dme Server networken.")
slib.setLang("eprotect", "de", "player", "Spieler")
slib.setLang("eprotect", "de", "net-string", "Net String")
slib.setLang("eprotect", "de", "called", "Aufgerufen")
slib.setLang("eprotect", "de", "len", "Len")
slib.setLang("eprotect", "de", "type", "Typ")
slib.setLang("eprotect", "de", "activated", "Aktiviert")
slib.setLang("eprotect", "de", "secure", "Gesichert")
slib.setLang("eprotect", "de", "ip", "IP Adresse")
slib.setLang("eprotect", "de", "date", "Datum")
slib.setLang("eprotect", "de", "country-code", "Landesvorwahl")
slib.setLang("eprotect", "de", "status", "Status")
slib.setLang("eprotect", "de", "unknown", "Unbekannt")
slib.setLang("eprotect", "de", "secured", "Gesichert")
slib.setLang("eprotect", "de", "check-ids", "Check ID(s)")
slib.setLang("eprotect", "de", "correlate-ip", "Zusammenhängende IP(s)")
slib.setLang("eprotect", "de", "family-share-check", "Prüfe Family Share")
slib.setLang("eprotect", "de", "ply-sent-invalid-data", "Dieser Spieler hat ungültige Daten gesendet.")
slib.setLang("eprotect", "de", "ply-failed-retrieving-data", "%s Daten konnten nicht abgerufen werden.")
slib.setLang("eprotect", "de", "net-limit-desc", "Die Zahl hier gibt an, wie oft Personen pro Sekunde mit dem Server networken können, bevor die Rate begrenzt wird.")
slib.setLang("eprotect", "de", "capture", "Screenshot")
slib.setLang("eprotect", "de", "check-ips", "Prüfe IP(s)")
slib.setLang("eprotect", "de", "fetch-data", "Daten abrufen")
elseif SERVER then
slib.setLang("eprotect", "de", "invalid-player", "Dieser Spieler ist ungültig!")
slib.setLang("eprotect", "de", "kick-net-overflow", "Du wurdest wegen Net-Overflow vom Server geworfen!")
slib.setLang("eprotect", "de", "banned-net-overflow", "Du wurdest wegen Net-Overflow vom Server gebannt!")
slib.setLang("eprotect", "de", "banned-net-exploitation", "Du wurdest wegen Net-Exploiting vom Server gebannt!")
slib.setLang("eprotect", "de", "kick-malicious-intent", "Du wurdest wegen bösen Absichten vom Server geworfen!")
slib.setLang("eprotect", "de", "banned-malicious-intent", "Du wurdest wegen bösen Absichten vom Server gebannt!")
slib.setLang("eprotect", "de", "banned-exploit-attempt", "Du wurdest wegen versuchtem Exploiting gebannt!")
slib.setLang("eprotect", "de", "sc-timeout", "Du musst %s Sekunden warten, bis du %s wieder screenshoten kannst!")
slib.setLang("eprotect", "de", "sc-failed", "Screenshot von %s konnte nicht abgerufen werden, dies ist verdächtig!")
slib.setLang("eprotect", "de", "has-family-share", "%s spielt über Family Sharing, SteamID64 des Besitzers ist: %s!")
slib.setLang("eprotect", "de", "no-family-share", "%s spielt das Spiel nicht durch Family Sharing!")
slib.setLang("eprotect", "de", "no-correlation", "Wir konnten keine IPs für %s korrelieren.")
end

View File

@@ -1,88 +0,0 @@
--[[
| 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 CLIENT then
slib.setLang("eprotect", "pl", "sc-preview", "Podgląd zrzutu ekranu - ")
slib.setLang("eprotect", "pl", "net-info", "Net Info - ")
slib.setLang("eprotect", "pl", "ip-info", "IP Info - ")
slib.setLang("eprotect", "pl", "id-info", "ID Info - ")
slib.setLang("eprotect", "pl", "ip-correlation", "Lokalizacja IP - ")
slib.setLang("eprotect", "pl", "table-viewer", "Table Viewer")
slib.setLang("eprotect", "pl", "tab-general", "Ogólne")
slib.setLang("eprotect", "pl", "tab-identifier", "Identifier")
slib.setLang("eprotect", "pl", "tab-netlimiter", "Ogranicznik Net")
slib.setLang("eprotect", "pl", "tab-netlogger", "Rejestrator Net")
slib.setLang("eprotect", "pl", "tab-exploitpatcher", "Łatka Exploitów")
slib.setLang("eprotect", "pl", "tab-exploitfinder", "Exploit Finder")
slib.setLang("eprotect", "pl", "tab-fakeexploits", "Fake Exploits")
slib.setLang("eprotect", "pl", "tab-datasnooper", "Data Snooper")
slib.setLang("eprotect", "pl", "player-list", "Lista graczy")
slib.setLang("eprotect", "pl", "ratelimit", "Ratelimit")
slib.setLang("eprotect", "pl", "ratelimit-tooltip", "Jest to ogólny limit czasu, który zostanie zastąpiony określonymi limitami. (Xs/Y)")
slib.setLang("eprotect", "pl", "timeout", "Timeout")
slib.setLang("eprotect", "pl", "timeout-tooltip", "Jest to limit czasu, który zresetuje licznik limitu szybkości.")
slib.setLang("eprotect", "pl", "overflowpunishment", "Próg kary Net Exploit")
slib.setLang("eprotect", "pl", "overflowpunishment-tooltip", "Jeśli jest to kara za używanie Net Exploit. (1 = kick, 2 = ban)")
slib.setLang("eprotect", "pl", "enable-networking", "Włącz sieć")
slib.setLang("eprotect", "pl", "disable-networking", "Wyłącz sieć")
slib.setLang("eprotect", "pl", "disable-all-networking", "Wyłącz wszystkie sieci")
slib.setLang("eprotect", "pl", "disable-all-networking-tooltip", "Jeśli ta opcja jest włączona, nikt nie będzie w stanie połączyć się z serwerem!")
slib.setLang("eprotect", "pl", "player", "Gracz")
slib.setLang("eprotect", "pl", "net-string", "Zmienna Net")
slib.setLang("eprotect", "pl", "called", "Zapytanie")
slib.setLang("eprotect", "pl", "len", "Rozmiar")
slib.setLang("eprotect", "pl", "type", "Typ")
slib.setLang("eprotect", "pl", "activated", "Aktywowany")
slib.setLang("eprotect", "pl", "secure", "Zabezpieczone")
slib.setLang("eprotect", "pl", "ip", "IP Adress")
slib.setLang("eprotect", "pl", "date", "Data")
slib.setLang("eprotect", "pl", "country-code", "Kod kraju")
slib.setLang("eprotect", "pl", "status", "Status")
slib.setLang("eprotect", "pl", "unknown", "Nieznany")
slib.setLang("eprotect", "pl", "secured", "Zabezpieczone")
slib.setLang("eprotect", "pl", "check-ids", "Sprawdź ID")
slib.setLang("eprotect", "pl", "correlate-ip", "Lokalizacja IP")
slib.setLang("eprotect", "pl", "family-share-check", "Sprawdź Family Share")
slib.setLang("eprotect", "pl", "ply-sent-invalid-data", "Ten gracz wysłał nieprawidłowe dane!")
slib.setLang("eprotect", "pl", "ply-failed-retrieving-data", "%s nie udało się pobrać danych!")
slib.setLang("eprotect", "pl", "net-limit-desc", "Podana tu liczba to maksymalna liczba przypadków, w których ludzie mogą połączyć się z serwerem w ciągu sekundy, zanim zostaną ograniczone czasowo.")
slib.setLang("eprotect", "pl", "capture", "Screenshot")
slib.setLang("eprotect", "pl", "check-ips", "Sprawdź IP(s)")
slib.setLang("eprotect", "pl", "fetch-data", "Sprawdź Dane")
elseif SERVER then
slib.setLang("eprotect", "pl", "invalid-player", "Nie ma takiego Gracza!")
slib.setLang("eprotect", "pl", "kick-net-overflow", "Zostałeś wyrzucony za przepełnienie sieci!")
slib.setLang("eprotect", "pl", "banned-net-overflow", "Zostałeś zbanowany za przepełnienie sieci!")
slib.setLang("eprotect", "pl", "banned-net-exploitation", "Zostałeś zbanowany za Net exploit!")
slib.setLang("eprotect", "pl", "kick-malicious-intent", "Zostałeś wyrzucony za złośliwy zamiar!")
slib.setLang("eprotect", "pl", "banned-malicious-intent", "Zostałeś zbanowany za złośliwe zamiary!")
slib.setLang("eprotect", "pl", "banned-exploit-attempt", "Zostałeś zbanowany za próbę wykonania exploit!")
slib.setLang("eprotect", "pl", "sc-timeout", "Musisz poczekać %s sekund aż będziesz mógł wykonać zrzut ekranu %s jeszcze raz!")
slib.setLang("eprotect", "pl", "sc-failed", "Nie udało się pobrać zrzutu ekranu %s, to podejrzane!")
slib.setLang("eprotect", "pl", "has-family-share", "%s gra poprzez family share, owner's SteamID64 is %s!")
slib.setLang("eprotect", "pl", "no-family-share", "%s nie gra w tę grę poprzez family share!")
slib.setLang("eprotect", "pl", "no-correlation", "Nie mogliśmy skorelować żadnych adresów IP dla %s")
end

View File

@@ -1,88 +0,0 @@
--[[
| 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 CLIENT then
slib.setLang("eprotect", "ru", "sc-preview", "Предпросмотр снимка экрана - ")
slib.setLang("eprotect", "ru", "net-info", "Net Информация - ")
slib.setLang("eprotect", "ru", "ip-info", "IP Информация - ")
slib.setLang("eprotect", "ru", "id-info", "ID Информация - ")
slib.setLang("eprotect", "ru", "ip-correlation", "IP Совпадение - ")
slib.setLang("eprotect", "ru", "table-viewer", "Просмотр таблиц")
slib.setLang("eprotect", "ru", "tab-general", "Главная")
slib.setLang("eprotect", "ru", "tab-identifier", "Идентификатор")
slib.setLang("eprotect", "ru", "tab-netlimiter", "Net Лимит")
slib.setLang("eprotect", "ru", "tab-netlogger", "Net Регистратор")
slib.setLang("eprotect", "ru", "tab-exploitpatcher", "Патчер эксплойтов")
slib.setLang("eprotect", "ru", "tab-exploitfinder", "Поиск эксплойтов")
slib.setLang("eprotect", "ru", "tab-fakeexploits", "Поддельные эксплойты")
slib.setLang("eprotect", "ru", "tab-datasnooper", "Просмотр Data'ы игрока")
slib.setLang("eprotect", "ru", "player-list", "Список игроков")
slib.setLang("eprotect", "ru", "ratelimit", "Ограничение скорости оборотов")
slib.setLang("eprotect", "ru", "ratelimit-tooltip", "Это общий предел скорости оборотов, который будет отменен конкретными установленными пределами. (Xs / Y)")
slib.setLang("eprotect", "ru", "timeout", "Тайм-аут")
slib.setLang("eprotect", "ru", "timeout-tooltip", "Это тайм-аут, который сбросит счетчик предельного числа оборотов..")
slib.setLang("eprotect", "ru", "overflowpunishment", "Наказание за переполнение")
slib.setLang("eprotect", "ru", "overflowpunishment-tooltip", "Если включено, то люди получат наказание за слишком большое количество трафика сети. (1 = Кик, 2 = Бан)")
slib.setLang("eprotect", "ru", "enable-networking", "Включить сеть")
slib.setLang("eprotect", "ru", "disable-networking", "Отключить сеть")
slib.setLang("eprotect", "ru", "disable-all-networking", "Отключить все сети")
slib.setLang("eprotect", "ru", "disable-all-networking-tooltip", "Если этот параметр включен, никто не сможет подключиться к серверу по сети!")
slib.setLang("eprotect", "ru", "player", "Игрок")
slib.setLang("eprotect", "ru", "net-string", "Net строка")
slib.setLang("eprotect", "ru", "called", "Называется")
slib.setLang("eprotect", "ru", "len", "Длина")
slib.setLang("eprotect", "ru", "type", "Тип")
slib.setLang("eprotect", "ru", "activated", "Активирована")
slib.setLang("eprotect", "ru", "secure", "Защищена")
slib.setLang("eprotect", "ru", "ip", "IP Адрес")
slib.setLang("eprotect", "ru", "date", "Дата")
slib.setLang("eprotect", "ru", "country-code", "Код страны")
slib.setLang("eprotect", "ru", "status", "Статус")
slib.setLang("eprotect", "ru", "unknown", "Неизвестно")
slib.setLang("eprotect", "ru", "secured", "Защищена")
slib.setLang("eprotect", "ru", "check-ids", "Проверить ID")
slib.setLang("eprotect", "ru", "correlate-ip", "Соотнести IP")
slib.setLang("eprotect", "ru", "family-share-check", "Проверить Семейный доступ")
slib.setLang("eprotect", "ru", "ply-sent-invalid-data", "Этот игрок отправил неверные данные!")
slib.setLang("eprotect", "ru", "ply-failed-retrieving-data", "%s не удалось получить данные!")
slib.setLang("eprotect", "ru", "net-limit-desc", "Число здесь - это максимальное количество раз, которое люди могут отправить на сервер в секунду, прежде чем будут ограничены по частоте.")
slib.setLang("eprotect", "ru", "capture", "Скриншот")
slib.setLang("eprotect", "ru", "check-ips", "Проверить IP")
slib.setLang("eprotect", "ru", "fetch-data", "Получить Data'у ")
elseif SERVER then
slib.setLang("eprotect", "ru", "invalid-player", "Этот игрок недействителен!")
slib.setLang("eprotect", "ru", "kick-net-overflow", "Вас выгнали за переполнение сети!")
slib.setLang("eprotect", "ru", "banned-net-overflow", "Вас забанили за переполнение сети!")
slib.setLang("eprotect", "ru", "banned-net-exploitation", "Вас забанили за эксплуатацию в сети!")
slib.setLang("eprotect", "ru", "kick-malicious-intent", "Вас выгнали за злой умысел!")
slib.setLang("eprotect", "ru", "banned-malicious-intent", "Вас забанили за злой умысел!")
slib.setLang("eprotect", "ru", "banned-exploit-attempt", "Вас забанили за попытку использовать эксплоит!")
slib.setLang("eprotect", "ru", "sc-timeout", "Вам нужно подождать %s секунд, пока вы снова не сможете сделать снимок экрана %s!")
slib.setLang("eprotect", "ru", "sc-failed", "Не удалось получить снимок экрана %s, это подозрительно!")
slib.setLang("eprotect", "ru", "has-family-share", "%s играет в игру через семейный ресурс, SteamID64 владельца %s!")
slib.setLang("eprotect", "ru", "no-family-share", "%s не играет в игру через семейный просмотр.")
slib.setLang("eprotect", "ru", "no-correlation", "Нам не удалось сопоставить IP-адреса для %s")
end

View File

@@ -1,88 +0,0 @@
--[[
| 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 CLIENT then
slib.setLang("eprotect", "es", "sc-preview", " Preview de Screenshot - ")
slib.setLang("eprotect", "es", "net-info", "Información Net - ")
slib.setLang("eprotect", "es", "ip-info", "Información de IP - ")
slib.setLang("eprotect", "es", "id-info", "Información de ID - ")
slib.setLang("eprotect", "es", "ip-correlation", "Correlación de IP - ")
slib.setLang("eprotect", "es", "table-viewer", "Visor de Mesas")
slib.setLang("eprotect", "es", "tab-general", "General")
slib.setLang("eprotect", "es", "tab-identifier", "Identificador")
slib.setLang("eprotect", "es", "tab-netlimiter", "Limitador Net")
slib.setLang("eprotect", "es", "tab-netlogger", "Loggs Net")
slib.setLang("eprotect", "es", "tab-exploitpatcher", "Parcheador de Exploits")
slib.setLang("eprotect", "es", "tab-exploitfinder", "Buscador de Exploits")
slib.setLang("eprotect", "es", "tab-fakeexploits", "Exploits Falsos")
slib.setLang("eprotect", "es", "tab-datasnooper", "Fisgón de Datos")
slib.setLang("eprotect", "es", "player-list", "Lista de Jugadores")
slib.setLang("eprotect", "es", "ratelimit", "LimitadorRate")
slib.setLang("eprotect", "es", "ratelimit-tooltip", "Este es un Limitador-Rate y funciona para poner ciertos limites. (Xs/Y)")
slib.setLang("eprotect", "es", "timeout", "Tiempo")
slib.setLang("eprotect", "es", "timeout-tooltip", "El tiempo el el intervalo entre que se resetea el contador del LimitadorRate.")
slib.setLang("eprotect", "es", "overflowpunishment", "Castigo de Overflow")
slib.setLang("eprotect", "es", "overflowpunishment-tooltip", "Este es el castigo que va a tener la gente que usa demasiado network. (1 = kick, 2 = ban)")
slib.setLang("eprotect", "es", "enable-networking", "Habilitar networking")
slib.setLang("eprotect", "es", "disable-networking", "Deshabilitar networking")
slib.setLang("eprotect", "es", "disable-all-networking", "Deshabilitar todo el networking")
slib.setLang("eprotect", "es", "disable-all-networking-tooltip", "Si esto esta habilitado, nadie va a poder usar el network en el server!")
slib.setLang("eprotect", "es", "player", "Jugador")
slib.setLang("eprotect", "es", "net-string", "Net String")
slib.setLang("eprotect", "es", "called", "LLamado")
slib.setLang("eprotect", "es", "len", "Len")
slib.setLang("eprotect", "es", "type", "Tipo")
slib.setLang("eprotect", "es", "activated", "Activado")
slib.setLang("eprotect", "es", "secure", "Seguro")
slib.setLang("eprotect", "es", "ip", "Dirección IP")
slib.setLang("eprotect", "es", "date", "Fecha")
slib.setLang("eprotect", "es", "country-code", "Código de País")
slib.setLang("eprotect", "es", "status", "Status")
slib.setLang("eprotect", "es", "unknown", "Desconocido")
slib.setLang("eprotect", "es", "secured", "Seguro")
slib.setLang("eprotect", "es", "check-ids", "Checkear ID(s)")
slib.setLang("eprotect", "es", "correlate-ip", "Correlacionar IP(s)")
slib.setLang("eprotect", "es", "family-share-check", "Checkear Cuentas Familiares")
slib.setLang("eprotect", "es", "ply-sent-invalid-data", "Este Jugador envió datos inválidos!")
slib.setLang("eprotect", "es", "ply-failed-retrieving-data", "%s Fallo al recibir datos!")
slib.setLang("eprotect", "es", "net-limit-desc", "Este nuemero es la cantidad de veces que la gente puede usar network en un segundo antes de usar el LimitadorRate.")
slib.setLang("eprotect", "es", "capture", "Screenshot")
slib.setLang("eprotect", "es", "check-ips", "Checkear IP(s)")
slib.setLang("eprotect", "es", "fetch-data", "Buscar Datos")
elseif SERVER then
slib.setLang("eprotect", "es", "invalid-player", "Este Jugador en invalido!")
slib.setLang("eprotect", "es", "kick-net-overflow", "Fuiste expulsado por net overflow!")
slib.setLang("eprotect", "es", "banned-net-overflow", "Fuiste suspendido por net overflow!")
slib.setLang("eprotect", "es", "banned-net-exploitation", "Fuiste expulsado por exploitiar mensajes net!")
slib.setLang("eprotect", "es", "kick-malicious-intent", "Fuiste expulsado por intenciones maliciosas!")
slib.setLang("eprotect", "es", "banned-malicious-intent", "Fuiste suspendido por intenciones maliciosas!")
slib.setLang("eprotect", "es", "banned-exploit-attempt", "Fuiste suspendido por intentar usar un maliciosas!")
slib.setLang("eprotect", "es", "sc-timeout", "Tenes que esperar %s segundos antes de poder screeshotear a %s otra vez!")
slib.setLang("eprotect", "es", "sc-failed", "Fallo al cargar screenshot de %s, sospechoso...")
slib.setLang("eprotect", "es", "has-family-share", "%s esta jugando con una cuenta familiar, el SteamD64 del dueño es %s")
slib.setLang("eprotect", "es", "no-family-share", "%s no esta jugando con una cuenta familiar!")
slib.setLang("eprotect", "es", "no-correlation", "No se pudieron correlacionar IPs con %s")
end

View File

@@ -1,88 +0,0 @@
--[[
| 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 CLIENT then
slib.setLang("eprotect", "tr", "sc-preview", "Ekranı Görüntüle - ")
slib.setLang("eprotect", "tr", "net-info", "Ağ bilgisi - ")
slib.setLang("eprotect", "tr", "ip-info", "IP bilgisi - ")
slib.setLang("eprotect", "tr", "id-info", "ID bilgisi - ")
slib.setLang("eprotect", "tr", "ip-correlation", "IP ilişkisi - ")
slib.setLang("eprotect", "tr", "table-viewer", "Masa Görüntülemesi")
slib.setLang("eprotect", "tr", "tab-general", "Genel")
slib.setLang("eprotect", "tr", "tab-identifier", "Tanımlayıcı")
slib.setLang("eprotect", "tr", "tab-netlimiter", "Bağ limitleyicisi")
slib.setLang("eprotect", "tr", "tab-netlogger", "Ağ kayıısı")
slib.setLang("eprotect", "tr", "tab-exploitpatcher", "Exploit Güncelleyici")
slib.setLang("eprotect", "tr", "tab-exploitfinder", "Exploit Bulucusu")
slib.setLang("eprotect", "tr", "tab-fakeexploits", "Sahte Exploitler")
slib.setLang("eprotect", "tr", "tab-datasnooper", "Kayıt ağı")
slib.setLang("eprotect", "tr", "player-list", "Oyuncu Listesi")
slib.setLang("eprotect", "tr", "ratelimit", "Hız sınırlayıcısı")
slib.setLang("eprotect", "tr", "ratelimit-tooltip", "Bu genel bir hız sınırlayıcısı. (Xs/Y)")
slib.setLang("eprotect", "tr", "timeout", "Zaman Aşımı")
slib.setLang("eprotect", "tr", "timeout-tooltip", "Bu zaman aşımı genel hız sınırlayıcısına karşıdır.")
slib.setLang("eprotect", "tr", "overflowpunishment", "Taşma cezası")
slib.setLang("eprotect", "tr", "overflowpunishment-tooltip", "Bu ceza ağı rahatlatmak için uygulanır. (1 = kick, 2 = ban)")
slib.setLang("eprotect", "tr", "enable-networking", "Ağ oluşturmayı aktifleştir")
slib.setLang("eprotect", "tr", "disable-networking", "Ağ oluşturmayı engelle")
slib.setLang("eprotect", "tr", "disable-all-networking", "Tüm ağ oluşturmayı engelle")
slib.setLang("eprotect", "tr", "disable-all-networking-tooltip", "Eğer bu aktif olursa kimse sunucuya giremez!")
slib.setLang("eprotect", "tr", "player", "Player")
slib.setLang("eprotect", "tr", "net-string", "Net String")
slib.setLang("eprotect", "tr", "called", "Called")
slib.setLang("eprotect", "tr", "len", "Len")
slib.setLang("eprotect", "tr", "type", "Type")
slib.setLang("eprotect", "tr", "activated", "Activated")
slib.setLang("eprotect", "tr", "secure", "Secured")
slib.setLang("eprotect", "tr", "ip", "IP Adress")
slib.setLang("eprotect", "tr", "date", "Date")
slib.setLang("eprotect", "tr", "country-code", "Country code")
slib.setLang("eprotect", "tr", "status", "Status")
slib.setLang("eprotect", "tr", "unknown", "Unknown")
slib.setLang("eprotect", "tr", "secured", "Secured")
slib.setLang("eprotect", "tr", "check-ids", "ID'leri kontrol et")
slib.setLang("eprotect", "tr", "correlate-ip", "IP adreslerini ilişkilendir")
slib.setLang("eprotect", "tr", "family-share-check", "Aile paylaşımını kontrol et")
slib.setLang("eprotect", "tr", "ply-sent-invalid-data", "Bu oyuncu geçersiz data gönderdi!")
slib.setLang("eprotect", "tr", "ply-failed-retrieving-data", "%s data alınamadı!")
slib.setLang("eprotect", "tr", "net-limit-desc", "Buradaki sayı, insanların hız sınırlandırılmadan önce bir saniye içinde sunucuya maksimum ağ kurma sayısıdır..")
slib.setLang("eprotect", "tr", "capture", "Screenshot")
slib.setLang("eprotect", "tr", "check-ips", "Check IP(s)")
slib.setLang("eprotect", "tr", "fetch-data", "Fetch Data")
elseif SERVER then
slib.setLang("eprotect", "tr", "invalid-player", "böyle bir oyuncu yok!")
slib.setLang("eprotect", "tr", "kick-net-overflow", "Net ağına karşı kötü niyetli eylem gerçekleştirdiğinizden dolayı atıldınız!")
slib.setLang("eprotect", "tr", "banned-net-overflow", "Net ağına karşı kötü niyetli eylem gerçekleştirdiğinizden dolayı yasaklandınız !")
slib.setLang("eprotect", "tr", "banned-net-exploitation", "Net ağına karşı kötü niyetli eylem gerçekleştirdiğinizden dolayı yasaklandınız!")
slib.setLang("eprotect", "tr", "kick-malicious-intent", "Kötü niyetli eylem gerçekleştirdiğinizden dolayı sunucudan atıldınız!")
slib.setLang("eprotect", "tr", "banned-malicious-intent", "Kötü niyetli eylem gerçekleştirdiğinizden dolayı sunucudan yasaklandınız!")
slib.setLang("eprotect", "tr", "banned-exploit-attempt", "Exploit kullanmaya çalıştığın için sunucudan yasaklandın !")
slib.setLang("eprotect", "tr", "sc-timeout", "Şu kadar %s saniye beklemen gerek %s tekrar ekran görüntüsü almak için!")
slib.setLang("eprotect", "tr", "sc-failed", "Şu kişiden ekran görüntüsü alınamadı %s, şüpheli!")
slib.setLang("eprotect", "tr", "has-family-share", "%s Aile paylaşımından oynuyor oyunu ödünç aldığı kişinin ID'si %s!")
slib.setLang("eprotect", "tr", "no-family-share", "%s Aile paylaşımından oynamıyor!")
slib.setLang("eprotect", "tr", "no-correlation", "Şu değer için hiç bir IP adresi ilişkilendirilemedi %s")
end

View File

@@ -1,29 +0,0 @@
--[[
| 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 punished = {}
eProtect.logDetectionHandeler = function(ply, reason, info, type)
if eProtect.data.general["bypassgroup"][ply:GetUserGroup()] or eProtect.config["disabledModules"]["detection_log"] then return end
local sid, sid64 = ply:SteamID(), ply:SteamID64()
if eProtect.data.general["bypass_sids"][sid] or eProtect.data.general["bypass_sids"][sid64] then return end
if punished[sid] and CurTime() < punished[sid] then return end
punished[sid] = CurTime() + eProtect.data.general.timeout + 1
local name, sid64 = ply:Nick(), ply:SteamID64()
eProtect.logDetection(name, sid64, reason, info, type)
end
if eProtect.queueNetworking then
eProtect.queueNetworking(nil, "punishmentLogging")
end

View File

@@ -1,50 +0,0 @@
--[[
| 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/
--]]
eProtect = eProtect or {}
eProtect.data = eProtect.data or {}
eProtect.data.exploitPatcher = eProtect.data.exploitPatcher or {}
eProtect.patcher = eProtect.patcher or {}
local function addExploitPatch(str, func)
eProtect.patcher[str] = func
eProtect.data.exploitPatcher[str] = true
end
addExploitPatch("start_wd_emp", function(ply)
if IsValid(ply) and ply:IsPlayer() then
local wep = ply:GetActiveWeapon()
if !IsValid(wep) or wep:GetClass() ~= "weapon_hack_phone" then
return false
end
end
end)
addExploitPatch("gPrinters.removePrinter", function(ply)
if IsValid(ply) and ply:IsPlayer() then
return ply:IsSuperAdmin()
end
end)
hook.Add("eP:PreNetworking", "eP:ExploitPatches", function(ply, netstring, len)
if eProtect.patcher[netstring] and isfunction(eProtect.patcher[netstring]) and !eProtect.config["disabledModules"]["exploit_patcher"] then
local result = eProtect.patcher[netstring](ply)
if result == false then
eProtect.logDetectionHandeler(ply, "patched-exploit", netstring, 2)
eProtect.punish(ply, 2, slib.getLang("eprotect", eProtect.config["language"], "banned-exploit-attempt"))
return false end
end
end)
if eProtect.queueNetworking then
eProtect.queueNetworking(nil, "exploitPatcher")
end

View File

@@ -1,60 +0,0 @@
--[[
| 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/
--]]
eProtect = eProtect or {}
eProtect.data = eProtect.data or {}
eProtect.data.fakeNets = eProtect.data.fakeNets or {}
local generatedOnes = {}
eProtect.getRandUniqueNum = function()
local rand = math.random(1, 999999)
if generatedOnes[rand] then return eProtect.getRandUniqueNum() end
generatedOnes[rand] = true
return rand
end
eProtect.createFakeNets = function()
if eProtect.config["disabledModules"]["fake_exploits"] then return end
local createdNets = 0
local maxFakeNets = 3
local mixedTbl = {}
for k,v in pairs(eProtect.data.badNets) do
mixedTbl[eProtect.getRandUniqueNum()] = k
end
for k, netstring in pairs(mixedTbl) do
local validateNet = tobool(util.NetworkStringToID(netstring))
if validateNet then continue end
createdNets = createdNets + 1
eProtect.data.fakeNets[netstring] = eProtect.data.fakeNets[netstring] or eProtect.data.badNets[netstring]
eProtect.data.fakeNets[netstring].enabled = true
util.AddNetworkString(netstring)
net.Receive(netstring, function(_, ply)
eProtect.logDetectionHandeler(ply, "fake-exploit", netstring, 2)
eProtect.punish(ply, 2, slib.getLang("eprotect", eProtect.config["language"], "banned-net-exploitation"))
end)
if maxFakeNets > 0 and (createdNets >= maxFakeNets) then break end
end
if eProtect.queueNetworking then
eProtect.queueNetworking(nil, "fakeNets")
end
end
eProtect.createFakeNets()

View File

@@ -1,13 +0,0 @@
--[[
| 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/
--]]
hook.Add("eP:PostHTTP", "eP:HTTPLoggingHandeler", function(url, type)
eProtect.logHTTP(url, type)
end)

View File

@@ -1,36 +0,0 @@
--[[
| 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 function handleIPLoggin(ply, ip)
local sid64 = ply:SteamID64()
http.Fetch("http://ip-api.com/json/"..ip, function(json)
json = util.JSONToTable(json)
local result = json["countryCode"]
if !result then result = "N/A" end
eProtect.registerIP(sid64, ip, result)
end, function()
eProtect.registerIP(sid64, ip, "N/A")
end)
end
hook.Add("PlayerInitialSpawn", "eP:IPLogging", function(ply)
if ply:IsBot() or eProtect.config["disabledModules"]["identifier"] then return end
local ip = ""
for k,v in ipairs(string.ToTable(ply:IPAddress())) do
if v == ":" then break end
ip = ip..v
end
handleIPLoggin(ply, ip)
end)

View File

@@ -1,78 +0,0 @@
--[[
| 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/
--]]
eProtect = eProtect or {}
eProtect.data = eProtect.data or {}
eProtect.data.netLimitation = eProtect.data.netLimitation or {}
for i = 1, 2048 do
local netstring = util.NetworkIDToString(i)
if !netstring then continue end
if netstring and isstring(netstring) and eProtect.data.netLimitation[netstring] == nil and !eProtect.data.fakeNets[netstring] then
local func = net.Receivers[string.lower(netstring)]
if func then eProtect.data.netLimitation[netstring] = 0 end
end
end
if eProtect.queueNetworking then
eProtect.queueNetworking(nil, "netLimitation")
end
local generalCounter = {}
local specificCounter = {}
local timeout = {}
hook.Add("eP:PreNetworking", "eP:NetLimiter", function(ply, netstring, len)
if !eProtect.data or !eProtect.data.general or eProtect.data.netLimitation[netstring] == -1 or eProtect.config["disabledModules"]["net_limiter"] then return end
if !eProtect.data.netLimitation[netstring] then
local func = net.Receivers[string.lower(netstring)]
if func then eProtect.data.netLimitation[netstring] = 0 end
eProtect.queueNetworking(nil, "netLimitation")
end
local sid, sid64 = ply:SteamID(), ply:SteamID64()
local specific = eProtect.data.netLimitation[netstring] ~= nil and eProtect.data.netLimitation[netstring] > 0 or false
specificCounter[sid] = specificCounter[sid] or {}
if !timeout[sid] then timeout[sid] = CurTime() end
if timeout[sid] and ((CurTime() - timeout[sid]) >= eProtect.data.general.timeout) then
specificCounter[sid] = {}
generalCounter[sid] = 0
timeout[sid] = nil
end
if specific then
specificCounter[sid][netstring] = specificCounter[sid][netstring] or 0
specificCounter[sid][netstring] = specificCounter[sid][netstring] + 1
else
generalCounter[sid] = generalCounter[sid] or 0
generalCounter[sid] = generalCounter[sid] + 1
end
local counter = specific and specificCounter[sid][netstring] or generalCounter[sid]
local limit = specific and eProtect.data.netLimitation[netstring] or eProtect.data.general.ratelimit
if limit > -1 and counter > limit and eProtect.data.general.overflowpunishment > 0 and !eProtect.data.general["bypassgroup"][ply:GetUserGroup()] and !eProtect.data.general["bypass_sids"][sid] and !eProtect.data.general["bypass_sids"][sid64] then
if eProtect.data.general["whitelistergroup"][ply:GetUserGroup()] then
eProtect.data.netLimitation[netstring] = -1
eProtect.queueNetworking(nil, "netLimitation")
return end
eProtect.logDetectionHandeler(ply, "net-overflow", netstring, eProtect.data.general.overflowpunishment)
if eProtect.data.general.overflowpunishment <= 2 then
eProtect.punish(ply, eProtect.data.general.overflowpunishment, slib.getLang("eprotect", eProtect.config["language"], eProtect.data.general.overflowpunishment == 1 and "kick-net-overflow" or "banned-net-overflow"))
end
return false
end
end)

View File

@@ -1,31 +0,0 @@
--[[
| 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/
--]]
eProtect = eProtect or {}
eProtect.data = eProtect.data or {}
eProtect.data.netLogging = eProtect.data.netLogging or {}
hook.Add("eP:PostNetworking", "eP:LogNetworking", function(ply, net, len)
if !net or len == nil or eProtect.config["disabledModules"]["net_logger"] then return end
eProtect.data.netLogging[net] = eProtect.data.netLogging[net] or {called = 0, len = 0, playercalls = {}}
eProtect.data.netLogging[net].called = eProtect.data.netLogging[net].called + 1
eProtect.data.netLogging[net].len = eProtect.data.netLogging[net].len + len
if IsValid(ply) and ply:IsPlayer() then
local sid = ply:SteamID()
eProtect.data.netLogging[net].playercalls[sid] = eProtect.data.netLogging[net].playercalls[sid] or 0
eProtect.data.netLogging[net].playercalls[sid] = eProtect.data.netLogging[net].playercalls[sid] + 1
end
if eProtect.queueNetworking then
eProtect.queueNetworking(nil, "netLogging")
end
end)

View File

@@ -1,575 +0,0 @@
--[[
| 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/
--]]
eProtect = eProtect or {}
eProtect.queneData = eProtect.queneData or {}
eProtect.saveQueue = eProtect.saveQueue or {}
eProtect.data = eProtect.data or {}
eProtect.data.disabled = eProtect.data.disabled or {}
local ignoreSaving = {
["fakeNets"] = true,
["netLogging"] = true,
["exploitPatcher"] = true
}
util.AddNetworkString("eP:Handeler")
local function openMenu(ply)
net.Start("eP:Handeler")
net.WriteUInt(2, 3)
net.Send(ply)
end
local convertedTbl
convertedTbl = function(tbl)
local converted_tbl = {}
for k,v in pairs(tbl) do
if istable(v) then v = convertedTbl(v) end
local isSID = util.SteamIDFrom64(k) != "STEAM_0:0:0"
if isSID then
converted_tbl["sid64_"..k] = v
else
converted_tbl[k] = v
end
end
return converted_tbl
end
local function networkData(ply, data, specific)
if !data then return end
local data = util.TableToJSON(convertedTbl(data))
data = util.Compress(data)
net.Start("eP:Handeler")
net.WriteUInt(1, 3)
net.WriteUInt(#data, 32)
net.WriteData(data, #data)
if specific then
net.WriteString(specific)
end
net.Send(ply)
end
eProtect.hasPermission = function(ply, specific)
return eProtect.config["permission"][ply:GetUserGroup()]
end
local punished = {}
eProtect.getData = function(specific)
local data = file.Read("eprotect/data.json", "DATA")
if !data then return end
data = util.JSONToTable(data)
if specific then
data = data[specific]
end
for k,v in pairs(data) do
eProtect.data[k] = v
end
return table.Copy(data)
end
eProtect.dataVerification = function()
local data = eProtect.getData()
data = data or {}
data["general"] = data["general"] or {}
for k,v in pairs(eProtect.BaseConfig) do
if data["general"][k] then continue end
data["general"][k] = v[1]
end
for k,v in pairs(eProtect.data) do
if ignoreSaving[k] or k == "general" then continue end
data[k] = v
end
file.CreateDir("eprotect")
file.Write("eprotect/data.json", util.TableToJSON(data))
eProtect.getData()
eProtect.queueNetworking()
end
eProtect.saveData = function()
file.CreateDir("eprotect")
local data = table.Copy(eProtect.data)
for k, v in pairs(data) do
if ignoreSaving[k] then data[k] = nil end
end
file.Write("eprotect/data.json", util.TableToJSON(data))
end
eProtect.canNetwork = function(ply, netstring)
if !IsValid(ply) or !ply:IsPlayer() then return end
if (punished[ply:SteamID()] or eProtect.data.disabled[ply:SteamID()] or eProtect.data.general["disable-all-networking"]) and (netstring ~= "eP:Handeler") then return false end
return true
end
eProtect.punish = function(ply, type, msg, duration)
if eProtect.data.general["bypassgroup"][ply:GetUserGroup()] or eProtect.data.general["bypass_sids"][ply:SteamID()] or eProtect.data.general["bypass_sids"][ply:SteamID64()] then return end
msg = eProtect.config["prefix"]..msg
punished[ply:SteamID()] = true
slib.punish(ply, type, msg, duration)
end
eProtect.networkData = function(ply)
if eProtect.queneData[ply:SteamID()] then
for k,v in pairs(eProtect.queneData[ply:SteamID()]) do
networkData(ply, eProtect.data[k], k)
eProtect.queneData[ply:SteamID()][k] = nil
end
end
end
local function registerQuene(ply, specific)
if specific then
eProtect.queneData[ply:SteamID()] = eProtect.queneData[ply:SteamID()] and eProtect.queneData[ply:SteamID()] or {}
eProtect.queneData[ply:SteamID()][specific] = true
else
for k,v in pairs(eProtect.data) do
registerQuene(ply, k)
end
end
end
eProtect.queueNetworking = function(ply, specific)
if ply then
registerQuene(ply, specific)
else
for k,v in pairs(player.GetAll()) do
if !IsValid(v) then continue end
registerQuene(v, specific)
end
end
end
local screenshotRequested = {}
local idRequested = {}
local dataRequested = {}
local limitSC = {}
local function requestData(ply, target, type)
local data
if type == 1 then
local sid = target:SteamID()
if limitSC[sid] and CurTime() - limitSC[sid] < 10 then
slib.notify(eProtect.config["prefix"]..slib.getLang("eprotect", eProtect.config["language"], "sc-timeout", math.Round(10 - (CurTime() - limitSC[sid])), target:Nick()), ply)
return end
limitSC[sid] = CurTime()
data = screenshotRequested
elseif type == 2 then
data = idRequested
elseif type == 3 then
data = dataRequested
end
if data[target] then return end
data[target] = ply
net.Start("eP:Handeler")
net.WriteUInt(3, 3)
net.WriteUInt(type, 2)
net.WriteBool(false)
net.Send(target)
timer.Simple(10, function()
if !target or !ply then return end
if data[target] then
data[target] = nil
slib.notify(eProtect.config["prefix"]..slib.getLang("eprotect", eProtect.config["language"], "sc-failed", target:Nick()), ply)
end
end)
end
hook.Add("PlayerInitialSpawn", "eP:NetworkingQueuer", function(ply)
eProtect.queueNetworking(ply)
local sid = ply:SteamID()
if punished[sid] then punished[sid] = nil end
end)
local function verifyBannedAlt(ply, sid64, type)
sid64 = sid64 or ply:SteamID64()
local isBanned = slib.isBanned(sid64, function(banned, sid) if banned then if IsValid(ply) then slib.punish(ply, type, eProtect.config["prefix"]..slib.getLang("eprotect", eProtect.config["language"], "punished-alt")) end end end)
if isBanned then
slib.punish(ply, type, eProtect.config["prefix"]..slib.getLang("eprotect", eProtect.config["language"], "punished-alt"))
end
return isBanned
end
local settingConverter = { // Its reverted on clientside
[1] = 3,
[2] = 1,
[3] = 2
}
hook.Add("PlayerInitialSpawn", "eP:AutomaticChecks", function(ply)
local automatic_identifier = tonumber(eProtect.data.general["automatic-identifier"]) or 1
timer.Simple(1.5, function() -- Giving time to set usergroup.
if !IsValid(ply) or !ply:IsPlayer() or ply:IsBot() or eProtect.data.general["bypassgroup"][ply:GetUserGroup()] or eProtect.data.general["bypass_sids"][ply:SteamID64()] or eProtect.data.general["bypass_sids"][ply:SteamID()] then return end
if eProtect.data.general["block-vpn"] and !eProtect.data.general["bypass-vpn"][ply:GetUserGroup()] and !eProtect.data.general["bypass-vpn"][ply:SteamID64()] then
local ip = ""
for k,v in ipairs(string.ToTable(ply:IPAddress())) do
if v == ":" then break end
ip = ip..v
end
http.Fetch("https://proxycheck.io/v2/"..ip.."?vpn=1", function(result)
result = result and util.JSONToTable(result)
if result[ip] and result[ip].proxy == "yes" then
ply:Kick(eProtect.config["prefix"]..slib.getLang("eprotect", eProtect.config["language"], "vpn-blocked"))
end
end)
end
if automatic_identifier > 0 then
eProtect.correlateIP(ply, function(result)
local correlatedIPs = result
local plysid64, ownerplysid64 = ply:SteamID64(), ply:OwnerSteamID64()
local familyShare = ply:SteamID64() ~= ply:OwnerSteamID64()
local detections = !familyShare and !table.IsEmpty(correlatedIPs)
local altsDetected = {}
if detections then
local detect_type
detections = ""
if correlatedIPs and istable(correlatedIPs) and !table.IsEmpty(correlatedIPs) then
detect_type = "correlated-ip"
local foundAlts = {}
for k,v in ipairs(correlatedIPs) do
table.insert(altsDetected, v.sid64)
end
detections = slib.getLang("eprotect", eProtect.config["language"], "correlated-ip")
end
if familyShare then
detect_type = "family-share"
detections = detections == "" and slib.getLang("eprotect", eProtect.config["language"], "family-share") or detections.." "..slib.getLang("eprotect", eProtect.config["language"], "and").." "..slib.getLang("eprotect", eProtect.config["language"], "family-share")
table.insert(altsDetected, ownerplysid64)
end
if detections ~= "" then
local doneAction
if automatic_identifier == 1 then
for k, v in ipairs(player.GetAll()) do
if eProtect.data.general["notification-groups"][v:GetUserGroup()] then
slib.notify(eProtect.config["prefix"]..slib.getLang("eprotect", eProtect.config["language"], "auto-detected-alt", ply:Nick(), detections), ply)
end
end
doneAction = true
elseif automatic_identifier == 2 then
for k,v in ipairs(altsDetected) do
doneAction = doneAction or verifyBannedAlt(ply, v, 1)
end
elseif automatic_identifier == 3 then
for k,v in ipairs(altsDetected) do
doneAction = doneAction or verifyBannedAlt(ply, v, 2)
end
end
if doneAction then
eProtect.logDetectionHandeler(ply, "alt-detection", slib.getLang("eprotect", eProtect.config["language"], detect_type), settingConverter[automatic_identifier])
end
end
end
end)
end
end)
end)
hook.Add("PlayerSay", "eP:OpenMenu", function(ply, text, public)
if eProtect.config["command"] == string.lower(text) then
if !eProtect.hasPermission(ply) then
return text
end
eProtect.networkData(ply)
openMenu(ply)
return ""
end
end )
hook.Add("eP:PreNetworking", "eP:Restrictions", function(ply, netstring, len)
if !eProtect.canNetwork(ply, netstring) then return false end
if len >= 512000 then eProtect.logDetectionHandeler(ply, "net-overflow", netstring, 1) eProtect.punish(ply, 1, slib.getLang("eprotect", eProtect.config["language"], "kick-net-overflow")) return false end
end)
hook.Add("eP:PreHTTP", "eP:PreventBlockedHTTP", function(url)
if eProtect.data.general["httpfocusedurls"] then
return eProtect.data.general["httpfocusedurlsisblacklist"] == !tobool(eProtect.data.general["httpfocusedurls"][url])
end
end)
timer.Create("eP:SaveCache", eProtect.config["process-save-queue"], 0, function()
if !eProtect.saveQueue then return end
eProtect.saveData()
eProtect.saveQueue = nil
end)
net.Receive("eP:Handeler", function(len, ply)
local gateway = net.ReadBit()
local action = net.ReadUInt(2)
if tobool(gateway) then
if !eProtect.hasPermission(ply) then return end
if action == 0 then
local id = net.ReadUInt(1)
local page = net.ReadUInt(15)
local search = net.ReadString()
if id == 0 then
eProtect.requestHTTPLog(ply, page, search)
elseif id == 1 then
eProtect.requestDetectionLog(ply, page, search)
end
elseif action == 1 then
local specific = net.ReadUInt(3)
local strings = {}
for i=1,specific do
strings[i] = net.ReadString()
end
local statement = net.ReadUInt(2)
local data
if statement == 1 then
data = net.ReadBool()
elseif statement == 2 then
data = net.ReadInt(32)
elseif statement == 3 then
local chunk = net.ReadUInt(32)
data = net.ReadData(chunk)
data = util.Decompress(data)
data = util.JSONToTable(data)
local converted_tbl = {}
for k, v in pairs(data) do
if string.sub(k, 1, 6) == "sid64_" then
local sid64 = string.sub(k, 7, #k)
if util.SteamIDFrom64(sid64) != "STEAM_0:0:0" then
k = sid64
end
end
converted_tbl[k] = v
end
data = converted_tbl
end
local finaldestination = eProtect.data
for k,v in ipairs(strings) do
finaldestination = finaldestination[v]
if k >= (#strings - 1) then break end
end
finaldestination[strings[#strings]] = data
eProtect.saveQueue = true
eProtect.queueNetworking(nil, strings[1])
elseif action == 2 then
local subaction = net.ReadUInt(3)
local target = net.ReadUInt(14)
target = Entity(target)
if !IsValid(target) or !target:IsPlayer() then slib.notify(eProtect.config["prefix"]..slib.getLang("eprotect", eProtect.config["language"], "invalid-player"), ply) return end
local sid = target:SteamID()
if subaction == 1 then
eProtect.data.disabled[sid] = net.ReadBool()
eProtect.queueNetworking(nil, "disabled")
elseif subaction == 2 then
requestData(ply, target, net.ReadUInt(2))
elseif subaction == 3 then
local bit = net.ReadBit()
if tobool(bit) then
eProtect.correlateIP(target, function(result)
if !IsValid(target) or !IsValid(ply) then return end
if table.IsEmpty(result) then slib.notify(eProtect.config["prefix"]..slib.getLang("eprotect", eProtect.config["language"], "no-correlation", target:Nick()), ply) return end
result = util.TableToJSON(result)
result = util.Base64Encode(result)
net.Start("eP:Handeler")
net.WriteUInt(4,3)
net.WriteUInt(target:EntIndex(), 14)
net.WriteString(result)
net.WriteBit(1)
net.Send(ply)
end)
else
eProtect.showIPs(target, ply)
end
elseif subaction == 4 then
local sid64 = target:SteamID64()
local ownersid64 = target:OwnerSteamID64()
if sid64 == ownersid64 then
slib.notify(eProtect.config["prefix"]..slib.getLang("eprotect", eProtect.config["language"], "no-family-share", target:Nick()), ply)
else
slib.notify(eProtect.config["prefix"]..slib.getLang("eprotect", eProtect.config["language"], "has-family-share", target:Nick(), ownersid64), ply)
end
end
end
else
if action == 1 then
local subaction = net.ReadUInt(2)
local data
if subaction == 1 then
data = screenshotRequested
elseif subaction == 2 then
data = idRequested
elseif subaction == 3 then
data = dataRequested
end
if !data[ply] then if eProtect.config["punishMaliciousIntent"] then eProtect.punish(ply, 1, slib.getLang("eprotect", eProtect.config["language"], "kick-malicious-intent")) end return end
local target = data[ply]
data[ply] = nil
local id
if subaction == 3 then
local chunk = net.ReadUInt(32)
id = net.ReadData(chunk)
else
id = net.ReadString()
end
if !id or id == "" then
if eProtect.config["punishMaliciousIntent"] then
eProtect.punish(ply, 1, slib.getLang("eprotect", eProtect.config["language"], "kick-malicious-intent"))
end
return end
net.Start("eP:Handeler")
net.WriteUInt(3, 3)
net.WriteUInt(subaction, 2)
net.WriteUInt(ply:EntIndex(), 14)
net.WriteBool(true)
if subaction == 3 then
local chunk = #id
net.WriteUInt(chunk, 32)
net.WriteData(id, chunk)
else
net.WriteString(id)
end
net.Send(target)
elseif action == 2 then
local menu = net.ReadUInt(2)
local menus = {
[1] = "Loki",
[2] = "Exploit City"
}
eProtect.logDetectionHandeler(ply, "exploit-menu", menus[menu], 2)
eProtect.punish(ply, 2, slib.getLang("eprotect", eProtect.config["language"], "banned-exploit-menu"))
end
end
end)
hook.Add("eP:SQLConnected", "eP:TransferOldIPs", function()
local files = file.Find("eprotect/ips/*", "DATA")
for k,v in pairs(files) do
local sid64 = string.gsub(v, ".json", "")
local ips = file.Read("eprotect/ips/"..v, "DATA")
ips = util.JSONToTable(ips)
if !ips then continue end
for ip, data in pairs(ips) do
eProtect.registerIP(sid64, ip, data[1], data[2])
end
file.Delete("eprotect/ips/"..v)
end
file.Delete("eprotect/ips")
local save = false
if eProtect.data.httpLogging then
for url, v in pairs(eProtect.data.httpLogging) do
eProtect.logHTTP(url, v.type, v.called)
end
eProtect.data.httpLogging = nil
save = true
end
if eProtect.data.punishmentLogging then
for i = #eProtect.data.punishmentLogging, 1, -1 do
local data = eProtect.data.punishmentLogging[i]
eProtect.logDetection(data.ply, "", data.reason, data.info, data.type)
end
eProtect.data.punishmentLogging = nil
save = true
end
if save then
eProtect.saveData()
end
end)
eProtect.dataVerification()

View File

@@ -1,67 +0,0 @@
--[[
| 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/
--]]
eProtect = eProtect or {}
eProtect.overrides = eProtect.overrides or {}
if !eProtect.overrides["net.Incoming"] then
eProtect.overrides["net.Incoming"] = true
function net.Incoming( len, client )
local i = net.ReadHeader()
local strName = util.NetworkIDToString( i )
if ( !strName ) then return end
local func = net.Receivers[ strName:lower() ]
if ( !func ) then return end
len = len - 16
local pre = hook.Run("eP:PreNetworking", client, strName, len)
if pre == false then return end
func( len, client )
hook.Run("eP:PostNetworking", client, strName, len)
end
end
if !eProtect.config["disablehttplogging"] and ((!VC and !XEON and !mLib) or eProtect.config["ignoreDRM"]) then
if !eProtect.overrides["http.Fetch"] then
eProtect.overrides["http.Fetch"] = true
local oldFetch = http.Fetch
function http.Fetch(...)
local args = {...}
local result = hook.Run("eP:PreHTTP", args[1], "fetch")
if result == false then return end
oldFetch(...)
hook.Run("eP:PostHTTP", args[1], "fetch")
end
end
if !eProtect.overrides["http.Post"] then
eProtect.overrides["http.Post"] = true
local oldPost = http.Post
function http.Post(...)
local args = {...}
local result = hook.Run("eP:PreHTTP", args[1], "post")
if result == false then return end
oldPost(...)
hook.Run("eP:PostHTTP", args[1], "post")
end
end
end

View File

@@ -1,245 +0,0 @@
--[[
| 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 query, db
local escape_str = function(str) return SQLStr(str, true) end
local create_queries = {
[1] = [[CREATE TABLE IF NOT EXISTS eprotect_ips(
id INTEGER PRIMARY KEY %s,
sid64 CHAR(17),
ip CHAR(15),
country CHAR(3),
logged_time INTEGER DEFAULT 0
)]],
[2] = [[CREATE TABLE IF NOT EXISTS eprotect_detections(
id INTEGER PRIMARY KEY %s,
name CHAR(32),
sid64 CHAR(17),
reason CHAR(32),
info CHAR(32),
type INTEGER DEFAULT 0,
logged_time INTEGER DEFAULT 0
)]],
[3] = [[CREATE TABLE IF NOT EXISTS eprotect_http(
id INTEGER PRIMARY KEY %s,
link CHAR(64),
type CHAR(6),
called INTEGER DEFAULT 0
)]]
}
local function makeTables()
for i = 1, #create_queries do
query(string.format(create_queries[i], eProtect.config["storage_type"] == "sql_local" and "AUTOINCREMENT" or "AUTO_INCREMENT"))
end
end
if eProtect.config["storage_type"] == "mysql" then
require("mysqloo")
query = function() end
local dbinfo = eProtect.config["mysql_info"]
db = mysqloo.connect(dbinfo.host, dbinfo.username, dbinfo.password, dbinfo.database, dbinfo.port)
function db:onConnected()
print(eProtect.config["prefix"]..slib.getLang("eprotect", eProtect.config["language"], "mysql_successfull"))
query = function(str, func)
local q = db:query(str)
q.onSuccess = function(_, data)
if func then
func(data)
end
end
q.onError = function(_, err) end
q:start()
end
escape_str = function(str) return db:escape(tostring(str)) end
makeTables()
hook.Run("eP:SQLConnected")
end
function db:onConnectionFailed(err)
print(eProtect.config["prefix"]..slib.getLang("eprotect", eProtect.config["language"], "mysql_failed"))
print( "Error:", err )
end
db:connect()
else
local oldFunc = sql.Query
query = function(str, func)
local result = oldFunc(str)
if func then
func(result)
end
end
makeTables()
end
local function handleCallbacksCorrelation(parent_tbl, correlated, callback)
for k,v in ipairs(parent_tbl) do
if !v then return end
end
if !callback then return end
callback(correlated or {})
end
eProtect.correlateIP = function(target, callback)
if !IsValid(target) then return end
local sid64 = target:SteamID64()
local tbl = {}
query("SELECT * FROM eprotect_ips WHERE sid64 = '"..sid64.."'", function(result)
if result and result[1] then
local parent_tbl = {}
for k, v in ipairs(result) do
parent_tbl[k] = false
end
for key, plydata in ipairs(result) do
query("SELECT * FROM eprotect_ips WHERE ip = '"..(plydata.ip).."'", function(result)
if result and result[1] then
for k,v in ipairs(result) do
if v.sid64 == sid64 then continue end
table.insert(tbl, {sid64 = v.sid64, ip = v.ip})
end
end
parent_tbl[key] = true
handleCallbacksCorrelation(parent_tbl, tbl, callback)
end)
end
end
end)
end
eProtect.showIPs = function(target, ply)
local sid64 = target:SteamID64()
query("SELECT * FROM eprotect_ips WHERE sid64 = '"..sid64.."'", function(result)
if !IsValid(target) or !IsValid(ply) or !result or !result[1] then return end
result = util.TableToJSON(result)
result = util.Base64Encode(result)
net.Start("eP:Handeler")
net.WriteUInt(4,3)
net.WriteUInt(target:EntIndex(), 14)
net.WriteString(result)
net.WriteBit(0)
net.Send(ply)
end)
end
eProtect.registerIP = function(sid64, ip, country, time)
query("SELECT * FROM eprotect_ips WHERE ip = '"..ip.."' AND sid64 = '"..sid64.."'", function(result)
if result and result[1] then return end
query(string.format("INSERT INTO eprotect_ips(ip, sid64, country, logged_time) VALUES('%s', %s, '%s', %s)", escape_str(ip), sid64, escape_str(country), time or os.time()))
end)
end
eProtect.logDetection = function(name, sid64, reason, info, type)
query(string.format("INSERT INTO eprotect_detections(name, sid64, reason, info, type, logged_time) VALUES('%s', '%s', '%s', '%s', '%s', %s)", escape_str(name), escape_str(sid64), escape_str(reason), escape_str(info), escape_str(type), os.time()))
end
eProtect.logHTTP = function(link, type, called)
link = escape_str(link)
query("SELECT * FROM eprotect_http WHERE link = '"..link.."'", function(result)
if result and result[1] then
query("UPDATE eprotect_http SET called = "..(result[1].called + 1).." WHERE link = '"..link.."'")
return end
query(string.format("INSERT INTO eprotect_http(link, type, called) VALUES('%s', '%s', "..(tonumber(called) or 1)..")", link, escape_str(type)))
end)
end
local function networkData(ply, data, id)
local compressed = util.Compress(util.TableToJSON(data))
net.Start("eP:Handeler")
net.WriteUInt(5, 3)
net.WriteUInt(id, 1)
net.WriteUInt(#compressed, 32)
net.WriteData(compressed, #compressed)
net.Send(ply)
end
local http_cd, detection_cd = {}, {}
eProtect.requestHTTPLog = function(ply, page, search)
if http_cd[ply] and http_cd[ply] > CurTime() then return end
http_cd[ply] = CurTime() + .1
search = search ~= "" and escape_str(search) or nil
local perpage, pageCount = 20, 1
local start = perpage * ((tonumber(page) or 1) - 1)
local data = {}
local search_str = search and " WHERE (link LIKE '%"..search.."%')" or ""
query("SELECT COUNT(id) FROM eprotect_http"..search_str, function(pageresult)
if pageresult and pageresult[1] and pageresult[1]["COUNT(id)"] then
data.pageCount = math.max(math.ceil((pageresult[1]["COUNT(id)"] or 0) / perpage), 1)
end
data.page = page
query("SELECT * FROM eprotect_http "..search_str.." LIMIT "..start..", "..perpage, function(result)
data.result = result
networkData(ply, data, 0)
end)
end)
end
eProtect.requestDetectionLog = function(ply, page, search)
if detection_cd[ply] and detection_cd[ply] > CurTime() then return end
detection_cd[ply] = CurTime() + .1
search = search ~= "" and escape_str(search) or nil
local perpage, pageCount = 20, 1
local start = perpage * ((tonumber(page) or 1) - 1)
local data = {}
local search_str = search and " WHERE (sid64 LIKE '%"..search.."%' OR name LIKE '%"..search.."%') " or ""
query("SELECT COUNT(id) FROM eprotect_detections"..search_str, function(pageresult)
if pageresult and pageresult[1] and pageresult[1]["COUNT(id)"] then
data.pageCount = math.max(math.ceil((pageresult[1]["COUNT(id)"] or 0) / perpage), 1)
end
data.page = page
query("SELECT * FROM eprotect_detections"..search_str.." ORDER BY id DESC LIMIT "..start..", "..perpage, function(result)
data.result = result
networkData(ply, data, 1)
end)
end)
end
if eProtect.config["storage_type"] == "sql_local" then
hook.Run("eP:SQLConnected")
end

View File

@@ -1,109 +0,0 @@
--[[
| 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/
--]]
------------------------------------------------------
-- NO NOT TOUCH ANYTHING IN HERE!!!!!!!!!
------------------------------------------------------
eProtect = eProtect or {}
eProtect.BaseConfig = eProtect.BaseConfig or {}
eProtect.BaseConfig["disable-all-networking"] = {false, 1}
eProtect.BaseConfig["automatic-identifier"] = {1, 2, {min = 0, max = 3}}
eProtect.BaseConfig["block-vpn"] = {false, 3}
eProtect.BaseConfig["bypass-vpn"] = {{["76561198002319944"] = true}, 4, function()
local list = {}
for k,v in ipairs(player.GetAll()) do
local sid64 = v:SteamID64()
if !sid64 then continue end
list[sid64] = true
end
if CAMI and CAMI.GetUsergroups then
for k,v in pairs(CAMI.GetUsergroups()) do
list[k] = true
end
end
return list
end}
eProtect.BaseConfig["notification-groups"] = {{["superadmin"] = true}, 5, CAMI and CAMI.GetUsergroups and function() local tbl = {} for k,v in pairs(CAMI.GetUsergroups()) do tbl[k] = true end return tbl end or {}}
eProtect.BaseConfig["ratelimit"] = {500, 6, {min = -1, max = 100000}}
eProtect.BaseConfig["timeout"] = {3, 7, {min = 0, max = 5000}}
eProtect.BaseConfig["overflowpunishment"] = {2, 8, {min = 0, max = 3}}
eProtect.BaseConfig["whitelistergroup"] = {{}, 9, function()
local list = {}
if CAMI and CAMI.GetUsergroups then
for k,v in pairs(CAMI.GetUsergroups()) do
list[k] = true
end
end
return list
end}
eProtect.BaseConfig["bypassgroup"] = {{}, 10, function()
local list = {
["superadmin"] = true,
["owner"] = true
}
if CAMI and CAMI.GetUsergroups then
for k,v in pairs(CAMI.GetUsergroups()) do
list[k] = true
end
end
return list
end}
eProtect.BaseConfig["bypass_sids"] = {{["76561198002319944"] = true}, 11, function()
local list = {}
for k,v in ipairs(player.GetAll()) do
local sid64 = v:SteamID64()
if !sid64 then continue end
list[sid64] = true
end
return list
end}
eProtect.BaseConfig["httpfocusedurlsisblacklist"] = {true, 12}
eProtect.BaseConfig["httpfocusedurls"] = {{}, 13, function()
local list = {}
local tbl_http = eProtect.data["requestedHTTP"] and eProtect.data["requestedHTTP"].result or {}
if tbl_http then
for k,v in ipairs(tbl_http) do
list[v.link] = true
end
end
return list
end}
------------------------------------------------------
-- NO NOT TOUCH ANYTHING IN HERE!!!!!!!!!
------------------------------------------------------76561198002319944

View File

@@ -1,43 +0,0 @@
--[[
| 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/
--]]
eProtect = eProtect or {}
eProtect.config = eProtect.config or {}
eProtect.config["language"] = "en"
eProtect.config["prefix"] = "[eProtect] "
eProtect.config["storage_type"] = "mysql"-- (sql_local or mysql)
eProtect.config["disablehttplogging"] = false -- If a DRM is ran after eProtect it could break if they check for HTTP modifications! If so make this true.
eProtect.config["ignoreDRM"] = false
eProtect.config["punishMaliciousIntent"] = true
eProtect.config["disabledModules"] = {
["identifier"] = false,
["detection_log"] = false,
["net_limiter"] = false,
["net_logger"] = false,
["exploit_patcher"] = false,
["exploit_finder"] = false,
["fake_exploits"] = false,
["data_snooper"] = false
}
eProtect.config["permission"] = {
["owner"] = true,
["superadmin"] = true,
["community_manager"] = true,
["headofstaff"] = true
}

View File

@@ -1,550 +0,0 @@
--[[
| 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/
--]]
eProtect = eProtect or {}
eProtect.config = eProtect.config or {}
eProtect.config["mysql_info"] = {
host = "144.76.235.183",
port = 3306,
database = "s6_eprotect",
username = "u6_PouapUJD6P",
password = "V!3P!7^NQSXGvyBZPE76O^GY"
}
eProtect.config["command"] = "!eprotect"
eProtect.config["process-save-queue"] = 10 --- This will check if we should save data to the file. 00
eProtect.data = eProtect.data or {}
eProtect.data.badNets = eProtect.data.badNets or {}
eProtect.registerBadNet = function(netstring, num)
eProtect.data.badNets[netstring] = {type = num}
end
-- Credits to meepen for the table with known exploits and backdoors! <3
--- Known Exploits
eProtect.registerBadNet("pplay_deleterow", 1)
eProtect.registerBadNet("pplay_addrow", 1)
eProtect.registerBadNet("pplay_sendtable", 1)
eProtect.registerBadNet("WriteQuery", 1)
eProtect.registerBadNet("SendMoney", 1)
eProtect.registerBadNet("BailOut", 1)
eProtect.registerBadNet("customprinter_get", 1)
eProtect.registerBadNet("textstickers_entdata", 1)
eProtect.registerBadNet("NC_GetNameChange", 1)
eProtect.registerBadNet("ATS_WARP_REMOVE_CLIENT", 1)
eProtect.registerBadNet("ATS_WARP_FROM_CLIENT", 1)
eProtect.registerBadNet("ATS_WARP_VIEWOWNER", 1)
eProtect.registerBadNet("CFRemoveGame", 1)
eProtect.registerBadNet("CFJoinGame", 1)
eProtect.registerBadNet("CFEndGame", 1)
eProtect.registerBadNet("CreateCase", 1)
eProtect.registerBadNet("rprotect_terminal_settings", 1)
eProtect.registerBadNet("StackGhost", 1)
eProtect.registerBadNet("RevivePlayer", 1)
eProtect.registerBadNet("ARMORY_RetrieveWeapon", 1)
eProtect.registerBadNet("TransferReport", 1)
eProtect.registerBadNet("SimplicityAC_aysent", 1)
eProtect.registerBadNet("pac_to_contraption", 1)
eProtect.registerBadNet("SyncPrinterButtons76561198056171650", 1)
eProtect.registerBadNet("sendtable", 1)
eProtect.registerBadNet("steamid2", 1)
eProtect.registerBadNet("Kun_SellDrug", 1)
eProtect.registerBadNet("net_PSUnBoxServer", 1)
eProtect.registerBadNet("pplay_deleterow", 1)
eProtect.registerBadNet("pplay_addrow", 1)
eProtect.registerBadNet("CraftSomething", 1)
eProtect.registerBadNet("banleaver", 1)
eProtect.registerBadNet("75_plus_win", 1)
eProtect.registerBadNet("ATMDepositMoney", 1)
eProtect.registerBadNet("Taxi_Add", 1)
eProtect.registerBadNet("Kun_SellOil", 1)
eProtect.registerBadNet("SellMinerals", 1)
eProtect.registerBadNet("TakeBetMoney", 1)
eProtect.registerBadNet("PoliceJoin", 1)
eProtect.registerBadNet("CpForm_Answers", 1)
eProtect.registerBadNet("DepositMoney", 1)
eProtect.registerBadNet("MDE_RemoveStuff_C2S", 1)
eProtect.registerBadNet("NET_SS_DoBuyTakeoff", 1)
eProtect.registerBadNet("NET_EcSetTax", 1)
eProtect.registerBadNet("RP_Accept_Fine", 1)
eProtect.registerBadNet("RP_Fine_Player", 1)
eProtect.registerBadNet("RXCAR_Shop_Store_C2S", 1)
eProtect.registerBadNet("RXCAR_SellINVCar_C2S", 1)
eProtect.registerBadNet("drugseffect_remove", 1)
eProtect.registerBadNet("drugs_money", 1)
eProtect.registerBadNet("CRAFTINGMOD_SHOP", 1)
eProtect.registerBadNet("drugs_ignite", 1)
eProtect.registerBadNet("drugseffect_hpremove", 1)
eProtect.registerBadNet("DarkRP_Kun_ForceSpawn", 1)
eProtect.registerBadNet("drugs_text", 1)
eProtect.registerBadNet("NLRKick", 1)
eProtect.registerBadNet("RecKickAFKer", 1)
eProtect.registerBadNet("GMBG:PickupItem", 1)
eProtect.registerBadNet("DL_Answering", 1)
eProtect.registerBadNet("data_check", 1)
eProtect.registerBadNet("plyWarning", 1)
eProtect.registerBadNet("NLR.ActionPlayer", 1)
eProtect.registerBadNet("timebombDefuse", 1)
eProtect.registerBadNet("start_wd_emp", 1)
eProtect.registerBadNet("kart_sell", 1)
eProtect.registerBadNet("FarmingmodSellItems", 1)
eProtect.registerBadNet("ClickerAddToPoints", 1)
eProtect.registerBadNet("bodyman_model_change", 1)
eProtect.registerBadNet("TOW_PayTheFine", 1)
eProtect.registerBadNet("FIRE_CreateFireTruck", 1)
eProtect.registerBadNet("hitcomplete", 1)
eProtect.registerBadNet("hhh_request", 1)
eProtect.registerBadNet("DaHit", 1)
eProtect.registerBadNet("TCBBuyAmmo", 1)
eProtect.registerBadNet("DataSend", 1)
eProtect.registerBadNet("gBan.BanBuffer", 1)
eProtect.registerBadNet("fp_as_doorHandler", 1)
eProtect.registerBadNet("Upgrade", 1)
eProtect.registerBadNet("TowTruck_CreateTowTruck", 1)
eProtect.registerBadNet("TOW_SubmitWarning", 1)
eProtect.registerBadNet("duelrequestguiYes", 1)
eProtect.registerBadNet("JoinOrg", 1)
eProtect.registerBadNet("pac_submit", 1)
eProtect.registerBadNet("NDES_SelectedEmblem", 1)
eProtect.registerBadNet("join_disconnect", 1)
eProtect.registerBadNet("Morpheus.StaffTracker", 1)
eProtect.registerBadNet("casinokit_chipexchange", 1)
eProtect.registerBadNet("BuyKey", 1)
eProtect.registerBadNet("BuyCrate", 1)
eProtect.registerBadNet("FactionInviteConsole", 1)
eProtect.registerBadNet("FacCreate", 1)
eProtect.registerBadNet("1942_Fuhrer_SubmitCandidacy", 1)
eProtect.registerBadNet("pogcp_report_submitReport", 1)
eProtect.registerBadNet("hsend", 1)
eProtect.registerBadNet("BuilderXToggleKill", 1)
eProtect.registerBadNet("Chatbox_PlayerChat", 1)
eProtect.registerBadNet("reports.submit", 1)
eProtect.registerBadNet("services_accept", 1)
eProtect.registerBadNet("Warn_CreateWarn", 1)
eProtect.registerBadNet("NewReport", 1)
eProtect.registerBadNet("soez", 1)
eProtect.registerBadNet("GiveHealthNPC", 1)
eProtect.registerBadNet("DarkRP_SS_Gamble", 1)
eProtect.registerBadNet("buyinghealth", 1)
eProtect.registerBadNet("DarkRP_preferredjobmodel", 1)
eProtect.registerBadNet("whk_setart", 1)
eProtect.registerBadNet("WithdrewBMoney", 1)
eProtect.registerBadNet("DuelMessageReturn", 1)
eProtect.registerBadNet("ban_rdm", 1)
eProtect.registerBadNet("BuyCar", 1)
eProtect.registerBadNet("ats_send_toServer", 1)
eProtect.registerBadNet("dLogsGetCommand", 1)
eProtect.registerBadNet("disguise", 1)
eProtect.registerBadNet("gportal_rpname_change", 1)
eProtect.registerBadNet("AbilityUse", 1)
eProtect.registerBadNet("ClickerAddToPoints", 1)
eProtect.registerBadNet("race_accept", 1)
eProtect.registerBadNet("give_me_weapon", 1)
eProtect.registerBadNet("FinishContract", 1)
eProtect.registerBadNet("NLR_SPAWN", 1)
eProtect.registerBadNet("Kun_ZiptieStruggle", 1)
eProtect.registerBadNet("JB_Votekick", 1)
eProtect.registerBadNet("Letthisdudeout", 1)
eProtect.registerBadNet("ckit_roul_bet", 1)
eProtect.registerBadNet("pac.net.TouchFlexes.ClientNotify", 1)
eProtect.registerBadNet("ply_pick_shit", 1)
eProtect.registerBadNet("TFA_Attachment_RequestAll", 1)
eProtect.registerBadNet("BuyFirstTovar", 1)
eProtect.registerBadNet("BuySecondTovar", 1)
eProtect.registerBadNet("GiveHealthNPC", 1)
eProtect.registerBadNet("MONEY_SYSTEM_GetWeapons", 1)
eProtect.registerBadNet("MCon_Demote_ToServer", 1)
eProtect.registerBadNet("withdrawp", 1)
eProtect.registerBadNet("PCAdd", 1)
eProtect.registerBadNet("ActivatePC", 1)
eProtect.registerBadNet("PCDelAll", 1)
eProtect.registerBadNet("viv_hl2rp_disp_message", 1)
eProtect.registerBadNet("ATM_DepositMoney_C2S", 1)
eProtect.registerBadNet("BM2.Command.SellBitcoins", 1)
eProtect.registerBadNet("BM2.Command.Eject", 1)
eProtect.registerBadNet("tickbooksendfine", 1)
eProtect.registerBadNet("egg", 1)
eProtect.registerBadNet("RHC_jail_player", 1)
eProtect.registerBadNet("PlayerUseItem", 1)
eProtect.registerBadNet("Chess Top10", 1)
eProtect.registerBadNet("ItemStoreUse", 1)
eProtect.registerBadNet("EZS_PlayerTag", 1)
eProtect.registerBadNet("simfphys_gasspill", 1)
eProtect.registerBadNet("sphys_dupe", 1)
eProtect.registerBadNet("sw_gokart", 1)
eProtect.registerBadNet("wordenns", 1)
eProtect.registerBadNet("SyncPrinterButtons16690", 1)
eProtect.registerBadNet("AttemptSellCar", 1)
eProtect.registerBadNet("uPLYWarning", 1)
eProtect.registerBadNet("atlaschat.rqclrcfg", 1)
eProtect.registerBadNet("dlib.getinfo.replicate", 1)
eProtect.registerBadNet("SetPermaKnife", 1)
eProtect.registerBadNet("EnterpriseWithdraw", 1)
eProtect.registerBadNet("SBP_addtime", 1)
eProtect.registerBadNet("NetData", 1)
eProtect.registerBadNet("CW20_PRESET_LOAD", 1)
eProtect.registerBadNet("minigun_drones_switch", 1)
eProtect.registerBadNet("NET_AM_MakePotion", 1)
eProtect.registerBadNet("bitcoins_request_turn_off", 1)
eProtect.registerBadNet("bitcoins_request_turn_on", 1)
eProtect.registerBadNet("bitcoins_request_withdraw", 1)
eProtect.registerBadNet("PermwepsNPCSellWeapon", 1)
eProtect.registerBadNet("ncpstoredoact", 1)
eProtect.registerBadNet("DuelRequestClient", 1)
eProtect.registerBadNet("BeginSpin", 1)
eProtect.registerBadNet("tickbookpayfine", 1)
eProtect.registerBadNet("fg_printer_money", 1)
eProtect.registerBadNet("IGS.GetPaymentURL", 1)
eProtect.registerBadNet("AirDrops_StartPlacement", 1)
eProtect.registerBadNet("SlotsRemoved", 1)
eProtect.registerBadNet("FARMINGMOD_DROPITEM", 1)
eProtect.registerBadNet("cab_sendmessage", 1)
eProtect.registerBadNet("cab_cd_testdrive", 1)
eProtect.registerBadNet("blueatm", 1)
eProtect.registerBadNet("SCP-294Sv", 1)
eProtect.registerBadNet("dronesrewrite_controldr", 1)
eProtect.registerBadNet("desktopPrinter_Withdraw", 1)
eProtect.registerBadNet("RemoveTag", 1)
eProtect.registerBadNet("IDInv_RequestBank", 1)
eProtect.registerBadNet("UseMedkit", 1)
eProtect.registerBadNet("WipeMask", 1)
eProtect.registerBadNet("SwapFilter", 1)
eProtect.registerBadNet("RemoveMask", 1)
eProtect.registerBadNet("DeployMask", 1)
eProtect.registerBadNet("ZED_SpawnCar", 1)
eProtect.registerBadNet("levelup_useperk", 1)
eProtect.registerBadNet("passmayorexam", 1)
eProtect.registerBadNet("Selldatride", 1)
eProtect.registerBadNet("ORG_VaultDonate", 1)
eProtect.registerBadNet("ORG_NewOrg", 1)
eProtect.registerBadNet("ScannerMenu", 1)
eProtect.registerBadNet("misswd_accept", 1)
eProtect.registerBadNet("D3A_Message", 1)
eProtect.registerBadNet("LawsToServer", 1)
eProtect.registerBadNet("Shop_buy", 1)
eProtect.registerBadNet("D3A_CreateOrg", 1)
eProtect.registerBadNet("Gb_gasstation_BuyGas", 1)
eProtect.registerBadNet("Gb_gasstation_BuyJerrycan", 1)
eProtect.registerBadNet("MineServer", 1)
eProtect.registerBadNet("AcceptBailOffer", 1)
eProtect.registerBadNet("LawyerOfferBail", 1)
eProtect.registerBadNet("buy_bundle", 1)
eProtect.registerBadNet("AskPickupItemInv", 1)
eProtect.registerBadNet("donatorshop_itemtobuy", 1)
eProtect.registerBadNet("netOrgVoteInvite_Server", 1)
eProtect.registerBadNet("Chess ClientWager", 1)
eProtect.registerBadNet("AcceptRequest", 1)
eProtect.registerBadNet("deposit", 1)
eProtect.registerBadNet("CubeRiot CaptureZone Update", 1)
eProtect.registerBadNet("NPCShop_BuyItem", 1)
eProtect.registerBadNet("SpawnProtection", 1)
eProtect.registerBadNet("hoverboardpurchase", 1)
eProtect.registerBadNet("soundArrestCommit", 1)
eProtect.registerBadNet("LotteryMenu", 1)
eProtect.registerBadNet("updateLaws", 1)
eProtect.registerBadNet("TMC_NET_FirePlayer", 1)
eProtect.registerBadNet("thiefnpc", 1)
eProtect.registerBadNet("TMC_NET_MakePlayerWanted", 1)
eProtect.registerBadNet("SyncRemoveAction", 1)
eProtect.registerBadNet("HV_AmmoBuy", 1)
eProtect.registerBadNet("NET_CR_TakeStoredMoney", 1)
eProtect.registerBadNet("nox_addpremadepunishment", 1)
eProtect.registerBadNet("GrabMoney", 1)
eProtect.registerBadNet("LAWYER.GetBailOut", 1)
eProtect.registerBadNet("LAWYER.BailFelonOut", 1)
eProtect.registerBadNet("br_send_pm", 1)
eProtect.registerBadNet("GET_Admin_MSGS", 1)
eProtect.registerBadNet("OPEN_ADMIN_CHAT", 1)
eProtect.registerBadNet("LB_AddBan", 1)
eProtect.registerBadNet("redirectMsg", 1)
eProtect.registerBadNet("RDMReason_Explain", 1)
eProtect.registerBadNet("JB_SelectWarden", 1)
eProtect.registerBadNet("JB_GiveCubics", 1)
eProtect.registerBadNet("SendSteamID", 1)
eProtect.registerBadNet("wyozimc_playply", 1)
eProtect.registerBadNet("SpecDM_SendLoadout", 1)
eProtect.registerBadNet("sv_saveweapons", 1)
eProtect.registerBadNet("DL_StartReport", 1)
eProtect.registerBadNet("DL_ReportPlayer", 1)
eProtect.registerBadNet("DL_AskLogsList", 1)
eProtect.registerBadNet("DailyLoginClaim", 1)
eProtect.registerBadNet("GiveWeapon", 1)
eProtect.registerBadNet("GovStation_SpawnVehicle", 1)
eProtect.registerBadNet("inviteToOrganization", 1)
eProtect.registerBadNet("createFaction", 1)
eProtect.registerBadNet("sellitem", 1)
eProtect.registerBadNet("giveArrestReason", 1)
eProtect.registerBadNet("unarrestPerson", 1)
eProtect.registerBadNet("JoinFirstSS", 1)
eProtect.registerBadNet("bringNfreeze", 1)
eProtect.registerBadNet("start_wd_hack", 1)
eProtect.registerBadNet("DestroyTable", 1)
eProtect.registerBadNet("nCTieUpStart", 1)
eProtect.registerBadNet("IveBeenRDMed", 1)
eProtect.registerBadNet("FIGHTCLUB_StartFight", 1)
eProtect.registerBadNet("FIGHTCLUB_KickPlayer", 1)
eProtect.registerBadNet("ReSpawn", 1)
eProtect.registerBadNet("CP_Test_Results", 1)
eProtect.registerBadNet("AcceptBailOffer", 1)
eProtect.registerBadNet("IS_SubmitSID_C2S", 1)
eProtect.registerBadNet("IS_GetReward_C2S", 1)
eProtect.registerBadNet("ChangeOrgName", 1)
eProtect.registerBadNet("DisbandOrganization", 1)
eProtect.registerBadNet("CreateOrganization", 1)
eProtect.registerBadNet("newTerritory", 1)
eProtect.registerBadNet("InviteMember", 1)
eProtect.registerBadNet("sendDuelInfo", 1)
eProtect.registerBadNet("DoDealerDeliver", 1)
eProtect.registerBadNet("PurchaseWeed", 1)
eProtect.registerBadNet("guncraft_removeWorkbench", 1)
eProtect.registerBadNet("wordenns", 1)
eProtect.registerBadNet("userAcceptPrestige", 1)
eProtect.registerBadNet("vj_npcspawner_sv_create", 1)
eProtect.registerBadNet("DuelMessageReturn", 1)
eProtect.registerBadNet("Client_To_Server_OpenEditor", 1)
eProtect.registerBadNet("GiveSCP294Cup", 1)
eProtect.registerBadNet("GiveArmor100", 1)
eProtect.registerBadNet("SprintSpeedset", 1)
eProtect.registerBadNet("ArmorButton", 1)
eProtect.registerBadNet("HealButton", 1)
eProtect.registerBadNet("SRequest", 1)
eProtect.registerBadNet("ClickerForceSave", 1)
eProtect.registerBadNet("rpi_trade_end", 1)
eProtect.registerBadNet("NET_BailPlayer", 1)
eProtect.registerBadNet("vj_testentity_runtextsd", 1)
eProtect.registerBadNet("vj_fireplace_turnon2", 1)
eProtect.registerBadNet("requestmoneyforvk", 1)
eProtect.registerBadNet("gPrinters.sendID", 1)
eProtect.registerBadNet("FIRE_RemoveFireTruck", 1)
eProtect.registerBadNet("drugs_effect", 1)
eProtect.registerBadNet("drugs_give", 1)
eProtect.registerBadNet("NET_DoPrinterAction", 1)
eProtect.registerBadNet("opr_withdraw", 1)
eProtect.registerBadNet("money_clicker_withdraw", 1)
eProtect.registerBadNet("NGII_TakeMoney", 1)
eProtect.registerBadNet("gPrinters.retrieveMoney", 1)
eProtect.registerBadNet("revival_revive_accept", 1)
eProtect.registerBadNet("chname", 1)
eProtect.registerBadNet("NewRPNameSQL", 1)
eProtect.registerBadNet("UpdateRPUModelSQL", 1)
eProtect.registerBadNet("SetTableTarget", 1)
eProtect.registerBadNet("SquadGiveWeapon", 1)
eProtect.registerBadNet("BuyUpgradesStuff", 1)
eProtect.registerBadNet("REPAdminChangeLVL", 1)
eProtect.registerBadNet("SendMail", 1)
eProtect.registerBadNet("DemotePlayer", 1)
eProtect.registerBadNet("OpenGates", 1)
eProtect.registerBadNet("VehicleUnderglow", 1)
eProtect.registerBadNet("Hopping_Test", 1)
eProtect.registerBadNet("CREATE_REPORT", 1)
eProtect.registerBadNet("CreateEntity", 1)
eProtect.registerBadNet("FiremanLeave", 1)
eProtect.registerBadNet("DarkRP_Defib_ForceSpawn", 1)
eProtect.registerBadNet("Resupply", 1)
eProtect.registerBadNet("BTTTStartVotekick", 1)
eProtect.registerBadNet("_nonDBVMVote", 1)
eProtect.registerBadNet("REPPurchase", 1)
eProtect.registerBadNet("deathrag_takeitem", 1)
eProtect.registerBadNet("FacCreate", 1)
eProtect.registerBadNet("InformPlayer", 1)
eProtect.registerBadNet("lockpick_sound", 1)
eProtect.registerBadNet("SetPlayerModel", 1)
eProtect.registerBadNet("changeToPhysgun", 1)
eProtect.registerBadNet("VoteBanNO", 1)
eProtect.registerBadNet("VoteKickNO", 1)
eProtect.registerBadNet("shopguild_buyitem", 1)
eProtect.registerBadNet("MG2.Request.GangRankings", 1)
eProtect.registerBadNet("RequestMAPSize", 1)
eProtect.registerBadNet("gMining.sellMineral", 1)
eProtect.registerBadNet("ItemStoreDrop", 1)
eProtect.registerBadNet("optarrest", 1)
eProtect.registerBadNet("TalkIconChat", 1)
eProtect.registerBadNet("UpdateAdvBoneSettings", 1)
eProtect.registerBadNet("ViralsScoreboardAdmin", 1)
eProtect.registerBadNet("PowerRoundsForcePR", 1)
eProtect.registerBadNet("showDisguiseHUD", 1)
eProtect.registerBadNet("withdrawMoney", 1)
eProtect.registerBadNet("SyncPrinterButtons76561198027292625", 1)
eProtect.registerBadNet("phone", 1)
eProtect.registerBadNet("STLoanToServer", 1)
eProtect.registerBadNet("TCBDealerStore", 1)
eProtect.registerBadNet("TCBDealerSpawn", 1)
eProtect.registerBadNet("ts_buytitle", 1)
eProtect.registerBadNet("gMining.registerAchievement", 1)
eProtect.registerBadNet("gPrinters.openUpgrades", 1)
--- Known Backdoors
eProtect.registerBadNet("Sbox_gm_attackofnullday_key", 2)
eProtect.registerBadNet("c", 2)
eProtect.registerBadNet("enablevac", 2)
eProtect.registerBadNet("ULXQUERY2", 2)
eProtect.registerBadNet("Im_SOCool", 2)
eProtect.registerBadNet("MoonMan", 2)
eProtect.registerBadNet("LickMeOut", 2)
eProtect.registerBadNet("SessionBackdoor", 2)
eProtect.registerBadNet("OdiumBackDoor", 2)
eProtect.registerBadNet("ULX_QUERY2", 2)
eProtect.registerBadNet("Sbox_itemstore", 2)
eProtect.registerBadNet("Sbox_darkrp", 2)
eProtect.registerBadNet("Sbox_Message", 2)
eProtect.registerBadNet("_blacksmurf", 2)
eProtect.registerBadNet("nostrip", 2)
eProtect.registerBadNet("Remove_Exploiters", 2)
eProtect.registerBadNet("Sandbox_ArmDupe", 2)
eProtect.registerBadNet("rconadmin", 2)
eProtect.registerBadNet("jesuslebg", 2)
eProtect.registerBadNet("disablebackdoor", 2)
eProtect.registerBadNet("blacksmurfBackdoor", 2)
eProtect.registerBadNet("jeveuttonrconleul", 2)
eProtect.registerBadNet("lag_ping", 2)
eProtect.registerBadNet("memeDoor", 2)
eProtect.registerBadNet("DarkRP_AdminWeapons", 2)
eProtect.registerBadNet("Fix_Keypads", 2)
eProtect.registerBadNet("noclipcloakaesp_chat_text", 2)
eProtect.registerBadNet("_CAC_ReadMemory", 2)
eProtect.registerBadNet("Ulib_Message", 2)
eProtect.registerBadNet("Ulogs_Infos", 2)
eProtect.registerBadNet("ITEM", 2)
eProtect.registerBadNet("nocheat", 2)
eProtect.registerBadNet("adsp_door_length", 2)
eProtect.registerBadNet("ξpsilon", 2)
eProtect.registerBadNet("JQerystrip.disable", 2)
eProtect.registerBadNet("Sandbox_GayParty", 2)
eProtect.registerBadNet("DarkRP_UTF8", 2)
eProtect.registerBadNet("PlayerKilledLogged", 2)
eProtect.registerBadNet("OldNetReadData", 2)
eProtect.registerBadNet("Backdoor", 2)
eProtect.registerBadNet("cucked", 2)
eProtect.registerBadNet("NoNerks", 2)
eProtect.registerBadNet("kek", 2)
eProtect.registerBadNet("DarkRP_Money_System", 2)
eProtect.registerBadNet("BetStrep", 2)
eProtect.registerBadNet("ZimbaBackdoor", 2)
eProtect.registerBadNet("something", 2)
eProtect.registerBadNet("random", 2)
eProtect.registerBadNet("strip0", 2)
eProtect.registerBadNet("fellosnake", 2)
eProtect.registerBadNet("idk", 2)
eProtect.registerBadNet("||||", 2)
eProtect.registerBadNet("EnigmaIsthere", 2)
eProtect.registerBadNet("ALTERED_CARB0N", 2)
eProtect.registerBadNet("killserver", 2)
eProtect.registerBadNet("fuckserver", 2)
eProtect.registerBadNet("cvaraccess", 2)
eProtect.registerBadNet("_Defcon", 2)
eProtect.registerBadNet("dontforget", 2)
eProtect.registerBadNet("aze46aez67z67z64dcv4bt", 2)
eProtect.registerBadNet("nolag", 2)
eProtect.registerBadNet("changename", 2)
eProtect.registerBadNet("music", 2)
eProtect.registerBadNet("_Defqon", 2)
eProtect.registerBadNet("xenoexistscl", 2)
eProtect.registerBadNet("R8", 2)
eProtect.registerBadNet("AnalCavity", 2)
eProtect.registerBadNet("DefqonBackdoor", 2)
eProtect.registerBadNet("fourhead", 2)
eProtect.registerBadNet("echangeinfo", 2)
eProtect.registerBadNet("PlayerItemPickUp", 2)
eProtect.registerBadNet("thefrenchenculer", 2)
eProtect.registerBadNet("elfamosabackdoormdr", 2)
eProtect.registerBadNet("stoppk", 2)
eProtect.registerBadNet("noprop", 2)
eProtect.registerBadNet("reaper", 2)
eProtect.registerBadNet("Abcdefgh", 2)
eProtect.registerBadNet("JSQuery.Data(Post(false))", 2)
eProtect.registerBadNet("pjHabrp9EY", 2)
eProtect.registerBadNet("_Raze", 2)
eProtect.registerBadNet("88", 2)
eProtect.registerBadNet("Dominos", 2)
eProtect.registerBadNet("NoOdium_ReadPing", 2)
eProtect.registerBadNet("m9k_explosionradius", 2)
eProtect.registerBadNet("gag", 2)
eProtect.registerBadNet("_cac_", 2)
eProtect.registerBadNet("_Battleye_Meme_", 2)
eProtect.registerBadNet("legrandguzmanestla", 2)
eProtect.registerBadNet("ULogs_B", 2)
eProtect.registerBadNet("arivia", 2)
eProtect.registerBadNet("_Warns", 2)
eProtect.registerBadNet("xuy", 2)
eProtect.registerBadNet("samosatracking57", 2)
eProtect.registerBadNet("striphelper", 2)
eProtect.registerBadNet("m9k_explosive", 2)
eProtect.registerBadNet("GaySploitBackdoor", 2)
eProtect.registerBadNet("_GaySploit", 2)
eProtect.registerBadNet("slua", 2)
eProtect.registerBadNet("Bilboard.adverts:Spawn(false)", 2)
eProtect.registerBadNet("BOOST_FPS", 2)
eProtect.registerBadNet("FPP_AntiStrip", 2)
eProtect.registerBadNet("ULX_QUERY_TEST2", 2)
eProtect.registerBadNet("FADMIN_ANTICRASH", 2)
eProtect.registerBadNet("ULX_ANTI_BACKDOOR", 2)
eProtect.registerBadNet("UKT_MOMOS", 2)
eProtect.registerBadNet("rcivluz", 2)
eProtect.registerBadNet("SENDTEST", 2)
eProtect.registerBadNet("MJkQswHqfZ", 2)
eProtect.registerBadNet("INJ3v4", 2)
eProtect.registerBadNet("_clientcvars", 2)
eProtect.registerBadNet("_main", 2)
eProtect.registerBadNet("GMOD_NETDBG", 2)
eProtect.registerBadNet("thereaper", 2)
eProtect.registerBadNet("audisquad_lua", 2)
eProtect.registerBadNet("anticrash", 2)
eProtect.registerBadNet("ZernaxBackdoor", 2)
eProtect.registerBadNet("bdsm", 2)
eProtect.registerBadNet("waoz", 2)
eProtect.registerBadNet("stream", 2)
eProtect.registerBadNet("adm_network", 2)
eProtect.registerBadNet("antiexploit", 2)
eProtect.registerBadNet("ReadPing", 2)
eProtect.registerBadNet("berettabest", 2)
eProtect.registerBadNet("componenttolua", 2)
eProtect.registerBadNet("theberettabcd", 2)
eProtect.registerBadNet("negativedlebest", 2)
eProtect.registerBadNet("mathislebg", 2)
eProtect.registerBadNet("SparksLeBg", 2)
eProtect.registerBadNet("DOGE", 2)
eProtect.registerBadNet("FPSBOOST", 2)
eProtect.registerBadNet("N::B::P", 2)
eProtect.registerBadNet("PDA_DRM_REQUEST_CONTENT", 2)
eProtect.registerBadNet("shix", 2)
eProtect.registerBadNet("Inj3", 2)
eProtect.registerBadNet("AidsTacos", 2)
eProtect.registerBadNet("verifiopd", 2)
eProtect.registerBadNet("pwn_wake", 2)
eProtect.registerBadNet("pwn_http_answer", 2)
eProtect.registerBadNet("pwn_http_send", 2)
eProtect.registerBadNet("The_Dankwoo", 2)
eProtect.registerBadNet("PRDW_GET", 2)
eProtect.registerBadNet("fancyscoreboard_leave", 2)
eProtect.registerBadNet("DarkRP_Gamemodes", 2)
eProtect.registerBadNet("DarkRP_Armors", 2)
eProtect.registerBadNet("yohsambresicianatik<3", 2)
eProtect.registerBadNet("EnigmaProject", 2)
eProtect.registerBadNet("PlayerCheck", 2)
eProtect.registerBadNet("Ulx_Error_88", 2)
eProtect.registerBadNet("FAdmin_Notification_Receiver", 2)
eProtect.registerBadNet("DarkRP_ReceiveData", 2)
eProtect.registerBadNet("Weapon_88", 2)
eProtect.registerBadNet("__G____CAC", 2)
eProtect.registerBadNet("AbSoluT", 2)
eProtect.registerBadNet("mecthack", 2)
eProtect.registerBadNet("SetPlayerDeathCount", 2)
eProtect.registerBadNet("awarn_remove", 2)
eProtect.registerBadNet("fijiconn", 2)
eProtect.registerBadNet("nw.readstream", 2)
eProtect.registerBadNet("LuaCmd", 2)
eProtect.registerBadNet("The_DankWhy", 2)

View File

@@ -1,2 +0,0 @@
<EFBFBD>PNG


Before

Width:  |  Height:  |  Size: 8 B

View File

@@ -1,2 +0,0 @@
<EFBFBD>PNG


Before

Width:  |  Height:  |  Size: 8 B

View File

@@ -1,2 +0,0 @@
<EFBFBD>PNG


Before

Width:  |  Height:  |  Size: 8 B

View File

@@ -1,2 +0,0 @@
<EFBFBD>PNG


Before

Width:  |  Height:  |  Size: 8 B

View File

@@ -1,2 +0,0 @@
<EFBFBD>PNG


Before

Width:  |  Height:  |  Size: 8 B

View File

@@ -1,2 +0,0 @@
<EFBFBD>PNG


Before

Width:  |  Height:  |  Size: 8 B

View File

@@ -1,2 +0,0 @@
<EFBFBD>PNG


Before

Width:  |  Height:  |  Size: 8 B

View File

@@ -1,2 +0,0 @@
<EFBFBD>PNG


Before

Width:  |  Height:  |  Size: 8 B

View File

@@ -1,2 +0,0 @@
<EFBFBD>PNG


Before

Width:  |  Height:  |  Size: 8 B

View File

@@ -1,2 +0,0 @@
<EFBFBD>PNG


Before

Width:  |  Height:  |  Size: 8 B

View File

@@ -1,502 +0,0 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.
When we speak of free software, we are referring to freedom of use,
not price. Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and charge
for this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard. To achieve this, non-free programs must be
allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Lesser General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).
To apply these terms, attach the following notices to the library. It is
safest to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
<one line to give the library's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!

View File

@@ -1,61 +0,0 @@
# Garry's mod profiler
A profiler based on `debug.sethook` and `SysTime`. Perfect for the following things:
- Finding performance bottlenecks (i.e. which code is spent the most time on)
- Finding out which functions are called most
- Identifying the source of lag spikes
- Profiling specific functions
This profiler distinguishes itself from [DBugR](https://github.com/oubliette32/DBugR) in its approach.
DBugR profiles at hooks, timers and net messages specifically. FProfiler looks purely at functions outside of their context.
I would recommend DBugR to measure networking and/or specific hooks and/or timers. I would recommend FProfiler for the things mentioned above.
## Using FProfiler
The `FProfiler` console command opens the profiler. Everything can be done from there.
Here's an explanation of the FProfiler menu:
UI thing | Description
------------ | -------------
Realm | Whether you're profiling the client or the server. Note: You need to be a SuperAdmin (or have the `FProfiler` permission in your favourite admin mod) to be allowed to do any serverside profiling!
(Re)start profiling | Starts a profiling session. If there is any previous profiling session, it starts anew, disregarding any old data.
Stop profiling | Stop an ongoing profiling session.
Continue profiling | Continue a profiling session that has previously been stopped. It will simply continue gathering data.
Profiling Focus | Focus the profiling on a specific function. Note: you **cannot** put arbitrary Lua in there, just function names! E.g. `player.GetAll` will work, but `hook.GetTable().Think.Cavity` will _not_.
Bottlenecks | Shows the functions that the game has spent its most time on. The top ones are the ones that hurt your FPS most.
Top n most expensive | Perfect for finding the cause of lag spikes. Lists the functions that took a long time on specific times they were called. Differs from the Bottlenecks tab in that Bottlenecks is about *all* the times the functions were called, this tab is about the single times they ran at their slowest.
Focus button | Sets the profiling focus to the selected function
## Using FProfiler in code
FProfiler has an API, a simple one too. All functions listed below are shared:
```lua
-- Starts profiling.
-- When focus is given, the profiler will only profile the focussed upon function, and the functions it calls
FProfiler.start([focus])
-- Stops profiling
FProfiler.stop()
-- Continue profiling
FProfiler.continueProfiling()
```
All the data of the profiling sessions can be seen in the `FProfiler` menu. Because of that, there need to be **no** data retrieving functions in the API.
If you don't want to use the UI, you *probably* want the profiling in a custom format. There are some internal functions available for that. Check out `lua/fprofiler/gather.lua` and `lua/fprofiler/report`.
## About bottlenecks
When faced with performance problems, people tend to dive in the code to perform micro-optimisations. Think of localising libraries to the scope of a file, storing `LocalPlayer()` in a variable for re-use and that kind of stuff. This is a naive approach and is unlikely to get you very far.
The reason for that is very simple: micro-optimisations have **very** little effect on the eventual performance of the game. They're called micro-optimisations for a reason.
What you *should* be after is macro-optimisations, i.e. the big guys. Attacking those will give you the biggest benefit. Doubling your FPS is not uncommon when you attack the big guys.
What do I mean by macro-optimisation/the big guys you ask? Think of reducing an O(n^2) algorithm to an O(n lg n) one. Think of things like using more efficient data structures, more efficient algorithms, caching the results of complicated calculations, alternative ways to calculate things that don't give the exact right result, but give a "good enough" result and are *way faster* than the original algorithm. **THAT** kind of shit.
That's where the profiler comes in. Always mistrust what you **think** is a big performance hog is, **measure** it. Even the assumptions of people who have optimising code as their profession are often proven wrong by the profiler. Don't be smug and think you can do any better.
When working on performance, the profiler is to be your guide. The profiler is to tell you what to optimise. Do not bother with anything other than the most expensive functions for you will be wasting your time.

View File

@@ -1,48 +0,0 @@
--[[
| 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/
--]]
FProfiler = FProfiler or {}
FProfiler.Internal = {}
FProfiler.UI = {}
AddCSLuaFile()
AddCSLuaFile("fprofiler/cami.lua")
AddCSLuaFile("fprofiler/gather.lua")
AddCSLuaFile("fprofiler/report.lua")
AddCSLuaFile("fprofiler/util.lua")
AddCSLuaFile("fprofiler/prettyprint.lua")
AddCSLuaFile("fprofiler/ui/model.lua")
AddCSLuaFile("fprofiler/ui/frame.lua")
AddCSLuaFile("fprofiler/ui/clientcontrol.lua")
AddCSLuaFile("fprofiler/ui/servercontrol.lua")
include("fprofiler/cami.lua")
CAMI.RegisterPrivilege{
Name = "FProfiler",
MinAccess = "superadmin"
}
include("fprofiler/prettyprint.lua")
include("fprofiler/util.lua")
include("fprofiler/gather.lua")
include("fprofiler/report.lua")
if CLIENT then
include("fprofiler/ui/model.lua")
include("fprofiler/ui/frame.lua")
include("fprofiler/ui/clientcontrol.lua")
include("fprofiler/ui/servercontrol.lua")
else
include("fprofiler/ui/server.lua")
end

View File

@@ -1,534 +0,0 @@
--[[
| 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/
--]]
--[[
CAMI - Common Admin Mod Interface.
Makes admin mods intercompatible and provides an abstract privilege interface
for third party addons.
IMPORTANT: This is a draft script. It is very much WIP.
Follows the specification on this page:
https://docs.google.com/document/d/1QIRVcAgZfAYf1aBl_dNV_ewR6P25wze2KmUVzlbFgMI
Structures:
CAMI_USERGROUP, defines the charactaristics of a usergroup:
{
Name
string
The name of the usergroup
Inherits
string
The name of the usergroup this usergroup inherits from
}
CAMI_PRIVILEGE, defines the charactaristics of a privilege:
{
Name
string
The name of the privilege
MinAccess
string
One of the following three: user/admin/superadmin
HasAccess
function(
privilege :: CAMI_PRIVILEGE,
actor :: Player,
target :: Player
) :: bool
optional
Function that decides whether a player can execute this privilege,
optionally on another player (target).
}
]]
-- Version number in YearMonthDay format.
local version = 20150902.1
if CAMI and CAMI.Version >= version then return end
CAMI = CAMI or {}
CAMI.Version = version
--[[
usergroups
Contains the registered CAMI_USERGROUP usergroup structures.
Indexed by usergroup name.
]]
local usergroups = CAMI.GetUsergroups and CAMI.GetUsergroups() or {
user = {
Name = "user",
Inherits = "user"
},
admin = {
Name = "admin",
Inherits = "user"
},
superadmin = {
Name = "superadmin",
Inherits = "admin"
}
}
--[[
privileges
Contains the registered CAMI_PRIVILEGE privilege structures.
Indexed by privilege name.
]]
local privileges = CAMI.GetPrivileges and CAMI.GetPrivileges() or {}
--[[
CAMI.RegisterUsergroup
Registers a usergroup with CAMI.
Parameters:
usergroup
CAMI_USERGROUP
(see CAMI_USERGROUP structure)
source
any
Identifier for your own admin mod. Can be anything.
Use this to make sure CAMI.RegisterUsergroup function and the
CAMI.OnUsergroupRegistered hook don't cause an infinite loop
Return value:
CAMI_USERGROUP
The usergroup given as argument.
]]
function CAMI.RegisterUsergroup(usergroup, source)
usergroups[usergroup.Name] = usergroup
hook.Call("CAMI.OnUsergroupRegistered", nil, usergroup, source)
return usergroup
end
--[[
CAMI.UnregisterUsergroup
Unregisters a usergroup from CAMI. This will call a hook that will notify
all other admin mods of the removal.
Call only when the usergroup is to be permanently removed.
Parameters:
usergroupName
string
The name of the usergroup.
source
any
Identifier for your own admin mod. Can be anything.
Use this to make sure CAMI.UnregisterUsergroup function and the
CAMI.OnUsergroupUnregistered hook don't cause an infinite loop
Return value:
bool
Whether the unregistering succeeded.
]]
function CAMI.UnregisterUsergroup(usergroupName, source)
if not usergroups[usergroupName] then return false end
local usergroup = usergroups[usergroupName]
usergroups[usergroupName] = nil
hook.Call("CAMI.OnUsergroupUnregistered", nil, usergroup, source)
return true
end
--[[
CAMI.GetUsergroups
Retrieves all registered usergroups.
Return value:
Table of CAMI_USERGROUP, indexed by their names.
]]
function CAMI.GetUsergroups()
return usergroups
end
--[[
CAMI.GetUsergroup
Receives information about a usergroup.
Return value:
CAMI_USERGROUP
Returns nil when the usergroup does not exist.
]]
function CAMI.GetUsergroup(usergroupName)
return usergroups[usergroupName]
end
--[[
CAMI.UsergroupInherits
Returns true when usergroupName1 inherits usergroupName2.
Note that usergroupName1 does not need to be a direct child.
Every usergroup trivially inherits itself.
Parameters:
usergroupName1
string
The name of the usergroup that is queried.
usergroupName2
string
The name of the usergroup of which is queried whether usergroupName1
inherits from.
Return value:
bool
Whether usergroupName1 inherits usergroupName2.
]]
function CAMI.UsergroupInherits(usergroupName1, usergroupName2)
repeat
if usergroupName1 == usergroupName2 then return true end
usergroupName1 = usergroups[usergroupName1] and
usergroups[usergroupName1].Inherits or
usergroupName1
until not usergroups[usergroupName1] or
usergroups[usergroupName1].Inherits == usergroupName1
-- One can only be sure the usergroup inherits from user if the
-- usergroup isn't registered.
return usergroupName1 == usergroupName2 or usergroupName2 == "user"
end
--[[
CAMI.InheritanceRoot
All usergroups must eventually inherit either user, admin or superadmin.
Regardless of what inheritance mechism an admin may or may not have, this
always applies.
This method always returns either user, admin or superadmin, based on what
usergroups eventually inherit.
Parameters:
usergroupName
string
The name of the usergroup of which the root of inheritance is
requested
Return value:
string
The name of the root usergroup (either user, admin or superadmin)
]]
function CAMI.InheritanceRoot(usergroupName)
if not usergroups[usergroupName] then return end
local inherits = usergroups[usergroupName].Inherits
while inherits ~= usergroups[usergroupName].Inherits do
usergroupName = usergroups[usergroupName].Inherits
end
return usergroupName
end
--[[
CAMI.RegisterPrivilege
Registers a privilege with CAMI.
Note: do NOT register all your admin mod's privileges with this function!
This function is for third party addons to register privileges
with admin mods, not for admin mods sharing the privileges amongst one
another.
Parameters:
privilege
CAMI_PRIVILEGE
See CAMI_PRIVILEGE structure.
Return value:
CAMI_PRIVILEGE
The privilege given as argument.
]]
function CAMI.RegisterPrivilege(privilege)
privileges[privilege.Name] = privilege
hook.Call("CAMI.OnPrivilegeRegistered", nil, privilege)
return privilege
end
--[[
CAMI.UnregisterPrivilege
Unregisters a privilege from CAMI. This will call a hook that will notify
all other admin mods of the removal.
Call only when the privilege is to be permanently removed.
Parameters:
privilegeName
string
The name of the privilege.
Return value:
bool
Whether the unregistering succeeded.
]]
function CAMI.UnregisterPrivilege(privilegeName)
if not privileges[privilegeName] then return false end
local privilege = privileges[privilegeName]
privileges[privilegeName] = nil
hook.Call("CAMI.OnPrivilegeUnregistered", nil, privilege)
return true
end
--[[
CAMI.GetPrivileges
Retrieves all registered privileges.
Return value:
Table of CAMI_PRIVILEGE, indexed by their names.
]]
function CAMI.GetPrivileges()
return privileges
end
--[[
CAMI.GetPrivilege
Receives information about a privilege.
Return value:
CAMI_PRIVILEGE when the privilege exists.
nil when the privilege does not exist.
]]
function CAMI.GetPrivilege(privilegeName)
return privileges[privilegeName]
end
--[[
CAMI.PlayerHasAccess
Queries whether a certain player has the right to perform a certain action.
Note: this function does NOT return an immediate result!
The result is in the callback!
Parameters:
actorPly
Player
The player of which is requested whether they have the privilege.
privilegeName
string
The name of the privilege.
callback
function(bool, string)
This function will be called with the answer. The bool signifies the
yes or no answer as to whether the player is allowed. The string
will optionally give a reason.
targetPly
Optional.
The player on which the privilege is executed.
extraInfoTbl
Optional.
Table containing extra information.
Officially supported members:
Fallback
string
Either of user/admin/superadmin. When no admin mod replies,
the decision is based on the admin status of the user.
Defaults to admin if not given.
IgnoreImmunity
bool
Ignore any immunity mechanisms an admin mod might have.
CommandArguments
table
Extra arguments that were given to the privilege command.
Return value:
None, the answer is given in the callback function in order to allow
for the admin mod to perform e.g. a database lookup.
]]
-- Default access handler
local defaultAccessHandler = {["CAMI.PlayerHasAccess"] =
function(_, actorPly, privilegeName, callback, _, extraInfoTbl)
-- The server always has access in the fallback
if not IsValid(actorPly) then return callback(true, "Fallback.") end
local priv = privileges[privilegeName]
local fallback = extraInfoTbl and (
not extraInfoTbl.Fallback and actorPly:IsAdmin() or
extraInfoTbl.Fallback == "user" and true or
extraInfoTbl.Fallback == "admin" and actorPly:IsAdmin() or
extraInfoTbl.Fallback == "superadmin" and actorPly:IsSuperAdmin())
if not priv then return callback(fallback, "Fallback.") end
callback(
priv.MinAccess == "user" or
priv.MinAccess == "admin" and actorPly:IsAdmin() or
priv.MinAccess == "superadmin" and actorPly:IsSuperAdmin()
, "Fallback.")
end,
["CAMI.SteamIDHasAccess"] =
function(_, _, _, callback)
callback(false, "No information available.")
end
}
function CAMI.PlayerHasAccess(actorPly, privilegeName, callback, targetPly,
extraInfoTbl)
hook.Call("CAMI.PlayerHasAccess", defaultAccessHandler, actorPly,
privilegeName, callback, targetPly, extraInfoTbl)
end
--[[
CAMI.GetPlayersWithAccess
Finds the list of currently joined players who have the right to perform a
certain action.
NOTE: this function will NOT return an immediate result!
The result is in the callback!
Parameters:
privilegeName
string
The name of the privilege.
callback
function(players)
This function will be called with the list of players with access.
targetPly
Optional.
The player on which the privilege is executed.
extraInfoTbl
Optional.
Table containing extra information.
Officially supported members:
Fallback
string
Either of user/admin/superadmin. When no admin mod replies,
the decision is based on the admin status of the user.
Defaults to admin if not given.
IgnoreImmunity
bool
Ignore any immunity mechanisms an admin mod might have.
CommandArguments
table
Extra arguments that were given to the privilege command.
]]
function CAMI.GetPlayersWithAccess(privilegeName, callback, targetPly,
extraInfoTbl)
local allowedPlys = {}
local allPlys = player.GetAll()
local countdown = #allPlys
local function onResult(ply, hasAccess, _)
countdown = countdown - 1
if hasAccess then table.insert(allowedPlys, ply) end
if countdown == 0 then callback(allowedPlys) end
end
for _, ply in pairs(allPlys) do
CAMI.PlayerHasAccess(ply, privilegeName,
function(...) onResult(ply, ...) end,
targetPly, extraInfoTbl)
end
end
--[[
CAMI.SteamIDHasAccess
Queries whether a player with a steam ID has the right to perform a certain
action.
Note: the player does not need to be in the server for this to
work.
Note: this function does NOT return an immediate result!
The result is in the callback!
Parameters:
actorSteam
Player
The SteamID of the player of which is requested whether they have
the privilege.
privilegeName
string
The name of the privilege.
callback
function(bool, string)
This function will be called with the answer. The bool signifies the
yes or no answer as to whether the player is allowed. The string
will optionally give a reason.
targetSteam
Optional.
The SteamID of the player on which the privilege is executed.
extraInfoTbl
Optional.
Table containing extra information.
Officially supported members:
IgnoreImmunity
bool
Ignore any immunity mechanisms an admin mod might have.
CommandArguments
table
Extra arguments that were given to the privilege command.
Return value:
None, the answer is given in the callback function in order to allow
for the admin mod to perform e.g. a database lookup.
]]
function CAMI.SteamIDHasAccess(actorSteam, privilegeName, callback,
targetSteam, extraInfoTbl)
hook.Call("CAMI.SteamIDHasAccess", defaultAccessHandler, actorSteam,
privilegeName, callback, targetSteam, extraInfoTbl)
end
--[[
CAMI.SignalUserGroupChanged
Signify that your admin mod has changed the usergroup of a player. This
function communicates to other admin mods what it thinks the usergroup
of a player should be.
Listen to the hook to receive the usergroup changes of other admin mods.
Parameters:
ply
Player
The player for which the usergroup is changed
old
string
The previous usergroup of the player.
new
string
The new usergroup of the player.
source
any
Identifier for your own admin mod. Can be anything.
]]
function CAMI.SignalUserGroupChanged(ply, old, new, source)
hook.Call("CAMI.PlayerUsergroupChanged", nil, ply, old, new, source)
end
--[[
CAMI.SignalSteamIDUserGroupChanged
Signify that your admin mod has changed the usergroup of a disconnected
player. This communicates to other admin mods what it thinks the usergroup
of a player should be.
Listen to the hook to receive the usergroup changes of other admin mods.
Parameters:
ply
string
The steam ID of the player for which the usergroup is changed
old
string
The previous usergroup of the player.
new
string
The new usergroup of the player.
source
any
Identifier for your own admin mod. Can be anything.
]]
function CAMI.SignalSteamIDUserGroupChanged(steamId, old, new, source)
hook.Call("CAMI.SteamIDUsergroupChanged", nil, steamId, old, new, source)
end

View File

@@ -1,267 +0,0 @@
--[[
| 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 timeMeasurementFunc = SysTime
-- Helper function
-- Get all local variables
local NIL = {}
setmetatable(NIL, {__tostring = function() return "nil" end})
--[[-------------------------------------------------------------------------
Call counts:
registers how often function have been called
---------------------------------------------------------------------------]]
local callcounts = {}
-- Gets the call counts
FProfiler.Internal.getCallCounts = function() return callcounts end
-- Resets the call counts
function FProfiler.Internal.resetCallCounts()
callcounts = {}
end
--[[-------------------------------------------------------------------------
Inclusive function times
Keeps track of how long functions take in total
i.e. average time between the start and return of a function * times called
This includes the time that any function called by this function takes
(that's what the "inclusive" refers to).
Note: recursive calls are not counted double
---------------------------------------------------------------------------]]
local inclusiveTimes = {}
-- Gets the inclusive times
FProfiler.Internal.getInclusiveTimes = function() return inclusiveTimes end
-- Resets the inclusive times
function FProfiler.Internal.resetInclusiveTimes()
inclusiveTimes = {}
end
--[[-------------------------------------------------------------------------
Top n most expensive single function calls
Keeps track of the functions that took the longest time to run
Note: functions can appear in this list at most once
---------------------------------------------------------------------------]]
local mostExpensiveSingleCalls = {}
-- Gets most expensive single calls
FProfiler.Internal.getMostExpensiveSingleCalls = function() return mostExpensiveSingleCalls end
-- Dictionary to make sure the same function doesn't appear multiple times
-- in the top n
local mostExpensiveSingleDict = {}
function FProfiler.Internal.resetMostExpensiveSingleCalls()
for i = 1, 50 do mostExpensiveSingleCalls[i] = {runtime = 0} end
mostExpensiveSingleDict = {}
end
-- Initial empty list
FProfiler.Internal.resetMostExpensiveSingleCalls()
--[[-------------------------------------------------------------------------
Function information
Using debug.getinfo on a function object won't give you any function names
that's because functions can have multiple names.
Luckily, when the functions are called, debug.getinfo(level) gives the
function name and scope
---------------------------------------------------------------------------]]
local functionNames = {}
FProfiler.Internal.getFunctionNames = function() return functionNames end
--[[-------------------------------------------------------------------------
Recursion depth
Used internally to make sure recursive functions' times aren't counted
multiple times
---------------------------------------------------------------------------]]
local recursiveCount = {}
--[[-------------------------------------------------------------------------
Function start times
Used internally to keep track of when functions were called
---------------------------------------------------------------------------]]
local startTimes = {}
--[[-------------------------------------------------------------------------
Lua code event handlers
---------------------------------------------------------------------------]]
-- The recursion depth of the function that is in focus.
-- Only applies when profiling a specific function (i.e. laying focus upon)
local focusDepth = 0
-- Called when a function in the code is called
local function registerFunctionCall(funcInfo)
local func = funcInfo.func
-- Update call counts
callcounts[func] = (callcounts[func] or 0) + 1
-- Increase recursion depth for this function
recursiveCount[func] = (recursiveCount[func] or 0) + 1
-- Store function info
local funcname = funcInfo.name or ""
functionNames[func] = functionNames[func] or {}
functionNames[func][funcname] = functionNames[func][funcname] or
{ namewhat = funcInfo.namewhat,
nparams = funcInfo.nparams
}
local time = timeMeasurementFunc()
-- Update inclusive function times,
-- only when we're on the first recursive call
if recursiveCount[func] == 1 then
startTimes[func] = time
end
end
-- Called when a function returns
local function registerReturn(funcInfo)
local time = timeMeasurementFunc()
local func = funcInfo.func
local runtime = time - startTimes[func]
-- Update inclusive function time
-- Only update on the topmost call, to prevent recursive
-- calls for being counted multiple times.
if recursiveCount[func] == 1 then
inclusiveTimes[func] = (inclusiveTimes[func] or 0) + runtime
end
-- Maintain recursion depth
recursiveCount[func] = recursiveCount[func] - 1
-- Update top n list
-- This path will be taken most often: the function isn't special
-- Also only counts the top recursion
if runtime <= mostExpensiveSingleCalls[50].runtime or recursiveCount[func] > 1 then return end
-- If the function already appears in the top 10, replace it or discard the result
if mostExpensiveSingleDict[func] then
local i = mostExpensiveSingleDict[func]
-- Discard this info
if runtime < mostExpensiveSingleCalls[i].runtime then return end
-- Update the entry
mostExpensiveSingleCalls[i].runtime = runtime
mostExpensiveSingleCalls[i].info = funcInfo
mostExpensiveSingleCalls[i].func = func
-- Move the updated entry up the top 10 list if applicable
while i > 1 and runtime > mostExpensiveSingleCalls[i - 1].runtime do
mostExpensiveSingleDict[mostExpensiveSingleCalls[i - 1].func] = i
mostExpensiveSingleCalls[i - 1], mostExpensiveSingleCalls[i] = mostExpensiveSingleCalls[i], mostExpensiveSingleCalls[i - 1]
i = i - 1
end
mostExpensiveSingleDict[func] = i
return
end
-- Knowing that the function belongs in the top n, find its position
local i = 50
while i >= 1 and runtime > mostExpensiveSingleCalls[i].runtime do
-- Update the dictionary
-- All functions faster than the current one move down the list
if not mostExpensiveSingleCalls[i].func then i = i - 1 continue end
mostExpensiveSingleDict[mostExpensiveSingleCalls[i].func] = i + 1
i = i - 1
end
-- Insert the expensive call in the top n
mostExpensiveSingleDict[func] = i + 1
table.insert(mostExpensiveSingleCalls, i + 1,
{
func = func,
runtime = runtime,
info = funcInfo,
})
-- What was previously the 50th most expensive function
-- is now kicked out of the top 10
if mostExpensiveSingleCalls[51].func then
mostExpensiveSingleDict[mostExpensiveSingleCalls[51].func] = nil
end
mostExpensiveSingleCalls[51] = nil
end
-- Called on any Lua event
local function onLuaEvent(event, focus)
local info = debug.getinfo(3)
local func = info.func
if event == "call" or event == "tail call" then
-- Only track the focussed function and the functions
-- called by the focussed function
if focus == func then focusDepth = focusDepth + 1 end
if focus and focusDepth == 0 then return end
registerFunctionCall(info)
else
-- Functions that return right after the call to FProfiler.Internal.start()
-- are not to be counted
if not recursiveCount[func] or recursiveCount[func] == 0 then return end
if focus == func then focusDepth = focusDepth - 1 end
if focus and focusDepth == 0 then return end
registerReturn(info)
end
end
--[[-------------------------------------------------------------------------
Profiling control
---------------------------------------------------------------------------]]
-- Start profiling
-- focus: only measure data of everything that happens within a certain function
function FProfiler.Internal.start(focus)
-- Empty start times, so unfinished functions aren't
-- registered as returns on a second profiling session
-- local time = SysTime()
-- for k,v in pairs(startTimes) do startTimes[k] = time end
table.Empty(startTimes)
table.Empty(recursiveCount)
debug.sethook(function(event) onLuaEvent(event, focus) end, "cr")
end
-- Stop profiling
function FProfiler.Internal.stop()
debug.sethook()
end
-- Reset all profiling data
function FProfiler.Internal.reset()
FProfiler.Internal.resetCallCounts()
FProfiler.Internal.resetInclusiveTimes()
FProfiler.Internal.resetMostExpensiveSingleCalls()
end

View File

@@ -1,594 +0,0 @@
--[[
| 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/
--]]
-- Based on MDave's thing
-- https://gist.github.com/mentlerd/d56ad9e6361f4b86af84
if SERVER then AddCSLuaFile() end
local type_weight = {
[TYPE_FUNCTION] = 1,
[TYPE_TABLE] = 2,
}
local type_colors = {
[TYPE_BOOL] = Color(175, 130, 255),
[TYPE_NUMBER] = Color(175, 130, 255),
[TYPE_STRING] = Color(230, 220, 115),
[TYPE_FUNCTION] = Color(100, 220, 240)
}
local color_neutral = Color(220, 220, 220)
local color_name = Color(260, 150, 30)
local color_reference = Color(150, 230, 50)
local color_comment = Color( 30, 210, 30)
-- 'nil' value
local NIL = {}
-- Localise for faster access
local pcall = pcall
local string_len = string.len
local string_sub = string.sub
local string_find = string.find
local table_concat = table.concat
local table_insert = table.insert
local table_sort = table.sort
-- Stream interface
local gMsgF -- Print fragment
local gMsgN -- Print newline
local gMsgC -- Set print color
local PrintLocals, gBegin, gFinish, PrintTableGrep
do
local grep_color = Color(235, 70, 70)
-- Grep parameters (static between gBegin/gEnd)
local grep
local grep_raw
local grep_proximity
-- Current line parameters
local buffer
local colors
local markers
local baseColor
local currColor
local length
-- History
local history
local remain
-- Actual printing
local function gCheckMatch( buffer )
local raw = table_concat(buffer)
return raw, string_find(raw, grep, 0, grep_raw)
end
local function gFlushEx( raw, markers, colors, baseColor )
-- Print entire buffer
local len = string_len(raw)
-- Keep track of the current line properties
local index = 1
local marker = 1
local currColor = baseColor
-- Method to print to a preset area
local function printToIndex( limit, color )
local mark = markers and markers[marker]
-- Print all marker areas until we would overshoot
while mark and mark < limit do
-- Catch up to the marker
MsgC(color or currColor or color_neutral, string_sub(raw, index, mark))
index = mark +1
-- Set new color
currColor = colors[marker]
-- Select next marker
marker = marker +1
mark = markers[marker]
end
-- Print the remaining between the last marker and the limit
MsgC(color or currColor or color_neutral, string_sub(raw, index, limit))
index = limit +1
end
-- Grep!
local match, last = 1
local from, to = string_find(raw, grep, 0, grep_raw)
while from do
printToIndex(from -1)
printToIndex(to, grep_color)
last = to +1
from, to = string_find(raw, grep, last, grep_raw)
end
printToIndex(len)
MsgN()
end
local function gCommit()
if grep_proximity then
-- Check if the line has at least one match
local raw, match = gCheckMatch(buffer)
if match then
-- Divide matches
if history[grep_proximity] then
MsgN("...")
end
-- Flush history
if grep_proximity ~= 0 then
local len = #history
for index = len -1, 1, -1 do
local entry = history[index]
history[index] = nil
gFlushEx( entry[1], entry[2], entry[3], entry[4] )
end
history[len] = nil
end
-- Flush line, allow next X lines to get printed
gFlushEx( raw, markers, colors, baseColor )
remain = grep_proximity -1
history[grep_proximity +1] = nil
elseif remain > 0 then
-- Flush immediately
gFlushEx( raw, markers, colors, baseColor )
remain = remain -1
else
-- Store in history
table_insert(history, 1, {raw, markers, colors, baseColor})
history[grep_proximity +1] = nil
end
else
-- Flush anyway
gFlushEx( table_concat(buffer), markers, colors, baseColor )
end
-- Reset state
length = 0
buffer = {}
markers = nil
colors = nil
baseColor = nil
currColor = nil
end
-- State machine
function gBegin( new, prox )
grep = isstring(new) and new
if grep then
grep_raw = not pcall(string_find, ' ', grep)
grep_proximity = isnumber(prox) and prox
-- Reset everything
buffer = {}
history = {}
end
length = 0
remain = 0
baseColor = nil
currColor = nil
end
function gFinish()
if grep_proximity and history and history[1] then
MsgN("...")
end
-- Free memory
buffer = nil
markers = nil
colors = nil
history = nil
end
function gMsgC( color )
if grep then
-- Try to save some memory by not immediately allocating colors
if length == 0 then
baseColor = color
return
end
-- Record color change
if color ~= currColor then
if not markers then
markers = {}
colors = {}
end
-- Record color change
table_insert(markers, length)
table_insert(colors, color)
end
end
currColor = color
end
function gMsgF( str )
if grep then
-- Split multiline fragments to separate ones
local fragColor = currColor or baseColor
local last = 1
local from, to = string_find(str, '\n')
while from do
local frag = string_sub(str, last, from -1)
local len = from - last
-- Merge fragment to the line
length = length + len
table_insert(buffer, frag)
-- Print finished line
gCommit()
-- Assign base color as previous fragColor
baseColor = fragColor
-- Look for more
last = to +1
from, to = string_find(str, '\n', last)
end
-- Push last fragment
local frag = string_sub(str, last)
local len = string_len(str) - last +1
length = length + len
table_insert(buffer, frag)
else
-- Push immediately
MsgC(currColor or baseColor or color_neutral, str)
end
end
function gMsgN()
-- Print everything in the buffer
if grep then
gCommit()
else
MsgN()
end
baseColor = nil
currColor = nil
end
end
local function InternalPrintValue( value )
-- 'nil' values can also be printed
if value == NIL then
gMsgC(color_comment)
gMsgF("nil")
return
end
local color = type_colors[ TypeID(value) ]
-- For strings, place quotes
if isstring(value) then
if string_len(value) <= 1 then
value = string.format([['%s']], value)
else
value = string.format([["%s"]], value)
end
gMsgC(color)
gMsgF(value)
return
end
-- Workaround for userdata not using MetaName
if string_sub(tostring(value), 0, 8) == "userdata" then
local meta = getmetatable(value)
if meta and meta.MetaName then
value = string.format("%s: %p", meta.MetaName, value)
end
end
-- General print
gMsgC(color)
gMsgF(tostring(value))
-- For functions append source info
if isfunction(value) then
local info = debug.getinfo(value, 'S')
local aux
if info.what == 'C' then
aux = "\t-- [C]: -1"
else
if info.linedefined ~= info.lastlinedefined then
aux = string.format("\t-- [%s]: %i-%i", info.short_src, info.linedefined, info.lastlinedefined)
else
aux = string.format("\t-- [%s]: %i", info.short_src, info.linedefined)
end
end
gMsgC(color_comment)
gMsgF(aux)
end
end
-- Associated to object keys
local objID
local function isprimitive( value )
local id = TypeID(value)
return id <= TYPE_FUNCTION and id ~= TYPE_TABLE
end
local function InternalPrintTable( table, path, prefix, names, todo )
-- Collect keys and some info about them
local keyList = {}
local keyStr = {}
local keyCount = 0
for key, value in pairs( table ) do
-- Add to key list for later sorting
table_insert(keyList, key)
-- Describe key as string
if isprimitive(key) then
keyStr[key] = tostring(key)
else
-- Lookup already known name
local name = names[key]
-- Assign a new unique identifier
if not name then
objID = objID +1
name = string.format("%s: obj #%i", tostring(key), objID)
names[key] = name
todo[key] = true
end
-- Substitute object with name
keyStr[key] = name
end
keyCount = keyCount +1
end
-- Exit early for empty tables
if keyCount == 0 then
return
end
-- Determine max key length
local keyLen = 4
for key, str in pairs(keyStr) do
keyLen = math.max(keyLen, string.len(str))
end
-- Sort table keys
if keyCount > 1 then
table_sort( keyList, function( A, B )
-- Sort numbers numerically correct
if isnumber(A) and isnumber(B) then
return A < B
end
-- Weight types
local wA = type_weight[ TypeID( table[A] ) ] or 0
local wB = type_weight[ TypeID( table[B] ) ] or 0
if wA ~= wB then
return wA < wB
end
-- Order by string representation
return keyStr[A] < keyStr[B]
end )
end
-- Determine the next level ident
local new_prefix = string.format( "%s║%s", prefix, string.rep(' ', keyLen) )
-- Mark object as done
todo[table] = nil
-- Start describing table
for index, key in ipairs(keyList) do
local value = table[key]
-- Assign names to already described keys/values
local kName = names[key]
local vName = names[value]
-- Decide to either fully describe, or print the value
local describe = not isprimitive(value) and ( not vName or todo[value] )
-- Ident
gMsgF(prefix)
-- Fancy table guides
local moreLines = (index ~= keyCount) or describe
if index == 1 then
gMsgF(moreLines and '' or '')
else
gMsgF(moreLines and '' or '')
end
-- Print key
local sKey = kName or keyStr[key]
gMsgC(kName and color_reference or color_name)
gMsgF(sKey)
-- Describe non primitives
describe = istable(value) and ( not names[value] or todo[value] ) and value ~= NIL
-- Print key postfix
local padding = keyLen - string.len(sKey)
local postfix = string.format(describe and ":%s" or "%s = ", string.rep(' ', padding))
gMsgC(color_neutral)
gMsgF(postfix)
-- Print the value
if describe then
gMsgN()
-- Expand access path
local new_path = sKey
if isnumber(key) or kName then
new_path = string.format("%s[%s]", path or '', key)
elseif path then
new_path = string.format("%s.%s", path, new_path)
end
-- Name the object to mark it done
names[value] = names[value] or new_path
-- Describe
InternalPrintTable(value, new_path, new_prefix, names, todo)
else
-- Print the value (or the reference name)
if vName and not todo[value] then
gMsgC(color_reference)
gMsgF(string.format("ref: %s",vName))
else
InternalPrintValue(value)
end
gMsgN()
end
end
end
function PrintTableGrep( table, grep, proximity )
local base = {
[_G] = "_G",
[table] = "root"
}
gBegin(grep, proximity)
objID = 0
InternalPrintTable(table, nil, "", base, {})
gFinish()
end
function PrintLocals( level )
local level = level or 2
local hash = {}
for index = 1, 255 do
local name, value = debug.getlocal(2, index)
if not name then
break
end
if value == nil then
value = NIL
end
hash[name] = value
end
PrintTableGrep( hash )
end
function show(...)
local n = select('#', ...)
local tbl = {...}
for i = 1, n do
if istable(tbl[i]) then MsgN(tostring(tbl[i])) PrintTableGrep(tbl[i])
else InternalPrintValue(tbl[i]) MsgN() end
end
end
-- Hacky way of creating a pretty string from the above code
-- because I don't feel like refactoring the entire thing
local strResult
local toStringMsgF = function(txt)
table.insert(strResult, txt)
end
local toStringMsgN = function()
table.insert(strResult, "\n")
end
local toStringMsgC = function(_, txt)
table.insert(strResult, txt)
end
function showStr(...)
local oldF, oldN, oldMsgC, oldMsgN = gMsgF, gMsgN, MsgC, MsgN
gMsgF, gMsgN, MsgC, MsgN = toStringMsgF, toStringMsgN, toStringMsgC, toStringMsgN
strResult = {}
show(...)
gMsgF, gMsgN, MsgC, MsgN = oldF, oldN, oldMsgC, oldMsgN
return table.concat(strResult, "")
end

View File

@@ -1,114 +0,0 @@
--[[
| 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 function getData()
local callCounts = FProfiler.Internal.getCallCounts()
local inclusiveTimes = FProfiler.Internal.getInclusiveTimes()
local funcNames = FProfiler.Internal.getFunctionNames()
local data = {}
for func, called in pairs(callCounts) do
local row = {}
row.func = func
row.info = debug.getinfo(func, "nfS")
row.total_called = called
row.total_time = inclusiveTimes[func] or 0
row.average_time = row.total_time / row.total_called
row.name, row.namewhat = nil, nil
row.names = {}
for name, namedata in pairs(funcNames[func]) do
table.insert(row.names, {name = name, namewhat = namedata.namewhat, nparams = namedata.nparams})
end
table.insert(data, row)
end
return data
end
local function cull(data, count)
if not count then return data end
for i = count + 1, #data do
data[i] = nil
end
return data
end
--[[-------------------------------------------------------------------------
The functions that are called most often
Their implementations are O(n lg n),
which is probably suboptimal but not worth my time optimising.
---------------------------------------------------------------------------]]
function FProfiler.Internal.mostOftenCalled(count)
local sorted = getData()
table.SortByMember(sorted, "total_called")
return cull(sorted, count)
end
--[[-------------------------------------------------------------------------
The functions that take the longest time in total
---------------------------------------------------------------------------]]
function FProfiler.Internal.mostTimeInclusive(count)
local sorted = getData()
table.SortByMember(sorted, "total_time")
return cull(sorted, count)
end
--[[-------------------------------------------------------------------------
The functions that take the longest average time
---------------------------------------------------------------------------]]
function FProfiler.Internal.mostTimeInclusiveAverage(count)
local sorted = getData()
table.SortByMember(sorted, "average_time")
return cull(sorted, count)
end
--[[-------------------------------------------------------------------------
Get the top <count> of most often called, time inclusive and average
NOTE: This will almost definitely return more than <count> results.
Up to three times <count> is possible.
---------------------------------------------------------------------------]]
function FProfiler.Internal.getAggregatedResults(count)
count = count or 100
local dict = {}
local mostTime = FProfiler.Internal.mostTimeInclusive(count)
for i = 1, #mostTime do dict[mostTime[i].func] = true end
local mostAvg = FProfiler.Internal.mostTimeInclusiveAverage(count)
for i = 1, #mostAvg do
if dict[mostAvg[i].func] then continue end
dict[mostAvg[i].func] = true
table.insert(mostTime, mostAvg[i])
end
local mostCalled = FProfiler.Internal.mostOftenCalled(count)
for i = 1, #mostCalled do
if dict[mostCalled[i].func] then continue end
dict[mostCalled[i].func] = true
table.insert(mostTime, mostCalled[i])
end
table.SortByMember(mostTime, "total_time")
return mostTime
end

View File

@@ -1,110 +0,0 @@
--[[
| 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 get, update, onUpdate = FProfiler.UI.getModelValue, FProfiler.UI.updateModel, FProfiler.UI.onModelUpdate
--[[-------------------------------------------------------------------------
(Re)start clientside profiling
---------------------------------------------------------------------------]]
local function restartProfiling()
if get({"client", "shouldReset"}) then
FProfiler.Internal.reset()
update({"client", "recordTime"}, 0)
end
local focus = get({"client", "focusObj"})
update({"client", "sessionStart"}, CurTime())
update({"client", "sessionStartSysTime"}, SysTime())
FProfiler.Internal.start(focus)
end
--[[-------------------------------------------------------------------------
Stop profiling
---------------------------------------------------------------------------]]
local function stopProfiling()
FProfiler.Internal.stop()
local newTime = get({"client", "recordTime"}) + SysTime() - (get({"client", "sessionStartSysTime"}) or 0)
-- Get the aggregated data
local mostTime = FProfiler.Internal.getAggregatedResults(100)
update({"client", "bottlenecks"}, mostTime)
update({"client", "topLagSpikes"}, FProfiler.Internal.getMostExpensiveSingleCalls())
update({"client", "recordTime"}, newTime)
update({"client", "sessionStart"}, nil)
update({"client", "sessionStartSysTime"}, nil)
end
--[[-------------------------------------------------------------------------
Start/stop recording when the recording status is changed
---------------------------------------------------------------------------]]
onUpdate({"client", "status"}, function(new, old)
if new == old then return end
(new == "Started" and restartProfiling or stopProfiling)()
end)
--[[-------------------------------------------------------------------------
Update the current selected focus object when data is entered
---------------------------------------------------------------------------]]
onUpdate({"client", "focusStr"}, function(new)
update({"client", "focusObj"}, FProfiler.funcNameToObj(new))
end)
--[[-------------------------------------------------------------------------
Update info when a different line is selected
---------------------------------------------------------------------------]]
onUpdate({"client", "currentSelected"}, function(new)
if not new or not new.info or not new.info.linedefined or not new.info.lastlinedefined or not new.info.short_src then return end
update({"client", "sourceText"}, FProfiler.readSource(new.info.short_src, new.info.linedefined, new.info.lastlinedefined))
end)
--[[-------------------------------------------------------------------------
When a function is to be printed to console
---------------------------------------------------------------------------]]
onUpdate({"client", "toConsole"}, function(data)
if not data then return end
update({"client", "toConsole"}, nil)
show(data)
file.CreateDir("fprofiler")
file.Write("fprofiler/profiledata.txt", showStr(data))
MsgC(Color(200, 200, 200), "-----", Color(120, 120, 255), "NOTE", Color(200, 200, 200), "---------------\n")
MsgC(Color(200, 200, 200), "If the above function does not fit in console, you can find it in data/fprofiler/profiledata.txt\n\n")
end)
--[[-------------------------------------------------------------------------
API function: start profiling
---------------------------------------------------------------------------]]
function FProfiler.start(focus)
update({"client", "focusStr"}, tostring(focus))
update({"client", "focusObj"}, focus)
update({"client", "shouldReset"}, true)
update({"client", "status"}, "Started")
end
--[[-------------------------------------------------------------------------
API function: stop profiling
---------------------------------------------------------------------------]]
function FProfiler.stop()
update({"client", "status"}, "Stopped")
end
--[[-------------------------------------------------------------------------
API function: continue profiling
---------------------------------------------------------------------------]]
function FProfiler.continueProfiling()
update({"client", "shouldReset"}, false)
update({"client", "status"}, "Started")
end

View File

@@ -1,475 +0,0 @@
--[[
| 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/
--]]
--[[-------------------------------------------------------------------------
The panel that contains the realm switcher
---------------------------------------------------------------------------]]
local REALMPANEL = {}
function REALMPANEL:Init()
self:DockPadding(0, 0, 0, 0)
self:DockMargin(0, 0, 5, 0)
self.realmLabel = vgui.Create("DLabel", self)
self.realmLabel:SetDark(true)
self.realmLabel:SetText("Realm:")
self.realmLabel:SizeToContents()
self.realmLabel:Dock(TOP)
self.realmbox = vgui.Create("DComboBox", self)
self.realmbox:AddChoice("Client")
self.realmbox:AddChoice("Server")
self.realmbox:Dock(TOP)
FProfiler.UI.onModelUpdate("realm", function(new)
self.realmbox.selected = new == "client" and 1 or 2
self.realmbox:SetText(new == "client" and "Client" or "Server")
end)
FProfiler.UI.onModelUpdate("serverAccess", function(hasAccess)
self.realmbox:SetDisabled(not hasAccess)
if not hasAccess and self.realmbox.selected == 2 then
FProfiler.UI.updateModel("realm", "client")
end
end)
self.realmbox.OnSelect = function(_, _, value) FProfiler.UI.updateModel("realm", string.lower(value)) end
end
function REALMPANEL:PerformLayout()
self.realmLabel:SizeToContents()
local top = ( self:GetTall() - self.realmLabel:GetTall() - self.realmbox:GetTall()) * 0.5
self:DockPadding(0, top, 0, 0)
end
derma.DefineControl("FProfileRealmPanel", "", REALMPANEL, "Panel")
--[[-------------------------------------------------------------------------
The little red or green indicator that indicates whether the focussing
function is correct
---------------------------------------------------------------------------]]
local FUNCINDICATOR = {}
function FUNCINDICATOR:Init()
self:SetTall(5)
self.color = Color(0, 0, 0, 0)
end
function FUNCINDICATOR:Paint()
draw.RoundedBox(0, 0, 0, self:GetWide(), self:GetTall(), self.color)
end
derma.DefineControl("FProfileFuncIndicator", "", FUNCINDICATOR, "DPanel")
--[[-------------------------------------------------------------------------
The panel that contains the focus text entry and the focus indicator
---------------------------------------------------------------------------]]
local FOCUSPANEL = {}
function FOCUSPANEL:Init()
self:DockPadding(0, 0, 0, 0)
self:DockMargin(0, 0, 5, 0)
self.focusLabel = vgui.Create("DLabel", self)
self.focusLabel:SetDark(true)
self.focusLabel:SetText("Profiling Focus:")
self.focusLabel:SizeToContents()
self.focusLabel:Dock(TOP)
self.funcIndicator = vgui.Create("FProfileFuncIndicator", self)
self.funcIndicator:Dock(BOTTOM)
self.focusBox = vgui.Create("DTextEntry", self)
self.focusBox:SetText("")
self.focusBox:SetWidth(150)
self.focusBox:Dock(BOTTOM)
self.focusBox:SetTooltip("Focus the profiling on a single function.\nEnter a global function name here (like player.GetAll)\nYou're not allowed to call functions in here (e.g. hook.GetTable() is not allowed)")
function self.focusBox:OnChange()
FProfiler.UI.updateCurrentRealm("focusStr", self:GetText())
end
FProfiler.UI.onCurrentRealmUpdate("focusObj", function(new)
self.funcIndicator.color = FProfiler.UI.getCurrentRealmValue("focusStr") == "" and Color(0, 0, 0, 0) or new and Color(80, 255, 80, 255) or Color(255, 80, 80, 255)
end)
FProfiler.UI.onCurrentRealmUpdate("focusStr", function(new, old)
if self.focusBox:GetText() == new then return end
self.focusBox:SetText(tostring(new))
end)
end
function FOCUSPANEL:PerformLayout()
self.focusBox:SetWide(200)
self.focusLabel:SizeToContents()
end
derma.DefineControl("FProfileFocusPanel", "", FOCUSPANEL, "Panel")
--[[-------------------------------------------------------------------------
The timer that keeps track of for how long the profiling has been going on
---------------------------------------------------------------------------]]
local TIMERPANEL = {}
function TIMERPANEL:Init()
self:DockPadding(0, 5, 0, 5)
self:DockMargin(5, 0, 5, 0)
self.timeLabel = vgui.Create("DLabel", self)
self.timeLabel:SetDark(true)
self.timeLabel:SetText("Total profiling time:")
self.timeLabel:SizeToContents()
self.timeLabel:Dock(TOP)
self.counter = vgui.Create("DLabel", self)
self.counter:SetDark(true)
self.counter:SetText("00:00:00")
self.counter:SizeToContents()
self.counter:Dock(RIGHT)
function self.counter:Think()
local recordTime, sessionStart = FProfiler.UI.getCurrentRealmValue("recordTime"), FProfiler.UI.getCurrentRealmValue("sessionStart")
local totalTime = recordTime + (sessionStart and (CurTime() - sessionStart) or 0)
self:SetText(string.FormattedTime(totalTime, "%02i:%02i:%02i"))
end
end
function TIMERPANEL:PerformLayout()
self.timeLabel:SizeToContents()
self.counter:SizeToContents()
end
derma.DefineControl("FProfileTimerPanel", "", TIMERPANEL, "Panel")
--[[-------------------------------------------------------------------------
The top bar
---------------------------------------------------------------------------]]
local MAGICBAR = {}
function MAGICBAR:Init()
self:DockPadding(5, 5, 5, 5)
self.realmpanel = vgui.Create("FProfileRealmPanel", self)
-- (Re)Start profiling
self.restartProfiling = vgui.Create("DButton", self)
self.restartProfiling:SetText(" (Re)Start\n Profiling")
self.restartProfiling:DockMargin(0, 0, 5, 0)
self.restartProfiling:Dock(LEFT)
self.restartProfiling.DoClick = function()
FProfiler.UI.updateCurrentRealm("shouldReset", true)
FProfiler.UI.updateCurrentRealm("status", "Started")
end
FProfiler.UI.onCurrentRealmUpdate("status", function(new)
self.restartProfiling:SetDisabled(new == "Started")
end)
-- Stop profiling
self.stopProfiling = vgui.Create("DButton", self)
self.stopProfiling:SetText(" Stop\n Profiling")
self.stopProfiling:DockMargin(0, 0, 5, 0)
self.stopProfiling:Dock(LEFT)
self.stopProfiling.DoClick = function()
FProfiler.UI.updateCurrentRealm("status", "Stopped")
end
FProfiler.UI.onCurrentRealmUpdate("status", function(new)
self.stopProfiling:SetDisabled(new == "Stopped")
end)
-- Continue profiling
self.continueProfiling = vgui.Create("DButton", self)
self.continueProfiling:SetText(" Continue\n Profiling")
self.continueProfiling:DockMargin(0, 0, 5, 0)
self.continueProfiling:Dock(LEFT)
self.continueProfiling.DoClick = function()
FProfiler.UI.updateCurrentRealm("shouldReset", false)
FProfiler.UI.updateCurrentRealm("status", "Started")
end
FProfiler.UI.onCurrentRealmUpdate("status", function(new)
self.continueProfiling:SetDisabled(new == "Started")
end)
self.realmpanel:Dock(LEFT)
self.focuspanel = vgui.Create("FProfileFocusPanel", self)
self.focuspanel:Dock(LEFT)
-- Timer
self.timerpanel = vgui.Create("FProfileTimerPanel", self)
self.timerpanel:Dock(RIGHT)
end
function MAGICBAR:PerformLayout()
self.realmpanel:SizeToChildren(true, false)
self.focuspanel:SizeToChildren(true, false)
self.timerpanel:SizeToChildren(true, false)
end
derma.DefineControl("FProfileMagicBar", "", MAGICBAR, "DPanel")
--[[-------------------------------------------------------------------------
A custom sort by column function to deal with sorting by numeric value
--------------------------------------------------------------------------]]
local function SortByColumn(self, ColumnID, Desc)
table.Copy(self.Sorted, self.Lines)
table.sort(self.Sorted, function(a, b)
if Desc then
a, b = b, a
end
local aval = a:GetSortValue(ColumnID) or a:GetColumnText(ColumnID)
local bval = b:GetSortValue(ColumnID) or b:GetColumnText(ColumnID)
local anum = tonumber(aval)
local bnum = tonumber(bval)
if anum and bnum then
return anum < bnum
end
return tostring(aval) < tostring(bval)
end)
self:SetDirty(true)
self:InvalidateLayout()
end
--[[-------------------------------------------------------------------------
The Bottlenecks tab's contents
---------------------------------------------------------------------------]]
local BOTTLENECKTAB = {}
BOTTLENECKTAB.SortByColumn = SortByColumn
function BOTTLENECKTAB:Init()
self:SetMultiSelect(false)
self:AddColumn("Name")
self:AddColumn("Path")
self:AddColumn("Lines")
self:AddColumn("Amount of times called")
self:AddColumn("Total time in ms (inclusive)")
self:AddColumn("Average time in ms (inclusive)")
FProfiler.UI.onCurrentRealmUpdate("bottlenecks", function(new)
self:Clear()
for _, row in ipairs(new) do
local names = {}
local path = row.info.short_src
local lines = path ~= "[C]" and row.info.linedefined .. " - " .. row.info.lastlinedefined or "N/A"
local amountCalled = row.total_called
local totalTime = row.total_time * 100
local avgTime = row.average_time * 100
for _, fname in ipairs(row.names or {}) do
if fname.namewhat == "" and fname.name == "" then continue end
table.insert(names, fname.namewhat .. " " .. fname.name)
end
if #names == 0 then names[1] = "Unknown" end
local line = self:AddLine(table.concat(names, "/"), path, lines, amountCalled, totalTime, avgTime)
line.data = row
end
end)
FProfiler.UI.onCurrentRealmUpdate("currentSelected", function(new, old)
if new == old then return end
for _, line in pairs(self.Lines) do
line:SetSelected(line.data.func == new.func)
end
end)
end
function BOTTLENECKTAB:OnRowSelected(id, line)
FProfiler.UI.updateCurrentRealm("currentSelected", line.data)
end
derma.DefineControl("FProfileBottleNecks", "", BOTTLENECKTAB, "DListView")
--[[-------------------------------------------------------------------------
The Top n lag spikes tab's contents
---------------------------------------------------------------------------]]
local TOPTENTAB = {}
TOPTENTAB.SortByColumn = SortByColumn
function TOPTENTAB:Init()
self:SetMultiSelect(false)
self:AddColumn("Name")
self:AddColumn("Path")
self:AddColumn("Lines")
self:AddColumn("Runtime in ms")
FProfiler.UI.onCurrentRealmUpdate("topLagSpikes", function(new)
self:Clear()
for _, row in ipairs(new) do
if not row.func then break end
local name = row.info.name and row.info.name ~= "" and (row.info.namewhat .. " " .. row.info.name) or "Unknown"
local path = row.info.short_src
local lines = path ~= "[C]" and row.info.linedefined .. " - " .. row.info.lastlinedefined or "N/A"
local runtime = row.runtime * 100
local line = self:AddLine(name, path, lines, runtime)
line.data = row
end
end)
FProfiler.UI.onCurrentRealmUpdate("currentSelected", function(new, old)
if new == old then return end
for _, line in pairs(self.Lines) do
line:SetSelected(line.data.func == new.func)
end
end)
end
function TOPTENTAB:OnRowSelected(id, line)
FProfiler.UI.updateCurrentRealm("currentSelected", line.data)
end
derma.DefineControl("FProfileTopTen", "", TOPTENTAB, "DListView")
--[[-------------------------------------------------------------------------
The Tab panel of the bottlenecks and top n lag spikes
---------------------------------------------------------------------------]]
local RESULTSHEET = {}
function RESULTSHEET:Init()
self:DockMargin(0, 10, 0, 0)
self:SetPadding(0)
self.bottlenecksTab = vgui.Create("FProfileBottleNecks")
self:AddSheet("Bottlenecks", self.bottlenecksTab)
self.toptenTab = vgui.Create("FProfileTopTen")
self:AddSheet("Top 50 most expensive function calls", self.toptenTab)
end
derma.DefineControl("FProfileResultSheet", "", RESULTSHEET, "DPropertySheet")
--[[-------------------------------------------------------------------------
The function details panel
---------------------------------------------------------------------------]]
local FUNCDETAILS = {}
function FUNCDETAILS:Init()
self.titleLabel = vgui.Create("DLabel", self)
self.titleLabel:SetDark(true)
self.titleLabel:SetFont("DermaLarge")
self.titleLabel:SetText("Function Details")
self.titleLabel:SizeToContents()
-- self.titleLabel:Dock(TOP)
self.focus = vgui.Create("DButton", self)
self.focus:SetText("Focus")
self.focus:SetTall(50)
self.focus:SetFont("DermaDefaultBold")
self.focus:Dock(BOTTOM)
function self.focus:DoClick()
local sel = FProfiler.UI.getCurrentRealmValue("currentSelected")
if not sel then return end
FProfiler.UI.updateCurrentRealm("focusStr", sel.func)
end
self.source = vgui.Create("DTextEntry", self)
self.source:SetKeyboardInputEnabled(false)
self.source:DockMargin(0, 40, 0, 0)
self.source:SetMultiline(true)
self.source:Dock(FILL)
FProfiler.UI.onCurrentRealmUpdate("sourceText", function(new)
self.source:SetText(string.Replace(new, "\t", " "))
end)
self.toConsole = vgui.Create("DButton", self)
self.toConsole:SetText("Print Details to Console")
self.toConsole:SetTall(50)
self.toConsole:SetFont("DermaDefaultBold")
self.toConsole:Dock(BOTTOM)
function self.toConsole:DoClick()
FProfiler.UI.updateCurrentRealm("toConsole", FProfiler.UI.getCurrentRealmValue("currentSelected"))
end
end
function FUNCDETAILS:PerformLayout()
self.titleLabel:CenterHorizontal()
end
derma.DefineControl("FProfileFuncDetails", "", FUNCDETAILS, "DPanel")
--[[-------------------------------------------------------------------------
The actual frame
---------------------------------------------------------------------------]]
local FRAME = {}
local frameInstance
function FRAME:Init()
self:SetTitle("FProfiler profiling tool")
self:SetSize(ScrW() * 0.8, ScrH() * 0.8)
self:Center()
self:SetVisible(true)
self:MakePopup()
self:SetDeleteOnClose(false)
self.magicbar = vgui.Create("FProfileMagicBar", self)
self.magicbar:SetTall(math.max(self:GetTall() * 0.07, 48))
self.magicbar:Dock(TOP)
self.resultsheet = vgui.Create("FProfileResultSheet", self)
self.resultsheet:SetWide(self:GetWide() * 0.8)
self.resultsheet:Dock(LEFT)
self.details = vgui.Create("FProfileFuncDetails", self)
self.details:SetWide(self:GetWide() * 0.2 - 12)
self.details:DockMargin(5, 31, 0, 0)
self.details:Dock(RIGHT)
end
function FRAME:OnClose()
FProfiler.UI.updateModel("frameVisible", false)
end
derma.DefineControl("FProfileFrame", "", FRAME, "DFrame")
--[[-------------------------------------------------------------------------
The command to start the profiler
---------------------------------------------------------------------------]]
concommand.Add("FProfiler",
function()
frameInstance = frameInstance or vgui.Create("FProfileFrame")
frameInstance:SetVisible(true)
FProfiler.UI.updateModel("frameVisible", true)
end,
nil, "Starts FProfiler")

View File

@@ -1,188 +0,0 @@
--[[
| 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/
--]]
--[[-------------------------------------------------------------------------
The model describes the data that the drives the UI
Loosely based on the Elm architecture
---------------------------------------------------------------------------]]
local model =
{
realm = "client", -- "client" or "server"
serverAccess = false, -- Whether the player has access to profile the server
frameVisible = false, -- Whether the frame is visible
client = {
status = "Stopped", -- Started or Stopped
shouldReset = true, -- Whether profiling should start anew
recordTime = 0, -- Total time spent on the last full profiling session
sessionStart = nil, -- When the last profiling session was started
sessionStartSysTime = nil, -- When the last profiling session was started, measured in SysTime
bottlenecks = {}, -- The list of bottleneck functions
topLagSpikes = {}, -- Top of lagging functions
currentSelected = nil, -- Currently selected function
focusObj = nil, -- The current function being focussed upon in profiling
focusStr = "", -- The current function name being entered
toConsole = nil, -- Any functions that should be printed to console
sourceText = "", -- The text of the source function (if available)
},
server = {
status = "Stopped", -- Started or Stopped
shouldReset = true, -- Whether profiling should start anew
bottlenecks = {}, -- The list of bottleneck functions
recordTime = 0, -- Total time spent on the last full profiling session
sessionStart = nil, -- When the last profiling session was started
topLagSpikes = {}, -- Top of lagging functions
currentSelected = nil, -- Currently selected function
focusObj = nil, -- The current function being focussed upon in profiling
focusStr = "", -- The current function name
toConsole = nil, -- Any functions that should be printed to console
sourceText = "", -- The text of the source function (if available)
fromServer = false, -- Whether a change of the model came from the server.
},
}
local updaters = {}
--[[-------------------------------------------------------------------------
Update the model.
Automatically calls the registered update hook functions
e.g. updating the realm would be:
FProfiler.UI.updateModel("realm", "server")
---------------------------------------------------------------------------]]
function FProfiler.UI.updateModel(path, value)
path = istable(path) and path or {path}
local updTbl = updaters
local mdlTbl = model
local key = path[#path]
for i = 1, #path - 1 do
mdlTbl = mdlTbl[path[i]]
updTbl = updTbl and updTbl[path[i]]
end
local oldValue = mdlTbl[key]
mdlTbl[key] = value
for _, updFunc in ipairs(updTbl and updTbl[key] or {}) do
updFunc(value, oldValue)
end
end
--[[-------------------------------------------------------------------------
Update the model of the current realm
---------------------------------------------------------------------------]]
function FProfiler.UI.updateCurrentRealm(path, value)
path = istable(path) and path or {path}
table.insert(path, 1, model.realm)
FProfiler.UI.updateModel(path, value)
end
--[[-------------------------------------------------------------------------
Retrieve a value of the model
---------------------------------------------------------------------------]]
function FProfiler.UI.getModelValue(path)
path = istable(path) and path or {path}
local mdlTbl = model
local key = path[#path]
for i = 1, #path - 1 do
mdlTbl = mdlTbl[path[i]]
end
return mdlTbl[key]
end
--[[-------------------------------------------------------------------------
Retrieve a value of the model regardless of realm
---------------------------------------------------------------------------]]
function FProfiler.UI.getCurrentRealmValue(path)
path = istable(path) and path or {path}
table.insert(path, 1, model.realm)
return FProfiler.UI.getModelValue(path)
end
--[[-------------------------------------------------------------------------
Registers a hook that gets triggered when a certain part of the model is updated
e.g. FProfiler.UI.onModelUpdate("realm", print) prints when the realm is changed
---------------------------------------------------------------------------]]
function FProfiler.UI.onModelUpdate(path, func)
path = istable(path) and path or {path}
local updTbl = updaters
local mdlTbl = model
local key = path[#path]
for i = 1, #path - 1 do
mdlTbl = mdlTbl[path[i]]
updTbl[path[i]] = updTbl[path[i]] or {}
updTbl = updTbl[path[i]]
end
updTbl[key] = updTbl[key] or {}
table.insert(updTbl[key], func)
-- Call update with the initial value
if mdlTbl[key] ~= nil then
func(mdlTbl[key], mdlTbl[key])
end
end
--[[-------------------------------------------------------------------------
Registers a hook to both realms
---------------------------------------------------------------------------]]
function FProfiler.UI.onCurrentRealmUpdate(path, func)
path = istable(path) and path or {path}
table.insert(path, 1, "client")
FProfiler.UI.onModelUpdate(path, function(...)
if FProfiler.UI.getModelValue("realm") == "server" then return end
func(...)
end)
path[1] = "server"
FProfiler.UI.onModelUpdate(path, function(...)
if FProfiler.UI.getModelValue("realm") == "client" then return end
func(...)
end)
end
--[[-------------------------------------------------------------------------
When the realm is changed, all update functions of the new realm are to be called
---------------------------------------------------------------------------]]
FProfiler.UI.onModelUpdate("realm", function(new, old)
if not updaters[new] then return end
for k, funcTbl in pairs(updaters[new]) do
for _, func in ipairs(funcTbl) do
func(model[new][k], model[new][k])
end
end
end)

View File

@@ -1,305 +0,0 @@
--[[
| 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/
--]]
--[[-------------------------------------------------------------------------
The server is involved in the ui in the sense that it interacts with its model
---------------------------------------------------------------------------]]
-- Net messages
util.AddNetworkString("FProfile_startProfiling")
util.AddNetworkString("FProfile_stopProfiling")
util.AddNetworkString("FProfile_focusObj")
util.AddNetworkString("FProfile_getSource")
util.AddNetworkString("FProfile_printFunction")
util.AddNetworkString("FProfile_fullModelUpdate")
util.AddNetworkString("FProfile_focusUpdate")
util.AddNetworkString("FProfile_unsubscribe")
--[[-------------------------------------------------------------------------
Simplified version of the model
Contains only what the server needs to know
---------------------------------------------------------------------------]]
local model =
{
focusObj = nil, -- the function currently in focus
sessionStart = nil, -- When the last profiling session was started. Used for the live timer.
sessionStartSysTime = nil, -- Same as sessionStart, but measured in SysTime. Used to update recordTime
recordTime = 0, -- Total time spent on the last full profiling session
bottlenecks = {}, -- The list of bottleneck functions
topLagSpikes = {}, -- Top of lagging functions
subscribers = RecipientFilter(), -- The players that get updates of the profiler model
}
--[[-------------------------------------------------------------------------
Helper function: receive a net message
---------------------------------------------------------------------------]]
local function receive(msg, f)
net.Receive(msg, function(len, ply)
-- Check access.
CAMI.PlayerHasAccess(ply, "FProfiler", function(b, _)
if not b then return end
f(len, ply)
end)
end)
end
--[[-------------------------------------------------------------------------
Helper function:
Write generic row data to a net message
---------------------------------------------------------------------------]]
local function writeRowData(row)
net.WriteString(tostring(row.func))
net.WriteString(row.info.short_src)
net.WriteUInt(row.info.linedefined, 16)
net.WriteUInt(row.info.lastlinedefined, 16)
end
--[[-------------------------------------------------------------------------
Helper function:
Send the bottlenecks to the client
Only sends the things displayed
---------------------------------------------------------------------------]]
local function writeBottleNecks()
net.WriteUInt(#model.bottlenecks, 16)
for i, row in ipairs(model.bottlenecks) do
writeRowData(row)
net.WriteUInt(#row.names, 8)
for j, name in ipairs(row.names) do
net.WriteString(name.name)
net.WriteString(name.namewhat)
end
net.WriteUInt(row.total_called, 32)
net.WriteDouble(row.total_time)
net.WriteDouble(row.average_time)
end
end
--[[-------------------------------------------------------------------------
Helper function:
Sends the top n functions
---------------------------------------------------------------------------]]
local function writeTopN()
local count = #model.topLagSpikes
-- All top N f
for i = count, 0, -1 do
if model.topLagSpikes and model.topLagSpikes[i] and model.topLagSpikes[i].info then break end -- Entry exists
count = i
end
net.WriteUInt(count, 8)
for i = 1, count do
local row = model.topLagSpikes[i]
if not row.info then break end
writeRowData(row)
net.WriteString(row.info.name or "")
net.WriteString(row.info.namewhat or "")
net.WriteDouble(row.runtime)
end
end
-- Start profiling
local function startProfiling()
model.sessionStart = CurTime()
model.sessionStartSysTime = SysTime()
FProfiler.Internal.start(model.focusObj)
net.Start("FProfile_startProfiling")
net.WriteDouble(model.recordTime)
net.WriteDouble(model.sessionStart)
net.Send(model.subscribers:GetPlayers())
end
-- Stop profiling
local function stopProfiling()
FProfiler.Internal.stop()
model.recordTime = model.recordTime + SysTime() - (model.sessionStartSysTime or 0)
model.sessionStart = nil
model.sessionStartSysTime = nil
model.bottlenecks = FProfiler.Internal.getAggregatedResults(100)
model.topLagSpikes = FProfiler.Internal.getMostExpensiveSingleCalls()
net.Start("FProfile_stopProfiling")
net.WriteDouble(model.recordTime)
writeBottleNecks()
writeTopN()
net.Send(model.subscribers:GetPlayers())
end
--[[-------------------------------------------------------------------------
Receive an update of the function to focus on
---------------------------------------------------------------------------]]
receive("FProfile_focusObj", function(_, ply)
local funcStr = net.ReadString()
model.focusObj = FProfiler.funcNameToObj(funcStr)
net.Start("FProfile_focusObj")
net.WriteBool(model.focusObj and true or false)
net.Send(ply)
-- Send a focus update to all other players
net.Start("FProfile_focusUpdate")
net.WriteString(funcStr)
net.WriteBool(model.focusObj and true or false)
model.subscribers:RemovePlayer(ply)
net.Send(model.subscribers:GetPlayers())
model.subscribers:AddPlayer(ply)
end)
--[[-------------------------------------------------------------------------
Receive a "start profiling" signal
---------------------------------------------------------------------------]]
receive("FProfile_startProfiling", function(_, ply)
local shouldReset = net.ReadBool()
if shouldReset then
FProfiler.Internal.reset()
model.recordTime = 0
end
startProfiling()
end)
--[[-------------------------------------------------------------------------
Receive a stop profiling signal
---------------------------------------------------------------------------]]
receive("FProfile_stopProfiling", function(_, ply)
stopProfiling()
end)
--[[-------------------------------------------------------------------------
Send the source of a function to a client
---------------------------------------------------------------------------]]
receive("FProfile_getSource", function(_, ply)
local func = FProfiler.funcNameToObj(net.ReadString())
if not func then return end
local info = debug.getinfo(func)
if not info then return end
net.Start("FProfile_getSource")
net.WriteString(FProfiler.readSource(info.short_src, info.linedefined, info.lastlinedefined) or "")
net.Send(ply)
end)
--[[-------------------------------------------------------------------------
Print the details of a function
---------------------------------------------------------------------------]]
receive("FProfile_printFunction", function(_, ply)
local source = net.ReadBool() -- true is from bottlenecks, false is from Top-N
local dataSource = source and model.bottlenecks or model.topLagSpikes
local func = net.ReadString()
local data
for _, row in ipairs(dataSource or {}) do
if tostring(row.func) == func then data = row break end
end
if not data then return end
-- Show the data
show(data)
local plaintext = showStr(data)
-- Write to file if necessary
file.CreateDir("fprofiler")
file.Write("fprofiler/profiledata.txt", plaintext)
MsgC(Color(200, 200, 200), "-----", Color(120, 120, 255), "NOTE", Color(200, 200, 200), "---------------\n")
MsgC(Color(200, 200, 200), "If the above function does not fit in console, you can find it in data/fprofiler/profiledata.txt\n\n")
-- Listen server hosts already see the server console
if ply:IsListenServerHost() then return end
-- Send a plaintext version to the client
local binary = util.Compress(plaintext)
net.Start("FProfile_printFunction")
net.WriteData(binary, #binary)
net.Send(ply)
end)
--[[-------------------------------------------------------------------------
Request of a full model update
Particularly useful when someone else has done (or is performing) a profiling session
and the current player wants to see the results
---------------------------------------------------------------------------]]
receive("FProfile_fullModelUpdate", function(_, ply)
-- This player is now subscribed to the updates
model.subscribers:AddPlayer(ply)
net.Start("FProfile_fullModelUpdate")
net.WriteBool(model.focusObj ~= nil)
if model.focusObj ~= nil then net.WriteString(tostring(model.focusObj)) end
-- Bool also indicates whether it's currently profiling
net.WriteBool(model.sessionStart ~= nil)
if model.sessionStart ~= nil then net.WriteDouble(model.sessionStart) end
net.WriteDouble(model.recordTime)
writeBottleNecks()
writeTopN()
net.Send(ply)
end)
--[[-------------------------------------------------------------------------
Unsubscribe from the updates of the profiler
---------------------------------------------------------------------------]]
receive("FProfile_unsubscribe", function(_, ply)
model.subscribers:RemovePlayer(ply)
end)
--[[-------------------------------------------------------------------------
API function: start profiling
---------------------------------------------------------------------------]]
function FProfiler.start(focus)
FProfiler.Internal.reset()
model.recordTime = 0
model.focusObj = focus
startProfiling()
end
--[[-------------------------------------------------------------------------
API function: stop profiling
---------------------------------------------------------------------------]]
function FProfiler.stop()
stopProfiling()
end
--[[-------------------------------------------------------------------------
API function: continue profiling
---------------------------------------------------------------------------]]
function FProfiler.continueProfiling()
startProfiling()
end

View File

@@ -1,238 +0,0 @@
--[[
| 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 get, update, onUpdate = FProfiler.UI.getModelValue, FProfiler.UI.updateModel, FProfiler.UI.onModelUpdate
--[[-------------------------------------------------------------------------
Update the current selected focus object when data is entered
---------------------------------------------------------------------------]]
onUpdate({"server", "focusStr"}, function(new)
if not new or get({"server", "fromServer"}) then return end
net.Start("FProfile_focusObj")
net.WriteString(new)
net.SendToServer()
end)
net.Receive("FProfile_focusObj", function()
update({"server", "focusObj"}, net.ReadBool() and get({"server", "focusStr"}) or nil)
end)
-- A focus update occurs when someone else changes the focus
net.Receive("FProfile_focusUpdate", function()
update({"server", "fromServer"}, true)
local focusStr = net.ReadString()
update({"server", "focusStr"}, focusStr)
update({"server", "focusObj"}, net.ReadBool() and focusStr or nil)
update({"server", "fromServer"}, false)
end)
--[[-------------------------------------------------------------------------
(Re)start profiling
---------------------------------------------------------------------------]]
local function restartProfiling()
local shouldReset = get({"server", "shouldReset"})
net.Start("FProfile_startProfiling")
net.WriteBool(shouldReset)
net.SendToServer()
end
net.Receive("FProfile_startProfiling", function()
update({"server", "fromServer"}, true)
update({"server", "status"}, "Started")
update({"server", "recordTime"}, net.ReadDouble())
update({"server", "sessionStart"}, net.ReadDouble())
update({"server", "fromServer"}, false)
end)
--[[-------------------------------------------------------------------------
Stop profiling
---------------------------------------------------------------------------]]
local function stopProfiling()
net.Start("FProfile_stopProfiling")
net.SendToServer()
end
-- Read a row from a net message
local function readDataRow(countSize, readSpecific)
local res = {}
local count = net.ReadUInt(countSize)
for i = 1, count do
local row = {}
row.info = {}
row.func = net.ReadString()
row.info.short_src = net.ReadString()
row.info.linedefined = net.ReadUInt(16)
row.info.lastlinedefined = net.ReadUInt(16)
readSpecific(row)
table.insert(res, row)
end
return res
end
-- Read a bottleneck row
local function readBottleneckRow(row)
local nameCount = net.ReadUInt(8)
row.names = {}
for i = 1, nameCount do
table.insert(row.names, {
name = net.ReadString(),
namewhat = net.ReadString()
})
end
row.total_called = net.ReadUInt(32)
row.total_time = net.ReadDouble()
row.average_time = net.ReadDouble()
end
-- Read the top n row
local function readTopNRow(row)
row.info.name = net.ReadString()
row.info.namewhat = net.ReadString()
row.runtime = net.ReadDouble()
end
net.Receive("FProfile_stopProfiling", function()
update({"server", "fromServer"}, true)
update({"server", "status"}, "Stopped")
update({"server", "sessionStart"}, nil)
update({"server", "recordTime"}, net.ReadDouble())
update({"server", "bottlenecks"}, readDataRow(16, readBottleneckRow))
update({"server", "topLagSpikes"}, readDataRow(8, readTopNRow))
update({"server", "fromServer"}, false)
end)
--[[-------------------------------------------------------------------------
Start/stop recording when the recording status is changed
---------------------------------------------------------------------------]]
onUpdate({"server", "status"}, function(new, old)
if new == old or get({"server", "fromServer"}) then return end
(new == "Started" and restartProfiling or stopProfiling)()
end)
--[[-------------------------------------------------------------------------
Update info when a different line is selected
---------------------------------------------------------------------------]]
onUpdate({"server", "currentSelected"}, function(new)
if not new or not new.info or not new.info.linedefined or not new.info.lastlinedefined or not new.info.short_src then return end
net.Start("FProfile_getSource")
net.WriteString(tostring(new.func))
net.SendToServer()
end)
net.Receive("FProfile_getSource", function()
update({"server", "sourceText"}, net.ReadString())
end)
--[[-------------------------------------------------------------------------
When a function is to be printed to console
---------------------------------------------------------------------------]]
onUpdate({"server", "toConsole"}, function(data)
if not data then return end
update({"server", "toConsole"}, nil)
net.Start("FProfile_printFunction")
net.WriteBool(data.total_called and true or false) -- true for bottleneck function, false for top-n function
net.WriteString(tostring(data.func))
net.SendToServer()
end)
net.Receive("FProfile_printFunction", function(len)
local data = net.ReadData(len)
local decompressed = util.Decompress(data)
-- Print the text line by line, otherwise big parts of big data will not be printed
local split = string.Explode("\n", decompressed, false)
for _, line in ipairs(split) do
MsgN(line)
end
-- Write the thing to a file
file.CreateDir("fprofiler")
file.Write("fprofiler/profiledata.txt", showStr(data))
MsgC(Color(200, 200, 200), "-----", Color(120, 120, 255), "NOTE", Color(200, 200, 200), "---------------\n")
MsgC(Color(200, 200, 200), "In the server's console you can find a colour coded version of the above output.\nIf the above function does not fit in console, you can find it in data/fprofiler/profiledata.txt\n\n")
end)
--[[-------------------------------------------------------------------------
Check access when the frame opens
Also request a full serverside model update
---------------------------------------------------------------------------]]
onUpdate("frameVisible", function(isOpen)
-- Don't network if the server doesn't have FProfiler installed
if util.NetworkStringToID("FProfile_fullModelUpdate") == 0 then
update("serverAccess", false)
return
end
-- Update access
CAMI.PlayerHasAccess(LocalPlayer(), "FProfiler", function(b, _)
update("serverAccess", b)
end)
if not isOpen then
net.Start("FProfile_unsubscribe")
net.SendToServer()
return
end
net.Start("FProfile_fullModelUpdate")
net.SendToServer()
end)
net.Receive("FProfile_fullModelUpdate", function()
update({"server", "fromServer"}, true)
local focusExists = net.ReadBool()
if focusExists then
local focus = net.ReadString()
update({"server", "focusObj"}, focus)
update({"server", "focusStr"}, focus)
end
local startingTimeExists = net.ReadBool()
if startingTimeExists then
update({"server", "status"}, "Started")
update({"server", "sessionStart"}, net.ReadDouble())
else
update({"server", "status"}, "Stopped")
end
update({"server", "recordTime"}, net.ReadDouble())
update({"server", "bottlenecks"}, readDataRow(16, readBottleneckRow))
update({"server", "topLagSpikes"}, readDataRow(8, readTopNRow))
update({"server", "fromServer"}, false)
end)

View File

@@ -1,52 +0,0 @@
--[[
| 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/
--]]
-- Try to find the function represented by a string
function FProfiler.funcNameToObj(str)
if isfunction(str) then return str end
local times = FProfiler.Internal.getCallCounts()
for func, _ in pairs(times) do
if tostring(func) == str then return func end
end
local tbl = _G
local exploded = string.Explode(".", str, false)
if not exploded or not exploded[1] then return end
for i = 1, #exploded - 1 do
tbl = (tbl or {})[exploded[i]]
if not istable(tbl) then return end
end
local func = (tbl or {})[exploded[#exploded]]
if not isfunction(func) then return end
return func
end
-- Read a file
function FProfiler.readSource(fname, startLine, endLine)
if not file.Exists(fname, "GAME") then return "" end
if startLine < 0 or endLine < 0 or endLine < startLine then return "" end
local f = file.Open(fname, "r", "GAME")
for i = 1, startLine - 1 do f:ReadLine() end
local res = {}
for i = startLine, endLine do
table.insert(res, f:ReadLine() or "")
end
return table.concat(res, "\n")
end

View File

@@ -1,4 +0,0 @@
Plugin
{
file "lua/bin/gmsv_gluapack_plugin.so"
}

View File

@@ -25,15 +25,15 @@ return {
--
-- MySQL username
--
Username = "u1_IvQVCXwwft",
Username = "u21_kMfX6eETLo",
--
-- MySQL password
--
Password = "!@eQG1EP8mTaT3MlbqvTrSmt",
Password = "dbTxNjjcV=b=^swsHDuHTy+M",
--
-- MySQL database
--
Database = "s1_sam_dev",
}
Database = "s21_sam_french",
}

View File

@@ -1,11 +0,0 @@
--[[
| 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/
--]]
resource.AddSingleFile("sound/grove.ogg")

View File

@@ -1,89 +0,0 @@
--[[
| 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 groove = StormFox2.Weather.Add( "Groove" )
-- Name and Symbol
function groove:GetName(nTime, nTemp, nWind, bThunder, nFraction )
return "Groove"
end
local m_def = Material("stormfox2/hud/w_cloudy_night.png")
function groove.GetSymbol( nTime ) -- What the menu should show
return m_def
end
function groove.GetIcon( nTime, nTemp, nWind, bThunder, nFraction) -- What symbol the weather should show
return m_def
end
if CLIENT then -- Music
local music = StormFox2.Ambience.CreateAmbienceSnd( "grove.ogg", SF_AMB_OUTSIDE, 1 )
groove:AddAmbience( music )
-- Particles
local m = Material("effects/fluttercore_gmod")
local boogie = StormFox2.DownFall.CreateTemplate(m, true)
boogie:SetRandomAngle(0.2)
boogie:SetSpeed(0.1)
function boogie:OnHit( vPos, vNormal, nHitType, zPart )
if math.random(3) > 1 then return end -- 33% chance to spawn a splash
local dlight = DynamicLight(math.random(32, 20))
if ( dlight ) then
dlight.pos = vPos
local c = zPart:GetColor()
dlight.r = c.r
dlight.g = c.g
dlight.b = c.b
dlight.brightness = 2
dlight.Decay = 1000
dlight.Size = math.random(1, 3) * 256
dlight.DieTime = CurTime() + 1
end
end
local boogie2 = StormFox2.DownFall.CreateTemplate(m)
boogie2:SetSpeed(0.1)
function groove.Think()
for _,v in ipairs( StormFox2.DownFall.SmartTemplate( boogie, 10, 700, 900, 5, vNorm ) or {} ) do
local s = math.random(2, 5)
v:SetSize( s,s )
v:SetColor( HSVToColor(math.random(360), 1,1) )
v:SetSpeed(math.Rand(0.1,0.3))
end
for _,v in ipairs( StormFox2.DownFall.SmartTemplate(boogie2, 10, 1200, 50, 5, vNorm) or {} ) do
local s = math.random(2, 5)
v:SetSize( s, s * 0.4 )
v:SetRoll( math.random(360) )
v:SetColor( HSVToColor(math.random(360), 1,1) )
v:SetSpeed(math.Rand(0.1,0.3))
end
end
end
if SERVER then return end
local wallp = {}
local function GetWallpapers()
return wallp
end
local function LoadWallpapers( steamid64 )
http.Fetch("https://steamcommunity.com/inventory/" .. steamid64 .. "/753/6", function(code)
if not code then return end
local t = util.JSONToTable(code)
if not t then return end
wallp = {} -- empty
for k, v in ipairs(t.descriptions or {}) do
if not v.actions or not v.actions[1] then continue end
if not v.actions[1].link then continue end
if not string.match(v.actions[1].link, "%.jpg$") and not string.match(v.actions[1].link, "%.png$") then print(v.actions[1].link) continue end
wallp[v.name] = v.actions[1].link
end
end)
end
LoadWallpapers("76561198009860285")

View File

@@ -1 +0,0 @@
OggS

View File

@@ -1 +0,0 @@
- Add delay for player refresh after group change

View File

@@ -1,339 +0,0 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

View File

@@ -1,27 +0,0 @@
**IMPORTANT:** ONLY DOWNLOAD THIS ADDON ON THE RELEASES PAGE: https://github.com/matbyte-com/vyhub-gmod/releases
# vyhub-gmod: Garry's Mod Community-Management / Donation-System
This is the [VyHub](https://vyhub.net) addon for Garry's Mod.
## Features
- :shopping_cart: Shop / donation system -> sell items on your gameserver for real money
- :no_entry_sign: Bans
- :warning: Warnings
- :framed_picture: Ingame dashboard of bans and warnings
- :repeat: Synchronize player groups with admin mods
- :chart_with_upwards_trend: Playtime statistics
- :loudspeaker: Periodic adverts
Create your account for free on our [website](https://vyhub.net).
The documentation can be found [here](https://docs.vyhub.net/latest/game/gmod/).
## Supported Admin Mods
- ULX
- SAM
- xAdmin 1 & 2
- FAdmin
- sAdmin
- ServerGuard

View File

@@ -1,12 +0,0 @@
{
"title": "VyHub GMOD",
"description": "",
"type": "servercontent",
"tags": [
"fun"
],
"ignore": [
".git/*",
"README.md"
]
}

View File

@@ -1,174 +0,0 @@
--[[
| 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 f = string.format
VyHub = VyHub or {}
VyHub.Config = VyHub.Config or {}
VyHub.Lib = VyHub.Lib or {}
VyHub.ready = false
local vyhub_root = "vyhub"
local color_warn = Color(211, 120, 0)
local color_err = Color(255, 0, 0)
local color_green = Color(0, 255, 0)
function VyHub:msg(message, type)
type = type or "neutral"
// Remove color tags
message = string.gsub(message, "<([%l]+)>([^<]+)</%1>", "%2")
if type == "success" then
MsgC("[VyHub] ", color_green, message .. "\n")
elseif type == "error" then
MsgC("[VyHub] [ERROR] ", color_err, message .. "\n")
elseif type == "neutral" then
MsgC("[VyHub] ", color_white, message .. "\n")
elseif type == "warning" then
MsgC("[VyHub] [WARN] ", color_warn, message .. "\n")
elseif type == "debug" and VyHub.Config.debug then
MsgC("[VyHub] [Debug] ", color_white, message .. "\n")
end
end
VyHub:msg("Initializing...")
if SERVER then
addon_incomplete = false
if file.Exists( vyhub_root .. '/lang/en.json', "LUA") then
if file.Exists( vyhub_root .. '/config/sv_config.lua', "LUA") then
hook.Run("vyhub_loading_start")
-- libs
VyHub:msg("Loading lib files...")
local files = file.Find( vyhub_root .."/lib/*.lua", "LUA" )
for _, file in ipairs( files ) do
AddCSLuaFile( vyhub_root .. "/lib/" .. file )
include( vyhub_root .. "/lib/" .. file )
end
-- Shared Config
include( vyhub_root .. '/config/sh_config.lua' )
AddCSLuaFile( vyhub_root .. "/config/sh_config.lua" )
-- Language
VyHub:msg('Loading ' .. VyHub.Config.lang .. ' language...')
include( vyhub_root .. '/shared/sh_lang.lua' )
-- Config Files
VyHub:msg("Loading config files...")
include( vyhub_root .. '/config/sv_config.lua' )
-- Shared Files
VyHub:msg("Loading shared files...")
local files = file.Find( vyhub_root .."/shared/*.lua", "LUA" )
for _, file in ipairs( files ) do
AddCSLuaFile( vyhub_root .. "/shared/" .. file )
include( vyhub_root .. "/shared/" .. file )
end
-- Client Files
VyHub:msg("Loading client files...")
local files = file.Find( vyhub_root .."/client/*.lua", "LUA" )
for _, file in ipairs( files ) do
AddCSLuaFile( vyhub_root .."/client/" .. file )
end
-- Server Files
VyHub:msg("Loading server files...")
local files = file.Find( vyhub_root .. "/server/*.lua", "LUA" )
for _, file in ipairs( files ) do
include( vyhub_root .. "/server/" .. file )
end
game.ConsoleCommand("sv_hibernate_think 1\n")
file.CreateDir("vyhub")
VyHub.Config:load_cache_config()
timer.Simple(2, function()
hook.Run("vyhub_loading_finish")
end)
VyHub:msg("Finished loading!")
else
VyHub:msg("Could not find lua/vyhub/config/sv_config.lua. Please make sure it exists.", "error")
end
else
VyHub:msg("!!!", "error")
VyHub:msg("!!!", "error")
VyHub:msg("!!!", "error")
VyHub:msg("Could not find language files!!! Please make sure to download a correct vyhub-gmod release here: https://github.com/matbyte-com/vyhub-gmod/releases", "error")
VyHub:msg("Cannot proceed with initialization.", "error")
VyHub:msg("!!!", "error")
VyHub:msg("!!!", "error")
VyHub:msg("!!!", "error")
end
end
if CLIENT then
if file.Exists( vyhub_root .. '/shared/sh_lang.lua', "LUA") then
hook.Run("vyhub_loading_start")
-- libs
VyHub:msg("Loading lib files...")
local files = file.Find( vyhub_root .."/lib/*.lua", "LUA" )
for _, file in ipairs( files ) do
include( vyhub_root .. "/lib/" .. file )
end
-- Language
VyHub:msg('Loading language...')
include( vyhub_root .. '/shared/sh_lang.lua' )
-- Config Files
VyHub:msg("Loading config files...")
local files = file.Find( vyhub_root .."/config/*.lua", "LUA" )
for _, file in ipairs( files ) do
if not string.StartWith(file, 'sv_') then
include( vyhub_root .. "/config/" .. file )
end
end
-- Shared Files
VyHub:msg("Loading shared files...")
local files = file.Find( vyhub_root .."/shared/*.lua", "LUA" )
for _, file in ipairs( files ) do
include( vyhub_root .. "/shared/" .. file )
end
-- Client Files
VyHub:msg("Loading client files...")
local files = file.Find( vyhub_root .."/client/*.lua", "LUA" )
for _, file in ipairs( files ) do
include( vyhub_root .."/client/" .. file )
end
timer.Simple(2, function()
hook.Run("vyhub_loading_finish")
end)
VyHub:msg("Finished loading!")
else
VyHub:msg("!!!", "error")
VyHub:msg("!!!", "error")
VyHub:msg("!!!", "error")
VyHub:msg("VyHub not correctly loaded. Please check the server log.", "error")
VyHub:msg("!!!", "error")
VyHub:msg("!!!", "error")
VyHub:msg("!!!", "error")
end
end

View File

@@ -1,34 +0,0 @@
--[[
| 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 f = string.format
local color_red = Color(255, 0, 0)
if VyHub.Config.chat_tags and not DarkRP then
hook.Add("OnPlayerChat", "vyhub_chattag_OnPlayerChat", function(ply, msg)
if IsValid(ply) then
local group = VyHub.Group:get(ply:GetUserGroup())
if group then
local teamcolor = team.GetColor(ply:Team())
local deadTag = ""
if not ply:Alive() then
deadTag = f("*%s* ", VyHub.lang.other.dead)
end
chat.AddText(VyHub.Util:hex2rgb(group.color), "[", group.name, "]", " ", color_red, deadTag, teamcolor, ply:Nick(), color_white, ": ", msg)
return true
end
end
end)
end

View File

@@ -1,532 +0,0 @@
--[[
| 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 f = string.format
VyHub.Dashboard = VyHub.Dashboard or {}
VyHub.Dashboard.ui = VyHub.Dashboard.ui or nil
VyHub.Dashboard.html_ready = false
VyHub.Dashboard.html_generated = VyHub.Dashboard.html_generated or false
local dashboard_html = dashboard_html or "Loading, please try again. If this does not help, please ask the server owner to check for errors in the server console. In most cases, vyhub-gmod has not been downloaded correctly and is missing files."
function VyHub.Dashboard:create_ui()
VyHub.Dashboard.html_ready = false
local xsize = ScrW() - ScrW()/4
local ysize = ScrH() - ScrH()/4
local xpos = ScrW()/2 - xsize/2
local ypos = ScrH()/2 - ysize/2
local title = "VyHub Server-Dashboard"
local box_color = Color(94, 0, 0, 255)
VyHub.Dashboard.ui = vgui.Create("DFrame")
VyHub.Dashboard.ui:SetSize(xsize, ysize)
VyHub.Dashboard.ui:SetPos(xpos, ypos)
VyHub.Dashboard.ui:SetDraggable(true)
VyHub.Dashboard.ui:SetTitle(title)
VyHub.Dashboard.ui:SetDeleteOnClose(false)
function VyHub.Dashboard.ui.Paint(self, w, h)
surface.SetDrawColor(box_color)
surface.DrawRect(0, 0, w, 24)
end
VyHub.Dashboard.ui_html = vgui.Create("DHTML", VyHub.Dashboard.ui)
VyHub.Dashboard.ui_html:SetSize(xsize, ysize - 24)
VyHub.Dashboard.ui_html:SetPos(0, 24)
VyHub.Dashboard.ui_html:SetHTML(dashboard_html)
function VyHub.Dashboard.ui_html:OnDocumentReady()
MsgN("VyHub Dashboard: HTML Loaded")
VyHub.Dashboard.html_ready = true
VyHub.Dashboard.ui_html:RunJavascript('local_steamid64 = ' .. LocalPlayer():SteamID64())
end
VyHub.Dashboard.ui_html:AddFunction("vyhub", "warning_toggle", function (warning_id)
LocalPlayer():ConCommand(f("vh_warning_toggle %s", warning_id))
end)
VyHub.Dashboard.ui_html:AddFunction("vyhub", "warning_delete", function (warning_id)
LocalPlayer():ConCommand(f("vh_warning_delete %s", warning_id))
end)
VyHub.Dashboard.ui_html:AddFunction("vyhub", "ban_set_status", function (ban_id, status)
LocalPlayer():ConCommand(f("vh_ban_set_status %s %s", ban_id, status))
end)
VyHub.Dashboard.ui_html:AddFunction("vyhub", "warning_create", function (steamid, reason)
LocalPlayer():ConCommand(f('vh_warn %s "%s"', steamid, VyHub.Util:escape_concommand_str(reason)))
end)
VyHub.Dashboard.ui_html:AddFunction("vyhub", "ban_create", function (steamid, minutes, reason)
LocalPlayer():ConCommand(f('vh_ban %s "%s" "%s"', steamid, minutes, VyHub.Util:escape_concommand_str(reason)))
end)
end
function VyHub.Dashboard:load_html()
VyHub.Dashboard.html_generated = true
dashboard_html = [[
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="http://cdn.vyhub.net/assets/roboto-v30-latin/roboto-v30-latin.css">
<link rel="stylesheet" href="http://cdn.vyhub.net/assets/font-awesome-4.7.0/css/font-awesome.min.css">
<link rel="stylesheet" href="http://cdn.vyhub.net/assets/bootswatch-darkly.min.css">
<style>
::selection {
background: #b5b5b5; /* WebKit/Blink Browsers */
}
body{
overflow-x: hidden;
overflow-y: scroll;
font-family: Roboto !important;
}
.vh-input {
background-color: #303030;
color: white;
height: 30px;
}
.nav-pills .active {
background-color: #303030;
font-weight: bold;
margin-left: 4px;
}
.user-tab {
padding: 3px 6px 3px 6px;
border-radius: 8px;
text-overflow: ellipsis;
overflow:hidden;
}
#user_name {
width: 50%;
text-overflow: ellipsis;
overflow: hidden;
}
</style>
</head>
<body>
<div class="row" style="margin: 10px">
<div class="col-xs-4 col-lg-3">
<div class="input-group">
<div class="input-group-addon"><i class="fa fa-search"></i></div>
<input style="height: 40px;" id="user_search" type="text" class="form-control vh-input" onclick="$('#user_search').val(''); generate_user_list();" onkeyup="generate_user_list()" >
</div>
<br/>
<ul class="nav nav-pills nav-stacked" id="user_list">
</ul>
</div>
<div class="col-xs-8 col-lg-9">
<div id="user_content_empty">
]] .. VyHub.lang.dashboard.select_user .. [[
</div>
<div class="tab-content" id="user_content" style="display: none;">
<h3 style="margin: 5px 0px 0px 0;">
<div class="row">
<div class="col-xs-9">
<span id="user_name">
<span class="label label-default" style="background-color: #5E0000; border-radius: .25em 0 0 .25em;">
<i class="fa fa-user"></i> &nbsp;<span id="user_content_name"></span>
</span>
<span class="label label-default" style="border-radius: 0 .25em .25em 0;">
<span id="user_content_username"></span>
</span>
</span>
</div>
<div class="col-xs-3">
<span id="user_memberships" class="pull-right">
</span>
</div>
</div>
</h3>
<hr/>
<h4><span class="label label-default"><i class="fa fa-exclamation-triangle"></i> &nbsp;]] .. VyHub.lang.other.warnings .. [[</span></h3>
<div class="row perm-warning_edit">
<div class="col-xs-10">
<input id="user_warn" type="text" class="form-control vh-input" onclick="$('#user_warn').val('');" placeholder="]] .. VyHub.lang.other.reason .. [[" />
</div>
<div class="col-xs-2" style="padding-left: 0;">
<button style="height: 30px;" onclick="create_warning()" class="btn btn-warning btn-xs btn-block"><i class="fa fa-exclamation-triangle"></i> &nbsp; ]] .. VyHub.lang.dashboard.action_warn .. [[</button>
</div>
</div>
<br/>
<table class="table table-condensed table-hover">
<tr>
<th width="10px"></th>
<th>]] .. VyHub.lang.other.reason .. [[</th>
<th>]] .. VyHub.lang.other.admin .. [[</th>
<th>]] .. VyHub.lang.other.date .. [[</th>
<th class="text-right">]] .. VyHub.lang.other.actions .. [[</th>
</tr>
<tbody id="user_content_warnings">
</tbody>
</table>
<div>
<span class="label label-success"><i class="fa fa-check"></i>&nbsp; ]] .. VyHub.lang.other.active .. [[</span>
<span class="label label-warning"><i class="fa fa-hourglass"></i>&nbsp; ]] .. VyHub.lang.other.inactive .. [[</span>
<span class="label label-default"><i class="fa fa-times"></i>&nbsp; ]] .. VyHub.lang.other.disabled .. [[</span>
</div>
<hr />
<h4><span class="label label-default"><i class="fa fa-gavel"></i> &nbsp;]] .. VyHub.lang.other.bans .. [[</span></h3>
<div class="row perm-ban_edit">
<div class="col-xs-8">
<input id="user_ban_reason" type="text" class="form-control vh-input" onclick="$('#user_ban_reason').val('');" placeholder="]] .. VyHub.lang.other.reason .. [[" />
</div>
<div class="col-xs-2" style="padding-left: 0;">
<input id="user_ban_minutes" type="text" class="form-control vh-input" onclick="$('#user_ban_minutes').val('');" placeholder="]] .. VyHub.lang.other.minutes .. [[" />
</div>
<div class="col-xs-2" style="padding-left: 0;">
<button style="height: 30px;" onclick="create_ban()" class="btn btn-danger btn-xs btn-block"><i class="fa fa-gavel"></i> &nbsp; ]] .. VyHub.lang.dashboard.action_ban .. [[</button>
</div>
</div>
<br/>
<table class="table table-condensed table-hover">
<tr>
<th width="10px"></th>
<th>]] .. VyHub.lang.other.reason .. [[</th>
<th>]] .. VyHub.lang.other.admin .. [[</th>
<th>]] .. VyHub.lang.other.date .. [[</th>
<th>]] .. VyHub.lang.other.minutes .. [[</th>
<th class="text-right">]] .. VyHub.lang.other.actions .. [[</th>
</tr>
<tbody id="user_content_bans">
</tbody>
</table>
<div>
<span class="label label-success"><i class="fa fa-check"></i>&nbsp; ]] .. VyHub.lang.other.active .. [[</span>
<span class="label label-info"><i class="fa fa-globe"></i>&nbsp; ]] .. VyHub.lang.other.active_global .. [[</span>
<span class="label label-warning"><i class="fa fa-times"></i>&nbsp; ]] .. VyHub.lang.other.unbanned .. [[</span>
<span class="label label-danger"><i class="fa fa-hourglass"></i>&nbsp; ]] .. VyHub.lang.other.inactive .. [[</span>
</div>
</div>
</div>
</div>
</body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.30.1/moment.min.js"></script>
<script>
var perms = null;
var users = [];
var users_by_id = {};
var current_user = null;
var local_steamid64 = null;
function escape(str) {
return $("<div>").text(str).html();
}
function format_date(iso_str) {
return moment(iso_str).format('YYYY-MM-DD HH:mm');
}
function load_data(new_data) {
users = new_data;
users_by_id = {};
new_data.forEach(function(user) {
users_by_id[user.id] = user;
});
generate_user_list()
}
function load_perms(new_perms) {
perms = new_perms;
}
function enforce_perms() {
if (perms == null) { return; }
Object.keys(perms).forEach(function(perm) {
var has_perm = perms[perm];
if (has_perm) {
$('.perm-' + perm).show();
} else {
$('.perm-' + perm).hide();
}
});
}
function generate_user_list() {
$('#user_list').html('');
var filter = null;
if ($('#user_search').val()) {
filter = $('#user_search').val().toLowerCase();
}
var ids = [];
var only_local_user = perms == null || (!perms.warning_show && !perms.ban_show);
users.forEach(function(user) {
var activity = user.activities[0];
if (activity == null) { return; }
if (only_local_user && user.identifier !== local_steamid64) { return; }
if (filter != null) {
if (activity.extra.Nickname.toLowerCase().indexOf(filter) == -1 && user.username.toLowerCase().indexOf(filter) == -1) {
return;
}
}
var color = 'white';
if (user.memberships.length > 0) {
color = user.memberships[0].group.color;
}
var warn_badge_color = ((user.warnings.length == 0) ? '#444' : "#f0ad4e");
var ban_badge_color = ((user.bans.length == 0) ? '#444' : "#d9534f");
$('#user_list').append(' \
<li class="user-tab" id="user_tab_' + user.id + '" onclick="generate_user_overview(\'' + user.id + '\')" style="cursor:pointer; color: ' + color + ';"> \
' + escape(activity.extra.Nickname) + ' \
<span class="badge pull-right" style="background-color: ' + ban_badge_color + ';">' + user.bans.length + ' <i class="fa fa-gavel"></i></span> \
<span class="badge pull-right" style="background-color: ' + warn_badge_color + '; margin-left: 3px; margin-right: 3px;">' + user.warnings.length + ' <i class="fa fa-exclamation-triangle"></i></span> \
</li> \
');
ids.push(user.id);
});
if (ids.length == 1) {
generate_user_overview(ids[0]);
} else if (ids.length == 0) {
$('#user_content_empty').show();
$('#user_content').hide();
}
}
function generate_user_overview(user_id) {
current_user = null;
$('#user_content_empty').hide();
$('#user_content').hide();
var user = users_by_id[user_id];
if (user == null) { return; }
var activity = user.activities[0];
if (activity == null) { return; }
current_user = user;
$('#user_content_name').text(activity.extra.Nickname);
$('#user_content_username').text(user.username);
if (activity.extra.Nickname === user.username) {
$('#user_content_username').hide();
} else {
$('#user_content_username').show();
}
$('.user-tab').removeClass("active");
$('#user_tab_' + user_id).addClass("active");
$('#user_content_warnings').html('');
user.warnings.forEach(function(warning) {
var row_class = "success";
if (warning.disabled) {
row_class = "active";
} else if (!warning.active) {
row_class = "warning";
}
$('#user_content_warnings').append(' \
<tr> \
<td class="' + row_class + '"></td> \
<td>' + escape(warning.reason) + '</td> \
<td>' + escape(warning.creator.username) + '</td> \
<td>' + format_date(warning.created_on) + '</td> \
<td class="text-right"> \
<button class="btn btn-default btn-xs perm-warning_edit" onclick="vyhub.warning_toggle(\'' + warning.id + '\')"><i class="fa fa-play"></i><i class="fa fa-pause"></i></button> \
<button class="btn btn-default btn-xs perm-warning_delete" onclick="vyhub.warning_delete(\'' + warning.id + '\')"><i class="fa fa-trash"></i></button> \
</td> \
</tr> \
');
});
$('#user_content_bans').html('');
user.bans.forEach(function(ban) {
var minutes = '∞';
if (ban.length != null) {
minutes = Math.round(ban.length/60);
}
var row_class = "success";
if (ban.status == "UNBANNED") {
row_class = "warning";
} else if (!ban.active) {
row_class = "danger";
} else if (ban.serverbundle == null) {
row_class = "info";
}
var actions = "";
if (ban.status == "ACTIVE") {
actions += '<button class="btn btn-default btn-xs perm-ban_edit" onclick="vyhub.ban_set_status(\'' + ban.id + '\', \'UNBANNED\')"><i class="fa fa-check"></i> &nbsp;]] .. VyHub.lang.other.unban .. [[</button>';
} else if (ban.status == "UNBANNED") {
actions += '<button class="btn btn-default btn-xs perm-ban_edit" onclick="vyhub.ban_set_status(\'' + ban.id + '\', \'ACTIVE\')"><i class="fa fa-gavel"></i> &nbsp;]] .. VyHub.lang.other.reban .. [[</button>';
}
$('#user_content_bans').append(' \
<tr> \
<td class="' + row_class + '"></td> \
<td>' + escape(ban.reason) + '</td> \
<td>' + escape(ban.creator.username) + '</td> \
<td>' + format_date(ban.created_on) + '</td> \
<td>' + minutes + '</td> \
<td class="text-right">' + actions + '</td> \
</tr> \
');
});
$('#user_memberships').html('');
user.memberships.forEach(function(membership) {
$('#user_memberships').append('<span class="label label-default" style="background-color: ' + membership.group.color + ';">' + membership.group.name + '</span>');
});
$('#user_content').show();
enforce_perms();
}
function reload_current_user() {
if (current_user != null) {
generate_user_overview(current_user.id);
}
}
function create_warning() {
if (current_user == null) {
return;
}
var reason = $('#user_warn').val();
vyhub.warning_create(current_user.identifier, reason);
$('#user_warn').val('');
}
function create_ban() {
if (current_user == null) {
return;
}
var reason = $('#user_ban_reason').val();
var minutes = $('#user_ban_minutes').val();
vyhub.ban_create(current_user.identifier, minutes, reason);
$('#user_ban_reason').val('');
$('#user_ban_minutes').val('');
}
</script>
</html>
]]
end
function VyHub.Dashboard:load_users(users_json)
VyHub.Dashboard.ui_html:RunJavascript("load_data(" .. users_json .. ");")
VyHub.Dashboard.ui_html:RunJavascript("reload_current_user();")
end
function VyHub.Dashboard:load_perms(perms_json)
VyHub.Dashboard.ui_html:RunJavascript("load_perms(" .. perms_json .. ");")
end
concommand.Add("vh_dashboard", function ()
if VyHub.Dashboard.ui == nil or not VyHub.Dashboard.ui:IsValid() then
VyHub.Dashboard:create_ui()
VyHub.Dashboard.ui:Show()
VyHub.Dashboard.ui:MakePopup()
else
-- VyHub.Dashboard:create_ui()
-- if VyHub.Dashboard.ui != nil and VyHub.Dashboard.ui:IsValid() and VyHub.Dashboard.ui:IsVisible() then
-- VyHub.Dashboard.ui:Hide()
-- else
VyHub.Dashboard.ui:Show()
VyHub.Dashboard.ui:MakePopup()
-- end
end
net.Start("vyhub_dashboard")
net.SendToServer()
end)
net.Receive("vyhub_dashboard", function()
local data_length = net.ReadUInt(16)
local data_raw = net.ReadData(data_length)
local perms_json = net.ReadString()
local users_json = util.Decompress(data_raw)
timer.Create("vyhub_dashboard_html_ready", 0.3, 20, function ()
if not VyHub.Dashboard.html_ready then
MsgN("VyHub Dashboard: Waiting for HTML to load.")
return
end
timer.Remove("vyhub_dashboard_html_ready")
VyHub.Dashboard:load_perms(perms_json)
VyHub.Dashboard:load_users(users_json)
end)
end)
net.Receive("vyhub_dashboard_reload", function()
if VyHub.Dashboard.ui and VyHub.Dashboard.ui:IsVisible() then
MsgN("Reloading dashboard data, because server told us.")
net.Start("vyhub_dashboard")
net.SendToServer()
end
end)
hook.Add("vyhub_lang_loaded", "vyhub_dashboard_vyhub_lang_loaded", function ()
VyHub.Dashboard:load_html()
end)
if VyHub.Dashboard.html_generated then
VyHub.Dashboard:load_html()
end

View File

@@ -1,30 +0,0 @@
--[[
| 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/
--]]
VyHub.groups_mapped = VyHub.groups_mapped or nil
net.Receive("vyhub_group_data", function()
local num = net.ReadUInt(8)
local groups_mapped_new = {}
for i=1, num do
-- Currently only the name and color of the group is transferred
local name_game = net.ReadString()
local name = net.ReadString()
local color = net.ReadString()
groups_mapped_new[name_game] = {
name = name,
color = color,
}
end
VyHub.groups_mapped = groups_mapped_new
end)

View File

@@ -1,27 +0,0 @@
--[[
| 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 meta_ply = FindMetaTable("Player")
VyHub.user_id = VyHub.user_id or nil
function meta_ply:VyHubID()
if IsValid(self) then
if self == LocalPlayer() then
return VyHub.user_id
else
MsgN("ERROR: Cannot get VyHubID of other users on the client side.")
end
end
end
net.Receive("vyhub_user_id", function ()
VyHub.user_id = net.ReadString()
end)

View File

@@ -1,26 +0,0 @@
--[[
| 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/
--]]
-- Language used. Currently only languages in the "lang" directory are supported.
VyHub.Config.lang = "en"
-- Enable chat tags, not working together with DarkRP
VyHub.Config.chat_tags = true
-- Date format to use (for example in ban message)
-- See https://tieske.github.io/date/#dateObject.fmt
VyHub.Config.date_format = "%Y-%m-%d %H:%M:%S %z"
-- Time offset from UTC (+00:00)
-- Uses the timezone of the GMOD server when set to nil
-- Example: 2 for CEST, -5 for EST
VyHub.Config.time_offset = nil
-- Debug mode. Enable to see all API requests and responses
VyHub.Config.debug = false

View File

@@ -1,70 +0,0 @@
--[[
| 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/
--]]
-- VyHub Server Config
-- BEWARE: Additional config values can be set in data/vyhub/config.json with the `vh_config <key> <value>` console command.
-- The configuration in this file is overwritten by the configuration in data/vyhub/config.json
-- ONLY SET THE 3 FOLLOWING OPTIONS IF YOU KNOW WHAT YOU ARE DOING!
-- PLEASE FOLLOW THE INSTALLATION INSTRUCTIONS HERE: https://docs.vyhub.net/latest/game/gmod/#installation
VyHub.Config.api_url = "" -- https://api.vyhub.app/<name>/v1
VyHub.Config.api_key = "" -- Admin -> Settings -> Server -> Setup
VyHub.Config.server_id = "" -- Admin -> Settings -> Server -> Setup
-- Prevent script execution as reward
-- Rewards that want to execute a script will not work if this is enabled.
VyHub.Config.reward_disable_scripts = false
-- Whitelsit for executed reward commands
-- If this table has entries, only commands matching the given patterns are executed
-- Patterns: https://wiki.facepunch.com/gmod/Patterns
-- Example: { "^ulx adduser %l+ %l+$" } -> Allows a command like "ulx adduser username groupname"
VyHub.Config.reward_command_whitelist = {}
-- Player groups are checked every X seconds
VyHub.Config.player_refresh_time = 120
-- Groups are refreshed every X seconds
VyHub.Config.group_refresh_time = 300
-- Every X seconds, an advert message is shown.
VyHub.Config.advert_interval = 180
-- Printed before every advert line
VyHub.Config.advert_prefix = "[★] "
-- Disable group sync
VyHub.Config.group_disable_sync = false
-- Disable override of admin mod bans (ULX, SAM, ServerGuard, xAdmin, ...)
VyHub.Config.ban_disable_sync = false
-- Replace ULib ban list with VyHub bans
VyHub.Config.replace_ulib_bans = false
-- Commands that open the shop page
VyHub.Config.commands_shop = { '!shop' }
-- Commands that open the bans page
VyHub.Config.commands_bans = { '!bans' }
-- Commands that open the warnings page
VyHub.Config.commands_warnings = { '!warnings' }
-- Commands that open the news page
VyHub.Config.commands_news = { '!news' }
-- Commands that open the profile page of a user (Usage: !user <user>)
VyHub.Config.commands_profile = { '!user' }
-- Commands to warn a user (Usage: !warn <user> <reason>)
VyHub.Config.commands_warn = { '!warn' }
-- Commands to open the dashboard
VyHub.Config.commands_dashboard = { '!dashboard' }
-- Customize the ban message that banned players see when trying to connect
VyHub.Config.ban_message = ">>> Ban Message <<<" .. "\n\n"
.. VyHub.lang.other.reason .. ": %reason%" .. "\n"
.. VyHub.lang.other.ban_date .. ": %ban_date%" .. "\n"
.. VyHub.lang.other.unban_date .. ": %unban_date%" .. "\n"
.. VyHub.lang.other.admin .. ": %admin%" .. "\n"
.. VyHub.lang.other.id .. ": %id%" .. "\n\n"
.. VyHub.lang.other.unban_url .. ": %unban_url%" .. "\n\n"

View File

@@ -1 +0,0 @@
AA==

View File

@@ -1,201 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [2022] [Matbyte UG]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@@ -1,14 +0,0 @@
[![Translation Percentage](http://translate.matbyte.com/widgets/vyhub/-/vyhub-lang/svg-badge.svg)](http://translate.matbyte.com/engage/vyhub/)
# vyhub-lang
Translations for VyHub GMOD
Matbyte Translation Tool (MTT): https://translate.matbyte.com/projects/vyhub/vyhub-lang/
## Contribute
1. Create a MTT account (see above)
2. Contact us with your username and the language you wish to translate
3. After your account has been unlocked, translate as much as you want
4. Regularily check for new strings that need to be translated

View File

@@ -1,63 +0,0 @@
{
"ply": {
"no_permissions": "Du hast nicht die nötigen Berechtigungen dafür.",
"banned_self": "Du wurdest vom Server gebannt",
"group_changed": "Deine Gruppe wurde zu <green>%s</green> geändert.",
"error_get": "Spieler konnte nicht gefunden werden. Bitte probiere es später erneut.",
"banned": "Spieler <green>%s</green> wurde <red>%s gebannt</red>. Grund: <green>%s</green>",
"welcome": "Willkommen auf dem Server, <green>%s</green>"
},
"warning": {
"toggled": "Status der Verwarnung wurde geändert.",
"cmd_help": "<red>Ungültiger Spieler!</red> Verwendung: <green>!warn <nick> <reason></green>",
"create_error": "Fehler beim hinzufügen einer Verwarnung für <green>%s</green>: <red>%s</red>",
"deleted": "Verwarnung gelöscht.",
"received": "Du wurdest von <green>%s</green> verwarnt: <red>%s</red>",
"toggled_self": "Der Status einer deiner Verwarnungen wurde geändert. Du kannst deiner Verwarnungen unter !dashboard sehen.",
"user_warned": "<red>%s</red> wurde von <green>%s</green> verwarnt. Grund: <green>%s</green>",
"deleted_self": "Eine deiner Verwarnungen wurde gelöscht. Du kannst deiner Verwarnungen unter !dashboard sehen."
},
"ban": {
"status_changed": "Ban Status von %s erfolgreich auf %s gesetzt.",
"user_banned": "<red>%s</red> wurde von <green>%s</green> für <red>%s</red> vom Server gebannt. Grund: <green>%s</green>"
},
"rslots": {
"full": "Der Server ist voll",
"full_no_slot": "Der Server ist voll und du hast keinen Zugriff auf einen reservierten Slot",
"kick": "Ein Spieler mit einem reservierten Slot ist dem Server beigetreten und du wurdest gekickt um Platz zu schaffen"
},
"other": {
"id": "ID",
"reason": "Grund",
"dead": "TOT",
"ban_date": "Ban Datum",
"unban_date": "Ban Ende",
"admin": "Admin",
"unknown": "Unbekannt",
"minutes": "Minuten",
"x_minutes": "%i Minuten",
"permanently": "Permanent",
"unban_url": "Entbannungs URL",
"error_api": "Fehler bei der Kommunikation mit der API: %s",
"never": "Nie",
"active_global": "Aktiv (Global)",
"unban": "Entbannen",
"actions": "Aktionen",
"active": "Aktiv",
"inactive": "Inaktiv",
"disabled": "Deaktiviert",
"unbanned": "Entbannt",
"reban": "Bannen",
"warnings": "Verwarnungen",
"date": "Datum",
"warn": "Verwarnung",
"ban": "Bann",
"bans": "Banns",
"welcome": "Willkommen"
},
"dashboard": {
"select_user": "Bitte wähle einen Spieler aus.",
"action_ban": "Bannen",
"action_warn": "Verwarnen"
}
}

View File

@@ -1,63 +0,0 @@
{
"ply": {
"banned": "Player <green>%s</green> has been <red>banned for %s</red>. Reason: <green>%s</green>",
"no_permissions": "You don't have all required permissions.",
"banned_self": "You are banned from this server",
"group_changed": "Your group has been changed to <green>%s</green>.",
"error_get": "Could find player. Please try again.",
"welcome": "Welcome on the server, <green>%s</green>"
},
"warning": {
"user_warned": "<red>%s</red> has been warned by <green>%s</green>. Reason: <green>%s</green>",
"cmd_help": "<red>Invlid player!</red> Usage: <green>!warn <nick> <reason></green>",
"toggled_self": "The status of one of your warnings has been changed. Check your warnings with !dashboard.",
"create_error": "Error while adding warning for player <green>%s</green>: <red>%s</red>",
"toggled": "Warning status changed.",
"deleted": "Warning deleted.",
"deleted_self": "One of your warnings has been deleted. Check your warnings with !dashboard.",
"received": "You have received a warning by <green>%s</green>: <red>%s</red>"
},
"ban": {
"status_changed": "Successfully set ban status of %s to %s.",
"user_banned": "<red>%s</red> has been banned by <green>%s</green> for <red>%s</red>. Reason: <green>%s</green>"
},
"rslots": {
"kick": "A player with a reserved slot connected to the server and you got kicked to free up space",
"full": "The server is full",
"full_no_slot": "The server is full and you do not have access to a reserved slot"
},
"dashboard": {
"select_user": "Please select an user.",
"action_ban": "Ban",
"action_warn": "Warn"
},
"other": {
"active": "Active",
"active_global": "Active (Global)",
"inactive": "Inactive",
"disabled": "Disabled",
"unbanned": "Unbanned",
"id": "ID",
"reason": "Reason",
"dead": "DEAD",
"ban_date": "Ban date",
"unban_date": "Unban date",
"unban": "Unban",
"reban": "Reban",
"admin": "Admin",
"welcome": "Welcome",
"actions": "Actions",
"never": "Never",
"warnings": "Warnings",
"date": "Date",
"ban": "Ban",
"warn": "Warn",
"bans": "Bans",
"unknown": "Unknown",
"minutes": "Minutes",
"x_minutes": "%i Minutes",
"permanently": "Permanently",
"unban_url": "Unban URL",
"error_api": "Error while communicating with the API: %s"
}
}

View File

@@ -1,63 +0,0 @@
{
"ply": {
"banned": "Le joueur <green>%s</green> a été <red>banni pendant %s</red>. Raison : <green>%s</green>",
"no_permissions": "Vous ne disposez pas de toutes les permissions requises.",
"banned_self": "Vous êtes banni de ce serveur",
"error_get": "Pourrait trouver un joueur. Veuillez réessayer.",
"group_changed": "Votre groupe a été changé par <green>%s</green>.",
"welcome": "Bienvenue sur le serveur, <green>%s</green>"
},
"warning": {
"user_warned": "<red>%s</red> a été averti par <green>%s</green>. Raison : <green>%s</green>",
"toggled_self": "L'état de l'un de vos avertissements a été modifié. Vérifiez vos avertissements avec !dashboard.",
"create_error": "Erreur lors de l'ajout d'un avertissement pour le joueur <green>%s</green> : <red>%s</red>",
"deleted": "Avertissement supprimé.",
"deleted_self": "L'un de vos avertissements a été supprimé. Vérifiez vos avertissements avec !dashboard.",
"toggled": "L'état d'avertissement a changé.",
"cmd_help": "<red>Joueur invalide !</red> Utilisation : <green>!warn <joueur> <raison></green>",
"received": "Vous avez reçu un avertissement de <green>%s</green> : <red>%s</red>"
},
"ban": {
"status_changed": "Le statut de bannissement de %s a été défini avec succès sur %s.",
"user_banned": "<red>%s</red> a été banni par <green>%s</green> pour <red>%s</red>. Raison : <green>%s</green>"
},
"rslots": {
"full": "Le serveur est plein",
"full_no_slot": "Le serveur est plein et vous n'avez pas accès à un créneau réservé",
"kick": "Un joueur avec un emplacement réservé connecté au serveur et vous avez été expulsé pour libérer de l'espace"
},
"dashboard": {
"select_user": "Veuillez sélectionner un utilisateur.",
"action_warn": "Avertir",
"action_ban": "Bannir"
},
"other": {
"active": "Actif",
"active_global": "Actif (Global)",
"inactive": "Inactif",
"disabled": "Désactivé",
"unbanned": "Débannir",
"id": "ID",
"reason": "Raison",
"dead": "Mort",
"ban_date": "Date de bannissement",
"unban": "Débannir",
"unban_date": "Date de débannissement",
"reban": "Rebannir",
"admin": "Administrateur",
"actions": "Actions",
"never": "Jamais",
"warnings": "Avertissements",
"date": "Date",
"ban": "Bannir",
"warn": "Avertir",
"bans": "Bannissements",
"minutes": "Minutes",
"unknown": "Inconnu",
"x_minutes": "%i Minutes",
"unban_url": "URL de débannissement",
"permanently": "Permanent",
"error_api": "Erreur lors de la communication avec l'API : %s",
"welcome": "Bienvenue"
}
}

View File

@@ -1,766 +0,0 @@
--[[
| 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/
--]]
VyHub.Lib.date = VyHub.Lib.date or {}
---------------------------------------------------------------------------------------
-- Module for date and time calculations
--
-- Version 2.2
-- Copyright (C) 2005-2006, by Jas Latrix (jastejada@yahoo.com)
-- Copyright (C) 2013-2021, by Thijs Schreijer
-- Licensed under MIT, http://opensource.org/licenses/MIT
-- https://github.com/Tieske/date
-- Changes by Matbyte: New function setbias
--[[ CONSTANTS ]]--
local HOURPERDAY = 24
local MINPERHOUR = 60
local MINPERDAY = 1440 -- 24*60
local SECPERMIN = 60
local SECPERHOUR = 3600 -- 60*60
local SECPERDAY = 86400 -- 24*60*60
local TICKSPERSEC = 1000000
local TICKSPERDAY = 86400000000
local TICKSPERHOUR = 3600000000
local TICKSPERMIN = 60000000
local DAYNUM_MAX = 365242500 -- Sat Jan 01 1000000 00:00:00
local DAYNUM_MIN = -365242500 -- Mon Jan 01 1000000 BCE 00:00:00
local DAYNUM_DEF = 0 -- Mon Jan 01 0001 00:00:00
local _;
--[[ GLOBAL SETTINGS ]]--
local centuryflip = 0 -- year >= centuryflip == 1900, < centuryflip == 2000
--[[ LOCAL ARE FASTER ]]--
local type = type
local pairs = pairs
local error = error
local assert = assert
local tonumber = tonumber
local tostring = tostring
local string = string
local math = math
local os = os
local unpack = unpack or table.unpack
local setmetatable = setmetatable
local getmetatable = getmetatable
--[[ EXTRA FUNCTIONS ]]--
local fmt = string.format
local lwr = string.lower
local rep = string.rep
local len = string.len -- luacheck: ignore
local sub = string.sub
local gsub = string.gsub
local gmatch = string.gmatch or string.gfind
local find = string.find
local ostime = os.time
local osdate = os.date
local floor = math.floor
local ceil = math.ceil
local abs = math.abs
-- removes the decimal part of a number
local function fix(n) n = tonumber(n) return n and ((n > 0 and floor or ceil)(n)) end
-- returns the modulo n % d;
local function mod(n,d) return n - d*floor(n/d) end
-- is `str` in string list `tbl`, `ml` is the minimun len
local function inlist(str, tbl, ml, tn)
local sl = len(str)
if sl < (ml or 0) then return nil end
str = lwr(str)
for k, v in pairs(tbl) do
if str == lwr(sub(v, 1, sl)) then
if tn then tn[0] = k end
return k
end
end
end
local function fnil() end
--[[ DATE FUNCTIONS ]]--
local DATE_EPOCH -- to be set later
local sl_weekdays = {
[0]="Sunday",[1]="Monday",[2]="Tuesday",[3]="Wednesday",[4]="Thursday",[5]="Friday",[6]="Saturday",
[7]="Sun",[8]="Mon",[9]="Tue",[10]="Wed",[11]="Thu",[12]="Fri",[13]="Sat",
}
local sl_meridian = {[-1]="AM", [1]="PM"}
local sl_months = {
[00]="January", [01]="February", [02]="March",
[03]="April", [04]="May", [05]="June",
[06]="July", [07]="August", [08]="September",
[09]="October", [10]="November", [11]="December",
[12]="Jan", [13]="Feb", [14]="Mar",
[15]="Apr", [16]="May", [17]="Jun",
[18]="Jul", [19]="Aug", [20]="Sep",
[21]="Oct", [22]="Nov", [23]="Dec",
}
-- added the '.2' to avoid collision, use `fix` to remove
local sl_timezone = {
[000]="utc", [0.2]="gmt",
[300]="est", [240]="edt",
[360]="cst", [300.2]="cdt",
[420]="mst", [360.2]="mdt",
[480]="pst", [420.2]="pdt",
}
-- set the day fraction resolution
local function setticks(t)
TICKSPERSEC = t;
TICKSPERDAY = SECPERDAY*TICKSPERSEC
TICKSPERHOUR= SECPERHOUR*TICKSPERSEC
TICKSPERMIN = SECPERMIN*TICKSPERSEC
end
-- is year y leap year?
local function isleapyear(y) -- y must be int!
return (mod(y, 4) == 0 and (mod(y, 100) ~= 0 or mod(y, 400) == 0))
end
-- day since year 0
local function dayfromyear(y) -- y must be int!
return 365*y + floor(y/4) - floor(y/100) + floor(y/400)
end
-- day number from date, month is zero base
local function makedaynum(y, m, d)
local mm = mod(mod(m,12) + 10, 12)
return dayfromyear(y + floor(m/12) - floor(mm/10)) + floor((mm*306 + 5)/10) + d - 307
--local yy = y + floor(m/12) - floor(mm/10)
--return dayfromyear(yy) + floor((mm*306 + 5)/10) + (d - 1)
end
-- date from day number, month is zero base
local function breakdaynum(g)
local g = g + 306
local y = floor((10000*g + 14780)/3652425)
local d = g - dayfromyear(y)
if d < 0 then y = y - 1; d = g - dayfromyear(y) end
local mi = floor((100*d + 52)/3060)
return (floor((mi + 2)/12) + y), mod(mi + 2,12), (d - floor((mi*306 + 5)/10) + 1)
end
--[[ for floats or int32 Lua Number data type
local function breakdaynum2(g)
local g, n = g + 306;
local n400 = floor(g/DI400Y);n = mod(g,DI400Y);
local n100 = floor(n/DI100Y);n = mod(n,DI100Y);
local n004 = floor(n/DI4Y); n = mod(n,DI4Y);
local n001 = floor(n/365); n = mod(n,365);
local y = (n400*400) + (n100*100) + (n004*4) + n001 - ((n001 == 4 or n100 == 4) and 1 or 0)
local d = g - dayfromyear(y)
local mi = floor((100*d + 52)/3060)
return (floor((mi + 2)/12) + y), mod(mi + 2,12), (d - floor((mi*306 + 5)/10) + 1)
end
]]
-- day fraction from time
local function makedayfrc(h,r,s,t)
return ((h*60 + r)*60 + s)*TICKSPERSEC + t
end
-- time from day fraction
local function breakdayfrc(df)
return
mod(floor(df/TICKSPERHOUR),HOURPERDAY),
mod(floor(df/TICKSPERMIN ),MINPERHOUR),
mod(floor(df/TICKSPERSEC ),SECPERMIN),
mod(df,TICKSPERSEC)
end
-- weekday sunday = 0, monday = 1 ...
local function weekday(dn) return mod(dn + 1, 7) end
-- yearday 0 based ...
local function yearday(dn)
return dn - dayfromyear((breakdaynum(dn))-1)
end
-- parse v as a month
local function getmontharg(v)
local m = tonumber(v);
return (m and fix(m - 1)) or inlist(tostring(v) or "", sl_months, 2)
end
-- get daynum of isoweek one of year y
local function isow1(y)
local f = makedaynum(y, 0, 4) -- get the date for the 4-Jan of year `y`
local d = weekday(f)
d = d == 0 and 7 or d -- get the ISO day number, 1 == Monday, 7 == Sunday
return f + (1 - d)
end
local function isowy(dn)
local w1;
local y = (breakdaynum(dn))
if dn >= makedaynum(y, 11, 29) then
w1 = isow1(y + 1);
if dn < w1 then
w1 = isow1(y);
else
y = y + 1;
end
else
w1 = isow1(y);
if dn < w1 then
w1 = isow1(y-1)
y = y - 1
end
end
return floor((dn-w1)/7)+1, y
end
local function isoy(dn)
local y = (breakdaynum(dn))
return y + (((dn >= makedaynum(y, 11, 29)) and (dn >= isow1(y + 1))) and 1 or (dn < isow1(y) and -1 or 0))
end
local function makedaynum_isoywd(y,w,d)
return isow1(y) + 7*w + d - 8 -- simplified: isow1(y) + ((w-1)*7) + (d-1)
end
--[[ THE DATE MODULE ]]--
local fmtstr = "%x %X";
--#if not DATE_OBJECT_AFX then
local date = {}
setmetatable(date, date)
-- Version: VMMMRRRR; V-Major, M-Minor, R-Revision; e.g. 5.45.321 == 50450321
do
local major = 2
local minor = 2
local revision = 0
date.version = major * 10000000 + minor * 10000 + revision
end
--#end -- not DATE_OBJECT_AFX
--[[ THE DATE OBJECT ]]--
local dobj = {}
dobj.__index = dobj
dobj.__metatable = dobj
-- shout invalid arg
local function date_error_arg() return error("invalid argument(s)",0) end
-- create new date object
local function date_new(dn, df)
return setmetatable({daynum=dn, dayfrc=df}, dobj)
end
--#if not NO_LOCAL_TIME_SUPPORT then
-- magic year table
local date_epoch, yt;
local function getequivyear(y)
assert(not yt)
yt = {}
local de = date_epoch:copy()
local dw, dy
for _ = 0, 3000 do
de:setyear(de:getyear() + 1, 1, 1)
dy = de:getyear()
dw = de:getweekday() * (isleapyear(dy) and -1 or 1)
if not yt[dw] then yt[dw] = dy end --print(de)
if yt[1] and yt[2] and yt[3] and yt[4] and yt[5] and yt[6] and yt[7] and yt[-1] and yt[-2] and yt[-3] and yt[-4] and yt[-5] and yt[-6] and yt[-7] then
getequivyear = function(y) return yt[ (weekday(makedaynum(y, 0, 1)) + 1) * (isleapyear(y) and -1 or 1) ] end
return getequivyear(y)
end
end
end
-- TimeValue from date and time
local function totv(y,m,d,h,r,s)
return (makedaynum(y, m, d) - DATE_EPOCH) * SECPERDAY + ((h*60 + r)*60 + s)
end
-- TimeValue from TimeTable
local function tmtotv(tm)
return tm and totv(tm.year, tm.month - 1, tm.day, tm.hour, tm.min, tm.sec)
end
-- Returns the bias in seconds of utc time daynum and dayfrc
local function getbiasutc2(self)
local y,m,d = breakdaynum(self.daynum)
local h,r,s = breakdayfrc(self.dayfrc)
local tvu = totv(y,m,d,h,r,s) -- get the utc TimeValue of date and time
local tml = osdate("*t", tvu) -- get the local TimeTable of tvu
if (not tml) or (tml.year > (y+1) or tml.year < (y-1)) then -- failed try the magic
y = getequivyear(y)
tvu = totv(y,m,d,h,r,s)
tml = osdate("*t", tvu)
end
local tvl = tmtotv(tml)
if tvu and tvl then
return tvu - tvl, tvu, tvl
else
return error("failed to get bias from utc time")
end
end
-- Returns the bias in seconds of local time daynum and dayfrc
local function getbiasloc2(daynum, dayfrc)
local tvu
-- extract date and time
local y,m,d = breakdaynum(daynum)
local h,r,s = breakdayfrc(dayfrc)
-- get equivalent TimeTable
local tml = {year=y, month=m+1, day=d, hour=h, min=r, sec=s}
-- get equivalent TimeValue
local tvl = tmtotv(tml)
local function chkutc()
tml.isdst = nil; local tvug = ostime(tml) if tvug and (tvl == tmtotv(osdate("*t", tvug))) then tvu = tvug return end
tml.isdst = true; local tvud = ostime(tml) if tvud and (tvl == tmtotv(osdate("*t", tvud))) then tvu = tvud return end
tvu = tvud or tvug
end
chkutc()
if not tvu then
tml.year = getequivyear(y)
tvl = tmtotv(tml)
chkutc()
end
return ((tvu and tvl) and (tvu - tvl)) or error("failed to get bias from local time"), tvu, tvl
end
--#end -- not NO_LOCAL_TIME_SUPPORT
--#if not DATE_OBJECT_AFX then
-- the date parser
local strwalker = {} -- ^Lua regular expression is not as powerful as Perl$
strwalker.__index = strwalker
local function newstrwalker(s)return setmetatable({s=s, i=1, e=1, c=len(s)}, strwalker) end
function strwalker:aimchr() return "\n" .. self.s .. "\n" .. rep(".",self.e-1) .. "^" end
function strwalker:finish() return self.i > self.c end
function strwalker:back() self.i = self.e return self end
function strwalker:restart() self.i, self.e = 1, 1 return self end
function strwalker:match(s) return (find(self.s, s, self.i)) end
function strwalker:__call(s, f)-- print("strwalker:__call "..s..self:aimchr())
local is, ie; is, ie, self[1], self[2], self[3], self[4], self[5] = find(self.s, s, self.i)
if is then self.e, self.i = self.i, 1+ie; if f then f(unpack(self)) end return self end
end
local function date_parse(str)
local y,m,d, h,r,s, z, w,u, j, e, x,c, dn,df
local sw = newstrwalker(gsub(gsub(str, "(%b())", ""),"^(%s*)","")) -- remove comment, trim leading space
--local function error_out() print(y,m,d,h,r,s) end
local function error_dup(q) --[[error_out()]] error("duplicate value: " .. (q or "") .. sw:aimchr()) end
local function error_syn(q) --[[error_out()]] error("syntax error: " .. (q or "") .. sw:aimchr()) end
local function error_inv(q) --[[error_out()]] error("invalid date: " .. (q or "") .. sw:aimchr()) end
local function sety(q) y = y and error_dup() or tonumber(q); end
local function setm(q) m = (m or w or j) and error_dup(m or w or j) or tonumber(q) end
local function setd(q) d = d and error_dup() or tonumber(q) end
local function seth(q) h = h and error_dup() or tonumber(q) end
local function setr(q) r = r and error_dup() or tonumber(q) end
local function sets(q) s = s and error_dup() or tonumber(q) end
local function adds(q) s = s + tonumber(q) end
local function setj(q) j = (m or w or j) and error_dup() or tonumber(q); end
local function setz(q) z = (z ~= 0 and z) and error_dup() or q end
local function setzn(zs,zn) zn = tonumber(zn); setz( ((zn<24) and (zn*60) or (mod(zn,100) + floor(zn/100) * 60))*( zs=='+' and -1 or 1) ) end
local function setzc(zs,zh,zm) setz( ((tonumber(zh)*60) + tonumber(zm))*( zs=='+' and -1 or 1) ) end
if not (sw("^(%d%d%d%d)",sety) and (sw("^(%-?)(%d%d)%1(%d%d)",function(_,a,b) setm(tonumber(a)); setd(tonumber(b)) end) or sw("^(%-?)[Ww](%d%d)%1(%d?)",function(_,a,b) w, u = tonumber(a), tonumber(b or 1) end) or sw("^%-?(%d%d%d)",setj) or sw("^%-?(%d%d)",function(a) setm(a);setd(1) end))
and ((sw("^%s*[Tt]?(%d%d):?",seth) and sw("^(%d%d):?",setr) and sw("^(%d%d)",sets) and sw("^(%.%d+)",adds))
or sw:finish() or (sw"^%s*$" or sw"^%s*[Zz]%s*$" or sw("^%s-([%+%-])(%d%d):?(%d%d)%s*$",setzc) or sw("^%s*([%+%-])(%d%d)%s*$",setzn))
) )
then --print(y,m,d,h,r,s,z,w,u,j)
sw:restart(); y,m,d,h,r,s,z,w,u,j = nil,nil,nil,nil,nil,nil,nil,nil,nil,nil
repeat -- print(sw:aimchr())
if sw("^[tT:]?%s*(%d%d?):",seth) then --print("$Time")
_ = sw("^%s*(%d%d?)",setr) and sw("^%s*:%s*(%d%d?)",sets) and sw("^(%.%d+)",adds)
elseif sw("^(%d+)[/\\%s,-]?%s*") then --print("$Digits")
x, c = tonumber(sw[1]), len(sw[1])
if (x >= 70) or (m and d and (not y)) or (c > 3) then
sety( x + ((x >= 100 or c>3) and 0 or x<centuryflip and 2000 or 1900) )
else
if m then setd(x) else m = x end
end
elseif sw("^(%a+)[/\\%s,-]?%s*") then --print("$Words")
x = sw[1]
if inlist(x, sl_months, 2, sw) then
if m and (not d) and (not y) then d, m = m, false end
setm(mod(sw[0],12)+1)
elseif inlist(x, sl_timezone, 2, sw) then
c = fix(sw[0]) -- ignore gmt and utc
if c ~= 0 then setz(c, x) end
elseif not inlist(x, sl_weekdays, 2, sw) then
sw:back()
-- am pm bce ad ce bc
if sw("^([bB])%s*(%.?)%s*[Cc]%s*(%2)%s*[Ee]%s*(%2)%s*") or sw("^([bB])%s*(%.?)%s*[Cc]%s*(%2)%s*") then
e = e and error_dup() or -1
elseif sw("^([aA])%s*(%.?)%s*[Dd]%s*(%2)%s*") or sw("^([cC])%s*(%.?)%s*[Ee]%s*(%2)%s*") then
e = e and error_dup() or 1
elseif sw("^([PApa])%s*(%.?)%s*[Mm]?%s*(%2)%s*") then
x = lwr(sw[1]) -- there should be hour and it must be correct
if (not h) or (h > 12) or (h < 0) then return error_inv() end
if x == 'a' and h == 12 then h = 0 end -- am
if x == 'p' and h ~= 12 then h = h + 12 end -- pm
else error_syn() end
end
elseif not(sw("^([+-])(%d%d?):(%d%d)",setzc) or sw("^([+-])(%d+)",setzn) or sw("^[Zz]%s*$")) then -- sw{"([+-])",{"(%d%d?):(%d%d)","(%d+)"}}
error_syn("?")
end
sw("^%s*") until sw:finish()
--else print("$Iso(Date|Time|Zone)")
end
-- if date is given, it must be complete year, month & day
if (not y and not h) or ((m and not d) or (d and not m)) or ((m and w) or (m and j) or (j and w)) then return error_inv("!") end
-- fix month
if m then m = m - 1 end
-- fix year if we are on BCE
if e and e < 0 and y > 0 then y = 1 - y end
-- create date object
dn = (y and ((w and makedaynum_isoywd(y,w,u)) or (j and makedaynum(y, 0, j)) or makedaynum(y, m, d))) or DAYNUM_DEF
df = makedayfrc(h or 0, r or 0, s or 0, 0) + ((z or 0)*TICKSPERMIN)
--print("Zone",h,r,s,z,m,d,y,df)
return date_new(dn, df) -- no need to :normalize();
end
local function date_fromtable(v)
local y, m, d = fix(v.year), getmontharg(v.month), fix(v.day)
local h, r, s, t = tonumber(v.hour), tonumber(v.min), tonumber(v.sec), tonumber(v.ticks)
-- atleast there is time or complete date
if (y or m or d) and (not(y and m and d)) then return error("incomplete table") end
return (y or h or r or s or t) and date_new(y and makedaynum(y, m, d) or DAYNUM_DEF, makedayfrc(h or 0, r or 0, s or 0, t or 0))
end
local tmap = {
['number'] = function(v) return date_epoch:copy():addseconds(v) end,
['string'] = function(v) return date_parse(v) end,
['boolean']= function(v) return date_fromtable(osdate(v and "!*t" or "*t")) end,
['table'] = function(v) local ref = getmetatable(v) == dobj; return ref and v or date_fromtable(v), ref end
}
local function date_getdobj(v)
local o, r = (tmap[type(v)] or fnil)(v);
return (o and o:normalize() or error"invalid date time value"), r -- if r is true then o is a reference to a date obj
end
--#end -- not DATE_OBJECT_AFX
local function date_from(arg1, arg2, arg3, arg4, arg5, arg6, arg7)
local y, m, d = fix(arg1), getmontharg(arg2), fix(arg3)
local h, r, s, t = tonumber(arg4 or 0), tonumber(arg5 or 0), tonumber(arg6 or 0), tonumber(arg7 or 0)
if y and m and d and h and r and s and t then
return date_new(makedaynum(y, m, d), makedayfrc(h, r, s, t)):normalize()
else
return date_error_arg()
end
end
--[[ THE DATE OBJECT METHODS ]]--
function dobj:normalize()
local dn, df = fix(self.daynum), self.dayfrc
self.daynum, self.dayfrc = dn + floor(df/TICKSPERDAY), mod(df, TICKSPERDAY)
return (dn >= DAYNUM_MIN and dn <= DAYNUM_MAX) and self or error("date beyond imposed limits:"..self)
end
function dobj:getdate() local y, m, d = breakdaynum(self.daynum) return y, m+1, d end
function dobj:gettime() return breakdayfrc(self.dayfrc) end
function dobj:getclockhour() local h = self:gethours() return h>12 and mod(h,12) or (h==0 and 12 or h) end
function dobj:getyearday() return yearday(self.daynum) + 1 end
function dobj:getweekday() return weekday(self.daynum) + 1 end -- in lua weekday is sunday = 1, monday = 2 ...
function dobj:getyear() local r,_,_ = breakdaynum(self.daynum) return r end
function dobj:getmonth() local _,r,_ = breakdaynum(self.daynum) return r+1 end-- in lua month is 1 base
function dobj:getday() local _,_,r = breakdaynum(self.daynum) return r end
function dobj:gethours() return mod(floor(self.dayfrc/TICKSPERHOUR),HOURPERDAY) end
function dobj:getminutes() return mod(floor(self.dayfrc/TICKSPERMIN), MINPERHOUR) end
function dobj:getseconds() return mod(floor(self.dayfrc/TICKSPERSEC ),SECPERMIN) end
function dobj:getfracsec() return mod(floor(self.dayfrc/TICKSPERSEC ),SECPERMIN)+(mod(self.dayfrc,TICKSPERSEC)/TICKSPERSEC) end
function dobj:getticks(u) local x = mod(self.dayfrc,TICKSPERSEC) return u and ((x*u)/TICKSPERSEC) or x end
function dobj:getweeknumber(wdb)
local wd, yd = weekday(self.daynum), yearday(self.daynum)
if wdb then
wdb = tonumber(wdb)
if wdb then
wd = mod(wd-(wdb-1),7)-- shift the week day base
else
return date_error_arg()
end
end
return (yd < wd and 0) or (floor(yd/7) + ((mod(yd, 7)>=wd) and 1 or 0))
end
function dobj:getisoweekday() return mod(weekday(self.daynum)-1,7)+1 end -- sunday = 7, monday = 1 ...
function dobj:getisoweeknumber() return (isowy(self.daynum)) end
function dobj:getisoyear() return isoy(self.daynum) end
function dobj:getisodate()
local w, y = isowy(self.daynum)
return y, w, self:getisoweekday()
end
function dobj:setisoyear(y, w, d)
local cy, cw, cd = self:getisodate()
if y then cy = fix(tonumber(y))end
if w then cw = fix(tonumber(w))end
if d then cd = fix(tonumber(d))end
if cy and cw and cd then
self.daynum = makedaynum_isoywd(cy, cw, cd)
return self:normalize()
else
return date_error_arg()
end
end
function dobj:setisoweekday(d) return self:setisoyear(nil, nil, d) end
function dobj:setisoweeknumber(w,d) return self:setisoyear(nil, w, d) end
function dobj:setyear(y, m, d)
local cy, cm, cd = breakdaynum(self.daynum)
if y then cy = fix(tonumber(y))end
if m then cm = getmontharg(m) end
if d then cd = fix(tonumber(d))end
if cy and cm and cd then
self.daynum = makedaynum(cy, cm, cd)
return self:normalize()
else
return date_error_arg()
end
end
function dobj:setmonth(m, d)return self:setyear(nil, m, d) end
function dobj:setday(d) return self:setyear(nil, nil, d) end
function dobj:sethours(h, m, s, t)
local ch,cm,cs,ck = breakdayfrc(self.dayfrc)
ch, cm, cs, ck = tonumber(h or ch), tonumber(m or cm), tonumber(s or cs), tonumber(t or ck)
if ch and cm and cs and ck then
self.dayfrc = makedayfrc(ch, cm, cs, ck)
return self:normalize()
else
return date_error_arg()
end
end
function dobj:setminutes(m,s,t) return self:sethours(nil, m, s, t) end
function dobj:setseconds(s, t) return self:sethours(nil, nil, s, t) end
function dobj:setticks(t) return self:sethours(nil, nil, nil, t) end
function dobj:spanticks() return (self.daynum*TICKSPERDAY + self.dayfrc) end
function dobj:spanseconds() return (self.daynum*TICKSPERDAY + self.dayfrc)/TICKSPERSEC end
function dobj:spanminutes() return (self.daynum*TICKSPERDAY + self.dayfrc)/TICKSPERMIN end
function dobj:spanhours() return (self.daynum*TICKSPERDAY + self.dayfrc)/TICKSPERHOUR end
function dobj:spandays() return (self.daynum*TICKSPERDAY + self.dayfrc)/TICKSPERDAY end
function dobj:addyears(y, m, d)
local cy, cm, cd = breakdaynum(self.daynum)
if y then y = fix(tonumber(y))else y = 0 end
if m then m = fix(tonumber(m))else m = 0 end
if d then d = fix(tonumber(d))else d = 0 end
if y and m and d then
self.daynum = makedaynum(cy+y, cm+m, cd+d)
return self:normalize()
else
return date_error_arg()
end
end
function dobj:addmonths(m, d)
return self:addyears(nil, m, d)
end
local function dobj_adddayfrc(self,n,pt,pd)
n = tonumber(n)
if n then
local x = floor(n/pd);
self.daynum = self.daynum + x;
self.dayfrc = self.dayfrc + (n-x*pd)*pt;
return self:normalize()
else
return date_error_arg()
end
end
function dobj:adddays(n) return dobj_adddayfrc(self,n,TICKSPERDAY,1) end
function dobj:addhours(n) return dobj_adddayfrc(self,n,TICKSPERHOUR,HOURPERDAY) end
function dobj:addminutes(n) return dobj_adddayfrc(self,n,TICKSPERMIN,MINPERDAY) end
function dobj:addseconds(n) return dobj_adddayfrc(self,n,TICKSPERSEC,SECPERDAY) end
function dobj:addticks(n) return dobj_adddayfrc(self,n,1,TICKSPERDAY) end
local tvspec = {
-- Abbreviated weekday name (Sun)
['%a']=function(self) return sl_weekdays[weekday(self.daynum) + 7] end,
-- Full weekday name (Sunday)
['%A']=function(self) return sl_weekdays[weekday(self.daynum)] end,
-- Abbreviated month name (Dec)
['%b']=function(self) return sl_months[self:getmonth() - 1 + 12] end,
-- Full month name (December)
['%B']=function(self) return sl_months[self:getmonth() - 1] end,
-- Year/100 (19, 20, 30)
['%C']=function(self) return fmt("%.2d", fix(self:getyear()/100)) end,
-- The day of the month as a number (range 1 - 31)
['%d']=function(self) return fmt("%.2d", self:getday()) end,
-- year for ISO 8601 week, from 00 (79)
['%g']=function(self) return fmt("%.2d", mod(self:getisoyear() ,100)) end,
-- year for ISO 8601 week, from 0000 (1979)
['%G']=function(self) return fmt("%.4d", self:getisoyear()) end,
-- same as %b
['%h']=function(self) return self:fmt0("%b") end,
-- hour of the 24-hour day, from 00 (06)
['%H']=function(self) return fmt("%.2d", self:gethours()) end,
-- The hour as a number using a 12-hour clock (01 - 12)
['%I']=function(self) return fmt("%.2d", self:getclockhour()) end,
-- The day of the year as a number (001 - 366)
['%j']=function(self) return fmt("%.3d", self:getyearday()) end,
-- Month of the year, from 01 to 12
['%m']=function(self) return fmt("%.2d", self:getmonth()) end,
-- Minutes after the hour 55
['%M']=function(self) return fmt("%.2d", self:getminutes())end,
-- AM/PM indicator (AM)
['%p']=function(self) return sl_meridian[self:gethours() > 11 and 1 or -1] end, --AM/PM indicator (AM)
-- The second as a number (59, 20 , 01)
['%S']=function(self) return fmt("%.2d", self:getseconds()) end,
-- ISO 8601 day of the week, to 7 for Sunday (7, 1)
['%u']=function(self) return self:getisoweekday() end,
-- Sunday week of the year, from 00 (48)
['%U']=function(self) return fmt("%.2d", self:getweeknumber()) end,
-- ISO 8601 week of the year, from 01 (48)
['%V']=function(self) return fmt("%.2d", self:getisoweeknumber()) end,
-- The day of the week as a decimal, Sunday being 0
['%w']=function(self) return self:getweekday() - 1 end,
-- Monday week of the year, from 00 (48)
['%W']=function(self) return fmt("%.2d", self:getweeknumber(2)) end,
-- The year as a number without a century (range 00 to 99)
['%y']=function(self) return fmt("%.2d", mod(self:getyear() ,100)) end,
-- Year with century (2000, 1914, 0325, 0001)
['%Y']=function(self) return fmt("%.4d", self:getyear()) end,
-- Time zone offset, the date object is assumed local time (+1000, -0230)
['%z']=function(self) local b = -self:getbias(); local x = abs(b); return fmt("%s%.4d", b < 0 and "-" or "+", fix(x/60)*100 + floor(mod(x,60))) end,
-- Time zone name, the date object is assumed local time
['%Z']=function(self) return self:gettzname() end,
-- Misc --
-- Year, if year is in BCE, prints the BCE Year representation, otherwise result is similar to "%Y" (1 BCE, 40 BCE)
['%\b']=function(self) local x = self:getyear() return fmt("%.4d%s", x>0 and x or (-x+1), x>0 and "" or " BCE") end,
-- Seconds including fraction (59.998, 01.123)
['%\f']=function(self) local x = self:getfracsec() return fmt("%s%.9f",x >= 10 and "" or "0", x) end,
-- percent character %
['%%']=function(self) return "%" end,
-- Group Spec --
-- 12-hour time, from 01:00:00 AM (06:55:15 AM); same as "%I:%M:%S %p"
['%r']=function(self) return self:fmt0("%I:%M:%S %p") end,
-- hour:minute, from 01:00 (06:55); same as "%I:%M"
['%R']=function(self) return self:fmt0("%I:%M") end,
-- 24-hour time, from 00:00:00 (06:55:15); same as "%H:%M:%S"
['%T']=function(self) return self:fmt0("%H:%M:%S") end,
-- month/day/year from 01/01/00 (12/02/79); same as "%m/%d/%y"
['%D']=function(self) return self:fmt0("%m/%d/%y") end,
-- year-month-day (1979-12-02); same as "%Y-%m-%d"
['%F']=function(self) return self:fmt0("%Y-%m-%d") end,
-- The preferred date and time representation; same as "%x %X"
['%c']=function(self) return self:fmt0("%x %X") end,
-- The preferred date representation, same as "%a %b %d %\b"
['%x']=function(self) return self:fmt0("%a %b %d %\b") end,
-- The preferred time representation, same as "%H:%M:%\f"
['%X']=function(self) return self:fmt0("%H:%M:%\f") end,
-- GroupSpec --
-- Iso format, same as "%Y-%m-%dT%T"
['${iso}'] = function(self) return self:fmt0("%Y-%m-%dT%T") end,
-- http format, same as "%a, %d %b %Y %T GMT"
['${http}'] = function(self) return self:fmt0("%a, %d %b %Y %T GMT") end,
-- ctime format, same as "%a %b %d %T GMT %Y"
['${ctime}'] = function(self) return self:fmt0("%a %b %d %T GMT %Y") end,
-- RFC850 format, same as "%A, %d-%b-%y %T GMT"
['${rfc850}'] = function(self) return self:fmt0("%A, %d-%b-%y %T GMT") end,
-- RFC1123 format, same as "%a, %d %b %Y %T GMT"
['${rfc1123}'] = function(self) return self:fmt0("%a, %d %b %Y %T GMT") end,
-- asctime format, same as "%a %b %d %T %Y"
['${asctime}'] = function(self) return self:fmt0("%a %b %d %T %Y") end,
}
function dobj:fmt0(str) return (gsub(str, "%%[%a%%\b\f]", function(x) local f = tvspec[x];return (f and f(self)) or x end)) end
function dobj:fmt(str)
str = str or self.fmtstr or fmtstr
return self:fmt0((gmatch(str, "${%w+}")) and (gsub(str, "${%w+}", function(x)local f=tvspec[x];return (f and f(self)) or x end)) or str)
end
function dobj.__lt(a, b) if (a.daynum == b.daynum) then return (a.dayfrc < b.dayfrc) else return (a.daynum < b.daynum) end end
function dobj.__le(a, b) if (a.daynum == b.daynum) then return (a.dayfrc <= b.dayfrc) else return (a.daynum <= b.daynum) end end
function dobj.__eq(a, b)return (a.daynum == b.daynum) and (a.dayfrc == b.dayfrc) end
function dobj.__sub(a,b)
local d1, d2 = date_getdobj(a), date_getdobj(b)
local d0 = d1 and d2 and date_new(d1.daynum - d2.daynum, d1.dayfrc - d2.dayfrc)
return d0 and d0:normalize()
end
function dobj.__add(a,b)
local d1, d2 = date_getdobj(a), date_getdobj(b)
local d0 = d1 and d2 and date_new(d1.daynum + d2.daynum, d1.dayfrc + d2.dayfrc)
return d0 and d0:normalize()
end
function dobj.__concat(a, b) return tostring(a) .. tostring(b) end
function dobj:__tostring() return self:fmt() end
function dobj:copy() return date_new(self.daynum, self.dayfrc) end
function dobj:setbias(bias)
self.bias = bias
return self
end
--[[ THE LOCAL DATE OBJECT METHODS ]]--
function dobj:tolocal()
local dn,df = self.daynum, self.dayfrc
bias = self.bias or getbiasutc2(self)
if bias != nil then
-- utc = local + bias; local = utc - bias
self.daynum = dn
self.dayfrc = df - bias*TICKSPERSEC
return self:normalize()
else
return nil
end
end
function dobj:toutc()
local dn,df = self.daynum, self.dayfrc
local bias = self.bias or getbiasloc2(dn, df)
if bias then
-- utc = local + bias;
self.daynum = dn
self.dayfrc = df + bias*TICKSPERSEC
return self:normalize()
else
return nil
end
end
function dobj:getbias() return self.bias != nil and self.bias/SECPERMIN or (getbiasloc2(self.daynum, self.dayfrc))/SECPERMIN end
function dobj:gettzname()
if self.bias != nil then return "" end
local _, tvu, _ = getbiasloc2(self.daynum, self.dayfrc)
return tvu and osdate("%Z",tvu) or ""
end
--#if not DATE_OBJECT_AFX then
function date.time(h, r, s, t)
h, r, s, t = tonumber(h or 0), tonumber(r or 0), tonumber(s or 0), tonumber(t or 0)
if h and r and s and t then
return date_new(DAYNUM_DEF, makedayfrc(h, r, s, t))
else
return date_error_arg()
end
end
function date:__call(arg1, ...)
local arg_count = select("#", ...) + (arg1 == nil and 0 or 1)
if arg_count > 1 then return (date_from(arg1, ...))
elseif arg_count == 0 then return (date_getdobj(false))
else local o, r = date_getdobj(arg1); return r and o:copy() or o end
end
date.diff = dobj.__sub
function date.isleapyear(v)
local y = fix(v);
if not y then
y = date_getdobj(v)
y = y and y:getyear()
end
return isleapyear(y+0)
end
function date.epoch() return date_epoch:copy() end
function date.isodate(y,w,d) return date_new(makedaynum_isoywd(y + 0, w and (w+0) or 1, d and (d+0) or 1), 0) end
function date.setcenturyflip(y)
if y ~= floor(y) or y < 0 or y > 100 then date_error_arg() end
centuryflip = y
end
function date.getcenturyflip() return centuryflip end
-- Internal functions
function date.fmt(str) if str then fmtstr = str end; return fmtstr end
function date.daynummin(n) DAYNUM_MIN = (n and n < DAYNUM_MAX) and n or DAYNUM_MIN return n and DAYNUM_MIN or date_new(DAYNUM_MIN, 0):normalize()end
function date.daynummax(n) DAYNUM_MAX = (n and n > DAYNUM_MIN) and n or DAYNUM_MAX return n and DAYNUM_MAX or date_new(DAYNUM_MAX, 0):normalize()end
function date.ticks(t) if t then setticks(t) end return TICKSPERSEC end
--#end -- not DATE_OBJECT_AFX
local tm = osdate("!*t", 0);
if tm then
date_epoch = date_new(makedaynum(tm.year, tm.month - 1, tm.day), makedayfrc(tm.hour, tm.min, tm.sec, 0))
-- the distance from our epoch to os epoch in daynum
DATE_EPOCH = date_epoch and date_epoch:spandays()
else -- error will be raise only if called!
date_epoch = setmetatable({},{__index = function() error("failed to get the epoch date") end})
end
--#if not DATE_OBJECT_AFX then
VyHub.Lib.date = date
--#else
--$return date_from
--#end

View File

@@ -1,399 +0,0 @@
--[[
| 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/
--]]
VyHub.Lib.json = VyHub.Lib.json or {}
--
-- json.lua
--
-- Copyright (c) 2020 rxi
--
-- 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.
--
local json = { _version = "0.1.2" }
-------------------------------------------------------------------------------
-- Encode
-------------------------------------------------------------------------------
local encode
local escape_char_map = {
[ "\\" ] = "\\",
[ "\"" ] = "\"",
[ "\b" ] = "b",
[ "\f" ] = "f",
[ "\n" ] = "n",
[ "\r" ] = "r",
[ "\t" ] = "t",
}
local escape_char_map_inv = { [ "/" ] = "/" }
for k, v in pairs(escape_char_map) do
escape_char_map_inv[v] = k
end
local function escape_char(c)
return "\\" .. (escape_char_map[c] or string.format("u%04x", c:byte()))
end
local function encode_nil(val)
return "null"
end
local function encode_table(val, stack)
local res = {}
stack = stack or {}
-- Circular reference?
if stack[val] then error("circular reference") end
stack[val] = true
if rawget(val, 1) ~= nil or next(val) == nil then
-- Treat as array -- check keys are valid and it is not sparse
local n = 0
for k in pairs(val) do
if type(k) ~= "number" then
error("invalid table: mixed or invalid key types")
end
n = n + 1
end
if n ~= #val then
error("invalid table: sparse array")
end
-- Encode
for i, v in ipairs(val) do
table.insert(res, encode(v, stack))
end
stack[val] = nil
return "[" .. table.concat(res, ",") .. "]"
else
-- Treat as an object
for k, v in pairs(val) do
if type(k) ~= "string" then
error("invalid table: mixed or invalid key types")
end
table.insert(res, encode(k, stack) .. ":" .. encode(v, stack))
end
stack[val] = nil
return "{" .. table.concat(res, ",") .. "}"
end
end
local function encode_string(val)
return '"' .. val:gsub('[%z\1-\31\\"]', escape_char) .. '"'
end
local function encode_number(val)
-- Check for NaN, -inf and inf
if val ~= val or val <= -math.huge or val >= math.huge then
error("unexpected number value '" .. tostring(val) .. "'")
end
return string.format("%.14g", val)
end
local type_func_map = {
[ "nil" ] = encode_nil,
[ "table" ] = encode_table,
[ "string" ] = encode_string,
[ "number" ] = encode_number,
[ "boolean" ] = tostring,
}
encode = function(val, stack)
local t = type(val)
local f = type_func_map[t]
if f then
return f(val, stack)
end
error("unexpected type '" .. t .. "'")
end
function json.encode(val)
return ( encode(val) )
end
-------------------------------------------------------------------------------
-- Decode
-------------------------------------------------------------------------------
local parse
local function create_set(...)
local res = {}
for i = 1, select("#", ...) do
res[ select(i, ...) ] = true
end
return res
end
local space_chars = create_set(" ", "\t", "\r", "\n")
local delim_chars = create_set(" ", "\t", "\r", "\n", "]", "}", ",")
local escape_chars = create_set("\\", "/", '"', "b", "f", "n", "r", "t", "u")
local literals = create_set("true", "false", "null")
local literal_map = {
[ "true" ] = true,
[ "false" ] = false,
[ "null" ] = nil,
}
local function next_char(str, idx, set, negate)
for i = idx, #str do
if set[str:sub(i, i)] ~= negate then
return i
end
end
return #str + 1
end
local function decode_error(str, idx, msg)
local line_count = 1
local col_count = 1
for i = 1, idx - 1 do
col_count = col_count + 1
if str:sub(i, i) == "\n" then
line_count = line_count + 1
col_count = 1
end
end
error( string.format("%s at line %d col %d", msg, line_count, col_count) )
end
local function codepoint_to_utf8(n)
-- http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=iws-appendixa
local f = math.floor
if n <= 0x7f then
return string.char(n)
elseif n <= 0x7ff then
return string.char(f(n / 64) + 192, n % 64 + 128)
elseif n <= 0xffff then
return string.char(f(n / 4096) + 224, f(n % 4096 / 64) + 128, n % 64 + 128)
elseif n <= 0x10ffff then
return string.char(f(n / 262144) + 240, f(n % 262144 / 4096) + 128,
f(n % 4096 / 64) + 128, n % 64 + 128)
end
error( string.format("invalid unicode codepoint '%x'", n) )
end
local function parse_unicode_escape(s)
local n1 = tonumber( s:sub(1, 4), 16 )
local n2 = tonumber( s:sub(7, 10), 16 )
-- Surrogate pair?
if n2 then
return codepoint_to_utf8((n1 - 0xd800) * 0x400 + (n2 - 0xdc00) + 0x10000)
else
return codepoint_to_utf8(n1)
end
end
local function parse_string(str, i)
local res = ""
local j = i + 1
local k = j
while j <= #str do
local x = str:byte(j)
if x < 32 then
decode_error(str, j, "control character in string")
elseif x == 92 then -- `\`: Escape
res = res .. str:sub(k, j - 1)
j = j + 1
local c = str:sub(j, j)
if c == "u" then
local hex = str:match("^[dD][89aAbB]%x%x\\u%x%x%x%x", j + 1)
or str:match("^%x%x%x%x", j + 1)
or decode_error(str, j - 1, "invalid unicode escape in string")
res = res .. parse_unicode_escape(hex)
j = j + #hex
else
if not escape_chars[c] then
decode_error(str, j - 1, "invalid escape char '" .. c .. "' in string")
end
res = res .. escape_char_map_inv[c]
end
k = j + 1
elseif x == 34 then -- `"`: End of string
res = res .. str:sub(k, j - 1)
return res, j + 1
end
j = j + 1
end
decode_error(str, i, "expected closing quote for string")
end
local function parse_number(str, i)
local x = next_char(str, i, delim_chars)
local s = str:sub(i, x - 1)
local n = tonumber(s)
if not n then
decode_error(str, i, "invalid number '" .. s .. "'")
end
return n, x
end
local function parse_literal(str, i)
local x = next_char(str, i, delim_chars)
local word = str:sub(i, x - 1)
if not literals[word] then
decode_error(str, i, "invalid literal '" .. word .. "'")
end
return literal_map[word], x
end
local function parse_array(str, i)
local res = {}
local n = 1
i = i + 1
while 1 do
local x
i = next_char(str, i, space_chars, true)
-- Empty / end of array?
if str:sub(i, i) == "]" then
i = i + 1
break
end
-- Read token
x, i = parse(str, i)
res[n] = x
n = n + 1
-- Next token
i = next_char(str, i, space_chars, true)
local chr = str:sub(i, i)
i = i + 1
if chr == "]" then break end
if chr ~= "," then decode_error(str, i, "expected ']' or ','") end
end
return res, i
end
local function parse_object(str, i)
local res = {}
i = i + 1
while 1 do
local key, val
i = next_char(str, i, space_chars, true)
-- Empty / end of object?
if str:sub(i, i) == "}" then
i = i + 1
break
end
-- Read key
if str:sub(i, i) ~= '"' then
decode_error(str, i, "expected string for key")
end
key, i = parse(str, i)
-- Read ':' delimiter
i = next_char(str, i, space_chars, true)
if str:sub(i, i) ~= ":" then
decode_error(str, i, "expected ':' after key")
end
i = next_char(str, i + 1, space_chars, true)
-- Read value
val, i = parse(str, i)
-- Set
res[key] = val
-- Next token
i = next_char(str, i, space_chars, true)
local chr = str:sub(i, i)
i = i + 1
if chr == "}" then break end
if chr ~= "," then decode_error(str, i, "expected '}' or ','") end
end
return res, i
end
local char_func_map = {
[ '"' ] = parse_string,
[ "0" ] = parse_number,
[ "1" ] = parse_number,
[ "2" ] = parse_number,
[ "3" ] = parse_number,
[ "4" ] = parse_number,
[ "5" ] = parse_number,
[ "6" ] = parse_number,
[ "7" ] = parse_number,
[ "8" ] = parse_number,
[ "9" ] = parse_number,
[ "-" ] = parse_number,
[ "t" ] = parse_literal,
[ "f" ] = parse_literal,
[ "n" ] = parse_literal,
[ "[" ] = parse_array,
[ "{" ] = parse_object,
}
parse = function(str, idx)
local chr = str:sub(idx, idx)
local f = char_func_map[chr]
if f then
return f(str, idx)
end
decode_error(str, idx, "unexpected character '" .. chr .. "'")
end
function json.decode(str)
if type(str) ~= "string" then
error("expected argument of type string, got " .. type(str))
end
local res, idx = parse(str, next_char(str, 1, space_chars, true))
idx = next_char(str, idx, space_chars, true)
if idx <= #str then
decode_error(str, idx, "trailing garbage")
end
return res
end
VyHub.Lib.json = json

View File

@@ -1,57 +0,0 @@
--[[
| 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/
--]]
VyHub.Advert = VyHub.Advert or {}
VyHub.adverts = VyHub.adverts or {}
local current_advert = 0
function VyHub.Advert:refresh()
VyHub.API:get("/advert/", nil, { active = "true", serverbundle_id = VyHub.server.serverbundle.id }, function(code, result)
VyHub.adverts = result
end)
end
function VyHub.Advert:show(advert)
if advert then
local lines = string.Explode('\n', advert.content)
local color = VyHub.Util:hex2rgb(advert.color)
local prefix = VyHub.Config.advert_prefix
for _, line in ipairs(lines) do
VyHub.Util:print_chat_all(line, prefix, color)
end
end
end
function VyHub.Advert:next()
current_advert = current_advert + 1;
local advert = VyHub.adverts[current_advert];
if advert then
VyHub.Advert:show(advert)
else
current_advert = 0
end
end
hook.Add("vyhub_ready", "vyhub_advert_vyhub_ready", function ()
VyHub.Advert:refresh()
timer.Create("vyhub_advert_next", VyHub.Config.advert_interval, 0, function()
VyHub.Advert:next()
end)
timer.Create("vyhub_advert_refresh", 300, 0, function ()
VyHub.Advert:refresh()
end)
end)

View File

@@ -1,170 +0,0 @@
--[[
| 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 f = string.format
VyHub.API = VyHub.API or {}
local content_type = "application/json; charset=utf-8"
local json = VyHub.Lib.json
function VyHub.API:request(method, url, path_params, query, headers, request_body, type, success, failed, no_error_for)
no_error_for = no_error_for or {}
if path_params != nil then
url = f(url, unpack(path_params))
end
if istable(request_body) then
request_body = json.encode(request_body)
end
success_func = function(code, body, headers)
local result = body
if headers["Content-Type"] and headers["Content-Type"] == 'application/json' then
result = json.decode(body)
end
if code >= 200 and code < 300 then
VyHub:msg(f("HTTP %s %s (%s): %s", method, url, json.encode(query), code), "debug")
if success != nil then
-- VyHub:msg(f("Response: %s", body), "debug")
success(code, result, headers)
end
else
if not table.HasValue(no_error_for, code) then
local err_msg = f("HTTP %s %s: %s", method, url, code)
if query then
err_msg = err_msg .. f("\nQuery: %s", json.encode(query))
end
if request_body then
err_msg = err_msg .. f("\nBody: %s", request_body)
end
VyHub:msg(err_msg, "error")
if code < 500 and string.find( body:lower(), "html>" ) == nil then
VyHub:msg(f("Response: %s", body), "error")
end
end
if failed != nil then
local err_text = json.encode(result)
if istable(result) and result.detail != nil and result.detail.msg != nil then
err_text = f("%s (%s)", result.detail.msg, result.detail.code)
end
failed(code, result, headers, err_text)
end
end
end
failed_func = function(reason)
local err_msg = f("HTTP %s %s: %s", method, url, code)
if query then
err_msg = err_msg .. f("\nQuery: %s", json.encode(query))
end
if request_body then
err_msg = err_msg .. f("\nBody: %s", request_body)
end
VyHub:msg(err_msg, "error")
if failed != nil then
failed(0, reason, {})
end
end
HTTP({
method = method,
url = url,
parameters = query,
headers = headers,
body = request_body,
type = type,
success = success_func,
failed = failed_func,
})
end
function VyHub.API:get(endpoint, path_params, query, success, failed, no_error_for)
local url = f("%s%s", VyHub.API.url, endpoint)
VyHub.API:request("GET", url, path_params, query, self.headers, nil, content_type, success, failed, no_error_for)
end
function VyHub.API:delete(endpoint, path_params, success, failed)
local url = f("%s%s", VyHub.API.url, endpoint)
self:request("DELETE", url, path_params, nil, self.headers, nil, content_type, success, failed)
end
function VyHub.API:post(endpoint, path_params, body, success, failed, query)
local url = f("%s%s", VyHub.API.url, endpoint)
self:request("POST", url, path_params, query, self.headers, body, content_type, success, failed)
end
function VyHub.API:patch(endpoint, path_params, body, success, failed)
local url = f("%s%s", VyHub.API.url, endpoint)
self:request("PATCH", url, path_params, nil, self.headers, body, content_type, success, failed)
end
function VyHub.API:put(endpoint, path_params, body, success, failed)
local url = f("%s%s", VyHub.API.url, endpoint)
self:request("PUT", url, path_params, nil, self.headers, body, content_type, success, failed)
end
hook.Add("vyhub_loading_finish", "vyhub_api_vyhub_loading_finish", function()
if VyHub.Util:invalid_str({VyHub.Config.api_url, VyHub.Config.api_key, VyHub.Config.server_id}) then
VyHub:msg("API URL, Server ID or API Key not set! Please follow the manual.", "error")
timer.Simple(60, function ()
hook.Run("vyhub_loading_finish")
end)
return
end
VyHub.API.url = VyHub.Config.api_url
VyHub.API.headers = {
Authorization = f("Bearer %s", VyHub.Config.api_key)
}
if string.EndsWith(VyHub.API.url, "/") then
VyHub.API.url = string.sub(VyHub.API.url, 1, -2)
end
VyHub:msg(f("API URL is %s", VyHub.API.url))
VyHub.API:get("/openapi.json", nil, nil, function(code, result, headers)
VyHub:msg(f("Connection to API %s version %s successful!", result.info.title, result.info.version), "success")
hook.Run("vyhub_api_ready")
end, function()
VyHub:msg("Connection to API failed! Trying to use cache.", "error")
hook.Run("vyhub_api_failed")
end)
end)
concommand.Add("vh_reinit", function (ply)
if not VyHub.Util:is_server(ply) then return end
hook.Run("vyhub_loading_finish")
end)

File diff suppressed because it is too large Load Diff

View File

@@ -1,58 +0,0 @@
--[[
| 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 f = string.format
local json = VyHub.Lib.json
VyHub.Cache = VyHub.Cache or {}
function VyHub.Cache:save(key, value)
local data = {
timestamp = os.time(),
data = value
}
local filename = f("vyhub/%s.json", key)
local json = json.encode(data)
VyHub:msg("Write " .. filename .. ": " .. json, "debuga")
file.Write(filename, json)
end
function VyHub.Cache:get(key, max_age)
local path = f("vyhub/%s.json", key)
if not file.Exists(path, "data") then
return nil
end
local data_str = file.Read(path, "data")
if not string.Trim(data_str) then
return nil
end
local success, data = pcall(json.decode, data_str)
if not success then
return nil
end
if istable(data) and data.timestamp and data.data then
if max_age != nil and os.time() - data.timestamp > max_age then
return nil
end
return data.data
end
return nil
end

View File

@@ -1,75 +0,0 @@
--[[
| 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 f = string.format
hook.Add("vyhub_ready", "vyhub_commands_vyhub_ready", function ()
VyHub:get_frontend_url(function (url)
-- !shop
local function open_shop(ply, args)
if IsValid(ply) then
VyHub.Util:open_url(ply, f('%s/shop', url))
end
end
for _, cmd in ipairs(VyHub.Config.commands_shop) do
VyHub.Util:register_chat_command(cmd, open_shop)
end
-- !bans
local function open_bans(ply, args)
if IsValid(ply) then
VyHub.Util:open_url(ply, f('%s/bans', url))
end
end
for _, cmd in ipairs(VyHub.Config.commands_bans) do
VyHub.Util:register_chat_command(cmd, open_bans)
end
-- !warnings
local function open_warnings(ply, args)
if IsValid(ply) then
VyHub.Util:open_url(ply, f('%s/warnings', url))
end
end
for _, cmd in ipairs(VyHub.Config.commands_warnings) do
VyHub.Util:register_chat_command(cmd, open_warnings)
end
-- !news
local function open_news(ply, args)
if IsValid(ply) then
VyHub.Util:open_url(ply, f('%s/', url))
end
end
for _, cmd in ipairs(VyHub.Config.commands_news) do
VyHub.Util:register_chat_command(cmd, open_news)
end
-- !user
local function open_profile(ply, args)
if IsValid(ply) and args[1] then
other_ply = VyHub.Util:get_player_by_nick(args[1])
if IsValid(other_ply) then
VyHub.Util:open_url(ply, f('%s/profile/steam/%s', url, other_ply:SteamID64()))
end
end
end
for _, cmd in ipairs(VyHub.Config.commands_profile) do
VyHub.Util:register_chat_command(cmd, open_profile)
end
end)
end)

View File

@@ -1,88 +0,0 @@
--[[
| 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 f = string.format
function VyHub.Config:load_cache_config()
local ccfg = VyHub.Cache:get("config")
if ccfg != nil and #table.GetKeys(ccfg) > 0 then
VyHub.Config = table.Merge(VyHub.Config, ccfg)
VyHub:msg(f("Loaded cache config values: %s", table.concat(table.GetKeys(ccfg), ', ')))
end
end
concommand.Add("vh_setup", function (ply, _, args)
if not VyHub.Util:is_server(ply) then return end
if not args[1] or not args[2] or not args[3] then return end
local ccfg = VyHub.Cache:get("config")
if not istable(ccfg) then
ccfg = {}
end
ccfg["api_key"] = args[1]
ccfg["api_url"] = args[2]
ccfg["server_id"] = args[3]
VyHub.Cache:save("config", ccfg)
for key, value in pairs(ccfg) do
VyHub.Config[key] = value
end
VyHub:msg(f("Successfully set initial config, please wait up to one minute for VyHub to initialize (%s, %s, %s)", args[1], args[2], args[3]))
end)
concommand.Add("vh_config", function (ply, _, args)
if not VyHub.Util:is_server(ply) then return end
local ccfg = VyHub.Cache:get("config")
if not args[1] or not args[2] then
if istable(ccfg) then
VyHub:msg("Additional config options:")
PrintTable(ccfg)
else
VyHub:msg("No additional config options set.")
end
return
end
local key = args[1]
local value = args[2]
if not istable(ccfg) then
ccfg = {}
end
if value == "false" then
value = false
elseif value == "true" then
value = true
end
ccfg[key] = value
VyHub.Cache:save("config", ccfg)
VyHub.Config[key] = value
VyHub:msg(f("Successfully set config value %s.", key))
end)
concommand.Add("vh_config_reset", function (ply)
if not VyHub.Util:is_server(ply) then return end
VyHub.Cache:save("config", {})
VyHub:msg(f("Successfully cleared additional config.", key))
end)

View File

@@ -1,95 +0,0 @@
--[[
| 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 f = string.format
local json = VyHub.Lib.json
VyHub.Dashboard = VyHub.Dashboard or {}
VyHub.Dashboard.last_update = VyHub.Dashboard.last_update or {}
VyHub.Dashboard.data = VyHub.Dashboard.data or {}
util.AddNetworkString("vyhub_dashboard")
util.AddNetworkString("vyhub_dashboard_reload")
function VyHub.Dashboard:reset()
VyHub.Dashboard.data = {}
VyHub.Dashboard.last_update = {}
net.Start("vyhub_dashboard_reload")
net.Broadcast()
end
function VyHub.Dashboard:fetch_data(user_id, callback)
VyHub.API:get("/server/%s/user-activity?morph_user_id=%s", {VyHub.server.id, user_id}, nil, function(code, result)
callback(result)
end)
end
function VyHub.Dashboard:get_data(steamid64, callback)
if VyHub.Dashboard.data[steamid64] == nil or VyHub.Dashboard.last_update[steamid64] == nil or os.time() - VyHub.Dashboard.last_update[steamid64] > 30 then
VyHub.Player:get(steamid64, function (user)
if user then
VyHub.Dashboard:fetch_data(user.id, function (data)
VyHub.Dashboard.data[steamid64] = data
VyHub.Dashboard.last_update[steamid64] = os.time()
callback(VyHub.Dashboard.data[steamid64])
end)
end
end)
else
callback(VyHub.Dashboard.data[steamid64])
end
end
function VyHub.Dashboard:get_permissions(ply)
return {
warning_show = VyHub.Player:check_property(ply, 'warning_show'),
warning_edit = VyHub.Player:check_property(ply, 'warning_edit'),
warning_delete = VyHub.Player:check_property(ply, 'warning_delete'),
ban_show = VyHub.Player:check_property(ply, 'ban_show'),
ban_edit = VyHub.Player:check_property(ply, 'ban_edit'),
}
end
net.Receive("vyhub_dashboard", function(_, ply)
if not IsValid(ply) then return end
VyHub.Dashboard:get_data(ply:SteamID64(), function (users)
local users_json = json.encode(users)
local users_json_compressed = util.Compress(users_json)
local users_json_compressed_len = #users_json_compressed
local perms = VyHub.Dashboard:get_permissions(ply)
local perms_json = json.encode(perms)
net.Start("vyhub_dashboard")
net.WriteUInt(users_json_compressed_len, 16)
net.WriteData(users_json_compressed, users_json_compressed_len)
net.WriteString(perms_json)
net.Send(ply)
end)
end)
local function open_dashboard(ply, args)
if ply and IsValid(ply) then
ply:ConCommand("vh_dashboard")
end
end
hook.Add("vyhub_ready", "vyhub_dashboard_vyhub_ready", function ()
for _, cmd in ipairs(VyHub.Config.commands_dashboard) do
VyHub.Util:register_chat_command(cmd, open_dashboard)
end
end)
hook.Add("vyhub_dashboard_data_changed", "vyhub_dahboard_vyhub_dashboard_data_changed", function ()
VyHub.Dashboard:reset()
end)

View File

@@ -1,375 +0,0 @@
--[[
| 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 f = string.format
local json = VyHub.Lib.json
VyHub.Group = VyHub.Group or {}
VyHub.groups = VyHub.groups or nil
VyHub.groups_mapped = VyHub.groups_mapped or nil
VyHub.Group.group_changes = VyHub.Group.group_changes or {} -- dict(steamid64, groupname) of the last in-game group change (VyHub -> GMOD). Used to prevent loop.
util.AddNetworkString("vyhub_group_data")
local meta_ply = FindMetaTable("Player")
function VyHub.Group:refresh()
VyHub.API:get("/group/", nil, nil, function(code, result)
if result != VyHub.groups then
VyHub.groups = result
VyHub:msg(f("Found groups: %s", json.encode(result)), "debug")
VyHub.groups_mapped = {}
for _, group in ipairs(VyHub.groups) do
for _, mapping in ipairs(group.mappings) do
if mapping.serverbundle_id == nil or mapping.serverbundle_id == VyHub.server.serverbundle.id then
VyHub.groups_mapped[mapping.name] = group
break
end
end
end
VyHub.Group:send_groups()
end
end, function (code, reason)
VyHub:msg("Could not refresh groups.", "error")
end)
end
function VyHub.Group:send_groups(ply)
if not VyHub.groups_mapped then return end
local groups_to_send = VyHub.groups_mapped
net.Start("vyhub_group_data")
net.WriteUInt(table.Count(groups_to_send), 8)
for name_game, group in pairs(groups_to_send) do
net.WriteString(name_game)
net.WriteString(group.name)
net.WriteString(group.color)
end
if ply != nil and IsValid(ply) then
net.Send(ply)
else
net.Broadcast()
end
end
function VyHub.Group:set(steamid, groupname, seconds, processor_id, callback)
if seconds != nil and seconds == 0 then
seconds = nil
end
if VyHub.groups_mapped == nil then
VyHub:msg("Groups not initialized yet. Please try again later.", "error")
if callback then
callback(!VyHub.Config.strict_group_sync)
end
return
end
local group = VyHub.groups_mapped[groupname]
if group == nil then
VyHub:msg(f("Could not find VyHub group with name %s", groupname), "debug")
if callback then
callback(!VyHub.Config.strict_group_sync)
end
return
end
VyHub.Player:get(steamid, function (user)
if user == nil then
if callback then
callback(false)
return
end
end
local end_date = nil
if seconds != nil then
end_date = VyHub.Util:format_datetime(os.time() + seconds)
end
local url = '/user/%s/membership'
if processor_id != nil then
url = url .. '?morph_user_id=' .. processor_id
end
local ply = player.GetBySteamID64(steamid)
VyHub.API:post(url, {user.id}, {
begin = VyHub.Util.format_datetime(),
["end"] = end_date,
group_id = group.id,
serverbundle_id = VyHub.server.serverbundle.id
}, function (code, result)
VyHub:msg(f("Added membership in group %s for user %s.", groupname, steamid), "success")
if IsValid(ply) then
timer.Simple(5, function()
VyHub.Player:refresh(ply)
end)
end
if callback then
callback(true)
end
end, function (code, reason)
VyHub:msg(f("Could not add membership in group %s for user %s.", groupname, steamid), "error")
if callback then
callback(false)
end
if IsValid(ply) then
timer.Simple(2, function()
VyHub.Player:refresh(ply)
end)
end
end)
end)
end
function VyHub.Group:remove(steamid, processor_id, callback)
VyHub.Player:get(steamid, function (user)
if user == nil then
if callback then
callback(false)
return
end
end
local url = f('/user/%%s/membership?serverbundle_id=%s', VyHub.server.serverbundle.id)
if processor_id != nil then
url = url .. '&morph_user_id=' .. processor_id
end
VyHub.API:delete(url, {user.id}, function (code, result)
VyHub:msg(f("Removed %s from all groups.", steamid), "success")
local ply = player.GetBySteamID64(steamid)
if IsValid(ply) then
VyHub.Player:refresh(ply)
end
if callback then
callback(true)
end
end, function (code, reason)
VyHub:msg(f("Could not remove %s from all groups.", steamid), "error")
if callback then
callback(false)
end
end)
end)
end
function VyHub.Group:override_admin_mods()
if VyHub.Config.group_disable_sync then return end
local _setusergroup = meta_ply.SetUserGroup
if not ULib and not serverguard and not sam and not (xAdmin and xAdmin.Admin.RegisterBan) and not sAdmin then
hook.Remove("PlayerInitialSpawn", "PlayerAuthSpawn")
meta_ply.SetUserGroup = function(ply, name, ignore_vh)
if ply:GetUserGroup() == name then
VyHub:msg(ply:SteamID64() .. " already in group " .. name .. ". Ignoring change...")
return
end
local steamid = ply:SteamID64()
if not ignore_vh and VyHub.Group.group_changes[steamid] != name then
if VyHub.Group:set(steamid, name) or VyHub.Config.disable_group_check then
_setusergroup(ply, name)
end
else
_setusergroup(ply, name)
end
end
end
if xAdmin and xAdmin.Admin.RegisterBan then
local xadmin_setgroup = xAdmin.SetGroup
xAdmin.SetGroup = function(ply, group, ignore_vh)
local steamid32 = isstring(ply) and ply or ply:SteamID()
local steamid64 = util.SteamIDTo64(steamid32)
if not ignore_vh then
VyHub.Group:set(steamid64, group, nil, nil, function(success)
if success then
xadmin_setgroup( ply, group )
end
end)
else
xadmin_setgroup( ply, group )
end
end
end
if ULib then
local ulx_adduser = ULib.ucl.addUser
local ulx_removeuser = ULib.ucl.removeUser
ULib.ucl.addUser = function(steamid32, allow, deny, groupname, ignore_vh)
if not ignore_vh then
local steamid64 = util.SteamIDTo64(steamid32)
VyHub.Group:set(steamid64, groupname, nil, nil, function(success)
if success then
ulx_adduser( steamid32, allow, deny, groupname )
end
end)
else
ulx_adduser( steamid32, allow, deny, groupname )
end
end
ULib.ucl.removeUser = function(id)
local steamid64 = nil
if string.find(id, ":") then
steamid64 = util.SteamIDTo64(id)
else
local ply = player.GetByUniqueID(id)
if IsValid(ply) then
steamid64 = ply:SteamID64()
end
end
if steamid64 then
VyHub.Group:remove(steamid64, nil, function (success)
if success then
ulx_removeuser( id )
end
end)
end
end
end
if serverguard then
local servergaurd_setrank = serverguard.player["SetRank"]
function serverguard.player:SetRank(target, rank, length, ignore_vh)
if not ignore_vh then
if target then
if type(target) == "Player" and IsValid(target) then
VyHub.Group:set(target:SteamID64(), rank, nil, nil, function(success)
if success then
servergaurd_setrank(self, target, rank, length)
end
end)
elseif type(target) == "string" and string.match(target, "STEAM_%d:%d:%d+") then
local steamid = util.SteamIDTo64(target)
VyHub.Group:set(steamid, rank, nil, nil, function(success)
if success then
servergaurd_setrank(self, target, rank, length)
end
end)
end
end
else
servergaurd_setrank(self, target, rank, length)
end
end
end
if sam then
local sam_setrank = sam.player.set_rank
function sam.player.set_rank(ply, rank, length, ignore_vh)
if not ignore_vh then
if not sam.isnumber(length) or length < 0 then
length = nil
end
local seconds = nil
if length != nil then
seconds = math.Round(length * 60, 0)
end
VyHub.Group:set(ply:SteamID64(), rank, seconds, nil, function(success)
if success then
sam_setrank(ply, rank, length)
end
end)
else
sam_setrank(ply, rank, length)
end
end
end
if sAdmin then
local sadmin_setrank = sAdmin.setRank
sAdmin.setRank = function(ply, rank, expire, noupdate, ignore_vh)
rank = rank or "user"
if not ignore_vh and not noupdate then
local seconds = nil
if isnumber(expire) and expire > 0 then
seconds = math.max(expire, 0)
end
VyHub.Group:set(ply:SteamID64(), rank, seconds, nil, function(success)
if success then
sadmin_setrank(ply, rank, nil, noupdate)
end
end)
else
sadmin_setrank(ply, rank, expire, noupdate)
end
end
end
end
hook.Add("vyhub_ready", "vyhub_group_vyhub_ready", function ()
VyHub.Group:refresh()
timer.Create("vyhub_group_refresh", VyHub.Config.group_refresh_time, 0, function ()
VyHub.Group:refresh()
end)
hook.Add("vyhub_ply_connected", "vyhub_group_vyhub_ply_connected", function(ply)
VyHub.Group:send_groups(ply)
end)
concommand.Add("vh_setgroup", function(ply, _, args)
if VyHub.Util:is_server(ply) then
local steamid = args[1]
local group = args[2]
local bundle = args[3]
if steamid and group then
VyHub.Group:set(steamid, group)
end
end
end)
VyHub.Group:override_admin_mods()
end)

View File

@@ -1,92 +0,0 @@
--[[
| 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 f = string.format
VyHub.frontend_url = VyHub.frontend_url or nil
function VyHub:server_data_ready()
VyHub:msg(f("I am server %s in bundle %s.", VyHub.server.name, VyHub.server.serverbundle.name))
VyHub.ready = true
hook.Run("vyhub_ready")
end
function VyHub:get_frontend_url(callback)
if VyHub.frontend_url != nil then
if callback then
callback(VyHub.frontend_url)
end
return VyHub.frontend_url
end
VyHub.API:get('/general/frontend-url', nil, nil, function (code, result)
VyHub.frontend_url = result.frontend_url
VyHub.Cache:save('frontend_url', VyHub.frontend_url)
if callback then
callback(VyHub.frontend_url)
end
end, function ()
local frontend_url = VyHub.Cache:get('frontend_url')
if frontend_url == nil then
VyHub:msg("Could not get frontend_url!", "error")
end
if callback then
callback(frontend_url)
end
end)
end
hook.Add("vyhub_api_ready", "vyhub_main_vyhub_api_ready", function ()
VyHub.API:get("/server/%s", { VyHub.Config.server_id }, nil, function(code, result)
VyHub.server = result
VyHub:server_data_ready()
VyHub.Cache:save("server", VyHub.server)
end, function (code, result)
VyHub:msg(f("Could not find server with id %s", VyHub.Config.server_id), "error")
timer.Simple(60, function ()
hook.Run("vyhub_loading_finish")
end)
end)
VyHub:get_frontend_url()
end)
hook.Add("vyhub_api_failed", "vyhub_main_vyhub_api_failed", function ()
local server = VyHub.Cache:get("server", 604800)
if server != nil then
VyHub.server = server
VyHub:server_data_ready()
else
VyHub:msg("Could not find cached server data or cached data is too old. Please make sure that the server is able to reach the VyHub API.", "error")
timer.Simple(60, function ()
hook.Run("vyhub_loading_finish")
end)
end
end)
timer.Create("vyhub_not_ready_msg", 30, 0, function ()
if VyHub.ready then
timer.Remove("vyhub_not_ready_msg")
else
VyHub.Util:print_chat_all("<green>VyHub</green> is not ready. Please check the server log/console for errors.")
end
end)

View File

@@ -1,350 +0,0 @@
--[[
| 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 f = string.format
VyHub.Player = VyHub.Player or {}
VyHub.Player.connect_queue = VyHub.Player.connect_queue or {}
VyHub.Player.table = VyHub.Player.table or {}
util.AddNetworkString("vyhub_user_id")
local meta_ply = FindMetaTable("Player")
function VyHub.Player:initialize(ply, retry)
if not IsValid(ply) then return end
local steamid = ply:SteamID64()
VyHub:msg(f("Initializing user %s, %s", ply:Nick(), steamid))
VyHub.API:get("/user/%s", {steamid}, {type = "STEAM"}, function(code, result)
VyHub:msg(f("Found existing user %s for steam id %s (%s).", result.id, steamid, ply:Nick()), "success")
VyHub.Player.table[steamid] = result
VyHub.Player:refresh(ply)
VyHub.Player:send_user_id(ply)
hook.Run("vyhub_ply_initialized", ply)
local ply_timer_name = "vyhub_player_" .. steamid
timer.Create(ply_timer_name, VyHub.Config.player_refresh_time, 0, function()
if IsValid(ply) then
VyHub.Player:refresh(ply)
else
timer.Remove(ply_timer_name)
end
end)
end, function(code, reason)
if code != 404 then
VyHub:msg(f("Could not check if users %s exists. Retrying in a minute..", steamid), "error")
timer.Simple(60, function ()
VyHub.Player:initialize(ply)
end)
return
end
if retry then
VyHub:msg(f("Could not create user %s. Retrying in a minute..", steamid), "error")
timer.Simple(60, function()
VyHub.Player:initialize(ply)
end)
return
end
VyHub.Player:create(steamid, function()
VyHub.Player:initialize(ply, true)
end, function ()
VyHub.Player:initialize(ply, true)
end)
end, { 404 })
end
function VyHub.Player:send_user_id(ply)
if not IsValid(ply) then return end
ply:VyHubID(function (user_id)
net.Start("vyhub_user_id")
net.WriteString(user_id)
net.Send(ply)
end)
end
local creation_began = {}
local creation_success = {}
local creation_err = {}
function VyHub.Player:create(steamid, success, err)
-- Creation can take longer. If multiple creation requests occur, merge them to one.
if not istable(creation_success[steamid]) then creation_success[steamid] = {} end
if not istable(creation_err[steamid]) then creation_err[steamid] = {} end
table.insert(creation_success[steamid], success)
table.insert(creation_err[steamid], err)
if creation_began[steamid] and os.time() - creation_began[steamid] < 10 then
VyHub:msg(f("Queued creation request for steamid %s", steamid), "debug")
return
end
VyHub:msg(f("No existing user found for steam id %s. Creating..", steamid))
creation_began[steamid] = os.time()
local function reset_queue()
creation_began[steamid] = 0
creation_success[steamid] = {}
creation_err[steamid] = {}
end
VyHub.API:post('/user/', nil, { identifier = steamid, type = 'STEAM' }, function()
for _, success_callback in pairs(creation_success[steamid]) do
if success_callback then
success_callback()
end
end
reset_queue()
end, function()
for _, err_callback in pairs(creation_err[steamid]) do
if err_callback then
err_callback()
end
end
reset_queue()
end)
end
-- Return nil if steamid is nil or API error
-- Return false if steamid is false or could not create user
function VyHub.Player:get(steamid, callback, retry)
if steamid == nil then
callback(nil)
return
end
if steamid == false then
callback(false)
return
end
if VyHub.Player.table[steamid] != nil then
callback(VyHub.Player.table[steamid])
else
VyHub.API:get("/user/%s", {steamid}, {type = "STEAM"}, function(code, result)
VyHub:msg(f("Received user %s for steam id %s.", result.id, steamid), "debug")
VyHub.Player.table[steamid] = result
callback(result)
end, function(code)
VyHub:msg(f("Could not receive user %s.", steamid), "error")
if code == 404 and retry == nil then
VyHub.Player:create(steamid, function ()
VyHub.Player:get(steamid, callback, true)
end, function ()
callback(false)
end)
else
callback(nil)
end
end, {404})
end
end
function VyHub.Player:change_game_group(ply, group)
if not IsValid(ply) then return end
local steamid64 = ply:SteamID64()
local nick = ply:Nick()
VyHub.Group.group_changes[steamid64] = group
if serverguard then
serverguard.player:SetRank(ply, group, false, true)
elseif ulx then
ULib.ucl.addUser( ply:SteamID(), {}, {}, group, true )
elseif sam then
sam.player.set_rank(ply, group, 0, true)
elseif xAdmin and xAdmin.Admin.RegisterBan then
xAdmin.SetGroup(ply, group, true)
elseif sAdmin then
sAdmin.setRank(ply, group, 0, false, true)
else
ply:SetUserGroup(group, true)
end
VyHub:msg("Added " .. nick .. " to group " .. group, "success")
VyHub.Util:print_chat(ply, f(VyHub.lang.ply.group_changed, group))
end
function VyHub.Player:check_group(ply, callback)
if VyHub.Config.group_disable_sync then return end
if ply:VyHubID() == nil then
VyHub:msg(f("Could not check groups for user %s, because no VyHub id is available.", ply:SteamID64()), "debug")
return
end
VyHub.API:get("/user/%s/group", {ply:VyHubID()}, { serverbundle_id = VyHub.server.serverbundle_id }, function(code, result)
if not IsValid(ply) then return end
local steamid64 = ply:SteamID64()
local nick = ply:Nick()
local highest = nil
for _, group in ipairs(result) do
if highest == nil or highest.permission_level < group.permission_level then
highest = group
end
end
if highest == nil then
VyHub:msg(f("Could not find any active group for %s (%s)", nick, steamid64), "debug")
return
end
local group = nil
for _, mapping in ipairs(highest.mappings) do
if mapping.serverbundle_id == nil or mapping.serverbundle_id == VyHub.server.serverbundle.id then
group = mapping.name
break
end
end
if group == nil then
VyHub:msg(f("Could not find group name mapping for group %s.", highest.name), "debug")
return
end
local delay = 0
if sAdmin then
delay = 3
end
timer.Simple(delay, function ()
local curr_group = ply:GetUserGroup()
if curr_group != group then
VyHub.Player:change_game_group(ply, group)
end
end)
end, function()
end)
end
function VyHub.Player:refresh(ply, callback)
VyHub.Player:check_group(ply)
end
function VyHub.Player:get_group(ply)
if not IsValid(ply) then
return nil
end
local group = VyHub.groups_mapped[ply:GetUserGroup()]
if group == nil then
return nil
end
return group
end
function VyHub.Player:check_property(ply, property)
if not IsValid(ply) then return false end
local group = VyHub.Player:get_group(ply)
if group != nil then
local prop = group.properties[property]
if prop != nil and prop.granted then
return true
end
end
local steamid64 = ply:SteamID64()
if VyHub.Player.table[steamid64] then
return VyHub.Player.table[steamid64].admin
end
return false
end
function meta_ply:VyHubID(callback)
if IsValid(self) then
local user = VyHub.Player.table[self:SteamID64()]
local id = nil
if user != nil then
id = user.id
end
if id == nil or id == "" then
VyHub.Player:get(self:SteamID64(), function(user)
if user then
if callback then
callback(user.id)
end
else
if callback then
callback(nil)
end
end
end)
else
if callback then
callback(id)
end
end
return id
end
end
hook.Add("vyhub_ply_connected", "vyhub_ply_vyhub_ply_connected", function(ply)
VyHub.Player:initialize(ply)
end)
hook.Add("PlayerInitialSpawn","vyhub_ply_PlayerInitialSpawn", function(ply)
if IsValid(ply) and not ply:IsBot() then
if VyHub.ready then
hook.Run("vyhub_ply_connected", ply)
else
VyHub.Player.connect_queue[#VyHub.Player.connect_queue+1] = ply
end
end
end)
hook.Add("vyhub_ready", "vyhub_ply_vyhub_ready", function ()
timer.Simple(5, function()
for _, ply in ipairs(VyHub.Player.connect_queue) do
if IsValid(ply) then
hook.Run("vyhub_ply_connected", ply)
end
end
VyHub.Player.connect_queue = {}
end)
end)

View File

@@ -1,266 +0,0 @@
--[[
| 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 f = string.format
local json = VyHub.Lib.json
VyHub.Reward = VyHub.Reward or {}
VyHub.Reward.executed_rewards_queue = VyHub.Reward.executed_rewards_queue or {}
VyHub.Reward.executed_rewards = VyHub.Reward.executed_rewards or {}
VyHub.rewards = VyHub.rewards or {}
local RewardEvent = {
DIRECT = "DIRECT",
CONNECT = "CONNECT",
SPAWN = "SPAWN",
DEATH = "DEATH",
DISCONNECT = "DISCONNECT",
DISABLE = "DISABLE",
}
local RewardType = {
COMMAND = "COMMAND",
SCRIPT = "SCRIPT",
CREDITS = "CREDITS",
MEMBERSHIP = "MEMBERSHIP",
}
function VyHub.Reward:refresh(callback, limit_players, err)
local user_ids = ""
local players = limit_players or player.GetHumans()
for _, ply in ipairs(players) do
if IsValid(ply) then
local id = ply:VyHubID()
if id and string.len(id) == 36 then
local glue = '&'
if user_ids == "" then
glue = '?'
end
user_ids = user_ids .. glue .. 'user_id=' .. id
end
end
end
if user_ids == "" then
VyHub.rewards = {}
else
local query = f("%s&active=true&serverbundle_id=%s&status=OPEN&for_server_id=%s&foreign_ids=true", user_ids, VyHub.server.serverbundle.id, VyHub.server.id)
VyHub.API:get('/packet/reward/applied/user' .. query, nil, nil,
function(code, result)
if limit_players == nil then
VyHub.rewards = result
VyHub:msg(f("Found %i users with open rewards.", table.Count(result)), "debug")
else
for steamid, arewards in pairs(result) do
VyHub.rewards[steamid] = arewards
end
end
if callback then
callback()
end
end, function (code, reason)
if err then
err()
end
end)
end
end
function VyHub.Reward:set_executed(areward_id)
VyHub.Reward.executed_rewards_queue[areward_id] = true
table.insert(VyHub.Reward.executed_rewards, areward_id)
VyHub.Reward:save_executed()
end
function VyHub.Reward:save_executed()
VyHub.Cache:save("executed_rewards_queue", VyHub.Reward.executed_rewards_queue)
end
function VyHub.Reward:send_executed()
for areward_id, val in pairs(VyHub.Reward.executed_rewards_queue) do
if val != nil then
VyHub.API:patch('/packet/reward/applied/%s', { areward_id }, { executed_on = { VyHub.server.id } }, function (code, result)
VyHub.Reward.executed_rewards_queue[areward_id] = nil
VyHub.Reward:save_executed()
end, function (code, reason)
if code >= 400 and code < 500 then
VyHub:msg(f("Could not mark reward %s as executed. Aborting.", areward_id), "error")
VyHub.Reward.executed_rewards_queue[areward_id] = nil
VyHub.Reward:save_executed()
end
end)
end
end
end
function VyHub.Reward:exec_rewards(event, steamid)
steamid = steamid or nil
local allowed_events = { event }
local rewards_by_player = VyHub.rewards
if steamid != nil then
rewards_by_player = {}
rewards_by_player[steamid] = VyHub.rewards[steamid]
else
if event != RewardEvent.DIRECT then
return
end
end
if event == RewardEvent.DIRECT then
table.insert(allowed_events, RewardEvent.DISABLE)
end
for steamid, arewards in pairs(rewards_by_player) do
local ply = player.GetBySteamID64(steamid)
if not IsValid(ply) then
VyHub:msg(f("Player %s not valid, skipping.", steamid), "debug")
continue
end
for _, areward in ipairs(arewards) do
local se = true
local reward = areward.reward
if not table.HasValue(allowed_events, reward.on_event) then
continue
end
if table.HasValue(VyHub.Reward.executed_rewards, areward.id) then
VyHub:msg(f("Skipped reward %s, because it already has been executed.", areward.id), "debug")
continue
end
local data = reward.data
if reward.type == RewardType.COMMAND then
if data.command != nil then
local cmd = VyHub.Reward:do_string_replacements(data.command, ply, areward)
if VyHub.Config.reward_command_whitelist and #VyHub.Config.reward_command_whitelist > 0 then
local matched = false
for _, cmd_pattern in ipairs(VyHub.Config.reward_command_whitelist) do
if string.match(cmd, cmd_pattern) != nil then
matched = true
break
end
end
if not matched then
VyHub:msg(f("Failed to execute reward '%s': Command '%s' does not match a command on the whitelist.", reward.name, cmd), "error")
continue
end
end
game.ConsoleCommand(cmd.. "\n")
end
elseif reward.type == RewardType.SCRIPT then
if VyHub.Config.reward_disable_scripts then
VyHub:msg(f("Failed to execute reward '%s': Scripts are not allowed on this server. You can enable scripts in sv_config.lua or by entering 'vh_config reward_disable_scripts false' in the server console.", reward.name), "error")
continue
end
local lua_str = data.script
if lua_str != nil then
lua_str = VyHub.Reward:do_string_replacements(lua_str, ply, areward)
RunString("local PLAYER = player.GetBySteamID64(\"" .. steamid .. "\") " .. lua_str, "vyhub_reward_script")
end
else
VyHub:msg(f("No implementation for reward type %s", reward.type) "warning")
end
VyHub:msg(f("Executed reward %s for user %s (%s): %s", reward.type, ply:Nick(), ply:SteamID64(), json.encode(data)))
if se and reward.once then
VyHub.Reward:set_executed(areward.id)
end
end
end
VyHub.Reward:send_executed()
end
function VyHub.Reward:do_string_replacements(inp_str, ply, areward)
local purchase_amount = "-"
if areward.applied_packet.purchase != nil then
purchase_amount = areward.applied_packet.purchase.amount_text
end
local replacements = {
["user_id"] = ply:VyHubID(),
["nick"] = ply:Nick(),
["steamid64"] = ply:SteamID64(),
["steamid32"] = ply:SteamID(),
["uniqueid"] = ply:UniqueID(),
["applied_packet_id"] = areward.applied_packet_id,
["packet_title"] = areward.applied_packet.packet.title,
["purchase_amount"] = purchase_amount,
}
for k, v in pairs(replacements) do
inp_str = string.Replace(tostring(inp_str), "%" .. tostring(k) .. "%", tostring(v))
end
return inp_str
end
hook.Add("vyhub_ready", "vyhub_reward_vyhub_ready", function ()
VyHub.Reward.executed_rewards_queue = VyHub.Cache:get("executed_rewards_queue") or {}
VyHub.Reward:refresh(function ()
VyHub.Reward:exec_rewards(RewardEvent.DIRECT)
end)
timer.Create("vyhub_reward_refresh", 60, 0, function ()
VyHub.Reward:refresh(function ()
VyHub.Reward:exec_rewards(RewardEvent.DIRECT)
end)
end)
hook.Add("vyhub_ply_initialized", "vyhub_reward_vyhub_ply_initialized", function(ply)
local function exec_ply_rewards()
VyHub.Reward:exec_rewards(RewardEvent.CONNECT, tostring(ply:SteamID64()))
hook.Run("vyhub_reward_post_connect", ply)
end
VyHub.Reward:refresh(exec_ply_rewards, { ply }, exec_ply_rewards)
end)
hook.Add("PlayerSpawn", "vyhub_reward_PlayerSpawn", function(ply)
if ply:Alive() then
VyHub.Reward:exec_rewards(RewardEvent.SPAWN, tostring(ply:SteamID64()))
end
end)
hook.Add("PostPlayerDeath", "vyhub_reward_PostPlayerDeath", function(ply)
VyHub.Reward:exec_rewards(RewardEvent.DEATH, tostring(ply:SteamID64()))
end)
-- Does not work
hook.Add("PlayerDisconnect", "vyhub_reward_PlayerDisconnect", function(ply)
if IsValid(ply) then
VyHub.Reward:exec_rewards(RewardEvent.Disconnect, tostring(ply:SteamID64()))
end
end)
end)

View File

@@ -1,157 +0,0 @@
--[[
| 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 f = string.format
local json = VyHub.Lib.json
VyHub.Server = VyHub.Server or {}
VyHub.Server.extra_defaults = {
res_slots = 0,
res_slots_keep_free = false,
res_slots_hide = false,
}
VyHub.Server.reserved_slot_plys = VyHub.Server.reserved_slot_plys or {}
function VyHub.Server:get_extra(key)
if VyHub.server.extra != nil and VyHub.server.extra[key] != nil then
return VyHub.server.extra[key]
end
return VyHub.Server.extra_defaults[key]
end
function VyHub.Server:update_status()
local user_activities = {}
for _, ply in ipairs(player.GetHumans()) do
local id = ply:VyHubID()
if id and string.len(id) == 36 then
local tt = string.FormattedTime( ply:TimeConnected() )
table.insert(user_activities, { user_id = id, extra = {
Score = ply:Frags(),
Deaths = ply:Deaths(),
Nickname = ply:Nick(),
Playtime = f('%02d:%02d:%02d', tt.h, tt.m, tt.s),
Ping = f('%i ms', ply:Ping()),
}})
end
end
local data = {
users_max = VyHub.Server.max_slots_visible,
users_current = #player.GetAll(),
map = game.GetMap(),
is_alive = true,
user_activities = user_activities,
}
VyHub:msg(f("Updating status: %s", json.encode(data)), "debug")
VyHub.API:patch(
'/server/%s',
{VyHub.server.id},
data,
function ()
hook.Run("vyhub_dashboard_data_changed")
end,
function ()
VyHub:msg("Could not update server status.", "error")
end
)
end
function VyHub.Server:update_max_slots()
RunConsoleCommand("sv_visiblemaxplayers", VyHub.Server.max_slots_visible)
end
function VyHub.Server:init_slots()
VyHub.Server.max_slots = game.MaxPlayers() - VyHub.Server:get_extra("res_slots")
VyHub.Server.max_slots_visible = VyHub.Server.max_slots
if VyHub.Server:get_extra("res_slots_hide") then
VyHub.Server:update_max_slots()
hook.Add("PlayerDisconnected", "vyhub_server_PlayerDisconnected", function(ply)
timer.Create("vyhub_slots", 0.5, 20, function()
if not IsValid(ply) then
timer.Remove("vyhub_slots")
VyHub.Server:update_max_slots()
end
end)
end)
else
VyHub.Server.max_slots_visible = game.MaxPlayers()
end
end
function VyHub.Server:can_use_rslot(ply)
if not IsValid(ply) or ply:IsBot() then
return false
end
if table.HasValue(VyHub.Server.reserved_slot_plys, ply:SteamID64()) then
return true
end
local group = VyHub.Player:get_group(ply)
if group != nil then
if group.properties.reserved_slot_use != nil then
return group.properties.reserved_slot_use.granted
end
end
return false
end
function VyHub.Server:handle_ply_connect(ply)
if IsValid(ply) then
if #player.GetHumans() > VyHub.Server.max_slots then
if VyHub.Server:can_use_rslot(ply) then
if VyHub.Server:get_extra("res_slots_keep_free") then
local tokick = nil
for _, v in ipairs(player.GetHumans()) do
if v:SteamID64() != ply:SteamID64() and not VyHub.Server:can_use_rslot(v) then
if tokick == nil or (IsValid(tokick) and v:TimeConnected() < tokick:TimeConnected()) then
tokick = v
end
end
end
if tokick and IsValid(tokick) then
tokick:Kick(VyHub.lang.rslots.kick)
else
ply:Kick(VyHub.lang.rslots.full)
end
end
else
ply:Kick(VyHub.lang.rslots.full_no_slot)
end
end
end
end
hook.Add("vyhub_ready", "vyhub_server_vyhub_ready", function ()
VyHub.Server:init_slots()
VyHub.Server:update_status()
timer.Create("vyhub_status_update", 60, 0, function ()
VyHub.Server:update_status()
end)
hook.Add("vyhub_reward_post_connect", "vyhub_server_vyhub_reward_post_connect", function (ply)
VyHub.Server:handle_ply_connect(ply)
end)
end)

View File

@@ -1,143 +0,0 @@
--[[
| 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 f = string.format
local json = VyHub.Lib.json
VyHub.Statistic = VyHub.Statistic or {}
VyHub.Statistic.playtime = VyHub.Statistic.playtime or {}
VyHub.Statistic.attr_def = VyHub.Statistic.attr_def or nil
function VyHub.Statistic:save_playtime()
VyHub:msg(f("Saved playtime statistics: %s", json.encode(VyHub.Statistic.playtime)), "debug")
VyHub.Cache:save("playtime", VyHub.Statistic.playtime)
end
function VyHub.Statistic:add_one_minute()
for _, ply in ipairs(player.GetHumans()) do
local steamid = ply:SteamID64()
ply:VyHubID(function (user_id)
if user_id == nil or string.len(user_id) < 10 then
VyHub:msg(f("Could not add playtime for user %s", steamid))
return
end
VyHub.Statistic.playtime[user_id] = VyHub.Statistic.playtime[user_id] or 0
VyHub.Statistic.playtime[user_id] = VyHub.Statistic.playtime[user_id] + 60
end)
end
VyHub.Statistic:save_playtime()
end
function VyHub.Statistic:send_playtime()
VyHub.Statistic:get_or_create_attr_definition(function (attr_def)
if attr_def == nil then
VyHub:msg("Could not send playtime statistics to API.", "warning")
return
end
local user_ids = table.GetKeys(VyHub.Statistic.playtime)
timer.Create("vyhub_send_stats", 0.3, table.Count(user_ids), function ()
local i = table.Count(user_ids)
local user_id = user_ids[i]
if user_id != nil then
local seconds = VyHub.Statistic.playtime[user_id]
table.remove(user_ids, i)
if seconds != nil and seconds > 0 then
local hours = math.Round(seconds / 60 / 60, 2)
if hours > 0 then
if string.len(user_id) < 10 then
VyHub.Statistic.playtime[user_id] = nil
return
end
VyHub.API:post("/user/attribute/", nil, {
definition_id = attr_def.id,
user_id = user_id,
serverbundle_id = VyHub.server.serverbundle.id,
value = tostring(hours),
}, function (code, result)
VyHub.Statistic.playtime[user_id] = nil
VyHub.Statistic:save_playtime()
end, function (code, reason)
if code == 404 then
VyHub.Statistic.playtime[user_id] = nil
VyHub.Statistic:save_playtime()
end
VyHub:msg(f("Could not send %s seconds playtime of %s to API.", seconds, user_id), "warning")
end)
end
else
VyHub.Statistic.playtime[user_id] = nil
end
end
end)
end)
end
function VyHub.Statistic:get_or_create_attr_definition(callback)
local function cb_wrapper(attr_def)
VyHub.Statistic.attr_def = attr_def
callback(attr_def)
end
if VyHub.Statistic.attr_def != nil then
callback(VyHub.Statistic.attr_def)
return
end
VyHub.API:get("/user/attribute/definition/%s", { "playtime" }, nil, function (code, result)
VyHub.Cache:save("playtime_attr_def", result)
cb_wrapper(result)
end, function (code, reason)
if code != 404 then
local attr_def = VyHub.Cache:get("playtime_attr_def")
cb_wrapper(attr_def)
else
VyHub.API:post("/user/attribute/definition/", nil, {
name = "playtime",
title = "Play Time",
unit = "Hours",
type = "ACCUMULATED",
accumulation_interval = "day",
unspecific = "true",
}, function (code, result)
VyHub.Cache:save("playtime_attr_def", result)
cb_wrapper(result)
end, function (code, reason)
cb_wrapper(nil)
end)
end
end)
end
hook.Add("vyhub_ready", "vyhub_statistic_vyhub_ready", function ()
VyHub.Statistic.playtime = VyHub.Cache:get("playtime") or {}
VyHub.Statistic:send_playtime()
timer.Create("vyhub_statistic_playtime_tick", 60, 0, function ()
VyHub.Statistic:add_one_minute()
end)
timer.Create("vyhub_statistic_send_playtime", 3600, 0, function ()
VyHub.Statistic:send_playtime()
end)
end)

View File

@@ -1,183 +0,0 @@
--[[
| 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 f = string.format
VyHub.Warning = VyHub.Warning or {}
function VyHub.Warning:create(steamid, reason, processor_steamid)
processor_steamid = processor_steamid or nil
VyHub.Player:get(steamid, function (user)
if user == nil then
VyHub.Util:print_chat_steamid(processor_steamid, f("<red>Cannot find VyHub user with SteamID %s.</red>", steamid))
return
end
VyHub.Player:get(processor_steamid, function (processor)
if processor_steamid != nil and processor == nil then
return
end
local url = '/warning/'
if processor != nil then
url = url .. f('?morph_user_id=%s', processor.id)
end
VyHub.API:post(url, nil, {
reason = reason,
serverbundle_id = VyHub.server.serverbundle.id,
user_id = user.id
}, function (code, result)
VyHub.Ban:refresh()
VyHub:msg(f("Added warning for player %s: %s", user.username, reason))
VyHub.Util:print_chat_all(f(VyHub.lang.warning.user_warned, user.username, processor.username, reason))
VyHub.Util:print_chat_steamid(steamid, f(VyHub.lang.warning.received, processor.username, reason))
VyHub.Util:play_sound_steamid(steamid, "https://cdn.vyhub.net/sound/negativebeep.wav")
hook.Run("vyhub_dashboard_data_changed")
end, function (code, err_reason, _, err_text)
VyHub:msg(f("Error while adding warning for player %s: %s", user.username, err_text), "error")
VyHub.Util:print_chat_steamid(processor_steamid, f(VyHub.lang.warning.create_error, user.username, err_text))
end)
end)
end)
end
function VyHub.Warning:delete(warning_id, processor_steamid)
processor_steamid = processor_steamid or nil
VyHub.Player:get(processor_steamid, function (processor)
if not processor then return end
local url = '/warning/%s'
if processor != nil then
url = url .. f('?morph_user_id=%s', processor.id)
end
VyHub.API:delete(url, { warning_id }, function (code, result)
VyHub:msg(f("%s deleted warning %s.", processor.username, warning_id))
VyHub.Util:print_chat_steamid(processor_steamid, f(VyHub.lang.warning.deleted))
VyHub.Util:print_chat_steamid(steamid, VyHub.lang.warning.deleted_self)
hook.Run("vyhub_dashboard_data_changed")
end, function (code, err_reason, _, err_text)
VyHub:msg(f("Error while deleteing warning %s: %s", warning_id, err_text), "error")
VyHub.Util:print_chat_steamid(processor_steamid, f(VyHub.lang.other.error_api, err_text))
end)
end)
end
function VyHub.Warning:toggle(warning_id, processor_steamid)
processor_steamid = processor_steamid or nil
VyHub.Player:get(processor_steamid, function (processor)
if not processor then return end
local url = '/warning/%s/toggle'
if processor != nil then
url = url .. f('?morph_user_id=%s', processor.id)
end
VyHub.API:patch(url, { warning_id }, nil, function (code, result)
VyHub:msg(f("%s toggled warning %s.", processor.username, warning_id))
VyHub.Util:print_chat_steamid(processor_steamid, f(VyHub.lang.warning.toggled))
VyHub.Util:print_chat_steamid(steamid, VyHub.lang.warning.toggled_self)
hook.Run("vyhub_dashboard_data_changed")
end, function (code, err_reason, _, err_text)
VyHub:msg(f("Error while toggling status of warning %s: %s", warning_id, err_text), "error")
VyHub.Util:print_chat_steamid(processor_steamid, f(VyHub.lang.other.error_api, err_text))
end)
end)
end
local function warn_command(ply, args)
if not VyHub.Player:check_property(ply, "warning_edit") then
VyHub.Util:print_chat(ply, VyHub.lang.ply.no_permissions)
return
end
if args[1] and args[2] then
local reason = VyHub.Util:concat_args(args, 2)
local target = VyHub.Util:get_player_by_nick(args[1])
if target and IsValid(target) then
local nickparts = string.Explode(' ', target:Nick())
if #nickparts > 1 then
nickparts = VyHub.Util:concat_args(nickparts, 2) .. ' '
reason = string.Replace(reason, nickparts, '')
end
VyHub.Warning:create(target:SteamID64(), reason, ply:SteamID64())
end
end
if IsValid(ply) then
VyHub.Util:print_chat(ply, VyHub.lang.warning.cmd_help)
end
return false;
end
hook.Add("vyhub_ready", "vyhub_warning_vyhub_ready", function ()
concommand.Add("vh_warn", function(ply, _, args)
if not args[1] or not args[2] then return end
if VyHub.Util:is_server(ply) then
VyHub.Warning:create(args[1], args[2])
elseif IsValid(ply) then
if VyHub.Player:check_property(ply, "warning_edit") then
VyHub.Warning:create(args[1], args[2], ply:SteamID64())
else
VyHub.Util:print_chat(ply, VyHub.lang.ply.no_permissions)
end
end
end)
concommand.Add("vh_warning_toggle", function(ply, _, args)
if not args[1] then return end
local warning_id = args[1]
if VyHub.Util:is_server(ply) then
VyHub.Warning:toggle(warning_id)
elseif IsValid(ply) then
if VyHub.Player:check_property(ply, "warning_edit") then
VyHub.Warning:toggle(warning_id, ply:SteamID64())
else
VyHub.Util:print_chat(ply, VyHub.lang.ply.no_permissions)
end
end
end)
concommand.Add("vh_warning_delete", function(ply, _, args)
if not args[1] then return end
local warning_id = args[1]
if VyHub.Util:is_server(ply) then
VyHub.Warning:delete(warning_id)
elseif IsValid(ply) then
if VyHub.Player:check_property(ply, "warning_delete") then
VyHub.Warning:delete(warning_id, ply:SteamID64())
else
VyHub.Util:print_chat(ply, VyHub.lang.ply.no_permissions)
end
end
end)
for _, cmd in ipairs(VyHub.Config.commands_warn) do
VyHub.Util:register_chat_command(cmd, warn_command)
end
end)

View File

@@ -1,43 +0,0 @@
--[[
| 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/
--]]
-- DEFAULTS
VyHub.Config.date_format = VyHub.Config.date_format or "%Y-%m-%d %H:%M:%S %z"
if SERVER then
VyHub.Config.advert_interval = VyHub.Config.advert_interval or 180
VyHub.Config.advert_prefix = VyHub.Config.advert_prefix or "[★] "
-- Do not allow too small refresh intervals
if VyHub.Config.player_refresh_time < 5 then
VyHub.Config.player_refresh_time = 5
end
if VyHub.Config.group_refresh_time < 5 then
VyHub.Config.group_refresh_time = 5
end
VyHub.Config.ban_message = VyHub.Config.ban_message or ">>> Ban Message <<<" .. "\n\n"
.. VyHub.lang.other.reason .. ": %reason%" .. "\n"
.. VyHub.lang.other.ban_date .. ": %ban_date%" .. "\n"
.. VyHub.lang.other.unban_date .. ": %unban_date%" .. "\n"
.. VyHub.lang.other.admin .. ": %admin%" .. "\n"
.. VyHub.lang.other.id .. ": %id%" .. "\n\n"
.. VyHub.lang.other.unban_url .. ": %unban_url%" .. "\n\n"
VyHub.Config.commands_shop = VyHub.Config.commands_shop or { '!shop' }
VyHub.Config.commands_bans = VyHub.Config.commands_bans or { '!bans' }
VyHub.Config.commands_warnings = VyHub.Config.commands_warnings or { '!warnings' }
VyHub.Config.commands_news = VyHub.Config.commands_news or { '!news' }
VyHub.Config.commands_profile = VyHub.Config.commands_profile or { '!user' }
VyHub.Config.commands_warn = VyHub.Config.commands_warn or { '!warn' }
VyHub.Config.commands_dashboard = VyHub.Config.commands_dashboard or { '!dashboard' }
VyHub.Config.strict_group_sync = VyHub.Config.strict_group_sync or false
end

View File

@@ -1,19 +0,0 @@
--[[
| 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/
--]]
VyHub.Group = VyHub.Group or {}
function VyHub.Group:get(groupname)
if VyHub.groups_mapped == nil then
return nil
end
return VyHub.groups_mapped[groupname]
end

View File

@@ -1,110 +0,0 @@
--[[
| 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 f = string.format
local json = VyHub.Lib.json
VyHub.Lang = VyHub.Lang or {}
VyHub.lang = VyHub.lang or nil
if SERVER then
util.AddNetworkString("vyhub_lang")
VyHub.Lang.compressed = VyHub.Lang.compressed or nil
function VyHub.Lang:load()
local f_en = file.Open("vyhub/lang/en.json", "r", "LUA")
if f_en == nil then
VyHub:msg("Missing language file en.json!!! PLEASE MAKE SURE TO DOWNLOAD VYHUB-GMOD ON THE GITHUB RELESES PAGE! https://github.com/matbyte-com/vyhub-gmod/releases", "error")
return
end
local en = json.decode(f_en:Read())
f_en:Close()
if not istable(en) then
VyHub:msg("Could not load language file en.json!", "error")
return
end
VyHub.lang = en
VyHub:msg("Loaded language en.")
if VyHub.Config.lang != 'en' then
local f_custom = file.Open(f("vyhub/lang/%s.json", VyHub.Config.lang), "r", "LUA")
if f_custom != nil then
local custom = json.decode(f_custom:Read())
f_custom:Close()
if istable(custom) then
table.Merge(VyHub.lang, custom)
VyHub:msg(f("Loaded language %s.", VyHub.Config.lang))
else
VyHub:msg(f("Could not load language file %s.json!", VyHub.Config.lang), "warning")
end
else
VyHub:msg(f("Missing language file %s.json.", VyHub.Config.lang), "warning")
end
end
VyHub.Lang.compressed = util.Compress(json.encode(VyHub.lang))
end
if VyHub.lang == nil then
VyHub.Lang:load()
end
net.Receive("vyhub_lang", function(_, ply)
if not IsValid(ply) then return end
if not VyHub.Lang.compressed then return end
local len = #VyHub.Lang.compressed
net.Start("vyhub_lang")
net.WriteUInt(len, 16)
net.WriteData(VyHub.Lang.compressed, len)
net.Send(ply)
end)
end
if CLIENT then
function VyHub.Lang:load()
net.Start("vyhub_lang")
net.SendToServer()
end
net.Receive("vyhub_lang", function()
timer.Remove("vyhub_lang_load")
local len = net.ReadUInt(16)
local lang_compr = net.ReadData(len)
VyHub.lang = json.decode(util.Decompress(lang_compr))
VyHub:msg("Loaded language.")
hook.Run("vyhub_lang_loaded")
end)
hook.Add("Initialize", "vyhub_lang_Initialize", function ()
VyHub.Lang:load()
timer.Create("vyhub_lang_load", 5, 5, function ()
if VyHub.lang == nil then
VyHub.Lang:load()
else
timer.Remove("vyhub_lang_load")
end
end)
end)
end

View File

@@ -1,322 +0,0 @@
--[[
| 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 f = string.format
local date = VyHub.Lib.date
VyHub.Util = VyHub.Util or {}
VyHub.Util.chat_commands = VyHub.Util.chat_commands or {}
if SERVER then
util.AddNetworkString("vyhub_print_chat")
util.AddNetworkString("vyhub_play_sound")
util.AddNetworkString("vyhub_open_url")
end
function VyHub.Util:format_datetime(unix_timestamp)
unix_timestamp = unix_timestamp or os.time()
local tz_wrong = os.date("%z", unix_timestamp)
local timezone = f("%s:%s", string.sub(tz_wrong, 1, 3), string.sub(tz_wrong, 4, 5))
return os.date("%Y-%m-%dT%H:%M:%S" .. timezone, unix_timestamp)
end
function VyHub.Util:is_server(obj)
if type(obj) == "Entity" and (obj.EntIndex and obj:EntIndex() == 0) and !IsValid(obj) then
return true
else
return false
end
end
function VyHub.Util:iso_to_unix_timestamp(datetime)
if datetime == nil then return nil end
local pd = date(datetime)
if pd == nil then return nil end
local time = os.time(
{
year = pd:getyear(),
month = pd:getmonth(),
day = pd:getday(),
hour = pd:gethours(),
minute = pd:getminutes(),
second = pd:getseconds(),
}
)
return time
end
function VyHub.Util:get_ply_by_nick(nick)
nick = string.lower(nick);
for _, v in ipairs(player.GetHumans()) do
if(string.find(string.lower(v:Name()), nick, 1, true) != nil)
then return v;
end
end
end
function VyHub.Util:register_chat_command(strCommand, Func)
if !strCommand || !Func then return end
for k, v in pairs( VyHub.Util.chat_commands ) do
if( strCommand == k ) then
return
end
end
VyHub.Util.chat_commands[ tostring( strCommand ) ] = Func;
end
function VyHub.Util:concat_args(args, pos)
local toconcat = {}
if pos > 1 then
for i = pos, #args, 1 do
toconcat[#toconcat+1] = args[i]
end
end
return string.Implode(" ", toconcat)
end
if SERVER then
hook.Add("PlayerSay", "vyhub_util_PlayerSay", function(ply, message)
if VyHub.ready then
local chat_string = string.Explode(" ", message)
local ret = nil
for k, v in pairs( VyHub.Util.chat_commands ) do
if( string.lower(chat_string[1]) == string.lower(k) ) then
table.remove(chat_string, 1)
ret = v(ply, chat_string)
break
end
end
if ret != nil then
return ret
end
end
end)
end
local colors = {
red = Color(255, 24, 35),
green = Color(45, 170, 0),
blue = Color(0, 115, 204),
yellow = Color(229, 221, 0),
pink = Color(229, 0, 218),
}
-- Takes a str message with colors and returns a table
function VyHub.Util:replace_colors(message, no_color)
local resultTable = {}
local currentIndex = 1
local function getColor(colorName)
if colors[colorName] then
return colors[colorName]
else
return no_color
end
end
local function addStringToTable(str, color)
table.insert(resultTable, color)
table.insert(resultTable, str)
end
local tags = {}
-- Extract all color tags and their corresponding content
for tag, content in string.gmatch(message, "<([%l]+)>([^<]+)</%1>") do
table.insert(tags, {tag = tag, content = content})
end
-- Process the string, splitting it based on the color tags
for _, tagData in ipairs(tags) do
local startIndex, endIndex = string.find(message, f("<(%s)>[^<]+</%s>", string.PatternSafe(tagData.tag), string.PatternSafe(tagData.tag)), currentIndex, false)
if startIndex then
local str = string.sub(message, currentIndex, startIndex - 1)
addStringToTable(str, no_color)
addStringToTable(tagData.content, getColor(tagData.tag))
currentIndex = endIndex + 1
end
end
-- Append any remaining part of the string
local str = string.sub(message, currentIndex)
if str != "" then
addStringToTable(str, no_color)
end
return resultTable
end
local color_tag = Color(0, 187, 255)
function VyHub.Util:print_chat(ply, message, tag, color)
color = color or color_white
if SERVER then
if IsValid(ply) then
if not VyHub.Config.chat_tag then
VyHub.Config.chat_tag = "[VyHub] "
end
if not tag then
tag = VyHub.Config.chat_tag
end
message = string.Replace(message, '\r', '')
message = string.Replace(message, '\n', '')
net.Start("vyhub_print_chat")
net.WriteString(message)
net.WriteString(tag)
net.WriteColor(color)
net.Send(ply)
end
elseif CLIENT then
msg_table = VyHub.Util:replace_colors(message, color)
chat.AddText(color_tag, tag, color_white, unpack(msg_table))
end
end
function VyHub.Util:print_chat_steamid(steamid, message, tag, color)
if steamid != nil and steamid != false then
local ply = player.GetBySteamID64(steamid)
if IsValid(ply) then
VyHub.Util:print_chat(ply, message, tag, color)
end
end
end
function VyHub.Util:play_sound_steamid(steamid, url)
if steamid then
local ply = player.GetBySteamID64(steamid)
if IsValid(ply) then
return VyHub.Util:play_sound(ply, url)
end
end
end
function VyHub.Util:play_sound(ply, url)
if SERVER then
if IsValid(ply) then
net.Start("vyhub_play_sound")
net.WriteString(url)
net.Send(ply)
end
elseif CLIENT then
sound.PlayURL ( url, "", function() end)
end
end
function VyHub.Util:open_url(ply, url)
if SERVER then
if IsValid(ply) then
net.Start("vyhub_open_url")
net.WriteString(url)
net.Send(ply)
end
elseif CLIENT then
gui.OpenURL(url)
end
end
function VyHub.Util:print_chat_all(message, tag, color)
for _, ply in ipairs(player.GetHumans()) do
VyHub.Util:print_chat(ply, message, tag, color)
end
end
function VyHub.Util:get_player_by_nick(nick)
nick = string.lower(nick);
for _,v in ipairs(player.GetHumans()) do
if(string.find(string.lower(v:Name()), nick, 1, true) != nil)
then return v;
end
end
end
function VyHub.Util:hex2rgb(hex)
hex = hex:gsub("#","")
if(string.len(hex) == 3) then
return Color(tonumber("0x"..hex:sub(1,1)) * 17, tonumber("0x"..hex:sub(2,2)) * 17, tonumber("0x"..hex:sub(3,3)) * 17)
elseif(string.len(hex) == 6) then
return Color(tonumber("0x"..hex:sub(1,2)), tonumber("0x"..hex:sub(3,4)), tonumber("0x"..hex:sub(5,6)))
else
return color_white
end
end
function VyHub.Util:iso_ts_to_local_str(iso_ts)
local bias = VyHub.Config.time_offset != nil and -math.Round(VyHub.Config.time_offset * 60 * 60) or nil
return date(iso_ts):setbias(bias):tolocal():fmt(VyHub.Config.date_format)
end
function VyHub.Util:invalid_str(str_list)
for _, str in ipairs(str_list) do
if str == nil or string.Trim(str) == "" then
return true
end
end
return false
end
function VyHub.Util:escape_concommand_str(str)
str = string.Replace(str, '"', "'")
return str
end
if CLIENT then
net.Receive("vyhub_print_chat", function ()
local message = net.ReadString()
local tag = net.ReadString()
local color = net.ReadColor()
VyHub.Util:print_chat(nil, message, tag, color)
end)
net.Receive("vyhub_play_sound", function ()
local url = net.ReadString()
VyHub.Util:play_sound(nil, url)
end)
net.Receive("vyhub_open_url", function ()
local url = net.ReadString()
VyHub.Util:open_url(nil, url)
end)
end

View File

@@ -1,143 +0,0 @@
--[[
| 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/
--]]
--[[
__ ___ __ __
/ |/ /__ ____/ /__ / / __ __
/ /|_/ / _ `/ _ / -_) / _ \/ // /
/_/ /_/\_,_/\_,_/\__/ /_.__/\_, /
___ __ /___/ ___ __
/ _ \___ / /_ _____ ___ / /____ ____ / _ \__ ______/ /__
/ ___/ _ \/ / // / -_|_-</ __/ -_) __/ / // / // / __/ '_/
/_/ \___/_/\_, /\__/___/\__/\__/_/ /____/\_,_/\__/_/\_\
/___/
https://steamcommunity.com/profiles/76561198057599363
]]
CreateClientConVar("cl_weapon_holsters", "1", true, false, "Enable Weapon Holsters (client side)")
WepHolster = WepHolster or {}
WepHolster.wepInfo = WepHolster.wepInfo or {}
net.Receive("sendWholeWHData", function(len)
WepHolster.wepInfo = net.ReadTable()
end)
net.Receive("sendWHData", function(len)
local class = net.ReadString()
local tbl = net.ReadTable()
WepHolster.wepInfo[class] = tbl.Model and tbl or nil
if not tbl.Model then
for pl, weps in pairs(WepHolster.HolsteredWeps) do
local ply = Entity(pl)
for cls, wep in pairs(weps) do
if cls == class then
wep:Remove()
WepHolster.HolsteredWeps[pl][cls] = nil
end
end
end
end
end)
WepHolster.HolsteredWeps = WepHolster.HolsteredWeps or {}
local function CalcOffset(pos, ang, off)
return pos + ang:Right() * off.x + ang:Forward() * off.y + ang:Up() * off.z
end
local function cdwh()
return WepHolster.wepInfo and WepHolster.HolsteredWeps and GetConVar("cl_weapon_holsters"):GetBool() and GetConVar("sv_weapon_holsters"):GetBool()
end
hook.Add("PostPlayerDraw", "WeaponHolster", function(ply)
if not cdwh() then
return
end
if IsValid(ply) and ply:Alive() then
for wepclass, model in pairs(WepHolster.HolsteredWeps[ply:EntIndex()] or {}) do
if not WepHolster.wepInfo[wepclass] then
return
end
local bone = ply:LookupBone(WepHolster.wepInfo[wepclass].Bone)
if not bone then
return
end
local matrix = ply:GetBoneMatrix(bone)
if not matrix then
return
end
local pos = matrix:GetTranslation()
local ang = matrix:GetAngles()
pos = CalcOffset(pos, ang, WepHolster.wepInfo[wepclass].BoneOffset[1])
model:SetRenderOrigin(pos)
ang:RotateAroundAxis(ang:Forward(), WepHolster.wepInfo[wepclass].BoneOffset[2].p)
ang:RotateAroundAxis(ang:Up(), WepHolster.wepInfo[wepclass].BoneOffset[2].y)
ang:RotateAroundAxis(ang:Right(), WepHolster.wepInfo[wepclass].BoneOffset[2].r)
model:SetRenderAngles(ang)
model:DrawModel()
end
end
end)
hook.Add("Think", "WeaponHolster", function()
if not cdwh() then
return
end
for _, ply in pairs(player.GetAll()) do
if IsValid(ply) and ply:Alive() then
for k, v in pairs(ply:GetWeapons()) do
local class = v:GetClass()
local plyid = ply:EntIndex()
WepHolster.HolsteredWeps[plyid] = WepHolster.HolsteredWeps[plyid] or {}
if WepHolster.wepInfo[class] and ply:GetActiveWeapon() ~= v and not WepHolster.HolsteredWeps[plyid][class] then
WepHolster.HolsteredWeps[plyid][class] = ClientsideModel(WepHolster.wepInfo[class].Model, RENDERGROUP_OPAQUE)
if not IsValid(WepHolster.HolsteredWeps[plyid][class]) then
SafeRemoveEntity(WepHolster.HolsteredWeps[plyid][class]) -- just in case.
WepHolster.HolsteredWeps[plyid][class] = nil
return
end
WepHolster.HolsteredWeps[plyid][class]:SetNoDraw(true)
if WepHolster.wepInfo[class].isEditing then
WepHolster.HolsteredWeps[plyid][class]:SetMaterial("models/wireframe")
--print("wireframe화 think")
--print(WepHolster.wepInfo[class].isEditing)
end
end
end
end
end
-- 필요없는 CSEnt 찾아서 삭제
for pl, weps in pairs(WepHolster.HolsteredWeps) do
local ply = Entity(pl)
for class, wep in pairs(weps) do
if not IsValid(ply) or not ply:IsPlayer() or not ply:Alive() or (IsValid(ply:GetActiveWeapon()) and ply:GetActiveWeapon():GetClass() == class) or not IsValid(ply:GetWeapon(class)) then
wep:Remove() -- 삭제
WepHolster.HolsteredWeps[pl][class] = nil
return
end
end
end
end)

View File

@@ -1,678 +0,0 @@
--[[
| 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/
--]]
--[[
__ ___ __ __
/ |/ /__ ____/ /__ / / __ __
/ /|_/ / _ `/ _ / -_) / _ \/ // /
/_/ /_/\_,_/\_,_/\__/ /_.__/\_, /
___ __ /___/ ___ __
/ _ \___ / /_ _____ ___ / /____ ____ / _ \__ ______/ /__
/ ___/ _ \/ / // / -_|_-</ __/ -_) __/ / // / // / __/ '_/
/_/ \___/_/\_, /\__/___/\__/\__/_/ /____/\_,_/\__/_/\_\
/___/
https://steamcommunity.com/profiles/76561198057599363
]]
local Menu = {
Main = {},
Editor = {}
}
local playerBones = {"ValveBiped.Bip01_Head1", "ValveBiped.Bip01_Pelvis", "ValveBiped.Bip01_Spine", "ValveBiped.Bip01_Spine1", "ValveBiped.Bip01_Spine2", "ValveBiped.Bip01_Spine4", "ValveBiped.Anim_Attachment_RH", "ValveBiped.Bip01_R_Hand", "ValveBiped.Bip01_R_Forearm", "ValveBiped.Bip01_R_UpperArm", "ValveBiped.Bip01_R_Clavicle", "ValveBiped.Bip01_R_Foot", "ValveBiped.Bip01_R_Toe0", "ValveBiped.Bip01_R_Thigh", "ValveBiped.Bip01_R_Calf", "ValveBiped.Bip01_R_Shoulder", "ValveBiped.Bip01_R_Elbow", "ValveBiped.Bip01_Neck1", "ValveBiped.Anim_Attachment_LH", "ValveBiped.Bip01_L_Hand", "ValveBiped.Bip01_L_Forearm", "ValveBiped.Bip01_L_UpperArm", "ValveBiped.Bip01_L_Clavicle", "ValveBiped.Bip01_L_Foot", "ValveBiped.Bip01_L_Toe0", "ValveBiped.Bip01_L_Thigh", "ValveBiped.Bip01_L_Calf", "ValveBiped.Bip01_L_Shoulder", "ValveBiped.Bip01_L_Elbow"}
local function KeyboardOn(pnl)
if (IsValid(Menu.Main.Frame) and IsValid(pnl) and pnl:HasParent(Menu.Main.Frame)) then
Menu.Main.Frame:SetKeyboardInputEnabled(true)
end
end
hook.Add("OnTextEntryGetFocus", "lf_weapon_properties_editor_keyboard_on", KeyboardOn)
local function KeyboardOff(pnl)
if (IsValid(Menu.Main.Frame) and IsValid(pnl) and pnl:HasParent(Menu.Main.Frame)) then
Menu.Main.Frame:SetKeyboardInputEnabled(false)
if pnl.OnValueChange then
pnl:OnValueChange()
end
end
end
hook.Add("OnTextEntryLoseFocus", "lf_weapon_properties_editor_keyboard_off", KeyboardOff)
-- Blur Code by: https://facepunch.com/member.php?u=237675
local blur = Material("pp/blurscreen")
local function DrawBlur(panel, amount)
local x, y = panel:LocalToScreen(0, 0)
local scrW, scrH = ScrW(), ScrH()
surface.SetDrawColor(255, 255, 255)
surface.SetMaterial(blur)
for i = 1, 3 do
blur:SetFloat("$blur", (i / 3) * (amount or 6))
blur:Recompute()
render.UpdateScreenEffectTexture()
surface.DrawTexturedRect(x * -1, y * -1, scrW, scrH)
end
end
local function removeHolstWep(class)
for pl, weps in pairs(WepHolster.HolsteredWeps) do
for cls, wep in pairs(weps) do
if class == "" or cls == class then
wep:Remove()
WepHolster.HolsteredWeps[pl][cls] = nil
end
end
end
end
local function setEditing(class, bool)
if class ~= "" then
if WepHolster.wepInfo[class] then
WepHolster.wepInfo[class].isEditing = bool
end
else
for k, v in pairs(WepHolster.wepInfo) do
WepHolster.wepInfo[k].isEditing = bool
end
end
for pl, weps in pairs(WepHolster.HolsteredWeps) do
for cls, wep in pairs(weps) do
if cls == class or class == "" then
if bool then
wep:SetMaterial("models/wireframe")
--print("wireframe화 gui")
--print(WepHolster.wepInfo[cls].isEditing)
--print("wireframe 해제 gui")
--print(WepHolster.wepInfo[cls].isEditing)
else
wep:Remove()
WepHolster.HolsteredWeps[pl][cls] = nil
WepHolster.wepInfo[cls].isEditing = nil
end
end
end
end
end
function Menu.Editor:Init(class)
local Frame = vgui.Create("DFrame", Menu.Main.Frame)
local fw, fh = 600, 350
local pw, ph = fw - 10, fh - 34
Frame:SetPos(ScrW() - fw - 10, (ScrH() / 2) - (fh / 2))
Frame:SetSize(fw, fh)
Frame:SetTitle(class)
Frame:SetVisible(true)
Frame:SetDraggable(true)
Frame:SetScreenLock(false)
Frame:ShowCloseButton(true)
Frame:MakePopup()
Frame:SetKeyboardInputEnabled(false)
function Frame:Paint(w, h)
DrawBlur(self, 2)
draw.RoundedBox(0, 0, 0, w, h, Color(0, 0, 0, 200))
return true
end
function Frame.lblTitle:Paint(w, h)
draw.SimpleTextOutlined(Frame.lblTitle:GetText(), "DermaDefaultBold", 1, 2, Color(255, 255, 255, 255), 0, 0, 1, Color(0, 0, 0, 255))
return true
end
local pnl = Frame:Add("DPanel")
pnl:Dock(FILL)
pnl:DockPadding(10, 10, 10, 10)
local prop = pnl:Add("DCategoryList")
prop:Dock(FILL)
local function AddLineText(list, text, val, class)
local line = list:Add("DPanel")
line:DockPadding(5, 2, 5, 2)
line:SetDrawBackground(false)
local id
if val then
local lbl = line:Add("DLabel")
lbl:Dock(LEFT)
lbl:SetWide(239)
lbl:SetDark(true)
lbl:SetText(text)
id = line:Add("DTextEntry")
id:Dock(FILL)
id:SetText(val or "")
else
local lbl = line:Add("DLabel")
lbl:Dock(FILL)
lbl:SetText(text)
end
return line, id
end
local function AddLineInt(list, text, val, min, max)
local line = list:Add("DPanel")
line:DockPadding(5, 2, 5, 2)
line:SetPaintBackground(false)
local id
if val then
id = line:Add("DNumSlider")
id:Dock(FILL)
id:SetDark(true)
id:SetDecimals(3)
id:SetMinMax(min, max)
id:SetText(text)
id:SetValue(val or 0)
else
local lbl = line:Add("DLabel")
lbl:Dock(FILL)
lbl:SetText(text)
end
return line, id
end
local cat = prop:Add(class)
local list = vgui.Create("DListLayout")
cat:SetContents(list)
local line, rModel = AddLineText(list, "Model:", WepHolster.wepInfo[class].Model, class)
rModel.OnValueChange = function(val)
val = rModel:GetValue()
WepHolster.wepInfo[class].Model = val
setEditing(class, true)
removeHolstWep(class)
end
local line, rBone = AddLineText(list, "Bone:", WepHolster.wepInfo[class].Bone)
WepHolster.lookingBone = WepHolster.wepInfo[class].Bone
if rBone then
rBone.OnValueChange = function(val)
val = rBone:GetValue()
if table.HasValue(playerBones, val) then
WepHolster.wepInfo[class].Bone = val
setEditing(class, true)
WepHolster.lookingBone = val
end
end
local c = line:Add("DComboBox")
c:Dock(RIGHT)
c:SetWide(40)
c:SetSortItems(false)
c:SetValue("...")
for _, v in pairs(playerBones) do
c:AddChoice(v)
end
function c:OnSelect(index, value)
rBone:SetText(value)
rBone:OnValueChange()
c:SetValue("...")
end
end
local line, rVectorX = AddLineInt(list, "Position x:", WepHolster.wepInfo[class].BoneOffset[1].x, -20, 20, class)
rVectorX.OnValueChanged = function(value)
WepHolster.wepInfo[class].BoneOffset[1].x = rVectorX:GetValue()
setEditing(class, true)
end
local line, rVectorY = AddLineInt(list, "Position y:", WepHolster.wepInfo[class].BoneOffset[1].y, -20, 20, class)
rVectorY.OnValueChanged = function(value)
WepHolster.wepInfo[class].BoneOffset[1].y = rVectorY:GetValue()
setEditing(class, true)
end
local line, rVectorZ = AddLineInt(list, "Position z:", WepHolster.wepInfo[class].BoneOffset[1].z, -20, 20, class)
rVectorZ.OnValueChanged = function(value)
WepHolster.wepInfo[class].BoneOffset[1].z = rVectorZ:GetValue()
setEditing(class, true)
end
local line, rAngleP = AddLineInt(list, "Angle pitch:", WepHolster.wepInfo[class].BoneOffset[2].p, -180, 180, class)
rAngleP.OnValueChanged = function(value)
WepHolster.wepInfo[class].BoneOffset[2].p = rAngleP:GetValue()
setEditing(class, true)
end
local line, rAngleY = AddLineInt(list, "Angle yaw:", WepHolster.wepInfo[class].BoneOffset[2].y, -180, 180, class)
rAngleY.OnValueChanged = function(value)
WepHolster.wepInfo[class].BoneOffset[2].y = rAngleY:GetValue()
setEditing(class, true)
end
local line, rAngleR = AddLineInt(list, "Angle roll:", WepHolster.wepInfo[class].BoneOffset[2].r, -180, 180, class)
rAngleR.OnValueChanged = function(value)
WepHolster.wepInfo[class].BoneOffset[2].r = rAngleR:GetValue()
setEditing(class, true)
end
local subpnl = pnl:Add("DPanel")
subpnl:Dock(BOTTOM)
subpnl:DockMargin(0, 20, 0, 0)
subpnl:SetHeight(20)
subpnl:SetDrawBackground(false)
local lw = (pw - 10) / 2 - 10
local b = subpnl:Add("DComboBox")
b:Dock(LEFT)
b:SetWide(lw)
b:SetValue("Reset")
b:SetSortItems(false)
b:AddChoice("to saved data if available")
b:AddChoice("to default if available")
b.OnSelect = function(index, value, data)
Frame:Close()
if value == 2 then
local oldwhdata = WepHolster.wepInfo[class]
net.Start("resetWHDataToDefault")
net.WriteString(class)
net.SendToServer()
timer.Simple(0.1, function()
local different
for k, v in pairs(WepHolster.wepInfo[class]) do
if (k == "Model" or k == "Bone") and string.lower(oldwhdata[k]) ~= string.lower(v) then
different = true
print(k .. ": " .. v)
-- print(_..": "..vec_ang)
elseif k == "BoneOffset" then
for _, vec_ang in pairs(v) do
if vec_ang ~= oldwhdata[k][_] then
different = true
end
end
end
end
-- '==' operator is not working on table.. fuck.
if different then
setEditing(class, true)
end
end)
elseif not WepHolster.wepInfo[class].notSavedYet then
net.Start("reloadWH")
net.WriteString(class)
net.SendToServer()
setEditing(class, false)
end
timer.Simple(0.1, function()
Menu.Editor:Init(class)
removeHolstWep(class)
end)
end
local b = subpnl:Add("DComboBox")
b:Dock(RIGHT)
b:SetWide(lw)
b:SetValue("Delete")
b:AddChoice("Are you sure?")
b.OnSelect = function(index, value, data)
net.Start("deleteWHData")
net.WriteString(class)
net.SendToServer()
timer.Simple(0.1, function()
Menu.Main.Frame:Close()
Menu.Main:Init()
end)
end
local b = pnl:Add("DButton")
b:Dock(BOTTOM)
b:DockMargin(0, 10, 0, 0)
b:SetHeight(30)
b:SetText("Apply Changes")
b.DoClick = function()
setEditing(class, false)
WepHolster.wepInfo[class].notSavedYet = nil
net.Start("applyWepHolsterData")
net.WriteString(class)
net.WriteTable(WepHolster.wepInfo[class])
net.SendToServer()
Frame:Close()
end
Frame.OnClose = function()
--[[
net.Start("reloadWH")
net.WriteString(class)
net.SendToServer()
Menu.Main.Frame:Close()
timer.Simple(0.1, function()
removeHolstWep(class)
Menu.Main:Init()
end)
]]
WepHolster.lookingBone = nil
end
end
local function addWeapon(class, model)
WepHolster.wepInfo[class] = WepHolster.wepInfo[class] or {
Model = model or "models/weapons/w_rif_ak47.mdl",
Bone = "ValveBiped.Bip01_R_Clavicle",
BoneOffset = {Vector(13, 4, 5), Angle(90, 0, 100)},
notSavedYet = true
}
Menu.Main.Frame:Close()
Menu.Main:Init()
Menu.Editor:Init(class)
setEditing(class, true)
end
function Menu.Main:Init()
Menu.Main.Frame = vgui.Create("DFrame")
local Frame = Menu.Main.Frame
local fw, fh = 400, ScrH() - 20
local pw, ph = fw - 10, fh - 34
Frame:SetPos(10, 10)
Frame:SetSize(fw, fh)
Frame:SetTitle("Weapon Holsters Editor")
Frame:SetVisible(true)
Frame:SetDraggable(true)
Frame:SetScreenLock(false)
Frame:ShowCloseButton(true)
Frame:MakePopup()
Frame:SetKeyboardInputEnabled(false)
function Frame:Paint(w, h)
DrawBlur(self, 2)
draw.RoundedBox(0, 0, 0, w, h, Color(0, 0, 0, 200))
return true
end
function Frame.lblTitle:Paint(w, h)
draw.SimpleTextOutlined(Frame.lblTitle:GetText(), "DermaDefaultBold", 1, 2, Color(255, 255, 255, 255), 0, 0, 1, Color(0, 0, 0, 255))
return true
end
local pnl = Frame:Add("DPanel")
pnl:Dock(FILL)
pnl:DockPadding(10, 10, 10, 10)
local b = pnl:Add("DButton")
b:Dock(TOP)
b:DockMargin(0, 0, 0, 1)
b:SetHeight(25)
b:SetText("Add weapon by class:")
b.DoClick = function()
local name = tostring(Menu.Main.WeaponEntry:GetValue())
if name == "" then
return
end
addWeapon(name)
end
Menu.Main.WeaponEntry = pnl:Add("DTextEntry")
Menu.Main.WeaponEntry:Dock(TOP)
Menu.Main.WeaponEntry:DockMargin(0, 0, 0, 10)
Menu.Main.WeaponEntry:SetHeight(20)
Menu.Main.WeaponEntry:SetTooltip("Just right-click on the weapon icon in the spawn menu, click Copy to Clipboard, and paste it here.")
--[[
local help = pnl:Add("DLabel") -- Fuck you, I'll use SetTooltip instead.
help:Dock(TOP)
help:DockMargin(0, 0, 0, 10)
help:SetHeight(26)
help:SetText("Just right-click on the weapon icon in the spawn menu,\nclick Copy to Clipboard, and paste it here.")
]]
b = pnl:Add("DButton")
b:Dock(TOP)
b:DockMargin(0, 0, 0, 10)
b:SetHeight(24)
b:SetText("Add weapon you currently holding")
b.DoClick = function()
local weapon = LocalPlayer():GetActiveWeapon()
if IsValid(weapon) then
addWeapon(weapon:GetClass(), weapon:GetWeaponWorldModel())
end
end
--[[
local help = pnl:Add("DLabel")
help:Dock(TOP)
help:DockMargin(0, 0, 0, 5)
help:SetHeight(13)
help:SetText("Click the bar to sort the list, and double click the weapon to edit:")
]]
Menu.Main.WeaponList = pnl:Add("DListView")
Menu.Main.WeaponList:Dock(FILL)
Menu.Main.WeaponList:SetMultiSelect(false)
Menu.Main.WeaponList:AddColumn("Category")
Menu.Main.WeaponList:AddColumn("Name")
Menu.Main.WeaponList:AddColumn("Class")
Menu.Main.WeaponList:SetTooltip("Click the bar to sort the list, and double click the weapon to edit.")
function Menu.Main.WeaponList:DoDoubleClick(id, sel)
local wepclass = tostring(sel:GetValue(3))
if WepHolster.wepInfo[wepclass] then
Menu.Editor:Init(wepclass)
end
end
function Menu.Main.WeaponList:Populate()
self:Clear()
for k, v in pairs(WepHolster.wepInfo) do
local swep = weapons.Get(k)
self:AddLine(swep and swep.Category or "Other", swep and swep.PrintName or WepHolster.HL2Weps[k] or k, k)
end
self:SortByColumn(1)
end
Menu.Main.WeaponList:Populate()
local credit = pnl:Add("DLabel")
credit:Dock(BOTTOM)
credit:DockMargin(0, 10, 0, 0)
credit:SetHeight(13)
credit:SetText("Made by Polyester Duck")
local b = pnl:Add("DComboBox")
b:Dock(BOTTOM)
b:DockMargin(0, 10, 0, 0)
b:SetHeight(20)
b:SetValue("RESET EVERYTHING TO DEFAULT")
b:AddChoice("ARE YOU REALLY SURE?")
b.OnSelect = function(index, value, data)
setEditing("", false)
net.Start("resetWholeWHDataToDefault")
net.SendToServer()
Frame:Close()
timer.Simple(0.1, Menu.Main.Init)
end
Frame.OnClose = function()
--[[
net.Start("reloadWholeWH")
net.SendToServer()
for pl, weps in pairs(WepHolster.HolsteredWeps) do
for cls, wep in pairs(weps) do
wep:Remove()
WepHolster.HolsteredWeps[pl][cls] = nil
end
end
]]
WepHolster.lookingBone = nil
end
end
function Menu.Toggle()
if LocalPlayer():IsSuperAdmin() then
if IsValid(Menu.Main.Frame) then
Menu.Main.Frame:Close()
else
Menu.Main:Init()
end
else
if IsValid(Menu.Main.Frame) then
Menu.Main.Frame:Close()
end
end
end
concommand.Add("weapon_holsters_editor", Menu.Toggle)
local function clientTrickBox(panel, con_name, func_onchange)
local con = GetConVar(con_name)
if not con then
return
end
local tickbox = vgui.Create("DCheckBoxLabel", panel)
tickbox:SetText(con:GetHelpText() or "Unknown setting.")
tickbox:SetValue(con:GetBool())
tickbox.con_name = con_name
tickbox:SetDark(true)
function tickbox:OnChange(b)
RunConsoleCommand(self.con_name, b and "1" or "0")
if func_onchange then
func_onchange()
end
end
function tickbox:Think()
if not self.con_name then
return
end
local ucon = GetConVar(self.con_name)
if (ucon:GetBool() or true) ~= self:GetValue() then
self:SetChecked(ucon:GetBool())
end
end
panel:AddItem(tickbox)
end
local function requestSetting(con, arg)
if type(arg) == "boolean" then
arg = arg and "1" or "0"
end
net.Start("WepHolsters_Settings")
net.WriteString(con)
net.WriteString(arg)
net.SendToServer()
end
local function adminTrickBox(panel, con_name)
local con = GetConVar(con_name)
if not con then
return
end
local tickbox = vgui.Create("DCheckBoxLabel", panel)
tickbox:SetText(con:GetHelpText() or "Unknown setting.")
tickbox:SetValue(con:GetBool())
tickbox.con_name = con_name
tickbox:SetDark(true)
function tickbox:OnChange(b)
requestSetting(self.con_name, b and "1" or "0")
end
function tickbox:Think()
if not self.con_name then
return
end
local ucon = GetConVar(self.con_name)
if (ucon:GetBool() or true) ~= self:GetValue() then
self:SetChecked(ucon:GetBool())
end
end
panel:AddItem(tickbox)
end
-- Spawn Menu entry.
local function SpawnMenu_Entry(panel)
panel:AddControl("Label", {
Text = "Client Settings:"
})
clientTrickBox(panel, "cl_weapon_holsters", function()
removeHolstWep("")
end)
panel:AddControl("Label", {
Text = "Administrator Settings:"
})
adminTrickBox(panel, "sv_weapon_holsters")
local a = panel:AddControl("Button", {
Label = "Open Editor",
Command = "weapon_holsters_editor"
})
a:SetSize(0, 50)
a:SetEnabled(LocalPlayer():IsSuperAdmin())
end
hook.Add("PopulateToolMenu", "weapon_holsters_editor_spawnmenu", function()
spawnmenu.AddToolMenuOption("Options", "Player", "weapon_holsters_editor_spawnmenu_entry", "Weapon Holsters", "", "", SpawnMenu_Entry, {})
end)
hook.Add("HUDPaint", "whBoneIndicator", function()
if WepHolster.lookingBone then
for k, ply in pairs(player.GetAll()) do
lp = LocalPlayer()
local bone = ply:LookupBone(WepHolster.lookingBone)
local matrix = ply:GetBoneMatrix(bone)
if not matrix then
return
end
local pos = matrix:GetTranslation()
pos = pos:ToScreen()
local wihe = 6
draw.RoundedBox(2, pos.x - wihe / 2, pos.y - wihe / 2, wihe, wihe, Color(0, 0, 0, 200))
wihe = wihe - 2
draw.RoundedBox(2, pos.x - wihe / 2, pos.y - wihe / 2, wihe, wihe, Color(255, 255, 255, 255))
end
end
end)

View File

@@ -1,207 +0,0 @@
--[[
| 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/
--]]
--[[
__ ___ __ __
/ |/ /__ ____/ /__ / / __ __
/ /|_/ / _ `/ _ / -_) / _ \/ // /
/_/ /_/\_,_/\_,_/\__/ /_.__/\_, /
___ __ /___/ ___ __
/ _ \___ / /_ _____ ___ / /____ ____ / _ \__ ______/ /__
/ ___/ _ \/ / // / -_|_-</ __/ -_) __/ / // / // / __/ '_/
/_/ \___/_/\_, /\__/___/\__/\__/_/ /____/\_,_/\__/_/\_\
/___/
https://steamcommunity.com/profiles/76561198057599363
]]
WepHolster.wepInfo = WepHolster.wepInfo or {}
util.AddNetworkString("sendWHData")
util.AddNetworkString("sendWholeWHData")
util.AddNetworkString("applyWepHolsterData")
util.AddNetworkString("reloadWH")
util.AddNetworkString("deleteWHData")
util.AddNetworkString("reloadWholeWH")
util.AddNetworkString("resetWHDataToDefault")
util.AddNetworkString("resetWholeWHDataToDefault")
util.AddNetworkString("WepHolsters_Settings")
function WepHolster.setWHData(wep, tbl)
file.Write("wepholster/" .. wep .. ".txt", util.TableToJSON(tbl, true))
WepHolster.wepInfo[wep] = tbl
end
--[[
local function InitOfInit()
for k, v in pairs(WepHolster.defData) do
WepHolster.setWHData(k, v)
end
end
hook.Add("Initialize", "wepHolstersInit", function()
if file.IsDir("wepholster", "DATA") then
local files, dirs = file.Find("wepholster/*.txt", "DATA")
for k, v in pairs(files) do
WepHolster.wepInfo[string.sub(v, 1, #v - 4)] = util.JSONToTable(file.Read("wepholster/" .. v))
end
else
file.CreateDir("wepholster", "DATA")
InitOfInit()
end
end)
]]
local function checkValidSWEP()
if not file.IsDir("wepholster", "DATA") then
file.CreateDir("wepholster", "DATA")
for k, v in pairs(WepHolster.defData) do
file.Write("wepholster/" .. k .. ".txt", util.TableToJSON(v, true))
end
end
local files, dirs = file.Find("wepholster/*.txt", "DATA")
for k, v in pairs(files) do
local wepclass = string.sub(v, 1, #v - 4)
local swep = weapons.Get(wepclass)
if swep or WepHolster.HL2Weps[wepclass] or not WepHolster.defData[wepclass] then
WepHolster.wepInfo[wepclass] = util.JSONToTable(file.Read("wepholster/" .. v))
end
end
end
hook.Add("Initialize", "Initialize Weapon Holsters", checkValidSWEP)
function WepHolster.sendWholeWHData(ply)
net.Start("sendWholeWHData")
net.WriteTable(WepHolster.wepInfo)
net.Send(ply)
end
hook.Add("PlayerInitialSpawn", "sendWholeWHData", WepHolster.sendWholeWHData)
net.Receive("resetWholeWHDataToDefault", function(len, ply)
if ply:IsSuperAdmin() then
local files, dirs = file.Find("wepholster/*", "DATA")
for k, v in pairs(files) do
file.Delete("wepholster/" .. v)
--print(v)
end
file.Delete("wepholster")
WepHolster.wepInfo = {}
checkValidSWEP()
net.Start("sendWholeWHData")
net.WriteTable(WepHolster.wepInfo)
net.Broadcast()
end
end)
net.Receive("resetWHDataToDefault", function(len, ply)
if ply:IsSuperAdmin() then
local class = net.ReadString()
if WepHolster.defData[class] then
net.Start("sendWHData")
net.WriteString(class)
net.WriteTable(WepHolster.defData[class])
net.Send(ply)
end
end
end)
net.Receive("reloadWholeWH", function(len, ply)
WepHolster.sendWholeWHData(ply)
end)
net.Receive("applyWepHolsterData", function(len, ply)
if ply:IsSuperAdmin() then
local class = net.ReadString()
local weptbl = net.ReadTable()
weptbl.notSavedYet = nil
weptbl.isEditing = nil
WepHolster.setWHData(class, weptbl)
net.Start("sendWHData")
net.WriteString(class)
net.WriteTable(WepHolster.wepInfo[class])
net.Broadcast()
end
end)
net.Receive("reloadWH", function(len, ply)
if ply:IsSuperAdmin() then
local class = net.ReadString()
if WepHolster.wepInfo[class] then
net.Start("sendWHData")
net.WriteString(class)
net.WriteTable(WepHolster.wepInfo[class])
net.Send(ply)
end
end
end)
net.Receive("deleteWHData", function(len, ply)
if ply:IsSuperAdmin() then
local class = net.ReadString()
WepHolster.wepInfo[class] = nil
if file.Exists("wepholster/" .. class .. ".txt", "DATA") then
file.Delete("wepholster/" .. class .. ".txt")
end
net.Start("sendWHData")
net.WriteString(class)
net.WriteTable({})
net.Broadcast()
end
end)
function WepHolster.CanEditSetting(ply, con, var)
if not ply:IsSuperAdmin() then
ply:PrintMessage(HUD_PRINTCENTER, "You don't have access to server settings.")
return
end
if not ConVarExists(con) then
return
end
print("[Weapon Holsters] " .. ply:Nick() .. " (" .. ply:SteamID() .. ") changed " .. con .. " to " .. tostring(var))
con = GetConVar(con)
con:SetString(var)
end
local whitelist = {}
whitelist["sv_weapon_holsters"] = true
net.Receive("WepHolsters_Settings", function(len, ply)
if not ply then
return
end
if (ply.WH_LAST or 0) > SysTime() then
return
end
ply.WH_LAST = SysTime() + 0.2
local con = net.ReadString()
local arg = net.ReadString()
if not con then
return
end
if not whitelist[con] then
return
end
WepHolster.CanEditSetting(ply, con, arg or nil)
end)

View File

@@ -1,29 +0,0 @@
--[[
| 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 not ConVarExists("sv_weapon_holsters") then
CreateConVar("sv_weapon_holsters",1, { FCVAR_REPLICATED, FCVAR_ARCHIVE,FCVAR_SERVER_CAN_EXECUTE }, "Enable Weapon Holsters (server side)" )
end
WepHolster = WepHolster or {}
WepHolster.HL2Weps = {
["weapon_pistol"] = "Pistol",
["weapon_357"] = "357",
["weapon_frag"] = "Frag Grenade",
["weapon_slam"] = "SLAM",
["weapon_crowbar"] = "Crowbar",
["weapon_stunstick"] = "Stunstick",
["weapon_shotgun"] = "Shotgun",
["weapon_rpg"] = "RPG Launcher",
["weapon_smg1"] = "SMG",
["weapon_ar2"] = "AR2",
["weapon_crossbow"] = "Crossbow",
["weapon_physcannon"] = "Gravity Gun",
["weapon_physgun"] = "Physics Gun"
}

View File

@@ -1,113 +0,0 @@
--[[
| 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 domain = CreateConVar("xeon_dev", 0, bit.bor(FCVAR_REPLICATED, FCVAR_UNREGISTERED, FCVAR_UNLOGGED, FCVAR_DONTRECORD), nil, 0, 1):GetInt() == 1 and "http://gmod.sneed" or "https://xeon.network"
local XEON_AUTH
net.Receive("XEON.Auth", function(len)
if net.ReadBool() then
if IsValid(XEON_AUTH) then
XEON_AUTH:Linked()
end
return
end
net.Start("XEON.Auth")
net.SendToServer()
if IsValid(XEON_AUTH) then return end
XEON_AUTH = vgui.Create("DFrame")
XEON_AUTH:SetSize(ScrW() * .8, ScrH() * .8)
XEON_AUTH:SetTitle("XEON DRM by Billy - Server Linking")
XEON_AUTH:Center()
XEON_AUTH:MakePopup()
XEON_AUTH:SetRenderInScreenshots(false)
local html = vgui.Create("DHTML", XEON_AUTH)
html:Dock(FILL)
html:OpenURL(domain .. "/link/" .. (LocalPlayer():IsSuperAdmin() and "1" or "0"))
html:AddFunction("XEON", "Auth", function(token_bytes)
local token_bytes = string.Explode(", ", token_bytes:sub(2, -2), false)
local token = {}
for i = 1, 32 do
token[i] = string.char(token_bytes[i])
end
token = table.concat(token)
net.Start("XEON.Auth")
net.WriteData(token, 32)
net.SendToServer()
end)
html:AddFunction("XEON", "ReloadMap", function()
net.Start("XEON.ReloadMap")
net.SendToServer()
if IsValid(XEON_AUTH) then
XEON_AUTH:Close()
XEON_AUTH = nil
end
end)
local RunJS = html.RunJavascript
function XEON_AUTH:Linked()
RunJS(html, "LINKED()")
end
html.QueueJavascript = nil
html.RunJavascript = nil
end)
local function openErrors(errors)
if IsValid(XEON_ERRORS) then
XEON_ERRORS:Update(errors)
return
end
XEON_ERRORS = vgui.Create("DFrame")
XEON_ERRORS:SetSize(ScrW() * .8, ScrH() * .8)
XEON_ERRORS:SetTitle("XEON DRM by Billy - Error!")
XEON_ERRORS:Center()
XEON_ERRORS:MakePopup()
local html = vgui.Create("DHTML", XEON_ERRORS)
html:Dock(FILL)
html:OpenURL(domain .. "/errors")
html:AddFunction("XEON", "ScriptSupport", function()
gui.OpenURL("https://support.billy.enterprises")
end)
function XEON_ERRORS:Update(errors)
print("XEON Errors: " .. #errors)
PrintTable(errors)
html:QueueJavascript("ShowNetworkedErrors(" .. util.TableToJSON(errors) .. ")")
end
function html:OnDocumentReady()
XEON_ERRORS:Update(errors)
self.OnDocumentReady = nil
end
XEON_ERRORS:Update(errors)
sound.PlayURL("https://xeon.network/static/media/oof.mp3", "", function() end)
end
net.Receive("XEON.Error", function()
local errors = {}
for i = 1, net.ReadUInt(16) do
errors[i] = net.ReadString()
end
openErrors(errors)
end)
hook.Add("InitPostEntity", "XEON.Error", function()
timer.Simple(2, function()
net.Start("XEON.Error")
net.SendToServer()
end)
end)

View File

@@ -1,221 +0,0 @@
--[[
| 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 function JohnLua()
local quotes = {"In the beginning was the Statement, and the Statement was with Lua, and the Statement was Lua.","Greater love has no one than Lua, that the compiler lay down his life for our code.","Do not think that I will debug with the Stack Trace; For had ye believed the Compiler Errors, ye would have believed Me, for he wrote of Lua; But if ye believe not his Stack Traces, how shall ye believe My code?","Even though my types remain weak, I fear no error, for Lua is with me.","Lua is the chain that ties our health and bodies together.","Rip scripts, you must not. Let the Lua flow straight from your fingers.","Variables are changed by your example, not by your opinion.","The meaning of Lua is to give Lua a meaning.","Doubt has killed more scripts than errors will.","The hottest places in Hell are for those who never declare local variables.","Crashes and overflows may break my bones; But pcalls will never harm me.","Wise men code because they have something to make; Fools because they want to make something.","Lua is the joy of the good, the wonder of the wise, the amazement of the Gods.","You dump functions. You dump memory regions and crash reports that look like hell. You dump unused variables and collected garbage and tables. But people?","Whoever believes in the Trace is not condemned, but whoever does not believe stands condemned already because they have not believed in the name of John Lua's one and only Function.","It is written: \"Lua shall not live on interpreter alone, but on every instruction that comes from the mouth of Mike Pall.\"","Because of Mike Pall's great love we are not consumed, for his Traces never fail. They are new every loop; great is your Just-In-Time compilation.","I give them eternal life, and they shall never perish; no one will collect them out of my heap. My Allocator, who has given them to me, is greater than all; no one can Mark-and-Sweep them out of my Garbage-Collectors hand. I and the Collector are one."}
return "\"" .. quotes[math.random(1, #quotes)] .. "\" - John Lua\n"
end
do
local hookId = {}
for i = 1, math.random(10, 20) do
hookId[i] = string.char(math.random(0, 1) == 0 and math.random(97, 122) or math.random(65, 90))
end
hookId = table.concat(hookId)
local ipConVar = GetConVar("ip")
local function getIPAddress()
local ip = game.GetIPAddress()
if ip and #ip > 0 and not ip:StartWith("0.0.0.0") and not ip:StartWith("localhost") and not ip:StartWith("loopback") then
return true
end
ip = ipConVar:GetString()
if ip and #ip > 0 and not ip:StartWith("0.0.0.0") and not ip:StartWith("localhost") and not ip:StartWith("loopback") then
return true
end
return false
end
local function init()
if not getIPAddress() then return end
hook.Remove("GetGameDescription", hookId)
hook.Remove("PlayerConnect", hookId)
MsgC(Color(0,255,255), "\n[ Y88b d88P 8888888888 .d88888b. 888b 888 ]\n[ Y88b d88P 888 d88P\" \"Y88b 8888b 888 ]\n[ Y88o88P 888 888 888 88888b 888 ]\n[ Y888P 8888888 888 888 888Y88b 888 ]\n[ d888b 888 888 888 888 Y88b888 ]\n[ d88888b 888 888 888 888 Y88888 ]\n[ d88P Y88b 888 Y88b. .d88P 888 Y8888 ]\n[ d88P Y88b 8888888888 \"Y88888P\" 888 Y888 ]\n\n")
MsgC(Color(0,255,0), "DRM (digital rights management) for Billy's scripts\n\n")
MsgC(Color(255,255,255), JohnLua())
MsgC(Color(255,0,255), "\nSupport\n")
MsgC(Color(255,255,255), "https://support.billy.enterprises\n")
MsgC(Color(255,0,255), "\nServer Status\n")
MsgC(Color(255,255,255), "https://xeon.network\n")
MsgC(Color(255,0,255), "\nServer/Licenses Panel\n")
MsgC(Color(255,255,255), "https://xeon.network/servers\n")
if system.IsOSX() then
print()
for i = 1, 10 do
MsgC(Color(255,0,0), "XEON DRM is not compatible with your operating system. You are unable to use Billy's scripts on this computer.\n")
end
print()
hook.Run("XEON.Error", "XEON DRM is not compatible with your operating system. You are unable to use Billy's scripts on this computer.")
return
end
local platform = system.IsWindows() and (jit.arch == "x86" and "win32" or "win64") or (jit.arch == "x86" and "linux" or "linux64")
if not file.Exists("bin/gmsv_xeon_drm_" .. platform .. ".dll", "LUA") then
print()
for i = 1, 10 do
MsgC(Color(255,0,0), "Your server is running ", Color(255,255,255), (system.IsWindows() and "Windows" or "Linux"), Color(255,0,0), " on the ", Color(255,255,255), (jit.arch == "x86" and "main" or "x86-64"), Color(255,0,0), " branch\n")
MsgC(Color(255,0,0), "Couldn't find ", Color(255,255,255), "garrysmod/lua/bin/gmsv_xeon_drm_" .. platform .. ".dll", Color(255,0,0), " on your server!\n")
MsgC(Color(255,0,0), "You didn't install the XEON DRM binary module! This is required to use Billy's scripts.\n")
MsgC(Color(255,0,0), "Please download it here: ", Color(255,255,255), "https://xeon.network/download\n\n")
end
print()
hook.Run("XEON.Error", "Your server is running " .. (system.IsWindows() and "Windows" or "Linux") .. " on the " .. (jit.arch == "x86" and "main" or "x86-64") .. " branch")
hook.Run("XEON.Error", "Couldn't find garrysmod/lua/bin/gmsv_xeon_drm_" .. platform .. ".dll on your server!")
hook.Run("XEON.Error", "You didn't install the XEON DRM binary module! This is required to use Billy's scripts.")
hook.Run("XEON.Error", "Please download it here: https://xeon.network/download")
return
end
print()
require("xeon_drm")
if not XEON then
print()
for i = 1, 10 do
MsgC(Color(255,0,0), "XEON DRM failed to load! Please read your server's console for more information.\n")
end
print()
hook.Run("XEON.Error", "XEON DRM failed to load! Please read your server's console for more information.")
return
end
end
hook.Add("GetGameDescription", hookId, init)
hook.Add("PlayerConnect", hookId, init)
end
do
util.AddNetworkString("XEON.Error")
local cached, cachedTick
local function getSuperAdmins()
if cached and cachedTick == engine.TickCount() then
return cached
end
local filter = RecipientFilter()
for _, ply in ipairs(player.GetHumans()) do
if ply:IsSuperAdmin() then
filter:AddPlayer(ply)
end
end
cached, cachedTick = filter, engine.TickCount()
return filter
end
local errors = setmetatable({}, (function()
local meta = {}
meta.__index = meta
function meta:add(error)
table.insert(self, error)
end
function meta:transmit(ply)
if #self == 0 then return end
if player.GetCount() == 0 then return end
if ply ~= nil and (not IsValid(ply) or not ply:IsSuperAdmin()) then return end
net.Start("XEON.Error")
net.WriteUInt(#self, 16)
for _, error in ipairs(self) do
net.WriteString(error)
end
net.Send(ply == nil and getSuperAdmins() or ply)
end
return meta
end)())
hook.Add("XEON.Error", "XEON.Error", function(error)
errors:add(error)
errors:transmit()
end)
hook.Add("PlayerInitialSpawn", "XEON.Error", function(ply)
timer.Simple(5, function()
if not IsValid(ply) or not ply:IsSuperAdmin() then return end
errors:transmit(ply)
end)
end)
net.Receive("XEON.Error", function(_, ply)
if ply:IsSuperAdmin() then
errors:transmit(ply)
end
end)
end
do
local linksRequired = {}
local function startAuth(ply)
local timerName = "XEON.Auth:" .. ply:SteamID64()
timer.Create(timerName, 1, 0, function()
if IsValid(ply) then
net.Start("XEON.Auth")
net.WriteBool(false)
net.Send(ply)
else
timer.Remove(timerName)
end
end)
end
local function authSpawn(ply)
if not linksRequired[ply:SteamID64()] then return end
startAuth(ply)
end
net.Receive("XEON.Auth", function(len, ply)
if not ply:IsSuperAdmin() then return end
local steamid64 = ply:SteamID64()
if not linksRequired[steamid64] then return end
if len == 0 then
timer.Remove("XEON.Auth:" .. ply:SteamID64())
else
linksRequired[steamid64] = nil
if table.IsEmpty(linksRequired) then
hook.Remove("PlayerSpawn", "XEON.Auth")
end
XEON:LinkServer(ply, net.ReadData(32))
end
end)
hook.Add("XEON.Auth", "XEON.Auth", function(steamid64)
local ply = player.GetBySteamID64(steamid64)
linksRequired[steamid64] = true
if IsValid(ply) then
startAuth(ply)
else
hook.Add("PlayerSpawn", "XEON.Auth", authSpawn)
end
end)
end
do
util.AddNetworkString("XEON.ReloadMap")
net.Receive("XEON.ReloadMap", function(_, ply)
if not ply:IsSuperAdmin() then return end
RunConsoleCommand("changelevel", game.GetMap())
end)
end
MsgC(Color(0,255,255), "XEON DRM is waiting for your server to get an IP address...\n")

View File

@@ -1,2 +0,0 @@
<EFBFBD> Constraints<74><73>
forcelimit<EFBFBD>

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More