391 lines
9.7 KiB
Lua
391 lines
9.7 KiB
Lua
|
--[[
|
|||
|
<EFBFBD> 2017 Thriving Ventures Limited do not share, re-distribute or modify
|
|||
|
|
|||
|
without permission of its author (gustaf@thrivingventures.com).
|
|||
|
]]
|
|||
|
|
|||
|
--- ## Shared
|
|||
|
--- Library for managing plugins.
|
|||
|
-- @module serverguard.plugin
|
|||
|
|
|||
|
serverguard.plugin = serverguard.plugin or {};
|
|||
|
|
|||
|
local stored = {};
|
|||
|
local object = {};
|
|||
|
|
|||
|
object.__index = object;
|
|||
|
|
|||
|
--- Creates a new plugin table.
|
|||
|
-- @treturn table Plugin table.
|
|||
|
function serverguard.plugin.New()
|
|||
|
local plugin = {};
|
|||
|
|
|||
|
plugin.hooks = {};
|
|||
|
plugin.commands = {};
|
|||
|
plugin.categories = {};
|
|||
|
plugin.toggled = true;
|
|||
|
|
|||
|
setmetatable(plugin, object);
|
|||
|
|
|||
|
return plugin;
|
|||
|
end;
|
|||
|
|
|||
|
--- Registers a plugin.
|
|||
|
-- @table plugin Plugin table to register.
|
|||
|
function serverguard.plugin.Register(plugin)
|
|||
|
stored[plugin.unique] = plugin;
|
|||
|
|
|||
|
if (plugin.permissions) then
|
|||
|
serverguard.permission:Add(plugin.permissions);
|
|||
|
end;
|
|||
|
end;
|
|||
|
|
|||
|
--- Returns a plugin table with the specified name.
|
|||
|
-- @string unique Unique ID of the plugin.
|
|||
|
-- @treturn table Plugin table.
|
|||
|
function serverguard.plugin.FindByID(unique)
|
|||
|
return stored[unique];
|
|||
|
end;
|
|||
|
|
|||
|
serverguard.plugin.Get = serverguard.plugin.FindByID;
|
|||
|
|
|||
|
--- Returns all registered plugins.
|
|||
|
-- @treturn table Table of plugin tables.
|
|||
|
function serverguard.plugin.GetList()
|
|||
|
return stored;
|
|||
|
end;
|
|||
|
|
|||
|
--- Enables or disables a plugin. This toggles any registered hooks, chat commands, or UI categories.
|
|||
|
-- @string uniqueID Unique ID of the plugin.
|
|||
|
-- @bool bToggled Whether or not to turn the plugin on.
|
|||
|
function serverguard.plugin:Toggle(uniqueID, bToggled)
|
|||
|
if (!stored[uniqueID]) then
|
|||
|
return;
|
|||
|
end;
|
|||
|
|
|||
|
stored[uniqueID].toggled = bToggled;
|
|||
|
|
|||
|
local hooks = stored[uniqueID].hooks;
|
|||
|
local commands = stored[uniqueID].commands;
|
|||
|
|
|||
|
for name, data in pairs(hooks) do
|
|||
|
for hookUnique, callback in pairs(data) do
|
|||
|
if (bToggled) then
|
|||
|
hook.Add(name, hookUnique, callback);
|
|||
|
else
|
|||
|
hook.Remove(name, hookUnique);
|
|||
|
end;
|
|||
|
end;
|
|||
|
end;
|
|||
|
|
|||
|
for k, v in pairs(commands) do
|
|||
|
if (bToggled) then
|
|||
|
serverguard.command:Add(v);
|
|||
|
else
|
|||
|
serverguard.command:Remove(k);
|
|||
|
end;
|
|||
|
end;
|
|||
|
|
|||
|
if (CLIENT) then
|
|||
|
local categories = stored[uniqueID].categories;
|
|||
|
|
|||
|
for k, v in pairs(categories) do
|
|||
|
if (bToggled) then
|
|||
|
serverguard.menu.AddCategory(v);
|
|||
|
serverguard.menu:Rebuild();
|
|||
|
else
|
|||
|
serverguard.menu:RemoveCategory(k);
|
|||
|
end;
|
|||
|
end;
|
|||
|
end;
|
|||
|
|
|||
|
hook.Call("serverguard.PluginToggled", nil, uniqueID, bToggled);
|
|||
|
end;
|
|||
|
|
|||
|
--
|
|||
|
-- Add a hook.
|
|||
|
--
|
|||
|
|
|||
|
function object:Hook(name, unique, callback)
|
|||
|
self.hooks[name] = self.hooks[name] or {};
|
|||
|
self.hooks[name][unique] = callback;
|
|||
|
|
|||
|
hook.Add(name, unique, callback);
|
|||
|
end;
|
|||
|
|
|||
|
--
|
|||
|
-- Add a command.
|
|||
|
--
|
|||
|
|
|||
|
function object:AddCommand(commandTable)
|
|||
|
self.commands[commandTable.command] = self.commands[commandTable.command] or commandTable;
|
|||
|
serverguard.command:Add(commandTable);
|
|||
|
end;
|
|||
|
|
|||
|
--
|
|||
|
-- Parse a file.
|
|||
|
--
|
|||
|
|
|||
|
function object:IncludeFile(fileName, state)
|
|||
|
serverguard.ParseFile(self.path .. fileName, state)
|
|||
|
end
|
|||
|
|
|||
|
if (CLIENT) then
|
|||
|
--
|
|||
|
-- Add a category.
|
|||
|
--
|
|||
|
|
|||
|
function object:AddCategory(category)
|
|||
|
self.categories[category.name] = self.categories[category.name] or category;
|
|||
|
serverguard.menu.AddCategory(category);
|
|||
|
end;
|
|||
|
|
|||
|
--
|
|||
|
-- Add a subcategory.
|
|||
|
--
|
|||
|
|
|||
|
function object:AddSubCategory(parent_name, data)
|
|||
|
serverguard.menu.AddSubCategory(parent_name, data);
|
|||
|
end;
|
|||
|
end;
|
|||
|
|
|||
|
--- Load plugin files. This should **not** be called manually as it's done automatically when ServerGuard starts.
|
|||
|
function serverguard.plugin.LoadFiles()
|
|||
|
if (SG_DEBUG or SG_FILE_DEBUG) then
|
|||
|
serverguard.PrintConsole("Loading plugins...\n\n");
|
|||
|
end;
|
|||
|
|
|||
|
local _, folders = file.Find("plugins/*", "LUA");
|
|||
|
|
|||
|
for k, folder in pairs(folders) do
|
|||
|
plugin = serverguard.plugin.FindByID(folder) or serverguard.plugin.New();
|
|||
|
plugin.unique = folder;
|
|||
|
plugin.path = "plugins/" .. folder.. "/";
|
|||
|
|
|||
|
if (SERVER) then
|
|||
|
if (file.Exists("plugins/" .. folder.. "/init.lua", "LUA")) then
|
|||
|
include("plugins/" .. folder.. "/init.lua");
|
|||
|
end;
|
|||
|
|
|||
|
if (file.Exists("plugins/" .. folder.. "/cl_init.lua", "LUA")) then
|
|||
|
AddCSLuaFile("plugins/" .. folder.. "/cl_init.lua");
|
|||
|
end;
|
|||
|
elseif (CLIENT) then
|
|||
|
if (file.Exists("plugins/" .. folder.. "/cl_init.lua", "LUA")) then
|
|||
|
include("plugins/" .. folder.. "/cl_init.lua");
|
|||
|
end;
|
|||
|
end;
|
|||
|
|
|||
|
if (plugin.name) then
|
|||
|
serverguard.plugin.Register(plugin);
|
|||
|
|
|||
|
if (SG_DEBUG or SG_FILE_DEBUG) then
|
|||
|
serverguard.PrintConsole("Registered plugin '" .. plugin.name .. "'\n\n");
|
|||
|
end;
|
|||
|
else
|
|||
|
if (SG_DEBUG or SG_FILE_DEBUG) then
|
|||
|
serverguard.PrintConsole("Failed to load plugin '" .. folder .. "'!\n\n");
|
|||
|
end;
|
|||
|
end;
|
|||
|
|
|||
|
plugin = nil;
|
|||
|
end;
|
|||
|
|
|||
|
if (SG_DEBUG or SG_FILE_DEBUG) then
|
|||
|
serverguard.PrintConsole("Loaded plugins.\n");
|
|||
|
end;
|
|||
|
end;
|
|||
|
|
|||
|
serverguard.plugin.LoadFiles();
|
|||
|
|
|||
|
if (SERVER) then
|
|||
|
function serverguard.plugin:SaveData(bForced, uniqueIfForced)
|
|||
|
local pluginData = {};
|
|||
|
|
|||
|
for unique, v in pairs(stored) do
|
|||
|
if (bForced and unique == uniqueIfForced) then
|
|||
|
pluginData[unique] = {toggled = v.toggled, forced = bForced};
|
|||
|
else
|
|||
|
pluginData[unique] = {toggled = v.toggled, forced = v.forced};
|
|||
|
end;
|
|||
|
end;
|
|||
|
|
|||
|
serverguard.config.Save("plugins", pluginData);
|
|||
|
end;
|
|||
|
|
|||
|
--
|
|||
|
-- Send the status of all plugins.
|
|||
|
--
|
|||
|
|
|||
|
hook.Add("serverguard.LoadPlayerData", "plugin.LoadPlayerData", function(player)
|
|||
|
local plugins = serverguard.plugin.GetList()
|
|||
|
|
|||
|
for uniqueID, data in pairs(plugins) do
|
|||
|
serverguard.netstream.Start(player, "sgGetPluginStatus", {
|
|||
|
uniqueID, data.toggled
|
|||
|
});
|
|||
|
end
|
|||
|
end)
|
|||
|
|
|||
|
--
|
|||
|
-- Load the state of all plugins.
|
|||
|
--
|
|||
|
|
|||
|
serverguard.config.New("plugins", function(data)
|
|||
|
for unique, v in pairs(data) do
|
|||
|
if (stored[unique]) then
|
|||
|
local toggle = v.toggled;
|
|||
|
local forced = v.forced;
|
|||
|
|
|||
|
stored[unique].toggled = toggle;
|
|||
|
stored[unique].forced = forced;
|
|||
|
serverguard.plugin:Toggle(unique, toggle);
|
|||
|
end;
|
|||
|
end;
|
|||
|
end);
|
|||
|
|
|||
|
hook.Add("serverguard.PostLoadConfig", "serverguard.plugin.PostLoadConfig", function()
|
|||
|
for unique, v in pairs(stored) do
|
|||
|
if (stored[unique]) then
|
|||
|
local bToggled = v.toggled;
|
|||
|
|
|||
|
if (stored[unique].gamemodes and #stored[unique].gamemodes > 0 and !v.forced) then
|
|||
|
if (!table.HasValue(stored[unique].gamemodes, engine.ActiveGamemode())) then
|
|||
|
bToggled = false;
|
|||
|
|
|||
|
if (SG_DEBUG or SG_FILE_DEBUG) then
|
|||
|
serverguard.PrintConsole("Force-disabled plugin '"..unique.."' - gamemode not compatible!\n");
|
|||
|
end;
|
|||
|
end;
|
|||
|
end;
|
|||
|
|
|||
|
serverguard.plugin.Get(unique).toggled = bToggled;
|
|||
|
serverguard.plugin:Toggle(unique, bToggled);
|
|||
|
end;
|
|||
|
end;
|
|||
|
end);
|
|||
|
elseif (CLIENT) then
|
|||
|
serverguard.netstream.Hook("sgGetPluginStatus", function(data)
|
|||
|
local uniqueID = data[1];
|
|||
|
local state = tobool(data[2]);
|
|||
|
local pluginTable = serverguard.plugin.Get(uniqueID);
|
|||
|
|
|||
|
if (pluginTable) then
|
|||
|
pluginTable.toggled = state;
|
|||
|
|
|||
|
serverguard.plugin:Toggle(uniqueID, pluginTable.toggled);
|
|||
|
end;
|
|||
|
end);
|
|||
|
|
|||
|
--
|
|||
|
-- Create the menu category.
|
|||
|
--
|
|||
|
|
|||
|
local category = {}
|
|||
|
|
|||
|
category.name = "Plugins";
|
|||
|
category.material = "serverguard/menuicons/icon_toggle.png";
|
|||
|
category.permissions = "Manage Plugins";
|
|||
|
|
|||
|
function category:Create(base)
|
|||
|
base.quality = 50
|
|||
|
|
|||
|
base.panel = base:Add("tiger.panel")
|
|||
|
base.panel:SetTitle("Enabled or disabled plugins")
|
|||
|
base.panel:Dock(FILL)
|
|||
|
|
|||
|
base.panel.list = base.panel:Add("tiger.list")
|
|||
|
base.panel.list:Dock(FILL)
|
|||
|
base.panel.list:AddColumn("PLUGIN", 400)
|
|||
|
|
|||
|
function base.panel:PerformLayout()
|
|||
|
category.list = base.panel.list
|
|||
|
end
|
|||
|
|
|||
|
hook.Call("serverguard.panel.PluginList", nil, base.panel.list);
|
|||
|
|
|||
|
local column = base.panel.list:AddColumn("ENABLED")
|
|||
|
column:SetDisabled(true)
|
|||
|
|
|||
|
local plugins = serverguard.plugin.GetList()
|
|||
|
|
|||
|
for unique, data in pairs(plugins) do
|
|||
|
local panel = base.panel.list:AddItem(data.name)
|
|||
|
panel:SetToolTipSG("Version: " .. data.version .. "\n\n" .. data.description)
|
|||
|
|
|||
|
local toggleButton = vgui.Create("DImageButton")
|
|||
|
toggleButton:SetSize(16, 16)
|
|||
|
toggleButton:SetImage(octolib.icons.silk16('accept_button'))
|
|||
|
toggleButton.unique = unique
|
|||
|
toggleButton.whitelist = true
|
|||
|
|
|||
|
if (data.gamemodes and #data.gamemodes > 0) then
|
|||
|
if (!table.HasValue(data.gamemodes, engine.ActiveGamemode())) then
|
|||
|
toggleButton.whitelist = false
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
if (!toggleButton.whitelist) then
|
|||
|
toggleButton:SetToolTipSG("This plugin is not compatible with the current running gamemode!");
|
|||
|
end;
|
|||
|
|
|||
|
function toggleButton:DoClick()
|
|||
|
if (serverguard.player:HasPermission(LocalPlayer(), "Manage Plugins")) then
|
|||
|
if (!self.whitelist and !serverguard.plugin.Get(self.unique).toggled) then
|
|||
|
local q = util.CreateDialog("Incompatible gamemode",
|
|||
|
"This gamemode is incompatible with this plugin. Load it anyways?",
|
|||
|
function() serverguard.command.Run("plugintoggle", false, self.unique); end,
|
|||
|
"Yes",
|
|||
|
function() end,
|
|||
|
"No");
|
|||
|
return;
|
|||
|
end;
|
|||
|
|
|||
|
serverguard.command.Run("plugintoggle", false, self.unique);
|
|||
|
end;
|
|||
|
end;
|
|||
|
|
|||
|
function toggleButton:Think()
|
|||
|
local pluginTable = serverguard.plugin.Get(self.unique)
|
|||
|
|
|||
|
if (pluginTable.toggled) then
|
|||
|
if (self:GetImage() == octolib.icons.silk16('cancel')) then
|
|||
|
self:SetImage(octolib.icons.silk16('accept_button'))
|
|||
|
end
|
|||
|
else
|
|||
|
if (self:GetImage() == octolib.icons.silk16('accept_button')) then
|
|||
|
self:SetImage(octolib.icons.silk16('cancel'))
|
|||
|
end
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
function toggleButton:PerformLayout()
|
|||
|
DImageButton.PerformLayout(self)
|
|||
|
|
|||
|
local w, h = self:GetSize()
|
|||
|
local column = panel:GetThing(2).column
|
|||
|
local x = column:GetPos()
|
|||
|
|
|||
|
self:SetPos(x +column:GetWide() /2 -w /2, column:GetTall() /2 -h /2)
|
|||
|
end
|
|||
|
|
|||
|
panel:AddItem(toggleButton)
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
function category:Update(base)
|
|||
|
end
|
|||
|
|
|||
|
serverguard.menu.AddSubCategory("Server settings", category)
|
|||
|
|
|||
|
hook.Add("serverguard.menu.Close", "serverguard.PluginList", function()
|
|||
|
if (IsValid(category.list)) then
|
|||
|
for k, v in ipairs(category.list:GetCanvas():GetChildren()) do
|
|||
|
if (IsValid(v.tooltip_sg)) then
|
|||
|
v:OnCursorExited();
|
|||
|
end;
|
|||
|
end;
|
|||
|
end;
|
|||
|
end);
|
|||
|
end
|