diff --git a/lua/autorun/client/discord.lua b/lua/autorun/client/discord.lua new file mode 100644 index 0000000..9b5fa8d --- /dev/null +++ b/lua/autorun/client/discord.lua @@ -0,0 +1,189 @@ +--[[ + COPYRIGHT: + Made by Mestima © 2019 + + if (this addon using api.nilored server) then + I don't allow you to modify this addon. + I don't allow you to share this addon. + This addon using MY API server. I don't want billions of people to use my api server. + If you want to modify this addon, please contact me before or get the source code from my GitHub. + else + If you're reading this at the GitHub, you need to know + that this script is licensed under the GPLv3 License (https://www.gnu.org/licenses/gpl-3.0.html) + Copyright removing is NOT allowed! + + If you're using this type of GM-Discord addon that licensed under GPLv3 license, + you are NOT allowed to use api.nilored server. + end + + http://steamcommunity.com/id/mestima + http://github.com/Mestima +]] + +net.Receive("DiscordToGmod", function() + local username = net.ReadString() + local message = net.ReadString() + chat.AddText(Color(66, 140, 244, 255), "[Discord] ", Color(145, 191, 255, 255), username, Color(255, 255, 255, 255), ": ", Color(255, 255, 255, 255), message) +end) + +local function OpenDiscordSettings(ply) + if !ply:IsSuperAdmin() then return end + + local frame = vgui.Create("DFrame") + frame:SetSize(700, 390) + frame:SetPos(ScrW()/2-350, ScrH()/2-250) + frame:SetTitle("Discord Settings") + frame:MakePopup() + frame.Paint = function(s,w,h) draw.RoundedBox(0,0,0,w,h,Color(0,0,0,200)) end + + local mode = vgui.Create("DComboBox", frame) + mode:SetSize(335, 25) + mode:SetPos(10, 25) + mode:SetValue("Select Mode") + mode:AddChoice("Sandbox") + mode:AddChoice("DarkRP") + + local type = vgui.Create("DComboBox", frame) + type:SetSize(335, 25) + type:SetPos(355, 25) + type:SetValue("Select Type") + type:AddChoice("Embed") + type:AddChoice("Simple") + + local whook = vgui.Create("DTextEntry", frame) + whook:SetSize(680, 25) + whook:SetPos(10, 55) + whook:SetText("Webhook Link") + + local col = vgui.Create("DTextEntry", frame) + col:SetSize(680, 25) + col:SetPos(10, 85) + col:SetText("HTML Color") + + local tok = vgui.Create("DTextEntry", frame) + tok:SetSize(680, 25) + tok:SetPos(10, 115) + tok:SetText("Discord App token") + + local chan = vgui.Create("DTextEntry", frame) + chan:SetSize(680, 25) + chan:SetPos(10, 145) + chan:SetText("Discord Channel") + + local butts = { + { + name = "Set Mode", + f = function() + val = mode:GetValue() + net.Start("DiscordUpdate") + net.WriteString("mode") + net.WriteString(val) + net.SendToServer() + chat.AddText("Discord mode has been set to " .. val) + end + }, + { + name = "Set Type", + f = function() + local val = type:GetValue() + net.Start("DiscordUpdate") + net.WriteString("type") + net.WriteString(val) + net.SendToServer() + chat.AddText("Discord type has been set to " .. val) + end + }, + { + name = "Set Webhook", + f = function() + local val = whook:GetValue() + net.Start("DiscordUpdate") + net.WriteString("webhook") + net.WriteString(val) + net.SendToServer() + chat.AddText("Discord webhook has been set to " .. val) + end + }, + { + name = "Set Color", + f = function() + local val = col:GetValue() + net.Start("DiscordUpdate") + net.WriteString("color") + net.WriteString(val) + net.SendToServer() + chat.AddText("Discord embed color has been set to " .. val) + end + }, + { + name = "Set Discord App token", + f = function() + local val = tok:GetValue() + net.Start("DiscordUpdate") + net.WriteString("token") + net.WriteString(val) + net.SendToServer() + chat.AddText("Discord App token has been set to " .. val) + end + }, + { + name = "Set Discord Channel", + f = function() + local val = chan:GetValue() + net.Start("DiscordUpdate") + net.WriteString("channel") + net.WriteString(val) + net.SendToServer() + chat.AddText("Discord Channel has been set to " .. val) + end + }, + { + name = "Set All", + f = function() + local val = col:GetValue() + net.Start("DiscordUpdate") + net.WriteString("color") + net.WriteString(col:GetValue()) + net.SendToServer() + local val = whook:GetValue() + net.Start("DiscordUpdate") + net.WriteString("webhook") + net.WriteString(whook:GetValue()) + net.SendToServer() + local val = type:GetValue() + net.Start("DiscordUpdate") + net.WriteString("type") + net.WriteString(val) + net.SendToServer() + val = mode:GetValue() + net.Start("DiscordUpdate") + net.WriteString("mode") + net.WriteString(val) + net.SendToServer() + local val = chan:GetValue() + net.Start("DiscordUpdate") + net.WriteString("channel") + net.WriteString(val) + net.SendToServer() + local val = tok:GetValue() + net.Start("DiscordUpdate") + net.WriteString("token") + net.WriteString(val) + net.SendToServer() + chat.AddText("All Discord settings was updated!") + end + } + } + local panel = vgui.Create("DScrollPanel", frame) + panel:SetPos(10, 175) + panel:SetSize(680, 210) + for k,v in pairs(butts) do + local butt = panel:Add("DButton") + butt:SetText(v.name) + butt:SetSize(680, 25) + butt:Dock(TOP) + butt:DockMargin(0, 0, 0, 5) + butt.DoClick = v.f + end +end +concommand.Add("Discord", OpenDiscordSettings) diff --git a/lua/autorun/server/discord.lua b/lua/autorun/server/discord.lua new file mode 100644 index 0000000..3c751dc --- /dev/null +++ b/lua/autorun/server/discord.lua @@ -0,0 +1,217 @@ +--[[ + COPYRIGHT: + Made by Mestima © 2019 + + if (this addon using api.nilored server) then + I don't allow you to modify this addon. + I don't allow you to share this addon. + This addon using MY API server. I don't want billions of people to use my api server. + If you want to modify this addon, please contact me before or get the source code from my GitHub. + else + If you're reading this at the GitHub, you need to know + that this script is licensed under the GPLv3 License (https://www.gnu.org/licenses/gpl-3.0.html) + Copyright removing is NOT allowed! + + If you're using this type of GM-Discord addon that licensed under GPLv3 license, + you are NOT allowed to use api.nilored server. + end + + http://steamcommunity.com/id/mestima + http://github.com/Mestima +]] + +DiscordSettings = { + settings = { + mode = "Sandbox", -- Sandbox/DarkRP + type = "Simple", -- Embed or Simple + webhook = "https://discordapp.com/api/webhooks/GuildID/TOKEN", + color = 15258703, -- Decimal color (https://convertingcolors.com/decimal-color-15258703.html) + token = "TOKEN", + channel = "channel_id", + admins = {} -- Supports ULX admin mode! (ULX only!) + } +} + +function DiscordSettings:Save() + file.Write("discord.txt", util.TableToJSON(self.settings)) +end +function DiscordSettings:Load() + if !file.Exists("discord.txt", "DATA") then self:Save() end + self.settings = util.JSONToTable(file.Read("discord.txt", "DATA")) +end + +local function SaveDiscordStorage(tbl) + file.Write("discord_storage.txt", util.TableToJSON(tbl)) +end +if !file.Exists("discord_storage.txt", "DATA") then + local init = { + last = 1, + msg = {} + } + SaveDiscordStorage(init) +end + +--[[ Network ]] +util.AddNetworkString("DiscordToGmod") +util.AddNetworkString("DiscordUpdate") +net.Receive("DiscordUpdate", function(len,ply) + if !ply:IsSuperAdmin() then return end + local type = net.ReadString() + local var = net.ReadString() + DiscordSettings.settings[type] = var + DiscordSettings:Save() +end) + +--[[ Load Data ]] +DiscordSettings:Load() +DiscordStorage = util.JSONToTable(file.Read("discord_storage.txt", "DATA")) + +--[[ Discord Messages ]] +local function GetFromDiscord(body, len, headers, code) -- yeah, I know, so shitty function + local content = util.JSONToTable(body) + for i = DiscordStorage.last, #content do + if content[i].author.bot == true then goto skip end + for k,v in pairs(DiscordStorage.msg) do if v == content[i].id then goto skip end end + + table.insert(DiscordStorage.msg, content[i].id) + local tbl = { + last = i, -- Don't forget to make small oprimization :) + msg = DiscordStorage.msg + } + SaveDiscordStorage(tbl) + local username = content[i].author.username + local msg = content[i].content + local uid = tostring(content[i].author.id) + + local len = string.len(msg) + if len > 4 then + if string.sub(msg,1,1) == "!" then + if DiscordSettings.settings.admins[uid] then + local command = string.sub(msg, 2, len) + game.ConsoleCommand("ulx "..command.."\n") + goto skip + end + end + end + + net.Start("DiscordToGmod") + net.WriteString(username) + net.WriteString(msg) + net.Broadcast() + ::skip:: -- why don't I use 'continue' operator? + end +end +timer.Create("DiscordMessageGetter", 3, 0, function() + if not DiscordSettings then return end + if not DiscordSettings.settings then return end + if DiscordSettings.settings.token == "TOKEN" or DiscordSettings.settings.channel == "channel_id" then return end + http.Fetch("http://yourwebserver.com/request.php?channel="..DiscordSettings.settings.channel.."&token="..DiscordSettings.settings.token, GetFromDiscord) -- CHANGE URL HERE +end) + +--[[ Avatar Loading ]] +DiscordAvatar = {} +local function GetSteamAvatar(ply) + http.Fetch("https://steamcommunity.com/profiles/".. ply:SteamID64() .."?xml=1", function(body) + local p1,p2 = string.find(body, "") + if (p1 && p2) then + p1 = p1+21 + p2 = p2-16 + local id = ply:SteamID() + if !DiscordAvatar[id] then + DiscordAvatar[id] = string.sub(body, p1, p2) + end + end + end, + function() + error("Error. Steam api is down.") + end + ) +end + +--[[ Message Filtering Functions ]] +local SendFunctions = { + DarkRP = function(p,m,t) + local msg = m + if string.len(msg) < 4 then return false end + if string.sub(msg,1,3) == "///" then return false end + if string.sub(msg,1,3) == "/ad" then return false end + if string.sub(msg,1,2) ~= "//" && string.sub(msg,1,2) ~= "/a" && string.sub(msg,1,4) ~= "/ooc" then return false end + + msg = string.gsub(msg,"// ","") + msg = string.gsub(msg,"/a ","") + msg = string.gsub(msg,"/ooc ","") + local name = "" + + if t == true then name = name .. "(TEAM) " end + if p:Alive() == false then name = name .. "*DEAD* " end + name = name .. p:Nick() + return true, msg, name + end, + Sandbox = function(p,m,t) + local msg = m + local name = "" + + if t == true then name = name .. "(TEAM) " end + if p:Alive() == false then name = name .. "*DEAD* " end + name = name .. p:Nick() + return true, msg, name + end +} + +--[[ Transfer Function ]] +local function DiscordRelay(ply, text, team) + if !IsValid(ply) || !ply:IsPlayer() then return end + if !DiscordSettings || !DiscordSettings.settings then return end + + local flag, msg, uname = SendFunctions[DiscordSettings.settings.mode](ply, text, team) + if !flag then return end + + local data = { + username = uname, + avatar_url = DiscordAvatar[ply:SteamID()], + content = msg + } + + if DiscordSettings.settings.type == "Embed" then -- Embed settings + data = { + username = uname, + avatar_url = DiscordAvatar[ply:SteamID()], + embeds = { + { + author = { + name = msg + }, + color = DiscordSettings.settings.color + } + } + } + end + + http.Post("http://yourwebserver.com/send.php", { -- CHANGE URL HERE + webhook = DiscordSettings.settings.webhook, + content = util.TableToJSON(data), + }) +end + +--[[ Garbage Collector ]] +local function ClearCache(ply) + local id = ply:SteamID() + if !DiscordAvatar[id] then return end + DiscordAvatar[id] = nil +end +hook.Add("PlayerSay", "DiscordRelay", DiscordRelay) +hook.Add("PlayerDisconnected", "DiscordClearCache", ClearCache) +hook.Add("PlayerInitialSpawn", "DiscordAvatarInit", GetSteamAvatar) + +concommand.Add("Discord_AddAdmin", function(ply, cmd, args) + if IsValid(ply) and !ply:IsSuperAdmin() then return end + if !args[1] then return end + DiscordSettings.settings.admins[tostring(args[1])] = true + DiscordSettings:Save() +end) +concommand.Add("Discord_RemoveAdmin", function(ply, cmd, args) + if IsValid(ply) and !ply:IsSuperAdmin() then return end + if !args[1] then return end + DiscordSettings.settings.admins[tostring(args[1])] = nil + DiscordSettings:Save() +end)