Add support for nested datatables. (bug 5446, r=asherkin)
This commit is contained in:
parent
6af85409f1
commit
b9cd424186
@ -115,7 +115,7 @@ CHalfLife2::~CHalfLife2()
|
||||
{
|
||||
if (h_iter->val.trie)
|
||||
{
|
||||
sm_trie_destroy(h_iter->val.trie);
|
||||
delete h_iter->val.trie;
|
||||
h_iter->val.trie = NULL;
|
||||
}
|
||||
}
|
||||
@ -343,16 +343,11 @@ bool UTIL_FindInSendTable(SendTable *pTable,
|
||||
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)
|
||||
{
|
||||
for (int i=0; i<pMap->dataNumFields; i++)
|
||||
for (int i = 0; i < pMap->dataNumFields; ++i)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
*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;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
pDataTable->actual_offset += GetTypeDescOffs(&(pMap->dataDesc[i]));
|
||||
return true;
|
||||
}
|
||||
|
||||
pMap = pMap->baseMap;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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];
|
||||
|
||||
if (!val.trie)
|
||||
{
|
||||
val.trie = sm_trie_create();
|
||||
}
|
||||
if (!sm_trie_retrieve(val.trie, offset, (void **)&td))
|
||||
{
|
||||
if ((td = UTIL_FindInDataMap(pMap, offset, isNested)) != NULL)
|
||||
{
|
||||
sm_trie_insert(val.trie, offset, td);
|
||||
}
|
||||
val.trie = new KTrie<sm_datatable_info_t>;
|
||||
}
|
||||
|
||||
return td;
|
||||
sm_datatable_info_t * pNewTable = val.trie->retrieve(offset);
|
||||
|
||||
if (!pNewTable)
|
||||
{
|
||||
if (UTIL_FindDataMapInfo(pMap, offset, pDataTable))
|
||||
{
|
||||
val.trie->insert(offset, *pDataTable);
|
||||
}
|
||||
else
|
||||
{
|
||||
pDataTable->prop = NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
*pDataTable = *pNewTable;
|
||||
}
|
||||
|
||||
return (pDataTable->prop != NULL);
|
||||
}
|
||||
|
||||
void CHalfLife2::SetEdictStateChanged(edict_t *pEdict, unsigned short offset)
|
||||
@ -1221,8 +1224,14 @@ const char *CHalfLife2::GetEntityClassname(CBaseEntity *pEntity)
|
||||
{
|
||||
CBaseEntity *pGetterEnt = ReferenceToEntity(0);
|
||||
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);
|
||||
|
@ -66,7 +66,7 @@ struct DataTableInfo
|
||||
struct DataMapTrie
|
||||
{
|
||||
DataMapTrie() : trie(NULL) {}
|
||||
Trie *trie;
|
||||
KTrie<sm_datatable_info_t> *trie;
|
||||
};
|
||||
|
||||
struct DelayedFakeCliCmd
|
||||
@ -123,7 +123,7 @@ public: //IGameHelpers
|
||||
datamap_t *GetDataMap(CBaseEntity *pEntity);
|
||||
ServerClass *FindServerClass(const char *classname);
|
||||
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);
|
||||
bool TextMsg(int client, int dest, const char *msg);
|
||||
bool HintTextMsg(int client, const char *msg);
|
||||
|
@ -796,6 +796,82 @@ static cell_t FindSendPropInfo(IPluginContext *pContext, const cell_t *params)
|
||||
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)
|
||||
{
|
||||
CBaseEntity *pEntity;
|
||||
@ -815,15 +891,14 @@ static cell_t FindDataMapOffs(IPluginContext *pContext, const cell_t *params)
|
||||
}
|
||||
|
||||
pContext->LocalToString(params[2], &offset);
|
||||
bool isNested = false;
|
||||
if ((td=g_HL2.FindInDataMap(pMap, offset, &isNested)) == NULL)
|
||||
sm_datatable_info_t info;
|
||||
if (!g_HL2.FindDataMapInfo(pMap, offset, &info))
|
||||
{
|
||||
if (isNested)
|
||||
return pContext->ThrowNativeError("Property \"%s\" is not safe to access for entity %d", offset, params[1]);
|
||||
else
|
||||
return -1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
td = info.prop;
|
||||
|
||||
if (params[0] == 4)
|
||||
{
|
||||
cell_t *pType, *pSize;
|
||||
@ -831,83 +906,61 @@ static cell_t FindDataMapOffs(IPluginContext *pContext, const cell_t *params)
|
||||
pContext->LocalToPhysAddr(params[3], &pType);
|
||||
pContext->LocalToPhysAddr(params[4], &pSize);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
GuessDataPropTypes(td, pSize, pType);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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"); \
|
||||
} \
|
||||
bool isNested = false; \
|
||||
if ((td = g_HL2.FindInDataMap(pMap, prop, &isNested)) == NULL) \
|
||||
sm_datatable_info_t info; \
|
||||
if (!g_HL2.FindDataMapInfo(pMap, prop, &info)) \
|
||||
{ \
|
||||
const char *class_name = g_HL2.GetEntityClassname(pEntity); \
|
||||
if (isNested) \
|
||||
{ \
|
||||
return pContext->ThrowNativeError("Property \"%s\" not safe to access (entity %d/%s)", \
|
||||
prop, \
|
||||
params[1], \
|
||||
((class_name) ? class_name : "")); \
|
||||
} else { \
|
||||
return pContext->ThrowNativeError("Property \"%s\" not found (entity %d/%s)", \
|
||||
prop, \
|
||||
params[1], \
|
||||
((class_name) ? class_name : "")); \
|
||||
} \
|
||||
}
|
||||
return pContext->ThrowNativeError("Property \"%s\" not found (entity %d/%s)", \
|
||||
prop, \
|
||||
params[1], \
|
||||
((class_name) ? class_name : "")); \
|
||||
} \
|
||||
td = info.prop;
|
||||
|
||||
#define CHECK_SET_PROP_DATA_OFFSET() \
|
||||
if (element < 0 || element >= td->fieldSize) \
|
||||
@ -993,7 +1039,7 @@ static cell_t SetEntDataString(IPluginContext *pContext, const cell_t *params)
|
||||
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) \
|
||||
sm_sendprop_info_t info;\
|
||||
@ -1808,7 +1854,7 @@ static cell_t GetEntPropString(IPluginContext *pContext, const cell_t *params)
|
||||
element);
|
||||
}
|
||||
|
||||
offset = GetTypeDescOffs(td);
|
||||
offset = info.actual_offset;
|
||||
if (bIsStringIndex)
|
||||
{
|
||||
offset += (element * (td->fieldSizeInBytes / td->fieldSize));
|
||||
@ -1896,25 +1942,23 @@ static cell_t SetEntPropString(IPluginContext *pContext, const cell_t *params)
|
||||
case Prop_Data:
|
||||
{
|
||||
datamap_t *pMap;
|
||||
typedescription_t *td;
|
||||
if ((pMap=CBaseEntity_GetDataDescMap(pEntity)) == NULL)
|
||||
{
|
||||
return pContext->ThrowNativeError("Unable to retrieve GetDataDescMap offset");
|
||||
}
|
||||
pContext->LocalToString(params[3], &prop);
|
||||
bool isNested = false;
|
||||
if ((td=g_HL2.FindInDataMap(pMap, prop, &isNested)) == NULL)
|
||||
sm_datatable_info_t info;
|
||||
if (!g_HL2.FindDataMapInfo(pMap, prop, &info))
|
||||
{
|
||||
if (isNested)
|
||||
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]);
|
||||
return pContext->ThrowNativeError("Property \"%s\" not found for entity %d", prop, params[1]);
|
||||
}
|
||||
|
||||
typedescription_t *td = info.prop;
|
||||
if (td->fieldType != FIELD_CHARACTER)
|
||||
{
|
||||
return pContext->ThrowNativeError("Property \"%s\" is not a valid string", prop);
|
||||
}
|
||||
offset = GetTypeDescOffs(td);
|
||||
offset = info.actual_offset;
|
||||
maxlen = td->fieldSize;
|
||||
break;
|
||||
}
|
||||
@ -2138,14 +2182,16 @@ static cell_t GetEntityFlags(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
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)",
|
||||
prop,
|
||||
params[1]);
|
||||
}
|
||||
|
||||
int offset = GetTypeDescOffs(td);
|
||||
int offset = info.actual_offset;
|
||||
|
||||
int32_t actual_flags = *(int32_t *)((uint8_t *)pEntity + offset);
|
||||
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");
|
||||
}
|
||||
|
||||
typedescription_t *td;
|
||||
datamap_t *pMap;
|
||||
|
||||
if ((pMap = CBaseEntity_GetDataDescMap(pEntity)) == NULL)
|
||||
{
|
||||
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)",
|
||||
prop,
|
||||
params[1]);
|
||||
}
|
||||
|
||||
int offset = GetTypeDescOffs(td);
|
||||
int offset = info.actual_offset;
|
||||
|
||||
int32_t sm_flags = params[2];
|
||||
int32_t actual_flags = 0;
|
||||
@ -2262,5 +2309,6 @@ REGISTER_NATIVES(entityNatives)
|
||||
{"SetEntPropString", SetEntPropString},
|
||||
{"SetEntPropVector", SetEntPropVector},
|
||||
{"GetEntityAddress", GetEntityAddress},
|
||||
{"FindDataMapInfo", FindDataMapInfo},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
@ -356,8 +356,13 @@ const char *EntityOutputManager::GetEntityClassname(CBaseEntity *pEntity)
|
||||
if (offset == -1)
|
||||
{
|
||||
datamap_t *pMap = gamehelpers->GetDataMap(pEntity);
|
||||
typedescription_t *pDesc = gamehelpers->FindInDataMap(pMap, "m_iClassname");
|
||||
offset = GetTypeDescOffs(pDesc);
|
||||
sm_datatable_info_t info;
|
||||
if (!gamehelpers->FindDataMapInfo(pMap, "m_iClassname", &info))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
offset = info.actual_offset;
|
||||
}
|
||||
|
||||
return *(const char **)(((unsigned char *)pEntity) + offset);
|
||||
|
@ -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);
|
||||
|
||||
sm_datatable_info_t info;
|
||||
for ( int i = dict->m_Factories.First(); i != dict->m_Factories.InvalidIndex(); i = dict->m_Factories.Next( i ) )
|
||||
{
|
||||
IServerNetworkable *entity = dict->Create(dict->m_Factories.GetElementName(i));
|
||||
ServerClass *sclass = entity->GetServerClass();
|
||||
fprintf(fp,"%s - %s\n",sclass->GetName(), dict->m_Factories.GetElementName(i));
|
||||
|
||||
typedescription_t *datamap = gamehelpers->FindInDataMap(gamehelpers->GetDataMap(entity->GetBaseEntity()), "m_iEFlags");
|
||||
int *eflags = (int *)((char *)entity->GetBaseEntity() + GetTypeDescOffs(datamap));
|
||||
if (!gamehelpers->FindDataMapInfo(gamehelpers->GetDataMap(entity->GetBaseEntity()), "m_iEFlags", &info))
|
||||
continue;
|
||||
|
||||
int *eflags = (int *)((char *)entity->GetBaseEntity() + info.actual_offset);
|
||||
*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)
|
||||
{
|
||||
typedescription_t *datamap = gamehelpers->FindInDataMap(pMap, "m_iEFlags");
|
||||
|
||||
if (!datamap)
|
||||
sm_datatable_info_t info;
|
||||
if (!gamehelpers->FindDataMapInfo(pMap, "m_iEFlags", &info))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
offsEFlags = GetTypeDescOffs(datamap);
|
||||
offsEFlags = info.actual_offset;
|
||||
}
|
||||
|
||||
int *eflags = (int *)((char *)entity->GetBaseEntity() + offsEFlags);
|
||||
|
@ -548,10 +548,10 @@ static cell_t SlapPlayer(IPluginContext *pContext, const cell_t *params)
|
||||
if (frag_prop)
|
||||
{
|
||||
datamap_t *pMap = gamehelpers->GetDataMap(pEntity);
|
||||
typedescription_t *pType = gamehelpers->FindInDataMap(pMap, frag_prop);
|
||||
if (pType != NULL)
|
||||
sm_datatable_info_t info;
|
||||
if (gamehelpers->FindDataMapInfo(pMap, frag_prop, &info))
|
||||
{
|
||||
s_frag_offs = GetTypeDescOffs(pType);
|
||||
s_frag_offs = info.actual_offset;
|
||||
}
|
||||
}
|
||||
if (!s_frag_offs)
|
||||
@ -684,10 +684,13 @@ static cell_t NativeFindEntityByClassname(IPluginContext *pContext, const cell_t
|
||||
static int offset = -1;
|
||||
if (offset == -1)
|
||||
{
|
||||
offset = GetTypeDescOffs(
|
||||
gamehelpers->FindInDataMap(gamehelpers->GetDataMap(pEntity),
|
||||
"m_iClassname")
|
||||
);
|
||||
sm_datatable_info_t info;
|
||||
if (!gamehelpers->FindDataMapInfo(gamehelpers->GetDataMap(pEntity), "m_iClassname", &info))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
offset = info.actual_offset;
|
||||
}
|
||||
|
||||
string_t s;
|
||||
|
@ -450,6 +450,26 @@ native FindDataMapOffs(entity,
|
||||
&PropFieldType:type=PropFieldType: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.
|
||||
*
|
||||
|
@ -40,7 +40,7 @@
|
||||
*/
|
||||
|
||||
#define SMINTERFACE_GAMEHELPERS_NAME "IGameHelpers"
|
||||
#define SMINTERFACE_GAMEHELPERS_VERSION 9
|
||||
#define SMINTERFACE_GAMEHELPERS_VERSION 10
|
||||
|
||||
class CBaseEntity;
|
||||
class CBaseHandle;
|
||||
@ -67,6 +67,12 @@ namespace SourceMod
|
||||
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
|
||||
{
|
||||
public:
|
||||
@ -318,6 +324,17 @@ namespace SourceMod
|
||||
* @return True if valid, otherwise false.
|
||||
*/
|
||||
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;
|
||||
};
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user