Sped up native impl. of FindEntityByClassname (bug 4963, r=fyren).
authorNicholas Hastings <skamonkey@gmail.com>
Tue Jul 12 19:48:28 2011 -0400 (2011-07-12)
changeset 3352dba1e38e2024
parent 3350 4e7c8ee5bc0e
child 3353 c73d0ba1110b
Sped up native impl. of FindEntityByClassname (bug 4963, r=fyren).
extensions/sdktools/vnatives.cpp
     1.1 --- a/extensions/sdktools/vnatives.cpp	Fri Jul 08 07:55:20 2011 -0400
     1.2 +++ b/extensions/sdktools/vnatives.cpp	Tue Jul 12 19:48:28 2011 -0400
     1.3 @@ -40,7 +40,6 @@
     1.4  #include <inetchannel.h>
     1.5  #include <iclient.h>
     1.6  #include "iserver.h"
     1.7 -#include <iserverentity.h>
     1.8  
     1.9  SourceHook::List<ValveCall *> g_RegCalls;
    1.10  SourceHook::List<ICallWrapper *> g_CallWraps;
    1.11 @@ -632,7 +631,7 @@
    1.12  }
    1.13  
    1.14  #if SOURCE_ENGINE >= SE_ORANGEBOX
    1.15 -static cell_t FindEntityByClassname(IPluginContext *pContext, const cell_t *params)
    1.16 +static cell_t NativeFindEntityByClassname(IPluginContext *pContext, const cell_t *params)
    1.17  {
    1.18  	char *searchname;
    1.19  	CBaseEntity *pEntity;
    1.20 @@ -653,36 +652,48 @@
    1.21  		pEntity = (CBaseEntity *)servertools->NextEntity(pEntity);
    1.22  	}
    1.23  
    1.24 +	// it's tough to find a good ent these days
    1.25 +	if (!pEntity)
    1.26 +	{
    1.27 +		return -1;
    1.28 +	}
    1.29 +
    1.30  	pContext->LocalToString(params[2], &searchname);
    1.31  
    1.32 -	char buffer[128];
    1.33 -	const char *classname = buffer;
    1.34 -	int lastcharpos;
    1.35 -	bool ismatch = false;
    1.36 +	const char *classname;
    1.37 +	int lastletterpos;
    1.38 +
    1.39 +	static int offset = -1;
    1.40 +	if (offset == -1)
    1.41 +	{
    1.42 +		offset = GetTypeDescOffs(
    1.43 +			gamehelpers->FindInDataMap(gamehelpers->GetDataMap(pEntity),
    1.44 +			"m_iClassname")
    1.45 +			);
    1.46 +	}
    1.47 +
    1.48 +	string_t s;
    1.49  
    1.50  	while (pEntity)
    1.51  	{
    1.52 -		if (!servertools->GetKeyValue(pEntity, "classname", buffer, sizeof(buffer)))
    1.53 +		if ((s = *(string_t *)((uint8_t *)pEntity + offset)) == NULL_STRING)
    1.54  		{
    1.55  			pEntity = (CBaseEntity *)servertools->NextEntity(pEntity);
    1.56  			continue;
    1.57  		}
    1.58  
    1.59 -		lastcharpos = strlen(searchname);
    1.60 -		if (searchname[lastcharpos-1] == '*')
    1.61 +		classname = STRING(s);
    1.62 +
    1.63 +		lastletterpos = strlen(searchname) - 1;
    1.64 +		if (searchname[lastletterpos] == '*')
    1.65  		{
    1.66 -			if (strncasecmp(searchname, classname, lastcharpos-1) == 0)
    1.67 +			if (strncasecmp(searchname, classname, lastletterpos) == 0)
    1.68  			{
    1.69 -				ismatch = true;
    1.70 +				return gamehelpers->EntityToBCompatRef(pEntity);
    1.71  			}
    1.72  		}
    1.73  		else if (strcasecmp(searchname, classname) == 0)
    1.74  		{
    1.75 -			ismatch = true;
    1.76 -		}
    1.77 -
    1.78 -		if (ismatch)
    1.79 -		{
    1.80  			return gamehelpers->EntityToBCompatRef(pEntity);
    1.81  		}
    1.82  
    1.83 @@ -691,21 +702,48 @@
    1.84  
    1.85  	return -1;
    1.86  }
    1.87 -#else
    1.88 +#endif
    1.89 +
    1.90  static cell_t FindEntityByClassname(IPluginContext *pContext, const cell_t *params)
    1.91  {
    1.92  	static ValveCall *pCall = NULL;
    1.93 +	static bool bProbablyNoFEBC = false;
    1.94 +
    1.95 +#if SOURCE_ENGINE >= SE_ORANGEBOX
    1.96 +	if (bProbablyNoFEBC)
    1.97 +	{
    1.98 +		return NativeFindEntityByClassname(pContext, params);
    1.99 +	}
   1.100 +#endif
   1.101 +
   1.102  	if (!pCall)
   1.103  	{
   1.104  		ValvePassInfo pass[3];
   1.105  		InitPass(pass[0], Valve_CBaseEntity, PassType_Basic, PASSFLAG_BYVAL, VDECODE_FLAG_ALLOWNULL|VDECODE_FLAG_ALLOWWORLD);
   1.106  		InitPass(pass[1], Valve_String, PassType_Basic, PASSFLAG_BYVAL);
   1.107  		InitPass(pass[2], Valve_CBaseEntity, PassType_Basic, PASSFLAG_BYVAL);
   1.108 +
   1.109 +		char error[256];
   1.110 +		error[0] = '\0';
   1.111  		if (!CreateBaseCall("FindEntityByClassname", ValveCall_EntityList, &pass[2], pass, 2, &pCall))
   1.112  		{
   1.113 -			return pContext->ThrowNativeError("\"FindEntityByClassname\" not supported by this mod");
   1.114 +			g_pSM->Format(error, sizeof(error), "\"FindEntityByClassname\" not supported by this mod");
   1.115  		} else if (!pCall) {
   1.116 -			return pContext->ThrowNativeError("\"FindEntityByClassname\" wrapper failed to initialize");
   1.117 +			g_pSM->Format(error, sizeof(error), "\"FindEntityByClassname\" wrapper failed to initialize");
   1.118 +		}
   1.119 +
   1.120 +		if (error[0] != '\0')
   1.121 +		{
   1.122 +#if SOURCE_ENGINE >= SE_ORANGEBOX
   1.123 +			if (!bProbablyNoFEBC)
   1.124 +			{
   1.125 +				bProbablyNoFEBC = true;
   1.126 +				g_pSM->LogError(myself, "%s, falling back to IServerTools method.", error);
   1.127 +			}
   1.128 +			return NativeFindEntityByClassname(pContext, params);
   1.129 +#else
   1.130 +			return pContext->ThrowNativeError("%s", error);
   1.131 +#endif
   1.132  		}
   1.133  	}
   1.134  
   1.135 @@ -718,7 +756,6 @@
   1.136  
   1.137  	return gamehelpers->EntityToBCompatRef(pEntity);
   1.138  }
   1.139 -#endif
   1.140  
   1.141  #if SOURCE_ENGINE >= SE_ORANGEBOX
   1.142  static cell_t CreateEntityByName(IPluginContext *pContext, const cell_t *params)