diff --git a/configs/dynamicmenu/adminmenu_grouping.txt b/configs/dynamicmenu/adminmenu_grouping.txt new file mode 100644 index 00000000..7835432b --- /dev/null +++ b/configs/dynamicmenu/adminmenu_grouping.txt @@ -0,0 +1,18 @@ +/* Add group options to be added to 'group' or 'groupplayer' type submenus + * The left side is the name that will show in the menu, right is the command that will be fired + */ + +Groups +{ + "All" "@all" + "Bots" "@bots" + "Alive" "@alive" + "Dead" "@dead" + "Humans" "@humans" + "Current aim" "@aim" + + /* You can enable these if you are using Counter-Strike Source and running the cstrike extension */ +// "Terrorists" "@t" +// "Counter-Terrorists" "@ct" + +} \ No newline at end of file diff --git a/configs/dynamicmenu/menu.ini b/configs/dynamicmenu/menu.ini new file mode 100644 index 00000000..08fa0da4 --- /dev/null +++ b/configs/dynamicmenu/menu.ini @@ -0,0 +1,4 @@ +"Commands" +{ + +} \ No newline at end of file diff --git a/core/AdminCache.cpp b/core/AdminCache.cpp index 97f50b4f..154f88a4 100644 --- a/core/AdminCache.cpp +++ b/core/AdminCache.cpp @@ -2,7 +2,7 @@ * vim: set ts=4 : * ============================================================================= * SourceMod - * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved. + * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. * ============================================================================= * * This program is free software; you can redistribute it and/or modify it under diff --git a/core/AdminCache.h b/core/AdminCache.h index bb66c6b2..c7d21da1 100644 --- a/core/AdminCache.h +++ b/core/AdminCache.h @@ -2,7 +2,7 @@ * vim: set ts=4 : * ============================================================================= * SourceMod - * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved. + * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. * ============================================================================= * * This program is free software; you can redistribute it and/or modify it under diff --git a/core/sm_trie.cpp b/core/sm_trie.cpp index fcc9dd5c..ac267de7 100644 --- a/core/sm_trie.cpp +++ b/core/sm_trie.cpp @@ -2,7 +2,7 @@ * vim: set ts=4 : * ============================================================================= * SourceMod - * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved. + * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. * ============================================================================= * * This program is free software; you can redistribute it and/or modify it under diff --git a/core/sm_trie.h b/core/sm_trie.h index 263bef94..8306fd55 100644 --- a/core/sm_trie.h +++ b/core/sm_trie.h @@ -2,7 +2,7 @@ * vim: set ts=4 : * ============================================================================= * SourceMod - * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved. + * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. * ============================================================================= * * This program is free software; you can redistribute it and/or modify it under diff --git a/editor/crimson/spec/sourcepawn.key b/editor/crimson/spec/sourcepawn.key index 86155320..1868916c 100644 --- a/editor/crimson/spec/sourcepawn.key +++ b/editor/crimson/spec/sourcepawn.key @@ -15,7 +15,7 @@ cellsof chars sizeof tagof # Predefined constants false true cellbits cellmax cellmin charbits charmax charmin myinfo INVALID_HANDLE -__version +__version NULL_VECTOR NULL_STRING # Predefined tag names bool Float Handle String diff --git a/editor/crimson/tools/compile.cmd b/editor/crimson/tools/compile.cmd new file mode 100644 index 00000000..4c9e9064 Binary files /dev/null and b/editor/crimson/tools/compile.cmd differ diff --git a/extensions/regex/CRegEx.cpp b/extensions/regex/CRegEx.cpp new file mode 100644 index 00000000..6405a3a0 --- /dev/null +++ b/extensions/regex/CRegEx.cpp @@ -0,0 +1,124 @@ +#include "pcre.h" +#include "CRegEx.h" +#include +#include "extension.h" + +RegEx::RegEx() +{ + mErrorOffset = 0; + mError = NULL; + re = NULL; + mFree = true; + subject = NULL; + mSubStrings = 0; +} + +void RegEx::Clear () +{ + mErrorOffset = 0; + mError = NULL; + if (re) + pcre_free(re); + re = NULL; + mFree = true; + if (subject) + delete [] subject; + subject = NULL; + mSubStrings = 0; +} + +RegEx::~RegEx() +{ + Clear(); +} + +bool RegEx::isFree(bool set, bool val) +{ + if (set) + { + mFree = val; + return true; + } else { + return mFree; + } +} + +int RegEx::Compile(const char *pattern, int iFlags) +{ + if (!mFree) + Clear(); + + re = pcre_compile(pattern, iFlags, &mError, &mErrorOffset, NULL); + + if (re == NULL) + { + return 0; + } + + mFree = false; + + return 1; +} + +int RegEx::Match(const char *str) +{ + int rc = 0; + + if (mFree || re == NULL) + return -1; + + this->ClearMatch(); + + //save str + subject = new char[strlen(str)+1]; + strcpy(subject, str); + + rc = pcre_exec(re, NULL, subject, (int)strlen(subject), 0, 0, ovector, 30); + + if (rc < 0) + { + if (rc == PCRE_ERROR_NOMATCH) + { + return 0; + } else { + mErrorOffset = rc; + return -1; + } + } + + mSubStrings = rc; + + return 1; +} +void RegEx::ClearMatch() +{ + // Clears match results + mErrorOffset = 0; + mError = NULL; + if (subject) + delete [] subject; + subject = NULL; + mSubStrings = 0; +} + +const char *RegEx::GetSubstring(int s, char buffer[], int max) +{ + int i = 0; + if (s >= mSubStrings || s < 0) + return NULL; + + char *substr_a = subject + ovector[2*s]; + int substr_l = ovector[2*s+1] - ovector[2*s]; + + for (i = 0; i= max) + break; + buffer[i] = substr_a[i]; + } + + buffer[i] = '\0'; + + return buffer; +} + diff --git a/extensions/regex/CRegEx.h b/extensions/regex/CRegEx.h new file mode 100644 index 00000000..183a3039 --- /dev/null +++ b/extensions/regex/CRegEx.h @@ -0,0 +1,28 @@ +#ifndef _INCLUDE_CREGEX_H +#define _INCLUDE_CREGEX_H + +class RegEx +{ +public: + RegEx(); + ~RegEx(); + bool isFree(bool set=false, bool val=false); + void Clear(); + + int Compile(const char *pattern, int iFlags); + int Match(const char *str); + void ClearMatch(); + const char *GetSubstring(int s, char buffer[], int max); +public: + int mErrorOffset; + const char *mError; + int mSubStrings; +private: + pcre *re; + bool mFree; + int ovector[30]; + char *subject; +}; + +#endif //_INCLUDE_CREGEX_H + diff --git a/extensions/regex/Makefile b/extensions/regex/Makefile new file mode 100644 index 00000000..c5996806 --- /dev/null +++ b/extensions/regex/Makefile @@ -0,0 +1,73 @@ +#(C)2004-2008 Metamod:Source Development Team +# Makefile written by David "BAILOPAN" Anderson + +SOURCEMM = ../../../sourcemm-1.6 +SMSDK = ../.. + +##################################### +### EDIT BELOW FOR OTHER PROJECTS ### +##################################### + +PROJECT = regex + +OBJECTS = sdk/smsdk_ext.cpp extension.cpp CRegEx.cpp + +############################################## +### CONFIGURE ANY OTHER FLAGS/OPTIONS HERE ### +############################################## + +C_OPT_FLAGS = -O3 -funroll-loops -s -pipe -fno-strict-aliasing +C_DEBUG_FLAGS = -g -ggdb3 +CPP_GCC4_FLAGS = -fvisibility=hidden -fvisibility-inlines-hidden +CPP = gcc-4.1 + +LINK = lib_linux/libpcre.a -static-libgcc + +INCLUDE += -I. -I.. -Isdk -I$(HL2PUB) -I$(SOURCEMM)/sourcehook -I$(SMSDK)/public \ + -I$(SMSDK)/public/sourcepawn -I$(SMSDK)/public/extensions + +CFLAGS += -D_LINUX -DNDEBUG -Dstricmp=strcasecmp -D_stricmp=strcasecmp -D_strnicmp=strncasecmp -Dstrnicmp=strncasecmp \ + -D_snprintf=snprintf -D_vsnprintf=vsnprintf -D_alloca=alloca -Dstrcmpi=strcasecmp -Wall -Werror -Wno-switch \ + -Wno-unused -mfpmath=sse -msse -DSOURCEMOD_BUILD -DHAVE_STDINT_H -m32 +CPPFLAGS += -Wno-non-virtual-dtor -fno-exceptions -fno-rtti -fno-threadsafe-statics + +################################################ +### DO NOT EDIT BELOW HERE FOR MOST PROJECTS ### +################################################ + +ifeq "$(DEBUG)" "true" + BIN_DIR = Debug.$(ENGINE) + CFLAGS += $(C_DEBUG_FLAGS) +else + BIN_DIR = Release.$(ENGINE) + CFLAGS += $(C_OPT_FLAGS) +endif + +GCC_VERSION := $(shell $(CPP) -dumpversion >&1 | cut -b1) +ifeq "$(GCC_VERSION)" "4" + CPPFLAGS += $(CPP_GCC4_FLAGS) +endif + +BINARY = $(PROJECT).ext.so + +OBJ_LINUX := $(OBJECTS:%.cpp=$(BIN_DIR)/%.o) + +$(BIN_DIR)/%.o: %.cpp + $(CPP) $(INCLUDE) $(CFLAGS) $(CPPFLAGS) -o $@ -c $< + +all: + mkdir -p $(BIN_DIR)/sdk + $(MAKE) -f Makefile extension + +extension: $(OBJ_LINUX) + $(CPP) $(INCLUDE) $(OBJ_LINUX) $(LINK) -m32 -shared -ldl -lm -o$(BIN_DIR)/$(BINARY) + +debug: + $(MAKE) -f Makefile all DEBUG=true + +default: all + +clean: + rm -rf $(BIN_DIR)/*.o + rm -rf $(BIN_DIR)/sdk/*.o + rm -rf $(BIN_DIR)/$(BINARY) diff --git a/extensions/regex/extension.cpp b/extensions/regex/extension.cpp new file mode 100644 index 00000000..e3519172 --- /dev/null +++ b/extensions/regex/extension.cpp @@ -0,0 +1,188 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod Sample Extension + * Copyright (C) 2004-2007 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 "extension.h" + +#include +#include "pcre.h" +#include "CRegEx.h" +using namespace SourceHook; + +/** + * @file extension.cpp + * @brief Implement extension code here. + */ + +RegexExtension g_RegexExtension; /**< Global singleton for extension's main interface */ + +SMEXT_LINK(&g_RegexExtension); + +RegexHandler g_RegexHandler; +HandleType_t g_RegexHandle=0; + + + +bool RegexExtension::SDK_OnLoad(char *error, size_t err_max, bool late) +{ + g_pShareSys->AddNatives(myself,regex_natives); + g_RegexHandle = g_pHandleSys->CreateType("Regex", &g_RegexHandler, 0, NULL, NULL, myself->GetIdentity(), NULL); + return true; +} + +void RegexExtension::SDK_OnUnload() +{ + g_pHandleSys->RemoveType(g_RegexHandle, myself->GetIdentity()); + +} + +static cell_t CompileRegex(IPluginContext *pCtx, const cell_t *params) +{ + char *regex; + pCtx->LocalToString(params[1], ®ex); + + RegEx *x = new RegEx(); + + if (x->Compile(regex, params[2]) == 0) + { + cell_t *eOff; + pCtx->LocalToPhysAddr(params[5], &eOff); + const char *err = x->mError; + *eOff = x->mErrorOffset; + pCtx->StringToLocal(params[3], params[4], err ? err:"unknown"); + return 0; + } + + return g_pHandleSys->CreateHandle(g_RegexHandle, (void*)x, pCtx->GetIdentity(), myself->GetIdentity(), NULL); +} + + +static cell_t MatchRegex(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError err; + HandleSecurity sec; + sec.pOwner = NULL; + sec.pIdentity = myself->GetIdentity(); + + RegEx *x; + + if ((err=g_pHandleSys->ReadHandle(hndl, g_RegexHandle, &sec, (void **)&x)) != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid file handle %x (error %d)", hndl, err); + } + + if (!x) + { + pCtx->ThrowNativeError("Regex data not found\n"); + + return 0; + } + + char *str; + pCtx->LocalToString(params[2], &str); + + int e = x->Match(str); + + if (e == -1) + { + /* there was a match error. move on. */ + cell_t *res; + pCtx->LocalToPhysAddr(params[3], &res); + *res = x->mErrorOffset; + /* only clear the match results, since the regex object + may still be referenced later */ + x->ClearMatch(); + + return -1; + } + else if (e == 0) + { + /* only clear the match results, since the regex object + may still be referenced later */ + x->ClearMatch(); + + return 0; + } + else + { + return x->mSubStrings; + } +} + +static cell_t GetRegexSubString(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl=static_cast(params[1]); + HandleError err; + HandleSecurity sec; + sec.pOwner=NULL; + sec.pIdentity=myself->GetIdentity(); + + RegEx *x; + + if ((err=g_pHandleSys->ReadHandle(hndl, g_RegexHandle, &sec, (void **)&x)) != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid file handle %x (error %d)", hndl, err); + } + + if (!x) + { + pCtx->ThrowNativeError("Regex data not found\n"); + return 0; + } + + static char buffer[4096]; + const char *ret=x->GetSubstring(params[2], buffer, sizeof(buffer)); + + if(!ret) + { + return 0; + } + + pCtx->StringToLocalUTF8(params[3], params[4], ret, NULL); + + return 1; +} + +void RegexHandler::OnHandleDestroy(HandleType_t type, void *object) +{ + RegEx *x = (RegEx *)object; + + x->Clear(); + delete x; +} + +const sp_nativeinfo_t regex_natives[] = +{ + {"GetRegexSubString", GetRegexSubString}, + {"MatchRegex", MatchRegex}, + {"CompileRegex", CompileRegex}, + {NULL, NULL}, +}; diff --git a/extensions/regex/extension.h b/extensions/regex/extension.h new file mode 100644 index 00000000..0c4beff2 --- /dev/null +++ b/extensions/regex/extension.h @@ -0,0 +1,133 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod Sample Extension + * Copyright (C) 2004-2007 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_EXTENSION_PROPER_H_ +#define _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_ + +/** + * @file extension.h + * @brief Sample extension code header. + */ + +#include "smsdk_ext.h" + + +/** + * @brief Sample implementation of the SDK Extension. + * Note: Uncomment one of the pre-defined virtual functions in order to use it. + */ +class RegexExtension : public SDKExtension +{ +public: + /** + * @brief This is called after the initial loading sequence has been processed. + * + * @param error Error message buffer. + * @param maxlength Size of error message buffer. + * @param late Whether or not the module was loaded after map load. + * @return True to succeed loading, false to fail. + */ + virtual bool SDK_OnLoad(char *error, size_t maxlength, bool late); + + /** + * @brief This is called right before the extension is unloaded. + */ + virtual void SDK_OnUnload(); + + /** + * @brief This is called once all known extensions have been loaded. + * Note: It is is a good idea to add natives here, if any are provided. + */ + //virtual void SDK_OnAllLoaded(); + + /** + * @brief Called when the pause state is changed. + */ + //virtual void SDK_OnPauseChange(bool paused); + + /** + * @brief this is called when Core wants to know if your extension is working. + * + * @param error Error message buffer. + * @param maxlength Size of error message buffer. + * @return True if working, false otherwise. + */ + //virtual bool QueryRunning(char *error, size_t maxlength); +public: +#if defined SMEXT_CONF_METAMOD + /** + * @brief Called when Metamod is attached, before the extension version is called. + * + * @param error Error buffer. + * @param maxlength Maximum size of error buffer. + * @param late Whether or not Metamod considers this a late load. + * @return True to succeed, false to fail. + */ + //virtual bool SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlength, bool late); + + /** + * @brief Called when Metamod is detaching, after the extension version is called. + * NOTE: By default this is blocked unless sent from SourceMod. + * + * @param error Error buffer. + * @param maxlength Maximum size of error buffer. + * @return True to succeed, false to fail. + */ + //virtual bool SDK_OnMetamodUnload(char *error, size_t maxlength); + + /** + * @brief Called when Metamod's pause state is changing. + * NOTE: By default this is blocked unless sent from SourceMod. + * + * @param paused Pause state being set. + * @param error Error buffer. + * @param maxlength Maximum size of error buffer. + * @return True to succeed, false to fail. + */ + //virtual bool SDK_OnMetamodPauseChange(bool paused, char *error, size_t maxlength); +#endif +}; + + +class RegexHandler: public IHandleTypeDispatch +{ +public: + void OnHandleDestroy(HandleType_t type, void *object); +}; + +extern RegexHandler g_RegexHandler; +extern HandleType_t g_RegexHandle; + + +// Natives +extern const sp_nativeinfo_t regex_natives[]; + +#endif // _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_ diff --git a/extensions/regex/lib_linux/libpcre.a b/extensions/regex/lib_linux/libpcre.a new file mode 100644 index 00000000..e8f6fbde Binary files /dev/null and b/extensions/regex/lib_linux/libpcre.a differ diff --git a/extensions/regex/lib_win/pcre.lib b/extensions/regex/lib_win/pcre.lib new file mode 100644 index 00000000..0fb8eeaa Binary files /dev/null and b/extensions/regex/lib_win/pcre.lib differ diff --git a/extensions/regex/msvc8/regex.sln b/extensions/regex/msvc8/regex.sln new file mode 100644 index 00000000..1126def0 --- /dev/null +++ b/extensions/regex/msvc8/regex.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "regex", "regex.vcproj", "{B3E797CF-4E77-4C9D-B8A8-7589B6902206}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Debug|Win32.ActiveCfg = Debug|Win32 + {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Debug|Win32.Build.0 = Debug|Win32 + {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Release|Win32.ActiveCfg = Release|Win32 + {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/extensions/regex/msvc8/regex.vcproj b/extensions/regex/msvc8/regex.vcproj new file mode 100644 index 00000000..e61748d7 --- /dev/null +++ b/extensions/regex/msvc8/regex.vcproj @@ -0,0 +1,243 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/extensions/regex/pcre.h b/extensions/regex/pcre.h new file mode 100644 index 00000000..77720e1c --- /dev/null +++ b/extensions/regex/pcre.h @@ -0,0 +1,305 @@ +/************************************************* +* Perl-Compatible Regular Expressions * +*************************************************/ + +/* This is the public header file for the PCRE library, to be #included by +applications that call the PCRE functions. + + Copyright (c) 1997-2007 University of Cambridge + +----------------------------------------------------------------------------- +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of the University of Cambridge nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +----------------------------------------------------------------------------- +*/ + +#ifndef _PCRE_H +#define _PCRE_H + +/* The current PCRE version information. */ + +#define PCRE_MAJOR 7 +#define PCRE_MINOR 4 +#define PCRE_PRERELEASE +#define PCRE_DATE 2007-09-21 + +/* When an application links to a PCRE DLL in Windows, the symbols that are +imported have to be identified as such. When building PCRE, the appropriate +export setting is defined in pcre_internal.h, which includes this file. So we +don't change existing definitions of PCRE_EXP_DECL and PCRECPP_EXP_DECL. */ + +#define PCRE_STATIC + +#if defined(_WIN32) && !defined(PCRE_STATIC) +# ifndef PCRE_EXP_DECL +# define PCRE_EXP_DECL extern __declspec(dllimport) +# endif +# ifdef __cplusplus +# ifndef PCRECPP_EXP_DECL +# define PCRECPP_EXP_DECL extern __declspec(dllimport) +# endif +# ifndef PCRECPP_EXP_DEFN +# define PCRECPP_EXP_DEFN __declspec(dllimport) +# endif +# endif +#endif + +/* By default, we use the standard "extern" declarations. */ + +#ifndef PCRE_EXP_DECL +# ifdef __cplusplus +# define PCRE_EXP_DECL extern "C" +# else +# define PCRE_EXP_DECL extern +# endif +#endif + +#ifdef __cplusplus +# ifndef PCRECPP_EXP_DECL +# define PCRECPP_EXP_DECL extern +# endif +# ifndef PCRECPP_EXP_DEFN +# define PCRECPP_EXP_DEFN +# endif +#endif + +/* Have to include stdlib.h in order to ensure that size_t is defined; +it is needed here for malloc. */ + +#include + +/* Allow for C++ users */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Options */ + +#define PCRE_CASELESS 0x00000001 +#define PCRE_MULTILINE 0x00000002 +#define PCRE_DOTALL 0x00000004 +#define PCRE_EXTENDED 0x00000008 +#define PCRE_ANCHORED 0x00000010 +#define PCRE_DOLLAR_ENDONLY 0x00000020 +#define PCRE_EXTRA 0x00000040 +#define PCRE_NOTBOL 0x00000080 +#define PCRE_NOTEOL 0x00000100 +#define PCRE_UNGREEDY 0x00000200 +#define PCRE_NOTEMPTY 0x00000400 +#define PCRE_UTF8 0x00000800 +#define PCRE_NO_AUTO_CAPTURE 0x00001000 +#define PCRE_NO_UTF8_CHECK 0x00002000 +#define PCRE_AUTO_CALLOUT 0x00004000 +#define PCRE_PARTIAL 0x00008000 +#define PCRE_DFA_SHORTEST 0x00010000 +#define PCRE_DFA_RESTART 0x00020000 +#define PCRE_FIRSTLINE 0x00040000 +#define PCRE_DUPNAMES 0x00080000 +#define PCRE_NEWLINE_CR 0x00100000 +#define PCRE_NEWLINE_LF 0x00200000 +#define PCRE_NEWLINE_CRLF 0x00300000 +#define PCRE_NEWLINE_ANY 0x00400000 +#define PCRE_NEWLINE_ANYCRLF 0x00500000 +#define PCRE_BSR_ANYCRLF 0x00800000 +#define PCRE_BSR_UNICODE 0x01000000 + +/* Exec-time and get/set-time error codes */ + +#define PCRE_ERROR_NOMATCH (-1) +#define PCRE_ERROR_NULL (-2) +#define PCRE_ERROR_BADOPTION (-3) +#define PCRE_ERROR_BADMAGIC (-4) +#define PCRE_ERROR_UNKNOWN_OPCODE (-5) +#define PCRE_ERROR_UNKNOWN_NODE (-5) /* For backward compatibility */ +#define PCRE_ERROR_NOMEMORY (-6) +#define PCRE_ERROR_NOSUBSTRING (-7) +#define PCRE_ERROR_MATCHLIMIT (-8) +#define PCRE_ERROR_CALLOUT (-9) /* Never used by PCRE itself */ +#define PCRE_ERROR_BADUTF8 (-10) +#define PCRE_ERROR_BADUTF8_OFFSET (-11) +#define PCRE_ERROR_PARTIAL (-12) +#define PCRE_ERROR_BADPARTIAL (-13) +#define PCRE_ERROR_INTERNAL (-14) +#define PCRE_ERROR_BADCOUNT (-15) +#define PCRE_ERROR_DFA_UITEM (-16) +#define PCRE_ERROR_DFA_UCOND (-17) +#define PCRE_ERROR_DFA_UMLIMIT (-18) +#define PCRE_ERROR_DFA_WSSIZE (-19) +#define PCRE_ERROR_DFA_RECURSE (-20) +#define PCRE_ERROR_RECURSIONLIMIT (-21) +#define PCRE_ERROR_NULLWSLIMIT (-22) /* No longer actually used */ +#define PCRE_ERROR_BADNEWLINE (-23) + +/* Request types for pcre_fullinfo() */ + +#define PCRE_INFO_OPTIONS 0 +#define PCRE_INFO_SIZE 1 +#define PCRE_INFO_CAPTURECOUNT 2 +#define PCRE_INFO_BACKREFMAX 3 +#define PCRE_INFO_FIRSTBYTE 4 +#define PCRE_INFO_FIRSTCHAR 4 /* For backwards compatibility */ +#define PCRE_INFO_FIRSTTABLE 5 +#define PCRE_INFO_LASTLITERAL 6 +#define PCRE_INFO_NAMEENTRYSIZE 7 +#define PCRE_INFO_NAMECOUNT 8 +#define PCRE_INFO_NAMETABLE 9 +#define PCRE_INFO_STUDYSIZE 10 +#define PCRE_INFO_DEFAULT_TABLES 11 +#define PCRE_INFO_OKPARTIAL 12 +#define PCRE_INFO_JCHANGED 13 +#define PCRE_INFO_HASCRORLF 14 + +/* Request types for pcre_config(). Do not re-arrange, in order to remain +compatible. */ + +#define PCRE_CONFIG_UTF8 0 +#define PCRE_CONFIG_NEWLINE 1 +#define PCRE_CONFIG_LINK_SIZE 2 +#define PCRE_CONFIG_POSIX_MALLOC_THRESHOLD 3 +#define PCRE_CONFIG_MATCH_LIMIT 4 +#define PCRE_CONFIG_STACKRECURSE 5 +#define PCRE_CONFIG_UNICODE_PROPERTIES 6 +#define PCRE_CONFIG_MATCH_LIMIT_RECURSION 7 +#define PCRE_CONFIG_BSR 8 + +/* Bit flags for the pcre_extra structure. Do not re-arrange or redefine +these bits, just add new ones on the end, in order to remain compatible. */ + +#define PCRE_EXTRA_STUDY_DATA 0x0001 +#define PCRE_EXTRA_MATCH_LIMIT 0x0002 +#define PCRE_EXTRA_CALLOUT_DATA 0x0004 +#define PCRE_EXTRA_TABLES 0x0008 +#define PCRE_EXTRA_MATCH_LIMIT_RECURSION 0x0010 + +/* Types */ + +struct real_pcre; /* declaration; the definition is private */ +typedef struct real_pcre pcre; + +/* When PCRE is compiled as a C++ library, the subject pointer type can be +replaced with a custom type. For conventional use, the public interface is a +const char *. */ + +#ifndef PCRE_SPTR +#define PCRE_SPTR const char * +#endif + +/* The structure for passing additional data to pcre_exec(). This is defined in +such as way as to be extensible. Always add new fields at the end, in order to +remain compatible. */ + +typedef struct pcre_extra { + unsigned long int flags; /* Bits for which fields are set */ + void *study_data; /* Opaque data from pcre_study() */ + unsigned long int match_limit; /* Maximum number of calls to match() */ + void *callout_data; /* Data passed back in callouts */ + const unsigned char *tables; /* Pointer to character tables */ + unsigned long int match_limit_recursion; /* Max recursive calls to match() */ +} pcre_extra; + +/* The structure for passing out data via the pcre_callout_function. We use a +structure so that new fields can be added on the end in future versions, +without changing the API of the function, thereby allowing old clients to work +without modification. */ + +typedef struct pcre_callout_block { + int version; /* Identifies version of block */ + /* ------------------------ Version 0 ------------------------------- */ + int callout_number; /* Number compiled into pattern */ + int *offset_vector; /* The offset vector */ + PCRE_SPTR subject; /* The subject being matched */ + int subject_length; /* The length of the subject */ + int start_match; /* Offset to start of this match attempt */ + int current_position; /* Where we currently are in the subject */ + int capture_top; /* Max current capture */ + int capture_last; /* Most recently closed capture */ + void *callout_data; /* Data passed in with the call */ + /* ------------------- Added for Version 1 -------------------------- */ + int pattern_position; /* Offset to next item in the pattern */ + int next_item_length; /* Length of next item in the pattern */ + /* ------------------------------------------------------------------ */ +} pcre_callout_block; + +/* Indirection for store get and free functions. These can be set to +alternative malloc/free functions if required. Special ones are used in the +non-recursive case for "frames". There is also an optional callout function +that is triggered by the (?) regex item. For Virtual Pascal, these definitions +have to take another form. */ + +#ifndef VPCOMPAT +PCRE_EXP_DECL void *(*pcre_malloc)(size_t); +PCRE_EXP_DECL void (*pcre_free)(void *); +PCRE_EXP_DECL void *(*pcre_stack_malloc)(size_t); +PCRE_EXP_DECL void (*pcre_stack_free)(void *); +PCRE_EXP_DECL int (*pcre_callout)(pcre_callout_block *); +#else /* VPCOMPAT */ +PCRE_EXP_DECL void *pcre_malloc(size_t); +PCRE_EXP_DECL void pcre_free(void *); +PCRE_EXP_DECL void *pcre_stack_malloc(size_t); +PCRE_EXP_DECL void pcre_stack_free(void *); +PCRE_EXP_DECL int pcre_callout(pcre_callout_block *); +#endif /* VPCOMPAT */ + +/* Exported PCRE functions */ + +PCRE_EXP_DECL pcre *pcre_compile(const char *, int, const char **, int *, + const unsigned char *); +PCRE_EXP_DECL pcre *pcre_compile2(const char *, int, int *, const char **, + int *, const unsigned char *); +PCRE_EXP_DECL int pcre_config(int, void *); +PCRE_EXP_DECL int pcre_copy_named_substring(const pcre *, const char *, + int *, int, const char *, char *, int); +PCRE_EXP_DECL int pcre_copy_substring(const char *, int *, int, int, char *, + int); +PCRE_EXP_DECL int pcre_dfa_exec(const pcre *, const pcre_extra *, + const char *, int, int, int, int *, int , int *, int); +PCRE_EXP_DECL int pcre_exec(const pcre *, const pcre_extra *, PCRE_SPTR, + int, int, int, int *, int); +PCRE_EXP_DECL void pcre_free_substring(const char *); +PCRE_EXP_DECL void pcre_free_substring_list(const char **); +PCRE_EXP_DECL int pcre_fullinfo(const pcre *, const pcre_extra *, int, + void *); +PCRE_EXP_DECL int pcre_get_named_substring(const pcre *, const char *, + int *, int, const char *, const char **); +PCRE_EXP_DECL int pcre_get_stringnumber(const pcre *, const char *); +PCRE_EXP_DECL int pcre_get_stringtable_entries(const pcre *, const char *, + char **, char **); +PCRE_EXP_DECL int pcre_get_substring(const char *, int *, int, int, + const char **); +PCRE_EXP_DECL int pcre_get_substring_list(const char *, int *, int, + const char ***); +PCRE_EXP_DECL int pcre_info(const pcre *, int *, int *); +PCRE_EXP_DECL const unsigned char *pcre_maketables(void); +PCRE_EXP_DECL int pcre_refcount(pcre *, int); +PCRE_EXP_DECL pcre_extra *pcre_study(const pcre *, int, const char **); +PCRE_EXP_DECL const char *pcre_version(void); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* End of pcre.h */ diff --git a/extensions/regex/sdk/smsdk_config.h b/extensions/regex/sdk/smsdk_config.h new file mode 100644 index 00000000..1cde4726 --- /dev/null +++ b/extensions/regex/sdk/smsdk_config.h @@ -0,0 +1,79 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod Sample Extension + * Copyright (C) 2004-2007 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_EXTENSION_CONFIG_H_ +#define _INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_ + +/** + * @file smsdk_config.h + * @brief Contains macros for configuring basic extension information. + */ + +/* Basic information exposed publicly */ +#define SMEXT_CONF_NAME "Regex" +#define SMEXT_CONF_DESCRIPTION "Provides regex natives for plugins" +#define SMEXT_CONF_VERSION "SVN_FULL_VERSION" +#define SMEXT_CONF_AUTHOR "AlliedModders LLC" +#define SMEXT_CONF_URL "http://www.sourcemod.net/" +#define SMEXT_CONF_LOGTAG "REGEX" +#define SMEXT_CONF_LICENSE "GPL" +#define SMEXT_CONF_DATESTRING __DATE__ + +/** + * @brief Exposes plugin's main interface. + */ +#define SMEXT_LINK(name) SDKExtension *g_pExtensionIface = name; + +/** + * @brief Sets whether or not this plugin required Metamod. + * NOTE: Uncomment to enable, comment to disable. + */ +//#define SMEXT_CONF_METAMOD + +/** Enable interfaces you want to use here by uncommenting lines */ +//#define SMEXT_ENABLE_FORWARDSYS +#define SMEXT_ENABLE_HANDLESYS +//#define SMEXT_ENABLE_PLAYERHELPERS +//#define SMEXT_ENABLE_DBMANAGER +//#define SMEXT_ENABLE_GAMECONF +//#define SMEXT_ENABLE_MEMUTILS +//#define SMEXT_ENABLE_GAMEHELPERS +//#define SMEXT_ENABLE_TIMERSYS +//#define SMEXT_ENABLE_THREADER +//#define SMEXT_ENABLE_LIBSYS +//#define SMEXT_ENABLE_MENUS +//#define SMEXT_ENABLE_ADTFACTORY +//#define SMEXT_ENABLE_PLUGINSYS +//#define SMEXT_ENABLE_ADMINSYS +//#define SMEXT_ENABLE_TEXTPARSERS +//#define SMEXT_ENABLE_USERMSGS + +#endif // _INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_ diff --git a/extensions/regex/sdk/smsdk_ext.cpp b/extensions/regex/sdk/smsdk_ext.cpp new file mode 100644 index 00000000..0c728f00 --- /dev/null +++ b/extensions/regex/sdk/smsdk_ext.cpp @@ -0,0 +1,455 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod Base Extension Code + * Copyright (C) 2004-2007 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 +#include +#include "smsdk_ext.h" + +/** + * @file smsdk_ext.cpp + * @brief Contains wrappers for making Extensions easier to write. + */ + +IExtension *myself = NULL; /**< Ourself */ +IShareSys *g_pShareSys = NULL; /**< Share system */ +IShareSys *sharesys = NULL; /**< Share system */ +ISourceMod *g_pSM = NULL; /**< SourceMod helpers */ +ISourceMod *smutils = NULL; /**< SourceMod helpers */ + +#if defined SMEXT_ENABLE_FORWARDSYS +IForwardManager *g_pForwards = NULL; /**< Forward system */ +IForwardManager *forwards = NULL; /**< Forward system */ +#endif +#if defined SMEXT_ENABLE_HANDLESYS +IHandleSys *g_pHandleSys = NULL; /**< Handle system */ +IHandleSys *handlesys = NULL; /**< Handle system */ +#endif +#if defined SMEXT_ENABLE_PLAYERHELPERS +IPlayerManager *playerhelpers = NULL; /**< Player helpers */ +#endif //SMEXT_ENABLE_PLAYERHELPERS +#if defined SMEXT_ENABLE_DBMANAGER +IDBManager *dbi = NULL; /**< DB Manager */ +#endif //SMEXT_ENABLE_DBMANAGER +#if defined SMEXT_ENABLE_GAMECONF +IGameConfigManager *gameconfs = NULL; /**< Game config manager */ +#endif //SMEXT_ENABLE_DBMANAGER +#if defined SMEXT_ENABLE_MEMUTILS +IMemoryUtils *memutils = NULL; +#endif //SMEXT_ENABLE_DBMANAGER +#if defined SMEXT_ENABLE_GAMEHELPERS +IGameHelpers *gamehelpers = NULL; +#endif +#if defined SMEXT_ENABLE_TIMERSYS +ITimerSystem *timersys = NULL; +#endif +#if defined SMEXT_ENABLE_ADTFACTORY +IADTFactory *adtfactory = NULL; +#endif +#if defined SMEXT_ENABLE_THREADER +IThreader *threader = NULL; +#endif +#if defined SMEXT_ENABLE_LIBSYS +ILibrarySys *libsys = NULL; +#endif +#if defined SMEXT_ENABLE_PLUGINSYS +SourceMod::IPluginManager *plsys; +#endif +#if defined SMEXT_ENABLE_MENUS +IMenuManager *menus = NULL; +#endif +#if defined SMEXT_ENABLE_ADMINSYS +IAdminSystem *adminsys = NULL; +#endif +#if defined SMEXT_ENABLE_TEXTPARSERS +ITextParsers *textparsers = NULL; +#endif +#if defined SMEXT_ENABLE_USERMSGS +IUserMessages *usermsgs = NULL; +#endif + +/** Exports the main interface */ +PLATFORM_EXTERN_C IExtensionInterface *GetSMExtAPI() +{ + return g_pExtensionIface; +} + +SDKExtension::SDKExtension() +{ +#if defined SMEXT_CONF_METAMOD + m_SourceMMLoaded = false; + m_WeAreUnloaded = false; + m_WeGotPauseChange = false; +#endif +} + +bool SDKExtension::OnExtensionLoad(IExtension *me, IShareSys *sys, char *error, size_t maxlength, bool late) +{ + g_pShareSys = sharesys = sys; + myself = me; + +#if defined SMEXT_CONF_METAMOD + m_WeAreUnloaded = true; + + if (!m_SourceMMLoaded) + { + if (error) + { + snprintf(error, maxlength, "Metamod attach failed"); + } + return false; + } +#endif + SM_GET_IFACE(SOURCEMOD, g_pSM); + smutils = g_pSM; +#if defined SMEXT_ENABLE_HANDLESYS + SM_GET_IFACE(HANDLESYSTEM, g_pHandleSys); + handlesys = g_pHandleSys; +#endif +#if defined SMEXT_ENABLE_FORWARDSYS + SM_GET_IFACE(FORWARDMANAGER, g_pForwards); + forwards = g_pForwards; +#endif +#if defined SMEXT_ENABLE_PLAYERHELPERS + SM_GET_IFACE(PLAYERMANAGER, playerhelpers); +#endif +#if defined SMEXT_ENABLE_DBMANAGER + SM_GET_IFACE(DBI, dbi); +#endif +#if defined SMEXT_ENABLE_GAMECONF + SM_GET_IFACE(GAMECONFIG, gameconfs); +#endif +#if defined SMEXT_ENABLE_MEMUTILS + SM_GET_IFACE(MEMORYUTILS, memutils); +#endif +#if defined SMEXT_ENABLE_GAMEHELPERS + SM_GET_IFACE(GAMEHELPERS, gamehelpers); +#endif +#if defined SMEXT_ENABLE_TIMERSYS + SM_GET_IFACE(TIMERSYS, timersys); +#endif +#if defined SMEXT_ENABLE_ADTFACTORY + SM_GET_IFACE(ADTFACTORY, adtfactory); +#endif +#if defined SMEXT_ENABLE_THREADER + SM_GET_IFACE(THREADER, threader); +#endif +#if defined SMEXT_ENABLE_LIBSYS + SM_GET_IFACE(LIBRARYSYS, libsys); +#endif +#if defined SMEXT_ENABLE_PLUGINSYS + SM_GET_IFACE(PLUGINSYSTEM, plsys); +#endif +#if defined SMEXT_ENABLE_MENUS + SM_GET_IFACE(MENUMANAGER, menus); +#endif +#if defined SMEXT_ENABLE_ADMINSYS + SM_GET_IFACE(ADMINSYS, adminsys); +#endif +#if defined SMEXT_ENABLE_TEXTPARSERS + SM_GET_IFACE(TEXTPARSERS, textparsers); +#endif +#if defined SMEXT_ENABLE_USERMSGS + SM_GET_IFACE(USERMSGS, usermsgs); +#endif + + if (SDK_OnLoad(error, maxlength, late)) + { +#if defined SMEXT_CONF_METAMOD + m_WeAreUnloaded = true; +#endif + return true; + } + + return false; +} + +bool SDKExtension::IsMetamodExtension() +{ +#if defined SMEXT_CONF_METAMOD + return true; +#else + return false; +#endif +} + +void SDKExtension::OnExtensionPauseChange(bool state) +{ +#if defined SMEXT_CONF_METAMOD + m_WeGotPauseChange = true; +#endif + SDK_OnPauseChange(state); +} + +void SDKExtension::OnExtensionsAllLoaded() +{ + SDK_OnAllLoaded(); +} + +void SDKExtension::OnExtensionUnload() +{ +#if defined SMEXT_CONF_METAMOD + m_WeAreUnloaded = true; +#endif + SDK_OnUnload(); +} + +const char *SDKExtension::GetExtensionAuthor() +{ + return SMEXT_CONF_AUTHOR; +} + +const char *SDKExtension::GetExtensionDateString() +{ + return SMEXT_CONF_DATESTRING; +} + +const char *SDKExtension::GetExtensionDescription() +{ + return SMEXT_CONF_DESCRIPTION; +} + +const char *SDKExtension::GetExtensionVerString() +{ + return SMEXT_CONF_VERSION; +} + +const char *SDKExtension::GetExtensionName() +{ + return SMEXT_CONF_NAME; +} + +const char *SDKExtension::GetExtensionTag() +{ + return SMEXT_CONF_LOGTAG; +} + +const char *SDKExtension::GetExtensionURL() +{ + return SMEXT_CONF_URL; +} + +bool SDKExtension::SDK_OnLoad(char *error, size_t maxlength, bool late) +{ + return true; +} + +void SDKExtension::SDK_OnUnload() +{ +} + +void SDKExtension::SDK_OnPauseChange(bool paused) +{ +} + +void SDKExtension::SDK_OnAllLoaded() +{ +} + +#if defined SMEXT_CONF_METAMOD + +PluginId g_PLID = 0; /**< Metamod plugin ID */ +ISmmPlugin *g_PLAPI = NULL; /**< Metamod plugin API */ +SourceHook::ISourceHook *g_SHPtr = NULL; /**< SourceHook pointer */ +ISmmAPI *g_SMAPI = NULL; /**< SourceMM API pointer */ + +IVEngineServer *engine = NULL; /**< IVEngineServer pointer */ +IServerGameDLL *gamedll = NULL; /**< IServerGameDLL pointer */ + +/** Exposes the extension to Metamod */ +SMM_API void *PL_EXPOSURE(const char *name, int *code) +{ +#if defined METAMOD_PLAPI_VERSION + if (name && !strcmp(name, METAMOD_PLAPI_NAME)) +#else + if (name && !strcmp(name, PLAPI_NAME)) +#endif + { + if (code) + { + *code = IFACE_OK; + } + return static_cast(g_pExtensionIface); + } + + if (code) + { + *code = IFACE_FAILED; + } + + return NULL; +} + +bool SDKExtension::Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen, bool late) +{ + PLUGIN_SAVEVARS(); + +#if defined METAMOD_PLAPI_VERSION + GET_V_IFACE_ANY(serverFactory, gamedll, IServerGameDLL, INTERFACEVERSION_SERVERGAMEDLL); + GET_V_IFACE_CURRENT(engineFactory, engine, IVEngineServer, INTERFACEVERSION_VENGINESERVER); +#else + GET_V_IFACE_ANY(GetServerFactory, gamedll, IServerGameDLL, INTERFACEVERSION_SERVERGAMEDLL); + GET_V_IFACE_CURRENT(GetEngineFactory, engine, IVEngineServer, INTERFACEVERSION_VENGINESERVER); +#endif + + m_SourceMMLoaded = true; + + return SDK_OnMetamodLoad(ismm, error, maxlen, late); +} + +bool SDKExtension::Unload(char *error, size_t maxlen) +{ + if (!m_WeAreUnloaded) + { + if (error) + { + snprintf(error, maxlen, "This extension must be unloaded by SourceMod."); + } + return false; + } + + return SDK_OnMetamodUnload(error, maxlen); +} + +bool SDKExtension::Pause(char *error, size_t maxlen) +{ + if (!m_WeGotPauseChange) + { + if (error) + { + snprintf(error, maxlen, "This extension must be paused by SourceMod."); + } + return false; + } + + m_WeGotPauseChange = false; + + return SDK_OnMetamodPauseChange(true, error, maxlen); +} + +bool SDKExtension::Unpause(char *error, size_t maxlen) +{ + if (!m_WeGotPauseChange) + { + if (error) + { + snprintf(error, maxlen, "This extension must be unpaused by SourceMod."); + } + return false; + } + + m_WeGotPauseChange = false; + + return SDK_OnMetamodPauseChange(false, error, maxlen); +} + +const char *SDKExtension::GetAuthor() +{ + return GetExtensionAuthor(); +} + +const char *SDKExtension::GetDate() +{ + return GetExtensionDateString(); +} + +const char *SDKExtension::GetDescription() +{ + return GetExtensionDescription(); +} + +const char *SDKExtension::GetLicense() +{ + return SMEXT_CONF_LICENSE; +} + +const char *SDKExtension::GetLogTag() +{ + return GetExtensionTag(); +} + +const char *SDKExtension::GetName() +{ + return GetExtensionName(); +} + +const char *SDKExtension::GetURL() +{ + return GetExtensionURL(); +} + +const char *SDKExtension::GetVersion() +{ + return GetExtensionVerString(); +} + +bool SDKExtension::SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlength, bool late) +{ + return true; +} + +bool SDKExtension::SDK_OnMetamodUnload(char *error, size_t maxlength) +{ + return true; +} + +bool SDKExtension::SDK_OnMetamodPauseChange(bool paused, char *error, size_t maxlength) +{ + return true; +} + +#endif + +/* Overload a few things to prevent libstdc++ linking */ +#if defined __linux__ +extern "C" void __cxa_pure_virtual(void) +{ +} + +void *operator new(size_t size) +{ + return malloc(size); +} + +void *operator new[](size_t size) +{ + return malloc(size); +} + +void operator delete(void *ptr) +{ + free(ptr); +} + +void operator delete[](void * ptr) +{ + free(ptr); +} +#endif diff --git a/extensions/regex/sdk/smsdk_ext.h b/extensions/regex/sdk/smsdk_ext.h new file mode 100644 index 00000000..4702f2a2 --- /dev/null +++ b/extensions/regex/sdk/smsdk_ext.h @@ -0,0 +1,327 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod Base Extension Code + * Copyright (C) 2004-2007 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_EXTENSION_BASESDK_H_ +#define _INCLUDE_SOURCEMOD_EXTENSION_BASESDK_H_ + +/** + * @file smsdk_ext.h + * @brief Contains wrappers for making Extensions easier to write. + */ + +#include "smsdk_config.h" +#include +#include +#include +#include +#include +#if defined SMEXT_ENABLE_FORWARDSYS +#include +#endif //SMEXT_ENABLE_FORWARDSYS +#if defined SMEXT_ENABLE_PLAYERHELPERS +#include +#endif //SMEXT_ENABLE_PlAYERHELPERS +#if defined SMEXT_ENABLE_DBMANAGER +#include +#endif //SMEXT_ENABLE_DBMANAGER +#if defined SMEXT_ENABLE_GAMECONF +#include +#endif +#if defined SMEXT_ENABLE_MEMUTILS +#include +#endif +#if defined SMEXT_ENABLE_GAMEHELPERS +#include +#endif +#if defined SMEXT_ENABLE_TIMERSYS +#include +#endif +#if defined SMEXT_ENABLE_ADTFACTORY +#include +#endif +#if defined SMEXT_ENABLE_THREADER +#include +#endif +#if defined SMEXT_ENABLE_LIBSYS +#include +#endif +#if defined SMEXT_ENABLE_PLUGINSYS +#include +#endif +#if defined SMEXT_ENABLE_MENUS +#include +#endif +#if defined SMEXT_ENABLE_ADMINSYS +#include +#endif +#if defined SMEXT_ENABLE_TEXTPARSERS +#include +#endif +#if defined SMEXT_ENABLE_USERMSGS +#include +#endif + +#if defined SMEXT_CONF_METAMOD +#include +#include +#endif + +using namespace SourceMod; +using namespace SourcePawn; + +class SDKExtension : +#if defined SMEXT_CONF_METAMOD + public ISmmPlugin, +#endif + public IExtensionInterface +{ +public: + /** Constructor */ + SDKExtension(); +public: + /** + * @brief This is called after the initial loading sequence has been processed. + * + * @param error Error message buffer. + * @param maxlength Size of error message buffer. + * @param late Whether or not the module was loaded after map load. + * @return True to succeed loading, false to fail. + */ + virtual bool SDK_OnLoad(char *error, size_t maxlength, bool late); + + /** + * @brief This is called right before the extension is unloaded. + */ + virtual void SDK_OnUnload(); + + /** + * @brief This is called once all known extensions have been loaded. + */ + virtual void SDK_OnAllLoaded(); + + /** + * @brief Called when the pause state is changed. + */ + virtual void SDK_OnPauseChange(bool paused); + +#if defined SMEXT_CONF_METAMOD + /** + * @brief Called when Metamod is attached, before the extension version is called. + * + * @param error Error buffer. + * @param maxlength Maximum size of error buffer. + * @param late Whether or not Metamod considers this a late load. + * @return True to succeed, false to fail. + */ + virtual bool SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlength, bool late); + + /** + * @brief Called when Metamod is detaching, after the extension version is called. + * NOTE: By default this is blocked unless sent from SourceMod. + * + * @param error Error buffer. + * @param maxlength Maximum size of error buffer. + * @return True to succeed, false to fail. + */ + virtual bool SDK_OnMetamodUnload(char *error, size_t maxlength); + + /** + * @brief Called when Metamod's pause state is changing. + * NOTE: By default this is blocked unless sent from SourceMod. + * + * @param paused Pause state being set. + * @param error Error buffer. + * @param maxlength Maximum size of error buffer. + * @return True to succeed, false to fail. + */ + virtual bool SDK_OnMetamodPauseChange(bool paused, char *error, size_t maxlength); +#endif + +public: //IExtensionInterface + virtual bool OnExtensionLoad(IExtension *me, IShareSys *sys, char *error, size_t maxlength, bool late); + virtual void OnExtensionUnload(); + virtual void OnExtensionsAllLoaded(); + + /** Returns whether or not this is a Metamod-based extension */ + virtual bool IsMetamodExtension(); + + /** + * @brief Called when the pause state changes. + * + * @param state True if being paused, false if being unpaused. + */ + virtual void OnExtensionPauseChange(bool state); + + /** Returns name */ + virtual const char *GetExtensionName(); + /** Returns URL */ + virtual const char *GetExtensionURL(); + /** Returns log tag */ + virtual const char *GetExtensionTag(); + /** Returns author */ + virtual const char *GetExtensionAuthor(); + /** Returns version string */ + virtual const char *GetExtensionVerString(); + /** Returns description string */ + virtual const char *GetExtensionDescription(); + /** Returns date string */ + virtual const char *GetExtensionDateString(); +#if defined SMEXT_CONF_METAMOD +public: //ISmmPlugin + /** Called when the extension is attached to Metamod. */ + virtual bool Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlength, bool late); + /** Returns the author to MM */ + virtual const char *GetAuthor(); + /** Returns the name to MM */ + virtual const char *GetName(); + /** Returns the description to MM */ + virtual const char *GetDescription(); + /** Returns the URL to MM */ + virtual const char *GetURL(); + /** Returns the license to MM */ + virtual const char *GetLicense(); + /** Returns the version string to MM */ + virtual const char *GetVersion(); + /** Returns the date string to MM */ + virtual const char *GetDate(); + /** Returns the logtag to MM */ + virtual const char *GetLogTag(); + /** Called on unload */ + virtual bool Unload(char *error, size_t maxlength); + /** Called on pause */ + virtual bool Pause(char *error, size_t maxlength); + /** Called on unpause */ + virtual bool Unpause(char *error, size_t maxlength); +private: + bool m_SourceMMLoaded; + bool m_WeAreUnloaded; + bool m_WeGotPauseChange; +#endif +}; + +extern SDKExtension *g_pExtensionIface; +extern IExtension *myself; + +extern IShareSys *g_pShareSys; +extern IShareSys *sharesys; /* Note: Newer name */ +extern ISourceMod *g_pSM; +extern ISourceMod *smutils; /* Note: Newer name */ + +/* Optional interfaces are below */ +#if defined SMEXT_ENABLE_FORWARDSYS +extern IForwardManager *g_pForwards; +extern IForwardManager *forwards; /* Note: Newer name */ +#endif //SMEXT_ENABLE_FORWARDSYS +#if defined SMEXT_ENABLE_HANDLESYS +extern IHandleSys *g_pHandleSys; +extern IHandleSys *handlesys; /* Note: Newer name */ +#endif //SMEXT_ENABLE_HANDLESYS +#if defined SMEXT_ENABLE_PLAYERHELPERS +extern IPlayerManager *playerhelpers; +#endif //SMEXT_ENABLE_PLAYERHELPERS +#if defined SMEXT_ENABLE_DBMANAGER +extern IDBManager *dbi; +#endif //SMEXT_ENABLE_DBMANAGER +#if defined SMEXT_ENABLE_GAMECONF +extern IGameConfigManager *gameconfs; +#endif //SMEXT_ENABLE_DBMANAGER +#if defined SMEXT_ENABLE_MEMUTILS +extern IMemoryUtils *memutils; +#endif +#if defined SMEXT_ENABLE_GAMEHELPERS +extern IGameHelpers *gamehelpers; +#endif +#if defined SMEXT_ENABLE_TIMERSYS +extern ITimerSystem *timersys; +#endif +#if defined SMEXT_ENABLE_ADTFACTORY +extern IADTFactory *adtfactory; +#endif +#if defined SMEXT_ENABLE_THREADER +extern IThreader *threader; +#endif +#if defined SMEXT_ENABLE_LIBSYS +extern ILibrarySys *libsys; +#endif +#if defined SMEXT_ENABLE_PLUGINSYS +extern SourceMod::IPluginManager *plsys; +#endif +#if defined SMEXT_ENABLE_MENUS +extern IMenuManager *menus; +#endif +#if defined SMEXT_ENABLE_ADMINSYS +extern IAdminSystem *adminsys; +#endif +#if defined SMEXT_ENABLE_USERMSGS +extern IUserMessages *usermsgs; +#endif + +#if defined SMEXT_CONF_METAMOD +PLUGIN_GLOBALVARS(); +extern IVEngineServer *engine; +extern IServerGameDLL *gamedll; +#endif + +/** Creates a SourceMod interface macro pair */ +#define SM_MKIFACE(name) SMINTERFACE_##name##_NAME, SMINTERFACE_##name##_VERSION +/** Automates retrieving SourceMod interfaces */ +#define SM_GET_IFACE(prefix, addr) \ + if (!g_pShareSys->RequestInterface(SM_MKIFACE(prefix), myself, (SMInterface **)&addr)) \ + { \ + if (error != NULL && maxlength) \ + { \ + size_t len = snprintf(error, maxlength, "Could not find interface: %s", SMINTERFACE_##prefix##_NAME); \ + if (len >= maxlength) \ + { \ + error[maxlength - 1] = '\0'; \ + } \ + } \ + return false; \ + } +/** Automates retrieving SourceMod interfaces when needed outside of SDK_OnLoad() */ +#define SM_GET_LATE_IFACE(prefix, addr) \ + g_pShareSys->RequestInterface(SM_MKIFACE(prefix), myself, (SMInterface **)&addr) +/** Validates a SourceMod interface pointer */ +#define SM_CHECK_IFACE(prefix, addr) \ + if (!addr) \ + { \ + if (error != NULL && maxlength) \ + { \ + size_t len = snprintf(error, maxlength, "Could not find interface: %s", SMINTERFACE_##prefix##_NAME); \ + if (len >= maxlength) \ + { \ + error[maxlength - 1] = '\0'; \ + } \ + } \ + return false; \ + } + +#endif // _INCLUDE_SOURCEMOD_EXTENSION_BASESDK_H_ diff --git a/extensions/sdktools/Makefile b/extensions/sdktools/Makefile index d02951cf..71b4e669 100644 --- a/extensions/sdktools/Makefile +++ b/extensions/sdktools/Makefile @@ -1,4 +1,4 @@ -#(C)2004-2006 SourceMM Development Team +#(C)2004-2008 Metamod:Source Development Team # Makefile written by David "BAILOPAN" Anderson HL2SDK_ORIG = ../../../hl2sdk @@ -16,7 +16,8 @@ PROJECT = sdktools OBJECTS = sdk/smsdk_ext.cpp extension.cpp vdecoder.cpp vcallbuilder.cpp vcaller.cpp \ vnatives.cpp vsound.cpp tenatives.cpp trnatives.cpp tempents.cpp vstringtable.cpp \ - vhelpers.cpp vglobals.cpp voice.cpp inputnatives.cpp teamnatives.cpp + vhelpers.cpp vglobals.cpp voice.cpp inputnatives.cpp teamnatives.cpp output.cpp \ + outputnatives.cpp detours.cpp ############################################## ### CONFIGURE ANY OTHER FLAGS/OPTIONS HERE ### @@ -104,4 +105,3 @@ clean: rm -rf $(BIN_DIR)/*.o rm -rf $(BIN_DIR)/sdk/*.o rm -rf $(BIN_DIR)/$(BINARY) - diff --git a/extensions/sdktools/detours.cpp b/extensions/sdktools/detours.cpp new file mode 100644 index 00000000..f4646009 --- /dev/null +++ b/extensions/sdktools/detours.cpp @@ -0,0 +1,39 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod SDKTools Extension + * Copyright (C) 2004-2007 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 "extension.h" +#include "output.h" + + + + + + diff --git a/extensions/sdktools/detours.h b/extensions/sdktools/detours.h new file mode 100644 index 00000000..325a4ecb --- /dev/null +++ b/extensions/sdktools/detours.h @@ -0,0 +1,98 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod SDKTools Extension + * Copyright (C) 2004-2007 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_DETOURS_H_ +#define _INCLUDE_SOURCEMOD_DETOURS_H_ + +#if defined PLATFORM_LINUX +#include +#define PAGE_SIZE 4096 +#define ALIGN(ar) ((long)ar & ~(PAGE_SIZE-1)) +#define PAGE_EXECUTE_READWRITE PROT_READ|PROT_WRITE|PROT_EXEC +#endif + +struct patch_t +{ + patch_t() + { + patch[0] = 0; + bytes = 0; + } + unsigned char patch[20]; + size_t bytes; +}; + +inline void ProtectMemory(void *addr, int length, int prot) +{ +#if defined PLATFORM_LINUX + void *addr2 = (void *)ALIGN(addr); + mprotect(addr2, sysconf(_SC_PAGESIZE), prot); +#elif defined PLATFORM_WINDOWS + DWORD old_prot; + VirtualProtect(addr, length, prot, &old_prot); +#endif +} + +inline void SetMemPatchable(void *address, size_t size) +{ + ProtectMemory(address, (int)size, PAGE_EXECUTE_READWRITE); +} + +inline void DoGatePatch(unsigned char *target, void *callback) +{ + SetMemPatchable(target, 20); + + target[0] = 0xFF; /* JMP */ + target[1] = 0x25; /* MEM32 */ + *(void **)(&target[2]) = callback; +} + +inline void ApplyPatch(void *address, int offset, const patch_t *patch, patch_t *restore) +{ + ProtectMemory(address, 20, PAGE_EXECUTE_READWRITE); + + unsigned char *addr = (unsigned char *)address + offset; + if (restore) + { + for (size_t i=0; ibytes; i++) + { + restore->patch[i] = addr[i]; + } + restore->bytes = patch->bytes; + } + + for (size_t i=0; ibytes; i++) + { + addr[i] = patch->patch[i]; + } +} + +#endif //_INCLUDE_SOURCEMOD_DETOURS_H_ diff --git a/extensions/sdktools/extension.cpp b/extensions/sdktools/extension.cpp index c01ff74a..ca87044e 100644 --- a/extensions/sdktools/extension.cpp +++ b/extensions/sdktools/extension.cpp @@ -2,7 +2,7 @@ * vim: set ts=4 : * ============================================================================= * SourceMod SDKTools Extension - * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved. + * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. * ============================================================================= * * This program is free software; you can redistribute it and/or modify it under @@ -36,6 +36,7 @@ #include "vglobals.h" #include "tempents.h" #include "vsound.h" +#include "output.h" #if defined ORANGEBOX_BUILD #define SDKTOOLS_GAME_FILE "sdktools.games.ep2" @@ -92,6 +93,7 @@ bool SDKTools::SDK_OnLoad(char *error, size_t maxlength, bool late) sharesys->AddNatives(myself, g_VoiceNatives); sharesys->AddNatives(myself, g_EntInputNatives); sharesys->AddNatives(myself, g_TeamNatives); + sharesys->AddNatives(myself, g_EntOutputNatives); SM_GET_IFACE(GAMEHELPERS, g_pGameHelpers); @@ -116,6 +118,14 @@ bool SDKTools::SDK_OnLoad(char *error, size_t maxlength, bool late) MathLib_Init(2.2f, 2.2f, 0.0f, 2); + spengine = g_pSM->GetScriptingEngine(); + + //g_OutputManager.VariantHandle = handlesys->CreateType("Variant", &g_OutputManager, 0, NULL, NULL, myself->GetIdentity(), NULL); + + plsys->AddPluginsListener(&g_OutputManager); + + g_OutputManager.Init(); + return true; } diff --git a/extensions/sdktools/extension.h b/extensions/sdktools/extension.h index c13343a9..700b73f3 100644 --- a/extensions/sdktools/extension.h +++ b/extensions/sdktools/extension.h @@ -2,7 +2,7 @@ * vim: set ts=4 : * ============================================================================= * SourceMod SDKTools Extension - * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved. + * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. * ============================================================================= * * This program is free software; you can redistribute it and/or modify it under diff --git a/extensions/sdktools/inputnatives.cpp b/extensions/sdktools/inputnatives.cpp index 86435fd1..b8b56620 100644 --- a/extensions/sdktools/inputnatives.cpp +++ b/extensions/sdktools/inputnatives.cpp @@ -2,7 +2,7 @@ * vim: set ts=4 : * ============================================================================= * SourceMod SDKTools Extension - * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved. + * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. * ============================================================================= * * This program is free software; you can redistribute it and/or modify it under diff --git a/extensions/sdktools/msvc8/sdktools.vcproj b/extensions/sdktools/msvc8/sdktools.vcproj index bc11f13a..cd0c00ea 100644 --- a/extensions/sdktools/msvc8/sdktools.vcproj +++ b/extensions/sdktools/msvc8/sdktools.vcproj @@ -16,7 +16,7 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - + + + + @@ -742,10 +591,18 @@ RelativePath="..\CellRecipientFilter.h" > + + + + @@ -796,78 +653,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - . + * + * 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 "extension.h" +#include "output.h" + +ISourcePawnEngine *spengine = NULL; +EntityOutputManager g_OutputManager; + +bool EntityOutputManager::CreateFireEventDetour() +{ + if (!g_pGameConf->GetMemSig("FireOutput", &info_address) || !info_address) + { + g_pSM->LogError(myself, "Could not locate FireOutput - Disabling Entity Outputs"); + return false; + } + + if (!g_pGameConf->GetOffset("FireOutputBackup", (int *)&(info_restore.bytes))) + { + g_pSM->LogError(myself, "Could not locate FireOutputBackup - Disabling Entity Outputs"); + return false; + } + + /* First, save restore bits */ + for (size_t i=0; iExecAlloc(100); + JitWriter wr; + JitWriter *jit = ≀ + wr.outbase = (jitcode_t)info_callback; + wr.outptr = wr.outbase; + + /* Function we are detouring into is + * + * void FireEventDetour(CBaseEntityOutput(void *) *pOutput, CBaseEntity *pActivator, CBaseEntity *pCaller, float fDelay = 0 ) + */ + + /* push fDelay [esp+20h] + * push pCaller [esp+1Ch] + * push pActivator [esp+18h] + * push pOutput [ecx] + */ + + +#if defined PLATFORM_WINDOWS + + IA32_Push_Rm_Disp8_ESP(jit, 32); + IA32_Push_Rm_Disp8_ESP(jit, 32); + IA32_Push_Rm_Disp8_ESP(jit, 32); + + /* variant_t doesnt do anything so i'll disable this bit */ + //IA32_Push_Rm_Disp8_ESP(jit, 32); + //IA32_Push_Rm_Disp8_ESP(jit, 32); + //IA32_Push_Rm_Disp8_ESP(jit, 32); + //IA32_Push_Rm_Disp8_ESP(jit, 32); + //IA32_Push_Rm_Disp8_ESP(jit, 32); + + IA32_Push_Reg(jit, REG_ECX); + +#elif defined PLATFORM_LINUX + IA32_Push_Rm_Disp8_ESP(jit, 20); + IA32_Push_Rm_Disp8_ESP(jit, 20); + IA32_Push_Rm_Disp8_ESP(jit, 20); + // We miss the variant_t pointer + IA32_Push_Rm_Disp8_ESP(jit, 16); +#endif + + jitoffs_t call = IA32_Call_Imm32(jit, 0); + IA32_Write_Jump32_Abs(jit, call, (void *)TempDetour); + + +#if defined PLATFORM_LINUX + IA32_Add_Rm_Imm8(jit, REG_ESP, 4, MOD_REG); //add esp, 4 +#elif defined PLATFORM_WINDOWS + IA32_Pop_Reg(jit, REG_ECX); +#endif + + IA32_Add_Rm_Imm8(jit, REG_ESP, 12, MOD_REG); //add esp, 12 (0Ch) + + + /* Patch old bytes in */ + for (size_t i=0; iwrite_ubyte(info_restore.patch[i]); + } + + /* Return to the original function */ + call = IA32_Jump_Imm32(jit, 0); + IA32_Write_Jump32_Abs(jit, call, (unsigned char *)info_address + info_restore.bytes); + + return true; +} + +void EntityOutputManager::InitFireEventDetour() +{ + if (!is_detoured) + { + DoGatePatch((unsigned char *)info_address, &info_callback); + is_detoured = true; + } +} + +void EntityOutputManager::DeleteFireEventDetour() +{ + if (is_detoured) + { + ShutdownFireEventDetour(); + } + + if (info_callback) + { + /* Free the gate */ + spengine->ExecFree(info_callback); + info_callback = NULL; + } +} + +void TempDetour(void *pOutput, CBaseEntity *pActivator, CBaseEntity *pCaller, float fDelay) +{ + g_OutputManager.FireEventDetour(pOutput, pActivator, pCaller, fDelay); +} + +void EntityOutputManager::ShutdownFireEventDetour() +{ + if (info_callback) + { + /* Remove the patch */ + ApplyPatch(info_address, 0, &info_restore, NULL); + is_detoured = false; + } +} + +void EntityOutputManager::FireEventDetour(void *pOutput, CBaseEntity *pActivator, CBaseEntity *pCaller, float fDelay) +{ + char sOutput[20]; + Q_snprintf(sOutput, sizeof(sOutput), "%x", pOutput); + + // attempt to directly lookup a hook using the pOutput pointer + OutputNameStruct *pOutputName = NULL; + + edict_t *pEdict = gameents->BaseEntityToEdict(pCaller); + + /* TODO: Add support for entities without an edict */ + if (pEdict == NULL) + { + return; + } + + bool fastLookup = false; + + // Fast lookup failed - check the slow way for hooks that havn't fired yet + if ((fastLookup = EntityOutputs->Retrieve(sOutput, (void **)&pOutputName)) == false) + { + const char *classname = pEdict->GetClassName(); + const char *outputname = FindOutputName(pOutput, pCaller); + + pOutputName = FindOutputPointer(classname, outputname, false); + + if (!pOutputName) + { + return; + } + } + + if (!pOutputName->hooks.empty()) + { + if (!fastLookup) + { + // hook exists on this classname and output - map it into our quick find trie + EntityOutputs->Insert(sOutput, pOutputName); + } + + SourceHook::List::iterator _iter; + + omg_hooks *hook; + + _iter = pOutputName->hooks.begin(); + + while (_iter != pOutputName->hooks.end()) + { + hook = (omg_hooks *)*_iter; + + hook->in_use = true; + + int serial = pEdict->m_NetworkSerialNumber; + + if (serial != hook->entity_filter && hook->entity_index == engine->IndexOfEdict(pEdict)) + { + // same entity index but different serial number. Entity has changed, kill the hook. + _iter = pOutputName->hooks.erase(_iter); + CleanUpHook(hook); + + continue; + } + + if (hook->entity_filter == -1 || hook->entity_filter == serial) // Global classname hook + { + /* + Handle_t handle; + + if (Value.FieldType() == FIELD_VOID) + { + handle = 0; + } + else + { + varhandle_t *varhandle = new varhandle_t; + memmove ((void *)&varhandle->crab, (void *)&Value, sizeof(variant_t)); + + handle = handlesys->CreateHandle(VariantHandle, (void *)varhandle, hook->pf->GetParentContext()->GetIdentity(), myself->GetIdentity(), NULL); + } + */ + + //fire the forward to hook->pf + hook->pf->PushString(pOutputName->Name); + hook->pf->PushCell(engine->IndexOfEdict(pEdict)); + + edict_t *pEdictActivator = gameents->BaseEntityToEdict(pActivator); + if (!pEdictActivator) + { + hook->pf->PushCell(-1); + } + else + { + hook->pf->PushCell(engine->IndexOfEdict(pEdictActivator)); + } + //hook->pf->PushCell(handle); + hook->pf->PushFloat(fDelay); + hook->pf->Execute(NULL); + + if ((hook->entity_filter != -1) && hook->only_once) + { + _iter = pOutputName->hooks.erase(_iter); + CleanUpHook(hook); + + continue; + } + + if (hook->delete_me) + { + _iter = pOutputName->hooks.erase(_iter); + CleanUpHook(hook); + continue; + } + + hook->in_use = false; + _iter++; + + continue; + } + } + } +} + +omg_hooks *EntityOutputManager::NewHook() +{ + omg_hooks *hook; + + if (FreeHooks.empty()) + { + hook = new omg_hooks; + } + else + { + hook = g_OutputManager.FreeHooks.front(); + g_OutputManager.FreeHooks.pop(); + } + + return hook; +} + +void EntityOutputManager::OnHookAdded() +{ + HookCount++; + + if (HookCount == 1) + { + // This is the first hook created + InitFireEventDetour(); + } +} + +void EntityOutputManager::OnHookRemoved() +{ + HookCount--; + + if (HookCount == 0) + { + //we need to check if we are inside a detour. easy. + //if we are how do we + ShutdownFireEventDetour(); + } +} + +void EntityOutputManager::CleanUpHook(omg_hooks *hook) +{ + FreeHooks.push(hook); + + OnHookRemoved(); + + IPlugin *pPlugin = plsys->FindPluginByContext(hook->pf->GetParentContext()->GetContext()); + SourceHook::List *pList = NULL; + + if (!pPlugin->GetProperty("OutputHookList", (void **)&pList, false) || !pList) + { + return; + } + + SourceHook::List::iterator p_iter = pList->begin(); + + omg_hooks *pluginHook; + + while (p_iter != pList->end()) + { + pluginHook = (omg_hooks *)*p_iter; + if (pluginHook == hook) + { + p_iter = pList->erase(p_iter); + } + else + { + p_iter++; + } + } +} + +void EntityOutputManager::OnPluginDestroyed(IPlugin *plugin) +{ + SourceHook::List *pList = NULL; + + if (plugin->GetProperty("OutputHookList", (void **)&pList, true)) + { + SourceHook::List::iterator p_iter = pList->begin(); + omg_hooks *hook; + + while (p_iter != pList->end()) + { + hook = (omg_hooks *)*p_iter; + + p_iter = pList->erase(p_iter); //remove from this plugins list + hook->m_parent->hooks.remove(hook); // remove from the y's list + + FreeHooks.push(hook); //save the omg_hook + + OnHookRemoved(); + } + } +} + +OutputNameStruct *EntityOutputManager::FindOutputPointer(const char *classname, const char *outputname, bool create) +{ + ClassNameStruct *pClassname; + + if (!ClassNames->Retrieve(classname, (void **)&pClassname)) + { + if (create) + { + pClassname = new ClassNameStruct; + ClassNames->Insert(classname, pClassname); + } + else + { + return NULL; + } + } + + OutputNameStruct *pOutputName; + + if (!pClassname->OutputList->Retrieve(outputname, (void **)&pOutputName)) + { + if (create) + { + pOutputName = new OutputNameStruct; + pClassname->OutputList->Insert(outputname, pOutputName); + strncpy(pOutputName->Name, outputname, sizeof(pOutputName->Name)); + pOutputName->Name[49] = 0; + } + else + { + return NULL; + } + } + + return pOutputName; +} + +// Iterate the datamap of pCaller and look for output pointers with the same address as pOutput +const char *EntityOutputManager::FindOutputName(void *pOutput, CBaseEntity *pCaller) +{ + datamap_t *pMap = gamehelpers->GetDataMap(pCaller); + + while (pMap) + { + for (int i=0; idataNumFields; i++) + { + if (pMap->dataDesc[i].flags & FTYPEDESC_OUTPUT) + { + if ((char *)pCaller + pMap->dataDesc[i].fieldOffset[0] == pOutput) + { + return pMap->dataDesc[i].externalName; + } + } + } + pMap = pMap->baseMap; + } + + return NULL; +} +#if 0 +// Almost identical copy of this function from cbase.cpp - FIELD_EHANDLE changed to remove dependencies +const char *variant_t::ToString( void ) const +{ + COMPILE_TIME_ASSERT( sizeof(string_t) == sizeof(int) ); + + static char szBuf[512]; + + switch (fieldType) + { + case FIELD_STRING: + { + return(STRING(iszVal)); + } + + case FIELD_BOOLEAN: + { + if (bVal == 0) + { + Q_strncpy(szBuf, "false",sizeof(szBuf)); + } + else + { + Q_strncpy(szBuf, "true",sizeof(szBuf)); + } + return(szBuf); + } + + case FIELD_INTEGER: + { + Q_snprintf( szBuf, sizeof( szBuf ), "%i", iVal ); + return(szBuf); + } + + case FIELD_FLOAT: + { + Q_snprintf(szBuf,sizeof(szBuf), "%g", flVal); + return(szBuf); + } + + case FIELD_COLOR32: + { + Q_snprintf(szBuf,sizeof(szBuf), "%d %d %d %d", (int)rgbaVal.r, (int)rgbaVal.g, (int)rgbaVal.b, (int)rgbaVal.a); + return(szBuf); + } + + case FIELD_VECTOR: + { + Q_snprintf(szBuf,sizeof(szBuf), "[%g %g %g]", (double)vecVal[0], (double)vecVal[1], (double)vecVal[2]); + return(szBuf); + } + + case FIELD_VOID: + { + szBuf[0] = '\0'; + return(szBuf); + } + + case FIELD_EHANDLE: + { + CBaseHandle temp = eVal; + + const char *pszName = g_OutputManager.BaseHandleToEdict(temp)->GetClassName(); + + if (pszName == NULL) + { + Q_strncpy( szBuf, "<>", 512 ); + return (szBuf); + } + + Q_strncpy( szBuf, pszName, 512 ); + return (szBuf); + } + + default: + break; + } + + return("No conversion to string"); +} +#endif +// Thanks SM core +edict_t *EntityOutputManager::BaseHandleToEdict(CBaseHandle &hndl) +{ + if (!hndl.IsValid()) + { + return NULL; + } + + int index = hndl.GetEntryIndex(); + + edict_t *pStoredEdict; + + pStoredEdict = engine->PEntityOfEntIndex(index); + + if (pStoredEdict == NULL) + { + return NULL; + } + + IServerEntity *pSE = pStoredEdict->GetIServerEntity(); + + if (pSE == NULL) + { + return NULL; + } + + if (pSE->GetRefEHandle() != hndl) + { + return NULL; + } + + return pStoredEdict; +} + + + diff --git a/extensions/sdktools/output.h b/extensions/sdktools/output.h new file mode 100644 index 00000000..62158b22 --- /dev/null +++ b/extensions/sdktools/output.h @@ -0,0 +1,176 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod SDKTools Extension + * Copyright (C) 2004-2007 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_OUTPUT_H_ +#define _INCLUDE_SOURCEMOD_OUTPUT_H_ + +#include +#include +//#include "variant_t.h" +#include "sh_list.h" +#include "sh_stack.h" +#include "sm_trie_tpl.h" +#include "detours.h" + +extern ISourcePawnEngine *spengine; + +struct OutputNameStruct; + +/** + * This is a function specific hook that corresponds to an entity classname + * and outputname. There can be many of these for each classname/output combo + */ +struct omg_hooks +{ + int entity_filter; // if not -1 is an entity signature + int entity_index; + bool only_once; + IPluginFunction *pf; + OutputNameStruct *m_parent; + bool in_use; + bool delete_me; +}; + +/** + * This represents an output belonging to a specific classname + */ +struct OutputNameStruct +{ + SourceHook::List hooks; + char Name[50]; +}; + +/** + * This represents an entity classname + */ +struct ClassNameStruct +{ + //Trie mapping outputname to a OutputNameStruct + //KTrie OutputList; + IBasicTrie *OutputList; + + ClassNameStruct() + { + OutputList = adtfactory->CreateBasicTrie(); + } + + ~ClassNameStruct() + { + OutputList->Destroy(); + } +}; + +class EntityOutputManager : public IPluginsListener +{ +public: + EntityOutputManager() + { + info_address = NULL; + info_callback = NULL; + HookCount = 0; + is_detoured = false; + enabled = false; + } + + ~EntityOutputManager() + { + EntityOutputs->Destroy(); + ClassNames->Destroy(); + ShutdownFireEventDetour(); + } + + void Init() + { + enabled = CreateFireEventDetour(); + + if (!enabled) + { + return; + } + + EntityOutputs = adtfactory->CreateBasicTrie(); + ClassNames = adtfactory->CreateBasicTrie(); + } + + bool IsEnabled() + { + return enabled; + } + + void FireEventDetour(void *pOutput, CBaseEntity *pActivator, CBaseEntity *pCaller, float fDelay); + + void OnPluginDestroyed(IPlugin *plugin); + + OutputNameStruct *FindOutputPointer(const char *classname, const char *outputname, bool create); + + void CleanUpHook(omg_hooks *hook); + + omg_hooks *NewHook(); + + void OnHookAdded(); + void OnHookRemoved(); + +private: + bool enabled; + + // Patch/unpatch the server dll + void InitFireEventDetour(); + void ShutdownFireEventDetour(); + bool is_detoured; + + //These create/delete the allocated memory and write into it + bool CreateFireEventDetour(); + void DeleteFireEventDetour(); + + const char *FindOutputName(void *pOutput, CBaseEntity *pCaller); + edict_t *BaseHandleToEdict(CBaseHandle &hndl); + + //Maps CEntityOutput * to a OutputNameStruct + IBasicTrie *EntityOutputs; + // Maps classname to a ClassNameStruct + IBasicTrie *ClassNames; + + SourceHook::CStack FreeHooks; //Stores hook pointers to avoid calls to new + + int HookCount; + + patch_t info_restore; + void *info_address; + void *info_callback; +}; + +void TempDetour(void *pOutput, CBaseEntity *pActivator, CBaseEntity *pCaller, float fDelay); + +extern EntityOutputManager g_OutputManager; + +extern sp_nativeinfo_t g_EntOutputNatives[]; + +#endif //_INCLUDE_SOURCEMOD_OUTPUT_H_ diff --git a/extensions/sdktools/outputnatives.cpp b/extensions/sdktools/outputnatives.cpp new file mode 100644 index 00000000..11c9d4f6 --- /dev/null +++ b/extensions/sdktools/outputnatives.cpp @@ -0,0 +1,611 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod SDKTools Extension + * Copyright (C) 2004-2007 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 "extension.h" +#include "output.h" + + +// HookSingleEntityOutput(ent, const String:output[], function, bool:once); +cell_t HookSingleEntityOutput(IPluginContext *pContext, const cell_t *params) +{ + if (!g_OutputManager.IsEnabled()) + { + return pContext->ThrowNativeError("Entity Outputs are disabled - See error logs for details"); + } + + edict_t *pEdict = engine->PEntityOfEntIndex(params[1]); + if (!pEdict) + { + return pContext->ThrowNativeError("Invalid Entity index %i", params[1]); + } + const char *classname = pEdict->GetClassName(); + + char *outputname; + pContext->LocalToString(params[2], &outputname); + + OutputNameStruct *pOutputName = g_OutputManager.FindOutputPointer((const char *)classname, outputname, true); + + //Check for an existing identical hook + SourceHook::List::iterator _iter; + + omg_hooks *hook; + + IPluginFunction *pFunction; + pFunction = pContext->GetFunctionById(params[3]); + + for (_iter=pOutputName->hooks.begin(); _iter!=pOutputName->hooks.end(); _iter++) + { + hook = (omg_hooks *)*_iter; + if (hook->pf == pFunction && hook->entity_filter == pEdict->m_NetworkSerialNumber) + { + return 0; + } + } + + hook = g_OutputManager.NewHook(); + + hook->entity_filter = pEdict->m_NetworkSerialNumber; + hook->entity_index = engine->IndexOfEdict(pEdict); + hook->only_once= !!params[4]; + hook->pf = pFunction; + hook->m_parent = pOutputName; + hook->in_use = false; + hook->delete_me = false; + + pOutputName->hooks.push_back(hook); + + g_OutputManager.OnHookAdded(); + + IPlugin *pPlugin = plsys->FindPluginByContext(pContext->GetContext()); + SourceHook::List *pList = NULL; + + if (!pPlugin->GetProperty("OutputHookList", (void **)&pList, false) || !pList) + { + pList = new SourceHook::List; + pPlugin->SetProperty("OutputHookList", pList); + } + + pList->push_back(hook); + + return 1; +} + + +// HookEntityOutput(const String:classname[], const String:output[], function); +cell_t HookEntityOutput(IPluginContext *pContext, const cell_t *params) +{ + if (!g_OutputManager.IsEnabled()) + { + return pContext->ThrowNativeError("Entity Outputs are disabled - See error logs for details"); + } + + //Find or create the base structures for this classname and the output + char *classname; + pContext->LocalToString(params[1], &classname); + + char *outputname; + pContext->LocalToString(params[2], &outputname); + + OutputNameStruct *pOutputName = g_OutputManager.FindOutputPointer((const char *)classname, outputname, true); + + //Check for an existing identical hook + SourceHook::List::iterator _iter; + + omg_hooks *hook; + + IPluginFunction *pFunction; + pFunction = pContext->GetFunctionById(params[3]); + + for (_iter=pOutputName->hooks.begin(); _iter!=pOutputName->hooks.end(); _iter++) + { + hook = (omg_hooks *)*_iter; + if (hook->pf == pFunction && hook->entity_filter == -1) + { + //already hooked to this function... + //throw an error or just let them get away with stupidity? + // seems like poor coding if they dont know if something is hooked or not + return 0; + } + } + + hook = g_OutputManager.NewHook(); + + hook->entity_filter = -1; + hook->pf = pFunction; + hook->m_parent = pOutputName; + hook->in_use = false; + hook->delete_me = false; + + pOutputName->hooks.push_back(hook); + + g_OutputManager.OnHookAdded(); + + IPlugin *pPlugin = plsys->FindPluginByContext(pContext->GetContext()); + SourceHook::List *pList = NULL; + + if (!pPlugin->GetProperty("OutputHookList", (void **)&pList, false) || !pList) + { + pList = new SourceHook::List; + pPlugin->SetProperty("OutputHookList", pList); + } + + pList->push_back(hook); + + return 1; +} + +// UnHookEntityOutput(const String:classname[], const String:output[], EntityOutput:callback); +cell_t UnHookEntityOutput(IPluginContext *pContext, const cell_t *params) +{ + if (!g_OutputManager.IsEnabled()) + { + return pContext->ThrowNativeError("Entity Outputs are disabled - See error logs for details"); + } + + char *classname; + pContext->LocalToString(params[1], &classname); + + char *outputname; + pContext->LocalToString(params[2], &outputname); + + OutputNameStruct *pOutputName = g_OutputManager.FindOutputPointer((const char *)classname, outputname, false); + + if (!pOutputName) + { + return 0; + } + + //Check for an existing identical hook + SourceHook::List::iterator _iter; + + omg_hooks *hook; + + IPluginFunction *pFunction; + pFunction = pContext->GetFunctionById(params[3]); + + for (_iter=pOutputName->hooks.begin(); _iter!=pOutputName->hooks.end(); _iter++) + { + hook = (omg_hooks *)*_iter; + if (hook->pf == pFunction && hook->entity_filter == -1) + { + // remove this hook. + if (hook->in_use) + { + hook->delete_me = true; + return 1; + } + + pOutputName->hooks.erase(_iter); + g_OutputManager.CleanUpHook(hook); + + return 1; + } + } + + return 0; +} + +// UnHookSingleEntityOutput(entity, const String:output[], EntityOutput:callback); +cell_t UnHookSingleEntityOutput(IPluginContext *pContext, const cell_t *params) +{ + if (!g_OutputManager.IsEnabled()) + { + return pContext->ThrowNativeError("Entity Outputs are disabled - See error logs for details"); + } + + // Find the classname of the entity and lookup the classname and output structures + edict_t *pEdict = engine->PEntityOfEntIndex(params[1]); + if (!pEdict) + { + return pContext->ThrowNativeError("Invalid Entity index %i", params[1]); + } + + const char *classname = pEdict->GetClassName(); + + char *outputname; + pContext->LocalToString(params[2], &outputname); + + OutputNameStruct *pOutputName = g_OutputManager.FindOutputPointer((const char *)classname, outputname, false); + + if (!pOutputName) + { + return 0; + } + + //Check for an existing identical hook + SourceHook::List::iterator _iter; + + omg_hooks *hook; + + IPluginFunction *pFunction; + pFunction = pContext->GetFunctionById(params[3]); + + for (_iter=pOutputName->hooks.begin(); _iter!=pOutputName->hooks.end(); _iter++) + { + hook = (omg_hooks *)*_iter; + if (hook->pf == pFunction && hook->entity_index == engine->IndexOfEdict(pEdict)) + { + // remove this hook. + if (hook->in_use) + { + hook->delete_me = true; + return 1; + } + + pOutputName->hooks.erase(_iter); + g_OutputManager.CleanUpHook(hook); + + return 1; + } + } + + return 0; +} + +#if 0 +static cell_t GetVariantType(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError err; + varhandle_t *pInfo; + HandleSecurity sec; + + sec.pOwner = NULL; + sec.pIdentity = myself->GetIdentity(); + + if ((err=handlesys->ReadHandle(hndl, g_OutputManager.VariantHandle, &sec, (void **)&pInfo)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid variant handle %x (error %d)", hndl, err); + } + + return pInfo->crab.FieldType(); +} + +static cell_t GetVariantInt(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError err; + varhandle_t *pInfo; + HandleSecurity sec; + + sec.pOwner = NULL; + sec.pIdentity = myself->GetIdentity(); + + + if ((err=handlesys->ReadHandle(hndl, g_OutputManager.VariantHandle, &sec, (void **)&pInfo)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid variant handle %x (error %d)", hndl, err); + } + + if (pInfo->crab.FieldType() != FIELD_INTEGER) + { + return pContext->ThrowNativeError("Variant is not an integer"); + } + + return pInfo->crab.Int(); +} + +static cell_t GetVariantBool(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError err; + varhandle_t *pInfo; + HandleSecurity sec; + + sec.pOwner = NULL; + sec.pIdentity = myself->GetIdentity(); + + if ((err=handlesys->ReadHandle(hndl, g_OutputManager.VariantHandle, &sec, (void **)&pInfo)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid variant handle %x (error %d)", hndl, err); + } + + if (pInfo->crab.FieldType() != FIELD_BOOLEAN) + { + return pContext->ThrowNativeError("Variant is not a boolean"); + } + + return pInfo->crab.Bool(); +} + +static cell_t GetVariantEntity(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError err; + varhandle_t *pInfo; + HandleSecurity sec; + + sec.pOwner = NULL; + sec.pIdentity = myself->GetIdentity(); + + if ((err=handlesys->ReadHandle(hndl, g_OutputManager.VariantHandle, &sec, (void **)&pInfo)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid variant handle %x (error %d)", hndl, err); + } + + if (pInfo->crab.FieldType() != FIELD_EHANDLE) + { + return pContext->ThrowNativeError("Variant is not an entity"); + } + + edict_t *pEdict = g_OutputManager.BaseHandleToEdict((CBaseHandle)pInfo->crab.Entity()); + + return engine->IndexOfEdict(pEdict); +} + +static cell_t GetVariantFloat(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError err; + varhandle_t *pInfo; + HandleSecurity sec; + + sec.pOwner = NULL; + sec.pIdentity = myself->GetIdentity(); + + if ((err=handlesys->ReadHandle(hndl, g_OutputManager.VariantHandle, &sec, (void **)&pInfo)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid variant handle %x (error %d)", hndl, err); + } + + if (pInfo->crab.FieldType() != FIELD_FLOAT) + { + return pContext->ThrowNativeError("Variant is not a float"); + } + + return sp_ftoc(pInfo->crab.Float()); +} + +static cell_t GetVariantVector(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError err; + varhandle_t *pInfo; + HandleSecurity sec; + + sec.pOwner = NULL; + sec.pIdentity = myself->GetIdentity(); + + if ((err=handlesys->ReadHandle(hndl, g_OutputManager.VariantHandle, &sec, (void **)&pInfo)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid variant handle %x (error %d)", hndl, err); + } + + if (pInfo->crab.FieldType() != FIELD_VECTOR) + { + return pContext->ThrowNativeError("Variant is not a vector"); + } + + cell_t *r; + pContext->LocalToPhysAddr(params[2], &r); + + Vector temp; + pInfo->crab.Vector3D(temp); + + r[0] = sp_ftoc(temp[0]); + r[1] = sp_ftoc(temp[1]); + r[2] = sp_ftoc(temp[2]); + + return 0; +} + +static cell_t GetVariantColour(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError err; + varhandle_t *pInfo; + HandleSecurity sec; + + sec.pOwner = NULL; + sec.pIdentity = myself->GetIdentity(); + + if ((err=handlesys->ReadHandle(hndl, g_OutputManager.VariantHandle, &sec, (void **)&pInfo)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid variant handle %x (error %d)", hndl, err); + } + + if (pInfo->crab.FieldType() != FIELD_COLOR32) + { + return pContext->ThrowNativeError("Variant is not a colour"); + } + + cell_t *r; + pContext->LocalToPhysAddr(params[2], &r); + + color32 temp = pInfo->crab.Color32(); + + r[0] = temp.r; + r[1] = temp.g; + r[2] = temp.b; + r[4] = temp.a; + + return 0; +} + +static cell_t GetVariantString(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError err; + varhandle_t *pInfo; + HandleSecurity sec; + + sec.pOwner = NULL; + sec.pIdentity = myself->GetIdentity(); + + if ((err=handlesys->ReadHandle(hndl, g_OutputManager.VariantHandle, &sec, (void **)&pInfo)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid variant handle %x (error %d)", hndl, err); + } + + char *dest; + const char *src = pInfo->crab.String(); + size_t len; + + pContext->LocalToString(params[2], &dest); + + /* Perform bounds checking */ + len = strlen(src); + if (len >= (unsigned)params[3]) + { + len = params[3] - 1; + } else { + len = params[3]; + } + + /* Copy */ + memmove(dest, src, len); + + dest[len] = '\0'; + + return 0; +} +#endif + +sp_nativeinfo_t g_EntOutputNatives[] = +{ + {"HookEntityOutput", HookEntityOutput}, + {"UnhookEntityOutput", UnHookEntityOutput}, + {"HookSingleEntityOutput", HookSingleEntityOutput}, + {"UnhookSingleEntityOutput", UnHookSingleEntityOutput}, +#if 0 //Removed because we don't need them + {"GetVariantType", GetVariantType}, + {"GetVariantInt", GetVariantInt}, + {"GetVariantFloat", GetVariantFloat}, + {"GetVariantBool", GetVariantBool}, + {"GetVariantString", GetVariantString}, + {"GetVariantEntity", GetVariantEntity}, + {"GetVariantVector", GetVariantVector}, + {"GetVariantColour", GetVariantColour}, +#endif + {NULL, NULL}, +}; + +#if 0 +//Include file stuff that wasn't needed: + +enum FieldType +{ + FieldType_Float = 1, + FieldType_String = 2, + FieldType_Vector = 3, + FieldType_Int = 5, + FieldType_Bool = 6, + FieldType_Colour = 9, + FieldType_Entity = 13 +} + +/** + * Gets the current type of a variant handle + * + * @param variant A variant handle. + * @return Current type of the variant. + */ +native FieldType:GetVariantType(Handle:variant); + +/** + * Retreives a Float from a variant handle. + * + * @param variant A variant handle. + * @return Float value. + * @error Variant handle is not type FieldType_Float + */ +native Float:GetVariantFloat(Handle:variant); + +/** + * Retreives an Integer from a variant handle. + * + * @param variant A variant handle. + * @return Int value. + * @error Variant handle is not type FieldType_Int + */ +native GetVariantInt(Handle:variant); + +/** + * Retreives a bool from a variant handle. + * + * @param variant A variant handle. + * @return bool value. + * @error Variant handle is not type FieldType_Bool + */ +native bool:GetVariantBool(Handle:variant); + +/** + * Retreives an entity from a variant handle. + * + * @param variant A variant handle. + * @return Entity Index. + * @error Variant handle is not type FieldType_Entity + */ +native GetVariantEntity(Handle:variant); + +/** + * Retreives a Vector from a variant handle. + * + * @param variant A variant handle. + * @param vec buffer to store the Vector. + * @noreturn + * @error Variant handle is not type FieldType_Vector + */ +native GetVariantVector(Handle:variant, Float:vec[3]); + +/** + * Retreives a String from a variant handle. + * + * @note This native does not require the variant to be FieldType_String, + * It can convert any type into a string representation. + * + * @param variant A variant handle. + * @param buffer buffer to store the string in + * @param maxlen Maximum length of buffer. + * @noreturn + */ +native GetVariantString(Handle:variant, String:buffer[], maxlen); + +/** + * Retreives a Colour from a variant handle. + * + * @note Colour is in format r,g,b,a + * + * @param variant A variant handle. + * @param colour buffer array to store the colour in. + * @noreturn + * @error Variant handle is not type FieldType_Colour + */ +native GetVariantColour(Handle:variant, colour[4]); +#endif diff --git a/extensions/sdktools/teamnatives.cpp b/extensions/sdktools/teamnatives.cpp index 3eac3c68..6ebb67d8 100644 --- a/extensions/sdktools/teamnatives.cpp +++ b/extensions/sdktools/teamnatives.cpp @@ -2,7 +2,7 @@ * vim: set ts=4 : * ============================================================================= * SourceMod SDKTools Extension - * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved. + * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. * ============================================================================= * * This program is free software; you can redistribute it and/or modify it under diff --git a/extensions/sdktools/tempents.cpp b/extensions/sdktools/tempents.cpp index 9660affa..407f709a 100644 --- a/extensions/sdktools/tempents.cpp +++ b/extensions/sdktools/tempents.cpp @@ -2,7 +2,7 @@ * vim: set ts=4 : * ============================================================================= * SourceMod SDKTools Extension - * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved. + * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. * ============================================================================= * * This program is free software; you can redistribute it and/or modify it under diff --git a/extensions/sdktools/tempents.h b/extensions/sdktools/tempents.h index 9e3ff97a..366ccc6a 100644 --- a/extensions/sdktools/tempents.h +++ b/extensions/sdktools/tempents.h @@ -2,7 +2,7 @@ * vim: set ts=4 : * ============================================================================= * SourceMod SDKTools Extension - * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved. + * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. * ============================================================================= * * This program is free software; you can redistribute it and/or modify it under diff --git a/extensions/sdktools/tenatives.cpp b/extensions/sdktools/tenatives.cpp index 7ab784a4..4d0b69f3 100644 --- a/extensions/sdktools/tenatives.cpp +++ b/extensions/sdktools/tenatives.cpp @@ -2,7 +2,7 @@ * vim: set ts=4 : * ============================================================================= * SourceMod SDKTools Extension - * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved. + * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. * ============================================================================= * * This program is free software; you can redistribute it and/or modify it under diff --git a/extensions/sdktools/trnatives.cpp b/extensions/sdktools/trnatives.cpp index 5f19a72a..f748ec72 100644 --- a/extensions/sdktools/trnatives.cpp +++ b/extensions/sdktools/trnatives.cpp @@ -2,7 +2,7 @@ * vim: set ts=4 : * ============================================================================= * SourceMod SDKTools Extension - * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved. + * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. * ============================================================================= * * This program is free software; you can redistribute it and/or modify it under diff --git a/extensions/sdktools/util.h b/extensions/sdktools/util.h index 2aa42160..b304923a 100644 --- a/extensions/sdktools/util.h +++ b/extensions/sdktools/util.h @@ -2,7 +2,7 @@ * vim: set ts=4 : * ============================================================================= * SourceMod SDKTools Extension - * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved. + * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. * ============================================================================= * * This program is free software; you can redistribute it and/or modify it under diff --git a/extensions/sdktools/vcallbuilder.cpp b/extensions/sdktools/vcallbuilder.cpp index 54b6cb05..b6eca41d 100644 --- a/extensions/sdktools/vcallbuilder.cpp +++ b/extensions/sdktools/vcallbuilder.cpp @@ -2,7 +2,7 @@ * vim: set ts=4 : * ============================================================================= * SourceMod SDKTools Extension - * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved. + * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. * ============================================================================= * * This program is free software; you can redistribute it and/or modify it under diff --git a/extensions/sdktools/vcallbuilder.h b/extensions/sdktools/vcallbuilder.h index ccd8816f..3237fe5d 100644 --- a/extensions/sdktools/vcallbuilder.h +++ b/extensions/sdktools/vcallbuilder.h @@ -2,7 +2,7 @@ * vim: set ts=4 : * ============================================================================= * SourceMod SDKTools Extension - * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved. + * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. * ============================================================================= * * This program is free software; you can redistribute it and/or modify it under diff --git a/extensions/sdktools/vcaller.cpp b/extensions/sdktools/vcaller.cpp index 75b89b82..6ea1f131 100644 --- a/extensions/sdktools/vcaller.cpp +++ b/extensions/sdktools/vcaller.cpp @@ -2,7 +2,7 @@ * vim: set ts=4 : * ============================================================================= * SourceMod SDKTools Extension - * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved. + * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. * ============================================================================= * * This program is free software; you can redistribute it and/or modify it under diff --git a/extensions/sdktools/vdecoder.cpp b/extensions/sdktools/vdecoder.cpp index 12bfaabb..03f0dcff 100644 --- a/extensions/sdktools/vdecoder.cpp +++ b/extensions/sdktools/vdecoder.cpp @@ -2,7 +2,7 @@ * vim: set ts=4 : * ============================================================================= * SourceMod SDKTools Extension - * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved. + * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. * ============================================================================= * * This program is free software; you can redistribute it and/or modify it under diff --git a/extensions/sdktools/vdecoder.h b/extensions/sdktools/vdecoder.h index b8f37955..f397d7bb 100644 --- a/extensions/sdktools/vdecoder.h +++ b/extensions/sdktools/vdecoder.h @@ -2,7 +2,7 @@ * vim: set ts=4 : * ============================================================================= * SourceMod SDKTools Extension - * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved. + * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. * ============================================================================= * * This program is free software; you can redistribute it and/or modify it under diff --git a/extensions/sdktools/vglobals.cpp b/extensions/sdktools/vglobals.cpp index 0925dbec..9a0ba0f8 100644 --- a/extensions/sdktools/vglobals.cpp +++ b/extensions/sdktools/vglobals.cpp @@ -2,7 +2,7 @@ * vim: set ts=4 : * ============================================================================= * SourceMod SDKTools Extension - * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved. + * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. * ============================================================================= * * This program is free software; you can redistribute it and/or modify it under @@ -83,20 +83,20 @@ void InitializeValveGlobals() } #endif -bool vcmp(const void *_addr1, const void *_addr2, size_t len) -{ - unsigned char *addr1 = (unsigned char *)_addr1; - unsigned char *addr2 = (unsigned char *)_addr2; - - for (size_t i=0; i 0) + { + str[len] = 0; // Strip the final '|' + } + + return str; +} + +void UTIL_DrawDataTable(FILE *fp, datamap_t *pMap, int level) +{ + char spaces[255]; + + for (int i=0; idataNumFields; i++) + { + if (pMap->dataDesc[i].fieldName == NULL) + { + continue; + } + + if (pMap->dataDesc[i].td) + { + fprintf(fp, " %sSub-Class Table (%d Deep): %s - %s\n", spaces, level+1, pMap->dataDesc[i].fieldName, pMap->dataDesc[i].td->dataClassName); + UTIL_DrawDataTable(fp, pMap->dataDesc[i].td, level+1); + } + else + { + externalname = pMap->dataDesc[i].externalName; + flags = UTIL_FlagsToString(pMap->dataDesc[i].flags); + + if (externalname == NULL) + { + fprintf(fp,"%s- %s (%s)(%i Bytes)\n", spaces, pMap->dataDesc[i].fieldName, flags, pMap->dataDesc[i].fieldSizeInBytes); + } + else + { + fprintf(fp,"%s- %s (%s)(%i Bytes) - %s\n", spaces, pMap->dataDesc[i].fieldName, flags, pMap->dataDesc[i].fieldSizeInBytes, externalname); + } + } + } + pMap = pMap->baseMap; + } +} + +CON_COMMAND(sm_dump_datamaps, "Dumps the data map list as a text file") +{ +#if !defined ORANGEBOX_BUILD + CCommand args; +#endif + + if (args.ArgC() < 2) + { + META_CONPRINT("Usage: sm_dump_datamaps \n"); + return; + } + + const char *file = args.Arg(1); + if (!file || file[0] == '\0') + { + META_CONPRINT("Usage: sm_dump_datamaps \n"); + return; + } + + ICallWrapper *pWrapper = NULL; + + if (!pWrapper) + { + PassInfo retData; + retData.flags = PASSFLAG_BYVAL; + retData.size = sizeof(void *); + retData.type = PassType_Basic; + + void *addr; + if (!g_pGameConf->GetMemSig("EntityFactory", &addr) || addr == NULL) + { + META_CONPRINT("Failed to locate function\n"); + return; + } + + pWrapper = g_pBinTools->CreateCall(addr, CallConv_Cdecl, &retData, NULL, 0); + } + + + void *returnData = NULL; + + pWrapper->Execute(NULL, &returnData); + + pWrapper->Destroy(); + + if (returnData == NULL) + { + return; + } + + CEntityFactoryDictionary *dict = ( CEntityFactoryDictionary * )returnData; + + if ( !dict ) + { + return; + } + + char path[PLATFORM_MAX_PATH]; + g_pSM->BuildPath(Path_Game, path, sizeof(path), "%s", file); + + FILE *fp = NULL; + if ((fp = fopen(path, "wt")) == NULL) + { + META_CONPRINTF("Could not open file \"%s\"\n", path); + return; + } + + char buffer[80]; + buffer[0] = 0; + +#if defined SUBPLATFORM_SECURECRT + _invalid_parameter_handler handler = _set_invalid_parameter_handler(_ignore_invalid_parameter); +#endif + + time_t t = g_pSM->GetAdjustedTime(); + size_t written = strftime(buffer, sizeof(buffer), "%d/%m/%Y", localtime(&t)); + +#if defined SUBPLATFORM_SECURECRT + _set_invalid_parameter_handler(handler); +#endif + + fprintf(fp, "// Dump of all datamaps for \"%s\" as at %s\n//\n//\n", g_pSM->GetGameFolderName(), buffer); + + + fprintf(fp, "// Flag Details:\n//\n"); + + fprintf(fp, "// Global: This field is masked for global entity save/restore\n"); + fprintf(fp, "// Save: This field is saved to disk\n"); + fprintf(fp, "// Key: This field can be requested and written to by string name at load time\n"); + fprintf(fp, "// Input: This field can be written to by string name at run time, and a function called\n"); + fprintf(fp, "// Output: This field propogates it's value to all targets whenever it changes\n"); + fprintf(fp, "// FunctionTable: This is a table entry for a member function pointer\n"); + fprintf(fp, "// Ptr: This field is a pointer, not an embedded object\n"); + fprintf(fp, "// Override: The field is an override for one in a base class (only used by prediction system for now)\n"); + + fprintf(fp, "//\n\n"); + + for ( int i = dict->m_Factories.First(); i != dict->m_Factories.InvalidIndex(); i = dict->m_Factories.Next( i ) ) + { + IServerNetworkable *entity = dict->Create(dict->m_Factories.GetElementName(i)); + ServerClass *sclass = entity->GetServerClass(); + datamap_t *pMap = gamehelpers->GetDataMap(entity->GetBaseEntity()); + + fprintf(fp,"%s - %s\n", sclass->GetName(), dict->m_Factories.GetElementName(i)); + + UTIL_DrawDataTable(fp, pMap, 0); + + typedescription_t *datamap = gamehelpers->FindInDataMap(pMap, "m_iEFlags"); + + int *eflags = (int *)((char *)entity->GetBaseEntity() + datamap->fieldOffset[TD_OFFSET_NORMAL]); + *eflags |= (1<<0); // EFL_KILLME + } + + fclose(fp); + +} + + + + + + diff --git a/extensions/sdktools/vhelpers.h b/extensions/sdktools/vhelpers.h index 3ba1b116..46cbdb81 100644 --- a/extensions/sdktools/vhelpers.h +++ b/extensions/sdktools/vhelpers.h @@ -2,7 +2,7 @@ * vim: set ts=4 : * ============================================================================= * SourceMod SDKTools Extension - * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved. + * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. * ============================================================================= * * This program is free software; you can redistribute it and/or modify it under diff --git a/extensions/sdktools/vnatives.cpp b/extensions/sdktools/vnatives.cpp index d905fadd..ae6c0623 100644 --- a/extensions/sdktools/vnatives.cpp +++ b/extensions/sdktools/vnatives.cpp @@ -2,7 +2,7 @@ * vim: set ts=4 : * ============================================================================= * SourceMod SDKTools Extension - * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved. + * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. * ============================================================================= * * This program is free software; you can redistribute it and/or modify it under @@ -871,6 +871,29 @@ static cell_t GetServerNetStats(IPluginContext *pContext, const cell_t *params) return 1; } +static cell_t WeaponEquip(IPluginContext *pContext, const cell_t *params) +{ + static ValveCall *pCall = NULL; + if (!pCall) + { + ValvePassInfo pass[1]; + InitPass(pass[0], Valve_CBaseEntity, PassType_Basic, PASSFLAG_BYVAL); + if (!CreateBaseCall("WeaponEquip", ValveCall_Player, NULL, pass, 1, &pCall)) + { + return pContext->ThrowNativeError("\"WeaponEquip\" not supported by this mod"); + } else if (!pCall) { + return pContext->ThrowNativeError("\"WeaponEquip\" wrapper failed to initialized"); + } + } + + START_CALL(); + DECODE_VALVE_PARAM(1, thisinfo, 0); + DECODE_VALVE_PARAM(2, vparams, 0); + FINISH_CALL_SIMPLE(NULL); + + return 1; +} + sp_nativeinfo_t g_Natives[] = { {"ExtinguishEntity", ExtinguishEntity}, @@ -895,5 +918,6 @@ sp_nativeinfo_t g_Natives[] = {"SetEntityModel", sm_SetEntityModel}, {"GetPlayerDecalFile", GetPlayerDecalFile}, {"GetServerNetStats", GetServerNetStats}, + {"EquipPlayerWeapon", WeaponEquip}, {NULL, NULL}, }; diff --git a/extensions/sdktools/vnatives.h b/extensions/sdktools/vnatives.h index 0dd2375a..74612360 100644 --- a/extensions/sdktools/vnatives.h +++ b/extensions/sdktools/vnatives.h @@ -2,7 +2,7 @@ * vim: set ts=4 : * ============================================================================= * SourceMod SDKTools Extension - * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved. + * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. * ============================================================================= * * This program is free software; you can redistribute it and/or modify it under diff --git a/extensions/sdktools/voice.cpp b/extensions/sdktools/voice.cpp index 196745bc..d9b179f4 100644 --- a/extensions/sdktools/voice.cpp +++ b/extensions/sdktools/voice.cpp @@ -2,7 +2,7 @@ * vim: set ts=4 : * ============================================================================= * SourceMod SDKTools Extension - * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved. + * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. * ============================================================================= * * This program is free software; you can redistribute it and/or modify it under diff --git a/extensions/sdktools/vsound.cpp b/extensions/sdktools/vsound.cpp index 75fcb166..078f39fb 100644 --- a/extensions/sdktools/vsound.cpp +++ b/extensions/sdktools/vsound.cpp @@ -2,7 +2,7 @@ * vim: set ts=4 : * ============================================================================= * SourceMod SDKTools Extension - * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved. + * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. * ============================================================================= * * This program is free software; you can redistribute it and/or modify it under diff --git a/extensions/sdktools/vsound.h b/extensions/sdktools/vsound.h index 040cbbe6..0536b558 100644 --- a/extensions/sdktools/vsound.h +++ b/extensions/sdktools/vsound.h @@ -2,7 +2,7 @@ * vim: set ts=4 : * ============================================================================= * SourceMod SDKTools Extension -* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved. +* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. * ============================================================================= * * This program is free software; you can redistribute it and/or modify it under diff --git a/extensions/sdktools/vstringtable.cpp b/extensions/sdktools/vstringtable.cpp index 22561340..522e4e47 100644 --- a/extensions/sdktools/vstringtable.cpp +++ b/extensions/sdktools/vstringtable.cpp @@ -2,7 +2,7 @@ * vim: set ts=4 : * ============================================================================= * SourceMod SDKTools Extension - * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved. + * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. * ============================================================================= * * This program is free software; you can redistribute it and/or modify it under diff --git a/extensions/tf2/Makefile b/extensions/tf2/Makefile new file mode 100644 index 00000000..af829ccf --- /dev/null +++ b/extensions/tf2/Makefile @@ -0,0 +1,104 @@ +#(C)2004-2008 Metamod:Source Development Team +# Makefile written by David "BAILOPAN" Anderson + +HL2SDK_ORIG = ../../../hl2sdk +HL2SDK_OB = ../../../hl2sdk-ob +SOURCEMM14 = ../../../sourcemm-1.4 +SOURCEMM16 = ../../../sourcemm-1.6 +SRCDS_BASE = ~/srcds +SMSDK = ../.. + +##################################### +### EDIT BELOW FOR OTHER PROJECTS ### +##################################### + +PROJECT = game.tf2 + +OBJECTS = sdk/smsdk_ext.cpp extension.cpp RegNatives.cpp natives.cpp util.cpp + +############################################## +### CONFIGURE ANY OTHER FLAGS/OPTIONS HERE ### +############################################## + +C_OPT_FLAGS = -O3 -funroll-loops -s -pipe -fno-strict-aliasing +C_DEBUG_FLAGS = -g -ggdb3 +CPP_GCC4_FLAGS = -fvisibility=hidden -fvisibility-inlines-hidden +CPP = gcc-4.1 + +ifeq "$(ENGINE)" "original" + HL2SDK = $(HL2SDK_ORIG) + HL2PUB = $(HL2SDK_ORIG)/public + HL2LIB = $(HL2SDK_ORIG)/linux_sdk + METAMOD = $(SOURCEMM14) + INCLUDE += -I$(HL2SDK)/public/dlls + SRCDS = $(SRCDS_BASE) +endif +ifeq "$(ENGINE)" "orangebox" + HL2SDK = $(HL2SDK_OB) + HL2PUB = $(HL2SDK_OB)/public + HL2LIB = $(HL2SDK_OB)/linux_sdk + CFLAGS += -DORANGEBOX_BUILD + METAMOD = $(SOURCEMM16) + INCLUDE += -I$(HL2SDK)/public/game/server -I$(HL2SDK)/common + SRCDS = $(SRCDS_BASE)/orangebox +endif +ifeq "$(ENGINE)" "" + echo "You must supply ENGINE=orangebox or ENGINE=original" + false +endif + +LINK_HL2 = $(HL2LIB)/tier1_i486.a $(HL2LIB)/mathlib_i486.a vstdlib_i486.so tier0_i486.so + +LINK += $(LINK_HL2) -static-libgcc + +INCLUDE += -I. -I.. -Isdk -I$(HL2PUB) -I$(HL2PUB)/engine -I$(HL2PUB)/tier0 -I$(HL2PUB)/tier1 \ + -I$(HL2PUB)/vstdlib -I$(HL2SDK)/tier1 -I$(METAMOD) -I$(METAMOD)/sourcehook -I$(METAMOD)/sourcemm \ + -I$(SMSDK)/public -I$(SMSDK)/public/sourcepawn -I$(SMSDK)/public/extensions \ + +CFLAGS += -D_LINUX -DNDEBUG -Dstricmp=strcasecmp -D_stricmp=strcasecmp -D_strnicmp=strncasecmp -Dstrnicmp=strncasecmp \ + -D_snprintf=snprintf -D_vsnprintf=vsnprintf -D_alloca=alloca -Dstrcmpi=strcasecmp -Wall -Werror -Wno-switch \ + -Wno-unused -mfpmath=sse -msse -DSOURCEMOD_BUILD -DHAVE_STDINT_H -m32 -Wno-uninitialized +CPPFLAGS += -Wno-non-virtual-dtor -fno-exceptions -fno-rtti -fno-threadsafe-statics + +################################################ +### DO NOT EDIT BELOW HERE FOR MOST PROJECTS ### +################################################ + +ifeq "$(DEBUG)" "true" + BIN_DIR = Debug.$(ENGINE) + CFLAGS += $(C_DEBUG_FLAGS) +else + BIN_DIR = Release.$(ENGINE) + CFLAGS += $(C_OPT_FLAGS) +endif + +GCC_VERSION := $(shell $(CPP) -dumpversion >&1 | cut -b1) +ifeq "$(GCC_VERSION)" "4" + CPPFLAGS += $(CPP_GCC4_FLAGS) +endif + +BINARY = $(PROJECT).ext.so + +OBJ_LINUX := $(OBJECTS:%.cpp=$(BIN_DIR)/%.o) + +$(BIN_DIR)/%.o: %.cpp + $(CPP) $(INCLUDE) $(CFLAGS) $(CPPFLAGS) -o $@ -c $< + +all: + mkdir -p $(BIN_DIR)/sdk + ln -sf $(SRCDS)/bin/vstdlib_i486.so vstdlib_i486.so + ln -sf $(SRCDS)/bin/tier0_i486.so tier0_i486.so + $(MAKE) -f Makefile extension + +extension: $(OBJ_LINUX) + $(CPP) $(INCLUDE) $(OBJ_LINUX) $(LINK) -m32 -shared -ldl -lm -o$(BIN_DIR)/$(BINARY) + +debug: + $(MAKE) -f Makefile all DEBUG=true + +default: all + +clean: + rm -rf $(BIN_DIR)/*.o + rm -rf $(BIN_DIR)/sdk/*.o + rm -rf $(BIN_DIR)/$(BINARY) diff --git a/extensions/tf2/RegNatives.cpp b/extensions/tf2/RegNatives.cpp new file mode 100644 index 00000000..03b1cce6 --- /dev/null +++ b/extensions/tf2/RegNatives.cpp @@ -0,0 +1,52 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod Team Fortress 2 Extension + * 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 "extension.h" +#include "RegNatives.h" + +RegNatives g_RegNatives; + +void RegNatives::Register(ICallWrapper *pWrapper) +{ + m_List.push_back(pWrapper); +} + +void RegNatives::UnregisterAll() +{ + SourceHook::List::iterator iter; + + for (iter=m_List.begin(); iter!=m_List.end(); iter++) + { + (*iter)->Destroy(); + } + + m_List.clear(); +} diff --git a/extensions/tf2/RegNatives.h b/extensions/tf2/RegNatives.h new file mode 100644 index 00000000..b355dbc3 --- /dev/null +++ b/extensions/tf2/RegNatives.h @@ -0,0 +1,48 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod Team Fortress 2 Extension + * 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_TF2TOOLS_REGNATIVES_H_ +#define _INCLUDE_TF2TOOLS_REGNATIVES_H_ + +#include + +class RegNatives +{ +public: + void Register(ICallWrapper *pWrapper); + void UnregisterAll(); +private: + SourceHook::List m_List; +}; + +extern RegNatives g_RegNatives; + +#endif //_INCLUDE_TF2TOOLS_REGNATIVES_H_ diff --git a/extensions/tf2/extension.cpp b/extensions/tf2/extension.cpp new file mode 100644 index 00000000..d4c09b13 --- /dev/null +++ b/extensions/tf2/extension.cpp @@ -0,0 +1,327 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod Team Fortress 2 Extension + * 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 "extension.h" +#include "util.h" +#include "RegNatives.h" +#include "iplayerinfo.h" +#include "sm_trie_tpl.h" + +/** + * @file extension.cpp + * @brief Implement extension code here. + */ + + +TF2Tools g_TF2Tools; +IGameConfig *g_pGameConf = NULL; + +IBinTools *g_pBinTools = NULL; + +SMEXT_LINK(&g_TF2Tools); + +CGlobalVars *gpGlobals = NULL; + +sm_sendprop_info_t *playerSharedOffset; + +extern sp_nativeinfo_t g_TFNatives[]; + +int g_resourceEntity; + +SH_DECL_HOOK3_void(IServerGameDLL, ServerActivate, SH_NOATTRIB, 0, edict_t *, int , int); + +bool TF2Tools::SDK_OnLoad(char *error, size_t maxlength, bool late) +{ + ServerClass *sc = UTIL_FindServerClass("CTFPlayer"); + if (sc == NULL) + { + snprintf(error, maxlength, "Could not find CTFPlayer server class"); + + return false; + } + + playerSharedOffset = new sm_sendprop_info_t; + + if (!UTIL_FindDataTable(sc->m_pTable, "DT_TFPlayerShared", playerSharedOffset, 0)) + { + snprintf(error, maxlength, "Could not find DT_TFPlayerShared data table"); + + return false; + } + + sharesys->AddDependency(myself, "bintools.ext", true, true); + + char conf_error[255]; + if (!gameconfs->LoadGameConfigFile("sm-tf2.games", &g_pGameConf, conf_error, sizeof(conf_error))) + { + if (error) + { + snprintf(error, maxlength, "Could not read sm-tf2.games.txt: %s", conf_error); + } + return false; + } + + sharesys->AddNatives(myself, g_TFNatives); + sharesys->RegisterLibrary(myself, "tf2"); + + playerhelpers->RegisterCommandTargetProcessor(this); + + return true; +} + +bool TF2Tools::SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlen, bool late) +{ + GET_V_IFACE_CURRENT(GetEngineFactory, engine, IVEngineServer, INTERFACEVERSION_VENGINESERVER); + + gpGlobals = ismm->GetCGlobals(); + + SH_ADD_HOOK(IServerGameDLL, ServerActivate, gamedll, SH_STATIC(OnServerActivate), true); + + return true; +} + +void TF2Tools::SDK_OnUnload() +{ + SH_REMOVE_HOOK(IServerGameDLL, ServerActivate, gamedll, SH_STATIC(OnServerActivate), true); + + g_RegNatives.UnregisterAll(); + gameconfs->CloseGameConfigFile(g_pGameConf); + playerhelpers->UnregisterCommandTargetProcessor(this); +} + +void TF2Tools::SDK_OnAllLoaded() +{ + SM_GET_LATE_IFACE(BINTOOLS, g_pBinTools); +} + +bool TF2Tools::QueryRunning(char *error, size_t maxlength) +{ + SM_CHECK_IFACE(BINTOOLS, g_pBinTools); + + return true; +} + +bool TF2Tools::QueryInterfaceDrop(SMInterface *pInterface) +{ + if (pInterface == g_pBinTools) + { + return false; + } + + return IExtensionInterface::QueryInterfaceDrop(pInterface); +} + +void TF2Tools::NotifyInterfaceDrop(SMInterface *pInterface) +{ + g_RegNatives.UnregisterAll(); +} + +void OnServerActivate(edict_t *pEdictList, int edictCount, int clientMax) +{ + g_resourceEntity = FindResourceEntity(); +} + + +bool TF2Tools::ProcessCommandTarget(cmd_target_info_t *info) +{ + int max_clients; + IPlayerInfo *pInfo; + unsigned int team_index = 0; + IGamePlayer *pPlayer, *pAdmin; + + if ((info->flags & COMMAND_FILTER_NO_MULTI) == COMMAND_FILTER_NO_MULTI) + { + return false; + } + + if (info->admin) + { + if ((pAdmin = playerhelpers->GetGamePlayer(info->admin)) == NULL) + { + return false; + } + if (!pAdmin->IsInGame()) + { + return false; + } + } + else + { + pAdmin = NULL; + } + + if (strcmp(info->pattern, "@red") == 0 ) + { + team_index = 2; + } + else if (strcmp(info->pattern, "@blue") == 0) + { + team_index = 3; + } + else + { + return false; + } + + info->num_targets = 0; + + max_clients = playerhelpers->GetMaxClients(); + for (int i = 1; + i <= max_clients && (cell_t)info->num_targets < info->max_targets; + i++) + { + if ((pPlayer = playerhelpers->GetGamePlayer(i)) == NULL) + { + continue; + } + if (!pPlayer->IsInGame()) + { + continue; + } + if ((pInfo = pPlayer->GetPlayerInfo()) == NULL) + { + continue; + } + if (pInfo->GetTeamIndex() != (int)team_index) + { + continue; + } + if (playerhelpers->FilterCommandTarget(pAdmin, pPlayer, info->flags) + != COMMAND_TARGET_VALID) + { + continue; + } + info->targets[info->num_targets] = i; + info->num_targets++; + } + + if (info->num_targets == 0) + { + info->reason = COMMAND_TARGET_EMPTY_FILTER; + } + else + { + info->reason = COMMAND_TARGET_VALID; + } + + info->target_name_style = COMMAND_TARGETNAME_RAW; + if (team_index == 2) + { + UTIL_Format(info->target_name, info->target_name_maxlength, "Red Team"); + } + else if (team_index == 3) + { + UTIL_Format(info->target_name, info->target_name_maxlength, "Blue Team"); + } + + return true; +} + +int FindResourceEntity() +{ + return FindEntityByNetClass(-1, "CTFPlayerResource"); +} + + +int FindEntityByNetClass(int start, const char *classname) +{ + edict_t *current; + + for (int i = ((start != -1) ? start : 0); i < gpGlobals->maxEntities; i++) + { + current = engine->PEntityOfEntIndex(i); + if (current == NULL) + { + continue; + } + + IServerNetworkable *network = current->GetNetworkable(); + + if (network == NULL) + { + continue; + } + + ServerClass *sClass = network->GetServerClass(); + const char *name = sClass->GetName(); + + + if (strcmp(name, classname) == 0) + { + return i; + } + } + + return -1; +} + +TFClassType ClassnameToType(const char *classname) +{ + static KTrie trie; + static bool filled = false; + + if (!filled) + { + trie.insert("scout", TFClass_Scout); + trie.insert("scout", TFClass_Scout); + trie.insert("sniper", TFClass_Sniper); + trie.insert("soldier", TFClass_Soldier); + trie.insert("demoman", TFClass_DemoMan); + trie.insert("demo", TFClass_DemoMan); + trie.insert("medic", TFClass_Medic); + trie.insert("heavy", TFClass_Heavy); + trie.insert("hwg", TFClass_Heavy); + trie.insert("pyro", TFClass_Pyro); + trie.insert("spy", TFClass_Spy); + trie.insert("engineer", TFClass_Engineer); + trie.insert("engy", TFClass_Engineer); + + filled = true; + } + + TFClassType *value; + + if (!(value = trie.retrieve(classname))) + { + return TFClass_Unknown; + } + + return *value; +} + + + +/** + * A picture of a blue crab given to me as a gift and stored here for safe keeping + * + * http://www.democracycellproject.net/blog/archives/Clown%20car.jpg + */ + diff --git a/extensions/tf2/extension.h b/extensions/tf2/extension.h new file mode 100644 index 00000000..4a2b7adc --- /dev/null +++ b/extensions/tf2/extension.h @@ -0,0 +1,154 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod Team Fortress 2 Extension + * 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_EXTENSION_PROPER_H_ +#define _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_ + +/** + * @file extension.h + * @brief Sample extension code header. + */ + +#include "smsdk_ext.h" +#include + +/** + * @brief Sample implementation of the SDK Extension. + * Note: Uncomment one of the pre-defined virtual functions in order to use it. + */ +class TF2Tools : + public SDKExtension, + public ICommandTargetProcessor +{ +public: + /** + * @brief This is called after the initial loading sequence has been processed. + * + * @param error Error message buffer. + * @param maxlength Size of error message buffer. + * @param late Whether or not the module was loaded after map load. + * @return True to succeed loading, false to fail. + */ + virtual bool SDK_OnLoad(char *error, size_t maxlength, bool late); + + /** + * @brief This is called right before the extension is unloaded. + */ + virtual void SDK_OnUnload(); + + /** + * @brief This is called once all known extensions have been loaded. + * Note: It is is a good idea to add natives here, if any are provided. + */ + virtual void SDK_OnAllLoaded(); + + /** + * @brief Called when the pause state is changed. + */ + //virtual void SDK_OnPauseChange(bool paused); + + /** + * @brief this is called when Core wants to know if your extension is working. + * + * @param error Error message buffer. + * @param maxlength Size of error message buffer. + * @return True if working, false otherwise. + */ + virtual bool QueryRunning(char *error, size_t maxlength); + + void NotifyInterfaceDrop(SMInterface *pInterface); + bool QueryInterfaceDrop(SMInterface *pInterface); +public: + bool ProcessCommandTarget(cmd_target_info_t *info); +public: +#if defined SMEXT_CONF_METAMOD + /** + * @brief Called when Metamod is attached, before the extension version is called. + * + * @param error Error buffer. + * @param maxlength Maximum size of error buffer. + * @param late Whether or not Metamod considers this a late load. + * @return True to succeed, false to fail. + */ + virtual bool SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlength, bool late); + + /** + * @brief Called when Metamod is detaching, after the extension version is called. + * NOTE: By default this is blocked unless sent from SourceMod. + * + * @param error Error buffer. + * @param maxlength Maximum size of error buffer. + * @return True to succeed, false to fail. + */ + //virtual bool SDK_OnMetamodUnload(char *error, size_t maxlength); + + /** + * @brief Called when Metamod's pause state is changing. + * NOTE: By default this is blocked unless sent from SourceMod. + * + * @param paused Pause state being set. + * @param error Error buffer. + * @param maxlength Maximum size of error buffer. + * @return True to succeed, false to fail. + */ + //virtual bool SDK_OnMetamodPauseChange(bool paused, char *error, size_t maxlength); +#endif +}; + +enum TFClassType +{ + TFClass_Unknown = 0, + TFClass_Scout, + TFClass_Sniper, + TFClass_Soldier, + TFClass_DemoMan, + TFClass_Medic, + TFClass_Heavy, + TFClass_Pyro, + TFClass_Spy, + TFClass_Engineer +}; + +TFClassType ClassnameToType(const char *classname); + +extern IBinTools *g_pBinTools; +extern IGameConfig *g_pGameConf; +extern sm_sendprop_info_t *playerSharedOffset; + +void OnServerActivate(edict_t *pEdictList, int edictCount, int clientMax); + +int FindResourceEntity(); +int FindEntityByNetClass(int start, const char *classname); + +extern int g_resourceEntity; + + +#endif // _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_ diff --git a/extensions/tf2/msvc8/tf2.sln b/extensions/tf2/msvc8/tf2.sln new file mode 100644 index 00000000..5aa5277e --- /dev/null +++ b/extensions/tf2/msvc8/tf2.sln @@ -0,0 +1,32 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tf2", "tf2.vcproj", "{B3E797CF-4E77-4C9D-B8A8-7589B6902206}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug - Episode1|Win32 = Debug - Episode1|Win32 + Debug - Old Metamod|Win32 = Debug - Old Metamod|Win32 + Debug - Orange Box|Win32 = Debug - Orange Box|Win32 + Release - Episode 1|Win32 = Release - Episode 1|Win32 + Release - Old Metamod|Win32 = Release - Old Metamod|Win32 + Release - Orange Box|Win32 = Release - Orange Box|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Debug - Episode1|Win32.ActiveCfg = Debug - Episode1|Win32 + {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Debug - Episode1|Win32.Build.0 = Debug - Episode1|Win32 + {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Debug - Old Metamod|Win32.ActiveCfg = Debug - Old Metamod|Win32 + {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Debug - Old Metamod|Win32.Build.0 = Debug - Old Metamod|Win32 + {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Debug - Orange Box|Win32.ActiveCfg = Debug - Orange Box|Win32 + {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Debug - Orange Box|Win32.Build.0 = Debug - Orange Box|Win32 + {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Release - Episode 1|Win32.ActiveCfg = Release - Episode 1|Win32 + {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Release - Episode 1|Win32.Build.0 = Release - Episode 1|Win32 + {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Release - Old Metamod|Win32.ActiveCfg = Release - Old Metamod|Win32 + {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Release - Old Metamod|Win32.Build.0 = Release - Old Metamod|Win32 + {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Release - Orange Box|Win32.ActiveCfg = Release - Orange Box|Win32 + {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Release - Orange Box|Win32.Build.0 = Release - Orange Box|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/extensions/tf2/msvc8/tf2.vcproj b/extensions/tf2/msvc8/tf2.vcproj new file mode 100644 index 00000000..320051c1 --- /dev/null +++ b/extensions/tf2/msvc8/tf2.vcproj @@ -0,0 +1,735 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/extensions/tf2/natives.cpp b/extensions/tf2/natives.cpp new file mode 100644 index 00000000..f3220915 --- /dev/null +++ b/extensions/tf2/natives.cpp @@ -0,0 +1,258 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod Team Fortress 2 Extension + * 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 "extension.h" +#include "util.h" +#include "time.h" +#include "RegNatives.h" + + +// native TF2_Burn(client, target) +cell_t TF2_Burn(IPluginContext *pContext, const cell_t *params) +{ + static ICallWrapper *pWrapper = NULL; + + // CTFPlayerShared::Burn(CTFPlayer*) + if (!pWrapper) + { + REGISTER_NATIVE_ADDR("Burn", + PassInfo pass[1]; \ + pass[0].flags = PASSFLAG_BYVAL; \ + pass[0].size = sizeof(CBaseEntity *); \ + pass[0].type = PassType_Basic; \ + pWrapper = g_pBinTools->CreateCall(addr, CallConv_ThisCall, NULL, pass, 1)) + } + + CBaseEntity *pEntity; + if (!(pEntity = UTIL_GetCBaseEntity(params[1], true))) + { + return pContext->ThrowNativeError("Client index %d is not valid", params[1]); + } + + CBaseEntity *pTarget; + if (!(pTarget = UTIL_GetCBaseEntity(params[2], true))) + { + return pContext->ThrowNativeError("Client index %d is not valid", params[2]); + } + + void *obj = (void *)((uint8_t *)pEntity + playerSharedOffset->actual_offset); + + unsigned char vstk[sizeof(void *) + sizeof(CBaseEntity *)]; + unsigned char *vptr = vstk; + + *(void **)vptr = obj; + vptr += sizeof(void *); + *(CBaseEntity **)vptr = pTarget; + + pWrapper->Execute(vstk, NULL); + + return 1; +} + +// native TF2_Invuln(client, bool:enabled) +cell_t TF2_Invuln(IPluginContext *pContext, const cell_t *params) +{ + static ICallWrapper *pWrapper = NULL; + + //CTFPlayerShared::SetInvulnerable(bool, bool) + if (!pWrapper) + { + REGISTER_NATIVE_ADDR("Invuln", + PassInfo pass[2]; \ + pass[0].flags = PASSFLAG_BYVAL; \ + pass[0].size = sizeof(bool); \ + pass[0].type = PassType_Basic; \ + pass[1].flags = PASSFLAG_BYVAL; \ + pass[1].size = sizeof(bool); \ + pass[1].type = PassType_Basic; \ + pWrapper = g_pBinTools->CreateCall(addr, CallConv_ThisCall, NULL, pass, 2)) + } + + CBaseEntity *pEntity; + if (!(pEntity = UTIL_GetCBaseEntity(params[1], true))) + { + return pContext->ThrowNativeError("Client index %d is not valid", params[1]); + } + + void *obj = (void *)((uint8_t *)pEntity + playerSharedOffset->actual_offset); + + unsigned char vstk[sizeof(void *) + 2*sizeof(bool)]; + unsigned char *vptr = vstk; + + + *(void **)vptr = obj; + vptr += sizeof(void *); + *(bool *)vptr = !!params[2]; + vptr += sizeof(bool); + *(bool *)vptr = true; + + pWrapper->Execute(vstk, NULL); + + return 1; +} + +cell_t TF2_Disguise(IPluginContext *pContext, const cell_t *params) +{ + static ICallWrapper *pWrapper = NULL; + + //CTFPlayerShared::Disguise(int, int) + if (!pWrapper) + { + REGISTER_NATIVE_ADDR("Disguise", + PassInfo pass[2]; \ + pass[0].flags = PASSFLAG_BYVAL; \ + pass[0].size = sizeof(int); \ + pass[0].type = PassType_Basic; \ + pass[1].flags = PASSFLAG_BYVAL; \ + pass[1].size = sizeof(int); \ + pass[1].type = PassType_Basic; \ + pWrapper = g_pBinTools->CreateCall(addr, CallConv_ThisCall, NULL, pass, 2)) + } + + CBaseEntity *pEntity; + if (!(pEntity = UTIL_GetCBaseEntity(params[1], true))) + { + return pContext->ThrowNativeError("Client index %d is not valid", params[1]); + } + + void *obj = (void *)((uint8_t *)pEntity + playerSharedOffset->actual_offset); + + unsigned char vstk[sizeof(void *) + 2*sizeof(int)]; + unsigned char *vptr = vstk; + + + *(void **)vptr = obj; + vptr += sizeof(void *); + *(int *)vptr = params[2]; + vptr += sizeof(int); + *(int *)vptr = params[3]; + + pWrapper->Execute(vstk, NULL); + + return 1; +} + +cell_t TF2_RemoveDisguise(IPluginContext *pContext, const cell_t *params) +{ + static ICallWrapper *pWrapper = NULL; + + //CTFPlayerShared::RemoveDisguise() + if (!pWrapper) + { + REGISTER_NATIVE_ADDR("RemoveDisguise", + pWrapper = g_pBinTools->CreateCall(addr, CallConv_ThisCall, NULL, NULL, 0)) + } + + CBaseEntity *pEntity; + if (!(pEntity = UTIL_GetCBaseEntity(params[1], true))) + { + return pContext->ThrowNativeError("Client index %d is not valid", params[1]); + } + + void *obj = (void *)((uint8_t *)pEntity + playerSharedOffset->actual_offset); + + unsigned char vstk[sizeof(void *)]; + unsigned char *vptr = vstk; + + + *(void **)vptr = obj; + + pWrapper->Execute(vstk, NULL); + + return 1; +} + +cell_t TF2_Respawn(IPluginContext *pContext, const cell_t *params) +{ + static ICallWrapper *pWrapper = NULL; + + //CTFPlayer::ForceRespawn() + + if (!pWrapper) + { + int offset; + + if (!g_pGameConf->GetOffset("ForceRespawn", &offset)) + { + return pContext->ThrowNativeError("Failed to locate function"); + } + + pWrapper = g_pBinTools->CreateVCall(offset, + 0, + 0, + NULL, + NULL, + 0); + + g_RegNatives.Register(pWrapper); + } + + CBaseEntity *pEntity; + if (!(pEntity = UTIL_GetCBaseEntity(params[1], true))) + { + return pContext->ThrowNativeError("Client index %d is not valid", params[1]); + } + + unsigned char vstk[sizeof(void *)]; + unsigned char *vptr = vstk; + + + *(void **)vptr = (void *)pEntity; + + pWrapper->Execute(vstk, NULL); + + return 1; +} + +cell_t TF2_GetResourceEntity(IPluginContext *pContext, const cell_t *params) +{ + return g_resourceEntity; +} + +cell_t TF2_GetClass(IPluginContext *pContext, const cell_t *params) +{ + char *str; + pContext->LocalToString(params[1], &str); + + return (cell_t)ClassnameToType(str); +} + +sp_nativeinfo_t g_TFNatives[] = +{ + {"TF2_IgnitePlayer", TF2_Burn}, + {"TF2_SetPlayerInvuln", TF2_Invuln}, + {"TF2_RespawnPlayer", TF2_Respawn}, + {"TF2_DisguisePlayer", TF2_Disguise}, + {"TF2_RemovePlayerDisguise", TF2_RemoveDisguise}, + {"TF2_GetResourceEntity", TF2_GetResourceEntity}, + {"TF2_GetClass", TF2_GetClass}, + {NULL, NULL} +}; diff --git a/extensions/tf2/sdk/smsdk_config.h b/extensions/tf2/sdk/smsdk_config.h new file mode 100644 index 00000000..7356d772 --- /dev/null +++ b/extensions/tf2/sdk/smsdk_config.h @@ -0,0 +1,76 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod Team Fortress 2 Extension + * 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_EXTENSION_CONFIG_H_ +#define _INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_ + +/** + * @file smsdk_config.h + * @brief Contains macros for configuring basic extension information. + */ + +#include "svn_version.h" + +/* Basic information exposed publicly */ +#define SMEXT_CONF_NAME "TF2 Tools" +#define SMEXT_CONF_DESCRIPTION "TF2 extended functionality" +#define SMEXT_CONF_VERSION SVN_FULL_VERSION +#define SMEXT_CONF_AUTHOR "AlliedModders LLC" +#define SMEXT_CONF_URL "http://www.sourcemod.net/" +#define SMEXT_CONF_LOGTAG "TF2" +#define SMEXT_CONF_LICENSE "GPL" +#define SMEXT_CONF_DATESTRING __DATE__ + +/** + * @brief Exposes plugin's main interface. + */ +#define SMEXT_LINK(name) SDKExtension *g_pExtensionIface = name; + +/** + * @brief Sets whether or not this plugin required Metamod. + * NOTE: Uncomment to enable, comment to disable. + */ +#define SMEXT_CONF_METAMOD + +/** Enable interfaces you want to use here by uncommenting lines */ +//#define SMEXT_ENABLE_FORWARDSYS +//#define SMEXT_ENABLE_HANDLESYS +#define SMEXT_ENABLE_PLAYERHELPERS +//#define SMEXT_ENABLE_DBMANAGER +#define SMEXT_ENABLE_GAMECONF +//#define SMEXT_ENABLE_MEMUTILS +#define SMEXT_ENABLE_GAMEHELPERS +//#define SMEXT_ENABLE_TIMERSYS +//#define SMEXT_ENABLE_THREADER +//#define SMEXT_ENABLE_LIBSYS +//#define SMEXT_ENABLE_USERMSGS + +#endif // _INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_ diff --git a/extensions/tf2/sdk/smsdk_ext.cpp b/extensions/tf2/sdk/smsdk_ext.cpp new file mode 100644 index 00000000..cc9bee0e --- /dev/null +++ b/extensions/tf2/sdk/smsdk_ext.cpp @@ -0,0 +1,422 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod Team Fortress 2 Extension + * 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 +#include +#include "smsdk_ext.h" + +/** + * @file smsdk_ext.cpp + * @brief Contains wrappers for making Extensions easier to write. + */ + +IExtension *myself = NULL; /**< Ourself */ +IShareSys *g_pShareSys = NULL; /**< Share system */ +IShareSys *sharesys = NULL; /**< Share system */ +ISourceMod *g_pSM = NULL; /**< SourceMod helpers */ +ISourceMod *smutils = NULL; /**< SourceMod helpers */ + +#if defined SMEXT_ENABLE_FORWARDSYS +IForwardManager *g_pForwards = NULL; /**< Forward system */ +IForwardManager *forwards = NULL; /**< Forward system */ +#endif +#if defined SMEXT_ENABLE_HANDLESYS +IHandleSys *g_pHandleSys = NULL; /**< Handle system */ +IHandleSys *handlesys = NULL; /**< Handle system */ +#endif +#if defined SMEXT_ENABLE_PLAYERHELPERS +IPlayerManager *playerhelpers = NULL; /**< Player helpers */ +#endif //SMEXT_ENABLE_PLAYERHELPERS +#if defined SMEXT_ENABLE_DBMANAGER +IDBManager *dbi = NULL; /**< DB Manager */ +#endif //SMEXT_ENABLE_DBMANAGER +#if defined SMEXT_ENABLE_GAMECONF +IGameConfigManager *gameconfs = NULL; /**< Game config manager */ +#endif //SMEXT_ENABLE_DBMANAGER +#if defined SMEXT_ENABLE_MEMUTILS +IMemoryUtils *memutils = NULL; +#endif //SMEXT_ENABLE_DBMANAGER +#if defined SMEXT_ENABLE_GAMEHELPERS +IGameHelpers *gamehelpers = NULL; +#endif +#if defined SMEXT_ENABLE_TIMERSYS +ITimerSystem *timersys = NULL; +#endif +#if defined SMEXT_ENABLE_ADTFACTORY +IADTFactory *adtfactory = NULL; +#endif +#if defined SMEXT_ENABLE_THREADER +IThreader *threader = NULL; +#endif +#if defined SMEXT_ENABLE_LIBSYS +ILibrarySys *libsys = NULL; +#endif +#if defined SMEXT_ENABLE_USERMSGS +IUserMessages *usermsgs = NULL; +#endif + +/** Exports the main interface */ +PLATFORM_EXTERN_C IExtensionInterface *GetSMExtAPI() +{ + return g_pExtensionIface; +} + +SDKExtension::SDKExtension() +{ +#if defined SMEXT_CONF_METAMOD + m_SourceMMLoaded = false; + m_WeAreUnloaded = false; + m_WeGotPauseChange = false; +#endif +} + +bool SDKExtension::OnExtensionLoad(IExtension *me, IShareSys *sys, char *error, size_t maxlength, bool late) +{ + g_pShareSys = sharesys = sys; + myself = me; + +#if defined SMEXT_CONF_METAMOD + m_WeAreUnloaded = true; + + if (!m_SourceMMLoaded) + { + if (error) + { + snprintf(error, maxlength, "Metamod attach failed"); + } + return false; + } +#endif + SM_GET_IFACE(SOURCEMOD, g_pSM); + smutils = g_pSM; +#if defined SMEXT_ENABLE_HANDLESYS + SM_GET_IFACE(HANDLESYSTEM, g_pHandleSys); + handlesys = g_pHandleSys; +#endif +#if defined SMEXT_ENABLE_FORWARDSYS + SM_GET_IFACE(FORWARDMANAGER, g_pForwards); + forwards = g_pForwards; +#endif +#if defined SMEXT_ENABLE_PLAYERHELPERS + SM_GET_IFACE(PLAYERMANAGER, playerhelpers); +#endif +#if defined SMEXT_ENABLE_DBMANAGER + SM_GET_IFACE(DBI, dbi); +#endif +#if defined SMEXT_ENABLE_GAMECONF + SM_GET_IFACE(GAMECONFIG, gameconfs); +#endif +#if defined SMEXT_ENABLE_MEMUTILS + SM_GET_IFACE(MEMORYUTILS, memutils); +#endif +#if defined SMEXT_ENABLE_GAMEHELPERS + SM_GET_IFACE(GAMEHELPERS, gamehelpers); +#endif +#if defined SMEXT_ENABLE_TIMERSYS + SM_GET_IFACE(TIMERSYS, timersys); +#endif +#if defined SMEXT_ENABLE_ADTFACTORY + SM_GET_IFACE(ADTFACTORY, adtfactory); +#endif +#if defined SMEXT_ENABLE_THREADER + SM_GET_IFACE(THREADER, threader); +#endif +#if defined SMEXT_ENABLE_LIBSYS + SM_GET_IFACE(LIBRARYSYS, libsys); +#endif +#if defined SMEXT_ENABLE_USERMSGS + SM_GET_IFACE(USERMSGS, usermsgs); +#endif + + if (SDK_OnLoad(error, maxlength, late)) + { +#if defined SMEXT_CONF_METAMOD + m_WeAreUnloaded = true; +#endif + return true; + } + + return false; +} + +bool SDKExtension::IsMetamodExtension() +{ +#if defined SMEXT_CONF_METAMOD + return true; +#else + return false; +#endif +} + +void SDKExtension::OnExtensionPauseChange(bool state) +{ +#if defined SMEXT_CONF_METAMOD + m_WeGotPauseChange = true; +#endif + SDK_OnPauseChange(state); +} + +void SDKExtension::OnExtensionsAllLoaded() +{ + SDK_OnAllLoaded(); +} + +void SDKExtension::OnExtensionUnload() +{ +#if defined SMEXT_CONF_METAMOD + m_WeAreUnloaded = true; +#endif + SDK_OnUnload(); +} + +const char *SDKExtension::GetExtensionAuthor() +{ + return SMEXT_CONF_AUTHOR; +} + +const char *SDKExtension::GetExtensionDateString() +{ + return SMEXT_CONF_DATESTRING; +} + +const char *SDKExtension::GetExtensionDescription() +{ + return SMEXT_CONF_DESCRIPTION; +} + +const char *SDKExtension::GetExtensionVerString() +{ + return SMEXT_CONF_VERSION; +} + +const char *SDKExtension::GetExtensionName() +{ + return SMEXT_CONF_NAME; +} + +const char *SDKExtension::GetExtensionTag() +{ + return SMEXT_CONF_LOGTAG; +} + +const char *SDKExtension::GetExtensionURL() +{ + return SMEXT_CONF_URL; +} + +bool SDKExtension::SDK_OnLoad(char *error, size_t maxlength, bool late) +{ + return true; +} + +void SDKExtension::SDK_OnUnload() +{ +} + +void SDKExtension::SDK_OnPauseChange(bool paused) +{ +} + +void SDKExtension::SDK_OnAllLoaded() +{ +} + +#if defined SMEXT_CONF_METAMOD + +PluginId g_PLID = 0; /**< Metamod plugin ID */ +ISmmPlugin *g_PLAPI = NULL; /**< Metamod plugin API */ +SourceHook::ISourceHook *g_SHPtr = NULL; /**< SourceHook pointer */ +ISmmAPI *g_SMAPI = NULL; /**< SourceMM API pointer */ + +IVEngineServer *engine = NULL; /**< IVEngineServer pointer */ +IServerGameDLL *gamedll = NULL; /**< IServerGameDLL pointer */ + +/** Exposes the extension to Metamod */ +SMM_API void *PL_EXPOSURE(const char *name, int *code) +{ + if (name && !strcmp(name, METAMOD_PLAPI_NAME)) + { + if (code) + { + *code = IFACE_OK; + } + return static_cast(g_pExtensionIface); + } + + if (code) + { + *code = IFACE_FAILED; + } + + return NULL; +} + +bool SDKExtension::Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen, bool late) +{ + PLUGIN_SAVEVARS(); + + GET_V_IFACE_ANY(GetServerFactory, gamedll, IServerGameDLL, INTERFACEVERSION_SERVERGAMEDLL); + GET_V_IFACE_CURRENT(GetEngineFactory, engine, IVEngineServer, INTERFACEVERSION_VENGINESERVER); + + m_SourceMMLoaded = true; + + return SDK_OnMetamodLoad(ismm, error, maxlen, late); +} + +bool SDKExtension::Unload(char *error, size_t maxlen) +{ + if (!m_WeAreUnloaded) + { + if (error) + { + snprintf(error, maxlen, "This extension must be unloaded by SourceMod."); + } + return false; + } + + return SDK_OnMetamodUnload(error, maxlen); +} + +bool SDKExtension::Pause(char *error, size_t maxlen) +{ + if (!m_WeGotPauseChange) + { + if (error) + { + snprintf(error, maxlen, "This extension must be paused by SourceMod."); + } + return false; + } + + m_WeGotPauseChange = false; + + return SDK_OnMetamodPauseChange(true, error, maxlen); +} + +bool SDKExtension::Unpause(char *error, size_t maxlen) +{ + if (!m_WeGotPauseChange) + { + if (error) + { + snprintf(error, maxlen, "This extension must be unpaused by SourceMod."); + } + return false; + } + + m_WeGotPauseChange = false; + + return SDK_OnMetamodPauseChange(false, error, maxlen); +} + +const char *SDKExtension::GetAuthor() +{ + return GetExtensionAuthor(); +} + +const char *SDKExtension::GetDate() +{ + return GetExtensionDateString(); +} + +const char *SDKExtension::GetDescription() +{ + return GetExtensionDescription(); +} + +const char *SDKExtension::GetLicense() +{ + return SMEXT_CONF_LICENSE; +} + +const char *SDKExtension::GetLogTag() +{ + return GetExtensionTag(); +} + +const char *SDKExtension::GetName() +{ + return GetExtensionName(); +} + +const char *SDKExtension::GetURL() +{ + return GetExtensionURL(); +} + +const char *SDKExtension::GetVersion() +{ + return GetExtensionVerString(); +} + +bool SDKExtension::SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlength, bool late) +{ + return true; +} + +bool SDKExtension::SDK_OnMetamodUnload(char *error, size_t maxlength) +{ + return true; +} + +bool SDKExtension::SDK_OnMetamodPauseChange(bool paused, char *error, size_t maxlength) +{ + return true; +} + +#endif + +/* Overload a few things to prevent libstdc++ linking */ +#if defined __linux__ +extern "C" void __cxa_pure_virtual(void) +{ +} + +void *operator new(size_t size) +{ + return malloc(size); +} + +void *operator new[](size_t size) +{ + return malloc(size); +} + +void operator delete(void *ptr) +{ + free(ptr); +} + +void operator delete[](void * ptr) +{ + free(ptr); +} +#endif diff --git a/extensions/tf2/sdk/smsdk_ext.h b/extensions/tf2/sdk/smsdk_ext.h new file mode 100644 index 00000000..f2dae105 --- /dev/null +++ b/extensions/tf2/sdk/smsdk_ext.h @@ -0,0 +1,310 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod Team Fortress 2 Extension + * 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_EXTENSION_BASESDK_H_ +#define _INCLUDE_SOURCEMOD_EXTENSION_BASESDK_H_ + +/** + * @file smsdk_ext.h + * @brief Contains wrappers for making Extensions easier to write. + */ + +#include "smsdk_config.h" +#include +#include +#include +#include +#include +#if defined SMEXT_ENABLE_FORWARDSYS +#include +#endif //SMEXT_ENABLE_FORWARDSYS +#if defined SMEXT_ENABLE_PLAYERHELPERS +#include +#endif //SMEXT_ENABLE_PlAYERHELPERS +#if defined SMEXT_ENABLE_DBMANAGER +#include +#endif //SMEXT_ENABLE_DBMANAGER +#if defined SMEXT_ENABLE_GAMECONF +#include +#endif +#if defined SMEXT_ENABLE_MEMUTILS +#include +#endif +#if defined SMEXT_ENABLE_GAMEHELPERS +#include +#endif +#if defined SMEXT_ENABLE_TIMERSYS +#include +#endif +#if defined SMEXT_ENABLE_ADTFACTORY +#include +#endif +#if defined SMEXT_ENABLE_THREADER +#include +#endif +#if defined SMEXT_ENABLE_LIBSYS +#include +#endif +#if defined SMEXT_ENABLE_USERMSGS +#include +#endif + +#if defined SMEXT_CONF_METAMOD +#include +#include +#endif + +#if !defined METAMOD_PLAPI_VERSION + #include +#endif + +using namespace SourceMod; +using namespace SourcePawn; + +class SDKExtension : +#if defined SMEXT_CONF_METAMOD + public ISmmPlugin, +#endif + public IExtensionInterface +{ +public: + /** Constructor */ + SDKExtension(); +public: + /** + * @brief This is called after the initial loading sequence has been processed. + * + * @param error Error message buffer. + * @param maxlength Size of error message buffer. + * @param late Whether or not the module was loaded after map load. + * @return True to succeed loading, false to fail. + */ + virtual bool SDK_OnLoad(char *error, size_t maxlength, bool late); + + /** + * @brief This is called right before the extension is unloaded. + */ + virtual void SDK_OnUnload(); + + /** + * @brief This is called once all known extensions have been loaded. + */ + virtual void SDK_OnAllLoaded(); + + /** + * @brief Called when the pause state is changed. + */ + virtual void SDK_OnPauseChange(bool paused); + +#if defined SMEXT_CONF_METAMOD + /** + * @brief Called when Metamod is attached, before the extension version is called. + * + * @param error Error buffer. + * @param maxlength Maximum size of error buffer. + * @param late Whether or not Metamod considers this a late load. + * @return True to succeed, false to fail. + */ + virtual bool SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlength, bool late); + + /** + * @brief Called when Metamod is detaching, after the extension version is called. + * NOTE: By default this is blocked unless sent from SourceMod. + * + * @param error Error buffer. + * @param maxlength Maximum size of error buffer. + * @return True to succeed, false to fail. + */ + virtual bool SDK_OnMetamodUnload(char *error, size_t maxlength); + + /** + * @brief Called when Metamod's pause state is changing. + * NOTE: By default this is blocked unless sent from SourceMod. + * + * @param paused Pause state being set. + * @param error Error buffer. + * @param maxlength Maximum size of error buffer. + * @return True to succeed, false to fail. + */ + virtual bool SDK_OnMetamodPauseChange(bool paused, char *error, size_t maxlength); +#endif + +public: //IExtensionInterface + virtual bool OnExtensionLoad(IExtension *me, IShareSys *sys, char *error, size_t maxlength, bool late); + virtual void OnExtensionUnload(); + virtual void OnExtensionsAllLoaded(); + + /** Returns whether or not this is a Metamod-based extension */ + virtual bool IsMetamodExtension(); + + /** + * @brief Called when the pause state changes. + * + * @param state True if being paused, false if being unpaused. + */ + virtual void OnExtensionPauseChange(bool state); + + /** Returns name */ + virtual const char *GetExtensionName(); + /** Returns URL */ + virtual const char *GetExtensionURL(); + /** Returns log tag */ + virtual const char *GetExtensionTag(); + /** Returns author */ + virtual const char *GetExtensionAuthor(); + /** Returns version string */ + virtual const char *GetExtensionVerString(); + /** Returns description string */ + virtual const char *GetExtensionDescription(); + /** Returns date string */ + virtual const char *GetExtensionDateString(); +#if defined SMEXT_CONF_METAMOD +public: //ISmmPlugin + /** Called when the extension is attached to Metamod. */ + virtual bool Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlength, bool late); + /** Returns the author to MM */ + virtual const char *GetAuthor(); + /** Returns the name to MM */ + virtual const char *GetName(); + /** Returns the description to MM */ + virtual const char *GetDescription(); + /** Returns the URL to MM */ + virtual const char *GetURL(); + /** Returns the license to MM */ + virtual const char *GetLicense(); + /** Returns the version string to MM */ + virtual const char *GetVersion(); + /** Returns the date string to MM */ + virtual const char *GetDate(); + /** Returns the logtag to MM */ + virtual const char *GetLogTag(); + /** Called on unload */ + virtual bool Unload(char *error, size_t maxlength); + /** Called on pause */ + virtual bool Pause(char *error, size_t maxlength); + /** Called on unpause */ + virtual bool Unpause(char *error, size_t maxlength); +private: + bool m_SourceMMLoaded; + bool m_WeAreUnloaded; + bool m_WeGotPauseChange; +#endif +}; + +extern SDKExtension *g_pExtensionIface; +extern IExtension *myself; + +extern IShareSys *g_pShareSys; +extern IShareSys *sharesys; /* Note: Newer name */ +extern ISourceMod *g_pSM; +extern ISourceMod *smutils; /* Note: Newer name */ + +/* Optional interfaces are below */ +#if defined SMEXT_ENABLE_FORWARDSYS +extern IForwardManager *g_pForwards; +extern IForwardManager *forwards; /* Note: Newer name */ +#endif //SMEXT_ENABLE_FORWARDSYS +#if defined SMEXT_ENABLE_HANDLESYS +extern IHandleSys *g_pHandleSys; +extern IHandleSys *handlesys; /* Note: Newer name */ +#endif //SMEXT_ENABLE_HANDLESYS +#if defined SMEXT_ENABLE_PLAYERHELPERS +extern IPlayerManager *playerhelpers; +#endif //SMEXT_ENABLE_PLAYERHELPERS +#if defined SMEXT_ENABLE_DBMANAGER +extern IDBManager *dbi; +#endif //SMEXT_ENABLE_DBMANAGER +#if defined SMEXT_ENABLE_GAMECONF +extern IGameConfigManager *gameconfs; +#endif //SMEXT_ENABLE_DBMANAGER +#if defined SMEXT_ENABLE_MEMUTILS +extern IMemoryUtils *memutils; +#endif +#if defined SMEXT_ENABLE_GAMEHELPERS +extern IGameHelpers *gamehelpers; +#endif +#if defined SMEXT_ENABLE_TIMERSYS +extern ITimerSystem *timersys; +#endif +#if defined SMEXT_ENABLE_ADTFACTORY +extern IADTFactory *adtfactory; +#endif +#if defined SMEXT_ENABLE_THREADER +extern IThreader *threader; +#endif +#if defined SMEXT_ENABLE_LIBSYS +extern ILibrarySys *libsys; +#endif +#if defined SMEXT_ENABLE_USERMSGS +extern IUserMessages *usermsgs; +#endif + +#if defined SMEXT_CONF_METAMOD +PLUGIN_GLOBALVARS(); +extern IVEngineServer *engine; +extern IServerGameDLL *gamedll; +#endif + +/** Creates a SourceMod interface macro pair */ +#define SM_MKIFACE(name) SMINTERFACE_##name##_NAME, SMINTERFACE_##name##_VERSION +/** Automates retrieving SourceMod interfaces */ +#define SM_GET_IFACE(prefix, addr) \ + if (!g_pShareSys->RequestInterface(SM_MKIFACE(prefix), myself, (SMInterface **)&addr)) \ + { \ + if (error != NULL && maxlength) \ + { \ + size_t len = snprintf(error, maxlength, "Could not find interface: %s", SMINTERFACE_##prefix##_NAME); \ + if (len >= maxlength) \ + { \ + error[maxlength - 1] = '\0'; \ + } \ + } \ + return false; \ + } +/** Automates retrieving SourceMod interfaces when needed outside of SDK_OnLoad() */ +#define SM_GET_LATE_IFACE(prefix, addr) \ + g_pShareSys->RequestInterface(SM_MKIFACE(prefix), myself, (SMInterface **)&addr) +/** Validates a SourceMod interface pointer */ +#define SM_CHECK_IFACE(prefix, addr) \ + if (!addr) \ + { \ + if (error != NULL && maxlength) \ + { \ + size_t len = snprintf(error, maxlength, "Could not find interface: %s", SMINTERFACE_##prefix##_NAME); \ + if (len >= maxlength) \ + { \ + error[maxlength - 1] = '\0'; \ + } \ + } \ + return false; \ + } + +#endif // _INCLUDE_SOURCEMOD_EXTENSION_BASESDK_H_ diff --git a/extensions/tf2/util.cpp b/extensions/tf2/util.cpp new file mode 100644 index 00000000..678102ef --- /dev/null +++ b/extensions/tf2/util.cpp @@ -0,0 +1,134 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod Team Fortress 2 Extension + * 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 "extension.h" +#include "util.h" + +size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + size_t len = vsnprintf(buffer, maxlength, fmt, ap); + va_end(ap); + + if (len >= maxlength) + { + buffer[maxlength - 1] = '\0'; + return (maxlength - 1); + } + else + { + return len; + } +} + +bool UTIL_FindDataTable(SendTable *pTable, + const char *name, + sm_sendprop_info_t *info, + unsigned int offset) +{ + const char *pname; + int props = pTable->GetNumProps(); + SendProp *prop; + SendTable *table; + + for (int i=0; iGetProp(i); + + if ((table = prop->GetDataTable()) != NULL) + { + pname = table->GetName(); + if (pname && strcmp(name, pname) == 0) + { + info->prop = prop; + info->actual_offset = offset + info->prop->GetOffset(); + return true; + } + + if (UTIL_FindDataTable(table, + name, + info, + offset + prop->GetOffset()) + ) + { + return true; + } + } + } + + return false; +} + +ServerClass *UTIL_FindServerClass(const char *classname) +{ + ServerClass *sc = gamedll->GetAllServerClasses(); + while (sc) + { + if (strcmp(classname, sc->GetName()) == 0) + { + return sc; + } + sc = sc->m_pNext; + } + + return NULL; +} + +CBaseEntity *UTIL_GetCBaseEntity(int num, bool onlyPlayers) +{ + edict_t *pEdict = engine->PEntityOfEntIndex(num); + if (!pEdict || pEdict->IsFree()) + { + return NULL; + } + + if (num > 0 && num < playerhelpers->GetMaxClients()) + { + IGamePlayer *pPlayer = playerhelpers->GetGamePlayer(pEdict); + if (!pPlayer || !pPlayer->IsConnected()) + { + return NULL; + } + } + else if (onlyPlayers) + { + return NULL; + } + + IServerUnknown *pUnk; + if ((pUnk=pEdict->GetUnknown()) == NULL) + { + return NULL; + } + + return pUnk->GetBaseEntity(); +} diff --git a/extensions/tf2/util.h b/extensions/tf2/util.h new file mode 100644 index 00000000..a79f09d0 --- /dev/null +++ b/extensions/tf2/util.h @@ -0,0 +1,57 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod Team Fortress 2 Extension + * 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_TF2TOOLS_UTIL_H_ +#define _INCLUDE_TF2TOOLS_UTIL_H_ + +#define REGISTER_NATIVE_ADDR(name, code) \ + void *addr; \ + if (!g_pGameConf->GetMemSig(name, &addr) || !addr) \ + { \ + return pContext->ThrowNativeError("Failed to locate function"); \ + } \ + code; \ + g_RegNatives.Register(pWrapper); + + +size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...); + +bool UTIL_FindDataTable(SendTable *pTable, + const char *name, + sm_sendprop_info_t *info, + unsigned int offset); + +ServerClass *UTIL_FindServerClass(const char *classname); + +CBaseEntity *UTIL_GetCBaseEntity(int num, bool onlyPlayers); + + +#endif //_INCLUDE_TF2TOOLS_UTIL_H_ diff --git a/gamedata/sdktools.games.ep2.txt b/gamedata/sdktools.games.ep2.txt index 65a430be..fdf04d04 100644 --- a/gamedata/sdktools.games.ep2.txt +++ b/gamedata/sdktools.games.ep2.txt @@ -276,6 +276,11 @@ "windows" "34" "linux" "35" } + "WeaponEquip" + { + "windows" "227" + "linux" "228" + } } } /* EntityFactoryDictionary function */ @@ -291,4 +296,29 @@ } } } + /* CBaseEntityOutput::FireOutput */ + "#default" + { + "#supported" + { + "game" "tf" + } + "Signatures" + { + "FireOutput" + { + "library" "server" + "windows" "\x81\xEC\x1C\x01\x00\x00\x53\x55\x56\x8B\x71\x14\x85\xF6" + "linux" "@_ZN17CBaseEntityOutput10FireOutputE9variant_tP11CBaseEntityS2_f" + } + } + "Offsets" + { + "FireOutputBackup" + { + "windows" "6" + "linux" "10" + } + } + } } diff --git a/gamedata/sdktools.games.txt b/gamedata/sdktools.games.txt index cd53d356..7a5e99de 100644 --- a/gamedata/sdktools.games.txt +++ b/gamedata/sdktools.games.txt @@ -332,6 +332,11 @@ "windows" "25" "linux" "26" } + "WeaponEquip" + { + "windows" "217" + "linux" "218" + } } } @@ -1693,5 +1698,31 @@ } } } + /* CBaseEntityOutput::FireOutput */ + "#default" + { + "#supported" + { + "game" "cstrike" + "game" "hl2mp" + } + "Signatures" + { + "FireOutput" + { + "library" "server" + "windows" "\x81\xEC\x1C\x03\x00\x00\x53\x55\x56\x8B\x71\x14" + "linux" "@_ZN17CBaseEntityOutput10FireOutputE9variant_tP11CBaseEntityS2_f" + } + } + "Offsets" + { + "FireOutputBackup" + { + "windows" "6" + "linux" "6" + } + } + } } diff --git a/gamedata/sm-tf2.games.txt b/gamedata/sm-tf2.games.txt new file mode 100644 index 00000000..c7bf3740 --- /dev/null +++ b/gamedata/sm-tf2.games.txt @@ -0,0 +1,42 @@ +"Games" +{ + "tf" + { + "Signatures" + { + "Burn" + { + "library" "server" + "windows" "\x56\x8B\xF1\x8B\x4E\x7C\x8B\x01\x8B\x90\xF8\x00\x00\x00\xFF\xD2\x84\xC0\x2A\x2A\x2A\x2A\x2A\x2A\x8B\x46\x7C" + "linux" "@_ZN15CTFPlayerShared4BurnEP9CTFPlayer" + } + "Invuln" + { + "library" "server" + "windows" "\x8A\x44\x24\x04\x83\xEC\x20\x56\x8B\xF1\x8B\x4E\x08\x57\x8D\x7E\x08\xC1\xE9\x05\x80\xE1\x01\x3A\xC8\x75\x32\x84\xC0" + "linux" "@_ZN15CTFPlayerShared15SetInvulnerableEbb" + } + "RemoveDisguise" + { + "library" "server" + "windows" "\x51\x56\x8B\xF1\x8B\x46\x08\x57\x8D\x7E\x08\x8D\x4C\x24\x08\x83\xE0\xF7" + "linux" "@_ZN15CTFPlayerShared14RemoveDisguiseEv" + } + "Disguise" + { + "library" "server" + "windows" "\x56\x8B\xF1\x8B\x4E\x7C\xE8" + "linux" "@_ZN15CTFPlayerShared8DisguiseEii" + } + + } + "Offsets" + { + "ForceRespawn" + { + "windows" "279" + "linux" "280" + } + } + } +} \ No newline at end of file diff --git a/loader/msvc8/loader.vcproj b/loader/msvc8/loader.vcproj index a84f17d6..1188ff0e 100644 --- a/loader/msvc8/loader.vcproj +++ b/loader/msvc8/loader.vcproj @@ -65,6 +65,7 @@ Name="VCLinkerTool" OutputFile="$(OutDir)\sourcemod_mm.dll" LinkIncremental="2" + IgnoreDefaultLibraryNames="LIBC;LIBCD;LIBCMT" GenerateDebugInformation="true" SubSystem="2" TargetMachine="1" @@ -143,6 +144,7 @@ Name="VCLinkerTool" OutputFile="$(OutDir)\sourcemod_mm.dll" LinkIncremental="1" + IgnoreDefaultLibraryNames="LIBC;LIBCD;LIBCMTD" GenerateDebugInformation="true" SubSystem="2" OptimizeReferences="2" diff --git a/plugins/adminmenu.sp b/plugins/adminmenu.sp index 8a68b46c..d3985ed5 100644 --- a/plugins/adminmenu.sp +++ b/plugins/adminmenu.sp @@ -45,6 +45,8 @@ public Plugin:myinfo = url = "http://www.sourcemod.net/" }; +new g_maxPlayers; + /* Forwards */ new Handle:hOnAdminMenuReady = INVALID_HANDLE; new Handle:hOnAdminMenuCreated = INVALID_HANDLE; @@ -57,6 +59,8 @@ new TopMenuObject:obj_playercmds = INVALID_TOPMENUOBJECT; new TopMenuObject:obj_servercmds = INVALID_TOPMENUOBJECT; new TopMenuObject:obj_votingcmds = INVALID_TOPMENUOBJECT; +#include "adminmenu/dynamicmenu.sp" + public bool:AskPluginLoad(Handle:myself, bool:late, String:error[], err_max) { CreateNative("GetAdminTopMenu", __GetAdminTopMenu); @@ -91,27 +95,36 @@ public OnConfigsExecuted() } } +public OnMapStart() +{ + g_maxPlayers = GetMaxClients(); + + ParseConfigs(); +} + public OnAllPluginsLoaded() { - hAdminMenu = CreateTopMenu(CategoryHandler); + hAdminMenu = CreateTopMenu(DefaultCategoryHandler); obj_playercmds = AddToTopMenu(hAdminMenu, "PlayerCommands", TopMenuObject_Category, - CategoryHandler, + DefaultCategoryHandler, INVALID_TOPMENUOBJECT); obj_servercmds = AddToTopMenu(hAdminMenu, "ServerCommands", TopMenuObject_Category, - CategoryHandler, + DefaultCategoryHandler, INVALID_TOPMENUOBJECT); obj_votingcmds = AddToTopMenu(hAdminMenu, "VotingCommands", TopMenuObject_Category, - CategoryHandler, + DefaultCategoryHandler, INVALID_TOPMENUOBJECT); + + BuildDynamicMenu(); Call_StartForward(hOnAdminMenuCreated); Call_PushCell(hAdminMenu); @@ -122,7 +135,7 @@ public OnAllPluginsLoaded() Call_Finish(); } -public CategoryHandler(Handle:topmenu, +public DefaultCategoryHandler(Handle:topmenu, TopMenuAction:action, TopMenuObject:object_id, param, diff --git a/plugins/adminmenu/dynamicmenu.sp b/plugins/adminmenu/dynamicmenu.sp new file mode 100644 index 00000000..00df74ee --- /dev/null +++ b/plugins/adminmenu/dynamicmenu.sp @@ -0,0 +1,623 @@ + +#define NAME_LENGTH 32 +#define CMD_LENGTH 255 + +#define ARRAY_STRING_LENGTH 32 + +enum GroupCommands +{ + Handle:groupListName, + Handle:groupListCommand +}; + +new g_groupList[GroupCommands]; +new g_groupCount; + +new Handle:g_configParser = INVALID_HANDLE; + +enum Places +{ + Place_Category, + Place_Item, + Place_ReplaceNum +}; + +new String:g_command[MAXPLAYERS+1][CMD_LENGTH]; +new g_currentPlace[MAXPLAYERS+1][Places]; + +/** + * What to put in the 'info' menu field (for PlayerList and Player_Team menus only) + */ +enum PlayerMethod +{ + ClientId, /** Client id number ( 1 - Maxplayers) */ + UserId, /** Client userid */ + Name, /** Client Name */ + SteamId, /** Client Steamid */ + IpAddress, /** Client's Ip Address */ + UserId2 /** Userid (not prefixed with #) */ +}; + +enum ExecuteType +{ + Execute_Player, + Execute_Server +} + +enum SubMenu_Type +{ + SubMenu_Group, + SubMenu_GroupPlayer, + SubMenu_Player, + SubMenu_MapCycle, + SubMenu_List, + SubMenu_OnOff +} + +enum Item +{ + String:Item_cmd[256], + ExecuteType:Item_execute, + Handle:Item_submenus +} + +enum Submenu +{ + SubMenu_Type:Submenu_type, + String:Submenu_title[32], + PlayerMethod:Submenu_method, + Submenu_listcount, + Handle:Submenu_listdata +} + +new Handle:g_DataArray; + +BuildDynamicMenu() +{ + new itemInput[Item]; + g_DataArray = CreateArray(sizeof(itemInput)); + + new String:executeBuffer[32]; + + new Handle:kvMenu; + kvMenu = CreateKeyValues("Commands"); + new String:file[256]; + BuildPath(Path_SM, file, 255, "configs/dynamicmenu/menu.ini"); + FileToKeyValues(kvMenu, file); + + new String:name[NAME_LENGTH]; + new String:buffer[NAME_LENGTH]; + + KvSetEscapeSequences(kvMenu, true); + + if (!KvGotoFirstSubKey(kvMenu)) + { + return; + } + + decl String:admin[30]; + + new TopMenuObject:categoryId; + + do + { + KvGetSectionName(kvMenu, buffer, sizeof(buffer)); + + KvGetString(kvMenu, "admin", admin, sizeof(admin),"sm_admin"); + + if ((categoryId =FindTopMenuCategory(hAdminMenu, buffer)) == INVALID_TOPMENUOBJECT) + { + categoryId = AddToTopMenu(hAdminMenu, + buffer, + TopMenuObject_Category, + DynamicMenuCategoryHandler, + INVALID_TOPMENUOBJECT, + admin, + ADMFLAG_GENERIC, + name); + + } + + if (!KvGotoFirstSubKey(kvMenu)) + { + return; + } + + do + { + KvGetSectionName(kvMenu, buffer, sizeof(buffer)); + + KvGetString(kvMenu, "admin", admin, sizeof(admin),""); + + if (admin[0] == '\0') + { + //No 'admin' keyvalue was found + //Use the first argument of the 'cmd' string instead + + decl String:temp[64]; + KvGetString(kvMenu, "cmd", temp, sizeof(temp),""); + + BreakString(temp, admin, sizeof(admin)); + } + + + KvGetString(kvMenu, "cmd", itemInput[Item_cmd], sizeof(itemInput[Item_cmd])); + KvGetString(kvMenu, "execute", executeBuffer, sizeof(executeBuffer)); + + if (StrEqual(executeBuffer, "server")) + { + itemInput[Item_execute] = Execute_Server; + } + else //assume player type execute + { + itemInput[Item_execute] = Execute_Player; + } + + /* iterate all submenus and load data into itemInput[Item_submenus] (adt array handle) */ + + new count = 1; + decl String:countBuffer[10] = "1"; + + decl String:inputBuffer[32]; + + while (KvJumpToKey(kvMenu, countBuffer)) + { + new submenuInput[Submenu]; + + if (count == 1) + { + itemInput[Item_submenus] = CreateArray(sizeof(submenuInput)); + } + + KvGetString(kvMenu, "type", inputBuffer, sizeof(inputBuffer)); + + if (strncmp(inputBuffer,"group",5)==0) + { + if (StrContains(inputBuffer, "player") != -1) + { + submenuInput[Submenu_type] = SubMenu_GroupPlayer; + } + else + { + submenuInput[Submenu_type] = SubMenu_Group; + } + } + else if (StrEqual(inputBuffer,"mapcycle")) + { + submenuInput[Submenu_type] = SubMenu_MapCycle; + + KvGetString(kvMenu, "path", inputBuffer, sizeof(inputBuffer),"mapcycle.txt"); + + submenuInput[Submenu_listdata] = CreateDataPack(); + WritePackString(submenuInput[Submenu_listdata], inputBuffer); + ResetPack(submenuInput[Submenu_listdata]); + } + else if (StrContains(inputBuffer, "player") != -1) + { + submenuInput[Submenu_type] = SubMenu_Player; + } + else if (StrEqual(inputBuffer,"onoff")) + { + submenuInput[Submenu_type] = SubMenu_OnOff; + } + else //assume 'list' type + { + submenuInput[Submenu_type] = SubMenu_List; + + submenuInput[Submenu_listdata] = CreateDataPack(); + + new String:temp[6]; + new String:value[64]; + new String:text[64]; + new i=1; + new bool:more = true; + + new listcount = 0; + + do + { + Format(temp,3,"%i",i); + KvGetString(kvMenu, temp, value, sizeof(value), ""); + + Format(temp,5,"%i.",i); + KvGetString(kvMenu, temp, text, sizeof(text), value); + + Format(temp,5,"%i*",i); + KvGetString(kvMenu, temp, admin, sizeof(admin),""); + + if (value[0]=='\0') + { + more = false; + } + else + { + listcount++; + WritePackString(submenuInput[Submenu_listdata], value); + WritePackString(submenuInput[Submenu_listdata], text); + WritePackString(submenuInput[Submenu_listdata], admin); + } + + i++; + + } while (more); + + ResetPack(submenuInput[Submenu_listdata]); + submenuInput[Submenu_listcount] = listcount; + } + + if ((submenuInput[Submenu_type] == SubMenu_Player) || (submenuInput[Submenu_type] == SubMenu_GroupPlayer)) + { + KvGetString(kvMenu, "method", inputBuffer, sizeof(inputBuffer)); + + if (StrEqual(inputBuffer, "clientid")) + { + submenuInput[Submenu_method] = ClientId; + } + else if (StrEqual(inputBuffer, "steamid")) + { + submenuInput[Submenu_method] = SteamId; + } + else if (StrEqual(inputBuffer, "userid2")) + { + submenuInput[Submenu_method] = UserId2; + } + else if (StrEqual(inputBuffer, "userid")) + { + submenuInput[Submenu_method] = UserId; + } + else if (StrEqual(inputBuffer, "ip")) + { + submenuInput[Submenu_method] = IpAddress; + } + else + { + submenuInput[Submenu_method] = Name; + } + + } + + KvGetString(kvMenu, "title", inputBuffer, sizeof(inputBuffer)); + strcopy(submenuInput[Submenu_title], sizeof(submenuInput[Submenu_title]), inputBuffer); + + count++; + Format(countBuffer, sizeof(countBuffer), "%i", count); + + PushArrayArray(itemInput[Item_submenus], submenuInput[0]); + + KvGoBack(kvMenu); + } + + /* Save this entire item into the global items array and add it to the menu */ + + new location = PushArrayArray(g_DataArray, itemInput[0]); + + decl String:locString[10]; + IntToString(location, locString, sizeof(locString)); + + AddToTopMenu(hAdminMenu, + buffer, + TopMenuObject_Item, + DynamicMenuItemHandler, + categoryId, + admin, + ADMFLAG_GENERIC, + locString); + + } while (KvGotoNextKey(kvMenu)); + + KvGoBack(kvMenu); + + } while (KvGotoNextKey(kvMenu)); + + CloseHandle(kvMenu); +} + +ParseConfigs() +{ + if (g_configParser == INVALID_HANDLE) + { + g_configParser = SMC_CreateParser(); + } + + SMC_SetReaders(g_configParser, NewSection, KeyValue, EndSection); + + if (g_groupList[groupListName] != INVALID_HANDLE) + { + CloseHandle(g_groupList[groupListName]); + } + + if (g_groupList[groupListCommand] != INVALID_HANDLE) + { + CloseHandle(g_groupList[groupListCommand]); + } + + g_groupList[groupListName] = CreateArray(ARRAY_STRING_LENGTH); + g_groupList[groupListCommand] = CreateArray(ARRAY_STRING_LENGTH); + + decl String:configPath[256]; + BuildPath(Path_SM, configPath, sizeof(configPath), "configs/dynamicmenu/adminmenu_grouping.txt"); + + if (!FileExists(configPath)) + { + LogError("Unable to locate admin menu groups file, no groups loaded."); + + return; + } + + new line; + new SMCError:err = SMC_ParseFile(g_configParser, configPath, line); + if (err != SMCError_Okay) + { + decl String:error[256]; + SMC_GetErrorString(err, error, sizeof(error)); + LogError("Could not parse file (line %d, file \"%s\"):", line, configPath); + LogError("Parser encountered error: %s", error); + } + + return; +} + +public SMCResult:NewSection(Handle:smc, const String:name[], bool:opt_quotes) +{ + +} + +public SMCResult:KeyValue(Handle:smc, const String:key[], const String:value[], bool:key_quotes, bool:value_quotes) +{ + PushArrayString(g_groupList[groupListName], key); + PushArrayString(g_groupList[groupListCommand], value); +} + +public SMCResult:EndSection(Handle:smc) +{ + g_groupCount = GetArraySize(g_groupList[groupListName]); +} + +public DynamicMenuCategoryHandler(Handle:topmenu, + TopMenuAction:action, + TopMenuObject:object_id, + param, + String:buffer[], + maxlength) +{ + if ((action == TopMenuAction_DisplayTitle) || (action == TopMenuAction_DisplayOption)) + { + GetTopMenuObjName(topmenu, object_id, buffer, maxlength); + } +} + +public DynamicMenuItemHandler(Handle:topmenu, + TopMenuAction:action, + TopMenuObject:object_id, + param, + String:buffer[], + maxlength) +{ + if (action == TopMenuAction_DisplayOption) + { + GetTopMenuObjName(topmenu, object_id, buffer, maxlength); + } + else if (action == TopMenuAction_SelectOption) + { + new String:locString[10]; + GetTopMenuInfoString(topmenu, object_id, locString, sizeof(locString)); + + new location = StringToInt(locString); + + new output[Item]; + GetArrayArray(g_DataArray, location, output[0]); + + strcopy(g_command[param], sizeof(g_command[]), output[Item_cmd]); + + g_currentPlace[param][Place_Item] = location; + + ParamCheck(param); + } +} + +public ParamCheck(client) +{ + new String:buffer[6]; + new String:buffer2[6]; + + new outputItem[Item]; + new outputSubmenu[Submenu]; + + GetArrayArray(g_DataArray, g_currentPlace[client][Place_Item], outputItem[0]); + + if (g_currentPlace[client][Place_ReplaceNum] < 1) + { + g_currentPlace[client][Place_ReplaceNum] = 1; + } + + Format(buffer, 5, "#%i", g_currentPlace[client][Place_ReplaceNum]); + Format(buffer2, 5, "@%i", g_currentPlace[client][Place_ReplaceNum]); + + if (StrContains(g_command[client], buffer) != -1 || StrContains(g_command[client], buffer2) != -1) + { + GetArrayArray(outputItem[Item_submenus], g_currentPlace[client][Place_ReplaceNum] - 1, outputSubmenu[0]); + + new Handle:itemMenu = CreateMenu(Menu_Selection); + + if ((outputSubmenu[Submenu_type] == SubMenu_Group) || (outputSubmenu[Submenu_type] == SubMenu_GroupPlayer)) + { + decl String:nameBuffer[ARRAY_STRING_LENGTH]; + decl String:commandBuffer[ARRAY_STRING_LENGTH]; + + for (new i = 0; i #include #include +#include enum SDKCallType { diff --git a/plugins/include/sdktools_entoutput.inc b/plugins/include/sdktools_entoutput.inc new file mode 100644 index 00000000..d728e23f --- /dev/null +++ b/plugins/include/sdktools_entoutput.inc @@ -0,0 +1,91 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This file is part of the SourceMod/SourcePawn SDK. + * + * 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$ + */ + +#if defined _sdktools_entoutput_included + #endinput +#endif +#define _sdktools_entoutput_included + +/** + * Called when an entity output is fired. + * + * @param output Name of the output that fired. + * @param caller Entity index of the caller. + * @param activator Entity index of the activator. + * @param delay Delay in seconds? before the event gets fired. + */ +functag EntityOutput public(const String:output[], caller, activator, Float:delay); + +/** + * Add an entity output hook on a entity classname + * + * @param classname The classname to hook. + * @param output The output name to hook. + * @param callback An EntityOutput function pointer. + * @noreturn + * @error Entity Outputs disabled. + */ +native HookEntityOutput(const String:classname[], const String:output[], EntityOutput:callback); + +/** + * Remove an entity output hook. + * @param classname The classname to hook. + * @param output The output name to hook. + * @param callback An EntityOutput function pointer. + * @return True on success, false if no valid hook was found. + * @error Entity Outputs disabled. + */ +native bool:UnhookEntityOutput(const String:classname[], const String:output[], EntityOutput:callback); + +/** + * Add an entity output hook on a single entity instance + * + * @param entity The entity on which to add a hook. + * @param output The output name to hook. + * @param callback An EntityOutput function pointer. + * @param once Only fire this hook once and then remove itself. + * @noreturn + * @error Entity Outputs disabled or Invalid Entity index. + */ +native HookSingleEntityOutput(entity, const String:output[], EntityOutput:callback , bool:once=false); + +/** + * Remove a single entity output hook. + * + * @param entity The entity on which to remove the hook. + * @param output The output name to hook. + * @param callback An EntityOutput function pointer. + * @return True on success, false if no valid hook was found. + * @error Entity Outputs disabled or Invalid Entity index. + */ +native bool:UnhookSingleEntityOutput(entity, const String:output[], EntityOutput:callback); + diff --git a/plugins/include/sdktools_functions.inc b/plugins/include/sdktools_functions.inc index 1765878c..aef9357b 100644 --- a/plugins/include/sdktools_functions.inc +++ b/plugins/include/sdktools_functions.inc @@ -1,7 +1,7 @@ /** * vim: set ts=4 : * ============================================================================= - * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. * ============================================================================= * * This file is part of the SourceMod/SourcePawn SDK. @@ -283,3 +283,15 @@ native bool:GetPlayerDecalFile(client, String:hex[], maxlength); * @noreturn */ native GetServerNetStats(&Float:in, &Float:out); + + +/** + * Equip's a player's weapon. + * + * @param client Client index. + * @param item CBaseCombatWeapon entity index. + * @noreturn + * @error Invalid client or entity, lack of mod support, or client not in + * game. + */ +native EquipPlayerWeapon(client, weapon); diff --git a/plugins/include/tf2.inc b/plugins/include/tf2.inc new file mode 100644 index 00000000..aab3cb82 --- /dev/null +++ b/plugins/include/tf2.inc @@ -0,0 +1,129 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This file is part of the SourceMod/SourcePawn SDK. + * + * 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$ + */ + +#if defined _tf2_included + #endinput +#endif +#define _tf2_included + +enum TFClassType +{ + TFClass_Unknown = 0, + TFClass_Scout, + TFClass_Sniper, + TFClass_Soldier, + TFClass_DemoMan, + TFClass_Medic, + TFClass_Heavy, + TFClass_Pyro, + TFClass_Spy, + TFClass_Engineer +} + +enum TFTeam +{ + TFTeam_Unassigned = 0, + TFTeam_Spectator = 1, + TFTeam_Red = 2, + TFTeam_Blue = 3 +} + +/** + * Set's a Clients invulnrability status (ubercharge effect) + * + * @param client Player's index. + * @param enabled Enable/Disable invulnrability. + * @noreturn + * @error Invalid client index, client not in game, or no mod support. + */ +native TF2_SetPlayerInvuln(client, bool:enabled); + +/** + * Respawns a client + * + * @param client Player's index. + * @noreturn + * @error Invalid client index, client not in game, or no mod support. + */ +native TF2_RespawnPlayer(client); + +/** + * Disguises a client to the given model and team. Only has an effect on spies. + * + * Note: This only starts the disguise process and a delay occurs before the spy is fully disguised + * + * @param client Player's index. + * @param team Team to disguise the player as (only TFTeam_Red and TFTeam_Blue have an effect) + * @param class TFClassType class to disguise the player as + * @noreturn + * @error Invalid client index, client not in game, or no mod support. + */ +native TF2_DisguisePlayer(client, TFTeam:team, TFClassType:class); + +/** + * Removes the current disguise from a client. Only has an effect on spies. + * + * @param client Player's index. + * @noreturn + * @error Invalid client index, client not in game, or no mod support. + */ +native TF2_RemovePlayerDisguise(client); + +/** + * Retrieves the entity index of the CPlayerResource entity + * + * @return The current resource entity index. + */ +native TF2_GetResourceEntity(); + +/** + * Finds the TFClassType for a given class name. + * + * @param classname A classname string such as "sniper" or "demoman" + * @return A TFClassType constant. + */ +native TFClassType:TF2_GetClass(const String:classname[]); + +/** + * Do not edit below this line! + */ +public Extension:__ext_tf2 = +{ + name = "TF2 Tools", + file = "game.tf2.ext", + autoload = 1, +#if defined REQUIRE_EXTENSIONS + required = 1, +#else + required = 0, +#endif +}; diff --git a/plugins/include/tf2_stocks.inc b/plugins/include/tf2_stocks.inc new file mode 100644 index 00000000..3de1541b --- /dev/null +++ b/plugins/include/tf2_stocks.inc @@ -0,0 +1,333 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This file is part of the SourceMod/SourcePawn SDK. + * + * 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$ + */ + +#if defined _tf2_stocks_included + #endinput +#endif +#define _tf2_stocks_included + +#include +#include + +enum TFResourceType +{ + TFResource_Ping, + TFResource_Score, + TFResource_Deaths, + TFResource_TotalScore, + TFResource_Captures, + TFResource_Defenses, + TFResource_Dominations, + TFResource_Revenge, + TFResource_BuildingsDestroyed, + TFResource_Headshots, + TFResource_Backstabs, + TFResource_HealPoints, + TFResource_Invulns, + TFResource_Teleports, + TFResource_ResupplyPoints, + TFResource_KillAssists, + TFResource_MaxHealth, + TFResource_PlayerClass +}; + +static const String:TFResourceNames[TFResourceType][] = +{ + "m_iPing", + "m_iScore", + "m_iDeaths", + "m_iTotalScore", + "m_iCaptures", + "m_iDefenses", + "m_iDominations", + "m_iRevenge", + "m_iBuildingsDestroyed", + "m_iHeadshots", + "m_iBackstabs", + "m_iHealPoints", + "m_iInvulns", + "m_iTeleports", + "m_iResupplyPoints", + "m_iKillAssists", + "m_iMaxHealth", + "m_iPlayerClass" +}; + +/** + * Get's a Clients current class. + * + * @param client Player's index. + * @param class TFClassType to change to. + * @noreturn + * @error Invalid client index. + */ +stock TFClassType:TF2_GetPlayerClass(client) +{ + return TFClassType:GetEntProp(client, Prop_Send, "m_iClass"); +} + +/** + * Set's a Clients class. + * + * @param client Player's index. + * @param class TFClassType class symbol. + * @param weapons If true, changes the players weapon set to that of the new class. + * @noreturn + * @error Invalid client index. + */ +stock TF2_SetPlayerClass(client, TFClassType:class, bool:weapons=true) +{ + SetEntProp(client, Prop_Send, "m_iClass", _:class); + SetEntProp(client, Prop_Send, "m_iDesiredPlayerClass", _:class); + TF2_SetPlayerResourceData(client, TFResource_PlayerClass, class); + + if (weapons) + { + TF2_RemoveAllWeapons(client); + TF2_EquipPlayerClassWeapons(client, class) + } +} + +/** + * Retrieves client data from the resource entity + * + * @param client Player's index. + * @param type ResourceType constant + * @return Value or -1 on failure. + * @error Invalid client index, client not in game or failed to find resource entity. + */ +stock TF2_GetPlayerResourceData(client, TFResourceType:type) +{ + if (!IsClientConnected(client)) + { + return -1; + } + + static offset; + static set = false; + + if (!set) + { + offset = FindSendPropInfo("CTFPlayerResource", TFResourceNames[type]); + set = true; + } + + if (offset < 1) + { + return -1; + } + + new entity = TF2_GetResourceEntity(); + + if (entity == -1) + { + return -1; + } + + return GetEntData(entity, offset + (client*4)); +} + +/** + * Sets client data in the resource entity + * + * @param client Player's index. + * @param type ResourceType constant + * @param value Value to set. + * @return Value or -1 on failure. + * @error Invalid client index, client not in game or failed to find resource entity. + */ +stock bool:TF2_SetPlayerResourceData(client, TFResourceType:type, any:value) +{ + if (!IsClientConnected(client)) + { + return false; + } + + static offset; + static set = false; + + if (!set) + { + offset = FindSendPropInfo("CTFPlayerResource", TFResourceNames[type]); + set = true; + } + + if (offset < 1) + { + return false; + } + + new entity = TF2_GetResourceEntity(); + + if (entity == -1) + { + return false; + } + + SetEntData(entity, offset + (client*4), value) + + return true; +} + +/** + * Removes all weapons from a client's weapon slot + * + * @param client Player's index. + * @param slot Slot index (0-5) + * @noreturn + * @error Invalid client, invalid slot or lack of mod support + */ +stock TF2_RemoveWeaponSlot(client, slot) +{ + new weaponIndex; + while ((weaponIndex = GetPlayerWeaponSlot(client, slot)) != -1) + { + RemovePlayerItem(client, weaponIndex); + RemoveEdict(weaponIndex); + } +} + +/** + * Removes all weapons from a client + * + * @param client Player's index. + * @noreturn + */ +stock TF2_RemoveAllWeapons(client) +{ + for (new i = 0; i <= 5; i++) + { + TF2_RemoveWeaponSlot(client, i); + } +} + +/** + * Gives a named weapon to a client + * + * @param client Player's index. + * @param weapon Weapon name + * @return False if weapon could not be created, true on success + * @error Invalid client index or lack of mod support + */ +stock bool:TF2_GivePlayerWeapon(client, const String:weapon[]) +{ + new weaponIndex = GivePlayerItem(client, weapon); + if (weaponIndex == -1) + { + return false; + } + + EquipPlayerWeapon(client, weaponIndex); + + return true; +} + +/** + * Equips a client with a class's weapons. This does not remove existing weapons. + * + * Note: Some class specific items such tf_weapon_pda_engineer_build are only given + * if the client is the correct class. + * + * @param client Player's index. + * @param class TFClasssType class symbol. + * @noreturn + */ +stock TF2_EquipPlayerClassWeapons(client, TFClassType:class) +{ + switch(class) + { + case TFClass_Scout: + { + TF2_GivePlayerWeapon(client, "tf_weapon_scattergun"); + TF2_GivePlayerWeapon(client, "tf_weapon_pistol_scout"); + TF2_GivePlayerWeapon(client, "tf_weapon_bat"); + } + case TFClass_Sniper: + { + TF2_GivePlayerWeapon(client, "tf_weapon_sniperrifle"); + TF2_GivePlayerWeapon(client, "tf_weapon_smg"); + TF2_GivePlayerWeapon(client, "tf_weapon_club"); + } + case TFClass_Soldier: + { + TF2_GivePlayerWeapon(client, "tf_weapon_rocketlauncher"); + TF2_GivePlayerWeapon(client, "tf_weapon_shotgun_soldier"); + TF2_GivePlayerWeapon(client, "tf_weapon_shovel"); + } + case TFClass_DemoMan: + { + TF2_GivePlayerWeapon(client, "tf_weapon_pipebomblauncher"); + TF2_GivePlayerWeapon(client, "tf_weapon_grenadelauncher"); + TF2_GivePlayerWeapon(client, "tf_weapon_bottle"); + } + case TFClass_Medic: + { + TF2_GivePlayerWeapon(client, "tf_weapon_syringegun_medic"); + TF2_GivePlayerWeapon(client, "tf_weapon_medigun"); + TF2_GivePlayerWeapon(client, "tf_weapon_bonesaw"); + } + case TFClass_Heavy: + { + TF2_GivePlayerWeapon(client, "tf_weapon_minigun"); + TF2_GivePlayerWeapon(client, "tf_weapon_shotgun_hwg"); + TF2_GivePlayerWeapon(client, "tf_weapon_fists"); + } + case TFClass_Pyro: + { + TF2_GivePlayerWeapon(client, "tf_weapon_flamethrower"); + TF2_GivePlayerWeapon(client, "tf_weapon_shotgun_pyro"); + TF2_GivePlayerWeapon(client, "tf_weapon_fireaxe"); + } + case TFClass_Spy: + { + TF2_GivePlayerWeapon(client, "tf_weapon_revolver"); + TF2_GivePlayerWeapon(client, "tf_weapon_knife"); + + if (TF2_GetPlayerClass(client) != TFClass_Spy) + return; + + TF2_GivePlayerWeapon(client, "tf_weapon_pda_spy"); + } + case TFClass_Engineer: + { + TF2_GivePlayerWeapon(client, "tf_weapon_shotgun_primary"); + TF2_GivePlayerWeapon(client, "tf_weapon_pistol"); + TF2_GivePlayerWeapon(client, "tf_weapon_wrench"); + + if (TF2_GetPlayerClass(client) != TFClass_Engineer) + return; + + TF2_GivePlayerWeapon(client, "tf_weapon_pda_engineer_build"); + TF2_GivePlayerWeapon(client, "tf_weapon_pda_engineer_destroy"); + } + } +} \ No newline at end of file diff --git a/plugins/testsuite/outputtest.sp b/plugins/testsuite/outputtest.sp new file mode 100644 index 00000000..f9312ee5 --- /dev/null +++ b/plugins/testsuite/outputtest.sp @@ -0,0 +1,59 @@ +#include +#include + +public Plugin:myinfo = +{ + name = "Entity Output Hook Testing", + author = "AlliedModders LLC", + description = "Test suite for Entity Output Hooks", + version = "1.0.0.0", + url = "http://www.sourcemod.net/" +}; + +public OnPluginStart() +{ + HookEntityOutput("point_spotlight", "OnLightOn", OutputHook); + + HookEntityOutput("func_door", "OnOpen", OutputHook); + HookEntityOutput("func_door_rotating", "OnOpen", OutputHook); + HookEntityOutput("func_door", "OnClose", OutputHook); + HookEntityOutput("func_door_rotating", "OnClose", OutputHook); +} + +public OutputHook(const String:name[], caller, activator, Float:delay) +{ + LogMessage("[ENTOUTPUT] %s", name); +} + +public OnMapStart() +{ + new ent = FindEntityByClassname(-1, "point_spotlight"); + + if (ent == -1) + { + LogError("Could not find a point_spotlight"); + ent = CreateEntityByName("point_spotlight"); + DispatchSpawn(ent); + } + + HookSingleEntityOutput(ent, "OnLightOn", OutputHook, true); + HookSingleEntityOutput(ent, "OnLightOff", OutputHook, true); + + AcceptEntityInput(ent, "LightOff", ent, ent); + AcceptEntityInput(ent, "LightOn", ent, ent); + + AcceptEntityInput(ent, "LightOff", ent, ent); + AcceptEntityInput(ent, "LightOn", ent, ent); + + HookSingleEntityOutput(ent, "OnLightOn", OutputHook, false); + HookSingleEntityOutput(ent, "OnLightOff", OutputHook, false); + + AcceptEntityInput(ent, "LightOff", ent, ent); + AcceptEntityInput(ent, "LightOn", ent, ent); + AcceptEntityInput(ent, "LightOff", ent, ent); + AcceptEntityInput(ent, "LightOn", ent, ent); + + //Comment these out (and reload the plugin heaps) to test for leaks on plugin unload + UnhookSingleEntityOutput(ent, "OnLightOn", OutputHook); + UnhookSingleEntityOutput(ent, "OnLightOff", OutputHook); +} \ No newline at end of file diff --git a/plugins/testsuite/tf2-test.sp b/plugins/testsuite/tf2-test.sp new file mode 100644 index 00000000..6623d33a --- /dev/null +++ b/plugins/testsuite/tf2-test.sp @@ -0,0 +1,167 @@ +#include +#include +#include +#include + +public Plugin:myinfo = +{ + name = "TF2 Test", + author = "pRED*", + description = "Test of Tf2 functions", + version = "1.0", + url = "www.sourcemod.net" +} + +public OnPluginStart() +{ + RegConsoleCmd("sm_burnme", Command_Burn); + RegConsoleCmd("sm_invuln", Command_Invuln); + RegConsoleCmd("sm_respawn", Command_Respawn); + RegConsoleCmd("sm_disguise", Command_Disguise); + RegConsoleCmd("sm_remdisguise", Command_RemDisguise); + RegConsoleCmd("sm_class", Command_Class); + RegConsoleCmd("sm_remove", Command_Remove); + RegConsoleCmd("sm_changeclass", Command_ChangeClass); +} + +public Action:Command_Class(client, args) +{ + TF2_RemoveAllWeapons(client); + + decl String:text[10]; + GetCmdArg(1, text, sizeof(text)); + + new one = StringToInt(text); + + TF2_EquipPlayerClassWeapons(client, TFClassType:one); + + PrintToChat(client, "Test: sniper's classnum is %i (should be %i)", TF2_GetClass("sniper"), TFClass_Sniper); + + return Plugin_Handled; +} + +public Action:Command_Remove(client, args) +{ + decl String:text[10]; + GetCmdArg(1, text, sizeof(text)); + + new one = StringToInt(text); + + TF2_RemoveWeaponSlot(client, one); + + PrintToChat(client, "Test: heavy's classnum is %i (should be %i)", TF2_GetClass("heavy"), TFClass_Heavy); + + new doms = TF2_GetPlayerResourceData(client, TFResource_Dominations); + PrintToChat(client, "Dominations read test: %i", doms); + + TF2_SetPlayerResourceData(client, TFResource_Dominations, doms + 10); + doms = TF2_GetPlayerResourceData(client, TFResource_Dominations); + PrintToChat(client, "Dominations write test: %i", doms); + + /* Note: This didn't appear to change my dominations value when I pressed tab. */ + + return Plugin_Handled; +} + +public Action:Command_ChangeClass(client, args) +{ + decl String:text[10]; + GetCmdArg(1, text, sizeof(text)); + + new one = StringToInt(text); + + PrintToChat(client, "Current class is :%i", TF2_GetPlayerClass(client)); + + TF2_SetPlayerClass(client, TFClassType:one); + + PrintToChat(client, "New class is :%i", TF2_GetPlayerClass(client)); + + return Plugin_Handled; +} + + + +public Action:Command_Burn(client, args) +{ + if (client == 0) + { + return Plugin_Handled; + } + + TF2_IgnitePlayer(client, client); + + return Plugin_Handled; +} + +public Action:Command_Invuln(client, args) +{ + if (client == 0) + { + return Plugin_Handled; + } + + if (args < 1) + { + return Plugin_Handled; + } + + decl String:text[10]; + GetCmdArg(1, text, sizeof(text)); + + new bool:one = !!StringToInt(text); + + TF2_SetPlayerInvuln(client, one) + + return Plugin_Handled; +} + +public Action:Command_Disguise(client, args) +{ + if (client == 0) + { + return Plugin_Handled; + } + + if (args < 2) + { + return Plugin_Handled; + } + + decl String:text[10]; + decl String:text2[10]; + GetCmdArg(1, text, sizeof(text)); + GetCmdArg(2, text2, sizeof(text2)); + + new one = StringToInt(text); + new two = StringToInt(text2); + + TF2_DisguisePlayer(client, TFTeam:one, TFClassType:two); + + return Plugin_Handled; +} + +public Action:Command_RemDisguise(client, args) +{ + if (client == 0) + { + return Plugin_Handled; + } + + TF2_RemovePlayerDisguise(client); + + return Plugin_Handled; +} + + +public Action:Command_Respawn(client, args) +{ + if (client == 0) + { + return Plugin_Handled; + } + + + TF2_RespawnPlayer(client); + + return Plugin_Handled; +} diff --git a/tools/builder/PkgCore.cs b/tools/builder/PkgCore.cs index e0d3a9c3..e0f5439b 100644 --- a/tools/builder/PkgCore.cs +++ b/tools/builder/PkgCore.cs @@ -51,6 +51,7 @@ namespace builder folders.Add("addons/sourcemod/data"); folders.Add("addons/sourcemod/scripting/include"); folders.Add("addons/sourcemod/scripting/admin-flatfile"); + folders.Add("addons/sourcemod/scripting/adminmenu"); folders.Add("addons/sourcemod/scripting/testsuite"); folders.Add("cfg/sourcemod"); folders.Add("addons/sourcemod/configs/sql-init-scripts"); @@ -114,6 +115,7 @@ namespace builder builder.CopyFolder(this, "translations", "addons/sourcemod/translations", null); builder.CopyFolder(this, "public/licenses", "addons/sourcemod", null); builder.CopyFolder(this, "plugins/admin-flatfile", "addons/sourcemod/scripting/admin-flatfile", null); + builder.CopyFolder(this, "plugins/adminmenu", "addons/sourcemod/scripting/adminmenu", null); builder.CopyFolder(this, "plugins/testsuite", "addons/sourcemod/scripting/testsuite", null); builder.CopyFolder(this, "plugins/basecommands", "addons/sourcemod/scripting/basecommands", null); builder.CopyFolder(this, "plugins/basecomm", "addons/sourcemod/scripting/basecomm", null);