-- console.lua -- Implements things related to console commands function InitConsoleCommands() local PluginMgr = cPluginManager:Get(); -- Please keep the list alpha-sorted PluginMgr:BindConsoleCommand("ban", HandleConsoleBan, "Bans a player by name"); PluginMgr:BindConsoleCommand("banlist", HandleConsoleBanList, "Lists all players banned by name"); PluginMgr:BindConsoleCommand("banlist ips", HandleConsoleBanList, "Lists all players banned by IP"); PluginMgr:BindConsoleCommand("help", HandleConsoleHelp, "Lists all commands"); PluginMgr:BindConsoleCommand("list", HandleConsoleList, "Lists all players in a machine-readable format"); PluginMgr:BindConsoleCommand("listgroups", HandleConsoleListGroups, "Shows a list of all the groups"); PluginMgr:BindConsoleCommand("numchunks", HandleConsoleNumChunks, "Shows number of chunks currently loaded"); PluginMgr:BindConsoleCommand("players", HandleConsolePlayers, "Lists all connected players"); PluginMgr:BindConsoleCommand("primaryserverversion", HandleConsolePrimaryServerVersion, "Gets or sets server version reported to 1.4+ clients"); PluginMgr:BindConsoleCommand("rank", HandleConsoleRank, " [Player] [Group] - add a player to a group"); PluginMgr:BindConsoleCommand("reload", HandleConsoleReload, "Reloads all plugins"); PluginMgr:BindConsoleCommand("save-all", HandleConsoleSaveAll, "Saves all chunks"); PluginMgr:BindConsoleCommand("say", HandleConsoleSay, "Sends a chat message to all players"); PluginMgr:BindConsoleCommand("unload", HandleConsoleUnload, "Unloads all unused chunks"); end function HandleConsoleBan(Split) if (#Split < 2) then return true, cChatColor.Green .. "Usage: /ban [Player] "; end local Reason = "You have been banned" if (#Split > 2) then Reason = table.concat(Split, " ", 3); end if (not(BanPlayer(Split[2], Reason))) then return true, cChatColor.Green .. "Could not find player " .. Split[2]; end return true, "Player " .. Split[2] .. " has been banned."; end function HandleConsoleBanList(Split) if (#Split == 1) then return true, BanListByName(); end if (string.lower(Split[2]) == "ips") then return true, BanListByIPs(); end return true, "Unknown banlist subcommand"; end function HandleConsoleHelp(Split) local Commands = {}; -- {index => {"Command", "HelpString"} } local MaxLength = 0; local AddToTable = function(Command, HelpString) table.insert(Commands, { Command, HelpString }); local CmdLen = Command:len(); if (CmdLen > MaxLength) then MaxLength = CmdLen; end end cPluginManager:Get():ForEachConsoleCommand(AddToTable); -- Sort the table: local CompareCommands = function(a, b) return a[1] < b[1]; -- compare command strings end table.sort(Commands, CompareCommands); local Out = ""; for i, Command in ipairs(Commands) do Out = Out .. Command[1] .. string.rep(" ", MaxLength - Command[1]:len()); -- Align to a table Out = Out .. " - " .. Command[2] .. "\n"; end return true, Out; end function HandleConsoleList(Split) -- Get a list of all players, one playername per line local Out = ""; cRoot:Get():ForEachWorld( function (a_World) a_World:ForEachPlayer( function (a_Player) Out = Out .. a_Player:GetName() .. "\n"; end ); end ); return true, Out; end function HandleConsoleListGroups(Split) -- Read the groups.ini file: local GroupsIni = cIniFile("groups.ini"); if (not(GroupsIni:ReadFile())) then return true, "No groups found"; end -- Read the groups: Number = GroupsIni:NumKeys(); Groups = {}; for i = 0, Number do table.insert(Groups, GroupsIni:KeyName(i)) end -- Output the groups, concatenated to a string: local Out = "Groups:\n" Out = Out .. table.concat(Groups, ", "); return true, Out; end function HandleConsoleNumChunks(Split) local Output = {}; local AddNumChunks = function(World) Output[World:GetName()] = World:GetNumChunks(); end; cRoot:Get():ForEachWorld(AddNumChunks); local Total = 0; local Out = ""; for name, num in pairs(Output) do Out = Out .. " " .. name .. ": " .. num .. " chunks\n"; Total = Total + num; end Out = Out .. "Total: " .. Total .. " chunks\n"; return true, Out; end function HandleConsolePlayers(Split) local PlayersInWorlds = {}; -- "WorldName" => [players array] local AddToTable = function(Player) local WorldName = Player:GetWorld():GetName(); if (PlayersInWorlds[WorldName] == nil) then PlayersInWorlds[WorldName] = {}; end table.insert(PlayersInWorlds[WorldName], Player:GetName() .. " @ " .. Player:GetIP()); end cRoot:Get():ForEachPlayer(AddToTable); local Out = ""; for WorldName, Players in pairs(PlayersInWorlds) do Out = Out .. "World " .. WorldName .. ":\n"; for i, PlayerName in ipairs(Players) do Out = Out .. " " .. PlayerName .. "\n"; end end return true, Out; end function HandleConsolePrimaryServerVersion(Split) if (#Split == 1) then -- Display current version: local Version = cRoot:Get():GetPrimaryServerVersion(); return true, "Primary server version: #" .. Version .. ", " .. cRoot:GetProtocolVersionTextFromInt(Version); end -- Set new value as the version: cRoot:Get():SetPrimaryServerVersion(tonumber(Split[2])); local Version = cRoot:Get():GetPrimaryServerVersion(); return true, "Primary server version is now #" .. Version .. ", " .. cRoot:GetProtocolVersionTextFromInt(Version); end function HandleConsoleRank(Split) if (Split[2] == nil) or (Split[3] == nil) then return true, "Usage: /rank [Player] [Group]"; end local Out = ""; -- Read the groups.ini file: local GroupsIni = cIniFile("groups.ini") if (not(GroupsIni:ReadFile())) then Out = "Could not read groups.ini, creating anew!\n" end -- Find the group: if (GroupsIni:FindKey(Split[3]) == -1) then return true, Out .. "Group does not exist"; end -- Read the users.ini file: local UsersIni = cIniFile("users.ini"); if (not(UsersIni:ReadFile())) then Out = Out .. "Could not read users.ini, creating anew!\n"; end -- Write the new group value to users.ini: UsersIni:DeleteKey(Split[2]); UsersIni:GetValueSet(Split[2], "Groups", Split[3]); UsersIni:WriteFile(); -- Reload the player's permissions: cRoot:Get():ForEachWorld( function (World) World:ForEachPlayer( function (Player) if (Player:GetName() == Split[2]) then Player:SendMessage(cChatColor.Green .. "You were moved to group " .. Split[3]); Player:LoadPermissionsFromDisk(); end end ); end ) return true, Out .. "Player " .. Split[2] .. " was moved to " .. Split[3]; end function HandleConsoleReload(Split) Server = cRoot:Get():GetServer(); Server:SendMessage(cChatColor.Green .. "Reloading all plugins."); cPluginManager:Get():ReloadPlugins(); return true; end function HandleConsoleSaveAll(Split) cRoot:Get():SaveAllChunks(); return true; end function HandleConsoleSay(Split) table.remove(Split, 1); local Message = ""; for i, Text in ipairs(Split) do Message = Message .. " " .. Text; end Message = Message:sub(2); -- Cut off the first space cRoot:Get():GetServer():BroadcastChat(cChatColor.Purple .. "[SERVER] " .. Message); return true; end function HandleConsoleUnload(Split) local UnloadChunks = function(World) World:UnloadUnusedChunks(); end local Out = "Num loaded chunks before: " .. cRoot:Get():GetTotalChunkCount() .. "\n"; cRoot:Get():ForEachWorld(UnloadChunks); Out = Out .. "Num loaded chunks after: " .. cRoot:Get():GetTotalChunkCount(); return true, Out; end ------------------------------------------------------------------------------------------- -- Helper functions: --- Returns the list of players banned by name, separated by ", " function BanListByName() local NumValues = BannedPlayersIni:NumValues("Banned"); local Banned = {}; local KeyID = BannedPlayersIni:FindKey("Banned"); for i = 1, NumValues do local PlayerName = BannedPlayersIni:ValueName(KeyID, i - 1); if (BannedPlayersIni:GetValueB("Banned", PlayerName)) then -- Player listed AND banned table.insert(Banned, PlayerName); end end return table.concat(Banned, ", "); end --- Returns the list of players banned by IP, separated by ", " function BanListByIPs() -- TODO: No IP ban implemented yet return ""; end