diff --git a/extensions/sdktools/util.h b/extensions/sdktools/util.h
new file mode 100644
index 000000000..124045571
--- /dev/null
+++ b/extensions/sdktools/util.h
@@ -0,0 +1,102 @@
+/**
+ * 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: vcallbuilder.h 1566 2007-10-14 22:12:46Z faluco $
+ */
+
+#ifndef _INCLUDE_SOURCEMOD_UTIL_H_
+#define _INCLUDE_SOURCEMOD_UTIL_H_
+
+#include "utldict.h"
+
+abstract_class IEntityFactory
+{
+public:
+ virtual IServerNetworkable *Create( const char *pClassName ) = 0;
+ virtual void Destroy( IServerNetworkable *pNetworkable ) = 0;
+ virtual size_t GetEntitySize() = 0;
+};
+
+template
+class CEntityFactory : public IEntityFactory
+{
+public:
+ CEntityFactory( const char *pClassName )
+ {
+ EntityFactoryDictionary()->InstallFactory( this, pClassName );
+ }
+
+ IServerNetworkable *Create( const char *pClassName )
+ {
+ T* pEnt = _CreateEntityTemplate((T*)NULL, pClassName);
+ return pEnt->NetworkProp();
+ }
+
+ void Destroy( IServerNetworkable *pNetworkable )
+ {
+ if ( pNetworkable )
+ {
+ pNetworkable->Release();
+ }
+ }
+
+ virtual size_t GetEntitySize()
+ {
+ return sizeof(T);
+ }
+};
+
+abstract_class IEntityFactoryDictionary
+{
+public:
+ virtual void InstallFactory( IEntityFactory *pFactory, const char *pClassName ) = 0;
+ virtual IServerNetworkable *Create( const char *pClassName ) = 0;
+ virtual void Destroy( const char *pClassName, IServerNetworkable *pNetworkable ) = 0;
+ virtual IEntityFactory *FindFactory( const char *pClassName ) = 0;
+ virtual const char *GetCannonicalName( const char *pClassName ) = 0;
+};
+
+
+class CEntityFactoryDictionary : public IEntityFactoryDictionary
+{
+public:
+ CEntityFactoryDictionary();
+
+ virtual void InstallFactory( IEntityFactory *pFactory, const char *pClassName );
+ virtual IServerNetworkable *Create( const char *pClassName );
+ virtual void Destroy( const char *pClassName, IServerNetworkable *pNetworkable );
+ virtual const char *GetCannonicalName( const char *pClassName );
+ void ReportEntitySizes();
+
+private:
+ IEntityFactory *FindFactory( const char *pClassName );
+public:
+ CUtlDict< IEntityFactory *, unsigned short > m_Factories;
+};
+
+#endif //_INCLUDE_SOURCEMOD_UTIL_H_
diff --git a/extensions/sdktools/vhelpers.cpp b/extensions/sdktools/vhelpers.cpp
index 571abdd08..49a83b3d5 100644
--- a/extensions/sdktools/vhelpers.cpp
+++ b/extensions/sdktools/vhelpers.cpp
@@ -30,6 +30,7 @@
*/
#include "extension.h"
+#include "util.h"
#include "vhelpers.h"
CallHelper s_Teleport;
@@ -501,3 +502,116 @@ CON_COMMAND(sm_dump_netprops, "Dumps the networkable property table as a text fi
fclose(fp);
}
+#if defined SUBPLATFORM_SECURECRT
+void _ignore_invalid_parameter(
+ const wchar_t * expression,
+ const wchar_t * function,
+ const wchar_t * file,
+ unsigned int line,
+ uintptr_t pReserved
+ )
+{
+ /* Wow we don't care, thanks Microsoft. */
+}
+#endif
+
+CON_COMMAND(sm_dump_classes, "Dumps the class list as a text file")
+{
+#if !defined ORANGEBOX_BUILD
+ CCommand args;
+#endif
+
+ if (args.ArgC() < 2)
+ {
+ META_CONPRINT("Usage: sm_dump_classes \n");
+ return;
+ }
+
+ const char *file = args.Arg(1);
+ if (!file || file[0] == '\0')
+ {
+ META_CONPRINT("Usage: sm_dump_classes \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 classes for \"%s\" as at %s\n//\n\n", g_pSM->GetGameFolderName(), buffer);
+
+ 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();
+ fprintf(fp,"%s - %s\n",sclass->GetName(), dict->m_Factories.GetElementName(i));
+
+ typedescription_t *datamap = gamehelpers->FindInDataMap(gamehelpers->GetDataMap(entity->GetBaseEntity()), "m_iEFlags");
+
+ int *eflags = (int *)((char *)entity->GetBaseEntity() + datamap->fieldOffset[TD_OFFSET_NORMAL]);
+ *eflags |= (1<<0); // EFL_KILLME
+ }
+
+ fclose(fp);
+
+}
+
+
diff --git a/gamedata/sdktools.games.ep2.txt b/gamedata/sdktools.games.ep2.txt
index 93afb06d3..65a430be6 100644
--- a/gamedata/sdktools.games.ep2.txt
+++ b/gamedata/sdktools.games.ep2.txt
@@ -278,4 +278,17 @@
}
}
}
+ /* EntityFactoryDictionary function */
+ "#default"
+ {
+ "Signatures"
+ {
+ "EntityFactory"
+ {
+ "library" "server"
+ "windows" "\xB8\x01\x00\x00\x00\x84\x2A\x2A\x2A\x2A\x2A\x75\x1D\x09\x2A\x2A\x2A\x2A\x2A\xB9\x2A\x2A\x2A\x2A\xE8\x2A\x2A\x2A\x2A\x68\x2A\x2A\x2A\x2A\xE8\x2A\x2A\x2A\x2A\x83\xC4\x04\xB8\x2A\x2A\x2A\x2A\xC3"
+ "linux" "@_Z23EntityFactoryDictionaryv"
+ }
+ }
+ }
}
diff --git a/gamedata/sdktools.games.txt b/gamedata/sdktools.games.txt
index 9ce214c5e..cd53d3561 100644
--- a/gamedata/sdktools.games.txt
+++ b/gamedata/sdktools.games.txt
@@ -1679,5 +1679,19 @@
}
}
}
+
+ /* EntityFactoryDictionary function */
+ "#default"
+ {
+ "Signatures"
+ {
+ "EntityFactory"
+ {
+ "library" "server"
+ "windows" "\xB8\x01\x00\x00\x00\x84\x2A\x2A\x2A\x2A\x2A\x75\x1D\x09\x2A\x2A\x2A\x2A\x2A\xB9\x2A\x2A\x2A\x2A\xE8\x2A\x2A\x2A\x2A\x68\x2A\x2A\x2A\x2A\xE8\x2A\x2A\x2A\x2A\x83\xC4\x04\xB8\x2A\x2A\x2A\x2A\xC3"
+ "linux" "@_Z23EntityFactoryDictionaryv"
+ }
+ }
+ }
}