1
0

Merge remote-tracking branch 'origin/HandleCommand'

This commit is contained in:
madmaxoft 2014-07-04 15:41:48 +02:00
commit 8f65d13d1b
3 changed files with 53 additions and 32 deletions

View File

@ -1875,9 +1875,9 @@ cPluginManager.AddHook(cPluginManager.HOOK_CHAT, OnChatMessage);
}, },
CallPlugin = { Params = "PluginName, FunctionName, [FunctionArgs...]", Return = "[FunctionRets]", Notes = "(STATIC) Calls the specified function in the specified plugin, passing all the given arguments to it. If it succeeds, it returns all the values returned by that function. If it fails, returns no value at all. Note that only strings, numbers, bools, nils and classes can be used for parameters and return values; tables and functions cannot be copied across plugins." }, CallPlugin = { Params = "PluginName, FunctionName, [FunctionArgs...]", Return = "[FunctionRets]", Notes = "(STATIC) Calls the specified function in the specified plugin, passing all the given arguments to it. If it succeeds, it returns all the values returned by that function. If it fails, returns no value at all. Note that only strings, numbers, bools, nils and classes can be used for parameters and return values; tables and functions cannot be copied across plugins." },
DisablePlugin = { Params = "PluginName", Return = "bool", Notes = "Disables a plugin specified by its name. Returns true if the plugin was disabled, false if it wasn't found or wasn't active." }, DisablePlugin = { Params = "PluginName", Return = "bool", Notes = "Disables a plugin specified by its name. Returns true if the plugin was disabled, false if it wasn't found or wasn't active." },
ExecuteCommand = { Params = "{{cPlayer|Player}}, CommandStr", Return = "bool", Notes = "Executes the command as if given by the specified Player. Checks permissions. Returns true if executed." }, ExecuteCommand = { Params = "{{cPlayer|Player}}, CommandStr", Return = "{{cPluginManager#CommandResult|CommandResult}}", Notes = "Executes the command as if given by the specified Player. Checks permissions." },
FindPlugins = { Params = "", Return = "", Notes = "Refreshes the list of plugins to include all folders inside the Plugins folder (potentially new disabled plugins)" }, FindPlugins = { Params = "", Return = "", Notes = "Refreshes the list of plugins to include all folders inside the Plugins folder (potentially new disabled plugins)" },
ForceExecuteCommand = { Params = "{{cPlayer|Player}}, CommandStr", Return = "bool", Notes = "Same as ExecuteCommand, but doesn't check permissions" }, ForceExecuteCommand = { Params = "{{cPlayer|Player}}, CommandStr", Return = "{{cPluginManager#CommandResult|CommandResult}}", Notes = "Same as ExecuteCommand, but doesn't check permissions" },
ForEachCommand = { Params = "CallbackFn", Return = "bool", Notes = "Calls the CallbackFn function for each command that has been bound using BindCommand(). The CallbackFn has the following signature: <pre class=\"prettyprint lang-lua\">function(Command, Permission, HelpString)</pre>. If the callback returns true, the enumeration is aborted and this API function returns false; if it returns false or no value, the enumeration continues with the next command, and the API function returns true." }, ForEachCommand = { Params = "CallbackFn", Return = "bool", Notes = "Calls the CallbackFn function for each command that has been bound using BindCommand(). The CallbackFn has the following signature: <pre class=\"prettyprint lang-lua\">function(Command, Permission, HelpString)</pre>. If the callback returns true, the enumeration is aborted and this API function returns false; if it returns false or no value, the enumeration continues with the next command, and the API function returns true." },
ForEachConsoleCommand = { Params = "CallbackFn", Return = "bool", Notes = "Calls the CallbackFn function for each command that has been bound using BindConsoleCommand(). The CallbackFn has the following signature: <pre class=\"prettyprint lang-lua\">function (Command, HelpString)</pre>. If the callback returns true, the enumeration is aborted and this API function returns false; if it returns false or no value, the enumeration continues with the next command, and the API function returns true." }, ForEachConsoleCommand = { Params = "CallbackFn", Return = "bool", Notes = "Calls the CallbackFn function for each command that has been bound using BindConsoleCommand(). The CallbackFn has the following signature: <pre class=\"prettyprint lang-lua\">function (Command, HelpString)</pre>. If the callback returns true, the enumeration is aborted and this API function returns false; if it returns false or no value, the enumeration continues with the next command, and the API function returns true." },
Get = { Params = "", Return = "cPluginManager", Notes = "(STATIC) Returns the single instance of the plugin manager" }, Get = { Params = "", Return = "cPluginManager", Notes = "(STATIC) Returns the single instance of the plugin manager" },
@ -1893,8 +1893,23 @@ cPluginManager.AddHook(cPluginManager.HOOK_CHAT, OnChatMessage);
LogStackTrace = { Params = "", Return = "", Notes = "(STATIC) Logs a current stack trace of the Lua engine to the server console log. Same format as is used when the plugin fails." }, LogStackTrace = { Params = "", Return = "", Notes = "(STATIC) Logs a current stack trace of the Lua engine to the server console log. Same format as is used when the plugin fails." },
ReloadPlugins = { Params = "", Return = "", Notes = "Reloads all active plugins" }, ReloadPlugins = { Params = "", Return = "", Notes = "Reloads all active plugins" },
}, },
ConstantGroups=
{
CommandResult =
{
Include = "^cr.*",
TextBefore = [[
Results that the (Force)ExecuteCommand return. This gives information if the command is executed or not and the reason.
]],
},
},
Constants = Constants =
{ {
crBlocked = { Notes = "When a plugin stopped the command using the OnExecuteCommand hook" },
crError = { Notes = "When the command handler for the given command results in an error" },
crExecuted = { Notes = "When the command is successfully executed." },
crNoPermission = { Notes = "When the player doesn't have permission to execute the given command." },
crUnknownCommand = { Notes = "When the given command doesn't exist." },
HOOK_BLOCK_SPREAD = { Notes = "Called when a block spreads based on world conditions" }, HOOK_BLOCK_SPREAD = { Notes = "Called when a block spreads based on world conditions" },
HOOK_BLOCK_TO_PICKUPS = { Notes = "Called when a block has been dug and is being converted to pickups. The server has provided the default pickups and the plugins may modify them." }, HOOK_BLOCK_TO_PICKUPS = { Notes = "Called when a block has been dug and is being converted to pickups. The server has provided the default pickups and the plugins may modify them." },
HOOK_CHAT = { Notes = "Called when a client sends a chat message that is not a command. The plugin may modify the chat message" }, HOOK_CHAT = { Notes = "Called when a client sends a chat message that is not a command. The plugin may modify the chat message" },

View File

@ -257,18 +257,17 @@ bool cPluginManager::CallHookBlockToPickups(
bool cPluginManager::CallHookChat(cPlayer * a_Player, AString & a_Message) bool cPluginManager::CallHookChat(cPlayer * a_Player, AString & a_Message)
{ {
bool WasCommandForbidden = false; switch (HandleCommand(a_Player, a_Message, true))
if (HandleCommand(a_Player, a_Message, true, WasCommandForbidden)) // We use HandleCommand as opposed to ExecuteCommand to accomodate the need to the WasCommandForbidden bool
{ {
return true; // Chat message was handled as command case crExecuted: return true;
} case crError: a_Player->SendMessageFailure(Printf("Something went wrong while executing command \"%s\"", a_Message.c_str())); return true;
else if (WasCommandForbidden) // Couldn't be handled as command, was it because of insufficient permissions? case crBlocked: return true; // The plugin that blocked the command probably wants to send a message to the player.
{ case crNoPermission: a_Player->SendMessageFailure(Printf("Forbidden command; insufficient privileges: \"%s\"", a_Message.c_str())); return true;
return true; // Yes - message was sent in HandleCommand, abort case crUnknownCommand: break;
} }
// Check if it was a standard command (starts with a slash) // Check if it was a standard command (starts with a slash)
// If it was, we know that it was completely unrecognised (WasCommandForbidden == false) // If it was, we know that it was completely unrecognised
if (!a_Message.empty() && (a_Message[0] == '/')) if (!a_Message.empty() && (a_Message[0] == '/'))
{ {
AStringVector Split(StringSplit(a_Message, " ")); AStringVector Split(StringSplit(a_Message, " "));
@ -1337,28 +1336,28 @@ bool cPluginManager::CallHookWorldTick(cWorld & a_World, float a_Dt, int a_LastT
bool cPluginManager::HandleCommand(cPlayer * a_Player, const AString & a_Command, bool a_ShouldCheckPermissions, bool & a_WasCommandForbidden) cPluginManager::CommandResult cPluginManager::HandleCommand(cPlayer * a_Player, const AString & a_Command, bool a_ShouldCheckPermissions)
{ {
ASSERT(a_Player != NULL); ASSERT(a_Player != NULL);
AStringVector Split(StringSplit(a_Command, " ")); AStringVector Split(StringSplit(a_Command, " "));
if (Split.empty()) if (Split.empty())
{ {
return false; return crUnknownCommand;
} }
CommandMap::iterator cmd = m_Commands.find(Split[0]); CommandMap::iterator cmd = m_Commands.find(Split[0]);
if (cmd == m_Commands.end()) if (cmd == m_Commands.end())
{ {
// Command not found // Command not found
return false; return crUnknownCommand;
} }
// Ask plugins first if a command is okay to execute the command: // Ask plugins first if a command is okay to execute the command:
if (CallHookExecuteCommand(a_Player, Split)) if (CallHookExecuteCommand(a_Player, Split))
{ {
LOGINFO("Player %s tried executing command \"%s\" that was stopped by the HOOK_EXECUTE_COMMAND hook", a_Player->GetName().c_str(), Split[0].c_str()); LOGINFO("Player %s tried executing command \"%s\" that was stopped by the HOOK_EXECUTE_COMMAND hook", a_Player->GetName().c_str(), Split[0].c_str());
return false; return crBlocked;
} }
if ( if (
@ -1367,15 +1366,18 @@ bool cPluginManager::HandleCommand(cPlayer * a_Player, const AString & a_Command
!a_Player->HasPermission(cmd->second.m_Permission) !a_Player->HasPermission(cmd->second.m_Permission)
) )
{ {
a_Player->SendMessageFailure(Printf("Forbidden command; insufficient privileges: \"%s\"", Split[0].c_str()));
LOGINFO("Player %s tried to execute forbidden command: \"%s\"", a_Player->GetName().c_str(), Split[0].c_str()); LOGINFO("Player %s tried to execute forbidden command: \"%s\"", a_Player->GetName().c_str(), Split[0].c_str());
a_WasCommandForbidden = true; return crNoPermission;
return false;
} }
ASSERT(cmd->second.m_Plugin != NULL); ASSERT(cmd->second.m_Plugin != NULL);
return cmd->second.m_Plugin->HandleCommand(Split, a_Player); if (!cmd->second.m_Plugin->HandleCommand(Split, a_Player))
{
return crError;
}
return crExecuted;
} }
@ -1573,7 +1575,7 @@ AString cPluginManager::GetCommandPermission(const AString & a_Command)
bool cPluginManager::ExecuteCommand(cPlayer * a_Player, const AString & a_Command) cPluginManager::CommandResult cPluginManager::ExecuteCommand(cPlayer * a_Player, const AString & a_Command)
{ {
return HandleCommand(a_Player, a_Command, true); return HandleCommand(a_Player, a_Command, true);
} }
@ -1582,7 +1584,7 @@ bool cPluginManager::ExecuteCommand(cPlayer * a_Player, const AString & a_Comman
bool cPluginManager::ForceExecuteCommand(cPlayer * a_Player, const AString & a_Command) cPluginManager::CommandResult cPluginManager::ForceExecuteCommand(cPlayer * a_Player, const AString & a_Command)
{ {
return HandleCommand(a_Player, a_Command, false); return HandleCommand(a_Player, a_Command, false);
} }

View File

@ -57,8 +57,17 @@ public: // tolua_export
// Called each tick // Called each tick
virtual void Tick(float a_Dt); virtual void Tick(float a_Dt);
// tolua_begin // tolua_begin
enum CommandResult
{
crExecuted,
crUnknownCommand,
crError,
crBlocked,
crNoPermission,
} ;
enum PluginHook enum PluginHook
{ {
HOOK_BLOCK_SPREAD, HOOK_BLOCK_SPREAD,
@ -246,11 +255,11 @@ public: // tolua_export
/** Returns the permission needed for the specified command; empty string if command not found */ /** Returns the permission needed for the specified command; empty string if command not found */
AString GetCommandPermission(const AString & a_Command); // tolua_export AString GetCommandPermission(const AString & a_Command); // tolua_export
/** Executes the command, as if it was requested by a_Player. Checks permissions first. Returns true if executed. */ /** Executes the command, as if it was requested by a_Player. Checks permissions first. Returns crExecuted if executed. */
bool ExecuteCommand(cPlayer * a_Player, const AString & a_Command); // tolua_export CommandResult ExecuteCommand(cPlayer * a_Player, const AString & a_Command); // tolua_export
/** Executes the command, as if it was requested by a_Player. Permisssions are not checked. Returns true if executed (false if not found) */ /** Executes the command, as if it was requested by a_Player. Permisssions are not checked. Returns crExecuted if executed. */
bool ForceExecuteCommand(cPlayer * a_Player, const AString & a_Command); // tolua_export CommandResult ForceExecuteCommand(cPlayer * a_Player, const AString & a_Command); // tolua_export
/** Removes all console command bindings that the specified plugin has made */ /** Removes all console command bindings that the specified plugin has made */
void RemovePluginConsoleCommands(cPlugin * a_Plugin); void RemovePluginConsoleCommands(cPlugin * a_Plugin);
@ -323,13 +332,8 @@ private:
/** Adds the plugin into the internal list of plugins and initializes it. If initialization fails, the plugin is removed again. */ /** Adds the plugin into the internal list of plugins and initializes it. If initialization fails, the plugin is removed again. */
bool AddPlugin(cPlugin * a_Plugin); bool AddPlugin(cPlugin * a_Plugin);
/** Tries to match a_Command to the internal table of commands, if a match is found, the corresponding plugin is called. Returns true if the command is handled. */ /** Tries to match a_Command to the internal table of commands, if a match is found, the corresponding plugin is called. Returns crExecuted if the command is executed. */
bool HandleCommand(cPlayer * a_Player, const AString & a_Command, bool a_ShouldCheckPermissions, bool & a_WasCommandForbidden); cPluginManager::CommandResult HandleCommand(cPlayer * a_Player, const AString & a_Command, bool a_ShouldCheckPermissions);
bool HandleCommand(cPlayer * a_Player, const AString & a_Command, bool a_ShouldCheckPermissions)
{
bool DummyBoolean = false;
return HandleCommand(a_Player, a_Command, a_ShouldCheckPermissions, DummyBoolean);
}
} ; // tolua_export } ; // tolua_export