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)) |  | ||||||
| 	{ |  | ||||||
| 		if ((td = UTIL_FindInDataMap(pMap, offset, isNested)) != NULL) |  | ||||||
| 		{ |  | ||||||
| 			sm_trie_insert(val.trie, offset, td); |  | ||||||
| 		} |  | ||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
| 	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) | 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,15 +891,14 @@ 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) | ||||||
| 	{ | 	{ | ||||||
| 		cell_t *pType, *pSize; | 		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[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; | ||||||
|  | |||||||
| @ -450,6 +450,26 @@ native FindDataMapOffs(entity, | |||||||
| 					   &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; | ||||||
| @ -67,6 +67,12 @@ namespace SourceMod | |||||||
| 		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 | ||||||
| 	{ | 	{ | ||||||
| 	public: | 	public: | ||||||
| @ -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