Add support for nested datatables. (bug 5446, r=asherkin)

This commit is contained in:
Kyle Sanderson 2013-08-12 00:54:21 +01:00
parent 6af85409f1
commit b9cd424186
8 changed files with 269 additions and 165 deletions

View File

@ -115,7 +115,7 @@ CHalfLife2::~CHalfLife2()
{ {
if (h_iter->val.trie) if (h_iter->val.trie)
{ {
sm_trie_destroy(h_iter->val.trie); delete h_iter->val.trie;
h_iter->val.trie = NULL; h_iter->val.trie = NULL;
} }
} }
@ -343,16 +343,11 @@ bool UTIL_FindInSendTable(SendTable *pTable,
return false; return false;
} }
typedescription_t *UTIL_FindInDataMap(datamap_t *pMap, const char *name, bool *isNested) bool UTIL_FindDataMapInfo(datamap_t *pMap, const char *name, sm_datatable_info_t *pDataTable)
{ {
if (isNested)
{
*isNested = false;
}
while (pMap) while (pMap)
{ {
for (int i=0; i<pMap->dataNumFields; i++) for (int i = 0; i < pMap->dataNumFields; ++i)
{ {
if (pMap->dataDesc[i].fieldName == NULL) if (pMap->dataDesc[i].fieldName == NULL)
{ {
@ -360,32 +355,23 @@ typedescription_t *UTIL_FindInDataMap(datamap_t *pMap, const char *name, bool *i
} }
if (strcmp(name, pMap->dataDesc[i].fieldName) == 0) if (strcmp(name, pMap->dataDesc[i].fieldName) == 0)
{ {
return &(pMap->dataDesc[i]); pDataTable->prop = &(pMap->dataDesc[i]);
pDataTable->actual_offset = GetTypeDescOffs(pDataTable->prop);
return true;
} }
if (pMap->dataDesc[i].td) if (pMap->dataDesc[i].td == NULL || !UTIL_FindDataMapInfo(pMap->dataDesc[i].td, name, pDataTable))
{ {
if (isNested) continue;
{
*isNested = (UTIL_FindInDataMap(pMap->dataDesc[i].td, name, NULL) != NULL);
if (*isNested)
{
return NULL;
} else {
continue;
}
} else { // Use the old behaviour, we dont want to spring this on extensions - even if they're doing bad things.
typedescription_t *_td;
if ((_td=UTIL_FindInDataMap(pMap->dataDesc[i].td, name, NULL)) != NULL)
{
return _td;
}
}
} }
pDataTable->actual_offset += GetTypeDescOffs(&(pMap->dataDesc[i]));
return true;
} }
pMap = pMap->baseMap; pMap = pMap->baseMap;
} }
return NULL; return false;
} }
ServerClass *CHalfLife2::FindServerClass(const char *classname) ServerClass *CHalfLife2::FindServerClass(const char *classname)
@ -472,27 +458,44 @@ SendProp *CHalfLife2::FindInSendTable(const char *classname, const char *offset)
typedescription_t *CHalfLife2::FindInDataMap(datamap_t *pMap, const char *offset) typedescription_t *CHalfLife2::FindInDataMap(datamap_t *pMap, const char *offset)
{ {
return this->FindInDataMap(pMap, offset, NULL); sm_datatable_info_t dt_info;
if (!(this->FindDataMapInfo(pMap, offset, &dt_info)))
{
return NULL;
}
return dt_info.prop;
} }
typedescription_t *CHalfLife2::FindInDataMap(datamap_t *pMap, const char *offset, bool *isNested) bool CHalfLife2::FindDataMapInfo(datamap_t *pMap, const char *offset, sm_datatable_info_t *pDataTable)
{ {
typedescription_t *td = NULL;
DataMapTrie &val = m_Maps[pMap]; DataMapTrie &val = m_Maps[pMap];
if (!val.trie) if (!val.trie)
{ {
val.trie = sm_trie_create(); val.trie = new KTrie<sm_datatable_info_t>;
} }
if (!sm_trie_retrieve(val.trie, offset, (void **)&td))
sm_datatable_info_t * pNewTable = val.trie->retrieve(offset);
if (!pNewTable)
{ {
if ((td = UTIL_FindInDataMap(pMap, offset, isNested)) != NULL) if (UTIL_FindDataMapInfo(pMap, offset, pDataTable))
{ {
sm_trie_insert(val.trie, offset, td); val.trie->insert(offset, *pDataTable);
}
else
{
pDataTable->prop = NULL;
} }
} }
else
{
*pDataTable = *pNewTable;
}
return td; return (pDataTable->prop != NULL);
} }
void CHalfLife2::SetEdictStateChanged(edict_t *pEdict, unsigned short offset) void CHalfLife2::SetEdictStateChanged(edict_t *pEdict, unsigned short offset)
@ -1221,8 +1224,14 @@ const char *CHalfLife2::GetEntityClassname(CBaseEntity *pEntity)
{ {
CBaseEntity *pGetterEnt = ReferenceToEntity(0); CBaseEntity *pGetterEnt = ReferenceToEntity(0);
datamap_t *pMap = GetDataMap(pGetterEnt); datamap_t *pMap = GetDataMap(pGetterEnt);
typedescription_t *pDesc = FindInDataMap(pMap, "m_iClassname");
offset = GetTypeDescOffs(pDesc); sm_datatable_info_t info;
if (!FindDataMapInfo(pMap, "m_iClassname", &info))
{
return NULL;
}
offset = info.actual_offset;
} }
return *(const char **)(((unsigned char *)pEntity) + offset); return *(const char **)(((unsigned char *)pEntity) + offset);

View File

@ -66,7 +66,7 @@ struct DataTableInfo
struct DataMapTrie struct DataMapTrie
{ {
DataMapTrie() : trie(NULL) {} DataMapTrie() : trie(NULL) {}
Trie *trie; KTrie<sm_datatable_info_t> *trie;
}; };
struct DelayedFakeCliCmd struct DelayedFakeCliCmd
@ -123,7 +123,7 @@ public: //IGameHelpers
datamap_t *GetDataMap(CBaseEntity *pEntity); datamap_t *GetDataMap(CBaseEntity *pEntity);
ServerClass *FindServerClass(const char *classname); ServerClass *FindServerClass(const char *classname);
typedescription_t *FindInDataMap(datamap_t *pMap, const char *offset); typedescription_t *FindInDataMap(datamap_t *pMap, const char *offset);
typedescription_t *FindInDataMap(datamap_t *pMap, const char *offset, bool *isNested); bool FindDataMapInfo(datamap_t *pMap, const char *offset, sm_datatable_info_t *pDataTable);
void SetEdictStateChanged(edict_t *pEdict, unsigned short offset); void SetEdictStateChanged(edict_t *pEdict, unsigned short offset);
bool TextMsg(int client, int dest, const char *msg); bool TextMsg(int client, int dest, const char *msg);
bool HintTextMsg(int client, const char *msg); bool HintTextMsg(int client, const char *msg);

View File

@ -796,6 +796,82 @@ static cell_t FindSendPropInfo(IPluginContext *pContext, const cell_t *params)
return info.actual_offset; return info.actual_offset;
} }
static void GuessDataPropTypes(typedescription_t *td, cell_t * pSize, cell_t * pType)
{
switch (td->fieldType)
{
case FIELD_TICK:
case FIELD_MODELINDEX:
case FIELD_MATERIALINDEX:
case FIELD_INTEGER:
case FIELD_COLOR32:
{
*pType = PropField_Integer;
*pSize = 32;
break;
}
case FIELD_VECTOR:
case FIELD_POSITION_VECTOR:
{
*pType = PropField_Vector;
*pSize = 12;
break;
}
case FIELD_SHORT:
{
*pType = PropField_Integer;
*pSize = 16;
break;
}
case FIELD_BOOLEAN:
{
*pType = PropField_Integer;
*pSize = 1;
break;
}
case FIELD_CHARACTER:
{
if (td->fieldSize == 1)
{
*pType = PropField_Integer;
*pSize = 8;
}
else
{
*pType = PropField_String;
*pSize = 8 * td->fieldSize;
}
break;
}
case FIELD_MODELNAME:
case FIELD_SOUNDNAME:
case FIELD_STRING:
{
*pSize = sizeof(string_t);
*pType = PropField_String_T;
break;
}
case FIELD_FLOAT:
case FIELD_TIME:
{
*pType = PropField_Float;
*pSize = 32;
break;
}
case FIELD_EHANDLE:
{
*pType = PropField_Entity;
*pSize = 32;
break;
}
default:
{
*pType = PropField_Unsupported;
*pSize = 0;
}
}
}
static cell_t FindDataMapOffs(IPluginContext *pContext, const cell_t *params) static cell_t FindDataMapOffs(IPluginContext *pContext, const cell_t *params)
{ {
CBaseEntity *pEntity; CBaseEntity *pEntity;
@ -815,14 +891,13 @@ static cell_t FindDataMapOffs(IPluginContext *pContext, const cell_t *params)
} }
pContext->LocalToString(params[2], &offset); pContext->LocalToString(params[2], &offset);
bool isNested = false; sm_datatable_info_t info;
if ((td=g_HL2.FindInDataMap(pMap, offset, &isNested)) == NULL) if (!g_HL2.FindDataMapInfo(pMap, offset, &info))
{ {
if (isNested) return -1;
return pContext->ThrowNativeError("Property \"%s\" is not safe to access for entity %d", offset, params[1]);
else
return -1;
} }
td = info.prop;
if (params[0] == 4) if (params[0] == 4)
{ {
@ -830,84 +905,62 @@ static cell_t FindDataMapOffs(IPluginContext *pContext, const cell_t *params)
pContext->LocalToPhysAddr(params[3], &pType); pContext->LocalToPhysAddr(params[3], &pType);
pContext->LocalToPhysAddr(params[4], &pSize); pContext->LocalToPhysAddr(params[4], &pSize);
switch (td->fieldType) GuessDataPropTypes(td, pSize, pType);
{
case FIELD_TICK:
case FIELD_MODELINDEX:
case FIELD_MATERIALINDEX:
case FIELD_INTEGER:
case FIELD_COLOR32:
{
*pType = PropField_Integer;
*pSize = 32;
break;
}
case FIELD_VECTOR:
case FIELD_POSITION_VECTOR:
{
*pType = PropField_Vector;
*pSize = 12;
break;
}
case FIELD_SHORT:
{
*pType = PropField_Integer;
*pSize = 16;
break;
}
case FIELD_BOOLEAN:
{
*pType = PropField_Integer;
*pSize = 1;
break;
}
case FIELD_CHARACTER:
{
if (td->fieldSize == 1)
{
*pType = PropField_Integer;
*pSize = 8;
}
else
{
*pType = PropField_String;
*pSize = 8 * td->fieldSize;
}
break;
}
case FIELD_MODELNAME:
case FIELD_SOUNDNAME:
case FIELD_STRING:
{
*pSize = sizeof(string_t);
*pType = PropField_String_T;
break;
}
case FIELD_FLOAT:
case FIELD_TIME:
{
*pType = PropField_Float;
*pSize = 32;
break;
}
case FIELD_EHANDLE:
{
*pType = PropField_Entity;
*pSize = 32;
break;
}
default:
{
*pType = PropField_Unsupported;
*pSize = 0;
}
}
} }
return GetTypeDescOffs(td); return GetTypeDescOffs(td);
} }
static cell_t FindDataMapInfo(IPluginContext *pContext, const cell_t *params)
{
CBaseEntity *pEntity;
datamap_t *pMap;
typedescription_t *td;
char *offset;
pEntity = GetEntity(params[1]);
if (!pEntity)
{
return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
}
if ((pMap=CBaseEntity_GetDataDescMap(pEntity)) == NULL)
{
return pContext->ThrowNativeError("Unable to retrieve GetDataDescMap offset");
}
pContext->LocalToString(params[2], &offset);
sm_datatable_info_t info;
if (!g_HL2.FindDataMapInfo(pMap, offset, &info))
{
return -1;
}
td = info.prop;
if (params[0] >= 4)
{
cell_t *pType, *pSize;
pContext->LocalToPhysAddr(params[3], &pType);
pContext->LocalToPhysAddr(params[4], &pSize);
GuessDataPropTypes(td, pSize, pType);
if (params[0] == 5)
{
cell_t *pLocalOffs;
pContext->LocalToPhysAddr(params[5], &pLocalOffs);
*pLocalOffs = GetTypeDescOffs(info.prop);
}
}
return info.actual_offset;
}
static cell_t GetEntDataString(IPluginContext *pContext, const cell_t *params) static cell_t GetEntDataString(IPluginContext *pContext, const cell_t *params)
{ {
CBaseEntity *pEntity = GetEntity(params[1]); CBaseEntity *pEntity = GetEntity(params[1]);
@ -966,23 +1019,16 @@ static cell_t SetEntDataString(IPluginContext *pContext, const cell_t *params)
{ \ { \
return pContext->ThrowNativeError("Could not retrieve datamap"); \ return pContext->ThrowNativeError("Could not retrieve datamap"); \
} \ } \
bool isNested = false; \ sm_datatable_info_t info; \
if ((td = g_HL2.FindInDataMap(pMap, prop, &isNested)) == NULL) \ if (!g_HL2.FindDataMapInfo(pMap, prop, &info)) \
{ \ { \
const char *class_name = g_HL2.GetEntityClassname(pEntity); \ const char *class_name = g_HL2.GetEntityClassname(pEntity); \
if (isNested) \ return pContext->ThrowNativeError("Property \"%s\" not found (entity %d/%s)", \
{ \ prop, \
return pContext->ThrowNativeError("Property \"%s\" not safe to access (entity %d/%s)", \ params[1], \
prop, \ ((class_name) ? class_name : "")); \
params[1], \ } \
((class_name) ? class_name : "")); \ td = info.prop;
} else { \
return pContext->ThrowNativeError("Property \"%s\" not found (entity %d/%s)", \
prop, \
params[1], \
((class_name) ? class_name : "")); \
} \
}
#define CHECK_SET_PROP_DATA_OFFSET() \ #define CHECK_SET_PROP_DATA_OFFSET() \
if (element < 0 || element >= td->fieldSize) \ if (element < 0 || element >= td->fieldSize) \
@ -993,7 +1039,7 @@ static cell_t SetEntDataString(IPluginContext *pContext, const cell_t *params)
td->fieldSize); \ td->fieldSize); \
} \ } \
\ \
offset = GetTypeDescOffs(td) + (element * (td->fieldSizeInBytes / td->fieldSize)); offset = info.actual_offset + (element * (td->fieldSizeInBytes / td->fieldSize));
#define FIND_PROP_SEND(type, type_name) \ #define FIND_PROP_SEND(type, type_name) \
sm_sendprop_info_t info;\ sm_sendprop_info_t info;\
@ -1808,7 +1854,7 @@ static cell_t GetEntPropString(IPluginContext *pContext, const cell_t *params)
element); element);
} }
offset = GetTypeDescOffs(td); offset = info.actual_offset;
if (bIsStringIndex) if (bIsStringIndex)
{ {
offset += (element * (td->fieldSizeInBytes / td->fieldSize)); offset += (element * (td->fieldSizeInBytes / td->fieldSize));
@ -1896,25 +1942,23 @@ static cell_t SetEntPropString(IPluginContext *pContext, const cell_t *params)
case Prop_Data: case Prop_Data:
{ {
datamap_t *pMap; datamap_t *pMap;
typedescription_t *td;
if ((pMap=CBaseEntity_GetDataDescMap(pEntity)) == NULL) if ((pMap=CBaseEntity_GetDataDescMap(pEntity)) == NULL)
{ {
return pContext->ThrowNativeError("Unable to retrieve GetDataDescMap offset"); return pContext->ThrowNativeError("Unable to retrieve GetDataDescMap offset");
} }
pContext->LocalToString(params[3], &prop); pContext->LocalToString(params[3], &prop);
bool isNested = false; sm_datatable_info_t info;
if ((td=g_HL2.FindInDataMap(pMap, prop, &isNested)) == NULL) if (!g_HL2.FindDataMapInfo(pMap, prop, &info))
{ {
if (isNested) return pContext->ThrowNativeError("Property \"%s\" not found for entity %d", prop, params[1]);
return pContext->ThrowNativeError("Property \"%s\" is not safe to access for entity %d", prop, params[1]);
else
return pContext->ThrowNativeError("Property \"%s\" not found for entity %d", prop, params[1]);
} }
typedescription_t *td = info.prop;
if (td->fieldType != FIELD_CHARACTER) if (td->fieldType != FIELD_CHARACTER)
{ {
return pContext->ThrowNativeError("Property \"%s\" is not a valid string", prop); return pContext->ThrowNativeError("Property \"%s\" is not a valid string", prop);
} }
offset = GetTypeDescOffs(td); offset = info.actual_offset;
maxlen = td->fieldSize; maxlen = td->fieldSize;
break; break;
} }
@ -2138,14 +2182,16 @@ static cell_t GetEntityFlags(IPluginContext *pContext, const cell_t *params)
{ {
return pContext->ThrowNativeError("Could not retrieve datamap"); return pContext->ThrowNativeError("Could not retrieve datamap");
} }
if ((td = g_HL2.FindInDataMap(pMap, prop)) == NULL)
sm_datatable_info_t info;
if (!g_HL2.FindDataMapInfo(pMap, prop, &info))
{ {
return pContext->ThrowNativeError("Property \"%s\" not found (entity %d)", return pContext->ThrowNativeError("Property \"%s\" not found (entity %d)",
prop, prop,
params[1]); params[1]);
} }
int offset = GetTypeDescOffs(td); int offset = info.actual_offset;
int32_t actual_flags = *(int32_t *)((uint8_t *)pEntity + offset); int32_t actual_flags = *(int32_t *)((uint8_t *)pEntity + offset);
int32_t sm_flags = 0; int32_t sm_flags = 0;
@ -2176,21 +2222,22 @@ static cell_t SetEntityFlags(IPluginContext *pContext, const cell_t *params)
return pContext->ThrowNativeError("Could not find m_fFlags prop in gamedata"); return pContext->ThrowNativeError("Could not find m_fFlags prop in gamedata");
} }
typedescription_t *td;
datamap_t *pMap; datamap_t *pMap;
if ((pMap = CBaseEntity_GetDataDescMap(pEntity)) == NULL) if ((pMap = CBaseEntity_GetDataDescMap(pEntity)) == NULL)
{ {
return pContext->ThrowNativeError("Could not retrieve datamap"); return pContext->ThrowNativeError("Could not retrieve datamap");
} }
if ((td = g_HL2.FindInDataMap(pMap, prop)) == NULL)
sm_datatable_info_t info;
if (!g_HL2.FindDataMapInfo(pMap, prop, &info))
{ {
return pContext->ThrowNativeError("Property \"%s\" not found (entity %d)", return pContext->ThrowNativeError("Property \"%s\" not found (entity %d)",
prop, prop,
params[1]); params[1]);
} }
int offset = GetTypeDescOffs(td); int offset = info.actual_offset;
int32_t sm_flags = params[2]; int32_t sm_flags = params[2];
int32_t actual_flags = 0; int32_t actual_flags = 0;
@ -2262,5 +2309,6 @@ REGISTER_NATIVES(entityNatives)
{"SetEntPropString", SetEntPropString}, {"SetEntPropString", SetEntPropString},
{"SetEntPropVector", SetEntPropVector}, {"SetEntPropVector", SetEntPropVector},
{"GetEntityAddress", GetEntityAddress}, {"GetEntityAddress", GetEntityAddress},
{"FindDataMapInfo", FindDataMapInfo},
{NULL, NULL} {NULL, NULL}
}; };

View File

@ -356,8 +356,13 @@ const char *EntityOutputManager::GetEntityClassname(CBaseEntity *pEntity)
if (offset == -1) if (offset == -1)
{ {
datamap_t *pMap = gamehelpers->GetDataMap(pEntity); datamap_t *pMap = gamehelpers->GetDataMap(pEntity);
typedescription_t *pDesc = gamehelpers->FindInDataMap(pMap, "m_iClassname"); sm_datatable_info_t info;
offset = GetTypeDescOffs(pDesc); if (!gamehelpers->FindDataMapInfo(pMap, "m_iClassname", &info))
{
return NULL;
}
offset = info.actual_offset;
} }
return *(const char **)(((unsigned char *)pEntity) + offset); return *(const char **)(((unsigned char *)pEntity) + offset);

View File

@ -585,14 +585,17 @@ CON_COMMAND(sm_dump_classes, "Dumps the class list as a text file")
fprintf(fp, "// Dump of all classes for \"%s\" as at %s\n//\n\n", g_pSM->GetGameFolderName(), buffer); fprintf(fp, "// Dump of all classes for \"%s\" as at %s\n//\n\n", g_pSM->GetGameFolderName(), buffer);
sm_datatable_info_t info;
for ( int i = dict->m_Factories.First(); i != dict->m_Factories.InvalidIndex(); i = dict->m_Factories.Next( i ) ) for ( int i = dict->m_Factories.First(); i != dict->m_Factories.InvalidIndex(); i = dict->m_Factories.Next( i ) )
{ {
IServerNetworkable *entity = dict->Create(dict->m_Factories.GetElementName(i)); IServerNetworkable *entity = dict->Create(dict->m_Factories.GetElementName(i));
ServerClass *sclass = entity->GetServerClass(); ServerClass *sclass = entity->GetServerClass();
fprintf(fp,"%s - %s\n",sclass->GetName(), dict->m_Factories.GetElementName(i)); fprintf(fp,"%s - %s\n",sclass->GetName(), dict->m_Factories.GetElementName(i));
typedescription_t *datamap = gamehelpers->FindInDataMap(gamehelpers->GetDataMap(entity->GetBaseEntity()), "m_iEFlags"); if (!gamehelpers->FindDataMapInfo(gamehelpers->GetDataMap(entity->GetBaseEntity()), "m_iEFlags", &info))
int *eflags = (int *)((char *)entity->GetBaseEntity() + GetTypeDescOffs(datamap)); continue;
int *eflags = (int *)((char *)entity->GetBaseEntity() + info.actual_offset);
*eflags |= (1<<0); // EFL_KILLME *eflags |= (1<<0); // EFL_KILLME
} }
@ -819,14 +822,13 @@ CON_COMMAND(sm_dump_datamaps, "Dumps the data map list as a text file")
if (offsEFlags == -1) if (offsEFlags == -1)
{ {
typedescription_t *datamap = gamehelpers->FindInDataMap(pMap, "m_iEFlags"); sm_datatable_info_t info;
if (!gamehelpers->FindDataMapInfo(pMap, "m_iEFlags", &info))
if (!datamap)
{ {
continue; continue;
} }
offsEFlags = GetTypeDescOffs(datamap); offsEFlags = info.actual_offset;
} }
int *eflags = (int *)((char *)entity->GetBaseEntity() + offsEFlags); int *eflags = (int *)((char *)entity->GetBaseEntity() + offsEFlags);

View File

@ -548,10 +548,10 @@ static cell_t SlapPlayer(IPluginContext *pContext, const cell_t *params)
if (frag_prop) if (frag_prop)
{ {
datamap_t *pMap = gamehelpers->GetDataMap(pEntity); datamap_t *pMap = gamehelpers->GetDataMap(pEntity);
typedescription_t *pType = gamehelpers->FindInDataMap(pMap, frag_prop); sm_datatable_info_t info;
if (pType != NULL) if (gamehelpers->FindDataMapInfo(pMap, frag_prop, &info))
{ {
s_frag_offs = GetTypeDescOffs(pType); s_frag_offs = info.actual_offset;
} }
} }
if (!s_frag_offs) if (!s_frag_offs)
@ -684,10 +684,13 @@ static cell_t NativeFindEntityByClassname(IPluginContext *pContext, const cell_t
static int offset = -1; static int offset = -1;
if (offset == -1) if (offset == -1)
{ {
offset = GetTypeDescOffs( sm_datatable_info_t info;
gamehelpers->FindInDataMap(gamehelpers->GetDataMap(pEntity), if (!gamehelpers->FindDataMapInfo(gamehelpers->GetDataMap(pEntity), "m_iClassname", &info))
"m_iClassname") {
); return -1;
}
offset = info.actual_offset;
} }
string_t s; string_t s;

View File

@ -449,6 +449,26 @@ native FindDataMapOffs(entity,
const String:prop[], const String:prop[],
&PropFieldType:type=PropFieldType:0, &PropFieldType:type=PropFieldType:0,
&num_bits=0); &num_bits=0);
/**
* Given an entity, finds a nested datamap property offset.
* This information is cached for future calls.
*
* @param entity Entity index.
* @param prop Property name.
* @param type Optional parameter to store the type.
* @param num_bits Optional parameter to store the number of bits the field
* uses. The bit count will either be 1 (for boolean) or
* divisible by 8 (including 0 if unknown).
* @param local_offset Optional parameter to store the local offset, as
* FindDataMapOffs() would return.
* @return An offset, or -1 on failure.
*/
native FindDataMapInfo(entity,
const String:prop[],
&PropFieldType:type=PropFieldType:0,
&num_bits=0,
&local_offset=0);
/** /**
* Wrapper function for finding a send property for a particular entity. * Wrapper function for finding a send property for a particular entity.

View File

@ -40,7 +40,7 @@
*/ */
#define SMINTERFACE_GAMEHELPERS_NAME "IGameHelpers" #define SMINTERFACE_GAMEHELPERS_NAME "IGameHelpers"
#define SMINTERFACE_GAMEHELPERS_VERSION 9 #define SMINTERFACE_GAMEHELPERS_VERSION 10
class CBaseEntity; class CBaseEntity;
class CBaseHandle; class CBaseHandle;
@ -66,6 +66,12 @@ namespace SourceMod
SendProp *prop; /**< Property instance. */ SendProp *prop; /**< Property instance. */
unsigned int actual_offset; /**< Actual computed offset. */ unsigned int actual_offset; /**< Actual computed offset. */
}; };
struct sm_datatable_info_t
{
typedescription_t *prop; /**< Property instance. */
unsigned int actual_offset; /**< Actual computed offset. */
};
class IGameHelpers : public SMInterface class IGameHelpers : public SMInterface
{ {
@ -318,6 +324,17 @@ namespace SourceMod
* @return True if valid, otherwise false. * @return True if valid, otherwise false.
*/ */
virtual bool IsMapValid(const char *map) =0; virtual bool IsMapValid(const char *map) =0;
/**
* @brief Finds a datamap_t definition.
*
* @param pMap datamap_t pointer.
* @param offset Property name.
* @param pDataTable Buffer to store sm_datatable_info_t data.
* @return typedescription_t pointer on success, NULL
* on failure.
*/
virtual bool FindDataMapInfo(datamap_t *pMap, const char *offset, sm_datatable_info_t *pDataTable) =0;
}; };
} }