From 096a04b3e4549ba201852d6b67c7b982af4195f6 Mon Sep 17 00:00:00 2001 From: Matt Woodrow Date: Thu, 5 Mar 2009 11:59:49 +1300 Subject: [PATCH] Added SourceMod to the sv_tags list and added a tags API for plugins (bug 3688, r=dvander) --- core/Makefile | 2 +- core/TagsSystem.cpp | 206 +++++++++++++++++++++++++++++++++ core/TagsSystem.h | 71 ++++++++++++ core/msvc9/sourcemod_mm.vcproj | 8 ++ core/smn_console.cpp | 57 +++++++++ plugins/include/console.inc | 20 ++++ 6 files changed, 363 insertions(+), 1 deletion(-) create mode 100644 core/TagsSystem.cpp create mode 100644 core/TagsSystem.h diff --git a/core/Makefile b/core/Makefile index 0862d4cc..d68423c5 100644 --- a/core/Makefile +++ b/core/Makefile @@ -19,7 +19,7 @@ OBJECTS = AdminCache.cpp CDataPack.cpp ConCmdManager.cpp ConVarManager.cpp CoreC sourcemm_api.cpp sourcemod.cpp MenuStyle_Base.cpp MenuStyle_Valve.cpp MenuManager.cpp \ MenuStyle_Radio.cpp ChatTriggers.cpp ADTFactory.cpp MenuVoting.cpp sm_crc32.cpp \ frame_hooks.cpp concmd_cleaner.cpp Profiler.cpp PhraseCollection.cpp NextMap.cpp \ - NativeOwner.cpp + NativeOwner.cpp TagsSystem.cpp OBJECTS += smn_admin.cpp smn_bitbuffer.cpp smn_console.cpp smn_core.cpp \ smn_datapacks.cpp smn_entities.cpp smn_events.cpp smn_fakenatives.cpp \ smn_filesystem.cpp smn_float.cpp smn_functions.cpp smn_gameconfigs.cpp smn_halflife.cpp \ diff --git a/core/TagsSystem.cpp b/core/TagsSystem.cpp new file mode 100644 index 00000000..93615368 --- /dev/null +++ b/core/TagsSystem.cpp @@ -0,0 +1,206 @@ +/** +* vim: set ts=4 : +* ============================================================================= +* SourceMod +* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. +* ============================================================================= +* +* This program is free software; you can redistribute it and/or modify it under +* the terms of the GNU General Public License, version 3.0, as published by the +* Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +* details. +* +* You should have received a copy of the GNU General Public License along with +* this program. If not, see . +* +* As a special exception, AlliedModders LLC gives you permission to link the +* code of this program (as well as its derivative works) to "Half-Life 2," the +* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software +* by the Valve Corporation. You must obey the GNU General Public License in +* all respects for all other code used. Additionally, AlliedModders LLC grants +* this exception to all derivative works. AlliedModders LLC defines further +* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), +* or . +* +* Version: $Id$ +*/ + +#include "TagsSystem.h" +#include "sourcemod.h" +#include "sourcemm_api.h" +#include "sm_stringutil.h" +#include "PluginSys.h" +#include "compat_wrappers.h" + +TagHandler g_Tags; + +TagHandler::TagHandler() +{ + m_SvTags = NULL; +} + +TagHandler::~TagHandler() +{ + SourceHook::List::iterator iter = m_TagList.begin(); + + while (iter != m_TagList.end()) + { + g_pMemAlloc->Free(*iter); + iter = m_TagList.erase(iter); + } +} + +void TagHandler::OnSourceModAllInitialized_Post() +{ + g_PluginSys.AddPluginsListener(this); + + m_SvTags = icvar->FindVar("sv_tags"); + AddTag("sourcemod"); +} + +void TagHandler::OnSourceModLevelActivated() +{ + SourceHook::List::iterator iter = m_TagList.begin(); + + while (iter != m_TagList.end()) + { + ApplyTag(*iter); + iter++; + } +} + +void TagHandler::OnSourceModShutdown() +{ + RemoveTag("sourcemod"); +} + +void TagHandler::OnPluginDestroyed(IPlugin *plugin) +{ + SourceHook::List *pList = NULL; + + if (!plugin->GetProperty("ServerTags", (void **)&pList, false) || !pList) + { + return; + } + + SourceHook::List::iterator iter = pList->begin(); + + while (iter != pList->end()) + { + RemoveTag(*iter); + g_pMemAlloc->Free(*iter); + iter = pList->erase(iter); + } + + delete pList; +} + +bool TagHandler::AddTag(const char *addTag) +{ + SourceHook::List::iterator iter = m_TagList.begin(); + + while (iter != m_TagList.end()) + { + if (strcmp(*iter, addTag) == 0) + { + return false; + } + } + + m_TagList.push_back(strdup(addTag)); + ApplyTag(addTag); + + return true; +} + +bool TagHandler::RemoveTag(const char *removeTag) +{ + SourceHook::List::iterator iter = m_TagList.begin(); + + while (iter != m_TagList.end()) + { + if (strcmp(*iter, removeTag) == 0) + { + g_pMemAlloc->Free(*iter); + m_TagList.erase(iter); + StripTag(removeTag); + + return true; + } + } + + return false; +} + +void TagHandler::ApplyTag(const char *addTag) +{ + if (m_SvTags == NULL) + { + return; + } + + const char *curTags = m_SvTags->GetString(); + + if (strstr(curTags, addTag) != NULL) + { + /* Already tagged */ + return; + } + + if (curTags[0] == '\0') + { + m_SvTags->SetValue(addTag); + return; + } + + /* New tags buffer (+2 for , and null char) */ + size_t newLen = strlen(curTags) + strlen(addTag) + 2; + char *newTags = (char *)alloca(newLen); + + g_SourceMod.Format(newTags, newLen, "%s,%s", curTags, addTag); + + m_SvTags->SetValue(newTags); +} + +void TagHandler::StripTag(const char *removeTag) +{ + if (m_SvTags == NULL) + { + return; + } + + const char *curTags = m_SvTags->GetString(); + + if (strcmp(curTags, removeTag) == 0) + { + m_SvTags->SetValue(""); + return; + } + + char *newTags = strdup(curTags); + size_t searchLen = strlen(removeTag) + 2; + char *search = (char *)alloca(searchLen); + + if (strncmp(curTags, removeTag, strlen(removeTag)) == 0) + { + strcpy(search, removeTag); + search[searchLen-2] = ','; + search[searchLen-1] = '\0'; + } + else + { + strcpy(search+1, removeTag); + search[0] = ','; + search[searchLen-1] = '\0'; + } + + UTIL_ReplaceAll(newTags, strlen(newTags) + 1, search, "" , true); + + m_SvTags->SetValue(newTags); + + g_pMemAlloc->Free(newTags); +} diff --git a/core/TagsSystem.h b/core/TagsSystem.h new file mode 100644 index 00000000..2f8337a8 --- /dev/null +++ b/core/TagsSystem.h @@ -0,0 +1,71 @@ +/** +* vim: set ts=4 : +* ============================================================================= +* SourceMod +* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. +* ============================================================================= +* +* This program is free software; you can redistribute it and/or modify it under +* the terms of the GNU General Public License, version 3.0, as published by the +* Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +* details. +* +* You should have received a copy of the GNU General Public License along with +* this program. If not, see . +* +* As a special exception, AlliedModders LLC gives you permission to link the +* code of this program (as well as its derivative works) to "Half-Life 2," the +* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software +* by the Valve Corporation. You must obey the GNU General Public License in +* all respects for all other code used. Additionally, AlliedModders LLC grants +* this exception to all derivative works. AlliedModders LLC defines further +* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), +* or . +* +* Version: $Id$ +*/ + +#ifndef _INCLUDE_SOURCEMOD_TAGSSYSTEM_H_ +#define _INCLUDE_SOURCEMOD_TAGSSYSTEM_H_ + +#include "sm_globals.h" +#include "sh_list.h" +#include "convar.h" +#include "IPluginSys.h" + +class TagHandler : + public SMGlobalClass, + public IPluginsListener +{ +public: + TagHandler(); + ~TagHandler(); + +public: // SMGlobalClass + void OnSourceModAllInitialized_Post(); + void OnSourceModLevelActivated(); + void OnSourceModShutdown(); + +public: // IPluginsListener + void OnPluginDestroyed(IPlugin *plugin); + +public: + bool AddTag(const char *addTag); + bool RemoveTag(const char *removeTag); + +private: + void ApplyTag(const char *addTag); + void StripTag(const char *removeTag); + +private: + SourceHook::Listm_TagList; + ConVar *m_SvTags; +}; + +extern TagHandler g_Tags; + +#endif // _INCLUDE_SOURCEMOD_TAGSSYSTEM_H_ diff --git a/core/msvc9/sourcemod_mm.vcproj b/core/msvc9/sourcemod_mm.vcproj index 2f939677..2da543f3 100644 --- a/core/msvc9/sourcemod_mm.vcproj +++ b/core/msvc9/sourcemod_mm.vcproj @@ -1512,6 +1512,10 @@ RelativePath="..\sourcemod.cpp" > + + @@ -1750,6 +1754,10 @@ RelativePath="..\sourcemod.h" > + + diff --git a/core/smn_console.cpp b/core/smn_console.cpp index a210fdd5..19d9d5ef 100644 --- a/core/smn_console.cpp +++ b/core/smn_console.cpp @@ -43,6 +43,7 @@ #include #include #include +#include "TagsSystem.h" #if SOURCE_ENGINE == SE_LEFT4DEAD #define NET_SETCONVAR 6 @@ -1304,6 +1305,60 @@ static cell_t SendConVarValue(IPluginContext *pContext, const cell_t *params) return 1; } +static cell_t AddServerTag(IPluginContext *pContext, const cell_t *params) +{ + char *value; + pContext->LocalToString(params[1], &value); + + if (!g_Tags.AddTag(value)) + { + return 0; + } + + IPlugin *pPlugin = g_PluginSys.FindPluginByContext(pContext->GetContext()); + SourceHook::List *pList = NULL; + + if (!pPlugin->GetProperty("ServerTags", (void **)&pList, false) || !pList) + { + pList = new SourceHook::List; + pPlugin->SetProperty("ServerTags", pList); + } + + pList->push_back(strdup(value)); + + return 1; +} + +static cell_t RemoveServerTag(IPluginContext *pContext, const cell_t *params) +{ + char *value; + pContext->LocalToString(params[1], &value); + + IPlugin *pPlugin = g_PluginSys.FindPluginByContext(pContext->GetContext()); + SourceHook::List *pList = NULL; + + if (!pPlugin->GetProperty("ServerTags", (void **)&pList, false) || !pList) + { + pList = new SourceHook::List; + pPlugin->SetProperty("ServerTags", pList); + } + + SourceHook::List::iterator iter = pList->begin(); + + while (iter != pList->end()) + { + if (strcmp(*iter, value) == 0) + { + g_pMemAlloc->Free(*iter); + pList->erase(iter); + + return g_Tags.RemoveTag(value); + } + } + + return 0; +} + REGISTER_NATIVES(consoleNatives) { {"CreateConVar", sm_CreateConVar}, @@ -1351,5 +1406,7 @@ REGISTER_NATIVES(consoleNatives) {"FindFirstConCommand", FindFirstConCommand}, {"FindNextConCommand", FindNextConCommand}, {"SendConVarValue", SendConVarValue}, + {"AddServerTag", AddServerTag}, + {"RemoveServerTag", RemoveServerTag}, {NULL, NULL} }; diff --git a/plugins/include/console.inc b/plugins/include/console.inc index ffe5dcda..2130c30e 100644 --- a/plugins/include/console.inc +++ b/plugins/include/console.inc @@ -815,3 +815,23 @@ native bool:FindNextConCommand(Handle:search, String:buffer[], max_size, &bool:i * @error Invalid client index, client not in game, or client is fake */ native bool:SendConVarValue(client, Handle:convar, const String:value[]); + +/** + * Appends a string to Valve's sv_tags convar and makes sure it remains after mapchanges. + * + * Note: Tags are automatically removed on plugin unload + * + * @param tag Tag string to append. + * @noreturn + */ +native AddServerTag(const String:tag[]); + +/** + * Removes a string from valve's sv_tags convar. + * + * Note: You can only remove tags created by you. + * + * @param tag Tag string to remove. + * @noreturn + */ +native RemoveServerTag(const String:tag[]);