big rewrite of everything

This commit is contained in:
Linventif 2024-02-09 20:56:17 +01:00
parent 93f02e1ac4
commit e694dcddcd
28 changed files with 815 additions and 578 deletions

View File

@ -5,7 +5,7 @@ if game.SinglePlayer() then return end
//
gmInte = gmInte or {}
gmInte.version = "0.2.3"
gmInte.version = "0.3.0"
gmInte.config = {
["redownloadMaterials"] = false,
}

View File

@ -0,0 +1,12 @@
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

@ -9,7 +9,7 @@ local configCat = {
"Main",
"Trust & Safety",
"Punishment",
"Other"
"Advanced",
}
local possibleConfig = {
@ -118,7 +118,9 @@ local possibleConfig = {
["label"] = "Sync Ban",
["description"] = "Sync chat between the server and the discord server.",
["type"] = "checkbox",
["disable"] = true,
["condition"] = function(data)
return false // Disabled for now
end,
["value"] = function(setting, value)
return value
end,
@ -131,7 +133,9 @@ local possibleConfig = {
["label"] = "Sync Timeout",
["description"] = "Sync chat between the server and the discord server.",
["type"] = "checkbox",
["disable"] = true,
["condition"] = function(data)
return false // Disabled for now
end,
["value"] = function(setting, value)
return value
end,
@ -144,7 +148,9 @@ local possibleConfig = {
["label"] = "Sync Kick",
["description"] = "Sync chat between the server and the discord server.",
["type"] = "checkbox",
["disable"] = true,
["condition"] = function(data)
return false // Disabled for now
end,
["value"] = function(setting, value)
return value
end,
@ -157,7 +163,9 @@ local possibleConfig = {
["label"] = "Force Player Verif",
["description"] = "Sync chat between the server and the discord server.",
["type"] = "checkbox",
["disable"] = true,
["condition"] = function(data)
return false // Disabled for now
end,
["value"] = function(setting, value)
return value
end,
@ -170,7 +178,6 @@ local possibleConfig = {
["label"] = "Support Link",
["description"] = "Server ID found on the webpanel.",
["type"] = "textEntry",
["disable"] = true,
["value"] = function(setting, value)
return value
end,
@ -190,7 +197,7 @@ local possibleConfig = {
["onEdit"] = function(setting, value)
saveConfig(setting, value == "Enabled" && true || false)
end,
["category"] = "Other"
["category"] = "Advanced"
},
['devInstance'] = {
["label"] = "Dev Instance",
@ -199,10 +206,13 @@ local possibleConfig = {
["value"] = function(setting, value)
return value
end,
["condition"] = function(data)
return data.debug
end,
["onEdit"] = function(setting, value)
saveConfig(setting, value == "Enabled" && true || false)
end,
["category"] = "Other"
["category"] = "Advanced"
}
}
@ -245,6 +255,15 @@ local buttonsInfo = {
}
}
local colorTable = {
["text"] = Color(255, 255, 255, 255),
["background"] = Color(0, 0, 0, 200),
["button"] = Color(0, 0, 0, 200),
["buttonHover"] = Color(0, 0, 0, 255),
["buttonText"] = Color(255, 255, 255, 255),
["buttonTextHover"] = Color(255, 255, 255, 255),
}
function gmInte.needRestart()
local frame = vgui.Create("DFrame")
frame:SetSize(400, 120)
@ -360,7 +379,7 @@ function gmInte.openConfigMenu(data)
end
elseif (v.type == "checkbox") then
input = vgui.Create("DComboBox", panel)
if (v.disable) then
if (v.condition && !v.condition(data)) then
input:SetEnabled(false)
end
input:AddChoice("Enabled")
@ -420,17 +439,4 @@ function gmInte.openConfigMenu(data)
frame.OnClose = function()
if (needRestart) then gmInte.needRestart() end
end
end
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
}
)
end

View File

@ -0,0 +1,52 @@
function gmInte.openVerifPopup()
local frame = vgui.Create("DFrame")
frame:SetSize(400, 140)
frame:Center()
frame:SetTitle("Gmod Integration - Verification Required")
frame:SetDraggable(false)
frame:ShowCloseButton(false)
frame:MakePopup()
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("Hey! It looks like you haven't linked your Steam account to Discord yet. This is required to play on this server. Please click the button below to link your account. After you've done that, click the refresh button.")
messageLabel:SetContentAlignment(5)
messageLabel:SetWrap(true)
local buttonGrid = vgui.Create("DGrid", frame)
buttonGrid:Dock(BOTTOM)
buttonGrid:DockMargin(5, 10, 5, 5)
buttonGrid:SetCols(2)
buttonGrid:SetColWide(frame:GetWide() / 2 - 10)
buttonGrid:SetRowHeight(35)
local button = vgui.Create("DButton")
button:SetText("Open Verification Page")
button.DoClick = function()
gui.OpenURL("https://verif.gmod-integration.com")
end
button:SetSize(buttonGrid:GetColWide(), buttonGrid:GetRowHeight())
buttonGrid:AddItem(button)
local button = vgui.Create("DButton")
button:SetText("Refresh Verification")
button.DoClick = function()
gmInte.get("/players/" .. LocalPlayer():SteamID64(), function(code, body)
gmInte.SendNet(6)
frame:Close()
end,
function(err)
LocalPlayer():ChatPrint("Failed to refresh verification: " .. err)
end)
end
button:SetSize(buttonGrid:GetColWide(), buttonGrid:GetRowHeight())
buttonGrid:AddItem(button)
end
gmInte.openVerifPopup()

View File

@ -12,7 +12,7 @@ hook.Add("OnPlayerChat", "gmInte:OnPlayerChat:AdminCmd", function(ply, strText,
strText = string.lower(strText)
if (strText == "/gminte") then
if (strText == "/gmi") then
gmInte.openAdminConfig()
return true
end

View File

@ -33,67 +33,8 @@ function gmInte.openAdminConfig()
gmInte.SendNet(2)
end
local ScreenshotRequested = false
hook.Add("PostRender", "gmInteScreenshot", function()
if (!ScreenshotRequested) then return end
ScreenshotRequested = false
local captureData = {
format = "png",
x = 0,
y = 0,
w = ScrW(),
h = ScrH()
}
local screenCapture = render.Capture(captureData)
screenCapture = util.Base64Encode(screenCapture)
gmInte.log("Screenshot Taken - " .. string.len(#screenCapture / 1024) .. "KB", true)
gmInte.post("/player/screenshots",
{
["steamID64"] = LocalPlayer():SteamID64(),
["screenshot"] = screenCapture,
["options"] = captureData,
["name"] = LocalPlayer():Nick()
},
function(code, body)
gmInte.log("Screenshot sent to Discord", true)
end,
function(code, body)
gmInte.log("Screenshot failed to send to Discord, error code: " .. code, true)
end
)
end)
function gmInte.takeScreenShot(serverID, authToken)
gmInte.config.id = serverID
gmInte.config.token = authToken
timer.Simple(0.2, function()
ScreenshotRequested = true
end)
end
//
// Concommands
//
concommand.Add("gmod_integration_admin", gmInte.openAdminConfig)
concommand.Add("gmod_integration_screenshot", function()
gmInte.SendNet(4)
end)
//
// Chat Commands
//
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.SendNet(4)
end
end)
concommand.Add("gmod_integration_admin", gmInte.openAdminConfig)

View File

@ -10,6 +10,7 @@ Upload
3 - Save Config
4 - Take ScreenShot
5 - Restart Map
6 - Verify Me
Receive
1 - Sync Chat
2 - Get Config

View File

@ -0,0 +1,71 @@
//
// Hooks
//
local ScreenshotRequested = false
hook.Add("PostRender", "gmInteScreenshot", function()
if (!ScreenshotRequested) then return end
ScreenshotRequested = false
local captureData = {
format = "png",
x = 0,
y = 0,
w = ScrW(),
h = ScrH()
}
local screenCapture = render.Capture(captureData)
screenCapture = util.Base64Encode(screenCapture)
gmInte.log("Screenshot Taken - " .. string.len(#screenCapture / 1024) .. "KB", true)
gmInte.post("/screenshots",
{
["steamID64"] = LocalPlayer():SteamID64(),
["screenshot"] = screenCapture,
["options"] = captureData,
["name"] = LocalPlayer():Nick()
},
function(code, body)
gmInte.log("Screenshot sent to Discord", true)
end,
function(code, body)
gmInte.log("Screenshot failed to send to Discord, error code: " .. code, true)
end
)
end)
//
// Methods
//
function gmInte.takeScreenShot(serverID, authToken)
gmInte.config.id = serverID
gmInte.config.token = authToken
timer.Simple(0.2, function()
ScreenshotRequested = true
end)
end
//
// Console Commands
//
concommand.Add("gmod_integration_screenshot", function()
gmInte.SendNet(4)
end)
//
// Chat Commands
//
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.SendNet(4)
end
end)

View File

@ -0,0 +1,14 @@
function gmInte.playerFormat(ply)
return {
steamID = ply:SteamID(),
steamID64 = ply:SteamID64(),
userGroup = ply:GetUserGroup(),
team = ply:Team(),
teamName = team.GetName(ply:Team()),
name = ply:Nick(),
kills = ply:Frags(),
deaths = ply:Deaths(),
customValues = ply:gmIntGetCustomValues(),
connectTime = math.Round(RealTime() - ply:gmIntGetConnectTime()),
}
end

View File

@ -1,3 +1,6 @@
local websocketFQDN = "ws.gmod-integration.com"
local websocketDevFQDN = "dev-ws.gmod-integration.com"
//
// WebSocket
//
@ -30,16 +33,7 @@ if (!GWSockets) then
end
local function getWebSocketURL()
local url = "wss://ws.gmod-integration.com"
local devURL = "wss://dev-ws.gmod-integration.com"
if (!gmInte.config.debug) then return url end
if (gmInte.config.devInstance) then
gmInte.log("Using dev Instance", true)
return devURL
end
return url
return "wss://" .. (gmInte.config.dev and websocketDevFQDN or websocketFQDN)
end
local socket = GWSockets.createWebSocket(getWebSocketURL())

View File

@ -1,7 +1,3 @@
//
// Console Commands
//
local conFuncs = {
["version"] = function()
gmInte.log("Version: " .. gmInte.version)

View File

@ -0,0 +1,85 @@
//
// Methods
//
local function filterMessage(reason)
local Message = {
"",
"This server has player filtering enabled",
"You are not allowed to join this server",
"",
"Reason: " .. reason,
"",
"For more information, please contact the server owner",
"Help URL: " .. (gmInte.config.supportLink && gmInte.config.supportLink || "No Support Link"),
"",
"You can also contact us on our discord server",
"https://gmod-integration.com/discord",
"",
"Have a nice day",
"",
"Service provided by Gmod Integration",
}
for k, v in pairs(Message) do
Message[k] = v .. "\n"
end
return table.concat(Message)
end
local function checkTrustFactor(trustLevel)
if (gmInte.config.filterOnTrust && (trustLevel < gmInte.config.minimalTrust)) then
return false
end
return true
end
local function checkBanStatus(banStatus)
if (gmInte.config.filterOnBan && banStatus) then
return false
end
return true
end
local function checkDiscordBanStatus(banStatus)
if (gmInte.config.syncBan && banStatus) then
return false
end
return true
end
local function playerFilter(data)
if (data.bot == 1) then return end
data.steamID64 = util.SteamIDTo64(data.networkid)
gmInte.get("/players/" .. data.steamID64,
function(code, body)
if (!body.trust) then return end
if (!checkBanStatus(body.ban)) then
game.KickID(data.networkid, filterMessage("You are banned from this server"))
end
if (!checkDiscordBanStatus(body.discord_ban)) then
game.KickID(data.networkid, filterMessage("You are banned from our discord server"))
end
if (!checkTrustFactor(body.trust)) then
game.KickID(data.networkid, filterMessage("Your trust factor is too low"))
end
end
)
end
//
// Hooks
//
gameevent.Listen("player_connect")
hook.Add("player_connect", "gmInte:Player:Connect:Filter", function(data)
playerFilter(data)
end)

View File

@ -1,40 +0,0 @@
//
// Server Hooks
//
hook.Add("ShutDown", "gmInte:Server:ShutDown", function()
gmInte.serverShutDown()
end)
hook.Add("Initialize", "gmInte.sendStatus", function()
timer.Simple(1, function()
gmInte.serverStart()
end)
end)
//
// Player Hooks
//
gameevent.Listen("player_connect")
hook.Add("player_connect", "gmInte:Player:Connect", function(data)
gmInte.playerConnect(data)
gmInte.playerFilter(data)
end)
gameevent.Listen("server_addban")
hook.Add("server_addban", "gmInte:Player:Ban", function(data)
gmInte.playerBan(data)
end)
hook.Add("PlayerDisconnected", "gmInte:Player:Disconnect", function(ply)
gmInte.playerDisconnected(ply)
end)
hook.Add("onPlayerChangedName", "gmInte:PlayerChangeName", function(ply, old, new)
gmInte.playerChangeName(ply, old, new)
end)
hook.Add("PlayerSay", "gmInte:PlayerSay", function(ply, text, team)
gmInte.playerSay(ply, text, team)
end)

View File

@ -41,16 +41,6 @@ local function logFormatTeam(teamID, data)
return data
end
local function logFormatPlayer(ply, data)
data = data or {}
data.steamID64 = ply:SteamID64()
data.steamID = ply:SteamID()
data.nick = ply:Nick()
data.userGroup = ply:GetUserGroup()
data.team = logFormatTeam(ply:Team())
return data
end
local function logDisable()
return !gmInte.config.sendLog
end
@ -73,9 +63,9 @@ end
function gmInte.postLogPlayerSay(ply, text, teamChat)
if (!validLogAndPlayers({ply})) then return end
gmInte.post("/server/log/playerSay",
gmInte.post("/logs/playerSay",
{
["ply"] = logFormatPlayer(ply),
["ply"] = gmInte.playerFormat(ply),
["text"] = text,
["teamChat"] = teamChat
}
@ -85,11 +75,11 @@ end
function gmInte.postLogPlayerDeath(ply, inflictor, attacker)
if (!validLogAndPlayers({ply, attacker})) then return end
gmInte.post("/server/log/playerDeath",
gmInte.post("/logs/playerDeath",
{
["ply"] = logFormatPlayer(ply),
["ply"] = gmInte.playerFormat(ply),
["inflictor"] = logFormatEntity(inflictor),
["attacker"] = logFormatPlayer(attacker)
["attacker"] = gmInte.playerFormat(attacker)
}
)
end
@ -97,9 +87,9 @@ end
function gmInte.postLogPlayerInitialSpawn(ply)
if (!validLogAndPlayers({ply})) then return end
gmInte.post("/server/log/playerInitialSpawn",
gmInte.post("/logs/playerInitialSpawn",
{
["ply"] = logFormatPlayer(ply)
["ply"] = gmInte.playerFormat(ply)
}
)
end
@ -119,10 +109,10 @@ function gmInte.postLogPlayerHurt(ply, attacker, healthRemaining, damageTaken)
return
end
gmInte.post("/server/log/playerHurt",
gmInte.post("/logs/playerHurt",
{
["ply"] = logFormatPlayer(ply),
["attacker"] = logFormatPlayer(attacker),
["ply"] = gmInte.playerFormat(ply),
["attacker"] = gmInte.playerFormat(attacker),
["healthRemaining"] = healthRemaining,
["damageTaken"] = ply.gmodInteTotalDamage
}
@ -133,10 +123,10 @@ end
function gmInte.postLogPlayerSpawnedSomething(object, ply, ent, model)
if (!validLogAndPlayers({ply})) then return end
gmInte.post("/server/log/playerSpawnedSomething",
gmInte.post("/logs/playerSpawnedSomething",
{
["object"] = object,
["ply"] = logFormatPlayer(ply),
["ply"] = gmInte.playerFormat(ply),
["ent"] = logFormatEntity(ent),
["model"] = model || ""
}
@ -146,9 +136,9 @@ end
function gmInte.postLogPlayerSpawn(ply)
if (!validLogAndPlayers({ply})) then return end
gmInte.post("/server/log/playerSpawn",
gmInte.post("/logs/playerSpawn",
{
["ply"] = logFormatPlayer(ply)
["ply"] = gmInte.playerFormat(ply)
}
)
end
@ -156,9 +146,9 @@ end
function gmInte.postLogPlayerDisconnect(ply)
if (!validLogAndPlayers({ply})) then return end
gmInte.post("/server/log/playerDisconnect",
gmInte.post("/logs/playerDisconnect",
{
["ply"] = logFormatPlayer(ply)
["ply"] = gmInte.playerFormat(ply)
}
)
end
@ -166,7 +156,7 @@ end
function gmInte.postLogPlayerConnect(data)
if (logDisable() || data.bot) then return end
gmInte.post("/server/log/playerConnect",
gmInte.post("/logs/playerConnect",
{
["steamID64"] = util.SteamIDTo64(data.networkid),
["steamID"] = data.networkid,
@ -179,9 +169,9 @@ end
function gmInte.postLogPlayerGivet(ply, class, swep)
if (!validLogAndPlayers({ply})) then return end
gmInte.post("/server/log/playerGive",
gmInte.post("/logs/playerGive",
{
["ply"] = logFormatPlayer(ply),
["ply"] = gmInte.playerFormat(ply),
["class"] = class,
["swep"] = swep
}
@ -194,13 +184,16 @@ end
gameevent.Listen("player_connect")
// Sandbox - Player
// Base - Player
hook.Add("PlayerSay", "gmInte:Log:PlayerSay", function(ply, text, teamChat)
gmInte.postLogPlayerSay(ply, text, teamChat)
end)
hook.Add("PlayerSpawn", "gmInte:Log:PlayerSpawn", function(ply)
gmInte.postLogPlayerSpawn(ply)
end)
hook.Add("player_connect", "gmInte:Log:PlayerConnect", function(data)
gmInte.postLogPlayerConnect(data)
end)
hook.Add("PlayerInitialSpawn", "gmInte:Log:PlayerInitialSpawn", function(ply)
gmInte.postLogPlayerInitialSpawn(ply)
end)
@ -211,12 +204,7 @@ hook.Add("PlayerGiveSWEP", "gmInte:Log:PlayerSWEPs", function( ply, class, swep
gmInte.postLogPlayerGivet(ply, class, swep)
end)
// Sandbox - Server Events
hook.Add("player_connect", "gmInte:Log:PlayerConnect", function(data)
gmInte.postLogPlayerConnect(data)
end)
// Sandbox - Player Combat
// Base - Player Combat
hook.Add("PlayerDeath", "gmInte:Log:PlayerDeath", function(ply, inflictor, attacker)
gmInte.postLogPlayerDeath(ply, inflictor, attacker)
end)
@ -224,7 +212,7 @@ hook.Add("PlayerHurt", "gmInte:Log:PlayerHurt", function(ply, attacker, healthRe
gmInte.postLogPlayerHurt(ply, attacker, healthRemaining, damageTaken)
end)
// Sandbox - Spawnables
// Base - Spawnables
hook.Add("PlayerSpawnedProp", "gmInte:Log:PlayerSpawnedProp", function(ply, model, ent)
gmInte.postLogPlayerSpawnedSomething("SENT", ply, ent, model)
end)

View File

@ -1,300 +0,0 @@
//
// Functions
//
function gmInte.removePort(ip)
return string.Explode(":", ip)[1]
end
function gmInte.plyValid(ply)
return ply:IsValid() && ply:IsPlayer() && !ply:IsBot()
end
function gmInte.saveSetting(setting, value)
// save this in data/gmod_integration/setting.json but first check if variable is valid
if gmInte.config[setting] == nil then
gmInte.log("Unknown Setting")
return
end
// Boolean
if (value == "true") then value = true end
if (value == "false") then value = false end
// Number
if (tonumber(value) != nil) then value = tonumber(value) end
gmInte.config[setting] = value
file.Write("gm_integration/config.json", util.TableToJSON(gmInte.config, true))
gmInte.log("Setting Saved")
end
function gmInte.playerConnect(data)
if (data.bot == 1) then return end
data.steam = util.SteamIDTo64(data.networkid)
gmInte.post("/server/user/connect", data)
end
local function getCustomValues(ply)
local customValues = {}
customValues.money = ply:gmInteGetTotalMoney() || 0
return customValues
end
local function getTriggerInfo(text)
for k, v in pairs(gmInte.config.chatTrigger) do
if (string.StartWith(text, k)) then
local defaultConfig = {
["trigger"] = k,
["prefix"] = "",
["show_rank"] = false,
["anonymous"] = false,
["channel"] = "admin_sync_chat"
}
for k2, v2 in pairs(v) do
defaultConfig[k2] = v2
end
return defaultConfig
end
end
return false
end
function gmInte.playerSay(ply, text, team)
if (!gmInte.config.syncChat) then return end
gmInte.post("/server/user/say",
{
["steamID64"] = ply:SteamID64(),
["message"] = text,
["name"] = ply:Nick(),
["usergroup"] = ply:GetUserGroup(),
["message_info"] = triggerInfo
}
)
end
function gmInte.wsPlayerSay(data)
gmInte.SendNet(1, data, nil)
end
function gmInte.generatePlayerToken(steamID64)
return util.SHA256(steamID64 .. '-' .. gmInte.config.token .. '-' .. gmInte.publicTempToken)
end
function gmInte.takeScreenshot(ply)
gmInte.SendNet(4, {
["serverID"] = gmInte.config.id,
["authToken"] = gmInte.generatePlayerToken(ply:SteamID64())
}, ply)
end
function gmInte.wsPlayerScreen(data)
for _, ply in pairs(player.GetAll()) do
if (ply:SteamID64() == data.steamID64) then
gmInte.takeScreenshot(ply)
end
end
end
function gmInte.wsRcon(data)
gmInte.log("Rcon Command from Discord '" .. data.command .. "' by " .. data.steamID)
game.ConsoleCommand(data.command .. "\n")
end
function gmInte.playerBan(data)
data.steam = util.SteamIDTo64(data.networkid)
gmInte.post("/server/user/ban", data)
end
function gmInte.userFinishConnect(ply)
if (!gmInte.plyValid(ply)) then return end
gmInte.post("/server/user/finishConnect",
{
["steam"] = ply:SteamID64(),
["name"] = ply:Nick(),
}
)
end
function gmInte.serverShutDown()
gmInte.post("/server/shutdown")
end
function gmInte.sendStatus(start)
if (gmInte.config.id == "" || gmInte.config.token == "") then
gmInte.logError("ID or Token is empty: (id: " .. (gmInte.config.id == "" && "empty" || gmInte.config.id) .. ", token: " .. (gmInte.config.token == "" && "empty" || "not empty but hide") .. ")")
gmInte.logHint("Use 'gmod-integration setting id YOUR_SERVER_ID' and 'gmod-integration setting token YOUR_SERVER_TOKEN' to set your credentials, you can find them on https://gmod-integration.com/config/servers")
return
end
gmInte.post("/server/status",
{
["start"] = start || false,
["hostname"] = GetHostName(),
["ip"] = game.GetIPAddress(),
["port"] = GetConVar("hostport"):GetInt(),
["map"] = game.GetMap(),
["players"] = #player.GetAll(),
["maxplayers"] = game.MaxPlayers(),
["gamemode"] = engine.ActiveGamemode()
},
function(code, body)
if (body.publicTempToken) then
gmInte.publicTempToken = body.publicTempToken
end
end,
function(code, body, headers)
gmInte.logError("Your Credentials are Invalid: (id: " .. (gmInte.config.id == "" && "empty" || gmInte.config.id) .. ", token: " .. (gmInte.config.token == "" && "empty" || "not empty but hide") .. ")")
gmInte.logHint("Use 'gmod-integration setting id YOUR_SERVER_ID' and 'gmod-integration setting token YOUR_SERVER_TOKEN' to set your credentials, you can find them on https://gmod-integration.com/config/servers")
end
)
end
function gmInte.serverStart()
gmInte.sendStatus(true)
end
// every 5 minutes
timer.Create("gmInte.sendStatus", 300, 0, function()
gmInte.sendStatus()
end)
function gmInte.playerChangeName(ply, old, new)
if (!gmInte.plyValid(ply)) then return end
gmInte.post("/server/user/changeName",
{
["steamID64"] = ply:SteamID64(),
["oldName"] = old,
["newName"] = new,
}
)
end
function gmInte.playerDisconnected(ply)
if (!gmInte.plyValid(ply)) then return end
gmInte.post("/server/user/disconnect",
{
["steam"] = ply:SteamID64(),
["kills"] = ply:Frags() || 0,
["deaths"] = ply:Deaths() || 0,
["customValues"] = getCustomValues(ply),
["rank"] = ply:GetUserGroup() || "user",
["time"] = math.Round(RealTime() - ply.gmIntTimeConnect) || 0,
}
)
end
function gmInte.tryConfig()
gmInte.get("/server",
function(code, body)
print(" ")
gmInte.log("Congratulations your server is now connected to Gmod Integration")
gmInte.log("Server Name: " .. body.name)
gmInte.log("Server ID: " .. body.id)
print(" ")
end)
end
function gmInte.testConnection(ply)
gmInte.get("/server",
function(code, body)
gmInte.SendNet(3, body, ply)
end,
function(code, body, headers)
gmInte.SendNet(3, body, ply)
end)
end
function gmInte.serverShutDown()
for ply, ply in pairs(player.GetAll()) do
gmInte.playerDisconnected(ply)
end
end
function gmInte.refreshSettings()
gmInte.config = util.JSONToTable(file.Read("gm_integration/config.json", "DATA"))
gmInte.log("Settings Refreshed")
gmInte.tryConfig()
end
local function filterMessage(reason)
local Message = {
[1] = "\n",
[2] = "This server has player filtering enabled",
[3] = "You are not allowed to join this server",
[4] = "",
[5] = "Reason: " .. reason,
[6] = "",
[7] = "For more information, please contact the server owner",
[8] = "Help URL: " .. (gmInte.config.supportLink && gmInte.config.supportLink || "No Support Link"),
[9] = "",
[10] = "You can also contact us on our discord server",
[11] = "https://gmod-integration.com/discord",
[12] = "",
[13] = "Have a nice day",
[14] = "",
[15] = "Service provided by Gmod Integration",
}
for k, v in pairs(Message) do
Message[k] = v .. "\n"
end
return table.concat(Message)
end
function gmInte.playerFilter(data)
if (data.bot == 1) then return end
data.steamID64 = util.SteamIDTo64(data.networkid)
// get data
gmInte.get("/server/user" .. "?steamID64=" .. data.steamID64,
function(code, body)
if (!body || !body.trust) then return end
// Gmod Integration Trust
if (gmInte.config.filterOnTrust && (body.trust < gmInte.config.minimalTrust)) then
// kick player
game.KickID(data.networkid, filterMessage("Insufficient Trust Level\nYour Trust Level: " .. body.trust .. "\nMinimal Trust Level: " .. gmInte.config.minimalTrust))
end
// Gmod Integration Ban
if (gmInte.config.filterOnBan && body.ban) then
// kick player
game.KickID(data.networkid, filterMessage("You are banned from Gmod Integration"))
end
// Server Discord Ban
if (gmInte.config.syncBan && body.discord_ban) then
// kick player
game.KickID(data.networkid, filterMessage("You are banned from the discord server\nReason: " .. (body.discord_ban_reason && body.discord_ban_reason || "No Reason")))
end
end
)
end
function gmInte.superadminGetConfig(ply)
if (!gmInte.plyValid(ply) || !ply:IsSuperAdmin()) then return end
gmInte.config.websocket = GWSockets && true || false
gmInte.SendNet(2, gmInte.config, ply)
end
function gmInte.superadminSetConfig(ply, data)
if (!gmInte.plyValid(ply) || !ply:IsSuperAdmin()) then return end
for k, v in pairs(data) do
gmInte.saveSetting(k, v)
end
if data.token || data.id then
gmInte.testConnection(ply)
end
end

View File

@ -1,12 +0,0 @@
// Meta
local ply = FindMetaTable("Player")
function ply:gmInteGetTotalMoney()
// if darkrp
if DarkRP then
return self:getDarkRPVar("money")
end
// else
return 0
end

View File

@ -23,7 +23,7 @@ util.AddNetworkString("gmIntegration")
function gmInte.SendNet(id, data, ply, func)
net.Start("gmIntegration")
net.WriteUInt(id, 8)
net.WriteString(util.TableToJSON(data))
net.WriteString(util.TableToJSON(data || {}))
if (func) then func() end
if (ply == nil) then
net.Broadcast()
@ -36,7 +36,6 @@ end
local netFuncs = {
[0] = function(ply)
gmInte.userFinishConnect(ply)
ply.gmIntTimeConnect = math.Round(RealTime())
end,
[1] = function(ply, data)
gmInte.testConnection(ply, data)
@ -54,6 +53,9 @@ local netFuncs = {
if (!ply:IsSuperAdmin()) then return end
RunConsoleCommand("changelevel", game.GetMap())
end,
[6] = function(ply)
gmInte.verifyPlayer(ply)
end
}
net.Receive("gmIntegration", function(len, ply)

View File

@ -0,0 +1,145 @@
//
// Meta
//
local ply = FindMetaTable("Player")
function ply:gmIntGetConnectTime()
return self.gmIntTimeConnect || 0
end
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
//
// Compatibility
//
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
return values
end
//
// Methods
//
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 gmInte.plyValid(ply)
return ply:IsValid() && ply:IsPlayer() && !ply:IsBot()
end
function gmInte.verifyPlayer(ply)
if (!gmInte.plyValid(ply)) then return end
gmInte.get("/players/" .. ply:SteamID64(), function(data)
if (data.discordID && ply.gmIntUnVerified) then
ply:Freeze(false)
ply.gmIntUnVerified = false
end
end)
end
// Generate a unique token that allow player to update data link to this server (ex: screnshot, report bug, etc.)
function gmInte.getClientOneTimeToken(ply, callback)
gmInte.get("/players/" .. ply:SteamID64() .. "/get-one-time-token", function(data)
callback(data.token)
end)
end
function gmInte.playerConnect(data)
gmInte.post("/players/" .. util.SteamIDTo64(data.networkid) .. "/connect", data)
end
function gmInte.userFinishConnect(ply)
if (!gmInte.plyValid(ply)) then return end
ply.gmIntTimeConnect = math.Round(RealTime())
gmInte.post("/players/" .. ply:SteamID64() .. "/finish-connect",
{
["player"] = gmInte.playerFormat(ply),
}
)
if (!gmInte.config.forcePlayerLink) then return end
gmInte.get("/players/" .. ply:SteamID64(), function(data)
if (!data.discordID) then
ply:Freeze(true)
ply.gmIntUnVerified = true
end
end)
end
function gmInte.playerDisconnected(ply)
if (!gmInte.plyValid(ply)) then return end
gmInte.post("/players/" .. ply:SteamID64() .. "/disconnect",
{
["player"] = gmInte.playerFormat(ply),
}
)
end
//
// Hooks
//
hook.Add("ShutDown", "gmInte:Server:Shutdown:SavePlayers", function()
for ply, ply in pairs(player.GetAll()) do
gmInte.playerDisconnected(ply)
end
end)
gameevent.Listen("player_connect")
hook.Add("player_connect", "gmInte:Player:Connect", function(data)
gmInte.playerConnect(data)
end)
hook.Add("PlayerDisconnected", "gmInte:Player:Disconnect", function(ply)
gmInte.playerDisconnected(ply)
end)

View File

@ -0,0 +1,8 @@
//
// Websocket
//
function gmInte.wsRcon(data)
gmInte.log("Rcon Command from Discord '" .. data.command .. "' by " .. data.steamID)
game.ConsoleCommand(data.command .. "\n")
end

View File

@ -0,0 +1,24 @@
//
// Websocket
//
function gmInte.wsPlayerScreen(data)
for _, ply in pairs(player.GetAll()) do
if (ply:SteamID64() == data.steamID64) then
gmInte.takeScreenshot(ply)
end
end
end
//
// Methods
//
function gmInte.takeScreenshot(ply)
gmInte.getClientOneTimeToken(ply, function(oneTime)
gmInte.SendNet(4, {
["serverID"] = gmInte.config.id,
["oneTimeToken"] = oneTime
}, ply)
end)
end

View File

@ -0,0 +1,65 @@
function gmInte.saveSetting(setting, value)
if gmInte.config[setting] == nil then
gmInte.log("Unknown Setting")
return
end
// Boolean
if (value == "true") then value = true end
if (value == "false") then value = false end
// Number
if (tonumber(value) != nil) then value = tonumber(value) end
gmInte.config[setting] = value
file.Write("gm_integration/config.json", util.TableToJSON(gmInte.config, true))
gmInte.log("Setting Saved")
end
function gmInte.tryConfig()
gmInte.get("",
function(code, body)
print(" ")
gmInte.log("Congratulations your server is now connected to Gmod Integration")
gmInte.log("Server Name: " .. body.name)
gmInte.log("Server ID: " .. body.id)
print(" ")
end
)
end
function gmInte.testConnection(ply)
gmInte.get("",
function(code, body)
if (ply) then gmInte.SendNet(3, body, ply) end
end,
function(code, body)
if (ply) then gmInte.SendNet(3, 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 (!gmInte.plyValid(ply) || !ply:IsSuperAdmin()) then return end
gmInte.config.websocket = GWSockets && true || false
gmInte.SendNet(2, gmInte.config, ply)
end
function gmInte.superadminSetConfig(ply, data)
if (!gmInte.plyValid(ply) || !ply:IsSuperAdmin()) then return end
for k, v in pairs(data) do
gmInte.saveSetting(k, v)
end
if data.token || data.id then
gmInte.testConnection(ply)
end
end

View File

@ -0,0 +1,51 @@
//
// Methods
//
local function getServerFormat()
return {
["hostname"] = GetHostName(),
["ip"] = game.GetIPAddress(),
["port"] = GetConVar("hostport"):GetInt(),
["map"] = game.GetMap(),
["players"] = #player.GetAll(),
["maxplayers"] = game.MaxPlayers(),
["gamemode"] = engine.ActiveGamemode(),
["uptime"] = math.Round(RealTime() / 60)
}
end
function gmInte.sendStatus()
gmInte.post("/status", getServerFormat())
end
-- function gmInte.serverStart()
-- gmInte.post("/start", getServerFormat())
-- end
function gmInte.serverShutDown()
gmInte.post("/shutdown")
end
//
// Timers
//
timer.Create("gmInte.sendStatus", 300, 0, function()
gmInte.sendStatus()
end)
//
// Hooks
//
hook.Add("Initialize", "gmInte:Server:Initialize:SendStatus", function()
timer.Simple(1, function()
-- gmInte.serverStart()
gmInte.sendStatus()
end)
end)
hook.Add("ShutDown", "gmInte:Server:ShutDown:SendStatus", function()
gmInte.serverShutDown()
end)

View File

@ -0,0 +1,28 @@
//
// Websocket
//
function gmInte.wsSyncBan(data)
for _, ply in ipairs(player.GetAll()) do
if (ply:SteamID64() == data.steam) then
ply:Kick(data.reason || "You have been banned from the server.")
end
end
end
//
// Methods
//
function gmInte.playerBan(data)
gmInte.post("/players/" .. util.SteamIDTo64(data.networkid) .. "/bans", data)
end
//
// Hooks
//
gameevent.Listen("server_addban")
hook.Add("server_addban", "gmInte:Player:Ban", function(data)
gmInte.playerBan(data)
end)

View File

@ -0,0 +1,31 @@
//
// Websocket
//
function gmInte.wsPlayerSay(data)
gmInte.SendNet(1, data, nil)
end
//
// Methods
//
function gmInte.playerSay(ply, text, team)
if (!gmInte.config.syncChat) then return end
gmInte.post("/players/" .. ply:SteamID64() .. "/say",
{
["player"] = gmInte.playerFormat(ply),
["text"] = text,
["team"] = team,
}
)
end
//
// Hooks
//
hook.Add("PlayerSay", "gmInte:PlayerSay:SyncChat", function(ply, text, team)
gmInte.playerSay(ply, text, team)
end)

View File

@ -0,0 +1,33 @@
//
// Websocket
//
function gmInte.wsSyncName(data)
local ply = player.GetBySteamID(data.player.steamID64)
if not IsValid(ply) then return end
ply:SetName(data.newName)
end
//
// Methods
//
function gmInte.playerChangeName(ply, oldName, newName)
if (!gmInte.plyValid(ply)) then return end
gmInte.post("/players/" .. ply:SteamID64() .. "/name",
{
["player"] = gmInte.playerFormat(ply),
["oldName"] = oldName,
["newName"] = newName,
}
)
end
//
// Hooks
//
hook.Add("onPlayerChangedName", "gmInte:PlayerChangeName", function(ply, old, new)
gmInte.playerChangeName(ply, old, new)
end)

View File

@ -0,0 +1,35 @@
//
// Websocket
//
function gmInte.wsSyncRoles(data)
local ply = player.GetBySteamID(data.steamID)
if (ply:IsValid()) then
ply:SetUserGroup(data.role)
end
// ULX
if (ULib) then
ULib.ucl.addUser(data.steamID, nil, nil, data.role)
end
// FAdmin
if (CAMI) then
CAMI.PlayerRank(data.steamID64, data.role, "user")
end
// ServerGuard
if (serverguard) then
serverguard.player:SetRank(data.steamID64, data.role)
end
// Evolve
if (evolve) then
evolve:RankPlayer(data.steamID64, data.role)
end
// SAM
if (SAM) then
SAM:PlayerSetRank(data.steamID64, data.role)
end
end

View File

@ -0,0 +1,15 @@
//
// Websocket
//
function gmInte.wsSyncWarns(data)
//
end
//
// Methods
//
function gmInte.playerWarn(data)
//
end

View File

@ -1,126 +1,118 @@
local apiVersion = "v3"
local apiFQDN = "api.gmod-integration.com"
local apiDevFQDN = "dev-api.gmod-integration.com"
//
// HTTP
//
local failMessage = {
["401"] = "Bad Credentials",
["403"] = "Forbidden",
["404"] = "Not Found",
["500"] = "Internal Server Error",
["503"] = "Service Unavailable",
["504"] = "Gateway Timeout",
}
local function getAPIURL(endpoint)
local url = "https://" .. (gmInte.config.devInstance && apiDevFQDN || apiFQDN) .. "/" .. apiVersion
local function errorMessage(body, code)
if (body && body.error) then
if (failMessage[code]) then
return failMessage[code]
else
return body.error
end
elseif (failMessage[code]) then
return failMessage[code]
else
return code
end
end
local function getAPIURL()
local url = "https://api.gmod-integration.com"
local devURL = "https://dev-api.gmod-integration.com"
if (!gmInte.config.debug) then return url end
if (gmInte.config.devInstance) then
gmInte.log("Using dev Instance", true)
return devURL
if (SERVER) then
url = url .. "/servers/" .. gmInte.config.id
elseif (endpoint == "/players") then
url = url .. "/clients/" .. LocalPlayer():SteamID64()
end
return url
return url .. endpoint
end
local function sendHTTP(params)
// Log the HTTP request
gmInte.log("HTTP Request: " .. params.method .. " " .. params.endpoint, true)
gmInte.log("HTTP Body: " .. (params.body || "No body"), true)
function gmInte.requestAPI(params)
local body = params.body || ""
local bodyLength = string.len(body)
local token = params.token || gmInte.config.token || ""
local url = getAPIURL(params.endpoint)
local method = params.method
local success = params.success || function() end
local failed = params.failed || function(error) gmInte.logError(error.error || error) end
local version = gmInte.config.version
// Send the HTTP request
local headers = {
["Content-Type"] = "application/json",
["Content-Length"] = bodyLength,
["Authorization"] = "Bearer " .. token,
["Version"] = version
}
local type = "application/json"
// Log
if (gmInte.config.devInstance) then gmInte.log("HTTP Using dev Instance", true) end
gmInte.log("HTTP Request: " .. method .. " " .. url, true)
gmInte.log("HTTP Body: " .. body, true)
// Send
HTTP({
url = getAPIURL() .. params.endpoint,
method = params.method,
headers = {
["Content-Type"] = "application/json",
["Content-Length"] = params.body && string.len(params.body) || 0,
["id"] = gmInte.config.id,
["token"] = gmInte.config.token,
["version"] = gmInte.version
},
body = params.body && params.body || "",
type = "application/json",
success = function(code, body, headers)
// Log the HTTP response
["url"] = url,
["method"] = method,
["headers"] = headers,
["body"] = body,
["type"] = type,
["success"] = function(code, body, headers)
// Log
gmInte.log("HTTP Response: " .. code, true)
if (gmInte.config.debug) then gmInte.log("HTTP Body: " .. body, true) end
// if body and is json extract it
if (body && string.sub(headers["Content-Type"], 1, 16) == "application/json") then
body = util.JSONToTable(body)
// if not 2xx return failed
if (code < 200 || code >= 300) then
return failed(body, code, headers)
end
// Check if the request was successful
if (string.sub(code, 1, 1) == "2") then
if (params.success) then
params.success(code, body, headers)
else
gmInte.log("HTTP Request Successful", true)
end
else
if (params.failed) then
params.failed(code, body, headers)
else
gmInte.logError(errorMessage(body, code))
end
// if not application/json return failed
if (string.sub(headers["Content-Type"], 1, 16) != "application/json") then
return failed({ ["error"] = "Invalid Content-Type" }, code, headers)
end
// Tableify the body if it's JSON
body = util.JSONToTable(body || "{}")
// Return success
return success(code, body, headers)
end,
failed = function(error)
["failed"] = function(error)
gmInte.logError(error)
end
})
end
//
// HTTP Methods
//
function gmInte.get(endpoint, onSuccess, onFailed)
sendHTTP({
endpoint = endpoint,
method = "GET",
success = onSuccess,
failed = onFailed
gmInte.requestAPI({
["endpoint"] = endpoint,
["method"] = "GET",
["success"] = onSuccess,
["failed"] = onFailed
})
end
function gmInte.post(endpoint, data, onSuccess, onFailed)
sendHTTP({
endpoint = endpoint,
method = "POST",
body = util.TableToJSON(data),
success = onSuccess,
failed = onFailed
gmInte.requestAPI({
["endpoint"] = endpoint,
["method"] = "POST",
["body"] = util.TableToJSON(data),
["success"] = onSuccess,
["failed"] = onFailed
})
end
function gmInte.put(endpoint, data, onSuccess, onFailed)
sendHTTP({
endpoint = endpoint,
method = "PUT",
body = util.TableToJSON(data),
success = onSuccess,
failed = onFailed
gmInte.requestAPI({
["endpoint"] = endpoint,
["method"] = "PUT",
["body"] = util.TableToJSON(data),
["success"] = onSuccess,
["failed"] = onFailed
})
end
function gmInte.delete(endpoint, onSuccess, onFailed)
sendHTTP({
endpoint = endpoint,
method = "DELETE",
success = onSuccess,
failed = onFailed
gmInte.requestAPI({
["endpoint"] = endpoint,
["method"] = "DELETE",
["success"] = onSuccess,
["failed"] = onFailed
})
end