dobrograd-13-06-2022/garrysmod/addons/admin-sg/lua/modules/sh_commands.lua
Jonny_Bro (Nikita) e4d5311906 first commit
2023-11-16 15:01:19 +05:00

487 lines
15 KiB
Lua
Raw Blame History

--[[
<09> 2017 Thriving Ventures Ltd do not share, re-distribute or modify
without permission of its author (gustaf@thrivingventures.com).
]]
--- ## Shared
-- The registration and handling of chat commands.
-- @module serverguard.command
local string = string;
serverguard.command = serverguard.command or {};
serverguard.command.stored = serverguard.command.stored or {};
--- Gets a table of all the registered commands.
-- @treturn table Command data.
function serverguard.command:GetTable()
return self.stored;
end;
serverguard.command.GetStored = serverguard.command.GetTable;
--- Registers a new command.
-- @table data The command table to extract info from.
function serverguard.command:Add(data)
self.stored[data.command] = data;
if (data.permissions) then
serverguard.permission:Add(data.permissions);
end;
if (SERVER) then
self.stored[data.command].ContextMenu = nil;
end;
end;
--- Removes a command.
-- @string uniqueID The unique ID of the command.
function serverguard.command:Remove(uniqueID)
self.stored[uniqueID] = nil;
end;
--- Gets a command by its unique ID.
-- @string uniqueID The unique ID of the command.
-- @treturn table Command data.
function serverguard.command:FindByID(uniqueID)
local command = self.stored[uniqueID];
if (command) then
return command;
else
for k, v in pairs(self.stored) do
if (v.aliases and table.HasValue(v.aliases, uniqueID)) then
return v;
end;
end;
end;
end;
--- Gets the formatted argument string from a command table.
-- @table commandTable The command table.
-- @treturn string Formatted string.
function serverguard.command:GetArgumentsString(commandTable)
local result = "";
local first = true;
if (commandTable.arguments) then
for k, v in pairs(commandTable.arguments) do
if (first) then
first = false;
else
result = result .. " ";
end;
result = result .. "<" .. v .. ">";
end;
end;
if (commandTable.optionalArguments) then
for k, v in pairs(commandTable.optionalArguments) do
if (first) then
first = false;
else
result = result .. " ";
end;
result = result .. "[" .. v .. "]";
end;
end;
return result;
end;
serverguard.command.Get = serverguard.command.FindByID;
local function GetPlayerSteamID32(player)
local stid_32 = string.format("%.0f", string.sub(player:SteamID64(), 3) - "561197960265728")
return stid_32
end
if (SERVER) then
local notifyCommands = octolib.array.toKeys{ 'ban', 'unban', 'kick', 'rank' }
--[[ Internal function run a command. --]]
local function RUN_COMMAND(commandTable, player, bIsSilent, arguments)
if (!commandTable) then
return;
end;
bIsSilent = bIsSilent or not notifyCommands[commandTable.command or '']
-- Legacy command style.
if (commandTable.Execute) then
local bStatus, value = pcall(commandTable.Execute, commandTable, player, bIsSilent, arguments);
if (!commandTable.bNoLog) then
serverguard.PrintConsole(string.format(
"%s ran command \"%s %s\"\n", serverguard.player:GetName(player), commandTable.command, table.concat(arguments, " ")
));
end;
if (bStatus) then
hook.Call("serverguard.RanCommand", nil, player, commandTable, bIsSilent, arguments);
else
ErrorNoHalt(string.format("The \"%s\" command has failed to run.\n%s\n", commandTable.command, value));
return;
end;
else
if (commandTable.OnExecute) then
commandTable:OnExecute(player, arguments);
end;
local targets = {};
if (commandTable.bSingleTarget) then
local target = util.FindPlayer(arguments[1], player);
if (target and IsValid(target)) then
if (!util.PlayerMatchesImmunity(commandTable.immunity, player, target)) then
serverguard.Notify(player, SERVERGUARD.NOTIFY.RED, "This player has a higher immunity than you.");
else
if (commandTable:OnPlayerExecute(player, target, arguments)) then
targets = {target};
end;
end;
end;
else
targets = util.ExecuteOnPlayers(arguments[1], player, commandTable.immunity or SERVERGUARD.IMMUNITY.LESSOREQUAL, function(target)
return commandTable:OnPlayerExecute(player, target, arguments);
end);
end;
if (!bIsSilent and commandTable.OnNotify and targets and #targets > 0 and !hook.Call("serverguard.CommandNotify", nil, player, targets, arguments)) then
local arguments = {commandTable:OnNotify(player, targets, arguments)};
serverguard.Notify(nil, unpack(arguments));
end;
if (commandTable.OnExecuted) then
commandTable:OnExecuted(player, targets, arguments);
end;
if (!commandTable.bNoLog) then
serverguard.PrintConsole(string.format(
"%s ran command \"%s %s\"\n", serverguard.player:GetName(player), commandTable.command, table.concat(arguments, " ")
));
end;
hook.Call("serverguard.RanCommand", nil, player, commandTable, bIsSilent, arguments);
end;
end;
--- Makes a player run a command.
-- @player player The player running the command. You should **not** pass this argument clientside.
-- @string command The unique ID of the command to run.
-- @bool bIsSilent Whether or not to display a notification.
-- @param ... Any arguments to pass to the command.
-- @treturn bool Whether or not the command exists.
function serverguard.command.Run(player, command, bIsSilent, ...)
local arguments = {...};
local commandTable = serverguard.command:FindByID(command);
if (commandTable) then
if (commandTable.bDisallowConsole and util.IsConsole(player)) then
serverguard.PrintConsole("You cannot run the \"" .. commandTable.command .. "\" command as the server.\n");
return true;
end;
if (hook.Call("serverguard.PlayerCanUseCommand", nil, player, commandTable, bIsSilent, arguments) != false) then
if (util.IsConsole(player)) then
RUN_COMMAND(commandTable, player, bIsSilent, arguments);
return true;
end;
if (commandTable.permissions and #commandTable.permissions > 0) then
if (!serverguard.player:HasPermission(player, commandTable.permissions)) then
serverguard.Notify(player, SERVERGUARD.NOTIFY.RED, string.format("You do not have access to this command, %s.", player:Nick()));
return true;
end;
end;
if (!commandTable.arguments or #arguments >= #commandTable.arguments) then
RUN_COMMAND(commandTable, player, bIsSilent, arguments);
elseif (!util.IsConsole(player) and #arguments == 0 and commandTable.arguments and #commandTable.arguments == 1 and commandTable.arguments[1] == "player") then
RUN_COMMAND(commandTable, player, bIsSilent, {player:Name()});
else
serverguard.Notify(player, SERVERGUARD.NOTIFY.RED, "The syntax for this command is incorrect:");
serverguard.Notify(player, SERVERGUARD.NOTIFY.WHITE, string.format("!%s %s", commandTable.command, serverguard.command:GetArgumentsString(commandTable)));
end;
end;
return true;
end;
return false;
end;
hook.Add("PlayerSay", "serverguard.command.PlayerSay", function(pPlayer, text, m_bToAll, m_bDead)
if (text == "") then
return;
end;
local prefix = string.lower(string.sub(text, 1, 1));
local cmd = string.lower(string.Explode(' ', text)[1])
if (prefix == "!" or prefix == "~") then
local arguments = util.ExplodeByTags(text, " ", "\"", "\"", true);
local commandName = string.lower(string.sub(arguments[1], #prefix + 1));
table.remove(arguments, 1);
if (pPlayer:GetDBVar('sgMuted') and commandName != "unmute") then
return "";
end;
local commandExists = serverguard.command.Run(pPlayer, commandName, false, unpack(arguments));
if (commandExists) then
return "";
end;
elseif (pPlayer:GetDBVar('sgMuted')) then
return "";
end
end);
serverguard.netstream.Hook("sgRunCommand", function(pPlayer, data)
serverguard.command.Run(pPlayer, data.command, data.silent, unpack(data.arguments));
end);
concommand.Add("sg", function(pPlayer, command, arguments)
if (arguments and arguments[1]) then
local commandName = string.lower(arguments[1]);
local commandTable = serverguard.command:FindByID(commandName);
table.remove(arguments, 1);
if (commandTable) then
serverguard.command.Run(pPlayer, commandTable.command, false, unpack(arguments));
end;
end;
end);
elseif (CLIENT) then
local autoComplete = {}
local autoCompleteWidth = 0
local autoCompleteHeight = 0
local autoCompleteActive = 0
local autoCompletePrefix = {}
autoCompletePrefix["!"] = true
autoCompletePrefix["~"] = true
function serverguard.command.Run(command, bIsSilent, ...)
serverguard.netstream.Start("sgRunCommand", {
command = command, silent = bIsSilent, arguments = {...}
});
end;
concommand.Add("sg", function(_, command, arguments)
if (arguments and arguments[1]) then
local commandName = string.lower(arguments[1]);
local commandTable = serverguard.command:FindByID(commandName);
table.remove(arguments, 1);
if (commandTable) then
serverguard.command.Run(commandTable.command, false, unpack(arguments));
end;
end;
end, function(command, arguments)
local results = {};
local commands = serverguard.command:GetTable();
arguments = util.ExplodeByTags(string.Trim(arguments), " ", "\"", "\"", true);
if (arguments[1]) then
local command = serverguard.command:FindByID(arguments[1]);
if (command and serverguard.player:HasPermission(LocalPlayer(), command.permissions)) then
local sg_cmdabout = "sg " .. command.command .. " " .. serverguard.command:GetArgumentsString(command)
table.insert(results, sg_cmdabout);
if (command.arguments and #command.arguments > 0) then
for k, v in pairs(command.arguments) do
if (v == "player") then
for k, target in ipairs(player.GetAll()) do
if (arguments[2]) then
for _, result in pairs(results) do
if (result == sg_cmdabout) then
results[_] = nil
end
end
if !(target:IsBot()) then
if (target:Name():lower():find(arguments[2]) or target:SteamID():find(arguments[2]) or target:SteamID():lower():find(arguments[2]) or target:SteamID64():find(arguments[2]) or GetPlayerSteamID32(target):find(arguments[2])) then
table.insert(results, "sg " .. command.command .. " \"" .. target:Name() .. "\"")
end
else
if (target:Name():lower():find(arguments[2]) or target:SteamID():find(arguments[2])) then
table.insert(results, "sg " .. command.command .. " \"" .. target:Name() .. "\"");
end
end
else
table.insert(results, "sg " .. command.command .. " \"" .. target:Name() .. "\"")
end
end;
end;
end;
end;
elseif (!arguments[2]) then
for k, commandTable in util.SortedPairsByMemberValue(commands, "command") do
if (string.sub(commandTable.command, 1, string.len(arguments[1])) == arguments[1] and serverguard.player:HasPermission(LocalPlayer(), commandTable.permissions)) then
table.insert(results, "sg " .. commandTable.command .. " ");
end;
end;
end;
else
for k, commandTable in util.SortedPairsByMemberValue(commands, "command") do
if (serverguard.player:HasPermission(LocalPlayer(), commandTable.permissions)) then
table.insert(results, "sg " .. commandTable.command .. " ");
end;
end;
end;
hook.Call("serverguard.ConsoleAutoComplete", nil, arguments, results);
return results;
end);
local function serverGuard_AddAutoCompletePrefixes()
hook.Call("serverguard.AddPrefixes", nil, autoCompletePrefix)
end
timer.Simple(4, serverGuard_AddAutoCompletePrefixes)
local function serverGuard_PaintAutoComplete()
if (#autoComplete > 0) then
local x, y = chat.GetChatBoxPos()
if (Clockwork) then
x, y = Clockwork.chatBox:GetPosition()
end
draw.RoundedBox(2, x, y -(6 +autoCompleteHeight), autoCompleteWidth +10, autoCompleteHeight, Color(0, 0, 0, 200))
for k, v in pairs(autoComplete) do
if (k == autoCompleteActive) then
draw.SimpleText(v, "serverGuard_ownerFont", x +4, y -16 *k, Color(20, 193, 20, 255), TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER)
else
draw.SimpleText(v, "serverGuard_ownerFont", x +4, y -16 *k, color_white, TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER)
end
end
end
end
hook.Add("HUDPaint", "serverguard_chatcommands.HUDPaint", serverGuard_PaintAutoComplete)
local table = table
local isTabbing = false
local function serverGuard_CheckChatText(text)
if (!isTabbing) then
autoComplete = {}
-- Check the prefix.
if (autoCompletePrefix[string.sub(text, 0, 1)]) then
autoCompleteWidth = 0
autoCompleteHeight = 0
-- IS THIS A GOOD IDEA? LOL
local commands = table.Copy(serverguard.command.stored)
hook.Call("serverguard.AddAutoComplete", nil, commands)
for command, data in pairs(commands) do
if (string.find(command, text)) then
local aText = command
local width, height = util.GetTextSize("serverGuard_ownerFont", aText)
if (data.arguments) then
local args = ""
for k, v in pairs(data.arguments) do
args = args .. v .. " "
end
aText = command .. " " .. args
width, height = util.GetTextSize("serverGuard_ownerFont", aText)
end
if (width > autoCompleteWidth) then
autoCompleteWidth = width
end
autoCompleteHeight = autoCompleteHeight +height
table.insert(autoComplete, aText)
end
end
if (#autoComplete == 1) then
autoCompleteActive = 1
end
autoCompleteHeight = autoCompleteHeight +3
end
end
end
hook.Add("ChatTextChanged", "serverguard_chatcommands.ChatTextChanged", serverGuard_CheckChatText)
local function serverGuard_ChatboxClosed()
autoComplete = {}
autoCompleteWidth = 0
autoCompleteHeight = 0
autoCompleteActive = 0
isTabbing = false
end
hook.Add("FinishChat", "serverguard_chatcommands.FinishChat", serverGuard_ChatboxClosed)
timer.Create("serverguard.autocomplete.timer", FrameTime() *8, 0, function() timer.Stop("serverguard.autocomplete.timer") end)
local function serverGuard_ChatboxTabbed(text)
isTabbing = true
autoCompleteActive = autoCompleteActive +1
if (autoCompleteActive > #autoComplete) then
autoCompleteActive = 1
end
if (autoComplete[autoCompleteActive]) then
local start = string.find(autoComplete[autoCompleteActive], "<")
if (start) then
timer.Adjust("serverguard.autocomplete.timer", FrameTime() *8, 1, function()
isTabbing = false
timer.Stop("serverguard.autocomplete.timer")
end)
timer.Start("serverguard.autocomplete.timer")
return string.sub(autoComplete[autoCompleteActive], 0, start -2)
else
timer.Adjust("serverguard.autocomplete.timer", FrameTime() *8, 1, function()
isTabbing = false
timer.Stop("serverguard.autocomplete.timer")
end)
timer.Start("serverguard.autocomplete.timer")
return autoComplete[autoCompleteActive]
end
end
isTabbing = false
end
hook.Add("OnChatTab", "serverguard_chatcommands.OnChatTab", serverGuard_ChatboxTabbed)
end