1.1 --- a/core/ConCmdManager.cpp Fri Mar 28 06:21:34 2008 +0000
1.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
1.3 @@ -1,1117 +0,0 @@
1.4 -/**
1.5 - * vim: set ts=4 :
1.6 - * =============================================================================
1.7 - * SourceMod
1.8 - * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
1.9 - * =============================================================================
1.10 - *
1.11 - * This program is free software; you can redistribute it and/or modify it under
1.12 - * the terms of the GNU General Public License, version 3.0, as published by the
1.13 - * Free Software Foundation.
1.14 - *
1.15 - * This program is distributed in the hope that it will be useful, but WITHOUT
1.16 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
1.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
1.18 - * details.
1.19 - *
1.20 - * You should have received a copy of the GNU General Public License along with
1.21 - * this program. If not, see <http://www.gnu.org/licenses/>.
1.22 - *
1.23 - * As a special exception, AlliedModders LLC gives you permission to link the
1.24 - * code of this program (as well as its derivative works) to "Half-Life 2," the
1.25 - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
1.26 - * by the Valve Corporation. You must obey the GNU General Public License in
1.27 - * all respects for all other code used. Additionally, AlliedModders LLC grants
1.28 - * this exception to all derivative works. AlliedModders LLC defines further
1.29 - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
1.30 - * or <http://www.sourcemod.net/license.php>.
1.31 - *
1.32 - * Version: $Id$
1.33 - */
1.34 -
1.35 -#include "ConCmdManager.h"
1.36 -#include "sm_srvcmds.h"
1.37 -#include "AdminCache.h"
1.38 -#include "sm_stringutil.h"
1.39 -#include "PlayerManager.h"
1.40 -#include "Translator.h"
1.41 -#include "HalfLife2.h"
1.42 -#include "ChatTriggers.h"
1.43 -
1.44 -ConCmdManager g_ConCmds;
1.45 -
1.46 -#if defined ORANGEBOX_BUILD
1.47 - SH_DECL_HOOK1_void(ConCommand, Dispatch, SH_NOATTRIB, false, const CCommand &);
1.48 -#else
1.49 - SH_DECL_HOOK0_void(ConCommand, Dispatch, SH_NOATTRIB, false);
1.50 -#endif
1.51 -
1.52 -SH_DECL_HOOK1_void(IServerGameClients, SetCommandClient, SH_NOATTRIB, false, int);
1.53 -
1.54 -struct PlCmdInfo
1.55 -{
1.56 - ConCmdInfo *pInfo;
1.57 - CmdHook *pHook;
1.58 - CmdType type;
1.59 -};
1.60 -typedef List<PlCmdInfo> CmdList;
1.61 -
1.62 -void AddToPlCmdList(CmdList *pList, const PlCmdInfo &info);
1.63 -
1.64 -ConCmdManager::ConCmdManager() : m_Strings(1024)
1.65 -{
1.66 - m_pCmds = sm_trie_create();
1.67 - m_pCmdGrps = sm_trie_create();
1.68 - m_CmdClient = 0;
1.69 -}
1.70 -
1.71 -ConCmdManager::~ConCmdManager()
1.72 -{
1.73 - sm_trie_destroy(m_pCmds);
1.74 - sm_trie_destroy(m_pCmdGrps);
1.75 -}
1.76 -
1.77 -void ConCmdManager::OnSourceModAllInitialized()
1.78 -{
1.79 - g_PluginSys.AddPluginsListener(this);
1.80 - g_RootMenu.AddRootConsoleCommand("cmds", "List console commands", this);
1.81 - SH_ADD_HOOK_MEMFUNC(IServerGameClients, SetCommandClient, serverClients, this, &ConCmdManager::SetCommandClient, false);
1.82 -}
1.83 -
1.84 -void ConCmdManager::OnSourceModShutdown()
1.85 -{
1.86 - /* All commands should already be removed by the time we're done */
1.87 - SH_REMOVE_HOOK_MEMFUNC(IServerGameClients, SetCommandClient, serverClients, this, &ConCmdManager::SetCommandClient, false);
1.88 - g_RootMenu.RemoveRootConsoleCommand("cmds", this);
1.89 -}
1.90 -
1.91 -void ConCmdManager::OnUnlinkConCommandBase(ConCommandBase *pBase, const char *name, bool is_read_safe)
1.92 -{
1.93 - /* Whoa, first get its information struct */
1.94 - ConCmdInfo *pInfo;
1.95 -
1.96 - if (!sm_trie_retrieve(m_pCmds, name, (void **)&pInfo))
1.97 - {
1.98 - return;
1.99 - }
1.100 -
1.101 - RemoveConCmds(pInfo->srvhooks);
1.102 - RemoveConCmds(pInfo->conhooks);
1.103 -
1.104 - RemoveConCmd(pInfo, name, is_read_safe, false);
1.105 -}
1.106 -
1.107 -void ConCmdManager::RemoveConCmds(List<CmdHook *> &cmdlist)
1.108 -{
1.109 - List<CmdHook *>::iterator iter = cmdlist.begin();
1.110 -
1.111 - while (iter != cmdlist.end())
1.112 - {
1.113 - CmdHook *pHook = (*iter);
1.114 - IPluginContext *pContext = pHook->pf->GetParentContext();
1.115 - IPlugin *pPlugin = g_PluginSys.GetPluginByCtx(pContext->GetContext());
1.116 - CmdList *pList = NULL;
1.117 -
1.118 - //gaben
1.119 - if (!pPlugin->GetProperty("CommandList", (void **)&pList, false) || !pList)
1.120 - {
1.121 - continue;
1.122 - }
1.123 -
1.124 - CmdList::iterator p_iter = pList->begin();
1.125 - while (p_iter != pList->end())
1.126 - {
1.127 - PlCmdInfo &cmd = (*p_iter);
1.128 - if (cmd.pHook == pHook)
1.129 - {
1.130 - p_iter = pList->erase(p_iter);
1.131 - }
1.132 - else
1.133 - {
1.134 - p_iter++;
1.135 - }
1.136 - }
1.137 -
1.138 - delete pHook->pAdmin;
1.139 - delete pHook;
1.140 -
1.141 - iter = cmdlist.erase(iter);
1.142 - }
1.143 -}
1.144 -
1.145 -void ConCmdManager::RemoveConCmds(List<CmdHook *> &cmdlist, IPluginContext *pContext)
1.146 -{
1.147 - List<CmdHook *>::iterator iter = cmdlist.begin();
1.148 - CmdHook *pHook;
1.149 -
1.150 - while (iter != cmdlist.end())
1.151 - {
1.152 - pHook = (*iter);
1.153 - if (pHook->pf->GetParentContext() == pContext)
1.154 - {
1.155 - delete pHook->pAdmin;
1.156 - delete pHook;
1.157 - iter = cmdlist.erase(iter);
1.158 - }
1.159 - else
1.160 - {
1.161 - iter++;
1.162 - }
1.163 - }
1.164 -}
1.165 -
1.166 -void ConCmdManager::OnPluginDestroyed(IPlugin *plugin)
1.167 -{
1.168 - CmdList *pList;
1.169 - List<ConCmdInfo *> removed;
1.170 - if (plugin->GetProperty("CommandList", (void **)&pList, true))
1.171 - {
1.172 - IPluginContext *pContext = plugin->GetBaseContext();
1.173 - CmdList::iterator iter;
1.174 - /* First pass!
1.175 - * Only bother if there's an actual command list on this plugin...
1.176 - */
1.177 - for (iter=pList->begin();
1.178 - iter!=pList->end();
1.179 - iter++)
1.180 - {
1.181 - PlCmdInfo &cmd = (*iter);
1.182 - ConCmdInfo *pInfo = cmd.pInfo;
1.183 -
1.184 - /* Has this chain already been fully cleaned/removed? */
1.185 - if (removed.find(pInfo) != removed.end())
1.186 - {
1.187 - continue;
1.188 - }
1.189 -
1.190 - /* Remove any hooks from us on this command */
1.191 - RemoveConCmds(pInfo->conhooks, pContext);
1.192 - RemoveConCmds(pInfo->srvhooks, pContext);
1.193 -
1.194 - /* See if there are still hooks */
1.195 - if (pInfo->srvhooks.size())
1.196 - {
1.197 - continue;
1.198 - }
1.199 - if (pInfo->conhooks.size())
1.200 - {
1.201 - continue;
1.202 - }
1.203 -
1.204 - /* Remove the command, it should be safe now */
1.205 - RemoveConCmd(pInfo, pInfo->pCmd->GetName(), true, true);
1.206 - removed.push_back(pInfo);
1.207 - }
1.208 - delete pList;
1.209 - }
1.210 -}
1.211 -#if defined ORANGEBOX_BUILD
1.212 -void CommandCallback(const CCommand &command)
1.213 -{
1.214 -#else
1.215 -void CommandCallback()
1.216 -{
1.217 - CCommand command;
1.218 -#endif
1.219 -
1.220 - g_HL2.PushCommandStack(&command);
1.221 -
1.222 - g_ConCmds.InternalDispatch(command);
1.223 -
1.224 - g_HL2.PopCommandStack();
1.225 -}
1.226 -
1.227 -void ConCmdManager::SetCommandClient(int client)
1.228 -{
1.229 - m_CmdClient = client + 1;
1.230 -}
1.231 -
1.232 -ResultType ConCmdManager::DispatchClientCommand(int client, const char *cmd, int args, ResultType type)
1.233 -{
1.234 - ConCmdInfo *pInfo;
1.235 - if (sm_trie_retrieve(m_pCmds, cmd, (void **)&pInfo))
1.236 - {
1.237 - cell_t result = type;
1.238 - cell_t tempres = result;
1.239 - List<CmdHook *>::iterator iter;
1.240 - CmdHook *pHook;
1.241 - for (iter=pInfo->conhooks.begin();
1.242 - iter!=pInfo->conhooks.end();
1.243 - iter++)
1.244 - {
1.245 - pHook = (*iter);
1.246 - if (!pHook->pf->IsRunnable())
1.247 - {
1.248 - continue;
1.249 - }
1.250 - if (pHook->pAdmin && !CheckAccess(client, cmd, pHook->pAdmin))
1.251 - {
1.252 - if (result < Pl_Handled)
1.253 - {
1.254 - result = Pl_Handled;
1.255 - }
1.256 - continue;
1.257 - }
1.258 - pHook->pf->PushCell(client);
1.259 - pHook->pf->PushCell(args);
1.260 - if (pHook->pf->Execute(&tempres) == SP_ERROR_NONE)
1.261 - {
1.262 - if (tempres > result)
1.263 - {
1.264 - result = tempres;
1.265 - }
1.266 - if (result == Pl_Stop)
1.267 - {
1.268 - break;
1.269 - }
1.270 - }
1.271 - }
1.272 - type = (ResultType)result;
1.273 - }
1.274 -
1.275 - return type;
1.276 -}
1.277 -
1.278 -void ConCmdManager::InternalDispatch(const CCommand &command)
1.279 -{
1.280 - int client = m_CmdClient;
1.281 -
1.282 - if (client)
1.283 - {
1.284 - CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
1.285 - if (!pPlayer || !pPlayer->IsConnected())
1.286 - {
1.287 - return;
1.288 - }
1.289 - }
1.290 -
1.291 - /**
1.292 - * Note: Console commands will EITHER go through IServerGameDLL::ClientCommand,
1.293 - * OR this dispatch. They will NEVER go through both.
1.294 - * --
1.295 - * Whether or not it goes through the callback is determined by FCVAR_GAMEDLL
1.296 - */
1.297 - const char *cmd = g_HL2.CurrentCommandName();
1.298 -
1.299 - ConCmdInfo *pInfo;
1.300 - if (!sm_trie_retrieve(m_pCmds, cmd, (void **)&pInfo))
1.301 - {
1.302 - return;
1.303 - }
1.304 -
1.305 - cell_t result = Pl_Continue;
1.306 - int args = command.ArgC() - 1;
1.307 -
1.308 - List<CmdHook *>::iterator iter;
1.309 - CmdHook *pHook;
1.310 -
1.311 - /* Execute server-only commands if viable */
1.312 - if (client == 0 && pInfo->srvhooks.size())
1.313 - {
1.314 - cell_t tempres = result;
1.315 - for (iter=pInfo->srvhooks.begin();
1.316 - iter!=pInfo->srvhooks.end();
1.317 - iter++)
1.318 - {
1.319 - pHook = (*iter);
1.320 - if (!pHook->pf->IsRunnable())
1.321 - {
1.322 - continue;
1.323 - }
1.324 - pHook->pf->PushCell(args);
1.325 - if (pHook->pf->Execute(&tempres) == SP_ERROR_NONE)
1.326 - {
1.327 - if (tempres > result)
1.328 - {
1.329 - result = tempres;
1.330 - }
1.331 - if (result == Pl_Stop)
1.332 - {
1.333 - break;
1.334 - }
1.335 - }
1.336 - }
1.337 -
1.338 - /* Check if there's an early stop */
1.339 - if (result >= Pl_Stop)
1.340 - {
1.341 - if (!pInfo->sourceMod)
1.342 - {
1.343 - RETURN_META(MRES_SUPERCEDE);
1.344 - }
1.345 - return;
1.346 - }
1.347 - }
1.348 -
1.349 - /* Execute console commands */
1.350 - if (pInfo->conhooks.size())
1.351 - {
1.352 - cell_t tempres = result;
1.353 - for (iter=pInfo->conhooks.begin();
1.354 - iter!=pInfo->conhooks.end();
1.355 - iter++)
1.356 - {
1.357 - pHook = (*iter);
1.358 - if (!pHook->pf->IsRunnable())
1.359 - {
1.360 - continue;
1.361 - }
1.362 - if (client
1.363 - && pHook->pAdmin
1.364 - && !CheckAccess(client, cmd, pHook->pAdmin))
1.365 - {
1.366 - if (result < Pl_Handled)
1.367 - {
1.368 - result = Pl_Handled;
1.369 - }
1.370 - continue;
1.371 - }
1.372 -
1.373 - /* On a listen server, sometimes the server host's client index can be set as 0.
1.374 - * So index 1 is passed to the command callback to correct this potential problem.
1.375 - */
1.376 - if (client == 0 && !engine->IsDedicatedServer())
1.377 - {
1.378 - pHook->pf->PushCell(1);
1.379 - } else {
1.380 - pHook->pf->PushCell(client);
1.381 - }
1.382 -
1.383 - pHook->pf->PushCell(args);
1.384 - if (pHook->pf->Execute(&tempres) == SP_ERROR_NONE)
1.385 - {
1.386 - if (tempres > result)
1.387 - {
1.388 - result = tempres;
1.389 - }
1.390 - if (result == Pl_Stop)
1.391 - {
1.392 - break;
1.393 - }
1.394 - }
1.395 - }
1.396 - }
1.397 -
1.398 - if (result >= Pl_Handled)
1.399 - {
1.400 - if (!pInfo->sourceMod)
1.401 - {
1.402 - RETURN_META(MRES_SUPERCEDE);
1.403 - }
1.404 - return;
1.405 - }
1.406 -}
1.407 -
1.408 -bool ConCmdManager::CheckCommandAccess(int client, const char *cmd, FlagBits cmdflags)
1.409 -{
1.410 - if (cmdflags == 0 || client == 0)
1.411 - {
1.412 - return true;
1.413 - }
1.414 -
1.415 - /* If running listen server, then client 1 is the server host and should have 'root' access */
1.416 - if (client == 1 && !engine->IsDedicatedServer())
1.417 - {
1.418 - return true;
1.419 - }
1.420 -
1.421 - CPlayer *player = g_Players.GetPlayerByIndex(client);
1.422 - if (!player
1.423 - || player->GetEdict() == NULL
1.424 - || player->IsFakeClient())
1.425 - {
1.426 - return false;
1.427 - }
1.428 -
1.429 - AdminId adm = player->GetAdminId();
1.430 - if (adm != INVALID_ADMIN_ID)
1.431 - {
1.432 - FlagBits bits = g_Admins.GetAdminFlags(adm, Access_Effective);
1.433 -
1.434 - /* root knows all, WHOA */
1.435 - if ((bits & ADMFLAG_ROOT) == ADMFLAG_ROOT)
1.436 - {
1.437 - return true;
1.438 - }
1.439 -
1.440 - /* Check for overrides
1.441 - * :TODO: is it worth optimizing this?
1.442 - */
1.443 - unsigned int groups = g_Admins.GetAdminGroupCount(adm);
1.444 - GroupId gid;
1.445 - OverrideRule rule;
1.446 - bool override = false;
1.447 - for (unsigned int i=0; i<groups; i++)
1.448 - {
1.449 - gid = g_Admins.GetAdminGroup(adm, i, NULL);
1.450 - /* First get group-level override */
1.451 - override = g_Admins.GetGroupCommandOverride(gid, cmd, Override_CommandGroup, &rule);
1.452 - /* Now get the specific command override */
1.453 - if (g_Admins.GetGroupCommandOverride(gid, cmd, Override_Command, &rule))
1.454 - {
1.455 - override = true;
1.456 - }
1.457 - if (override)
1.458 - {
1.459 - if (rule == Command_Allow)
1.460 - {
1.461 - return true;
1.462 - } else if (rule == Command_Deny) {
1.463 - return false;
1.464 - }
1.465 - }
1.466 - }
1.467 -
1.468 - /* See if our other flags match */
1.469 - if ((bits & cmdflags) == cmdflags)
1.470 - {
1.471 - return true;
1.472 - }
1.473 - }
1.474 -
1.475 - return false;
1.476 -}
1.477 -
1.478 -bool ConCmdManager::CheckAccess(int client, const char *cmd, AdminCmdInfo *pAdmin)
1.479 -{
1.480 - if (CheckCommandAccess(client, cmd, pAdmin->eflags))
1.481 - {
1.482 - return true;
1.483 - }
1.484 -
1.485 - edict_t *pEdict = engine->PEntityOfEntIndex(client);
1.486 -
1.487 - /* If we got here, the command failed... */
1.488 - char buffer[128];
1.489 - if (g_Translator.CoreTrans(client, buffer, sizeof(buffer), "No Access", NULL, NULL)
1.490 - != Trans_Okay)
1.491 - {
1.492 - snprintf(buffer, sizeof(buffer), "You do not have access to this command");
1.493 - }
1.494 -
1.495 - unsigned int replyto = g_ChatTriggers.GetReplyTo();
1.496 - if (replyto == SM_REPLY_CONSOLE)
1.497 - {
1.498 - char fullbuffer[192];
1.499 - snprintf(fullbuffer, sizeof(fullbuffer), "[SM] %s.\n", buffer);
1.500 - engine->ClientPrintf(pEdict, fullbuffer);
1.501 - } else if (replyto == SM_REPLY_CHAT) {
1.502 - char fullbuffer[192];
1.503 - snprintf(fullbuffer, sizeof(fullbuffer), "[SM] %s.", buffer);
1.504 - g_HL2.TextMsg(client, HUD_PRINTTALK, fullbuffer);
1.505 - }
1.506 -
1.507 - return false;
1.508 -}
1.509 -
1.510 -bool ConCmdManager::AddConsoleCommand(IPluginFunction *pFunction,
1.511 - const char *name,
1.512 - const char *description,
1.513 - int flags)
1.514 -{
1.515 - ConCmdInfo *pInfo = AddOrFindCommand(name, description, flags);
1.516 -
1.517 - if (!pInfo)
1.518 - {
1.519 - return false;
1.520 - }
1.521 -
1.522 - CmdHook *pHook = new CmdHook();
1.523 -
1.524 - pHook->pf = pFunction;
1.525 - if (description && description[0])
1.526 - {
1.527 - pHook->helptext.assign(description);
1.528 - }
1.529 - pInfo->conhooks.push_back(pHook);
1.530 -
1.531 - /* Add to the plugin */
1.532 - CmdList *pList;
1.533 - IPlugin *pPlugin = g_PluginSys.GetPluginByCtx(pFunction->GetParentContext()->GetContext());
1.534 - if (!pPlugin->GetProperty("CommandList", (void **)&pList))
1.535 - {
1.536 - pList = new CmdList();
1.537 - pPlugin->SetProperty("CommandList", pList);
1.538 - }
1.539 - PlCmdInfo info;
1.540 - info.pInfo = pInfo;
1.541 - info.type = Cmd_Console;
1.542 - info.pHook = pHook;
1.543 - AddToPlCmdList(pList, info);
1.544 -
1.545 - return true;
1.546 -}
1.547 -
1.548 -bool ConCmdManager::AddAdminCommand(IPluginFunction *pFunction,
1.549 - const char *name,
1.550 - const char *group,
1.551 - int adminflags,
1.552 - const char *description,
1.553 - int flags)
1.554 -{
1.555 - ConCmdInfo *pInfo = AddOrFindCommand(name, description, flags);
1.556 -
1.557 - if (!pInfo)
1.558 - {
1.559 - return false;
1.560 - }
1.561 -
1.562 - CmdHook *pHook = new CmdHook();
1.563 - AdminCmdInfo *pAdmin = new AdminCmdInfo();
1.564 -
1.565 - pHook->pf = pFunction;
1.566 - if (description && description[0])
1.567 - {
1.568 - pHook->helptext.assign(description);
1.569 - }
1.570 - pHook->pAdmin = pAdmin;
1.571 -
1.572 - void *object;
1.573 - int grpid;
1.574 - if (!sm_trie_retrieve(m_pCmdGrps, group, (void **)&object))
1.575 - {
1.576 - grpid = m_Strings.AddString(group);
1.577 - sm_trie_insert(m_pCmdGrps, group, (void *)grpid);
1.578 - }
1.579 - else
1.580 - {
1.581 - grpid = (int)object;
1.582 - }
1.583 -
1.584 - pAdmin->cmdGrpId = grpid;
1.585 - pAdmin->flags = adminflags;
1.586 -
1.587 - /* First get the command group override, if any */
1.588 - bool override = g_Admins.GetCommandOverride(group,
1.589 - Override_CommandGroup,
1.590 - &(pAdmin->eflags));
1.591 -
1.592 - /* Next get the command override, if any */
1.593 - if (g_Admins.GetCommandOverride(name,
1.594 - Override_Command,
1.595 - &(pAdmin->eflags)))
1.596 - {
1.597 - override = true;
1.598 - }
1.599 -
1.600 - /* Assign normal flags if there were no overrides */
1.601 - if (!override)
1.602 - {
1.603 - pAdmin->eflags = pAdmin->flags;
1.604 - }
1.605 -
1.606 - /* Finally, add the hook */
1.607 - pInfo->conhooks.push_back(pHook);
1.608 - pInfo->admin = *(pHook->pAdmin);
1.609 - pInfo->is_admin_set = true;
1.610 -
1.611 - /* Now add to the plugin */
1.612 - CmdList *pList;
1.613 - IPlugin *pPlugin = g_PluginSys.GetPluginByCtx(pFunction->GetParentContext()->GetContext());
1.614 - if (!pPlugin->GetProperty("CommandList", (void **)&pList))
1.615 - {
1.616 - pList = new CmdList();
1.617 - pPlugin->SetProperty("CommandList", pList);
1.618 - }
1.619 - PlCmdInfo info;
1.620 - info.pInfo = pInfo;
1.621 - info.type = Cmd_Admin;
1.622 - info.pHook = pHook;
1.623 - AddToPlCmdList(pList, info);
1.624 -
1.625 - return true;
1.626 -}
1.627 -
1.628 -bool ConCmdManager::AddServerCommand(IPluginFunction *pFunction,
1.629 - const char *name,
1.630 - const char *description,
1.631 - int flags)
1.632 -
1.633 -{
1.634 - ConCmdInfo *pInfo = AddOrFindCommand(name, description, flags);
1.635 -
1.636 - if (!pInfo)
1.637 - {
1.638 - return false;
1.639 - }
1.640 -
1.641 - CmdHook *pHook = new CmdHook();
1.642 -
1.643 - pHook->pf = pFunction;
1.644 - if (description && description[0])
1.645 - {
1.646 - pHook->helptext.assign(description);
1.647 - }
1.648 -
1.649 - pInfo->srvhooks.push_back(pHook);
1.650 -
1.651 - /* Add to the plugin */
1.652 - CmdList *pList;
1.653 - IPlugin *pPlugin = g_PluginSys.GetPluginByCtx(pFunction->GetParentContext()->GetContext());
1.654 - if (!pPlugin->GetProperty("CommandList", (void **)&pList))
1.655 - {
1.656 - pList = new CmdList();
1.657 - pPlugin->SetProperty("CommandList", pList);
1.658 - }
1.659 - PlCmdInfo info;
1.660 - info.pInfo = pInfo;
1.661 - info.type = Cmd_Server;
1.662 - info.pHook = pHook;
1.663 - AddToPlCmdList(pList, info);
1.664 -
1.665 - return true;
1.666 -}
1.667 -
1.668 -void AddToPlCmdList(CmdList *pList, const PlCmdInfo &info)
1.669 -{
1.670 - CmdList::iterator iter = pList->begin();
1.671 - bool inserted = false;
1.672 - const char *orig = NULL;
1.673 -
1.674 - orig = info.pInfo->pCmd->GetName();
1.675 -
1.676 - /* Insert this into the help list, SORTED alphabetically. */
1.677 - while (iter != pList->end())
1.678 - {
1.679 - PlCmdInfo &obj = (*iter);
1.680 - const char *cmd = obj.pInfo->pCmd->GetName();
1.681 - if (strcmp(orig, cmd) < 0)
1.682 - {
1.683 - pList->insert(iter, info);
1.684 - inserted = true;
1.685 - break;
1.686 - }
1.687 - iter++;
1.688 - }
1.689 -
1.690 - if (!inserted)
1.691 - {
1.692 - pList->push_back(info);
1.693 - }
1.694 -}
1.695 -
1.696 -void ConCmdManager::AddToCmdList(ConCmdInfo *info)
1.697 -{
1.698 - List<ConCmdInfo *>::iterator iter = m_CmdList.begin();
1.699 - ConCmdInfo *pInfo;
1.700 - bool inserted = false;
1.701 - const char *orig = NULL;
1.702 -
1.703 - orig = info->pCmd->GetName();
1.704 -
1.705 - /* Insert this into the help list, SORTED alphabetically. */
1.706 - while (iter != m_CmdList.end())
1.707 - {
1.708 - const char *cmd = NULL;
1.709 - pInfo = (*iter);
1.710 - cmd = pInfo->pCmd->GetName();
1.711 - if (strcmp(orig, cmd) < 0)
1.712 - {
1.713 - m_CmdList.insert(iter, info);
1.714 - inserted = true;
1.715 - break;
1.716 - }
1.717 - iter++;
1.718 - }
1.719 -
1.720 - if (!inserted)
1.721 - {
1.722 - m_CmdList.push_back(info);
1.723 - }
1.724 -}
1.725 -
1.726 -void ConCmdManager::UpdateAdminCmdFlags(const char *cmd, OverrideType type, FlagBits bits, bool remove)
1.727 -{
1.728 - ConCmdInfo *pInfo;
1.729 -
1.730 - if (type == Override_Command)
1.731 - {
1.732 - if (!sm_trie_retrieve(m_pCmds, cmd, (void **)&pInfo))
1.733 - {
1.734 - return;
1.735 - }
1.736 -
1.737 - List<CmdHook *>::iterator iter;
1.738 - CmdHook *pHook;
1.739 -
1.740 - for (iter=pInfo->conhooks.begin(); iter!=pInfo->conhooks.end(); iter++)
1.741 - {
1.742 - pHook = (*iter);
1.743 - if (pHook->pAdmin)
1.744 - {
1.745 - if (!remove)
1.746 - {
1.747 - pHook->pAdmin->eflags = bits;
1.748 - } else {
1.749 - pHook->pAdmin->eflags = pHook->pAdmin->flags;
1.750 - }
1.751 - pInfo->admin = *(pHook->pAdmin);
1.752 - }
1.753 - }
1.754 - pInfo->is_admin_set = true;
1.755 - }
1.756 - else if (type == Override_CommandGroup)
1.757 - {
1.758 - void *object;
1.759 - if (!sm_trie_retrieve(m_pCmdGrps, cmd, &object))
1.760 - {
1.761 - return;
1.762 - }
1.763 - int grpid = (int)object;
1.764 -
1.765 - /* This is bad :( loop through all commands */
1.766 - List<ConCmdInfo *>::iterator iter;
1.767 - CmdHook *pHook;
1.768 - for (iter=m_CmdList.begin(); iter!=m_CmdList.end(); iter++)
1.769 - {
1.770 - pInfo = (*iter);
1.771 - for (List<CmdHook *>::iterator citer=pInfo->conhooks.begin();
1.772 - citer!=pInfo->conhooks.end();
1.773 - citer++)
1.774 - {
1.775 - pHook = (*citer);
1.776 - if (pHook->pAdmin && pHook->pAdmin->cmdGrpId == grpid)
1.777 - {
1.778 - if (remove)
1.779 - {
1.780 - pHook->pAdmin->eflags = bits;
1.781 - } else {
1.782 - pHook->pAdmin->eflags = pHook->pAdmin->flags;
1.783 - }
1.784 - pInfo->admin = *(pHook->pAdmin);
1.785 - }
1.786 - }
1.787 - }
1.788 - pInfo->is_admin_set = true;
1.789 - }
1.790 -}
1.791 -
1.792 -void ConCmdManager::RemoveConCmd(ConCmdInfo *info, const char *name, bool is_read_safe, bool untrack)
1.793 -{
1.794 - /* Remove from the trie */
1.795 - sm_trie_delete(m_pCmds, name);
1.796 -
1.797 - /* Remove console-specific information
1.798 - * This should always be true as of right now
1.799 - */
1.800 - if (info->pCmd)
1.801 - {
1.802 - if (info->sourceMod)
1.803 - {
1.804 - /* Unlink from SourceMM */
1.805 - g_SMAPI->UnregisterConCommandBase(g_PLAPI, info->pCmd);
1.806 - /* Delete the command's memory */
1.807 - char *new_help = const_cast<char *>(info->pCmd->GetHelpText());
1.808 - char *new_name = const_cast<char *>(info->pCmd->GetName());
1.809 - delete [] new_help;
1.810 - delete [] new_name;
1.811 - delete info->pCmd;
1.812 - }
1.813 - else
1.814 - {
1.815 - if (is_read_safe)
1.816 - {
1.817 - /* Remove the external hook */
1.818 - SH_REMOVE_HOOK_STATICFUNC(ConCommand, Dispatch, info->pCmd, CommandCallback, false);
1.819 - }
1.820 - if (untrack)
1.821 - {
1.822 - UntrackConCommandBase(info->pCmd, this);
1.823 - }
1.824 - }
1.825 - }
1.826 -
1.827 - /* Remove from list */
1.828 - m_CmdList.remove(info);
1.829 -
1.830 - delete info;
1.831 -}
1.832 -
1.833 -bool ConCmdManager::LookForSourceModCommand(const char *cmd)
1.834 -{
1.835 - ConCmdInfo *pInfo;
1.836 -
1.837 - if (!sm_trie_retrieve(m_pCmds, cmd, (void **)&pInfo))
1.838 - {
1.839 - return false;
1.840 - }
1.841 -
1.842 - return pInfo->sourceMod && (pInfo->conhooks.size() > 0);
1.843 -}
1.844 -
1.845 -bool ConCmdManager::LookForCommandAdminFlags(const char *cmd, FlagBits *pFlags)
1.846 -{
1.847 - ConCmdInfo *pInfo;
1.848 -
1.849 - if (!sm_trie_retrieve(m_pCmds, cmd, (void **)&pInfo))
1.850 - {
1.851 - return false;
1.852 - }
1.853 -
1.854 - *pFlags = pInfo->admin.eflags;
1.855 -
1.856 - return pInfo->is_admin_set;
1.857 -}
1.858 -
1.859 -ConCmdInfo *ConCmdManager::AddOrFindCommand(const char *name, const char *description, int flags)
1.860 -{
1.861 - ConCmdInfo *pInfo;
1.862 - if (!sm_trie_retrieve(m_pCmds, name, (void **)&pInfo))
1.863 - {
1.864 - pInfo = new ConCmdInfo();
1.865 - /* Find the commandopan */
1.866 - ConCommandBase *pBase = icvar->GetCommands();
1.867 - ConCommand *pCmd = NULL;
1.868 - while (pBase)
1.869 - {
1.870 - if (strcmp(pBase->GetName(), name) == 0)
1.871 - {
1.872 - /* Don't want to return convar with same name */
1.873 - if (!pBase->IsCommand())
1.874 - {
1.875 - return NULL;
1.876 - }
1.877 -
1.878 - pCmd = (ConCommand *)pBase;
1.879 - break;
1.880 - }
1.881 - pBase = const_cast<ConCommandBase *>(pBase->GetNext());
1.882 - }
1.883 -
1.884 - if (!pCmd)
1.885 - {
1.886 - /* Note that we have to duplicate because the source might not be
1.887 - * a static string, and these expect static memory.
1.888 - */
1.889 - if (!description)
1.890 - {
1.891 - description = "";
1.892 - }
1.893 - char *new_name = sm_strdup(name);
1.894 - char *new_help = sm_strdup(description);
1.895 - pCmd = new ConCommand(new_name, CommandCallback, new_help, flags);
1.896 - pInfo->sourceMod = true;
1.897 - }
1.898 - else
1.899 - {
1.900 - TrackConCommandBase(pCmd, this);
1.901 - SH_ADD_HOOK_STATICFUNC(ConCommand, Dispatch, pCmd, CommandCallback, false);
1.902 - }
1.903 -
1.904 - pInfo->pCmd = pCmd;
1.905 - pInfo->is_admin_set = false;
1.906 -
1.907 - sm_trie_insert(m_pCmds, name, pInfo);
1.908 - AddToCmdList(pInfo);
1.909 - }
1.910 -
1.911 - return pInfo;
1.912 -}
1.913 -
1.914 -void ConCmdManager::OnRootConsoleCommand(const char *cmdname, const CCommand &command)
1.915 -{
1.916 - if (command.ArgC() >= 3)
1.917 - {
1.918 - const char *text = command.Arg(2);
1.919 -
1.920 - int id = atoi(text);
1.921 - CPlugin *pPlugin = g_PluginSys.GetPluginByOrder(id);
1.922 -
1.923 - if (!pPlugin)
1.924 - {
1.925 - g_RootMenu.ConsolePrint("[SM] Plugin index %d not found.", id);
1.926 - return;
1.927 - }
1.928 -
1.929 - const sm_plugininfo_t *plinfo = pPlugin->GetPublicInfo();
1.930 - const char *plname = IS_STR_FILLED(plinfo->name) ? plinfo->name : pPlugin->GetFilename();
1.931 -
1.932 - CmdList *pList;
1.933 - if (!pPlugin->GetProperty("CommandList", (void **)&pList))
1.934 - {
1.935 - g_RootMenu.ConsolePrint("[SM] No commands found for: %s", plname);
1.936 - return;
1.937 - }
1.938 - if (!pList->size())
1.939 - {
1.940 - g_RootMenu.ConsolePrint("[SM] No commands found for: %s", plname);
1.941 - return;
1.942 - }
1.943 -
1.944 - CmdList::iterator iter;
1.945 - const char *type = NULL;
1.946 - const char *name;
1.947 - const char *help;
1.948 - g_RootMenu.ConsolePrint("[SM] Listing %d commands for: %s", pList->size(), plname);
1.949 - g_RootMenu.ConsolePrint(" %-17.16s %-8.7s %s", "[Name]", "[Type]", "[Help]");
1.950 - for (iter=pList->begin();
1.951 - iter!=pList->end();
1.952 - iter++, id++)
1.953 - {
1.954 - PlCmdInfo &cmd = (*iter);
1.955 - if (cmd.type == Cmd_Server)
1.956 - {
1.957 - type = "server";
1.958 - }
1.959 - else if (cmd.type == Cmd_Console)
1.960 - {
1.961 - type = "console";
1.962 - }
1.963 - else if (cmd.type == Cmd_Admin)
1.964 - {
1.965 - type = "admin";
1.966 - }
1.967 - name = cmd.pInfo->pCmd->GetName();
1.968 - if (cmd.pHook->helptext.size())
1.969 - {
1.970 - help = cmd.pHook->helptext.c_str();
1.971 - }
1.972 - else
1.973 - {
1.974 - help = cmd.pInfo->pCmd->GetHelpText();
1.975 - }
1.976 - g_RootMenu.ConsolePrint(" %-17.16s %-12.11s %s", name, type, help);
1.977 - }
1.978 -
1.979 - return;
1.980 - }
1.981 -
1.982 - g_RootMenu.ConsolePrint("[SM] Usage: sm cmds <plugin #>");
1.983 -}
1.984 -
1.985 -static int g_yam_state = 0;
1.986 -void _YamState(int state)
1.987 -{
1.988 - if (state == 0)
1.989 - {
1.990 - g_RootMenu.ConsolePrint("Welcome to the SourceMod Text Adventure.");
1.991 - g_RootMenu.ConsolePrint("Type sm_text to see the last message.");
1.992 - g_RootMenu.ConsolePrint("Type sm_text <word> to follow a capital word.");
1.993 - g_RootMenu.ConsolePrint("-------------------------------");
1.994 - g_RootMenu.ConsolePrint("You are at VALVE HEADQUARTERS.");
1.995 - g_RootMenu.ConsolePrint("To your LEFT is BAILOPAN, rearranging the letters to spell");
1.996 - g_RootMenu.ConsolePrint("\"A HARD VEAL QUEST\". FORWARD is the entrance to the building.");
1.997 - g_RootMenu.ConsolePrint("To your RIGHT is your last chance to flee in terror.");
1.998 - } else if (state == 1) {
1.999 - g_RootMenu.ConsolePrint("BAILOPAN tells you that his name his pronounced");
1.1000 - g_RootMenu.ConsolePrint("\"bye low pahn,\" not \"bay low pan.\" Do you ");
1.1001 - g_RootMenu.ConsolePrint("MOCK him, or NOD quietly?");
1.1002 - } else if (state == 2) {
1.1003 - g_RootMenu.ConsolePrint("You enter the Valve building. You hear screams coming from within.");
1.1004 - g_RootMenu.ConsolePrint("A grotesque figure lumbers up to greet you; it is Gabe Newell.");
1.1005 - g_RootMenu.ConsolePrint("\"Welcome,\" he belches, \"to my lair.\"");
1.1006 - g_RootMenu.ConsolePrint("Do you SHAKE Gaben's hand, WALK past him, or OFFER a donut?");
1.1007 - } else if (state == 3) {
1.1008 - g_RootMenu.ConsolePrint("You walk into the break room. Alfred \"Alf is from Melmac\" Reynolds and");
1.1009 - g_RootMenu.ConsolePrint("Yahn \"Yeti\" Bernier are discussing something (you overhear ");
1.1010 - g_RootMenu.ConsolePrint("the phrase \"and next Steam update, here's what we should break\").");
1.1011 - g_RootMenu.ConsolePrint("Should you DIE in a fire, REPORT a bug, REQUEST a feature, or ");
1.1012 - g_RootMenu.ConsolePrint("SPRAY them with butter?");
1.1013 - }
1.1014 - g_yam_state = state;
1.1015 -}
1.1016 -
1.1017 -#if defined ORANGEBOX_BUILD
1.1018 -void _IntExt_CallYams(const CCommand &cmd)
1.1019 -{
1.1020 -#else
1.1021 -void _IntExt_CallYams()
1.1022 -{
1.1023 - CCommand cmd;
1.1024 -#endif
1.1025 - const char *arg = cmd.Arg(1);
1.1026 -
1.1027 - /* should be impossible */
1.1028 - if (!arg || arg[0] == '\0')
1.1029 - {
1.1030 - _YamState(g_yam_state);
1.1031 - }
1.1032 -
1.1033 - if (g_yam_state == 1)
1.1034 - {
1.1035 - if (strcasecmp(arg, "mock") == 0)
1.1036 - {
1.1037 - g_RootMenu.ConsolePrint("You mock BAILOPAN's pronunciation. In a fit of rage, ");
1.1038 - g_RootMenu.ConsolePrint("he sticks an INT 3 call into your chest, rendering you broken.");
1.1039 - g_RootMenu.ConsolePrint("YOU HAVE DIED. GAME OVER.");
1.1040 - g_yam_state = 0;
1.1041 - } else if (strcasecmp(arg, "nod") == 0) {
1.1042 - g_RootMenu.ConsolePrint("You nod quietly, and then slowly back away into the Valve headquarters.");
1.1043 - _YamState(2);
1.1044 - } else {
1.1045 - g_RootMenu.ConsolePrint("Commands are MOCK and NOD.");
1.1046 - }
1.1047 - } else if (g_yam_state == 3) {
1.1048 - if (strcasecmp(arg, "report") == 0)
1.1049 - {
1.1050 - g_RootMenu.ConsolePrint("You report a bug to Alfred and Yeti. Immediately, both fall asleep.");
1.1051 - g_RootMenu.ConsolePrint("You decay in the break room for two years while they sleep.");
1.1052 - g_RootMenu.ConsolePrint("YOU HAVE DIED. GAME OVER.");
1.1053 - g_yam_state = 0;
1.1054 - } else if (strcasecmp(arg, "request") == 0) {
1.1055 - g_RootMenu.ConsolePrint("You request a feature to Alfred and Yeti. They both mutter something");
1.1056 - g_RootMenu.ConsolePrint("about it being implemented \"soon.\" Then, by accident, someone sends");
1.1057 - g_RootMenu.ConsolePrint("a message over \"Friends.\" The entire building catches fire.");
1.1058 - g_RootMenu.ConsolePrint("YOU HAVE DIED. GAME OVER.");
1.1059 - g_yam_state = 0;
1.1060 - } else if (strcasecmp(arg, "die") == 0) {
1.1061 - g_RootMenu.ConsolePrint("For no reason, you suddenly catch fire. Alfred and Yeti find this");
1.1062 - g_RootMenu.ConsolePrint("deeply disturbing, and cover your flaming corpse with Episode 2");
1.1063 - g_RootMenu.ConsolePrint("advertisements. Coming soon, with Team Fortress 2, and Portal!");
1.1064 - g_RootMenu.ConsolePrint("YOU HAVE DIED. GAME OVER.");
1.1065 - g_yam_state = 0;
1.1066 - } else if (strcasecmp(arg, "spray") == 0) {
1.1067 - g_RootMenu.ConsolePrint("You spray Alfred and Yeti with butter. Like Jack Thompson to an");
1.1068 - g_RootMenu.ConsolePrint("ambulance, Gabe Newell instantly appears and devours them both.");
1.1069 - g_RootMenu.ConsolePrint("You run away, just in time, as Gabe Newell explodes, registering ");
1.1070 - g_RootMenu.ConsolePrint("a 5.6 earthquake. Outside, world peace is achieved.");
1.1071 - g_RootMenu.ConsolePrint("YOU HAVE WON.");
1.1072 - g_yam_state = 0;
1.1073 - }
1.1074 - } else if (g_yam_state == 2) {
1.1075 - if (strcasecmp(arg, "shake") == 0)
1.1076 - {
1.1077 - g_RootMenu.ConsolePrint("You shake Gaben's hand. It is a terrifying and disgusting experience.");
1.1078 - g_RootMenu.ConsolePrint("However, you survive, and continue on.");
1.1079 - _YamState(3);
1.1080 - } else if (strcasecmp(arg, "offer") == 0) {
1.1081 - g_RootMenu.ConsolePrint("You offer Gabe Newell one (1) donut. With a gleam in his eyes, ");
1.1082 - g_RootMenu.ConsolePrint("he picks you up and devours you whole.");
1.1083 - g_RootMenu.ConsolePrint("YOU HAVE DIED. GAME OVER.");
1.1084 - g_yam_state = 0;
1.1085 - } else if (strcasecmp(arg, "walk") == 0) {
1.1086 - g_RootMenu.ConsolePrint("You walk past Gabe Newell. He can't keep up with your pace!");
1.1087 - _YamState(3);
1.1088 - } else {
1.1089 - g_RootMenu.ConsolePrint("Commands are SHAKE, OFFER, and WALK.");
1.1090 - }
1.1091 - } else if (g_yam_state == 0) {
1.1092 - if (strcasecmp(arg, "left") == 0)
1.1093 - {
1.1094 - _YamState(1);
1.1095 - } else if (strcasecmp(arg, "right") == 0) {
1.1096 - g_RootMenu.ConsolePrint("You run away from the Valve headquarters in sheer terror.");
1.1097 - g_RootMenu.ConsolePrint("While running, you smash into an unknown person, who turns out to be your soul mate.");
1.1098 - g_RootMenu.ConsolePrint("You marry and raise a family of 3 kids.");
1.1099 - g_RootMenu.ConsolePrint("Many years later, you look back, and realize this was your best choice.");
1.1100 - g_RootMenu.ConsolePrint("YOU HAVE WON.");
1.1101 - g_yam_state = 0;
1.1102 - } else if (strcasecmp(arg, "forward") == 0) {
1.1103 - _YamState(2);
1.1104 - } else if (arg[0] != '\0') {
1.1105 - g_RootMenu.ConsolePrint("Commands are FORWARD, LEFT, and RIGHT.");
1.1106 - }
1.1107 - }
1.1108 -}
1.1109 -
1.1110 -void _IntExt_EnableYams()
1.1111 -{
1.1112 - static ConCommand *pCmd = NULL;
1.1113 - if (!pCmd)
1.1114 - {
1.1115 - pCmd = new ConCommand("sm_text", _IntExt_CallYams, "Fountain of Yams Adventure Game", FCVAR_GAMEDLL);
1.1116 - g_RootMenu.ConsolePrint("Something is now enabled...");
1.1117 - } else {
1.1118 - g_RootMenu.ConsolePrint("Something is already enabled...");
1.1119 - }
1.1120 -}