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(); | ||||
| 		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) | ||||
| @ -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,14 +891,13 @@ 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) | ||||
| 	{ | ||||
| @ -830,84 +905,62 @@ 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; | ||||
|  | ||||
| @ -449,6 +449,26 @@ native FindDataMapOffs(entity, | ||||
| 					   const String:prop[], | ||||
| 					   &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; | ||||
| @ -66,6 +66,12 @@ namespace SourceMod | ||||
| 		SendProp *prop;					/**< Property instance. */ | ||||
| 		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 | ||||
| 	{ | ||||
| @ -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