Added support for logical (non-networked) entities using entity references - See http://wiki.alliedmods.net/Entity_References_%28SourceMod%29 (bug 2459, r=dvander)
authorMatt Woodrow <pred@alliedmods.net>
Fri Jul 24 12:34:31 2009 +1200 (2009-07-24)
changeset 27468d68569b9648
parent 2745 06cdeee2a723
child 2747 791eb96e3a20
child 2748 ff29fb92953c
Added support for logical (non-networked) entities using entity references - See http://wiki.alliedmods.net/Entity_References_%28SourceMod%29 (bug 2459, r=dvander)
core/HalfLife2.cpp
core/HalfLife2.h
core/smn_banning.cpp
core/smn_bitbuffer.cpp
core/smn_entities.cpp
core/smn_halflife.cpp
extensions/sdktools/inputnatives.cpp
extensions/sdktools/output.cpp
extensions/sdktools/output.h
extensions/sdktools/outputnatives.cpp
extensions/sdktools/trnatives.cpp
extensions/sdktools/vdecoder.cpp
extensions/sdktools/vglobals.cpp
extensions/sdktools/vhelpers.cpp
extensions/sdktools/vnatives.cpp
extensions/sdktools/vsound.cpp
gamedata/core.games/engine.darkm.txt
gamedata/core.games/engine.ep1.txt
gamedata/core.games/engine.ep2.txt
gamedata/core.games/engine.l4d.txt
gamedata/core.games/master.games.txt
gamedata/sdktools.games/engine.darkm.txt
gamedata/sdktools.games/engine.ep1.txt
gamedata/sdktools.games/engine.ep2.txt
gamedata/sdktools.games/engine.l4d.txt
plugins/include/halflife.inc
public/IGameHelpers.h
     1.1 --- a/core/HalfLife2.cpp	Thu Jul 09 17:51:12 2009 -0400
     1.2 +++ b/core/HalfLife2.cpp	Fri Jul 24 12:34:31 2009 +1200
     1.3 @@ -37,10 +37,14 @@
     1.4  #include "sm_stringutil.h"
     1.5  #include "GameConfigs.h"
     1.6  #include <compat_wrappers.h>
     1.7 +#include <Logger.h>
     1.8  
     1.9  CHalfLife2 g_HL2;
    1.10  ConVar *sv_lan = NULL;
    1.11  
    1.12 +static void *g_EntList = NULL;
    1.13 +static int entInfoOffset = -1;
    1.14 +
    1.15  namespace SourceHook
    1.16  {
    1.17  	template<>
    1.18 @@ -123,6 +127,51 @@
    1.19  	g_ShareSys.AddInterface(NULL, this);
    1.20  }
    1.21  
    1.22 +void CHalfLife2::OnSourceModAllInitialized_Post()
    1.23 +{
    1.24 +	char *addr = NULL;
    1.25 +#ifdef PLATFORM_WINDOWS
    1.26 +	int offset;
    1.27 +
    1.28 +	/* gEntList and/or g_pEntityList */
    1.29 +	if (!g_pGameConf->GetMemSig("LevelShutdown", (void **)&addr))
    1.30 +	{
    1.31 +		g_Logger.LogError("Logical Entities not supported by this mod (LevelShutdown) - Reverting to networkable entities only");
    1.32 +		return;
    1.33 +	}
    1.34 +	if (!addr)
    1.35 +	{
    1.36 +		g_Logger.LogError("Failed lookup of LevelShutdown - Reverting to networkable entities only");
    1.37 +		return;
    1.38 +	}
    1.39 +	if (!g_pGameConf->GetOffset("gEntList", &offset))
    1.40 +	{
    1.41 +		g_Logger.LogError("Logical Entities not supported by this mod (gEntList) - Reverting to networkable entities only");
    1.42 +		return;
    1.43 +	}
    1.44 +	g_EntList = *reinterpret_cast<void **>(addr + offset);
    1.45 +#elif defined PLATFORM_LINUX
    1.46 +	/* gEntList and/or g_pEntityList */
    1.47 +	if (!g_pGameConf->GetMemSig("gEntList", (void **)&addr))
    1.48 +	{
    1.49 +		g_Logger.LogError("Logical Entities not supported by this mod (gEntList) - Reverting to networkable entities only");
    1.50 +		return;
    1.51 +	}
    1.52 +	if (!addr)
    1.53 +	{
    1.54 +		g_Logger.LogError("Failed lookup of gEntList - Reverting to networkable entities only");
    1.55 +		return;
    1.56 +	}
    1.57 +	g_EntList = reinterpret_cast<void *>(addr);
    1.58 +#endif
    1.59 +
    1.60 +	if (!g_pGameConf->GetOffset("EntInfo", &entInfoOffset))
    1.61 +	{
    1.62 +		g_Logger.LogError("Logical Entities not supported by this mod (EntInfo) - Reverting to networkable entities only");
    1.63 +		return;
    1.64 +	}
    1.65 +}
    1.66 +
    1.67  #if !defined METAMOD_PLAPI_VERSION
    1.68  bool CHalfLife2::IsOriginalEngine()
    1.69  {
    1.70 @@ -642,3 +691,173 @@
    1.71  {
    1.72  	engine->ServerCommand(buffer);
    1.73  }
    1.74 +
    1.75 +cell_t CHalfLife2::EntityToReference(CBaseEntity *pEntity)
    1.76 +{
    1.77 +	IServerUnknown *pUnknown = (IServerUnknown *)pEntity;
    1.78 +	CBaseHandle hndl = pUnknown->GetRefEHandle();
    1.79 +	return (hndl.ToInt() | (1<<31));
    1.80 +}
    1.81 +
    1.82 +CBaseEntity *CHalfLife2::ReferenceToEntity(cell_t entRef)
    1.83 +{
    1.84 +	CEntInfo *pInfo = NULL;
    1.85 +
    1.86 +	if (entRef & (1<<31))
    1.87 +	{
    1.88 +		/* Proper ent reference */
    1.89 +		int hndlValue = entRef & ~(1<<31);
    1.90 +		CBaseHandle hndl(hndlValue);
    1.91 +
    1.92 +		pInfo = LookupEntity(hndl.GetEntryIndex());
    1.93 +		if (pInfo->m_SerialNumber != hndl.GetSerialNumber())
    1.94 +		{
    1.95 +			return NULL;
    1.96 +		}
    1.97 +	}
    1.98 +	else
    1.99 +	{
   1.100 +		/* Old style index only */
   1.101 +		pInfo = LookupEntity(entRef);
   1.102 +	}
   1.103 +
   1.104 +	if (!pInfo)
   1.105 +	{
   1.106 +		return NULL;
   1.107 +	}
   1.108 +
   1.109 +	IServerUnknown *pUnk = static_cast<IServerUnknown *>(pInfo->m_pEntity);
   1.110 +	if (pUnk)
   1.111 +	{
   1.112 +		return pUnk->GetBaseEntity();
   1.113 +	}
   1.114 +
   1.115 +	return NULL;
   1.116 +}
   1.117 +
   1.118 +/**
   1.119 + * Retrieves the CEntInfo pointer from g_EntList for a given entity index
   1.120 + */
   1.121 +CEntInfo *CHalfLife2::LookupEntity(int entIndex)
   1.122 +{
   1.123 +	if (!g_EntList || entInfoOffset == -1)
   1.124 +	{
   1.125 +		/* Attempt to use engine interface instead */
   1.126 +		static CEntInfo tempInfo;
   1.127 +		tempInfo.m_pNext = NULL;
   1.128 +		tempInfo.m_pPrev = NULL;
   1.129 +
   1.130 +		edict_t *pEdict = engine->PEntityOfEntIndex(entIndex);
   1.131 +
   1.132 +		if (!pEdict)
   1.133 +		{
   1.134 +			return NULL;
   1.135 +		}
   1.136 +
   1.137 +		IServerUnknown *pUnk = pEdict->GetUnknown();
   1.138 +
   1.139 +		if (!pUnk)
   1.140 +		{
   1.141 +			return NULL;
   1.142 +		}
   1.143 +
   1.144 +		tempInfo.m_pEntity = pUnk;
   1.145 +		tempInfo.m_SerialNumber = pUnk->GetRefEHandle().GetSerialNumber();
   1.146 +
   1.147 +		return &tempInfo;
   1.148 +	}
   1.149 +
   1.150 +	CEntInfo *pArray = (CEntInfo *)(((unsigned char *)g_EntList) + entInfoOffset);
   1.151 +	return &pArray[entIndex];
   1.152 +}
   1.153 +
   1.154 +/**
   1.155 +	SERIAL_MASK = 0x7fff (15 bits)
   1.156 +
   1.157 +	#define	MAX_EDICT_BITS				11
   1.158 +	#define NUM_ENT_ENTRY_BITS		(MAX_EDICT_BITS + 1)
   1.159 +	m_Index = iEntry | (iSerialNumber << NUM_ENT_ENTRY_BITS); 
   1.160 +	
   1.161 +	Top 5 bits of a handle are unused.
   1.162 +	Bit 31 - Our 'reference' flag indicator
   1.163 +*/
   1.164 +
   1.165 +cell_t CHalfLife2::IndexToReference(int entIndex)
   1.166 +{
   1.167 +	CBaseEntity *pEnt = ReferenceToEntity(entIndex);
   1.168 +	if (!pEnt)
   1.169 +	{
   1.170 +		return INVALID_EHANDLE_INDEX;
   1.171 +	}
   1.172 +
   1.173 +	return EntityToReference(pEnt);
   1.174 +}
   1.175 +
   1.176 +int CHalfLife2::ReferenceToIndex(cell_t entRef)
   1.177 +{
   1.178 +	if (entRef == INVALID_EHANDLE_INDEX)
   1.179 +	{
   1.180 +		return INVALID_EHANDLE_INDEX;
   1.181 +	}
   1.182 +
   1.183 +	if (entRef & (1<<31))
   1.184 +	{
   1.185 +		/* Proper ent reference */
   1.186 +		int hndlValue = entRef & ~(1<<31);
   1.187 +		CBaseHandle hndl(hndlValue);
   1.188 +
   1.189 +		CEntInfo *pInfo = LookupEntity(hndl.GetEntryIndex());
   1.190 +
   1.191 +		if (pInfo->m_SerialNumber != hndl.GetSerialNumber())
   1.192 +		{
   1.193 +			return INVALID_EHANDLE_INDEX;
   1.194 +		}
   1.195 +
   1.196 +		return hndl.GetEntryIndex();
   1.197 +	}
   1.198 +
   1.199 +	return entRef;
   1.200 +}
   1.201 +
   1.202 +cell_t CHalfLife2::EntityToBCompatRef(CBaseEntity *pEntity)
   1.203 +{
   1.204 +	if (pEntity == NULL)
   1.205 +	{
   1.206 +		return INVALID_EHANDLE_INDEX;
   1.207 +	}
   1.208 +
   1.209 +	IServerUnknown *pUnknown = (IServerUnknown *)pEntity;
   1.210 +	CBaseHandle hndl = pUnknown->GetRefEHandle();
   1.211 +
   1.212 +	if (hndl.GetEntryIndex() >= MAX_EDICTS)
   1.213 +	{
   1.214 +		return (hndl.ToInt() | (1<<31));
   1.215 +	}
   1.216 +	else
   1.217 +	{
   1.218 +		return hndl.GetEntryIndex();
   1.219 +	}
   1.220 +}
   1.221 +
   1.222 +cell_t CHalfLife2::ReferenceToBCompatRef(cell_t entRef)
   1.223 +{
   1.224 +	if (entRef == INVALID_EHANDLE_INDEX)
   1.225 +	{
   1.226 +		return INVALID_EHANDLE_INDEX;
   1.227 +	}
   1.228 +
   1.229 +	int hndlValue = entRef & ~(1<<31);
   1.230 +	CBaseHandle hndl(hndlValue);
   1.231 +
   1.232 +	if (hndl.GetEntryIndex() < MAX_EDICTS)
   1.233 +	{
   1.234 +		return hndl.GetEntryIndex();
   1.235 +	}
   1.236 +
   1.237 +	return entRef;
   1.238 +}
   1.239 +
   1.240 +void *CHalfLife2::GetGlobalEntityList()
   1.241 +{
   1.242 +	return g_EntList;
   1.243 +}
   1.244 \ No newline at end of file
     2.1 --- a/core/HalfLife2.h	Thu Jul 09 17:51:12 2009 -0400
     2.2 +++ b/core/HalfLife2.h	Fri Jul 24 12:34:31 2009 +1200
     2.3 @@ -43,6 +43,7 @@
     2.4  #include <KeyValues.h>
     2.5  #include <server_class.h>
     2.6  #include <datamap.h>
     2.7 +#include <ihandleentity.h>
     2.8  
     2.9  class CCommand;
    2.10  
    2.11 @@ -86,6 +87,15 @@
    2.12  	char buffer[384];
    2.13  };
    2.14  
    2.15 +class CEntInfo
    2.16 +{
    2.17 +public:
    2.18 +	IHandleEntity	*m_pEntity;
    2.19 +	int				m_SerialNumber;
    2.20 +	CEntInfo		*m_pPrev;
    2.21 +	CEntInfo		*m_pNext;
    2.22 +};
    2.23 +
    2.24  class CHalfLife2 : 
    2.25  	public SMGlobalClass,
    2.26  	public IGameHelpers
    2.27 @@ -96,6 +106,7 @@
    2.28  public:
    2.29  	void OnSourceModStartup(bool late);
    2.30  	void OnSourceModAllInitialized();
    2.31 +	void OnSourceModAllInitialized_Post();
    2.32  	/*void OnSourceModAllShutdown();*/
    2.33  public: //IGameHelpers
    2.34  	SendProp *FindInSendTable(const char *classname, const char *offset);
    2.35 @@ -115,6 +126,14 @@
    2.36  	void SetHandleEntity(CBaseHandle &hndl, edict_t *pEnt);
    2.37  	const char *GetCurrentMap();
    2.38  	void ServerCommand(const char *buffer);
    2.39 +	CBaseEntity *ReferenceToEntity(cell_t entRef);
    2.40 +	cell_t EntityToReference(CBaseEntity *pEntity);
    2.41 +	cell_t IndexToReference(int entIndex);
    2.42 +	int ReferenceToIndex(cell_t entRef);
    2.43 +	cell_t ReferenceToBCompatRef(cell_t entRef);
    2.44 +	CEntInfo *LookupEntity(int entIndex);
    2.45 +	cell_t EntityToBCompatRef(CBaseEntity *pEntity);
    2.46 +	void *GetGlobalEntityList();
    2.47  public:
    2.48  	void AddToFakeCliCmdQueue(int client, int userid, const char *cmd);
    2.49  	void ProcessFakeCliCmdQueue();
     3.1 --- a/core/smn_banning.cpp	Thu Jul 09 17:51:12 2009 -0400
     3.2 +++ b/core/smn_banning.cpp	Fri Jul 24 12:34:31 2009 +1200
     3.3 @@ -248,7 +248,7 @@
     3.4  	char *ban_reason, *ban_cmd;
     3.5  	int client, ban_flags, ban_source, ban_time;
     3.6  
     3.7 -	client = params[1];
     3.8 +	client = g_HL2.ReferenceToIndex(params[1]);
     3.9  
    3.10  	CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
    3.11  	if (!pPlayer || !pPlayer->IsConnected())
     4.1 --- a/core/smn_bitbuffer.cpp	Thu Jul 09 17:51:12 2009 -0400
     4.2 +++ b/core/smn_bitbuffer.cpp	Fri Jul 24 12:34:31 2009 +1200
     4.3 @@ -33,6 +33,7 @@
     4.4  #include "HandleSys.h"
     4.5  #include <bitbuf.h>
     4.6  #include <vector.h>
     4.7 +#include <HalfLife2.h>
     4.8  
     4.9  static cell_t smn_BfWriteBool(IPluginContext *pCtx, const cell_t *params)
    4.10  {
    4.11 @@ -226,7 +227,14 @@
    4.12  		return pCtx->ThrowNativeError("Invalid bit buffer handle %x (error %d)", hndl, herr);
    4.13  	}
    4.14  
    4.15 -	pBitBuf->WriteShort(params[2]);
    4.16 +	int index = g_HL2.ReferenceToIndex(params[2]);
    4.17 +
    4.18 +	if (index == -1)
    4.19 +	{
    4.20 +		return 0;
    4.21 +	}
    4.22 +
    4.23 +	pBitBuf->WriteShort(index);
    4.24  
    4.25  	return 1;
    4.26  }
    4.27 @@ -523,7 +531,9 @@
    4.28  		return pCtx->ThrowNativeError("Invalid bit buffer handle %x (error %d)", hndl, herr);
    4.29  	}
    4.30  
    4.31 -	return pBitBuf->ReadShort();
    4.32 +	int ref = g_HL2.IndexToReference(pBitBuf->ReadShort());
    4.33 +
    4.34 +	return g_HL2.ReferenceToBCompatRef(ref);
    4.35  }
    4.36  
    4.37  static cell_t smn_BfReadAngle(IPluginContext *pCtx, const cell_t *params)
     5.1 --- a/core/smn_entities.cpp	Thu Jul 09 17:51:12 2009 -0400
     5.2 +++ b/core/smn_entities.cpp	Fri Jul 24 12:34:31 2009 +1200
     5.3 @@ -54,45 +54,74 @@
     5.4  	PropField_String_T,			/**< Valid for Data fields.  Read only! */
     5.5  };
     5.6  
     5.7 +inline edict_t *BaseEntityToEdict(CBaseEntity *pEntity)
     5.8 +{
     5.9 +	IServerUnknown *pUnk = (IServerUnknown *)pEntity;
    5.10 +	IServerNetworkable *pNet = pUnk->GetNetworkable();
    5.11 +
    5.12 +	if (!pNet)
    5.13 +	{
    5.14 +		return NULL;
    5.15 +	}
    5.16 +
    5.17 +	return pNet->GetEdict();
    5.18 +}
    5.19 +
    5.20  inline edict_t *GetEdict(cell_t num)
    5.21  {
    5.22 -	edict_t *pEdict = PEntityOfEntIndex(num);
    5.23 +	CBaseEntity *pEntity = g_HL2.ReferenceToEntity(num);
    5.24 +
    5.25 +	if (!pEntity)
    5.26 +	{
    5.27 +		return 0;
    5.28 +	}
    5.29 +
    5.30 +	edict_t *pEdict = ::BaseEntityToEdict(pEntity);
    5.31  	if (!pEdict || pEdict->IsFree())
    5.32  	{
    5.33  		return NULL;
    5.34  	}
    5.35 -	if (num > 0 && num <= g_Players.GetMaxClients())
    5.36 +
    5.37 +	int index = g_HL2.ReferenceToIndex(num);
    5.38 +	if (index > 0 && index <= g_Players.GetMaxClients())
    5.39  	{
    5.40 -		CPlayer *pPlayer = g_Players.GetPlayerByIndex(num);
    5.41 +		CPlayer *pPlayer = g_Players.GetPlayerByIndex(index);
    5.42  		if (!pPlayer || !pPlayer->IsConnected())
    5.43  		{
    5.44  			return NULL;
    5.45  		}
    5.46  	}
    5.47 +
    5.48  	return pEdict;
    5.49  }
    5.50  
    5.51  edict_t *GetEntity(cell_t num, CBaseEntity **pData)
    5.52  {
    5.53 -	edict_t *pEdict = PEntityOfEntIndex(num);
    5.54 -	if (!pEdict || pEdict->IsFree())
    5.55 +	CBaseEntity *pEntity = g_HL2.ReferenceToEntity(num);
    5.56 +
    5.57 +	if (!pEntity)
    5.58  	{
    5.59 -		return NULL;
    5.60 +		return 0;
    5.61  	}
    5.62 -	if (num > 0 && num <= g_Players.GetMaxClients())
    5.63 +
    5.64 +	int index = g_HL2.ReferenceToIndex(num);
    5.65 +	if (index > 0 && index <= g_Players.GetMaxClients())
    5.66  	{
    5.67 -		CPlayer *pPlayer = g_Players.GetPlayerByIndex(num);
    5.68 +		CPlayer *pPlayer = g_Players.GetPlayerByIndex(index);
    5.69  		if (!pPlayer || !pPlayer->IsConnected())
    5.70  		{
    5.71  			return NULL;
    5.72  		}
    5.73  	}
    5.74 -	IServerUnknown *pUnk;
    5.75 -	if ((pUnk=pEdict->GetUnknown()) == NULL)
    5.76 +
    5.77 +	*pData = pEntity;
    5.78 +
    5.79 +	edict_t *pEdict = ::BaseEntityToEdict(pEntity);
    5.80 +	if (!pEdict || pEdict->IsFree())
    5.81  	{
    5.82  		return NULL;
    5.83  	}
    5.84 -	*pData = pUnk->GetBaseEntity();
    5.85 +
    5.86  	return pEdict;
    5.87  }
    5.88  
    5.89 @@ -161,11 +190,11 @@
    5.90  
    5.91  static cell_t RemoveEdict(IPluginContext *pContext, const cell_t *params)
    5.92  {
    5.93 -	edict_t *pEdict = PEntityOfEntIndex(params[1]);
    5.94 +	edict_t *pEdict = GetEdict(params[1]);
    5.95  
    5.96  	if (!pEdict)
    5.97  	{
    5.98 -		return pContext->ThrowNativeError("Edict %d is not a valid edict", params[1]);
    5.99 +		return pContext->ThrowNativeError("Edict %d (%d) is not a valid edict", g_HL2.ReferenceToIndex(params[1]), params[1]);
   5.100  	}
   5.101  
   5.102  	engine->RemoveEdict(pEdict);
   5.103 @@ -188,20 +217,8 @@
   5.104  
   5.105  static cell_t IsValidEntity(IPluginContext *pContext, const cell_t *params)
   5.106  {
   5.107 -	edict_t *pEdict = GetEdict(params[1]);
   5.108 -
   5.109 -	if (!pEdict)
   5.110 -	{
   5.111 -		return 0;
   5.112 -	}
   5.113 +	CBaseEntity *pEntity = g_HL2.ReferenceToEntity(params[1]);
   5.114  
   5.115 -	IServerUnknown *pUnknown = pEdict->GetUnknown();
   5.116 -	if (!pUnknown)
   5.117 -	{
   5.118 -		return 0;
   5.119 -	}
   5.120 -
   5.121 -	CBaseEntity *pEntity = pUnknown->GetBaseEntity();
   5.122  	return (pEntity != NULL) ? 1 : 0;
   5.123  }
   5.124  
   5.125 @@ -228,7 +245,7 @@
   5.126  
   5.127  	if (!pEdict)
   5.128  	{
   5.129 -		return pContext->ThrowNativeError("Invalid edict (%d)", params[1]);
   5.130 +		return pContext->ThrowNativeError("Invalid edict (%d - %d)", g_HL2.ReferenceToIndex(params[1]), params[1]);
   5.131  	}
   5.132  
   5.133  	return pEdict->m_fStateFlags;
   5.134 @@ -240,7 +257,7 @@
   5.135  
   5.136  	if (!pEdict)
   5.137  	{
   5.138 -		return pContext->ThrowNativeError("Invalid edict (%d)", params[1]);
   5.139 +		return pContext->ThrowNativeError("Invalid edict (%d - %d)", g_HL2.ReferenceToIndex(params[1]), params[1]);
   5.140  	}
   5.141  
   5.142  	pEdict->m_fStateFlags = params[2];
   5.143 @@ -254,7 +271,7 @@
   5.144  
   5.145  	if (!pEdict)
   5.146  	{
   5.147 -		return pContext->ThrowNativeError("Invalid edict (%d)", params[1]);
   5.148 +		return pContext->ThrowNativeError("Invalid edict (%d - %d)", g_HL2.ReferenceToIndex(params[1]), params[1]);
   5.149  	}
   5.150  
   5.151  	const char *cls = pEdict->GetClassName();
   5.152 @@ -271,14 +288,16 @@
   5.153  
   5.154  static cell_t GetEntityNetClass(IPluginContext *pContext, const cell_t *params)
   5.155  {
   5.156 -	edict_t *pEdict = GetEdict(params[1]);
   5.157 +	CBaseEntity *pEntity = g_HL2.ReferenceToEntity(params[1]);
   5.158 +
   5.159 +	IServerUnknown *pUnk = (IServerUnknown *)pEntity;
   5.160  
   5.161 -	if (!pEdict)
   5.162 +	if (!pEntity)
   5.163  	{
   5.164 -		return pContext->ThrowNativeError("Invalid edict (%d)", params[1]);
   5.165 +		return pContext->ThrowNativeError("Invalid entity (%d - %d)", g_HL2.ReferenceToIndex(params[1]), params[1]);
   5.166  	}
   5.167  
   5.168 -	IServerNetworkable *pNet = pEdict->GetNetworkable();
   5.169 +	IServerNetworkable *pNet = pUnk->GetNetworkable();
   5.170  	if (!pNet)
   5.171  	{
   5.172  		return 0;
   5.173 @@ -294,11 +313,11 @@
   5.174  static cell_t GetEntData(IPluginContext *pContext, const cell_t *params)
   5.175  {
   5.176  	CBaseEntity *pEntity;
   5.177 -	edict_t *pEdict = GetEntity(params[1], &pEntity);
   5.178 +	GetEntity(params[1], &pEntity);
   5.179  
   5.180 -	if (!pEdict || !pEntity)
   5.181 +	if (!pEntity)
   5.182  	{
   5.183 -		return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
   5.184 +		return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
   5.185  	}
   5.186  
   5.187  	int offset = params[2];
   5.188 @@ -325,9 +344,9 @@
   5.189  	CBaseEntity *pEntity;
   5.190  	edict_t *pEdict = GetEntity(params[1], &pEntity);
   5.191  
   5.192 -	if (!pEdict || !pEntity)
   5.193 +	if (!pEntity)
   5.194  	{
   5.195 -		return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
   5.196 +		return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
   5.197  	}
   5.198  
   5.199  	int offset = params[2];
   5.200 @@ -336,7 +355,7 @@
   5.201  		return pContext->ThrowNativeError("Offset %d is invalid", offset);
   5.202  	}
   5.203  
   5.204 -	if (params[5])
   5.205 +	if (params[5] && (pEdict != NULL))
   5.206  	{
   5.207  		g_HL2.SetEdictStateChanged(pEdict, offset);
   5.208  	}
   5.209 @@ -368,11 +387,11 @@
   5.210  static cell_t GetEntDataFloat(IPluginContext *pContext, const cell_t *params)
   5.211  {
   5.212  	CBaseEntity *pEntity;
   5.213 -	edict_t *pEdict = GetEntity(params[1], &pEntity);
   5.214 +	GetEntity(params[1], &pEntity);
   5.215  
   5.216 -	if (!pEdict || !pEntity)
   5.217 +	if (!pEntity)
   5.218  	{
   5.219 -		return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
   5.220 +		return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
   5.221  	}
   5.222  
   5.223  	int offset = params[2];
   5.224 @@ -391,9 +410,9 @@
   5.225  	CBaseEntity *pEntity;
   5.226  	edict_t *pEdict = GetEntity(params[1], &pEntity);
   5.227  
   5.228 -	if (!pEdict || !pEntity)
   5.229 +	if (!pEntity)
   5.230  	{
   5.231 -		return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
   5.232 +		return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
   5.233  	}
   5.234  
   5.235  	int offset = params[2];
   5.236 @@ -404,7 +423,7 @@
   5.237  
   5.238  	*(float *)((uint8_t *)pEntity + offset) = sp_ctof(params[3]);
   5.239  
   5.240 -	if (params[4])
   5.241 +	if (params[4] && (pEdict != NULL))
   5.242  	{
   5.243  		g_HL2.SetEdictStateChanged(pEdict, offset);
   5.244  	}
   5.245 @@ -415,11 +434,11 @@
   5.246  static cell_t GetEntDataVector(IPluginContext *pContext, const cell_t *params)
   5.247  {
   5.248  	CBaseEntity *pEntity;
   5.249 -	edict_t *pEdict = GetEntity(params[1], &pEntity);
   5.250 +	GetEntity(params[1], &pEntity);
   5.251  
   5.252 -	if (!pEdict || !pEntity)
   5.253 +	if (!pEntity)
   5.254  	{
   5.255 -		return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
   5.256 +		return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
   5.257  	}
   5.258  
   5.259  	int offset = params[2];
   5.260 @@ -445,9 +464,9 @@
   5.261  	CBaseEntity *pEntity;
   5.262  	edict_t *pEdict = GetEntity(params[1], &pEntity);
   5.263  
   5.264 -	if (!pEdict || !pEntity)
   5.265 +	if (!pEntity)
   5.266  	{
   5.267 -		return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
   5.268 +		return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
   5.269  	}
   5.270  
   5.271  	int offset = params[2];
   5.272 @@ -465,7 +484,7 @@
   5.273  	v->y = sp_ctof(vec[1]);
   5.274  	v->z = sp_ctof(vec[2]);
   5.275  
   5.276 -	if (params[4])
   5.277 +	if (params[4] && (pEdict != NULL))
   5.278  	{
   5.279  		g_HL2.SetEdictStateChanged(pEdict, offset);
   5.280  	}
   5.281 @@ -477,11 +496,11 @@
   5.282  static cell_t GetEntDataEnt(IPluginContext *pContext, const cell_t *params)
   5.283  {
   5.284  	CBaseEntity *pEntity;
   5.285 -	edict_t *pEdict = GetEntity(params[1], &pEntity);
   5.286 +	GetEntity(params[1], &pEntity);
   5.287  
   5.288 -	if (!pEdict || !pEntity)
   5.289 +	if (!pEntity)
   5.290  	{
   5.291 -		return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
   5.292 +		return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
   5.293  	}
   5.294  
   5.295  	int offset = params[2];
   5.296 @@ -497,7 +516,8 @@
   5.297  		return 0;
   5.298  	}
   5.299  
   5.300 -	return hndl.GetEntryIndex();
   5.301 +	int ref = g_HL2.IndexToReference(hndl.GetEntryIndex());
   5.302 +	return g_HL2.ReferenceToBCompatRef(ref);
   5.303  }
   5.304  
   5.305  int CheckBaseHandle(CBaseHandle &hndl)
   5.306 @@ -537,11 +557,11 @@
   5.307  static cell_t GetEntDataEnt2(IPluginContext *pContext, const cell_t *params)
   5.308  {
   5.309  	CBaseEntity *pEntity;
   5.310 -	edict_t *pEdict = GetEntity(params[1], &pEntity);
   5.311 +	GetEntity(params[1], &pEntity);
   5.312  
   5.313 -	if (pEdict == NULL || pEntity == NULL)
   5.314 +	if (pEntity == NULL)
   5.315  	{
   5.316 -		return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
   5.317 +		return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
   5.318  	}
   5.319  
   5.320  	int offset = params[2];
   5.321 @@ -552,7 +572,8 @@
   5.322  
   5.323  	CBaseHandle &hndl = *(CBaseHandle *)((uint8_t *)pEntity + offset);
   5.324  
   5.325 -	return CheckBaseHandle(hndl);
   5.326 +	int ref = g_HL2.IndexToReference(hndl.GetEntryIndex());
   5.327 +	return g_HL2.ReferenceToBCompatRef(ref);
   5.328  }
   5.329  
   5.330  /* THIS GUY IS DEPRECATED. */
   5.331 @@ -561,9 +582,9 @@
   5.332  	CBaseEntity *pEntity;
   5.333  	edict_t *pEdict = GetEntity(params[1], &pEntity);
   5.334  
   5.335 -	if (!pEdict || !pEntity)
   5.336 +	if (!pEntity)
   5.337  	{
   5.338 -		return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
   5.339 +		return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
   5.340  	}
   5.341  
   5.342  	int offset = params[2];
   5.343 @@ -574,20 +595,23 @@
   5.344  
   5.345  	CBaseHandle &hndl = *(CBaseHandle *)((uint8_t *)pEntity + offset);
   5.346  
   5.347 -	if (params[3] == 0)
   5.348 +	if (params[3] == 0 || params[3] == INVALID_EHANDLE_INDEX)
   5.349  	{
   5.350  		hndl.Set(NULL);
   5.351  	} else {
   5.352 -		edict_t *pEdict = GetEdict(params[3]);
   5.353 -		if (!pEdict)
   5.354 +		CBaseEntity *pOther;
   5.355 +		GetEntity(params[3], &pOther);
   5.356 +
   5.357 +		if (!pOther)
   5.358  		{
   5.359 -			return pContext->ThrowNativeError("Entity %d is invalid", params[3]);
   5.360 +			return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[3]), params[3]);
   5.361  		}
   5.362 -		IServerEntity *pEntOther = pEdict->GetIServerEntity();
   5.363 -		hndl.Set(pEntOther);
   5.364 +
   5.365 +		IHandleEntity *pHandleEnt = (IHandleEntity *)pOther;
   5.366 +		hndl.Set(pHandleEnt);
   5.367  	}
   5.368  
   5.369 -	if (params[4])
   5.370 +	if (params[4] && (pEdict != NULL))
   5.371  	{
   5.372  		g_HL2.SetEdictStateChanged(pEdict, offset);
   5.373  	}
   5.374 @@ -600,9 +624,9 @@
   5.375  	CBaseEntity *pEntity;
   5.376  	edict_t *pEdict = GetEntity(params[1], &pEntity);
   5.377  
   5.378 -	if (!pEdict || !pEntity)
   5.379 +	if (!pEntity)
   5.380  	{
   5.381 -		return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
   5.382 +		return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
   5.383  	}
   5.384  
   5.385  	int offset = params[2];
   5.386 @@ -613,22 +637,25 @@
   5.387  
   5.388  	CBaseHandle &hndl = *(CBaseHandle *)((uint8_t *)pEntity + offset);
   5.389  
   5.390 -	if (params[3] == -1)
   5.391 +	if (params[3] == INVALID_EHANDLE_INDEX)
   5.392  	{
   5.393  		hndl.Set(NULL);
   5.394  	}
   5.395  	else
   5.396  	{
   5.397 -		edict_t *pEdict = GetEdict(params[3]);
   5.398 -		if (!pEdict)
   5.399 +		CBaseEntity *pOther;
   5.400 +		GetEntity(params[3], &pOther);
   5.401 +
   5.402 +		if (!pOther)
   5.403  		{
   5.404 -			return pContext->ThrowNativeError("Entity %d is invalid", params[3]);
   5.405 +			return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[3]), params[3]);
   5.406  		}
   5.407 -		IServerEntity *pEntOther = pEdict->GetIServerEntity();
   5.408 -		hndl.Set(pEntOther);
   5.409 +
   5.410 +		IHandleEntity *pHandleEnt = (IHandleEntity *)pOther;
   5.411 +		hndl.Set(pHandleEnt);
   5.412  	}
   5.413  
   5.414 -	if (params[4])
   5.415 +	if (params[4] && (pEdict != NULL))
   5.416  	{
   5.417  		g_HL2.SetEdictStateChanged(pEdict, offset);
   5.418  	}
   5.419 @@ -642,7 +669,7 @@
   5.420  
   5.421  	if (!pEdict)
   5.422  	{
   5.423 -		return pContext->ThrowNativeError("Edict %d is invalid", params[1]);
   5.424 +		return pContext->ThrowNativeError("Edict %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
   5.425  	}
   5.426  
   5.427  	g_HL2.SetEdictStateChanged(pEdict, params[2]);
   5.428 @@ -725,11 +752,11 @@
   5.429  	datamap_t *pMap;
   5.430  	typedescription_t *td;
   5.431  	char *offset;
   5.432 -	edict_t *pEdict = GetEntity(params[1], &pEntity);
   5.433 +	GetEntity(params[1], &pEntity);
   5.434  
   5.435 -	if (!pEdict || !pEntity)
   5.436 +	if (!pEntity)
   5.437  	{
   5.438 -		return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
   5.439 +		return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
   5.440  	}
   5.441  
   5.442  	if ((pMap=CBaseEntity_GetDataDescMap(pEntity)) == NULL)
   5.443 @@ -830,11 +857,11 @@
   5.444  static cell_t GetEntDataString(IPluginContext *pContext, const cell_t *params)
   5.445  {
   5.446  	CBaseEntity *pEntity;
   5.447 -	edict_t *pEdict = GetEntity(params[1], &pEntity);
   5.448 +	GetEntity(params[1], &pEntity);
   5.449  
   5.450 -	if (!pEdict || !pEntity)
   5.451 +	if (!pEntity)
   5.452  	{
   5.453 -		return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
   5.454 +		return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
   5.455  	}
   5.456  
   5.457  	int offset = params[2];
   5.458 @@ -855,9 +882,9 @@
   5.459  	CBaseEntity *pEntity;
   5.460  	edict_t *pEdict = GetEntity(params[1], &pEntity);
   5.461  
   5.462 -	if (!pEdict || !pEntity)
   5.463 +	if (!pEntity)
   5.464  	{
   5.465 -		return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
   5.466 +		return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
   5.467  	}
   5.468  
   5.469  	int offset = params[2];
   5.470 @@ -872,7 +899,7 @@
   5.471  	pContext->LocalToString(params[3], &src);
   5.472  	size_t len = strncopy(dest, src, params[4]);
   5.473  
   5.474 -	if (params[5])
   5.475 +	if (params[5] && (pEdict != NULL))
   5.476  	{
   5.477  		g_HL2.SetEdictStateChanged(pEdict, offset);
   5.478  	}
   5.479 @@ -895,10 +922,11 @@
   5.480  	}
   5.481  
   5.482  #define FIND_PROP_SEND(pProp) \
   5.483 -	IServerNetworkable *pNet = pEdict->GetNetworkable(); \
   5.484 +	IServerUnknown *pUnk = (IServerUnknown *)pEntity; \
   5.485 +	IServerNetworkable *pNet = pUnk->GetNetworkable(); \
   5.486  	if (!pNet) \
   5.487  	{ \
   5.488 -		return pContext->ThrowNativeError("Edict %d is not networkable", params[1]); \
   5.489 +		return pContext->ThrowNativeError("Edict %d (%d) is not networkable", g_HL2.ReferenceToIndex(params[1]), params[1]); \
   5.490  	} \
   5.491  	if (!g_HL2.FindSendPropInfo(pNet->GetServerClass()->GetName(), prop, pProp)) \
   5.492  	{ \
   5.493 @@ -942,12 +970,13 @@
   5.494  
   5.495  	pEdict = GetEntity(params[1], &pEntity);
   5.496  
   5.497 -	if (!pEdict || !pEntity)
   5.498 +	if (!pEntity)
   5.499  	{
   5.500 -		return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
   5.501 +		return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
   5.502  	}
   5.503  
   5.504 -	if ((class_name = pEdict->GetClassName()) == NULL)
   5.505 +	/* TODO: Find a way to lookup classname without having an edict - Is this a guaranteed prop? */
   5.506 +	if (!pEdict || (class_name = pEdict->GetClassName()) == NULL)
   5.507  	{
   5.508  		class_name = "";
   5.509  	}
   5.510 @@ -1033,12 +1062,12 @@
   5.511  
   5.512  	pEdict = GetEntity(params[1], &pEntity);
   5.513  
   5.514 -	if (!pEdict || !pEntity)
   5.515 +	if (!pEntity)
   5.516  	{
   5.517 -		return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
   5.518 +		return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
   5.519  	}
   5.520  
   5.521 -	if ((class_name = pEdict->GetClassName()) == NULL)
   5.522 +	if (!pEdict || (class_name = pEdict->GetClassName()) == NULL)
   5.523  	{
   5.524  		class_name = "";
   5.525  	}
   5.526 @@ -1123,12 +1152,12 @@
   5.527  
   5.528  	pEdict = GetEntity(params[1], &pEntity);
   5.529  
   5.530 -	if (!pEdict || !pEntity)
   5.531 +	if (!pEntity)
   5.532  	{
   5.533 -		return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
   5.534 +		return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
   5.535  	}
   5.536  
   5.537 -	if ((class_name = pEdict->GetClassName()) == NULL)
   5.538 +	if (!pEdict || (class_name = pEdict->GetClassName()) == NULL)
   5.539  	{
   5.540  		class_name = "";
   5.541  	}
   5.542 @@ -1194,12 +1223,12 @@
   5.543  
   5.544  	pEdict = GetEntity(params[1], &pEntity);
   5.545  
   5.546 -	if (!pEdict || !pEntity)
   5.547 +	if (!pEntity)
   5.548  	{
   5.549 -		return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
   5.550 +		return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
   5.551  	}
   5.552  
   5.553 -	if ((class_name = pEdict->GetClassName()) == NULL)
   5.554 +	if (!pEdict || (class_name = pEdict->GetClassName()) == NULL)
   5.555  	{
   5.556  		class_name = "";
   5.557  	}
   5.558 @@ -1252,7 +1281,7 @@
   5.559  
   5.560  	*(float *)((uint8_t *)pEntity + offset) = sp_ctof(params[4]);
   5.561  
   5.562 -	if (params[2] == Prop_Send)
   5.563 +	if (params[2] == Prop_Send && (pEdict != NULL))
   5.564  	{
   5.565  		g_HL2.SetEdictStateChanged(pEdict, offset);
   5.566  	}
   5.567 @@ -1270,12 +1299,12 @@
   5.568  
   5.569  	pEdict = GetEntity(params[1], &pEntity);
   5.570  
   5.571 -	if (!pEdict || !pEntity)
   5.572 +	if (!pEntity)
   5.573  	{
   5.574 -		return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
   5.575 +		return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
   5.576  	}
   5.577  
   5.578 -	if ((class_name = pEdict->GetClassName()) == NULL)
   5.579 +	if (!pEdict || (class_name = pEdict->GetClassName()) == NULL)
   5.580  	{
   5.581  		class_name = "";
   5.582  	}
   5.583 @@ -1326,7 +1355,8 @@
   5.584  
   5.585  	CBaseHandle &hndl = *(CBaseHandle *)((uint8_t *)pEntity + offset);
   5.586  
   5.587 -	return CheckBaseHandle(hndl);
   5.588 +	int ref = g_HL2.IndexToReference(hndl.GetEntryIndex());
   5.589 +	return g_HL2.ReferenceToBCompatRef(ref);
   5.590  }
   5.591  
   5.592  static cell_t SetEntPropEnt(IPluginContext *pContext, const cell_t *params)
   5.593 @@ -1339,12 +1369,12 @@
   5.594  
   5.595  	pEdict = GetEntity(params[1], &pEntity);
   5.596  
   5.597 -	if (!pEdict || !pEntity)
   5.598 +	if (!pEntity)
   5.599  	{
   5.600 -		return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
   5.601 +		return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
   5.602  	}
   5.603  
   5.604 -	if ((class_name = pEdict->GetClassName()) == NULL)
   5.605 +	if (!pEdict || (class_name = pEdict->GetClassName()) == NULL)
   5.606  	{
   5.607  		class_name = "";
   5.608  	}
   5.609 @@ -1401,18 +1431,19 @@
   5.610  	}
   5.611  	else
   5.612  	{
   5.613 -		edict_t *pOther;
   5.614 -		CBaseEntity *pOtherEnt;
   5.615 +		CBaseEntity *pOther;
   5.616 +		GetEntity(params[4], &pOther);
   5.617  
   5.618 -		if ((pOther = GetEntity(params[4], &pOtherEnt)) == NULL)
   5.619 +		if (!pOther)
   5.620  		{
   5.621 -			return pContext->ThrowNativeError("Invalid entity %d", params[4]);
   5.622 +			return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[4]), params[4]);
   5.623  		}
   5.624  
   5.625 -		hndl.Set(pOther->GetIServerEntity());
   5.626 +		IHandleEntity *pHandleEnt = (IHandleEntity *)pOther;
   5.627 +		hndl.Set(pHandleEnt);
   5.628  	}
   5.629  
   5.630 -	if (params[2] == Prop_Send)
   5.631 +	if (params[2] == Prop_Send && (pEdict != NULL))
   5.632  	{
   5.633  		g_HL2.SetEdictStateChanged(pEdict, offset);
   5.634  	}
   5.635 @@ -1430,12 +1461,12 @@
   5.636  	
   5.637  	pEdict = GetEntity(params[1], &pEntity);
   5.638  
   5.639 -	if (!pEdict || !pEntity)
   5.640 +	if (!pEntity)
   5.641  	{
   5.642 -		return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
   5.643 +		return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
   5.644  	}
   5.645  
   5.646 -	if ((class_name = pEdict->GetClassName()) == NULL)
   5.647 +	if (!pEdict || (class_name = pEdict->GetClassName()) == NULL)
   5.648  	{
   5.649  		class_name = "";
   5.650  	}
   5.651 @@ -1508,12 +1539,12 @@
   5.652  	
   5.653  	pEdict = GetEntity(params[1], &pEntity);
   5.654  
   5.655 -	if (!pEdict || !pEntity)
   5.656 +	if (!pEntity)
   5.657  	{
   5.658 -		return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
   5.659 +		return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
   5.660  	}
   5.661  
   5.662 -	if ((class_name = pEdict->GetClassName()) == NULL)
   5.663 +	if (!pEdict || (class_name = pEdict->GetClassName()) == NULL)
   5.664  	{
   5.665  		class_name = "";
   5.666  	}
   5.667 @@ -1573,7 +1604,7 @@
   5.668  	v->y = sp_ctof(vec[1]);
   5.669  	v->z = sp_ctof(vec[2]);
   5.670  
   5.671 -	if (params[2] == Prop_Send)
   5.672 +	if (params[2] == Prop_Send && (pEdict != NULL))
   5.673  	{
   5.674  		g_HL2.SetEdictStateChanged(pEdict, offset);
   5.675  	}
   5.676 @@ -1592,12 +1623,12 @@
   5.677  	
   5.678  	pEdict = GetEntity(params[1], &pEntity);
   5.679  
   5.680 -	if (!pEdict || !pEntity)
   5.681 +	if (!pEntity)
   5.682  	{
   5.683 -		return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
   5.684 +		return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
   5.685  	}
   5.686  
   5.687 -	if ((class_name = pEdict->GetClassName()) == NULL)
   5.688 +	if (!pEdict || (class_name = pEdict->GetClassName()) == NULL)
   5.689  	{
   5.690  		class_name = "";
   5.691  	}
   5.692 @@ -1682,9 +1713,9 @@
   5.693  	int maxlen;
   5.694  	edict_t *pEdict = GetEntity(params[1], &pEntity);
   5.695  
   5.696 -	if (!pEdict || !pEntity)
   5.697 +	if (!pEntity)
   5.698  	{
   5.699 -		return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
   5.700 +		return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
   5.701  	}
   5.702  
   5.703  	switch (params[2])
   5.704 @@ -1713,7 +1744,8 @@
   5.705  	case Prop_Send:
   5.706  		{
   5.707  			char *prop;
   5.708 -			IServerNetworkable *pNet = pEdict->GetNetworkable();
   5.709 +			IServerUnknown *pUnk = (IServerUnknown *)pEntity;
   5.710 +			IServerNetworkable *pNet = pUnk->GetNetworkable();
   5.711  			if (!pNet)
   5.712  			{
   5.713  				return pContext->ThrowNativeError("The edict is not networkable");
   5.714 @@ -1744,7 +1776,7 @@
   5.715  	pContext->LocalToString(params[4], &src);
   5.716  	size_t len = strncopy(dest, src, maxlen);
   5.717  
   5.718 -	if (params[2] == Prop_Send)
   5.719 +	if (params[2] == Prop_Send && (pEdict != NULL))
   5.720  	{
   5.721  		g_HL2.SetEdictStateChanged(pEdict, offset);
   5.722  	}
     6.1 --- a/core/smn_halflife.cpp	Thu Jul 09 17:51:12 2009 -0400
     6.2 +++ b/core/smn_halflife.cpp	Fri Jul 24 12:34:31 2009 +1200
     6.3 @@ -475,6 +475,26 @@
     6.4  	return 0;
     6.5  }
     6.6  
     6.7 +static cell_t IndexToReference(IPluginContext *pContext, const cell_t *params)
     6.8 +{
     6.9 +	if (params[1] >= NUM_ENT_ENTRIES || params[1] < 0)
    6.10 +	{
    6.11 +		return pContext->ThrowNativeError("Invalid entity index %i", params[1]);
    6.12 +	}
    6.13 +
    6.14 +	return g_HL2.IndexToReference(params[1]);
    6.15 +}
    6.16 +
    6.17 +static cell_t ReferenceToIndex(IPluginContext *pContext, const cell_t *params)
    6.18 +{
    6.19 +	return g_HL2.ReferenceToIndex(params[1]);
    6.20 +}
    6.21 +
    6.22 +static cell_t ReferenceToBCompatRef(IPluginContext *pContext, const cell_t *params)
    6.23 +{
    6.24 +	return g_HL2.ReferenceToBCompatRef(params[1]);
    6.25 +}
    6.26 +
    6.27  REGISTER_NATIVES(halflifeNatives)
    6.28  {
    6.29  	{"CreateFakeClient",		CreateFakeClient},
    6.30 @@ -505,5 +525,8 @@
    6.31  	{"ShowVGUIPanel",			ShowVGUIPanel},
    6.32  	{"IsPlayerAlive",			smn_IsPlayerAlive},
    6.33  	{"GuessSDKVersion",			GuessSDKVersion},
    6.34 +	{"EntIndexToEntRef",		IndexToReference},
    6.35 +	{"EntRefToEntIndex",		ReferenceToIndex},
    6.36 +	{"MakeCompatEntRef",		ReferenceToBCompatRef},
    6.37  	{NULL,						NULL},
    6.38  };
     7.1 --- a/extensions/sdktools/inputnatives.cpp	Thu Jul 09 17:51:12 2009 -0400
     7.2 +++ b/extensions/sdktools/inputnatives.cpp	Fri Jul 24 12:34:31 2009 +1200
     7.3 @@ -37,21 +37,11 @@
     7.4  ICallWrapper *g_pAcceptInput = NULL;
     7.5  unsigned char g_Variant_t[SIZEOF_VARIANT_T] = {0};
     7.6  
     7.7 -#define ENTINDEX_TO_CBASEENTITY(index, buffer) \
     7.8 -	pEdict = PEntityOfEntIndex(index); \
     7.9 -	if (!pEdict || pEdict->IsFree()) \
    7.10 -	{ \
    7.11 -		return pContext->ThrowNativeError("Entity %d is not valid or is freed", index); \
    7.12 -	} \
    7.13 -	pUnk = pEdict->GetUnknown(); \
    7.14 -	if (!pUnk) \
    7.15 -	{ \
    7.16 -		return pContext->ThrowNativeError("Entity %d is a not an IServerUnknown", index); \
    7.17 -	} \
    7.18 -	buffer = pUnk->GetBaseEntity(); \
    7.19 +#define ENTINDEX_TO_CBASEENTITY(ref, buffer) \
    7.20 +	buffer = gamehelpers->ReferenceToEntity(ref); \
    7.21  	if (!buffer) \
    7.22  	{ \
    7.23 -		return pContext->ThrowNativeError("Entity %d is not a CBaseEntity", index); \
    7.24 +		return pContext->ThrowNativeError("Entity %d (%d) is not a CBaseEntity", gamehelpers->ReferenceToIndex(ref), ref); \
    7.25  	}
    7.26  
    7.27  /* Hack to init the variant_t object for the first time */
    7.28 @@ -109,8 +99,6 @@
    7.29  	}
    7.30  
    7.31  	CBaseEntity *pActivator, *pCaller, *pDest;
    7.32 -	edict_t *pEdict;
    7.33 -	IServerUnknown *pUnk;
    7.34  
    7.35  	char *inputname;
    7.36  	unsigned char vstk[sizeof(void *) + sizeof(const char *) + sizeof(CBaseEntity *)*2 + SIZEOF_VARIANT_T + sizeof(int)];
    7.37 @@ -257,8 +245,6 @@
    7.38  static cell_t SetVariantEntity(IPluginContext *pContext, const cell_t *params)
    7.39  {
    7.40  	CBaseEntity *pEntity;
    7.41 -	edict_t *pEdict;
    7.42 -	IServerUnknown *pUnk;
    7.43  	unsigned char *vptr = g_Variant_t;
    7.44  	CBaseHandle bHandle;
    7.45  
     8.1 --- a/extensions/sdktools/output.cpp	Thu Jul 09 17:51:12 2009 -0400
     8.2 +++ b/extensions/sdktools/output.cpp	Fri Jul 24 12:34:31 2009 +1200
     8.3 @@ -205,20 +205,12 @@
     8.4  	// attempt to directly lookup a hook using the pOutput pointer
     8.5  	OutputNameStruct *pOutputName = NULL;
     8.6  
     8.7 -	edict_t *pEdict = gameents->BaseEntityToEdict(pCaller);
     8.8 -
     8.9 -	/* TODO: Add support for entities without an edict */
    8.10 -	if (pEdict == NULL)
    8.11 -	{
    8.12 -		return;
    8.13 -	}
    8.14 -
    8.15  	bool fastLookup = false;
    8.16  	
    8.17  	// Fast lookup failed - check the slow way for hooks that havn't fired yet
    8.18  	if ((fastLookup = EntityOutputs->Retrieve(sOutput, (void **)&pOutputName)) == false)
    8.19  	{
    8.20 -		const char *classname = pEdict->GetClassName();
    8.21 +		const char *classname = GetEntityClassname(pCaller);
    8.22  		const char *outputname = FindOutputName(pOutput, pCaller);
    8.23  
    8.24  		pOutputName = FindOutputPointer(classname, outputname, false);
    8.25 @@ -249,37 +241,31 @@
    8.26  
    8.27  			hook->in_use = true;
    8.28  
    8.29 -			int serial = pEdict->m_NetworkSerialNumber;
    8.30 +			cell_t ref = gamehelpers->EntityToReference(pCaller);
    8.31  			
    8.32 -			if (serial != hook->entity_filter && hook->entity_index == IndexOfEdict(pEdict))
    8.33 +			if (hook->entity_ref != -1 
    8.34 +					&& gamehelpers->ReferenceToIndex(hook->entity_ref) == gamehelpers->ReferenceToIndex(ref)
    8.35 +					&& ref != hook->entity_ref)
    8.36  			{
    8.37 -				// same entity index but different serial number. Entity has changed, kill the hook.
    8.38 +				// same entity index but different reference. Entity has changed, kill the hook.
    8.39  				_iter = pOutputName->hooks.erase(_iter);
    8.40  				CleanUpHook(hook);
    8.41  
    8.42  				continue;
    8.43  			}
    8.44  
    8.45 -			if (hook->entity_filter == -1 || hook->entity_filter == serial) // Global classname hook
    8.46 +			if (hook->entity_ref == -1 || hook->entity_ref == ref) // Global classname hook
    8.47  			{
    8.48  				//fire the forward to hook->pf
    8.49  				hook->pf->PushString(pOutputName->Name);
    8.50 -				hook->pf->PushCell(IndexOfEdict(pEdict));
    8.51 -				
    8.52 -				edict_t *pEdictActivator = gameents->BaseEntityToEdict(pActivator);
    8.53 -				if (!pEdictActivator)
    8.54 -				{
    8.55 -					hook->pf->PushCell(-1);
    8.56 -				}
    8.57 -				else
    8.58 -				{
    8.59 -					hook->pf->PushCell(IndexOfEdict(pEdictActivator));
    8.60 -				}
    8.61 +				hook->pf->PushCell(gamehelpers->ReferenceToBCompatRef(ref));
    8.62 +				hook->pf->PushCell(gamehelpers->EntityToBCompatRef(pActivator));
    8.63 +
    8.64  				//hook->pf->PushCell(handle);
    8.65  				hook->pf->PushFloat(fDelay);
    8.66  				hook->pf->Execute(NULL);
    8.67  
    8.68 -				if ((hook->entity_filter != -1) && hook->only_once)
    8.69 +				if ((hook->entity_ref != -1) && hook->only_once)
    8.70  				{
    8.71  					_iter = pOutputName->hooks.erase(_iter);
    8.72  					CleanUpHook(hook);
    8.73 @@ -454,36 +440,15 @@
    8.74  	return NULL;
    8.75  }
    8.76  
    8.77 -// Thanks SM core
    8.78 -edict_t *EntityOutputManager::BaseHandleToEdict(CBaseHandle &hndl)
    8.79 +const char *EntityOutputManager::GetEntityClassname(CBaseEntity *pEntity)
    8.80  {
    8.81 -	if (!hndl.IsValid())
    8.82 +	static int offset = -1;
    8.83 +	if (offset == -1)
    8.84  	{
    8.85 -		return NULL;
    8.86 +		datamap_t *pMap = gamehelpers->GetDataMap(pEntity);
    8.87 +		typedescription_t *pDesc = gamehelpers->FindInDataMap(pMap, "m_iClassname");
    8.88 +		offset = pDesc->fieldOffset[TD_OFFSET_NORMAL];
    8.89  	}
    8.90  
    8.91 -	int index = hndl.GetEntryIndex();
    8.92 -
    8.93 -	edict_t *pStoredEdict;
    8.94 -
    8.95 -	pStoredEdict = PEntityOfEntIndex(index);
    8.96 -
    8.97 -	if (pStoredEdict == NULL)
    8.98 -	{
    8.99 -		return NULL;
   8.100 -	}
   8.101 -
   8.102 -	IServerEntity *pSE = pStoredEdict->GetIServerEntity();
   8.103 -
   8.104 -	if (pSE == NULL)
   8.105 -	{
   8.106 -		return NULL;
   8.107 -	}
   8.108 -
   8.109 -	if (pSE->GetRefEHandle() != hndl)
   8.110 -	{
   8.111 -		return NULL;
   8.112 -	}
   8.113 -
   8.114 -	return pStoredEdict;
   8.115 -}
   8.116 +	return (const char *)(((unsigned char *)pEntity) + offset);
   8.117 +}
   8.118 \ No newline at end of file
     9.1 --- a/extensions/sdktools/output.h	Thu Jul 09 17:51:12 2009 -0400
     9.2 +++ b/extensions/sdktools/output.h	Fri Jul 24 12:34:31 2009 +1200
     9.3 @@ -49,8 +49,7 @@
     9.4   */
     9.5  struct omg_hooks 
     9.6  {
     9.7 -	int entity_filter; // if not -1 is an entity signature
     9.8 -	int entity_index;
     9.9 +	cell_t entity_ref;
    9.10  	bool only_once;
    9.11  	IPluginFunction *pf;
    9.12  	OutputNameStruct *m_parent;
    9.13 @@ -110,6 +109,8 @@
    9.14  	void OnHookAdded();
    9.15  	void OnHookRemoved();
    9.16  
    9.17 +	const char *GetEntityClassname(CBaseEntity *pEntity);
    9.18 +
    9.19  private:
    9.20  	bool enabled;
    9.21  
    9.22 @@ -123,7 +124,6 @@
    9.23  	void DeleteFireEventDetour();
    9.24  
    9.25  	const char *FindOutputName(void *pOutput, CBaseEntity *pCaller);
    9.26 -	edict_t *BaseHandleToEdict(CBaseHandle &hndl);
    9.27  
    9.28  	//Maps CEntityOutput * to a OutputNameStruct
    9.29  	IBasicTrie *EntityOutputs;
    10.1 --- a/extensions/sdktools/outputnatives.cpp	Thu Jul 09 17:51:12 2009 -0400
    10.2 +++ b/extensions/sdktools/outputnatives.cpp	Fri Jul 24 12:34:31 2009 +1200
    10.3 @@ -40,12 +40,13 @@
    10.4  		return pContext->ThrowNativeError("Entity Outputs are disabled - See error logs for details");
    10.5  	}
    10.6  
    10.7 -	edict_t *pEdict = PEntityOfEntIndex(params[1]);
    10.8 -	if (!pEdict)
    10.9 +	CBaseEntity *pEntity = gamehelpers->ReferenceToEntity(params[1]);
   10.10 +	if (!pEntity)
   10.11  	{
   10.12 -		return pContext->ThrowNativeError("Invalid Entity index %i", params[1]);
   10.13 +		return pContext->ThrowNativeError("Invalid Entity index %i (%i)", gamehelpers->ReferenceToIndex(params[1]), params[1]);
   10.14  	}
   10.15 -	const char *classname = pEdict->GetClassName();
   10.16 +
   10.17 +	const char *classname = g_OutputManager.GetEntityClassname(pEntity);
   10.18  
   10.19  	char *outputname;
   10.20  	pContext->LocalToString(params[2], &outputname);
   10.21 @@ -63,7 +64,7 @@
   10.22  	for (_iter=pOutputName->hooks.begin(); _iter!=pOutputName->hooks.end(); _iter++)
   10.23  	{
   10.24  		hook = (omg_hooks *)*_iter;
   10.25 -		if (hook->pf == pFunction && hook->entity_filter == pEdict->m_NetworkSerialNumber)
   10.26 +		if (hook->pf == pFunction && hook->entity_ref == gamehelpers->EntityToReference(pEntity))
   10.27  		{
   10.28  			return 0;
   10.29  		}
   10.30 @@ -71,8 +72,7 @@
   10.31  
   10.32  	hook = g_OutputManager.NewHook();
   10.33  
   10.34 -	hook->entity_filter = pEdict->m_NetworkSerialNumber;
   10.35 -	hook->entity_index = IndexOfEdict(pEdict);
   10.36 +	hook->entity_ref = gamehelpers->EntityToReference(pEntity);
   10.37  	hook->only_once= !!params[4];
   10.38  	hook->pf = pFunction;
   10.39  	hook->m_parent = pOutputName;
   10.40 @@ -125,7 +125,7 @@
   10.41  	for (_iter=pOutputName->hooks.begin(); _iter!=pOutputName->hooks.end(); _iter++)
   10.42  	{
   10.43  		hook = (omg_hooks *)*_iter;
   10.44 -		if (hook->pf == pFunction && hook->entity_filter == -1)
   10.45 +		if (hook->pf == pFunction && hook->entity_ref == -1)
   10.46  		{
   10.47  			//already hooked to this function...
   10.48  			//throw an error or just let them get away with stupidity?
   10.49 @@ -136,7 +136,7 @@
   10.50  
   10.51  	hook = g_OutputManager.NewHook();
   10.52  
   10.53 -	hook->entity_filter = -1;
   10.54 +	hook->entity_ref = -1;
   10.55  	hook->pf = pFunction;
   10.56  	hook->m_parent = pOutputName;
   10.57  	hook->in_use = false;
   10.58 @@ -192,7 +192,7 @@
   10.59  	for (_iter=pOutputName->hooks.begin(); _iter!=pOutputName->hooks.end(); _iter++)
   10.60  	{
   10.61  		hook = (omg_hooks *)*_iter;
   10.62 -		if (hook->pf == pFunction && hook->entity_filter == -1)
   10.63 +		if (hook->pf == pFunction && hook->entity_ref == -1)
   10.64  		{
   10.65  			// remove this hook.
   10.66  			if (hook->in_use)
   10.67 @@ -220,13 +220,13 @@
   10.68  	}
   10.69  
   10.70  	// Find the classname of the entity and lookup the classname and output structures
   10.71 -	edict_t *pEdict = PEntityOfEntIndex(params[1]);
   10.72 -	if (!pEdict)
   10.73 +	CBaseEntity *pEntity = gamehelpers->ReferenceToEntity(params[1]);
   10.74 +	if (!pEntity)
   10.75  	{
   10.76 -		return pContext->ThrowNativeError("Invalid Entity index %i", params[1]);
   10.77 +		return pContext->ThrowNativeError("Invalid Entity index %i (%i)", gamehelpers->ReferenceToIndex(params[1]), params[1]);
   10.78  	}
   10.79  
   10.80 -	const char *classname = pEdict->GetClassName();
   10.81 +	const char *classname = g_OutputManager.GetEntityClassname(pEntity);
   10.82  
   10.83  	char *outputname;
   10.84  	pContext->LocalToString(params[2], &outputname);
   10.85 @@ -249,7 +249,8 @@
   10.86  	for (_iter=pOutputName->hooks.begin(); _iter!=pOutputName->hooks.end(); _iter++)
   10.87  	{
   10.88  		hook = (omg_hooks *)*_iter;
   10.89 -		if (hook->pf == pFunction && hook->entity_index == IndexOfEdict(pEdict))
   10.90 +		/* We're not serial checking and just removing by index here - This was always allowed so is left for bcompat */
   10.91 +		if (hook->pf == pFunction && gamehelpers->ReferenceToIndex(hook->entity_ref) == gamehelpers->ReferenceToIndex(params[1]))
   10.92  		{
   10.93  			// remove this hook.
   10.94  			if (hook->in_use)
    11.1 --- a/extensions/sdktools/trnatives.cpp	Thu Jul 09 17:51:12 2009 -0400
    11.2 +++ b/extensions/sdktools/trnatives.cpp	Fri Jul 24 12:34:31 2009 +1200
    11.3 @@ -38,8 +38,7 @@
    11.4  	bool ShouldHitEntity(IHandleEntity *pEntity, int contentsMask)
    11.5  	{
    11.6  		cell_t res = 1;
    11.7 -		edict_t *pEdict = gameents->BaseEntityToEdict(reinterpret_cast<CBaseEntity *>(pEntity));
    11.8 -		m_pFunc->PushCell(IndexOfEdict(pEdict));
    11.9 +		m_pFunc->PushCell(gamehelpers->EntityToBCompatRef(reinterpret_cast<CBaseEntity *>(pEntity)));
   11.10  		m_pFunc->PushCell(contentsMask);
   11.11  		m_pFunc->PushCell(m_Data);
   11.12  		m_pFunc->Execute(&res);
   11.13 @@ -505,8 +504,7 @@
   11.14  		return pContext->ThrowNativeError("Invalid Handle %x (error %d)", params[1], err);
   11.15  	}
   11.16  
   11.17 -	edict_t *pEdict = gameents->BaseEntityToEdict(tr->m_pEnt);
   11.18 -	return IndexOfEdict(pEdict);
   11.19 +	return gamehelpers->EntityToBCompatRef(tr->m_pEnt);
   11.20  }
   11.21  
   11.22  static cell_t smn_TRGetPointContents(IPluginContext *pContext, const cell_t *params)
   11.23 @@ -532,8 +530,7 @@
   11.24  #else
   11.25  		mask = enginetrace->GetPointContents(pos, &hentity);
   11.26  #endif
   11.27 -		edict_t *pEdict = gameents->BaseEntityToEdict(reinterpret_cast<CBaseEntity *>(hentity));
   11.28 -		*ent = IndexOfEdict(pEdict);
   11.29 +		*ent = gamehelpers->EntityToBCompatRef(reinterpret_cast<CBaseEntity *>(hentity));
   11.30  	}
   11.31  
   11.32  	return mask;
   11.33 @@ -541,7 +538,8 @@
   11.34  
   11.35  static cell_t smn_TRGetPointContentsEnt(IPluginContext *pContext, const cell_t *params)
   11.36  {
   11.37 -	edict_t *pEdict = PEntityOfEntIndex(params[1]);
   11.38 +	/* TODO: See if we can get the collidable with a prop and remove the reliance on edicts */
   11.39 +	edict_t *pEdict = PEntityOfEntIndex(gamehelpers->ReferenceToIndex(params[1]));
   11.40  	if (!pEdict || pEdict->IsFree())
   11.41  	{
   11.42  		return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
    12.1 --- a/extensions/sdktools/vdecoder.cpp	Thu Jul 09 17:51:12 2009 -0400
    12.2 +++ b/extensions/sdktools/vdecoder.cpp	Fri Jul 24 12:34:31 2009 +1200
    12.3 @@ -222,8 +222,7 @@
    12.4  			CBaseEntity *pEntity = *(CBaseEntity **)buffer;
    12.5  			if (pEntity)
    12.6  			{
    12.7 -				edict_t *pEdict = gameents->BaseEntityToEdict(pEntity);
    12.8 -				*addr = IndexOfEdict(pEdict);
    12.9 +				*addr = gamehelpers->EntityToBCompatRef(pEntity);
   12.10  			} else {
   12.11  				*addr = -1;
   12.12  			}
   12.13 @@ -384,16 +383,21 @@
   12.14  		}
   12.15  	case Valve_CBasePlayer:
   12.16  		{
   12.17 -			edict_t *pEdict;
   12.18 +			CBaseEntity *pEntity = NULL;
   12.19  			if (data->decflags & VDECODE_FLAG_BYREF)
   12.20  			{
   12.21  				cell_t *addr;
   12.22  				pContext->LocalToPhysAddr(param, &addr);
   12.23  				param = *addr;
   12.24  			}
   12.25 -			if (param >= 1 && param <= playerhelpers->GetMaxClients())
   12.26 +			int index = gamehelpers->ReferenceToIndex(param);
   12.27 +			if (index == INVALID_EHANDLE_INDEX && param != -1)
   12.28  			{
   12.29 -				IGamePlayer *player = playerhelpers->GetGamePlayer(param);
   12.30 +				return Data_Fail;
   12.31 +			}
   12.32 +			if (index >= 1 && index <= playerhelpers->GetMaxClients())
   12.33 +			{
   12.34 +				IGamePlayer *player = playerhelpers->GetGamePlayer(index);
   12.35  				if ((data->decflags & VDECODE_FLAG_ALLOWNOTINGAME)
   12.36  					&& !player->IsConnected())
   12.37  				{
   12.38 @@ -403,44 +407,20 @@
   12.39  					pContext->ThrowNativeError("Client %d is not in game", param);
   12.40  					return Data_Fail;
   12.41  				}
   12.42 -				pEdict = player->GetEdict();
   12.43 +				pEntity = gamehelpers->ReferenceToEntity(param);
   12.44  			} else if (param == -1) {
   12.45  				if (data->decflags & VDECODE_FLAG_ALLOWNULL)
   12.46  				{
   12.47 -					pEdict = NULL;
   12.48 +					pEntity = NULL;
   12.49  				} else {
   12.50  					pContext->ThrowNativeError("NULL not allowed");
   12.51  					return Data_Fail;
   12.52  				}
   12.53 -			} else if (param == 0) {
   12.54 -				if (data->decflags & VDECODE_FLAG_ALLOWWORLD)
   12.55 -				{
   12.56 -					pEdict = PEntityOfEntIndex(0);
   12.57 -				} else {
   12.58 -					pContext->ThrowNativeError("World not allowed");
   12.59 -					return Data_Fail;
   12.60 -				}
   12.61  			} else {
   12.62  				pContext->ThrowNativeError("Entity index %d is not a valid client", param);
   12.63  				return Data_Fail;
   12.64  			}
   12.65 -			CBaseEntity *pEntity = NULL;
   12.66 -			if (pEdict)
   12.67 -			{
   12.68 -				IServerUnknown *pUnknown = pEdict->GetUnknown();
   12.69 -				if (!pUnknown)
   12.70 -				{
   12.71 -					pContext->ThrowNativeError("Entity %d is a not an IServerUnknown", param);
   12.72 -					return Data_Fail;
   12.73 -				}
   12.74 -				pEntity = pUnknown->GetBaseEntity();
   12.75 -				if (!pEntity)
   12.76 -				{
   12.77 -					pContext->ThrowNativeError("Entity %d is not a CBaseEntity", param);
   12.78 -					return Data_Fail;
   12.79 -				}
   12.80 -			}
   12.81 -
   12.82 +			
   12.83  			CBaseEntity **ebuf = (CBaseEntity **)buffer;
   12.84  			*ebuf = pEntity;
   12.85  
   12.86 @@ -448,16 +428,21 @@
   12.87  		}
   12.88  	case Valve_CBaseEntity:
   12.89  		{
   12.90 -			edict_t *pEdict;
   12.91 +			CBaseEntity *pEntity = NULL;
   12.92  			if (data->decflags & VDECODE_FLAG_BYREF)
   12.93  			{
   12.94  				cell_t *addr;
   12.95  				pContext->LocalToPhysAddr(param, &addr);
   12.96  				param = *addr;
   12.97  			}
   12.98 -			if (param >= 1 && param <= playerhelpers->GetMaxClients())
   12.99 +			int index = gamehelpers->ReferenceToIndex(param);
  12.100 +			if (index == INVALID_EHANDLE_INDEX && param != -1)
  12.101  			{
  12.102 -				IGamePlayer *player = playerhelpers->GetGamePlayer(param);
  12.103 +				return Data_Fail;
  12.104 +			}
  12.105 +			if (index >= 1 && index <= playerhelpers->GetMaxClients())
  12.106 +			{
  12.107 +				IGamePlayer *player = playerhelpers->GetGamePlayer(index);
  12.108  				if ((data->decflags & VDECODE_FLAG_ALLOWNOTINGAME)
  12.109  					&& !player->IsConnected())
  12.110  				{
  12.111 @@ -467,44 +452,28 @@
  12.112  					pContext->ThrowNativeError("Client %d is not in game", param);
  12.113  					return Data_Fail;
  12.114  				}
  12.115 -				pEdict = player->GetEdict();
  12.116 +				pEntity = gamehelpers->ReferenceToEntity(param);
  12.117  			} else if (param == -1) {
  12.118  				if (data->decflags & VDECODE_FLAG_ALLOWNULL)
  12.119  				{
  12.120 -					pEdict = NULL;
  12.121 +					pEntity = NULL;
  12.122  				} else {
  12.123  					pContext->ThrowNativeError("NULL not allowed");
  12.124  					return Data_Fail;
  12.125  				}
  12.126 -			} else if (param == 0) {
  12.127 +			} else if (index == 0) {
  12.128  				if (data->decflags & VDECODE_FLAG_ALLOWWORLD)
  12.129  				{
  12.130 -					pEdict = PEntityOfEntIndex(0);
  12.131 +					pEntity = gamehelpers->ReferenceToEntity(0);
  12.132  				} else {
  12.133  					pContext->ThrowNativeError("World not allowed");
  12.134  					return Data_Fail;
  12.135  				}
  12.136  			} else {
  12.137 -				pEdict = PEntityOfEntIndex(param);
  12.138 -				if (!pEdict || pEdict->IsFree())
  12.139 -				{
  12.140 -					pContext->ThrowNativeError("Entity %d is not valid or is freed", param);
  12.141 -					return Data_Fail;
  12.142 -				}
  12.143 -			}
  12.144 -			CBaseEntity *pEntity = NULL;
  12.145 -			if (pEdict)
  12.146 -			{
  12.147 -				IServerUnknown *pUnknown = pEdict->GetUnknown();
  12.148 -				if (!pUnknown)
  12.149 -				{
  12.150 -					pContext->ThrowNativeError("Entity %d is a not an IServerUnknown", param);
  12.151 -					return Data_Fail;
  12.152 -				}
  12.153 -				pEntity = pUnknown->GetBaseEntity();
  12.154 +				pEntity = gamehelpers->ReferenceToEntity(param);
  12.155  				if (!pEntity)
  12.156  				{
  12.157 -					pContext->ThrowNativeError("Entity %d is not a CBaseEntity", param);
  12.158 +					pContext->ThrowNativeError("Entity %d is not valid", param);
  12.159  					return Data_Fail;
  12.160  				}
  12.161  			}
    13.1 --- a/extensions/sdktools/vglobals.cpp	Thu Jul 09 17:51:12 2009 -0400
    13.2 +++ b/extensions/sdktools/vglobals.cpp	Fri Jul 24 12:34:31 2009 +1200
    13.3 @@ -34,54 +34,35 @@
    13.4  void **g_pGameRules = NULL;
    13.5  void *g_EntList = NULL;
    13.6  
    13.7 -#ifdef PLATFORM_WINDOWS
    13.8 +
    13.9  void InitializeValveGlobals()
   13.10  {
   13.11 -	char *addr = NULL;
   13.12 -	int offset;
   13.13 +	g_EntList = gamehelpers->GetGlobalEntityList();
   13.14  
   13.15 -	/* gEntList and/or g_pEntityList */
   13.16 -	if (!g_pGameConf->GetMemSig("LevelShutdown", (void **)&addr) || !addr)
   13.17 -	{
   13.18 -		return;
   13.19 -	}
   13.20 -	if (!g_pGameConf->GetOffset("gEntList", &offset) || !offset)
   13.21 -	{
   13.22 -		return;
   13.23 -	}
   13.24 -	g_EntList = *reinterpret_cast<void **>(addr + offset);
   13.25 +	char *addr;
   13.26  
   13.27 +#ifdef PLATFORM_WINDOWS
   13.28  	/* g_pGameRules */
   13.29  	if (!g_pGameConf->GetMemSig("CreateGameRulesObject", (void **)&addr) || !addr)
   13.30  	{
   13.31  		return;
   13.32  	}
   13.33 +
   13.34 +	int offset;
   13.35  	if (!g_pGameConf->GetOffset("g_pGameRules", &offset) || !offset)
   13.36  	{
   13.37  		return;
   13.38  	}
   13.39  	g_pGameRules = *reinterpret_cast<void ***>(addr + offset);
   13.40 -}
   13.41  #elif defined PLATFORM_LINUX
   13.42 -void InitializeValveGlobals()
   13.43 -{
   13.44 -	char *addr = NULL;
   13.45 -
   13.46 -	/* gEntList and/or g_pEntityList */
   13.47 -	if (!g_pGameConf->GetMemSig("gEntList", (void **)&addr) || !addr)
   13.48 -	{
   13.49 -		return;
   13.50 -	}
   13.51 -	g_EntList = reinterpret_cast<void *>(addr);
   13.52 -
   13.53  	/* g_pGameRules */
   13.54  	if (!g_pGameConf->GetMemSig("g_pGameRules", (void **)&addr) || !addr)
   13.55  	{
   13.56  		return;
   13.57  	}
   13.58  	g_pGameRules = reinterpret_cast<void **>(addr);
   13.59 +#endif
   13.60  }
   13.61 -#endif
   13.62  
   13.63  size_t UTIL_StringToSignature(const char *str, char buffer[], size_t maxlength)
   13.64  {
    14.1 --- a/extensions/sdktools/vhelpers.cpp	Thu Jul 09 17:51:12 2009 -0400
    14.2 +++ b/extensions/sdktools/vhelpers.cpp	Fri Jul 24 12:34:31 2009 +1200
    14.3 @@ -241,13 +241,8 @@
    14.4  		return -1;
    14.5  	}
    14.6  
    14.7 -	edict_t *pTarget = gameents->BaseEntityToEdict(tr.m_pEnt);
    14.8 -	if (pTarget == NULL)
    14.9 -	{
   14.10 -		return -1;
   14.11 -	}
   14.12 -
   14.13 -	int ent_index = IndexOfEdict(pTarget);
   14.14 +	int ent_ref = gamehelpers->EntityToBCompatRef(tr.m_pEnt);
   14.15 +	int ent_index = gamehelpers->ReferenceToIndex(ent_ref);
   14.16  
   14.17  	IGamePlayer *pTargetPlayer = playerhelpers->GetGamePlayer(ent_index);
   14.18  	if (pTargetPlayer != NULL && !pTargetPlayer->IsInGame())
   14.19 @@ -259,7 +254,7 @@
   14.20  		return -1;
   14.21  	}
   14.22  
   14.23 -	return ent_index;
   14.24 +	return ent_ref;
   14.25  }
   14.26  
   14.27  bool IsEyeAnglesSupported()
    15.1 --- a/extensions/sdktools/vnatives.cpp	Thu Jul 09 17:51:12 2009 -0400
    15.2 +++ b/extensions/sdktools/vnatives.cpp	Fri Jul 24 12:34:31 2009 +1200
    15.3 @@ -164,18 +164,7 @@
    15.4  	DECODE_VALVE_PARAM(3, vparams, 1);
    15.5  	FINISH_CALL_SIMPLE(&pEntity);
    15.6  
    15.7 -	if (pEntity == NULL)
    15.8 -	{
    15.9 -		return -1;
   15.10 -	}
   15.11 -
   15.12 -	edict_t *pEdict = gameents->BaseEntityToEdict(pEntity);
   15.13 -	if (!pEdict)
   15.14 -	{
   15.15 -		return -1;
   15.16 -	}
   15.17 -
   15.18 -	return IndexOfEdict(pEdict);
   15.19 +	return gamehelpers->EntityToBCompatRef(pEntity);
   15.20  }
   15.21  
   15.22  static cell_t GetPlayerWeaponSlot(IPluginContext *pContext, const cell_t *params)
   15.23 @@ -200,18 +189,7 @@
   15.24  	DECODE_VALVE_PARAM(2, vparams, 0);
   15.25  	FINISH_CALL_SIMPLE(&pEntity);
   15.26  
   15.27 -	if (pEntity == NULL)
   15.28 -	{
   15.29 -		return -1;
   15.30 -	}
   15.31 -
   15.32 -	edict_t *pEdict = gameents->BaseEntityToEdict(pEntity);
   15.33 -	if (!pEdict)
   15.34 -	{
   15.35 -		return -1;
   15.36 -	}
   15.37 -
   15.38 -	return IndexOfEdict(pEdict);
   15.39 +	return gamehelpers->EntityToBCompatRef(pEntity);
   15.40  }
   15.41  
   15.42  #if SOURCE_ENGINE != SE_DARKMESSIAH
   15.43 @@ -389,7 +367,7 @@
   15.44  		return pContext->ThrowNativeError("Client %d is not in game", params[1]);
   15.45  	}
   15.46  
   15.47 -	edict_t *pEdict = PEntityOfEntIndex(params[2]);
   15.48 +	edict_t *pEdict = PEntityOfEntIndex(gamehelpers->ReferenceToIndex(params[1]));
   15.49  	if (!pEdict || pEdict->IsFree())
   15.50  	{
   15.51  		return pContext->ThrowNativeError("Entity %d is not valid", params[2]);
   15.52 @@ -477,13 +455,12 @@
   15.53  	}
   15.54  
   15.55  	/* First check if the client is valid */
   15.56 -	int client = params[1];
   15.57 -	IGamePlayer *player = playerhelpers->GetGamePlayer(client);
   15.58 +	IGamePlayer *player = playerhelpers->GetGamePlayer(params[1]);
   15.59  	if (!player)
   15.60  	{
   15.61 -		return pContext->ThrowNativeError("Client %d is not valid", client);
   15.62 +		return pContext->ThrowNativeError("Client %d is not valid", params[1]);
   15.63  	} else if (!player->IsInGame()) {
   15.64 -		return pContext->ThrowNativeError("Client %d is not in game", client);
   15.65 +		return pContext->ThrowNativeError("Client %d is not in game", params[1]);
   15.66  	}
   15.67  
   15.68  	edict_t *pEdict = player->GetEdict();
   15.69 @@ -551,7 +528,7 @@
   15.70  			CellRecipientFilter rf;
   15.71  			rf.SetToReliable(true);
   15.72  			rf.Initialize(player_list, total_players);
   15.73 -			engsound->EmitSound(rf, client, CHAN_AUTO, sound_name, VOL_NORM, ATTN_NORM, 0, PITCH_NORM, &pos);
   15.74 +			engsound->EmitSound(rf, params[1], CHAN_AUTO, sound_name, VOL_NORM, ATTN_NORM, 0, PITCH_NORM, &pos);
   15.75  		}
   15.76  	}
   15.77  
   15.78 @@ -619,16 +596,15 @@
   15.79  
   15.80  static cell_t GetClientEyeAngles(IPluginContext *pContext, const cell_t *params)
   15.81  {
   15.82 -	int client = params[1];
   15.83 -	IGamePlayer *pPlayer = playerhelpers->GetGamePlayer(client);
   15.84 +	IGamePlayer *pPlayer = playerhelpers->GetGamePlayer(params[1]);
   15.85  
   15.86  	if (!pPlayer)
   15.87  	{
   15.88 -		return pContext->ThrowNativeError("Invalid client index %d", client);
   15.89 +		return pContext->ThrowNativeError("Invalid client index %d", params[1]);
   15.90  	}
   15.91  	else if (!pPlayer->IsInGame())
   15.92  	{
   15.93 -		return pContext->ThrowNativeError("Client %d is not in game", client);
   15.94 +		return pContext->ThrowNativeError("Client %d is not in game", params[1]);
   15.95  	}
   15.96  
   15.97  	edict_t *pEdict = pPlayer->GetEdict();
   15.98 @@ -678,18 +654,7 @@
   15.99  	DECODE_VALVE_PARAM(2, vparams, 1);
  15.100  	FINISH_CALL_SIMPLE(&pEntity);
  15.101  
  15.102 -	if (pEntity == NULL)
  15.103 -	{
  15.104 -		return -1;
  15.105 -	}
  15.106 -
  15.107 -	edict_t *pEdict = gameents->BaseEntityToEdict(pEntity);
  15.108 -	if (!pEdict)
  15.109 -	{
  15.110 -		return -1;
  15.111 -	}
  15.112 -
  15.113 -	return IndexOfEdict(pEdict);
  15.114 +	return gamehelpers->EntityToBCompatRef(pEntity);
  15.115  }
  15.116  
  15.117  #if SOURCE_ENGINE == SE_LEFT4DEAD
  15.118 @@ -718,18 +683,7 @@
  15.119  	*(bool *)(vptr + 8) = true;
  15.120  	FINISH_CALL_SIMPLE(&pEntity);
  15.121  
  15.122 -	if (pEntity == NULL)
  15.123 -	{
  15.124 -		return -1;
  15.125 -	}
  15.126 -
  15.127 -	edict_t *pEdict = gameents->BaseEntityToEdict(pEntity);
  15.128 -	if (!pEdict)
  15.129 -	{
  15.130 -		return -1;
  15.131 -	}
  15.132 -
  15.133 -	return IndexOfEdict(pEdict);
  15.134 +	return gamehelpers->EntityToBCompatRef(pEntity);
  15.135  }
  15.136  #else
  15.137  static cell_t CreateEntityByName(IPluginContext *pContext, const cell_t *params)
  15.138 @@ -755,18 +709,7 @@
  15.139  	DECODE_VALVE_PARAM(2, vparams, 1);
  15.140  	FINISH_CALL_SIMPLE(&pEntity);
  15.141  
  15.142 -	if (pEntity == NULL)
  15.143 -	{
  15.144 -		return -1;
  15.145 -	}
  15.146 -
  15.147 -	edict_t *pEdict = gameents->BaseEntityToEdict(pEntity);
  15.148 -	if (!pEdict)
  15.149 -	{
  15.150 -		return -1;
  15.151 -	}
  15.152 -
  15.153 -	return IndexOfEdict(pEdict);
  15.154 +	return gamehelpers->EntityToBCompatRef(pEntity);
  15.155  }
  15.156  #endif
  15.157  
  15.158 @@ -881,16 +824,15 @@
  15.159  
  15.160  static cell_t sm_GetClientAimTarget(IPluginContext *pContext, const cell_t *params)
  15.161  {
  15.162 -	int client = params[1];
  15.163 -	IGamePlayer *pPlayer = playerhelpers->GetGamePlayer(client);
  15.164 +	IGamePlayer *pPlayer = playerhelpers->GetGamePlayer(params[1]);
  15.165  
  15.166  	if (!pPlayer)
  15.167  	{
  15.168 -		return pContext->ThrowNativeError("Invalid client index %d", client);
  15.169 +		return pContext->ThrowNativeError("Invalid client index %d", params[1]);
  15.170  	}
  15.171  	else if (!pPlayer->IsInGame())
  15.172  	{
  15.173 -		return pContext->ThrowNativeError("Client %d is not in game", client);
  15.174 +		return pContext->ThrowNativeError("Client %d is not in game", params[1]);
  15.175  	}
  15.176  
  15.177  	return GetClientAimTarget(pPlayer->GetEdict(), params[2] ? true : false);
    16.1 --- a/extensions/sdktools/vsound.cpp	Thu Jul 09 17:51:12 2009 -0400
    16.2 +++ b/extensions/sdktools/vsound.cpp	Fri Jul 24 12:34:31 2009 +1200
    16.3 @@ -383,7 +383,7 @@
    16.4  	float vol, delay;
    16.5  	int pitch, flags, level;
    16.6  
    16.7 -	entity = params[3];
    16.8 +	entity = gamehelpers->ReferenceToIndex(params[3]);
    16.9  
   16.10  	cell_t *addr;
   16.11  	pContext->LocalToPhysAddr(params[2], &addr);
   16.12 @@ -436,7 +436,7 @@
   16.13  
   16.14  static cell_t StopSound(IPluginContext *pContext, const cell_t *params)
   16.15  {
   16.16 -	int entity = params[1];
   16.17 +	int entity = gamehelpers->ReferenceToIndex(params[1]);
   16.18  	int channel = params[2];
   16.19  
   16.20  	char *name;
   16.21 @@ -477,7 +477,7 @@
   16.22  	char *sample;
   16.23  	pContext->LocalToString(params[3], &sample);
   16.24  	
   16.25 -	int entity = params[4];
   16.26 +	int entity = gamehelpers->ReferenceToIndex(params[4]);
   16.27  	int channel = params[5];
   16.28  	int level = params[6];
   16.29  	int flags = params[7];
   16.30 @@ -648,7 +648,7 @@
   16.31  	crf.Initialize(addr, numClients);
   16.32  
   16.33  	int sentence = params[3];
   16.34 -	int entity = params[4];
   16.35 +	int entity = gamehelpers->ReferenceToIndex(params[4]);
   16.36  	int channel = params[5];
   16.37  	int level = params[6];
   16.38  	int flags = params[7];
    17.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    17.2 +++ b/gamedata/core.games/engine.darkm.txt	Fri Jul 24 12:34:31 2009 +1200
    17.3 @@ -0,0 +1,46 @@
    17.4 +/**
    17.5 + * Do not edit this file.  Any changes will be overwritten by the gamedata
    17.6 + * updater or by upgrading your SourceMod install.
    17.7 + *
    17.8 + * To override data in this file, create a subdirectory named "custom" and
    17.9 + * place your own gamedata file(s) inside of it.  Such files will be parsed
   17.10 + * after SM's own.
   17.11 + *
   17.12 + * For more information, see http://wiki.alliedmods.net/Gamedata_Updating_(SourceMod)
   17.13 + */
   17.14 +
   17.15 +"Games"
   17.16 +{
   17.17 +	/* CGlobalEntityList */
   17.18 +	"#default"
   17.19 +	{
   17.20 +		"#supported"
   17.21 +		{
   17.22 +			"game"		"!Might and Magic Multiplayer"
   17.23 +		}
   17.24 +		
   17.25 +		"Offsets"
   17.26 +		{
   17.27 +			/* Offset into LevelShutdown */
   17.28 +			"gEntList"
   17.29 +			{
   17.30 +				"windows"	"11"
   17.31 +			}
   17.32 +
   17.33 +			"EntInfo"
   17.34 +			{
   17.35 +				"windows"	"4"	
   17.36 +				"linux"		"4"
   17.37 +			}
   17.38 +		}
   17.39 +		
   17.40 +		"Signatures"
   17.41 +		{
   17.42 +			"LevelShutdown"
   17.43 +			{
   17.44 +				"library"	"server"
   17.45 +				"windows"	"\xE8\x2A\x2A\x2A\x2A\xE8\x2A\x2A\x2A\x2A\xB9\x2A\x2A\x2A\x2A\xE8\x2A\x2A\x2A\x2A\xE8"
   17.46 +			}
   17.47 +		}
   17.48 +	}
   17.49 +}
    18.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    18.2 +++ b/gamedata/core.games/engine.ep1.txt	Fri Jul 24 12:34:31 2009 +1200
    18.3 @@ -0,0 +1,62 @@
    18.4 +/**
    18.5 + * Do not edit this file.  Any changes will be overwritten by the gamedata
    18.6 + * updater or by upgrading your SourceMod install.
    18.7 + *
    18.8 + * To override data in this file, create a subdirectory named "custom" and
    18.9 + * place your own gamedata file(s) inside of it.  Such files will be parsed
   18.10 + * after SM's own.
   18.11 + *
   18.12 + * For more information, see http://wiki.alliedmods.net/Gamedata_Updating_(SourceMod)
   18.13 + */
   18.14 +
   18.15 +"Games"
   18.16 +{
   18.17 +	/* CGlobalEntityList */
   18.18 +	"#default"
   18.19 +	{
   18.20 +		"#supported"
   18.21 +		{
   18.22 +			"game"		"cstrike"
   18.23 +			"game"		"garrysmod"
   18.24 +			"game"		"hl2mp"
   18.25 +			"game"		"ship"
   18.26 +			"game"		"insurgency"
   18.27 +			"game"		"pvkii"
   18.28 +			"game"		"sourceforts"
   18.29 +			"game"		"FortressForever"
   18.30 +			"game"		"empires"
   18.31 +			"game"		"synergy"
   18.32 +			"game"		"hidden"
   18.33 +			"game"		"zombie_master"
   18.34 +		}
   18.35 +		
   18.36 +		"Offsets"
   18.37 +		{
   18.38 +			/* Offset into LevelShutdown */
   18.39 +			"gEntList"
   18.40 +			{
   18.41 +				"windows"	"11"
   18.42 +			}
   18.43 +
   18.44 +			"EntInfo"
   18.45 +			{
   18.46 +				"windows"	"4"	
   18.47 +				"linux"		"4"
   18.48 +			}
   18.49 +		}
   18.50 +		
   18.51 +		"Signatures"
   18.52 +		{
   18.53 +			"LevelShutdown"
   18.54 +			{
   18.55 +				"library"	"server"
   18.56 +				"windows"	"\xE8\x2A\x2A\x2A\x2A\xE8\x2A\x2A\x2A\x2A\xB9\x2A\x2A\x2A\x2A\xE8\x2A\x2A\x2A\x2A\xE8"
   18.57 +			}
   18.58 +			"gEntList"
   18.59 +			{
   18.60 +				"library"	"server"
   18.61 +				"linux"		"@gEntList"
   18.62 +			}
   18.63 +		}
   18.64 +	}
   18.65 +}
    19.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    19.2 +++ b/gamedata/core.games/engine.ep2.txt	Fri Jul 24 12:34:31 2009 +1200
    19.3 @@ -0,0 +1,54 @@
    19.4 +/**
    19.5 + * Do not edit this file.  Any changes will be overwritten by the gamedata
    19.6 + * updater or by upgrading your SourceMod install.
    19.7 + *
    19.8 + * To override data in this file, create a subdirectory named "custom" and
    19.9 + * place your own gamedata file(s) inside of it.  Such files will be parsed
   19.10 + * after SM's own.
   19.11 + *
   19.12 + * For more information, see http://wiki.alliedmods.net/Gamedata_Updating_(SourceMod)
   19.13 + */
   19.14 +
   19.15 +"Games"
   19.16 +{
   19.17 +	/* CGlobalEntityList */
   19.18 +	"#default"
   19.19 +	{
   19.20 +		"#supported"
   19.21 +		{
   19.22 +			"game"		"dod"
   19.23 +			"game"		"tf"
   19.24 +			"game"		"ageofchivalry"
   19.25 +			"game"		"ZPS"
   19.26 +		}
   19.27 +		
   19.28 +		"Offsets"
   19.29 +		{
   19.30 +			/* Offset into LevelShutdown */
   19.31 +			"gEntList"
   19.32 +			{
   19.33 +				"windows"	"11"
   19.34 +			}
   19.35 +
   19.36 +			"EntInfo"
   19.37 +			{
   19.38 +				"windows"	"4"	
   19.39 +				"linux"		"4"
   19.40 +			}
   19.41 +		}
   19.42 +		
   19.43 +		"Signatures"
   19.44 +		{
   19.45 +			"LevelShutdown"
   19.46 +			{
   19.47 +				"library"	"server"
   19.48 +				"windows"	"\xE8\x2A\x2A\x2A\x2A\xE8\x2A\x2A\x2A\x2A\xB9\x2A\x2A\x2A\x2A\xE8\x2A\x2A\x2A\x2A\xE8"
   19.49 +			}
   19.50 +			"gEntList"
   19.51 +			{
   19.52 +				"library"	"server"
   19.53 +				"linux"		"@gEntList"
   19.54 +			}
   19.55 +		}
   19.56 +	}
   19.57 +}
   19.58 \ No newline at end of file
    20.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    20.2 +++ b/gamedata/core.games/engine.l4d.txt	Fri Jul 24 12:34:31 2009 +1200
    20.3 @@ -0,0 +1,51 @@
    20.4 +/**
    20.5 + * Do not edit this file.  Any changes will be overwritten by the gamedata
    20.6 + * updater or by upgrading your SourceMod install.
    20.7 + *
    20.8 + * To override data in this file, create a subdirectory named "custom" and
    20.9 + * place your own gamedata file(s) inside of it.  Such files will be parsed
   20.10 + * after SM's own.
   20.11 + *
   20.12 + * For more information, see http://wiki.alliedmods.net/Gamedata_Updating_(SourceMod)
   20.13 + */
   20.14 +
   20.15 +"Games"
   20.16 +{
   20.17 +	/* CGlobalEntityList */
   20.18 +	"#default"
   20.19 +	{
   20.20 +		"#supported"
   20.21 +		{
   20.22 +			"game"		"left4dead"
   20.23 +		}
   20.24 +		
   20.25 +		"Offsets"
   20.26 +		{
   20.27 +			/* Offset into LevelShutdown */
   20.28 +			"gEntList"
   20.29 +			{
   20.30 +				"windows"	"11"
   20.31 +			}
   20.32 +
   20.33 +			"EntInfo"
   20.34 +			{
   20.35 +				"windows"	"4"	
   20.36 +				"linux"		"4"
   20.37 +			}
   20.38 +		}
   20.39 +		
   20.40 +		"Signatures"
   20.41 +		{
   20.42 +			"LevelShutdown"
   20.43 +			{
   20.44 +				"library"	"server"
   20.45 +				"windows"	"\xE8\x2A\x2A\x2A\x2A\xE8\x2A\x2A\x2A\x2A\xB9\x2A\x2A\x2A\x2A\xE8\x2A\x2A\x2A\x2A\xE8"
   20.46 +			}
   20.47 +			"gEntList"
   20.48 +			{
   20.49 +				"library"	"server"
   20.50 +				"linux"		"@gEntList"
   20.51 +			}
   20.52 +		}
   20.53 +	}
   20.54 +}
    21.1 --- a/gamedata/core.games/master.games.txt	Thu Jul 09 17:51:12 2009 -0400
    21.2 +++ b/gamedata/core.games/master.games.txt	Fri Jul 24 12:34:31 2009 +1200
    21.3 @@ -14,4 +14,25 @@
    21.4  	"common.games.txt"
    21.5  	{
    21.6  	}
    21.7 -}
    21.8 +
    21.9 +	"engine.l4d.txt"
   21.10 +	{
   21.11 +		"engine"	"left4dead"
   21.12 +	}
   21.13 +	
   21.14 +	"engine.ep2.txt"
   21.15 +	{
   21.16 +		"engine"	"orangebox"
   21.17 +	}
   21.18 +	
   21.19 +	"engine.ep1.txt"
   21.20 +	{
   21.21 +		"engine"	"original"
   21.22 +	}
   21.23 +	
   21.24 +	"engine.darkm.txt"
   21.25 +	{
   21.26 +		"engine"	"darkmessiah"
   21.27 +	}
   21.28 +
   21.29 +}
   21.30 \ No newline at end of file
    22.1 --- a/gamedata/sdktools.games/engine.darkm.txt	Thu Jul 09 17:51:12 2009 -0400
    22.2 +++ b/gamedata/sdktools.games/engine.darkm.txt	Fri Jul 24 12:34:31 2009 +1200
    22.3 @@ -105,24 +105,9 @@
    22.4  		{
    22.5  			"game"		"!Might and Magic Multiplayer"
    22.6  		}
    22.7 -		
    22.8 -		"Offsets"
    22.9 -		{
   22.10 -			/* Offset into LevelShutdown */
   22.11 -			"gEntList"
   22.12 -			{
   22.13 -				"windows"	"11"
   22.14 -			}
   22.15 -		}
   22.16 -		
   22.17 +				
   22.18  		"Signatures"
   22.19  		{
   22.20 -			"LevelShutdown"
   22.21 -			{
   22.22 -				"library"	"server"
   22.23 -				"windows"	"\xE8\x2A\x2A\x2A\x2A\xE8\x2A\x2A\x2A\x2A\xB9\x2A\x2A\x2A\x2A\xE8\x2A\x2A\x2A\x2A\xE8"
   22.24 -			}
   22.25 -
   22.26  			/* Functions in CGlobalEntityList */
   22.27  			"FindEntityByClassname"
   22.28  			{
   22.29 @@ -239,7 +224,7 @@
   22.30  			/**
   22.31  			 * CBaseClient::SetUserCVar(char  const*,char  const*);
   22.32  			 * Linux offset straight from VTable dump.
   22.33 -			 * Windows offset is crazy. Found the windows 'SetName' function using string "(%d)%-0.*s"
   22.34 +			 * Windows offset is crazy. Found the windows SetName function using string "(%d)%-0.*s"
   22.35  			 * Cross referenced back to the vtable and counted manually (SetUserCvar is 1 higher, offsets start from 1)
   22.36  			 */
   22.37  			"SetUserCvar"
    23.1 --- a/gamedata/sdktools.games/engine.ep1.txt	Thu Jul 09 17:51:12 2009 -0400
    23.2 +++ b/gamedata/sdktools.games/engine.ep1.txt	Fri Jul 24 12:34:31 2009 +1200
    23.3 @@ -139,28 +139,8 @@
    23.4  			"game"		"zombie_master"
    23.5  		}
    23.6  		
    23.7 -		"Offsets"
    23.8 -		{
    23.9 -			/* Offset into LevelShutdown */
   23.10 -			"gEntList"
   23.11 -			{
   23.12 -				"windows"	"11"
   23.13 -			}
   23.14 -		}
   23.15 -		
   23.16  		"Signatures"
   23.17 -		{
   23.18 -			"LevelShutdown"
   23.19 -			{
   23.20 -				"library"	"server"
   23.21 -				"windows"	"\xE8\x2A\x2A\x2A\x2A\xE8\x2A\x2A\x2A\x2A\xB9\x2A\x2A\x2A\x2A\xE8\x2A\x2A\x2A\x2A\xE8"
   23.22 -			}
   23.23 -			"gEntList"
   23.24 -			{
   23.25 -				"library"	"server"
   23.26 -				"linux"		"@gEntList"
   23.27 -			}
   23.28 -			
   23.29 +		{	
   23.30  			/* Functions in CGlobalEntityList */
   23.31  			"FindEntityByClassname"
   23.32  			{
   23.33 @@ -288,7 +268,7 @@
   23.34  			/**
   23.35  			 * CBaseClient::SetUserCVar(char  const*,char  const*);
   23.36  			 * Linux offset straight from VTable dump.
   23.37 -			 * Windows offset is crazy. Found the windows 'SetName' function using string "(%d)%-0.*s"
   23.38 +			 * Windows offset is crazy. Found the windows SetName function using string "(%d)%-0.*s"
   23.39  			 * Cross referenced back to the vtable and counted manually (SetUserCvar is 1 higher, offsets start from 1)
   23.40  			 */
   23.41  			"SetUserCvar"
    24.1 --- a/gamedata/sdktools.games/engine.ep2.txt	Thu Jul 09 17:51:12 2009 -0400
    24.2 +++ b/gamedata/sdktools.games/engine.ep2.txt	Fri Jul 24 12:34:31 2009 +1200
    24.3 @@ -100,28 +100,8 @@
    24.4  			"game"		"ZPS"
    24.5  		}
    24.6  		
    24.7 -		"Offsets"
    24.8 -		{
    24.9 -			/* Offset into LevelShutdown */
   24.10 -			"gEntList"
   24.11 -			{
   24.12 -				"windows"	"11"
   24.13 -			}
   24.14 -		}
   24.15 -		
   24.16  		"Signatures"
   24.17  		{
   24.18 -			"LevelShutdown"
   24.19 -			{
   24.20 -				"library"	"server"
   24.21 -				"windows"	"\xE8\x2A\x2A\x2A\x2A\xE8\x2A\x2A\x2A\x2A\xB9\x2A\x2A\x2A\x2A\xE8\x2A\x2A\x2A\x2A\xE8"
   24.22 -			}
   24.23 -			"gEntList"
   24.24 -			{
   24.25 -				"library"	"server"
   24.26 -				"linux"		"@gEntList"
   24.27 -			}
   24.28 -			
   24.29  			/* Functions in CGlobalEntityList */
   24.30  			"FindEntityByClassname"
   24.31  			{
   24.32 @@ -261,7 +241,7 @@
   24.33  			/**
   24.34  			 * CBaseClient::SetUserCVar(char  const*,char  const*);
   24.35  			 * Linux offset straight from VTable dump.
   24.36 -			 * Windows offset is crazy. Found the windows 'SetName' function using string "(%d)%-0.*s"
   24.37 +			 * Windows offset is crazy. Found the windows SetName function using string "(%d)%-0.*s"
   24.38  			 * Cross referenced back to the vtable and counted manually (SetUserCvar is 1 higher, offsets start from 1)
   24.39  			 */
   24.40  			"SetUserCvar"
    25.1 --- a/gamedata/sdktools.games/engine.l4d.txt	Thu Jul 09 17:51:12 2009 -0400
    25.2 +++ b/gamedata/sdktools.games/engine.l4d.txt	Fri Jul 24 12:34:31 2009 +1200
    25.3 @@ -101,29 +101,9 @@
    25.4  		{
    25.5  			"game"		"left4dead"
    25.6  		}
    25.7 -		
    25.8 -		"Offsets"
    25.9 -		{
   25.10 -			/* Offset into LevelShutdown */
   25.11 -			"gEntList"
   25.12 -			{
   25.13 -				"windows"	"11"
   25.14 -			}
   25.15 -		}
   25.16 -		
   25.17 +			
   25.18  		"Signatures"
   25.19  		{
   25.20 -			"LevelShutdown"
   25.21 -			{
   25.22 -				"library"	"server"
   25.23 -				"windows"	"\xE8\x2A\x2A\x2A\x2A\xE8\x2A\x2A\x2A\x2A\xB9\x2A\x2A\x2A\x2A\xE8\x2A\x2A\x2A\x2A\xE8"
   25.24 -			}
   25.25 -			"gEntList"
   25.26 -			{
   25.27 -				"library"	"server"
   25.28 -				"linux"		"@gEntList"
   25.29 -			}
   25.30 -			
   25.31  			/* Functions in CGlobalEntityList */
   25.32  			"FindEntityByClassname"
   25.33  			{
   25.34 @@ -258,7 +238,7 @@
   25.35  			/**
   25.36  			 * CBaseClient::SetUserCVar(char  const*,char  const*);
   25.37  			 * Linux offset straight from VTable dump.
   25.38 -			 * Windows offset is crazy. Found the windows 'SetName' function using string "(%d)%-0.*s"
   25.39 +			 * Windows offset is crazy. Found the windows SetName function using string "(%d)%-0.*s"
   25.40  			 * Cross referenced back to the vtable and counted manually (SetUserCvar is 1 higher, offsets start from 1)
   25.41  			 */
   25.42  			"SetUserCvar"
    26.1 --- a/plugins/include/halflife.inc	Thu Jul 09 17:51:12 2009 -0400
    26.2 +++ b/plugins/include/halflife.inc	Fri Jul 24 12:34:31 2009 +1200
    26.3 @@ -56,6 +56,8 @@
    26.4  	DialogType_AskConnect	/**< ask the client to connect to a specified IP */
    26.5  };
    26.6  
    26.7 +#define INVALID_ENT_REFERENCE 0xFFFFFFFF
    26.8 +
    26.9  /**
   26.10   * Logs a generic message to the HL2 logs.
   26.11   *
   26.12 @@ -544,3 +546,28 @@
   26.13  	CreateDialog(client, Kv, DialogType_AskConnect);
   26.14  	CloseHandle(Kv);
   26.15  }
   26.16 +
   26.17 +/**
   26.18 + * Converts an entity index into a serial encoded entity reference.
   26.19 + *
   26.20 + * @param entity		Entity index.
   26.21 + * @return				Entity reference.
   26.22 + */
   26.23 +native EntIndexToEntRef(entity);
   26.24 +
   26.25 +/**
   26.26 + * Retrieves the entity index from a reference.
   26.27 + *
   26.28 + * @param ref			Entity reference.
   26.29 + * @return				Entity index.
   26.30 + */
   26.31 +native EntRefToEntIndex(ref);
   26.32 +
   26.33 +/**
   26.34 + * Converts a reference into a backwards compatible version.
   26.35 + *
   26.36 + * @param ref			Entity reference.
   26.37 + * @return				Bcompat reference.
   26.38 + */
   26.39 +native MakeCompatEntRef(ref);
   26.40 +
    27.1 --- a/public/IGameHelpers.h	Thu Jul 09 17:51:12 2009 -0400
    27.2 +++ b/public/IGameHelpers.h	Fri Jul 24 12:34:31 2009 +1200
    27.3 @@ -193,6 +193,63 @@
    27.4  		 * @param buffer		Command buffer (does not auto \n terminate).
    27.5  		 */
    27.6  		virtual void ServerCommand(const char *buffer) =0;
    27.7 +
    27.8 +		/**
    27.9 +		 * @brief Looks up a reference and returns the CBasseEntity* it points to.
   27.10 +		 *
   27.11 +		 * @note Supports 'old style' simple indexes and does a serial confirmation check on references.
   27.12 +		 *
   27.13 +		 * @param entRef		Entity reference.
   27.14 +		 * @return				Entity pointer.
   27.15 +		 */
   27.16 +		virtual CBaseEntity *ReferenceToEntity(cell_t entRef) =0;
   27.17 +
   27.18 +		/**
   27.19 +		 * @brief Returns the entity reference for an entity.
   27.20 +		 *
   27.21 +		 * @param pEntity		Entity pointer.
   27.22 +		 * @return				Entity reference.
   27.23 +		 */
   27.24 +		virtual cell_t EntityToReference(CBaseEntity *pEntity) =0;
   27.25 +
   27.26 +		/**
   27.27 +		 * @brief Returns the entity reference for logical entities, or the index for networked entities.
   27.28 +		 *
   27.29 +		 * @param pEntity		Entity pointer.
   27.30 +		 * @return				Entity reference/index.
   27.31 +		 */
   27.32 +		virtual cell_t EntityToBCompatRef(CBaseEntity *pEntity) =0;
   27.33 +
   27.34 +		/**
   27.35 +		 * @brief Converts an entity index into an entity reference.
   27.36 +		 *
   27.37 +		 * @param entIndex		Entity index.
   27.38 +		 * @return				Entity reference.
   27.39 +		 */
   27.40 +		virtual cell_t IndexToReference(int entIndex) =0;
   27.41 +
   27.42 +		/**
   27.43 +		 * @brief Retrieves the entity index from a reference.
   27.44 +		 *
   27.45 +		 * @param entRef		Entity reference.
   27.46 +		 * @return				Entity index.
   27.47 +		 */
   27.48 +		virtual int ReferenceToIndex(cell_t entRef) =0;
   27.49 +
   27.50 +		/**
   27.51 +		 * @brief Converts a reference into a bcompat version (index for networked entities).
   27.52 +		 *
   27.53 +		 * @param entRef		Entity reference.
   27.54 +		 * @return				Entity reference/index.
   27.55 +		 */
   27.56 +		virtual cell_t ReferenceToBCompatRef(cell_t entRef) =0;
   27.57 +		
   27.58 +		/**
   27.59 +		 * @brief Returns the g_EntList pointer.
   27.60 +		 *
   27.61 +		 * @return				g_EntList pointer.
   27.62 +		 */
   27.63 +		virtual void *GetGlobalEntityList() =0;
   27.64  	};
   27.65  }
   27.66