Merge pull request #20 from gmod-integration/v0.5.0

V0.5.0
This commit is contained in:
Grégoire Becue 2025-07-03 05:41:17 +02:00 committed by GitHub
commit f96b3fd309
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
65 changed files with 889 additions and 701 deletions

View File

@ -1,69 +1,137 @@
if game.SinglePlayer() then return print("Gmod Integration is not supported in Singleplayer!") end
local alreadyLoadGMI = gmInte
local isLatest = debug.getinfo(1, "S").source == "@addons/gmod_integration_latest/lua/autorun/gmod_integration_latest.lua"
gmInte = gmInte || {}
gmInte.version = "0.4.9"
gmInte.version = "0.5.0"
gmInte.config = {}
gmInte.materials = {}
local function loadServerConfig()
gmInte.useDataConfig = true
if !alreadyLoadGMI then
if SERVER then
print(" ")
print(" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ")
print(" - - ")
print(" - Gmod Integration v" .. gmInte.version .. " - ")
print(" - - ")
print(" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ")
print(" - - ")
print(" - Thanks for using Gmod Integration ! - ")
print(" - If you have any questions, please contact us on Discord! - ")
print(" - https://gmod-integration.com/discord - ")
print(" - - ")
print(" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ")
print(" ")
else
print(" ")
print(" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ")
print(" - - ")
print(" - Gmod Integration v" .. gmInte.version .. " - ")
print(" - - ")
print(" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ")
print(" - - ")
print(" - Thanks for using Gmod Integration ! - ")
print(" - If you have any questions, please contact us on Discord! - ")
print(" - https://gmod-integration.com/discord - ")
print(" - - ")
print(" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ")
print(" ")
end
function gmInte.simpleLog(msg, debug)
print(" | " .. os.date(gmInte.config.logTimestamp || "%Y-%m-%d %H:%M:%S") .. " | Gmod Integration | " .. msg)
end
if file.Exists("lua/bin/gmsv_gmod_integration_loader_linux.dll", "GAME") then
if !file.Exists("gm_integration", "DATA") || !file.Exists("gm_integration/tmp.json", "DATA") then file.CreateDir("gm_integration") end
file.Write("gm_integration/tmp.json", util.TableToJSON({
gmod_integration_latest_updated = false,
}, true))
require("gmod_integration_loader")
local tmp = util.JSONToTable(file.Read("gm_integration/tmp.json", "DATA"))
if tmp.gmod_integration_latest_updated then
gmInte.simpleLog("Auto Loader: DLL was modified, changing map to apply changes")
timer.Simple(1, function()
if game.IsDedicated() then
gmInte.simpleLog("Auto Loader: Running changelevel command again")
RunConsoleCommand("changelevel", game.GetMap())
else
gmInte.simpleLog("Auto Loader: Running gamemode command again")
RunConsoleCommand("gamemode", game.GetMap())
end
end)
return
end
if !isLatest then return end
end
else
if !isLatest then return end
end
local function loadConfig()
RunConsoleCommand("sv_hibernate_think", "1")
if !file.Exists("gm_integration", "DATA") || !file.Exists("gm_integration/config.json", "DATA") then
file.CreateDir("gm_integration")
file.Write("gm_integration/config.json", util.TableToJSON(gmInte.config, true))
else
if gmInte.config.id && gmInte.config.id != "" then return end
if gmInte.config.id && gmInte.config.id != "" then
gmInte.useDataConfig = false
timer.Simple(1, function() gmInte.simpleLog("Using Data Config | This is not recommended, please revert change and use ig cmd !gmi to edit your config", true) end)
return
end
local oldConfig = util.JSONToTable(file.Read("gm_integration/config.json", "DATA"))
if !oldConfig.version || (oldConfig.version < gmInte.version) then
print(" | Merging Config | gmod_integration/sv_config.lua")
table.Merge(gmInte.config, oldConfig)
gmInte.config.version = gmInte.version
file.Write("gm_integration/config.json", util.TableToJSON(gmInte.config, true))
else
gmInte.config = oldConfig
end
gmInte.simpleLog("Using Data Config: Data config loaded from data/gm_integration/config.json")
end
end
local function loadAllFiles(folder)
local files, folders = file.Find(folder .. "/*", "LUA")
for k, fileName in SortedPairs(files) do
local path = folder .. "/" .. fileName
print(" | Loading File | " .. path)
if string.StartWith(fileName, "cl_") then
if SERVER then
AddCSLuaFile(path)
else
include(path)
end
elseif string.StartWith(fileName, "sv_") then
if SERVER then include(path) end
elseif string.StartWith(fileName, "sh_") then
if SERVER then AddCSLuaFile(path) end
local loadedFiles = {}
local function loadFile(folder, fileName)
local path = folder .. "/" .. fileName
if loadedFiles[path] then return end
loadedFiles[path] = true
if string.StartWith(fileName, "cl_") then
if SERVER then
AddCSLuaFile(path)
else
include(path)
end
if fileName == "sv_config.lua" then
loadServerConfig()
continue
end
elseif string.StartWith(fileName, "sv_") then
if SERVER then include(path) end
elseif string.StartWith(fileName, "sh_") then
if SERVER then AddCSLuaFile(path) end
include(path)
end
for k, v in SortedPairs(folders, true) do
loadAllFiles(folder .. "/" .. v, name)
if fileName == "sv_config.lua" then loadConfig() end
gmInte.simpleLog("File Loaded: " .. path)
end
local function loadFolder(folder)
local files, folders = file.Find(folder .. "/*", "LUA")
for k, fileName in SortedPairs(files) do
loadFile(folder, fileName)
end
for k, subFolder in SortedPairs(folders) do
loadFolder(folder .. "/" .. subFolder)
end
end
print(" ")
print(" ")
print(" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ")
print(" - - ")
print(" - Gmod Integration v" .. gmInte.version .. " - ")
print(" - - ")
print(" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ")
print(" - - ")
print(" - Thanks for using Gmod Integration ! - ")
print(" - If you have any questions, please contact us on Discord! - ")
print(" - https://gmod-integration.com/discord - ")
print(" - - ")
print(" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ")
print(" ")
loadAllFiles("gmod_integration")
local execFolder = debug.getinfo(1, "S").source:match("/(.+)/(.+)/(.+)/")
loadFile(execFolder, "sv_config.lua")
loadFolder(execFolder .. "/languages")
loadFolder(execFolder .. "/core/utils")
loadFolder(execFolder .. "/core/ui")
loadFolder(execFolder .. "/core")
loadFolder(execFolder .. "/modules")
loadFolder(execFolder)
print(" ")

View File

@ -1,35 +0,0 @@
list.Set("DesktopWindows", "GmodIntegration:DesktopWindows", {
icon = "gmod_integration/logo_context.png",
title = "GM Integration",
width = 960,
height = 700,
onewindow = true,
init = function(icon, window)
window:Close()
gmInte.openAdminConfig()
end
})
list.Set("DesktopWindows", "GmodIntegration:DesktopWindows:ReportBug", {
icon = "gmod_integration/logo_context_report.png",
title = "Report Bug",
width = 960,
height = 700,
onewindow = true,
init = function(icon, window)
window:Close()
gmInte.openReportBug()
end
})
list.Set("DesktopWindows", "GmodIntegration:DesktopWindows:SendScreen", {
icon = "gmod_integration/logo_context_screen.png",
title = "Screenshot",
width = 960,
height = 700,
onewindow = true,
init = function(icon, window)
window:Close()
gmInte.contextScreenshot()
end
})

View File

@ -1,14 +0,0 @@
hook.Add("InitPostEntity", "gmInte:Ply:Ready", function()
gmInte.SendNet("ready", {
["branch"] = LocalPlayer():gmInteGetBranch()
})
end)
hook.Add("OnPlayerChat", "gmInte:OnPlayerChat:AdminCmd", function(ply, strText, bTeamOnly, bPlayerIsDead)
if ply != LocalPlayer() then return end
strText = string.lower(strText)
if strText == "/gmi" || strText == "!gmi" then
gmInte.openAdminConfig()
return true
end
end)

View File

@ -1,105 +0,0 @@
function gmInte.chatAddText(...)
local args = {...}
table.insert(args, 1, Color(255, 130, 92))
table.insert(args, 2, "[Gmod Integration] ")
chat.AddText(unpack(args))
end
function gmInte.chatAddTextFromTable(data)
local args = {}
for _, v in ipairs(data) do
table.insert(args, v.color || Color(255, 255, 255))
table.insert(args, v.text)
end
gmInte.chatAddText(unpack(args))
end
function gmInte.showTestConnection(data)
if data && data.id then
gmInte.chatAddText(Color(89, 194, 89), gmInte.getTranslation("chat.authentication_success", "Successfully Authenticated"), Color(255, 255, 255), gmInte.getTranslation("chat.server_link", ", server linked as {1}.", data.name))
else
gmInte.chatAddText(Color(228, 81, 81), gmInte.getTranslation("chat.authentication_failed", "Failed to Authenticate"), Color(255, 255, 255), gmInte.getTranslation("chat.server_fail", ", check your ID and Token."))
end
end
function gmInte.openAdminConfig()
if !LocalPlayer():gmIntIsAdmin() then
gmInte.chatAddText(Color(228, 81, 81), gmInte.getTranslation("chat.missing_permissions", "You do not have permission to do this action."))
return
end
gmInte.SendNet("getConfig")
end
hook.Add("HUDPaint", "gmInte:HUD:ShowScreenshotInfo", function()
if !gmInte.showScreenshotInfo then return end
local screenInfo = {
{
txt = "Server ID",
val = gmInte.config.id
},
{
txt = "SteamID64",
val = LocalPlayer():SteamID64()
},
{
txt = "Date",
val = os.date("%Y-%m-%d %H:%M:%S")
},
{
txt = "Position",
val = function()
local pos = LocalPlayer():GetPos()
local newPos = ""
for i = 1, 3 do
newPos = newPos .. math.Round(pos[i])
if i < 3 then newPos = newPos .. ", " end
end
return newPos
end
},
{
txt = "Map",
val = game.GetMap()
},
{
txt = "Ping",
val = LocalPlayer():Ping()
},
{
txt = "FPS",
val = function() return math.Round(1 / FrameTime()) end
},
{
txt = "Size",
val = ScrW() .. "x" .. ScrH()
}
}
local concatInfo = ""
for k, v in pairs(screenInfo) do
local val = v.val
if type(val) == "function" then val = val() end
concatInfo = concatInfo .. v.txt .. ": " .. val
if k < #screenInfo then concatInfo = concatInfo .. " - " end
end
draw.SimpleText(concatInfo, "DermaDefault", ScrW() / 2, ScrH() - 15, Color(255, 255, 255, 119), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
end)
local lastTime = 0
local frameTime = 0
local fps = 0
hook.Add("Think", "gmInte:HUD:CalculateFPS", function()
frameTime = RealTime() - lastTime
lastTime = RealTime()
fps = math.Round(1 / frameTime)
end)
timer.Create("gmInte:HUD:SendFPS", 5, 0, function()
LocalPlayer().gmIntFPS = fps
gmInte.SendNet("sendFPS", {
["fps"] = fps
})
end)

View File

@ -1,43 +0,0 @@
local ImageCache = {}
function gmInte.createImgurMaterials(materials, addon_var, folder, name)
if !file.Exists(folder, "DATA") then file.CreateDir(folder) end
local function getMatFromUrl(url, id)
materials[id] = Material("nil")
if file.Exists(folder .. "/" .. id .. ".png", "DATA") && !gmInte.config.redownloadMaterials then
addon_var[id] = Material("../data/" .. folder .. "/" .. id .. ".png", "noclamp smooth")
gmInte.log("materials", name .. " - Image Loaded - " .. id .. ".png")
return
end
http.Fetch(url, function(body)
file.Write(folder .. "/" .. id .. ".png", body)
addon_var[id] = Material("../data/" .. folder .. "/" .. id .. ".png", "noclamp smooth")
ImageCache[table.Count(ImageCache) + 1] = {
["folder"] = folder,
["addon_var"] = addon_var,
["id"] = id
}
gmInte.log("materials", name .. " - Image Downloaded - " .. id .. ".png")
end)
end
for k, v in pairs(materials) do
getMatFromUrl("https://i.imgur.com/" .. v .. ".png", k)
end
end
function gmInte.redowloadMaterials()
for k, v in pairs(ImageCache) do
v.addon_var[v.id] = Material("../data/" .. v.folder .. "/" .. v.id .. ".png", "noclamp smooth")
gmInte.log("materials", v.name .. " - Image Redownloaded - " .. v.id .. ".png")
end
end
concommand.Add("gmod_integration_reload_materials", gmInte.redowloadMaterials)
concommand.Add("gmi_reload_materials", gmInte.redowloadMaterials)
local materialsList = {
["logo"] = "y3Mypbn"
}
gmInte.createImgurMaterials(materialsList, gmInte.materials, "gmod_integration/material", "Gmod Integration")

View File

@ -1,40 +0,0 @@
local netSend = {
["ready"] = 0,
["testConnection"] = 1,
["getConfig"] = 2,
["saveConfig"] = 3,
["takeScreenShot"] = 4,
["restartMap"] = 5,
["verifyMe"] = 6,
["sendFPS"] = 7
}
function gmInte.SendNet(id, args, func)
net.Start("gmIntegration")
net.WriteUInt(netSend[id], 8)
net.WriteString(util.TableToJSON(args || {}))
if func then func() end
net.SendToServer()
end
local netReceive = {
[1] = function(data) gmInte.discordSyncChatPly(data) end,
[2] = function(data) gmInte.openConfigMenu(data) end,
[3] = function(data) gmInte.showTestConnection(data) end,
[5] = function(data)
gmInte.config = table.Merge(gmInte.config, data.config)
gmInte.version = data.other.version
gmInte.loadTranslations()
if gmInte.config.clientBranch != "any" && gmInte.config.clientBranch != BRANCH then gmInte.openWrongBranchPopup() end
if !data.other.aprovedCredentials then RunConsoleCommand("gmod_integration_admin") end
end,
[6] = function(data) gmInte.chatAddTextFromTable(data) end,
[7] = function() gmInte.openVerifPopup() end,
[8] = function(data) gmInte.config.token = data.token end
}
net.Receive("gmIntegration", function()
local id = net.ReadUInt(8)
local args = util.JSONToTable(net.ReadString())
if netReceive[id] then netReceive[id](args) end
end)

View File

@ -0,0 +1,9 @@
function gmInte.sendToAPI(endpoint, method, data, onSuccess, onFailed)
gmInte.http.requestAPI({
["endpoint"] = endpoint,
["method"] = method,
["body"] = data,
["success"] = onSuccess,
["failed"] = onFailed
})
end

View File

@ -0,0 +1,95 @@
local function websocketDLLExist()
local files, _ = file.Find("lua/bin/*", "GAME")
for k, v in ipairs(files) do
if v:find("gwsockets") then return true end
end
return false
end
if !websocketDLLExist() then
timer.Simple(4, function()
gmInte.logHint("GWSockets is not installed !, Syncronize feature will not work !")
gmInte.logHint("Please install it from https://github.com/FredyH/GWSockets/releases")
end)
return
end
require("gwsockets")
local function getWebSocketURL()
local method = gmInte.isPrivateIP(gmInte.config.websocketFQDN) && "ws" || "wss"
return method .. "://" .. gmInte.config.websocketFQDN
end
function gmInte.setupWebSocket()
local callbacks_ = {}
gmInte.websocket = GWSockets.createWebSocket(getWebSocketURL())
gmInte.websocket:setHeader("id", gmInte.config.id)
gmInte.websocket:setHeader("token", gmInte.config.token)
gmInte.websocket:open()
function gmInte.websocket:onConnected()
gmInte.log("WebSocket Connected", true)
end
function gmInte.websocket:onMessage(txt)
gmInte.log("WebSocket Message: " .. txt, true)
local data = util.JSONToTable(txt)
if gmInte[data.method] then
gmInte[data.method](data)
elseif data.id && callbacks_[data.id] then
local callback = callbacks_[data.id]
callbacks_[data.id] = nil
if data.error then
gmInte.logError("WebSocket Error: " .. data.error, true)
callback(false, data.error)
else
callback(true, data.data)
end
else
gmInte.logError("WebSocket Message: " .. txt .. " is not a valid method !", true)
end
end
function gmInte.websocket:onDisconnected()
gmInte.log("WebSocket Disconnected", true)
end
function gmInte.websocket:onError(txt)
gmInte.logError("WebSocket Error: " .. txt, true)
end
function gmInte.websocket:send(method, data, callback, hidePrint)
if !self:isConnected() then
if !hidePrint then
gmInte.logError("WebSocket is not connected, cannot send data", true)
end
return
end
local id = tostring(SysTime()) .. "-" .. gmInte.generateRandomString(8)
local packet = {
method = method,
data = data,
id = id
}
if callback then
callbacks_[id] = callback
end
if !hidePrint then
gmInte.log("WebSocket Send: " .. util.TableToJSON(packet), true)
end
self:write(util.TableToJSON(packet))
end
end
timer.Create("gmInte:WebSocket:CheckConnection", 4, 0, function()
if (!gmInte.websocket || !gmInte.websocket:isConnected()) && gmInte.aprovedCredentials then
gmInte.log("WebSocket is not connected, trying to connect", true)
gmInte.setupWebSocket()
end
end)
hook.Add("GmodIntegration:Websocket:Restart", "gmInte:WebSocket:Restart", function() gmInte.setupWebSocket() end)
hook.Add("InitPostEntity", "gmInte:ServerReady:WebSocket", function() timer.Simple(1, function() gmInte.setupWebSocket() end) end)

View File

@ -13,6 +13,43 @@ local colorTable = {
["buttonTextHover"] = Color(255, 255, 255, 255),
}
// function to open a msg info say in game config has been disabled because default sv_config.lua has been edited
function gmInte.openDisabledConfig()
local frame = vgui.Create("DFrame")
frame:SetSize(400, 120)
frame:Center()
frame:SetTitle(gmInte.getFrameName(gmInte.getTranslation("admin.config_disabled", "Config Disabled")))
frame:SetDraggable(true)
frame:ShowCloseButton(true)
frame:MakePopup()
gmInte.applyPaint(frame)
local messagePanel = vgui.Create("DPanel", frame)
messagePanel:Dock(TOP)
messagePanel:SetSize(300, 40)
messagePanel:DockMargin(10, 0, 10, 10)
messagePanel:SetBackgroundColor(Color(0, 0, 0, 0))
local messageLabel = vgui.Create("DLabel", messagePanel)
messageLabel:Dock(FILL)
messageLabel:SetText(gmInte.getTranslation("admin.config_disabled_description", "The config has been disabled because the default sv_config.lua has been edited.\nPlease restore the default sv_config.lua to enable the config again."))
messageLabel:SetContentAlignment(5)
messageLabel:SetWrap(true)
local buttonGrid = vgui.Create("DGrid", frame)
buttonGrid:Dock(BOTTOM)
buttonGrid:DockMargin(5, 10, 5, 5)
buttonGrid:SetCols(1)
buttonGrid:SetColWide(frame:GetWide() - 10)
buttonGrid:SetRowHeight(35)
local button = vgui.Create("DButton")
button:SetText(gmInte.getTranslation("admin.ok", "OK"))
button.DoClick = function() frame:Close() end
button:SetSize(buttonGrid:GetColWide() - 10, buttonGrid:GetRowHeight())
gmInte.applyPaint(button)
buttonGrid:AddItem(button)
frame.OnClose = function() gmInte.openAdminPanel = false end
frame.OnRemove = function() gmInte.openAdminPanel = false end
frame.OnKeyCodePressed = function(self, key) if key == KEY_ESCAPE then self:Close() end end
end
function gmInte.needRestart()
local frame = vgui.Create("DFrame")
frame:SetSize(400, 120)
@ -222,6 +259,21 @@ function gmInte.openConfigMenu(data)
["onEditDelay"] = 0.5,
["category"] = gmInte.getTranslation("admin.advanced", "Advanced")
},
{
["id"] = "logTimestamp",
["label"] = gmInte.getTranslation("admin.internal_log_format", "Internal Log Format"),
["description"] = gmInte.getTranslation("admin.internal_log_format_description", "The timestamp format of the logs."),
["type"] = "textEntry",
["resetIfEmpty"] = true,
["defaultValue"] = "%Y-%m-%d %H:%M:%S",
["value"] = function(setting, value) return value end,
["onEdit"] = function(setting, value)
if !value || value == "" then return end
saveConfig(setting, value)
end,
["onEditDelay"] = 0.5,
["category"] = gmInte.getTranslation("admin.advanced", "Advanced")
},
}
local buttonsInfo = {
@ -395,5 +447,30 @@ function gmInte.openConfigMenu(data)
end
end
function gmInte.openAdminConfig()
if !LocalPlayer():gmIntIsAdmin() then
gmInte.chatAddText(Color(228, 81, 81), gmInte.getTranslation("chat.missing_permissions", "You do not have permission to do this action."))
return
end
gmInte.SendNet("getConfig")
end
function gmInte.showTestConnection(data)
if data && data.id then
gmInte.chatAddText(Color(89, 194, 89), gmInte.getTranslation("chat.authentication_success", "Successfully Authenticated"), Color(255, 255, 255), gmInte.getTranslation("chat.server_link", ", server linked as {1}.", data.name))
else
gmInte.chatAddText(Color(228, 81, 81), gmInte.getTranslation("chat.authentication_failed", "Failed to Authenticate"), Color(255, 255, 255), gmInte.getTranslation("chat.server_fail", ", check your ID and Token."))
end
end
concommand.Add("gmod_integration_admin", function() gmInte.SendNet("getConfig") end)
concommand.Add("gmi_admin", function() gmInte.SendNet("getConfig") end)
concommand.Add("gmi_admin", function() gmInte.SendNet("getConfig") end)
hook.Add("OnPlayerChat", "gmInte:OnPlayerChat:AdminCmd", function(ply, strText, bTeamOnly, bPlayerIsDead)
if ply != LocalPlayer() then return end
strText = string.lower(strText)
if strText == "/gmi" || strText == "!gmi" then
gmInte.openAdminConfig()
return true
end
end)

View File

@ -0,0 +1,11 @@
list.Set("DesktopWindows", "GmodIntegration:DesktopWindows", {
icon = "gmod_integration/logo_context.png",
title = "GM Integration",
width = 960,
height = 700,
onewindow = true,
init = function(icon, window)
window:Close()
gmInte.openAdminConfig()
end
})

View File

@ -3,7 +3,6 @@ local conFuncs = {
["set-setting"] = function(args) gmInte.saveSetting(args[2], args[3]) end,
["show-settings"] = function() PrintTable(gmInte.config) end,
["try"] = function() gmInte.tryConfig() end,
["refresh"] = function() gmInte.refreshSettings() end,
["get-server-id"] = function() print(gmInte.config.id || "none") end,
["export-warns"] = function() hook.Run("GmodIntegration:ExportWarns") end
}
@ -18,7 +17,6 @@ local function cmdExecuted(ply, cmd, args)
print("set-setting <setting> <value>")
print("show-settings")
print("try")
print("refresh")
print("get-server-id")
print("export-warns")
end

View File

@ -9,6 +9,10 @@ function gmInte.saveSetting(setting, value)
return
end
if setting == "id" || setting == "token" then
gmInte.aprovedCredentials = false
end
// Boolean
if value == "true" then value = true end
if value == "false" then value = false end
@ -42,14 +46,13 @@ function gmInte.testConnection(ply)
gmInte.http.get("/servers/:serverID", function(code, body) if ply then gmInte.SendNet("testApiConnection", body, ply) end end, function(code, body) if ply then gmInte.SendNet("testApiConnection", body, ply) end end)
end
function gmInte.refreshSettings()
gmInte.config = util.JSONToTable(file.Read("gm_integration/config.json", "DATA"))
gmInte.log("Settings Refreshed")
gmInte.tryConfig()
end
function gmInte.superadminGetConfig(ply)
if !ply:IsValid() || !ply:IsPlayer(ply) || !ply:gmIntIsAdmin() then return end
if !gmInte.useDataConfig then
gmInte.SendNet("notEditableConfig", {}, ply)
return
end
gmInte.config.websocket = GWSockets && true || false
gmInte.SendNet("adminConfig", gmInte.config, ply)
end
@ -64,7 +67,8 @@ function gmInte.publicGetConfig(ply)
["websocketFQDN"] = gmInte.config.websocketFQDN,
["adminRank"] = gmInte.config.adminRank,
["language"] = gmInte.config.language,
["clientBranch"] = gmInte.config.clientBranch
["clientBranch"] = gmInte.config.clientBranch,
["logTimestamp"] = gmInte.config.logTimestamp
},
["other"] = {
["aprovedCredentials"] = gmInte.aprovedCredentials,

View File

@ -0,0 +1,35 @@
function gmInte.SendNet(id, args, func)
net.Start("gmIntegration")
net.WriteString(id)
net.WriteString(util.TableToJSON(args || {}))
if func then func() end
net.SendToServer()
end
local netReceive = {
["wsRelayDiscordChat"] = function(data) gmInte.discordSyncChatPly(data) end,
["adminConfig"] = function(data) gmInte.openConfigMenu(data) end,
["testApiConnection"] = function(data) gmInte.showTestConnection(data) end,
["publicConfig"] = function(data)
gmInte.config = table.Merge(gmInte.config, data.config)
gmInte.version = data.other.version
gmInte.loadTranslations()
if gmInte.config.clientBranch != "any" && gmInte.config.clientBranch != BRANCH then gmInte.openWrongBranchPopup() end
if !data.other.aprovedCredentials then RunConsoleCommand("gmod_integration_admin") end
end,
["chatColorMessage"] = function(data) gmInte.chatAddTextFromTable(data) end,
["openVerifPopup"] = function() gmInte.openVerifPopup() end,
["savePlayerToken"] = function(data) gmInte.config.token = data.token end,
["notEditableConfig"] = function() gmInte.openDisabledConfig() end,
}
net.Receive("gmIntegration", function()
local id = net.ReadString()
local args = util.JSONToTable(net.ReadString())
if !netReceive[id] then return end
netReceive[id](args)
if gmInte.config.debug then
gmInte.log("[net] Received net message: " .. id)
gmInte.log("[net] Data: " .. util.TableToJSON(args))
end
end)

View File

@ -1,19 +1,7 @@
util.AddNetworkString("gmIntegration")
local netSend = {
["wsRelayDiscordChat"] = 1,
["adminConfig"] = 2,
["testApiConnection"] = 3,
["publicConfig"] = 5,
["chatColorMessage"] = 6,
["openVerifPopup"] = 7,
["savePlayerToken"] = 8
}
// Send
function gmInte.SendNet(id, data, ply, func)
if !netSend[id] then return end
net.Start("gmIntegration")
net.WriteUInt(netSend[id], 8)
net.WriteString(id)
net.WriteString(util.TableToJSON(data || {}))
if func then func() end
if ply == nil then
@ -24,27 +12,31 @@ function gmInte.SendNet(id, data, ply, func)
end
local netReceive = {
[0] = function(ply, data)
["ready"] = function(ply, data)
if ply.gmIntIsReady then return end
ply.branch = data.branch
hook.Run("gmInte:PlayerReady", ply)
end,
[1] = function(ply, data) gmInte.testConnection(ply, data) end,
[2] = function(ply) gmInte.superadminGetConfig(ply) end,
[3] = function(ply, data) gmInte.superadminSetConfig(ply, data) end,
[4] = function(ply) gmInte.takeScreenshot(ply) end,
[5] = function(ply)
["testConnection"] = function(ply, data) gmInte.testConnection(ply, data) end,
["getConfig"] = function(ply) gmInte.superadminGetConfig(ply) end,
["saveConfig"] = function(ply, data) gmInte.superadminSetConfig(ply, data) end,
["takeScreenShot"] = function(ply) gmInte.takeScreenshot(ply) end,
["restartMap"] = function(ply)
if !ply:gmIntIsAdmin() then return end
RunConsoleCommand("changelevel", game.GetMap())
end,
[6] = function(ply) gmInte.verifyPlayer(ply) end,
[7] = function(ply, data) gmInte.sendPlayerToken(ply) end
["verifyMe"] = function(ply) gmInte.verifyPlayer(ply) end,
["sendFPS"] = function(ply, data) ply:gmInteSetFPS(data.fps) end,
}
net.Receive("gmIntegration", function(len, ply)
if !ply || ply && !ply:IsValid() then return end
local id = net.ReadUInt(8)
local id = net.ReadString()
local data = util.JSONToTable(net.ReadString() || "{}")
if !netReceive[id] then return end
netReceive[id](ply, data)
if gmInte.config.debug then
gmInte.log("[net] Received net message: " .. id .. " from " .. (ply && ply:Nick() || "Unknown"))
gmInte.log("[net] Data: " .. util.TableToJSON(data))
end
end)

View File

@ -37,5 +37,5 @@ function gmInte.sendPlayerToken(ply)
end)
end
hook.Add("gmInte:PlayerReady", "gmInte:Verif:PlayerReady", function(ply) gmInte.sendPlayerToken(ply) end)
hook.Add("gmInte:PlayerReady", "gmInte:PlayerReady:SendToken", function(ply) gmInte.sendPlayerToken(ply) end)
hook.Add("Initialize", "gmInte:Server:Initialize:GetPublicToken", function() timer.Simple(1, function() gmInte.getPublicServerToken(function(publicToken) gmInte.log("Server Public Token Received: " .. publicToken) end) end) end)

View File

@ -0,0 +1,16 @@
function gmInte.chatAddText(...)
local args = {...}
table.insert(args, 1, Color(255, 130, 92))
table.insert(args, 2, "[Gmod Integration] ")
chat.AddText(unpack(args))
end
function gmInte.chatAddTextFromTable(data)
local args = {}
for _, v in ipairs(data) do
table.insert(args, v.color || Color(255, 255, 255))
table.insert(args, v.text)
end
gmInte.chatAddText(unpack(args))
end

View File

@ -0,0 +1,82 @@
local ply = FindMetaTable("Player")
function ply:gmIntGetTimeLastTeamChange()
return self.gmIntTimeLastTeamChange || RealTime()
end
function ply:gmInteResetTimeLastTeamChange()
self.gmIntTimeLastTeamChange = RealTime()
end
gmInte.restoreFileCache = gmInte.restoreFileCache || {}
function ply:getAdjustedTime()
if gmInte.restoreFileCache == nil || gmInte.restoreFileCache.sysTime == nil || gmInte.restoreFileCache.playersList == nil then return 0 end
if SERVER then
if table.IsEmpty(gmInte.restoreFileCache) then
if file.Exists("gm_integration/player_before_map_change.json", "DATA") then
gmInte.restoreFileCache = util.JSONToTable(file.Read("gm_integration/player_before_map_change.json", "DATA"))
else
return 0
end
end
else
if table.IsEmpty(gmInte.restoreFileCache) then
if file.Exists("gmod_integration/player_before_map_change.json", "DATA") then
gmInte.restoreFileCache = util.JSONToTable(file.Read("gmod_integration/player_before_map_change.json", "DATA"))
else
return 0
end
gmInte.restoreFileCache = gmInte.restoreFileCache[gmInte.config.id]
end
end
if !gmInte.restoreFileCache.sysTime || !gmInte.restoreFileCache.playersList then return 0 end
if (gmInte.restoreFileCache.sysTime + 60 * 5) < (os.time() - self:gmIntGetConnectTime()) then return 0 end
if !gmInte.restoreFileCache.playersList[self:SteamID()] then return 0 end
return gmInte.restoreFileCache.playersList[self:SteamID()].connectTime || 0
end
if SERVER then
gameevent.Listen("player_connect")
hook.Add("player_connect", "gmInte:Player:Connect:RemoveRestore", function(data)
if table.IsEmpty(gmInte.restoreFileCache) then
if file.Exists("gm_integration/player_before_map_change.json", "DATA") then
gmInte.restoreFileCache = util.JSONToTable(file.Read("gm_integration/player_before_map_change.json", "DATA"))
else
return
end
end
if gmInte.restoreFileCache.playersList && gmInte.restoreFileCache.playersList[data.networkid] then
gmInte.restoreFileCache.playersList[data.networkid] = nil
file.Write("gm_integration/player_before_map_change.json", util.TableToJSON(gmInte.restoreFileCache, true))
end
end)
end
local function saveTimeToLocal()
local dataToSave = {
["version"] = "1.0",
["serverID"] = gmInte.config.id,
["playersList"] = {},
["sysTime"] = os.time()
}
if SERVER then
for _, ply in ipairs(player.GetAll()) do
dataToSave.playersList[ply:SteamID()] = gmInte.getPlayerFormat(ply)
end
if !file.Exists("gm_integration", "DATA") then file.CreateDir("gm_integration") end
file.Write("gm_integration/player_before_map_change.json", util.TableToJSON(dataToSave, true))
else
dataToSave.playersList[LocalPlayer():SteamID()] = gmInte.getPlayerFormat(LocalPlayer())
local oldData = {}
if file.Exists("gmod_integration/player_before_map_change.json", "DATA") then oldData = util.JSONToTable(file.Read("gmod_integration/player_before_map_change.json", "DATA")) end
oldData[gmInte.config.id] = dataToSave
file.Write("gmod_integration/player_before_map_change.json", util.TableToJSON(oldData, true))
end
end
hook.Add("ShutDown", "gmInte:Server:ShutDown:SavePlayer", saveTimeToLocal)
hook.Add("GMI:SaveBeforeCrash", "gmInte:Server:BeforeCrash:SavePlayers", saveTimeToLocal)

View File

@ -0,0 +1,57 @@
local ply = FindMetaTable("Player")
function ply:gmIntSetCustomValue(key, value)
self.gmIntCustomValues = self.gmIntCustomValues || {}
self.gmIntCustomValues[key] = value
end
function ply:gmIntGetCustomValue(key)
return self.gmIntCustomValues && self.gmIntCustomValues[key]
end
function ply:gmIntRemoveCustomValue(key)
if self.gmIntCustomValues then self.gmIntCustomValues[key] = nil end
end
local function getCustomCompatability(ply)
local values = {}
// DarkRP
if DarkRP then
values.money = ply:getDarkRPVar("money")
values.job = ply:getDarkRPVar("job")
end
// GUI Level System
if GUILevelSystem then
values.level = ply:GetLevel()
values.xp = ply:GetXP()
end
// Pointshop 2
if Pointshop2 && ply.PS2_Wallet then
values.ps2Points = ply.PS2_Wallet.points
values.ps2PremiumPoints = ply.PS2_Wallet.premiumPoints
end
if CH_ATM && SERVER then values.bank = CH_ATM.GetMoneyBankAccount(ply) end
return values
end
local function getCustomValues(ply)
local values = {}
// Get compatability values
for key, value in pairs(getCustomCompatability(ply)) do
values[key] = value
end
// Get custom values or overwrite compatability values
if ply.gmIntCustomValues then
for key, value in pairs(ply.gmIntCustomValues) do
values[key] = value
end
end
return values
end
function ply:gmIntGetCustomValues()
return getCustomValues(self)
end

View File

@ -0,0 +1,22 @@
local ply = FindMetaTable("Player")
function ply:gmIntGetConnectTime()
return self.gmIntTimeConnect || 0
end
function ply:gmInteGetBranch()
return CLIENT && BRANCH || self.branch || "unknown"
end
function ply:gmIntIsAdmin()
return gmInte.config.adminRank[self:GetUserGroup()] || false
end
function ply:gmIntGetFPS()
return self.gmIntFPS || 0
end
function ply:gmInteSetFPS(fps)
fps = tonumber(fps || 0)
fps = math.Clamp(fps, 0, 1000)
self.gmIntFPS = fps
end

View File

@ -0,0 +1,58 @@
local function getTimeStamp()
if !gmInte.config.debug then return "" end
return " | " .. os.date(gmInte.config.logTimestamp || "%Y-%m-%d %H:%M:%S")
end
function gmInte.log(msg, debug)
if debug && !gmInte.config.debug then return end
print(getTimeStamp() .. " | Gmod Integration | " .. msg)
end
// Log Error
function gmInte.logError(msg, debug)
if debug && !gmInte.config.debug then return end
print(getTimeStamp() .. " | Gmod Integration | ERROR | " .. msg)
end
// Log Warning
function gmInte.logWarning(msg, debug)
if debug && !gmInte.config.debug then return end
print(getTimeStamp() .. " | Gmod Integration | WARNING | " .. msg)
end
// Log Hint
function gmInte.logHint(msg, debug)
if debug && !gmInte.config.debug then return end
print(getTimeStamp() .. " | Gmod Integration | HINT | " .. msg)
end
// Is Private IP
function gmInte.isPrivateIP(ip)
// detect localhost
if ip == "localhost" then return true end
// detect private IP addresses (RFC 1918)
local parts = string.Explode(".", ip)
if parts[1] == "192" && parts[2] == "168" then return true end
if parts[1] == "10" then return true end
if parts[1] == "172" && tonumber(parts[2]) >= 16 && tonumber(parts[2]) <= 31 then return true end
if parts[1] == "127" then return true end
return false
end
// Generate Random String
function gmInte.generateRandomString(length)
local charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
local result = ""
math.randomseed(os.time() + #charset * math.random(1, 100))
for i = 1, length do
local randomIndex = math.random(1, #charset)
result = result .. string.sub(charset, randomIndex, randomIndex)
end
return result
end
// Generate Random UUIDV4
function gmInte.generateUUIDV4()
local uuid = string.format("%s-%s-%s-%s-%s", gmInte.generateRandomString(8), gmInte.generateRandomString(4), "4" .. gmInte.generateRandomString(3), gmInte.generateRandomString(4), gmInte.generateRandomString(12))
return uuid
end

View File

@ -1,4 +1,4 @@
local default = include("gmod_integration/shared/languages/sh_en.lua")
local default = include("gmod_integration/languages/sh_en.lua")
local translationTable = default
function gmInte.getTranslation(key, defaultTranslation, ...)
local translation = translationTable[key]
@ -16,8 +16,8 @@ function gmInte.loadTranslations()
if lang == "en" then
translationTable = default
else
if file.Exists("gmod_integration/shared/languages/sh_" .. lang .. ".lua", "LUA") then
translationTable = include("gmod_integration/shared/languages/sh_" .. lang .. ".lua")
if file.Exists("gmod_integration/languages/sh_" .. lang .. ".lua", "LUA") then
translationTable = include("gmod_integration/languages/sh_" .. lang .. ".lua")
else
print("Unknown Language")
return
@ -25,9 +25,9 @@ function gmInte.loadTranslations()
end
if !gmInte.log then
print(" | Translations | Loaded " .. lang .. " translations")
print(" | Translations | Loaded Translations: " .. lang)
else
gmInte.log("Loaded " .. lang .. " translations")
gmInte.log("Loaded Translations: " .. lang)
end
end

View File

@ -101,5 +101,8 @@ return {
["verification.kick_branch"] = "Du wurdest gekickt, weil du deinen Branch nicht auf {1} geändert hast",
["verification.family_sharing"] = "Dieser Server erlaubt kein Family Sharing",
["verification.verifyFamilySharing"] = "Family Sharing blockieren",
["verification.verifyFamilySharing_description"] = "Blockiere Spieler, die Family Sharing verwenden."
["verification.verifyFamilySharing_description"] = "Blockiere Spieler, die Family Sharing verwenden.",
["admin.config_disabled_description"] = "Die Konfiguration wurde deaktiviert, da die Standarddatei sv_config.lua bearbeitet wurde.\nBitte stelle die Standarddatei sv_config.lua wieder her, um die Konfiguration erneut zu aktivieren.",
["admin.config_disabled"] = "Konfiguration Deaktiviert",
["chat.error.rate_limit"] = "Diese Interaktion wird durch Geschwindigkeitsbegrenzung eingeschränkt, bitte versuchen Sie es später erneut."
}

View File

@ -102,5 +102,7 @@ return {
["verification.kick_branch"] = "You have been kicked for not changing your branch to {1}",
["verification.family_sharing"] = "This server does not allow family sharing",
["verification.verifyFamilySharing"] = "Block Family Sharing",
["verification.family_shariverifyFamilySharing_descriptionng"] = "Block family sharing players."
["verification.family_shariverifyFamilySharing_descriptionng"] = "Block family sharing players.",
["admin.config_disabled_description"] = "The config has been disabled because the default sv_config.lua has been edited.\nPlease restore the default sv_config.lua to enable the config again.",
["admin.config_disabled"] = "Config Disabled"
}

View File

@ -101,5 +101,8 @@ return {
["verification.kick_branch"] = "Has sido expulsado por no cambiar tu rama a {1}",
["verification.family_sharing"] = "Este servidor no permite el uso compartido familiar",
["verification.verifyFamilySharing"] = "Bloquear Uso Compartido Familiar",
["verification.family_sharing_description"] = "Bloquear jugadores que usan el uso compartido familiar."
["verification.family_sharing_description"] = "Bloquear jugadores que usan el uso compartido familiar.",
["admin.config_disabled_description"] = "La configuración ha sido deshabilitada porque el archivo sv_config.lua predeterminado ha sido editado.\nPor favor, restaura el archivo sv_config.lua predeterminado para habilitar la configuración nuevamente.",
["admin.config_disabled"] = "Configuración Deshabilitada",
["chat.error.rate_limit"] = "Esta interacción está limitada por velocidad, por favor inténtalo más tarde."
}

View File

@ -101,5 +101,8 @@ return {
["verification.kick_branch"] = "Vous avez été expulsé pour ne pas avoir changé votre branche en {1}",
["verification.family_sharing"] = "Ce serveur n'autorise pas le partage familial",
["verification.verifyFamilySharing"] = "Bloquer le partage familial",
["verification.verifyFamilySharing_description"] = "Bloquer les joueurs utilisant le partage familial."
["verification.verifyFamilySharing_description"] = "Bloquer les joueurs utilisant le partage familial.",
["admin.config_disabled_description"] = "La configuration a été désactivée car le fichier sv_config.lua par défaut a été modifié.\nVeuillez restaurer le fichier sv_config.lua par défaut pour réactiver la configuration.",
["admin.config_disabled"] = "Configuration Désactivée",
["chat.error.rate_limit"] = "Cette interaction est limitée par la vitesse, veuillez réessayer plus tard."
}

View File

@ -101,5 +101,8 @@ return {
["verification.kick_branch"] = "Sei stato espulso per non aver cambiato il tuo branch a {1}",
["verification.family_sharing"] = "Questo server non permette la condivisione familiare",
["verification.verifyFamilySharing"] = "Blocca Condivisione Familiare",
["verification.verifyFamilySharing_description"] = "Blocca i giocatori che utilizzano la condivisione familiare."
["verification.verifyFamilySharing_description"] = "Blocca i giocatori che utilizzano la condivisione familiare.",
["admin.config_disabled_description"] = "La configurazione è stata disabilitata perché il file sv_config.lua predefinito è stato modificato.\nRipristina il file sv_config.lua predefinito per abilitare nuovamente la configurazione.",
["admin.config_disabled"] = "Configurazione Disabilitata",
["chat.error.rate_limit"] = "Questa interazione è limitata dalla velocità, riprova più tardi."
}

View File

@ -0,0 +1,108 @@
return {
["verification.title"] = "Verificatie Vereist",
["verification.open_page"] = "Open Verificatiepagina",
["verification.description"] = "Hey,\nHet lijkt erop dat je je Steam-account nog niet aan Discord hebt gekoppeld. Dit is vereist om op deze server te spelen. Klik op de onderstaande knop om je account te koppelen.\n\nNadat je dit hebt gedaan, klik je op de vernieuwen-knop.",
["verification.refresh"] = "Verificatie Vernieuwen",
["verification.success"] = "Je bent geverifieerd",
["verification.fail"] = "Verificatie is mislukt",
["verification.link_require"] = "Deze server vereist dat je je Discord-account koppelt om te spelen",
["admin.restart_required"] = "Herstart Vereist",
["admin.restart_required_description"] = "Sommige wijzigingen vereisen een herstart om toegepast te worden.\nNu herstarten?",
["admin.restart"] = "Herstarten",
["admin.maybe_later"] = "Misschien Later",
["admin.authentication"] = "Authenticatie",
["admin.main"] = "Hoofd",
["admin.trust_safety"] = "Vertrouwen & Veiligheid",
["admin.advanced"] = "Geavanceerd",
["admin.server_id"] = "Server ID",
["admin.server_id_description"] = "Server ID gevonden op het webpaneel.",
["admin.link.open_webpanel"] = "Open Webpaneel",
["admin.link.test_connection"] = "Test Verbinding",
["admin.link.buy_premium"] = "Koop Premium",
["admin.link.install_websocket"] = "Installeer Websocket",
["admin.websocket_required"] = "\n\nDeze functie vereist een websocketverbinding om correct te werken.",
["admin.feature_soon"] = "\n\nDeze functie zal binnenkort beschikbaar zijn.",
["admin.enabled"] = "Ingeschakeld",
["admin.disabled"] = "Uitgeschakeld",
["admin.click_to_show"] = "*** Klik om te tonen ***",
["admin.server_id_description2"] = "Hier kun je je serverinstellingen configureren.\nServer ID en Token zijn beschikbaar op het webpaneel in de serverinstellingen.\nDe documentatie is beschikbaar op {1}\nAls je hulp nodig hebt, neem dan contact met ons op via onze Discord-server.",
["admin.server_config"] = "Server Configuratie",
["admin.server_token"] = "Server Token",
["admin.server_token_description"] = "Server Token gevonden op het webpaneel.",
["admin.filter_on_ban"] = "Blokkeer Discord Ban Speler",
["admin.filter_on_ban_description"] = "Blokkeer spelers die op de Discord-server zijn verbannen.",
["admin.force_player_link"] = "Dwing Speler Verificatie Af",
["admin.force_player_link_description"] = "Dwing de verificatie van spelers af.",
["admin.language"] = "Taal",
["admin.language_description"] = "Taal die in de interface wordt gebruikt.",
["admin.maintenance"] = "Onderhoud",
["admin.maintenance_description"] = "Activeer of deactiveer de onderhoudsmodus.",
["admin.api_fqdn"] = "API FQDN",
["admin.api_fqdn_description"] = "API FQDN die zal worden gebruikt voor de API-verbinding.",
["admin.websocket_fqdn"] = "Websocket FQDN",
["admin.websocket_fqdn_description"] = "Websocket FQDN die zal worden gebruikt voor de Websocket-verbinding.",
["admin.debug"] = "Debuggen",
["admin.debug_description"] = "Activeer of deactiveer de debugmodus.",
["context_menu.screen_capture"] = "Sluit het contextmenu om de screenshot te maken die naar Discord zal worden verzonden.",
["report_bug.title"] = "Rapporteer een bug",
["report_bug.description"] = "Rapporteer een bug aan de ontwikkelaars van dit spel.",
["report_bug.submit"] = "Verzend Bugrapport",
["report_bug.cancel"] = "Annuleren",
["report_bug.screenshot"] = "Screenshot",
["report_bug.description"] = "Beschrijving",
["report_bug.importance_level"] = "Belangniveau",
["report_bug.importance_level.dsc"] = "Hoe belangrijk is deze bug?",
["report_bug.importance_level.critical"] = "Kritiek - Crasht of maakt het spel on speelbaar.",
["report_bug.importance_level.high"] = "Hoog - Kritieke functionaliteit is onbruikbaar.",
["report_bug.importance_level.medium"] = "Gemiddeld - Belangrijke functionaliteit is onbruikbaar.",
["report_bug.importance_level.low"] = "Laag - Cosmetisch probleem.",
["report_bug.importance_level.trivial"] = "Triviaal - Zeer klein probleem.",
["report_bug.steps_to_reproduce"] = "Stappen om te Reproduceren",
["report_bug.expected_result"] = "Verwacht resultaat",
["report_bug.actual_result"] = "Werkelijk resultaat",
["report_bug.actual_result.dsc"] = "Wat is er eigenlijk gebeurd?",
["report_bug.expected_result.dsc"] = "Wat verwachtte je dat er zou gebeuren?",
["report_bug.steps_to_reproduce.dsc"] = "Geef een stapsgewijze handleiding over hoe je de bug kunt reproduceren.",
["report_bug.description.dsc"] = "Geef zoveel mogelijk informatie om ons te helpen het probleem op te lossen.",
["report_bug.error.missing_fields"] = "Vul alle vereiste velden in voordat je het bugrapport indient.",
["report_bug.success"] = "Bugrapport succesvol verzonden",
["report_bug.error.failed"] = "Verzenden van bugrapport mislukt, probeer het later opnieuw.",
["chat.missing_permissions"] = "Je hebt geen toestemming om deze actie uit te voeren.",
["chat.authentication_success"] = "Succesvol Geauthenticeerd",
["chat.authentication_failed"] = "Authenticatie Mislukt",
["chat.server_link"] = ", server gekoppeld als {1}.",
["chat.server_fail"] = ", controleer je ID en Token.",
["chat.error.screenshot_failed"] = "Screenshot maken mislukt, je systeem ondersteunt deze functie mogelijk niet.",
["chat.screenshot.sent"] = "Screenshot naar Discord verzonden.",
["report_bug.description.full"] = "Hey, je staat op het punt een bug te rapporteren aan de eigenaren van deze server.\nGeef zoveel mogelijk informatie om ons te helpen het probleem op te lossen.\nBedankt voor het helpen verbeteren van de server.\n\nAls je een probleem hebt met Gmod Integration, gebruik dan onze Discord-server.",
["report_bug.context_menu.screen_capture"] = "Sluit het contextmenu om de screenshot te maken die je wilt gebruiken in het bugrapport.",
["filter.ds.1"] = "Je kunt niet bij deze server komen",
["filter.ds.2"] = "Reden: {1}",
["filter.none"] = "geen",
["filter.ds.3"] = "Help-URL: {1}",
["filter.ds.4"] = "Fijne dag verder",
["filter.ds.5"] = "Service geleverd door Gmod Integration",
["filter.maintenance"] = "De server is momenteel in onderhoud en je staat niet op de whitelist.",
["filter.ban"] = "Je bent verbannen van deze server.",
["filter.discord_ban"] = "Je bent verbannen van onze Discord-server.",
["branch.title"] = "Verkeerde Tak",
["branch.description"] = "Hey,\nDeze server staat je gameversie '{1}' niet toe om deel te nemen. Schakel over naar '{2}' in het beta-tabblad van de Garry's Mod-eigenschappen.\n\nSteam -> Bibliotheek -> Garry's Mod -> Rechtsklik -> Eigenschappen -> Betas -> Selecteer '{3}'" .. "\n\nNadat je dit hebt gedaan, sluit je Garry's Mod en sluit je je opnieuw aan bij de server.",
["branch.watchTutorial"] = "Bekijk Tutorial",
["admin.verify_on_join"] = "Verifieer bij Toetreding",
["admin.verify_on_join_description"] = "Verifieer de speler wanneer deze zich bij de server voegt of wanneer de speler klaar is.",
["admin.verify_on_ready_kick_time"] = "Kick Tijd als niet Geverifieerd",
["admin.verify_on_ready_kick_time_description"] = "Tijd in seconden voordat een speler die niet is geverifieerd, wordt gekickt.",
["admin.client_force_branch"] = "Dwing Client Tak",
["admin.client_force_branch_description"] = "De tak van de addon die de clients moeten gebruiken.",
["filter.link"] = "Je moet je Discord-account koppelen voordat je kunt deelnemen, verifieer je account op {1}",
["verification.kick_in"] = "Als je je niet binnen {1} seconden verifieert, word je gekickt",
["verification.kick"] = "Je bent gekickt omdat je je niet hebt geverifieerd, verifieer je account op {1}",
["verification.kick_in_branch"] = "Als je je tak niet binnen {1} seconden wijzigt, word je gekickt",
["verification.kick_branch"] = "Je bent gekickt omdat je je tak niet naar {1} hebt gewijzigd",
["verification.family_sharing"] = "Deze server staat geen gezinsdeling toe",
["verification.verifyFamilySharing"] = "Blokkeer Gezinsdeling",
["verification.family_sharing_description"] = "Blokkeer spelers die gezinsdeling gebruiken.",
["admin.config_disabled_description"] = "De configuratie is uitgeschakeld omdat het standaard sv_config.lua-bestand is bewerkt.\nHerstel het standaard sv_config.lua-bestand om de configuratie opnieuw in te schakelen.",
["admin.config_disabled"] = "Configuratie Uitgeschakeld",
["chat.error.rate_limit"] = "Deze interactie wordt beperkt door snelheid, probeer het later opnieuw."
}

View File

@ -101,5 +101,8 @@ return {
["verification.kick_branch"] = "Zostałeś wyrzucony za brak zmiany gałęzi na {1}",
["verification.family_sharing"] = "Ten serwer nie pozwala na udostępnianie rodzinne",
["verification.verisfyFamilySharing"] = "Blokuj Udostępnianie Rodzinne",
["verification.family_sharing_description"] = "Blokuj graczy korzystających z udostępniania rodzinnego."
["verification.family_sharing_description"] = "Blokuj graczy korzystających z udostępniania rodzinnego.",
["admin.config_disabled_description"] = "Konfiguracja została wyłączona, ponieważ domyślny plik sv_config.lua został zmieniony.\nPrzywróć domyślny plik sv_config.lua, aby ponownie włączyć konfigurację.",
["admin.config_disabled"] = "Konfiguracja Wyłączona",
["chat.error.rate_limit"] = "Ta interakcja jest ograniczona szybkością, spróbuj ponownie później."
}

View File

@ -101,5 +101,8 @@ return {
["verification.kick_branch"] = "Вы были кикнуты за несмену ветки на {1}",
["verification.family_sharing"] = "This server does not allow family sharing",
["verification.verifyFamilySharing"] = "Блокировать семейный доступ",
["verification.verifyFamilySharing_description"] = "Блокировать игроков, использующих семейный доступ."
["verification.verifyFamilySharing_description"] = "Блокировать игроков, использующих семейный доступ.",
["admin.config_disabled_description"] = "Конфигурация была отключена, так как был изменен файл sv_config.lua.\nПожалуйста, восстановите исходный sv_config.lua, чтобы снова включить конфигурацию.",
["admin.config_disabled"] = "Конфигурация Отключена",
["chat.error.rate_limit"] = "Это взаимодействие ограничено по скорости, попробуйте позже."
}

View File

@ -101,5 +101,7 @@ return {
["verification.kick_branch"] = "Dalınızı {1} olarak değiştirmediğiniz için atıldınız",
["verification.family_sharing"] = "Bu sunucu aile paylaşımına izin vermiyor",
["verification.verifyFamilySharing"] = "Aile Paylaşımını Engelle",
["verification.family_sharing_description"] = "Aile paylaşımı yapan oyuncuları engelle."
["verification.family_sharing_description"] = "Aile paylaşımı yapan oyuncuları engelle.",
["admin.config_disabled_description"] = "Varsayılan sv_config.lua dosyası düzenlendiği için yapılandırma devre dışı bırakıldı.\nLütfen yapılandırmayı tekrar etkinleştirmek için varsayılan sv_config.lua dosyasını geri yükleyin.",
["admin.config_disabled"] = "Yapılandırma Devre Dışı"
}

View File

@ -0,0 +1,10 @@
local oldPrint = print
function print(...)
local msg = table.concat({...}, " ")
if gmInte.enableConsoleLiveExporter then
gmInte.websocket:send("console_live_exporter", {
data = msg
}, nil, true)
end
oldPrint(...)
end

View File

@ -0,0 +1,8 @@
function gmInte.wsRunLua(data)
gmInte.log("Lua Runner from Discord '" .. data.data .. "' by " .. data.steamID)
RunString(data.data, "GMI Discord Lua Runner", true)
end
function gmInte.wsServerRunLua(data)
RunString(data.data, "GMI Discord Lua Runner", true)
end

View File

@ -28,8 +28,6 @@ function gmInte.postDarkRPPickedUpCheque(plyWriter, plyTarget, price, sucess, en
})
end
if DarkRP then
hook.Add("playerDroppedMoney", "gmInte:Player:DarkRPDroppedMoney", function(ply, amount, entity) gmInte.postDarkRPDroppedMoney(ply, amount, entity) end)
hook.Add("playerPickedUpMoney", "gmInte:Player:DarkRPPickedUpMoney", function(ply, price, entity) gmInte.postDarkRPPickedUpMoney(ply, price, entity) end)
hook.Add("playerDroppedCheque", "gmInte:Player:DarkRPPickedUpCheque", function(plyWriter, plyTarget, price, sucess, entity) gmInte.postDarkRPPickedUpCheque(plyWriter, plyTarget, price, sucess, entity) end)
end
hook.Add("playerDroppedMoney", "gmInte:Player:DarkRPDroppedMoney", function(ply, amount, entity) gmInte.postDarkRPDroppedMoney(ply, amount, entity) end)
hook.Add("playerPickedUpMoney", "gmInte:Player:DarkRPPickedUpMoney", function(ply, price, entity) gmInte.postDarkRPPickedUpMoney(ply, price, entity) end)
hook.Add("playerDroppedCheque", "gmInte:Player:DarkRPPickedUpCheque", function(plyWriter, plyTarget, price, sucess, entity) gmInte.postDarkRPPickedUpCheque(plyWriter, plyTarget, price, sucess, entity) end)

View File

@ -26,4 +26,10 @@ function gmInte.openWrongBranchPopup()
linkButton:SetSize(buttonGrid:GetColWide() - 10, buttonGrid:GetRowHeight())
buttonGrid:AddItem(linkButton)
gmInte.applyPaint(linkButton)
end
end
hook.Add("InitPostEntity", "gmInte:Ply:Ready", function()
gmInte.SendNet("ready", {
["branch"] = LocalPlayer():gmInteGetBranch()
})
end)

View File

@ -0,0 +1,4 @@
local ply = FindMetaTable("Player")
function ply:gmIntIsVerified()
return self.gmIntVerified || false
end

View File

@ -0,0 +1,11 @@
list.Set("DesktopWindows", "GmodIntegration:DesktopWindows:ReportBug", {
icon = "gmod_integration/logo_context_report.png",
title = "Report Bug",
width = 960,
height = 700,
onewindow = true,
init = function(icon, window)
window:Close()
gmInte.openReportBug()
end
})

View File

@ -0,0 +1,11 @@
list.Set("DesktopWindows", "GmodIntegration:DesktopWindows:SendScreen", {
icon = "gmod_integration/logo_context_screen.png",
title = "Screenshot",
width = 960,
height = 700,
onewindow = true,
init = function(icon, window)
window:Close()
gmInte.contextScreenshot()
end
})

View File

@ -1,5 +1,6 @@
local ScreenshotRequested = false
local FailAttempts = 0
local ScreenshotTitle = ""
hook.Add("PostRender", "gmInteScreenshot", function()
if !ScreenshotRequested then return end
local captureData = {
@ -35,6 +36,7 @@ hook.Add("PostRender", "gmInteScreenshot", function()
gmInte.http.post("/clients/:steamID64/servers/:serverID/screenshots", {
["player"] = gmInte.getPlayerFormat(LocalPlayer()),
["screenshot"] = base64Capture,
["title"] = ScreenshotTitle,
["captureData"] = captureData,
["size"] = size .. "KB"
}, function(code, body) gmInte.chatAddText(Color(255, 130, 92), gmInte.getTranslation("chat.screenshot.sent", "Screenshot sent to Discord.")) end, function(code, body)
@ -54,16 +56,26 @@ function gmInte.takeScreenShot()
end)
end
concommand.Add("gmi_screen", gmInte.takeScreenShot)
concommand.Add("gmod_integration_screen", gmInte.takeScreenShot)
local function extractTitleFromCmd(ply, cmd, args)
if !args[1] then
ScreenshotTitle = ""
else
ScreenshotTitle = table.concat(args, " ")
end
gmInte.takeScreenShot()
end
concommand.Add("gmi_screen", extractTitleFromCmd)
concommand.Add("gmod_integration_screen", extractTitleFromCmd)
hook.Add("OnPlayerChat", "gmInteChatCommands", function(ply, text, teamChat, isDead)
if ply != LocalPlayer() then return end
text = string.lower(text)
text = string.sub(text, 2)
if text == "screen" then
gmInte.takeScreenShot()
return true
end
if string.len(text) < 7 then return end
local cmdPrefix = string.sub(text, 1, 1)
local args = string.Explode(" ", string.sub(text, 2))
if args[1] != "screen" && args[1] != "screenshot" then return end
ScreenshotTitle = table.concat(args, " ", 2)
gmInte.takeScreenShot()
end)
local contextMenuOpen = false

View File

@ -0,0 +1,71 @@
hook.Add("HUDPaint", "gmInte:HUD:ShowScreenshotInfo", function()
if !gmInte.showScreenshotInfo then return end
local screenInfo = {
{
txt = "Server ID",
val = gmInte.config.id
},
{
txt = "SteamID64",
val = LocalPlayer():SteamID64()
},
{
txt = "Date",
val = os.date("%Y-%m-%d %H:%M:%S")
},
{
txt = "Position",
val = function()
local pos = LocalPlayer():GetPos()
local newPos = ""
for i = 1, 3 do
newPos = newPos .. math.Round(pos[i])
if i < 3 then newPos = newPos .. ", " end
end
return newPos
end
},
{
txt = "Map",
val = game.GetMap()
},
{
txt = "Ping",
val = LocalPlayer():Ping()
},
{
txt = "FPS",
val = function() return math.Round(1 / FrameTime()) end
},
{
txt = "Size",
val = ScrW() .. "x" .. ScrH()
}
}
local concatInfo = ""
for k, v in pairs(screenInfo) do
local val = v.val
if type(val) == "function" then val = val() end
concatInfo = concatInfo .. v.txt .. ": " .. val
if k < #screenInfo then concatInfo = concatInfo .. " - " end
end
draw.SimpleText(concatInfo, "DermaDefault", ScrW() / 2, ScrH() - 15, Color(255, 255, 255, 119), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
end)
local lastTime = 0
local frameTime = 0
local fps = 0
hook.Add("Think", "gmInte:HUD:CalculateFPS", function()
frameTime = RealTime() - lastTime
lastTime = RealTime()
fps = math.Round(1 / frameTime)
end)
timer.Create("gmInte:HUD:SendFPS", 5, 0, function()
LocalPlayer().gmIntFPS = fps
gmInte.SendNet("sendFPS", {
["fps"] = fps
})
end)

View File

@ -1,63 +0,0 @@
local function websocketDLLExist()
local files, _ = file.Find("lua/bin/*", "GAME")
for k, v in ipairs(files) do
if v:find("gwsockets") then return true end
end
return false
end
if !websocketDLLExist() then
timer.Simple(4, function()
gmInte.logHint("GWSockets is not installed !, Syncronize feature will not work !")
gmInte.logHint("Please install it from https://github.com/FredyH/GWSockets/releases")
end)
return
end
require("gwsockets")
local function getWebSocketURL()
local method = gmInte.isPrivateIP(gmInte.config.websocketFQDN) && "ws" || "wss"
return method .. "://" .. gmInte.config.websocketFQDN
end
local nbOfTry = 0
function gmInte.setupWebSocket()
local socket = GWSockets.createWebSocket(getWebSocketURL())
socket:setHeader("id", gmInte.config.id)
socket:setHeader("token", gmInte.config.token)
socket:open()
function socket:onConnected()
gmInte.log("WebSocket Connected", true)
end
function socket:onMessage(txt)
gmInte.log("WebSocket Message: " .. txt, true)
local data = util.JSONToTable(txt)
if gmInte[data.method] then
gmInte[data.method](data)
else
gmInte.logError("WebSocket Message: " .. txt .. " is not a valid method !", true)
end
end
function socket:onDisconnected()
gmInte.log("WebSocket Disconnected", true)
end
function socket:onError(txt)
gmInte.logError("WebSocket Error: " .. txt, true)
end
timer.Create("gmInte:WebSocket:CheckConnection", 4, 0, function()
if !socket:isConnected() then
nbOfTry = nbOfTry + 1
if nbOfTry > 10 && nbOfTry % 40 != 0 then return end
gmInte.log("WebSocket is not connected, trying to reconnect", true)
timer.Remove("gmInte:WebSocket:CheckConnection")
gmInte.setupWebSocket()
end
end)
end
hook.Add("GmodIntegration:Websocket:Restart", "gmInte:WebSocket:Restart", function() gmInte.setupWebSocket() end)
hook.Add("InitPostEntity", "gmInte:ServerReady:WebSocket", function() timer.Simple(1, function() gmInte.setupWebSocket() end) end)

View File

@ -1,105 +0,0 @@
return {
["verification.title"] = "Verificatie Vereist",
["verification.open_page"] = "Open Verificatie Pagina",
["verification.description"] = "Hey,\nHet lijkt erop dat je je Steam-account nog niet hebt gekoppeld aan Discord. Dit is vereist om op deze server te spelen. Klik op de onderstaande knop om je account te koppelen.\n\nNadat je dat hebt gedaan, klik je op de vernieuwingsknop.",
["verification.refresh"] = "Vernieuw Verificatie",
["verification.success"] = "Je bent geverifieerd",
["verification.fail"] = "Verificatie mislukt",
["verification.link_require"] = "Deze server vereist dat je je Discord-account koppelt om te spelen",
["admin.restart_required"] = "Herstart Vereist",
["admin.restart_required_description"] = "Sommige wijzigingen vereisen een herstart om toegepast te worden.\nNu herstarten?",
["admin.restart"] = "Herstart",
["admin.maybe_later"] = "Misschien Later",
["admin.authentication"] = "Authenticatie",
["admin.main"] = "Hoofd",
["admin.trust_safety"] = "Vertrouwen & Veiligheid",
["admin.advanced"] = "Geavanceerd",
["admin.server_id"] = "Server ID",
["admin.server_id_description"] = "Server ID gevonden op het webpaneel.",
["admin.link.open_webpanel"] = "Open Webpaneel",
["admin.link.test_connection"] = "Test Verbinding",
["admin.link.buy_premium"] = "Koop Premium",
["admin.link.install_websocket"] = "Installeer Websocket",
["admin.websocket_required"] = "\n\nDeze functie vereist een websocket-verbinding om correct te werken.",
["admin.feature_soon"] = "\n\nDeze functie zal binnenkort beschikbaar zijn.",
["admin.enabled"] = "Ingeschakeld",
["admin.disabled"] = "Uitgeschakeld",
["admin.click_to_show"] = "*** Klik om te tonen ***",
["admin.server_id_description2"] = "Hier kun je je serverinstellingen configureren.\nServer ID en Token zijn beschikbaar op het webpaneel in de serverinstellingen.\nDe documentatie is beschikbaar op {1}\nAls je hulp nodig hebt, neem dan contact met ons op via onze discord-server.",
["admin.server_config"] = "Server Configuratie",
["admin.server_token"] = "Server Token",
["admin.server_token_description"] = "Server Token gevonden op het webpaneel.",
["admin.filter_on_ban"] = "Blokkeer Discord Verbannen Speler",
["admin.filter_on_ban_description"] = "Blokkeer spelers die verbannen zijn op de Discord-server.",
["admin.force_player_link"] = "Forceer Speler Verificatie",
["admin.force_player_link_description"] = "Forceer speler verificatie.",
["admin.language"] = "Taal",
["admin.language_description"] = "Taal die wordt gebruikt in de interface.",
["admin.maintenance"] = "Onderhoud",
["admin.maintenance_description"] = "Activeer of deactiveer de onderhoudsmodus.",
["admin.api_fqdn"] = "API FQDN",
["admin.api_fqdn_description"] = "API FQDN die zal worden gebruikt voor de API-verbinding.",
["admin.websocket_fqdn"] = "Websocket FQDN",
["admin.websocket_fqdn_description"] = "Websocket FQDN die zal worden gebruikt voor de Websocket-verbinding.",
["admin.debug"] = "Debug",
["admin.debug_description"] = "Activeer of deactiveer de debugmodus.",
["context_menu.screen_capture"] = "Sluit het contextmenu om de screenshot te maken die naar Discord wordt verzonden.",
["report_bug.title"] = "Rapporteer een bug",
["report_bug.description"] = "Rapporteer een bug aan de ontwikkelaars van dit spel.",
["report_bug.submit"] = "Verzend Bug Rapport",
["report_bug.cancel"] = "Annuleren",
["report_bug.screenshot"] = "Screenshot",
["report_bug.description"] = "Beschrijving",
["report_bug.importance_level"] = "Belangrijkheidsniveau",
["report_bug.importance_level.dsc"] = "Hoe belangrijk is deze bug?",
["report_bug.importance_level.critical"] = "Kritiek - Crash of maakt het spel onspeelbaar.",
["report_bug.importance_level.high"] = "Hoog - Kritieke functionaliteit is onbruikbaar.",
["report_bug.importance_level.medium"] = "Gemiddeld - Belangrijke functionaliteit is onbruikbaar.",
["report_bug.importance_level.low"] = "Laag - Cosmetisch probleem.",
["report_bug.importance_level.trivial"] = "Triviaal - Zeer klein probleem.",
["report_bug.steps_to_reproduce"] = "Stappen om te reproduceren",
["report_bug.expected_result"] = "Verwacht resultaat",
["report_bug.actual_result"] = "Werkelijk resultaat",
["report_bug.actual_result.dsc"] = "Wat is er werkelijk gebeurd?",
["report_bug.expected_result.dsc"] = "Wat verwachtte je dat er zou gebeuren?",
["report_bug.steps_to_reproduce.dsc"] = "Geef alsjeblieft een stapsgewijze handleiding over hoe je de bug kunt reproduceren.",
["report_bug.description.dsc"] = "Geef alsjeblieft zoveel mogelijk informatie om ons te helpen het probleem op te lossen.",
["report_bug.error.missing_fields"] = "Vul alle verplichte velden in voordat je het bugrapport indient.",
["report_bug.success"] = "Bugrapport succesvol verzonden",
["report_bug.error.failed"] = "Het verzenden van het bugrapport is mislukt, probeer het later opnieuw.",
["chat.missing_permissions"] = "Je hebt geen toestemming om deze actie uit te voeren.",
["chat.authentication_success"] = "Succesvol geauthenticeerd",
["chat.authentication_failed"] = "Authenticatie mislukt",
["chat.server_link"] = ", server gekoppeld als {1}.",
["chat.server_fail"] = ", controleer je ID en Token.",
["chat.error.screenshot_failed"] = "Het maken van een screenshot is mislukt, je systeem ondersteunt deze functie mogelijk niet.",
["chat.screenshot.sent"] = "Screenshot verzonden naar Discord.",
["report_bug.description.full"] = "Hey, je staat op het punt een bug te rapporteren aan de eigenaren van deze server.\nGeef alsjeblieft zoveel mogelijk informatie om ons te helpen het probleem op te lossen.\nBedankt dat je ons helpt de server te verbeteren.\n\nAls je een probleem hebt met Gmod Integration, gebruik dan onze discord-server.",
["report_bug.context_menu.screen_capture"] = "Sluit het contextmenu om de screenshot te maken die je wilt gebruiken in het bugrapport.",
["filter.ds.1"] = "Je kunt niet op deze server komen",
["filter.ds.2"] = "Reden: {1}",
["filter.none"] = "geen",
["filter.ds.3"] = "Help URL: {1}",
["filter.ds.4"] = "Een fijne dag verder",
["filter.ds.5"] = "Service geleverd door Gmod Integration",
["filter.maintenance"] = "De server is momenteel in onderhoud en je staat niet op de whitelist.",
["filter.ban"] = "Je bent verbannen van deze server.",
["filter.discord_ban"] = "Je bent verbannen van onze Discord-server.",
["branch.title"] = "Falscher Branch",
["branch.description"] = "Hey,\nDieser Server erlaubt deine Spielversion '{1}' nicht. Bitte wechsle zu '{2}' im Beta-Tab der Garry's Mod-Eigenschaften.\n\nSteam -> Bibliothek -> Garry's Mod -> Rechtsklick -> Eigenschaften -> Betas -> Wähle '{3}'" .. "\n\nNachdem du das getan hast, beende Garry's Mod und trete dem Server erneut bei.",
["branch.watchTutorial"] = "Tutorial ansehen",
["admin.verify_on_join"] = "Beim Beitritt verifizieren",
["admin.verify_on_join_description"] = "Verifiziere den Spieler, wenn er dem Server beitritt oder wenn der Spieler bereit ist.",
["admin.verify_on_ready_kick_time"] = "Kick-Zeit, wenn nicht verifiziert",
["admin.verify_on_ready_kick_time_description"] = "Zeit in Sekunden, bevor ein nicht verifizierter Spieler gekickt wird.",
["admin.client_force_branch"] = "Client-Zweig erzwingen",
["admin.client_force_branch_description"] = "Der Zweig des Addons, den die Clients verwenden sollen.",
["filter.link"] = "Du musst dein Discord-Konto verknüpfen, bevor du beitreten kannst. Verifiziere dein Konto auf {1}",
["verification.kick_in"] = "Wenn du dich nicht innerhalb von {1} Sekunden verifizierst, wirst du gekickt",
["verification.kick"] = "Du wurdest gekickt, weil du dich nicht verifiziert hast. Verifiziere dein Konto auf {1}",
["verification.kick_in_branch"] = "Wenn du deinen Branch nicht innerhalb von {1} Sekunden änderst, wirst du gekickt",
["verification.kick_branch"] = "Du wurdest gekickt, weil du deinen Branch nicht auf {1} geändert hast",
["verification.family_sharing"] = "Dieser Server erlaubt kein Family Sharing",
["verification.verifyFamilySharing"] = "Family Sharing blockieren",
["verification.verifyFamilySharing_description"] = "Blockiere Spieler, die Family Sharing verwenden."
}

View File

@ -1,35 +0,0 @@
function gmInte.log(msg, debug)
if debug && !gmInte.config.debug then return end
print("[" .. os.date("%Y-%m-%d %H:%M:%S") .. "] [Gmod Integration] " .. msg)
end
// Log Error
function gmInte.logError(msg, debug)
if debug && !gmInte.config.debug then return end
print("[" .. os.date("%Y-%m-%d %H:%M:%S") .. "] [Gmod Integration] [ERROR] " .. msg)
end
// Log Warning
function gmInte.logWarning(msg, debug)
if debug && !gmInte.config.debug then return end
print("[" .. os.date("%Y-%m-%d %H:%M:%S") .. "] [Gmod Integration] [WARNING] " .. msg)
end
// Log Hint
function gmInte.logHint(msg, debug)
if debug && !gmInte.config.debug then return end
print("[" .. os.date("%Y-%m-%d %H:%M:%S") .. "] [Gmod Integration] [HINT] " .. msg)
end
// Is Private IP
function gmInte.isPrivateIP(ip)
// detect localhost
if ip == "localhost" then return true end
// detect private IP addresses (RFC 1918)
local parts = string.Explode(".", ip)
if parts[1] == "192" && parts[2] == "168" then return true end
if parts[1] == "10" then return true end
if parts[1] == "172" && tonumber(parts[2]) >= 16 && tonumber(parts[2]) <= 31 then return true end
if parts[1] == "127" then return true end
return false
end

View File

@ -1,159 +0,0 @@
local ply = FindMetaTable("Player")
function ply:gmIntGetConnectTime()
return self.gmIntTimeConnect || 0
end
function ply:gmIntIsVerified()
return self.gmIntVerified || false
end
function ply:gmIntGetTimeLastTeamChange()
return self.gmIntTimeLastTeamChange || RealTime()
end
function ply:gmInteResetTimeLastTeamChange()
self.gmIntTimeLastTeamChange = RealTime()
end
function ply:gmInteGetBranch()
return CLIENT && BRANCH || self.branch || "unknown"
end
function ply:gmIntSetCustomValue(key, value)
self.gmIntCustomValues = self.gmIntCustomValues || {}
self.gmIntCustomValues[key] = value
end
function ply:gmIntIsAdmin()
return gmInte.config.adminRank[self:GetUserGroup()] || false
end
function ply:gmIntGetCustomValue(key)
return self.gmIntCustomValues && self.gmIntCustomValues[key]
end
function ply:gmIntRemoveCustomValue(key)
if self.gmIntCustomValues then self.gmIntCustomValues[key] = nil end
end
local function getCustomCompatability(ply)
local values = {}
// DarkRP
if DarkRP then
values.money = ply:getDarkRPVar("money")
values.job = ply:getDarkRPVar("job")
end
// GUI Level System
if GUILevelSystem then
values.level = ply:GetLevel()
values.xp = ply:GetXP()
end
// Pointshop 2
if Pointshop2 && ply.PS2_Wallet then
values.ps2Points = ply.PS2_Wallet.points
values.ps2PremiumPoints = ply.PS2_Wallet.premiumPoints
end
if CH_ATM && SERVER then values.bank = CH_ATM.GetMoneyBankAccount(ply) end
return values
end
local function getCustomValues(ply)
local values = {}
// Get compatability values
for key, value in pairs(getCustomCompatability(ply)) do
values[key] = value
end
// Get custom values or overwrite compatability values
if ply.gmIntCustomValues then
for key, value in pairs(ply.gmIntCustomValues) do
values[key] = value
end
end
return values
end
function ply:gmIntGetCustomValues()
return getCustomValues(self)
end
function ply:gmIntGetFPS()
return self.gmIntFPS || 0
end
gmInte.restoreFileCache = gmInte.restoreFileCache || {}
function ply:getAdjustedTime()
if gmInte.restoreFileCache == nil || gmInte.restoreFileCache.sysTime == nil || gmInte.restoreFileCache.playersList == nil then return 0 end
if SERVER then
if table.IsEmpty(gmInte.restoreFileCache) then
if file.Exists("gm_integration/player_before_map_change.json", "DATA") then
gmInte.restoreFileCache = util.JSONToTable(file.Read("gm_integration/player_before_map_change.json", "DATA"))
else
return 0
end
end
else
if table.IsEmpty(gmInte.restoreFileCache) then
if file.Exists("gmod_integration/player_before_map_change.json", "DATA") then
gmInte.restoreFileCache = util.JSONToTable(file.Read("gmod_integration/player_before_map_change.json", "DATA"))
else
return 0
end
gmInte.restoreFileCache = gmInte.restoreFileCache[gmInte.config.id]
end
end
if !gmInte.restoreFileCache.sysTime || !gmInte.restoreFileCache.playersList then return 0 end
if (gmInte.restoreFileCache.sysTime + 60 * 5) < (os.time() - self:gmIntGetConnectTime()) then return 0 end
if !gmInte.restoreFileCache.playersList[self:SteamID()] then return 0 end
return gmInte.restoreFileCache.playersList[self:SteamID()].connectTime || 0
end
if SERVER then
gameevent.Listen("player_connect")
hook.Add("player_connect", "gmInte:Player:Connect:RemoveRestore", function(data)
if table.IsEmpty(gmInte.restoreFileCache) then
if file.Exists("gm_integration/player_before_map_change.json", "DATA") then
gmInte.restoreFileCache = util.JSONToTable(file.Read("gm_integration/player_before_map_change.json", "DATA"))
else
return
end
end
if gmInte.restoreFileCache.playersList && gmInte.restoreFileCache.playersList[data.networkid] then
gmInte.restoreFileCache.playersList[data.networkid] = nil
file.Write("gm_integration/player_before_map_change.json", util.TableToJSON(gmInte.restoreFileCache, true))
end
end)
end
local function saveTimeToLocal()
local dataToSave = {
["version"] = "1.0",
["serverID"] = gmInte.config.id,
["playersList"] = {},
["sysTime"] = os.time()
}
if SERVER then
for _, ply in ipairs(player.GetAll()) do
dataToSave.playersList[ply:SteamID()] = gmInte.getPlayerFormat(ply)
end
if !file.Exists("gm_integration", "DATA") then file.CreateDir("gm_integration") end
file.Write("gm_integration/player_before_map_change.json", util.TableToJSON(dataToSave, true))
else
dataToSave.playersList[LocalPlayer():SteamID()] = gmInte.getPlayerFormat(LocalPlayer())
local oldData = {}
if file.Exists("gmod_integration/player_before_map_change.json", "DATA") then oldData = util.JSONToTable(file.Read("gmod_integration/player_before_map_change.json", "DATA")) end
oldData[gmInte.config.id] = dataToSave
file.Write("gmod_integration/player_before_map_change.json", util.TableToJSON(oldData, true))
end
end
hook.Add("ShutDown", "gmInte:Server:ShutDown:SavePlayer", saveTimeToLocal)
hook.Add("GMI:SaveBeforeCrash", "gmInte:Server:BeforeCrash:SavePlayers", saveTimeToLocal)

View File

@ -38,6 +38,8 @@ gmInte.config.clientBranch = "any" // The branch of the addon that the clients s
gmInte.config.supportLink = "" // The link of your support (shown when a player do not have the requiments to join the server)
gmInte.config.maintenance = false // If true, the addon will only allow the players with the "gmod-integration.maintenance" permission to join the server
gmInte.config.language = "en" // The language of the addon (en, fr, de, es, it, tr, ru)
gmInte.config.logTimestamp = "%H:%M:%S" // The timestamp format of the logs
gmInte.config.dllBranch = "main" // The download branch of gmod integration via dll (Use at your own risk, this is not recommended for production servers)
gmInte.config.adminRank = {
// How can edit the configuration of the addon / bypass the maintenance mode
["superadmin"] = true,