dvander@1582: /** dvander@1582: * vim: set ts=4 : dvander@1582: * ============================================================================= dvander@1582: * SourceMod ds@1947: * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. dvander@1582: * ============================================================================= dvander@1582: * dvander@1582: * This program is free software; you can redistribute it and/or modify it under dvander@1582: * the terms of the GNU General Public License, version 3.0, as published by the dvander@1582: * Free Software Foundation. dvander@1582: * dvander@1582: * This program is distributed in the hope that it will be useful, but WITHOUT dvander@1582: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS dvander@1582: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more dvander@1582: * details. dvander@1582: * dvander@1582: * You should have received a copy of the GNU General Public License along with dvander@1582: * this program. If not, see . dvander@1582: * dvander@1582: * As a special exception, AlliedModders LLC gives you permission to link the dvander@1582: * code of this program (as well as its derivative works) to "Half-Life 2," the dvander@1582: * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software dvander@1582: * by the Valve Corporation. You must obey the GNU General Public License in dvander@1582: * all respects for all other code used. Additionally, AlliedModders LLC grants dvander@1582: * this exception to all derivative works. AlliedModders LLC defines further dvander@1582: * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), dvander@1582: * or . dvander@1582: * dvander@1582: * Version: $Id$ dvander@1582: */ dvander@1582: dvander@1582: #include "sm_globals.h" dvander@1582: #include dvander@1582: #include dvander@1582: #include "concmd_cleaner.h" dvander@1582: #include "sm_stringutil.h" dvander@1582: #include "sourcemm_api.h" ds@2400: #include "compat_wrappers.h" dvander@1582: ds@2400: #if SOURCE_ENGINE >= SE_ORANGEBOX dvander@1582: SH_DECL_HOOK1_void(ICvar, UnregisterConCommand, SH_NOATTRIB, 0, ConCommandBase *); dvander@2806: SH_DECL_HOOK1_void(ICvar, RegisterConCommand, SH_NOATTRIB, 0, ConCommandBase *); dvander@2806: #else dvander@2806: SH_DECL_HOOK1_void(ICvar, RegisterConCommandBase, SH_NOATTRIB, 0, ConCommandBase *); dvander@1582: #endif dvander@1582: dvander@1582: using namespace SourceHook; dvander@1582: dvander@1582: struct ConCommandInfo dvander@1582: { dvander@1582: ConCommandBase *pBase; dvander@1582: IConCommandTracker *cls; dvander@1582: char name[64]; dvander@1582: }; dvander@1582: dvander@1582: List tracked_bases; dvander@2806: IConCommandLinkListener *IConCommandLinkListener::head = NULL; dvander@1582: dvander@1582: ConCommandBase *FindConCommandBase(const char *name); dvander@1582: dvander@1582: class ConCommandCleaner : public SMGlobalClass dvander@1582: { dvander@1582: public: dvander@1582: void OnSourceModAllInitialized() dvander@1582: { dvander@2806: #if SOURCE_ENGINE >= SE_ORANGEBOX kyle@3819: SH_ADD_HOOK(ICvar, UnregisterConCommand, icvar, SH_MEMBER(this, &ConCommandCleaner::UnlinkConCommandBase), false); kyle@3819: SH_ADD_HOOK(ICvar, RegisterConCommand, icvar, SH_MEMBER(this, &ConCommandCleaner::LinkConCommandBase), false); dvander@2806: #else kyle@3819: SH_ADD_HOOK(ICvar, RegisterConCommandBase, icvar, SH_MEMBER(this, &ConCommandCleaner::LinkConCommandBase), false); dvander@2806: #endif dvander@1582: } dvander@1582: dvander@1582: void OnSourceModShutdown() dvander@1582: { dvander@2806: #if SOURCE_ENGINE >= SE_ORANGEBOX kyle@3819: SH_REMOVE_HOOK(ICvar, UnregisterConCommand, icvar, SH_MEMBER(this, &ConCommandCleaner::UnlinkConCommandBase), false); kyle@3819: SH_REMOVE_HOOK(ICvar, RegisterConCommand, icvar, SH_MEMBER(this, &ConCommandCleaner::LinkConCommandBase), false); dvander@2806: #else kyle@3819: SH_REMOVE_HOOK(ICvar, RegisterConCommandBase, icvar, SH_MEMBER(this, &ConCommandCleaner::LinkConCommandBase), false); dvander@2806: #endif dvander@1582: } dvander@2806: dvander@2806: void LinkConCommandBase(ConCommandBase *pBase) dvander@2806: { dvander@2806: IConCommandLinkListener *listener = IConCommandLinkListener::head; dvander@2806: while (listener) dvander@2806: { dvander@2806: listener->OnLinkConCommand(pBase); dvander@2806: listener = listener->next; dvander@2806: } dvander@2806: } dvander@1582: dvander@1582: void UnlinkConCommandBase(ConCommandBase *pBase) dvander@1582: { dvander@1582: ConCommandInfo *pInfo; dvander@1582: List::iterator iter = tracked_bases.begin(); dvander@1582: dvander@2806: IConCommandLinkListener *listener = IConCommandLinkListener::head; dvander@2806: while (listener) dvander@2806: { dvander@2806: listener->OnUnlinkConCommand(pBase); dvander@2806: listener = listener->next; dvander@2806: } dvander@2806: dvander@1582: if (pBase) dvander@1582: { dvander@1582: while (iter != tracked_bases.end()) dvander@1582: { dvander@1582: if ((*iter)->pBase == pBase) dvander@1582: { dvander@1582: pInfo = (*iter); dvander@1582: iter = tracked_bases.erase(iter); dvander@1582: pInfo->cls->OnUnlinkConCommandBase(pBase, pBase->GetName(), true); dvander@1582: delete pInfo; dvander@1582: } dvander@1582: else dvander@1582: { dvander@1582: iter++; dvander@1582: } dvander@1582: } dvander@1582: } dvander@1582: else dvander@1582: { dvander@1582: while (iter != tracked_bases.end()) dvander@1582: { dvander@1582: /* This is just god-awful! */ ds@2400: if (FindCommandBase((*iter)->name) != (*iter)->pBase) dvander@1582: { dvander@1582: pInfo = (*iter); dvander@1582: iter = tracked_bases.erase(iter); dvander@1584: pInfo->cls->OnUnlinkConCommandBase(pBase, pInfo->name, false); dvander@1582: delete pInfo; dvander@1582: } dvander@1582: else dvander@1582: { dvander@1582: iter++; dvander@1582: } dvander@1582: } dvander@1582: } dvander@1582: } dvander@1582: dvander@1582: void AddTarget(ConCommandBase *pBase, IConCommandTracker *cls) dvander@1582: { dvander@1582: ConCommandInfo *info = new ConCommandInfo; dvander@1582: dvander@1582: info->pBase = pBase; dvander@1582: info->cls = cls; dvander@1582: strncopy(info->name, pBase->GetName(), sizeof(info->name)); dvander@1582: dvander@1582: tracked_bases.push_back(info); dvander@1582: } dvander@1582: dvander@1582: void RemoveTarget(ConCommandBase *pBase, IConCommandTracker *cls) dvander@1582: { dvander@1582: List::iterator iter; dvander@1582: ConCommandInfo *pInfo; dvander@1582: dvander@1582: iter = tracked_bases.begin(); dvander@1582: while (iter != tracked_bases.end()) dvander@1582: { dvander@1582: pInfo = (*iter); dvander@1582: if (pInfo->pBase == pBase && pInfo->cls == cls) dvander@1582: { dvander@1582: delete pInfo; dvander@1582: iter = tracked_bases.erase(iter); dvander@1582: } dvander@1582: else dvander@1582: { dvander@1582: iter++; dvander@1582: } dvander@1582: } dvander@1582: } dvander@1582: } s_ConCmdTracker; dvander@1582: dvander@1582: void TrackConCommandBase(ConCommandBase *pBase, IConCommandTracker *me) dvander@1582: { dvander@1582: s_ConCmdTracker.AddTarget(pBase, me); dvander@1582: } dvander@1582: dvander@1582: void UntrackConCommandBase(ConCommandBase *pBase, IConCommandTracker *me) dvander@1582: { dvander@1582: s_ConCmdTracker.RemoveTarget(pBase, me); dvander@1582: } dvander@1582: dvander@1582: void Global_OnUnlinkConCommandBase(ConCommandBase *pBase) dvander@1582: { dvander@1582: s_ConCmdTracker.UnlinkConCommandBase(pBase); dvander@1582: }