1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/core/CConCmdManager.cpp Thu Feb 15 22:17:01 2007 +0000
1.3 @@ -0,0 +1,269 @@
1.4 +#include "CConCmdManager.h"
1.5 +#include "sm_srvcmds.h"
1.6 +
1.7 +CConCmdManager g_ConCmds;
1.8 +
1.9 +SH_DECL_HOOK0_void(ConCommand, Dispatch, SH_NOATTRIB, false);
1.10 +SH_DECL_HOOK1_void(IServerGameClients, SetCommandClient, SH_NOATTRIB, false, int);
1.11 +
1.12 +struct PlCmdInfo
1.13 +{
1.14 + ConCmdInfo *pInfo;
1.15 + CmdType type;
1.16 +};
1.17 +
1.18 +typedef List<PlCmdInfo> CmdList;
1.19 +
1.20 +char *sm_strdup(const char *str)
1.21 +{
1.22 + char *ptr = new char[strlen(str)+1];
1.23 + strcpy(ptr, str);
1.24 + return ptr;
1.25 +}
1.26 +
1.27 +CConCmdManager::CConCmdManager()
1.28 +{
1.29 + m_pCmds = sm_trie_create();
1.30 +}
1.31 +
1.32 +CConCmdManager::~CConCmdManager()
1.33 +{
1.34 + sm_trie_destroy(m_pCmds);
1.35 +}
1.36 +
1.37 +void CConCmdManager::OnSourceModAllInitialized()
1.38 +{
1.39 + g_PluginSys.AddPluginsListener(this);
1.40 + g_RootMenu.AddRootConsoleCommand("cmds", "List console commands", this);
1.41 + SH_ADD_HOOK_MEMFUNC(IServerGameClients, SetCommandClient, serverClients, this, &CConCmdManager::SetCommandClient, false);
1.42 +}
1.43 +
1.44 +void CConCmdManager::OnSourceModShutdown()
1.45 +{
1.46 + SH_REMOVE_HOOK_MEMFUNC(IServerGameClients, SetCommandClient, serverClients, this, &CConCmdManager::SetCommandClient, false);
1.47 + g_RootMenu.RemoveRootConsoleCommand("cmds", this);
1.48 + g_PluginSys.RemovePluginsListener(this);
1.49 +}
1.50 +
1.51 +void CConCmdManager::OnPluginLoaded(IPlugin *plugin)
1.52 +{
1.53 + /* Nothing yet... */
1.54 +}
1.55 +
1.56 +void CConCmdManager::OnPluginDestroyed(IPlugin *plugin)
1.57 +{
1.58 + CmdList *pList;
1.59 + if (plugin->GetProperty("CommandList", (void **)&pList, true))
1.60 + {
1.61 + CmdList::iterator iter;
1.62 + for (iter=pList->begin();
1.63 + iter!=pList->end();
1.64 + iter++)
1.65 + {
1.66 + PlCmdInfo &cmd = (*iter);
1.67 + if (cmd.type == Cmd_Server
1.68 + || cmd.type == Cmd_Console)
1.69 + {
1.70 + ConCmdInfo *pInfo = cmd.pInfo;
1.71 + /* See if there are still hooks */
1.72 + if (pInfo->srvhooks
1.73 + && pInfo->srvhooks->GetFunctionCount())
1.74 + {
1.75 + continue;
1.76 + }
1.77 + /* Remove the command */
1.78 + RemoveConCmd(pInfo);
1.79 + }
1.80 + }
1.81 + delete pList;
1.82 + }
1.83 +}
1.84 +
1.85 +void CommandCallback()
1.86 +{
1.87 + g_ConCmds.InternalDispatch();
1.88 +}
1.89 +
1.90 +void CConCmdManager::SetCommandClient(int client)
1.91 +{
1.92 + m_CmdClient = client + 1;
1.93 +}
1.94 +
1.95 +void CConCmdManager::InternalDispatch()
1.96 +{
1.97 + if (m_CmdClient)
1.98 + {
1.99 + return;
1.100 + }
1.101 +
1.102 + const char *cmd = engine->Cmd_Argv(0);
1.103 + ConCmdInfo *pInfo;
1.104 + if (!sm_trie_retrieve(m_pCmds, cmd, (void **)&pInfo))
1.105 + {
1.106 + return;
1.107 + }
1.108 +
1.109 + cell_t result = Pl_Continue;
1.110 + if (pInfo->srvhooks)
1.111 + {
1.112 + pInfo->srvhooks->Execute(&result);
1.113 + }
1.114 +
1.115 + if (result >= Pl_Handled)
1.116 + {
1.117 + if (!pInfo->sourceMod)
1.118 + {
1.119 + RETURN_META(MRES_SUPERCEDE);
1.120 + }
1.121 + return;
1.122 + }
1.123 +}
1.124 +
1.125 +void CConCmdManager::AddServerCommand(IPluginFunction *pFunction,
1.126 + const char *name,
1.127 + const char *description,
1.128 + int flags)
1.129 +
1.130 +{
1.131 + ConCmdInfo *pInfo = AddOrFindCommand(name, description, flags);
1.132 +
1.133 + if (!pInfo->srvhooks)
1.134 + {
1.135 + pInfo->srvhooks = g_Forwards.CreateForwardEx(NULL, ET_Hook, 1, NULL, Param_Cell);
1.136 + }
1.137 +
1.138 + pInfo->srvhooks->AddFunction(pFunction);
1.139 +
1.140 + /* Add to the plugin */
1.141 + CmdList *pList;
1.142 + IPlugin *pPlugin = g_PluginSys.GetPluginByCtx(pFunction->GetParentContext()->GetContext());
1.143 + if (!pPlugin->GetProperty("CommandList", (void **)&pList))
1.144 + {
1.145 + pList = new CmdList();
1.146 + pPlugin->SetProperty("CommandList", pList);
1.147 + }
1.148 + PlCmdInfo info;
1.149 + info.pInfo = pInfo;
1.150 + info.type = Cmd_Console;
1.151 + pList->push_back(info);
1.152 +}
1.153 +
1.154 +void CConCmdManager::AddToCmdList(ConCmdInfo *info)
1.155 +{
1.156 + List<ConCmdInfo *>::iterator iter = m_CmdList.begin();
1.157 + ConCmdInfo *pInfo;
1.158 + bool inserted = false;
1.159 + const char *orig;
1.160 +
1.161 + if (info->pCmd)
1.162 + {
1.163 + orig = info->pCmd->GetName();
1.164 + }
1.165 +
1.166 + /* Insert this into the help list, SORTED alphabetically. */
1.167 + while (iter != m_CmdList.end())
1.168 + {
1.169 + const char *cmd = NULL;
1.170 + pInfo = (*iter);
1.171 + if (pInfo->pCmd)
1.172 + {
1.173 + cmd = pInfo->pCmd->GetName();
1.174 + }
1.175 + if (strcmp(orig, cmd) < 0)
1.176 + {
1.177 + m_CmdList.insert(iter, info);
1.178 + inserted = true;
1.179 + break;
1.180 + }
1.181 + iter++;
1.182 + }
1.183 +
1.184 + if (!inserted)
1.185 + {
1.186 + m_CmdList.push_back(info);
1.187 + }
1.188 +}
1.189 +
1.190 +void CConCmdManager::RemoveConCmd(ConCmdInfo *info)
1.191 +{
1.192 + /* Remove console-specific information */
1.193 + if (info->pCmd)
1.194 + {
1.195 + /* Remove from the trie */
1.196 + sm_trie_delete(m_pCmds, info->pCmd->GetName());
1.197 +
1.198 + if (info->sourceMod)
1.199 + {
1.200 + /* Unlink from SourceMM */
1.201 + g_SMAPI->UnregisterConCmdBase(g_PLAPI, info->pCmd);
1.202 + /* Delete the command's memory */
1.203 + char *new_help = const_cast<char *>(info->pCmd->GetHelpText());
1.204 + char *new_name = const_cast<char *>(info->pCmd->GetName());
1.205 + delete [] new_help;
1.206 + delete [] new_name;
1.207 + delete info->pCmd;
1.208 + } else {
1.209 + /* Remove the external hook */
1.210 + SH_REMOVE_HOOK_STATICFUNC(ConCommand, Dispatch, info->pCmd, CommandCallback, false);
1.211 + }
1.212 + }
1.213 +
1.214 + /* Remove from list */
1.215 + m_CmdList.remove(info);
1.216 +
1.217 + /* Free forwards */
1.218 + if (info->srvhooks)
1.219 + {
1.220 + g_Forwards.ReleaseForward(info->srvhooks);
1.221 + }
1.222 +}
1.223 +
1.224 +ConCmdInfo *CConCmdManager::AddOrFindCommand(const char *name, const char *description, int flags)
1.225 +{
1.226 + ConCmdInfo *pInfo;
1.227 + if (!sm_trie_retrieve(m_pCmds, name, (void **)&pInfo))
1.228 + {
1.229 + pInfo = new ConCmdInfo();
1.230 + /* Find the commandopan */
1.231 + ConCommandBase *pBase = icvar->GetCommands();
1.232 + ConCommand *pCmd = NULL;
1.233 + while (pBase)
1.234 + {
1.235 + if (pBase->IsCommand()
1.236 + && (strcmp(pBase->GetName(), name) == 0))
1.237 + {
1.238 + pCmd = (ConCommand *)pBase;
1.239 + break;
1.240 + }
1.241 + pBase = const_cast<ConCommandBase *>(pBase->GetNext());
1.242 + }
1.243 +
1.244 + if (!pCmd)
1.245 + {
1.246 + /* Note that we have to duplicate because the source might not be
1.247 + * a static string, and these expect static memory.
1.248 + */
1.249 + if (!description)
1.250 + {
1.251 + description = "";
1.252 + }
1.253 + char *new_name = sm_strdup(name);
1.254 + char *new_help = sm_strdup(description);
1.255 + pCmd = new ConCommand(new_name, CommandCallback, new_help, flags);
1.256 + pInfo->sourceMod = true;
1.257 + } else {
1.258 + SH_ADD_HOOK_STATICFUNC(ConCommand, Dispatch, pCmd, CommandCallback, false);
1.259 + }
1.260 +
1.261 + pInfo->pCmd = pCmd;
1.262 +
1.263 + sm_trie_insert(m_pCmds, name, pInfo);
1.264 + AddToCmdList(pInfo);
1.265 + }
1.266 +
1.267 + return pInfo;
1.268 +}
1.269 +
1.270 +void CConCmdManager::OnRootConsoleCommand(const char *command, unsigned int argcount)
1.271 +{
1.272 +}