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: }