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)
|
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);
|
||||||
|
@ -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);
|
||||||
|
@ -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}
|
||||||
};
|
};
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
|
@ -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.
|
||||||
|
@ -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;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user