Merge pull request #353 from alliedmodders/getentpropstringt
Better string_t support for Get/Set EntPropString
This commit is contained in:
		
						commit
						01941d5504
					
				@ -1277,3 +1277,37 @@ bool CHalfLife2::IsMapValid(const char *map)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	return FindMap(szTmp, sizeof(szTmp)) != SMFindMapResult::NotFound;
 | 
						return FindMap(szTmp, sizeof(szTmp)) != SMFindMapResult::NotFound;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TODO: Add ep1 support for this. (No IServerTools available there)
 | 
				
			||||||
 | 
					#if SOURCE_ENGINE >= SE_ORANGEBOX
 | 
				
			||||||
 | 
					string_t CHalfLife2::AllocPooledString(const char *pszValue)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						// This is admittedly a giant hack, but it's a relatively safe method for
 | 
				
			||||||
 | 
						// inserting a string into the game's string pool that isn't likely to break.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// We find the first valid ent (should always be worldspawn), save off it's
 | 
				
			||||||
 | 
						// current targetname string_t, set it to our string to insert via SetKeyValue,
 | 
				
			||||||
 | 
						// read back the new targetname value, restore the old value, and return the new one.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						CBaseEntity *pEntity = ((IServerUnknown *) servertools->FirstEntity())->GetBaseEntity();
 | 
				
			||||||
 | 
						auto *pDataMap = GetDataMap(pEntity);
 | 
				
			||||||
 | 
						assert(pDataMap);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static int offset = -1;
 | 
				
			||||||
 | 
						if (offset == -1)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							sm_datatable_info_t info;
 | 
				
			||||||
 | 
							bool found = FindDataMapInfo(pDataMap, "m_iName", &info);
 | 
				
			||||||
 | 
							assert(found);
 | 
				
			||||||
 | 
							offset = info.actual_offset;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						string_t *pProp = (string_t *) ((intp) pEntity + offset);
 | 
				
			||||||
 | 
						string_t backup = *pProp;
 | 
				
			||||||
 | 
						servertools->SetKeyValue(pEntity, "targetname", pszValue);
 | 
				
			||||||
 | 
						string_t newString = *pProp;
 | 
				
			||||||
 | 
						*pProp = backup;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return newString;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
				
			|||||||
@ -47,9 +47,7 @@
 | 
				
			|||||||
#include <datamap.h>
 | 
					#include <datamap.h>
 | 
				
			||||||
#include <ihandleentity.h>
 | 
					#include <ihandleentity.h>
 | 
				
			||||||
#include <tier0/icommandline.h>
 | 
					#include <tier0/icommandline.h>
 | 
				
			||||||
#if SOURCE_ENGINE >= SE_PORTAL2
 | 
					 | 
				
			||||||
#include <string_t.h>
 | 
					#include <string_t.h>
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
class CCommand;
 | 
					class CCommand;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -185,6 +183,9 @@ public: //IGameHelpers
 | 
				
			|||||||
	const char *GetEntityClassname(CBaseEntity *pEntity);
 | 
						const char *GetEntityClassname(CBaseEntity *pEntity);
 | 
				
			||||||
	bool IsMapValid(const char *map);
 | 
						bool IsMapValid(const char *map);
 | 
				
			||||||
	SMFindMapResult FindMap(char *pMapName, int nMapNameMax);
 | 
						SMFindMapResult FindMap(char *pMapName, int nMapNameMax);
 | 
				
			||||||
 | 
					#if SOURCE_ENGINE >= SE_ORANGEBOX
 | 
				
			||||||
 | 
						string_t AllocPooledString(const char *pszValue);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	void AddToFakeCliCmdQueue(int client, int userid, const char *cmd);
 | 
						void AddToFakeCliCmdQueue(int client, int userid, const char *cmd);
 | 
				
			||||||
	void ProcessFakeCliCmdQueue();
 | 
						void ProcessFakeCliCmdQueue();
 | 
				
			||||||
 | 
				
			|||||||
@ -1886,7 +1886,6 @@ static cell_t GetEntPropString(IPluginContext *pContext, const cell_t *params)
 | 
				
			|||||||
	char *prop;
 | 
						char *prop;
 | 
				
			||||||
	int offset;
 | 
						int offset;
 | 
				
			||||||
	edict_t *pEdict;
 | 
						edict_t *pEdict;
 | 
				
			||||||
	bool bIsStringIndex;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int element = 0;
 | 
						int element = 0;
 | 
				
			||||||
	if (params[0] >= 6)
 | 
						if (params[0] >= 6)
 | 
				
			||||||
@ -1901,12 +1900,13 @@ static cell_t GetEntPropString(IPluginContext *pContext, const cell_t *params)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	pContext->LocalToString(params[3], &prop);
 | 
						pContext->LocalToString(params[3], &prop);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bIsStringIndex = false;
 | 
						const char *src;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch (params[2])
 | 
						switch (params[2])
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
	case Prop_Data:
 | 
						case Prop_Data:
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
 | 
								bool bIsStringIndex = false;
 | 
				
			||||||
			typedescription_t *td;
 | 
								typedescription_t *td;
 | 
				
			||||||
			
 | 
								
 | 
				
			||||||
			FIND_PROP_DATA(td);
 | 
								FIND_PROP_DATA(td);
 | 
				
			||||||
@ -1942,6 +1942,15 @@ static cell_t GetEntPropString(IPluginContext *pContext, const cell_t *params)
 | 
				
			|||||||
			if (bIsStringIndex)
 | 
								if (bIsStringIndex)
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				offset += (element * (td->fieldSizeInBytes / td->fieldSize));
 | 
									offset += (element * (td->fieldSizeInBytes / td->fieldSize));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									string_t idx;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									idx = *(string_t *) ((uint8_t *) pEntity + offset);
 | 
				
			||||||
 | 
									src = (idx == NULL_STRING) ? "" : STRING(idx);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								else
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									src = (char *) ((uint8_t *) pEntity + offset);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@ -1980,6 +1989,17 @@ static cell_t GetEntPropString(IPluginContext *pContext, const cell_t *params)
 | 
				
			|||||||
					element);
 | 
										element);
 | 
				
			||||||
 			}
 | 
					 			}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (info.prop->GetProxyFn())
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									DVariant var;
 | 
				
			||||||
 | 
									info.prop->GetProxyFn()(info.prop, pEntity, (const void *) ((intptr_t) pEntity + offset), &var, element, params[1]);
 | 
				
			||||||
 | 
									src = var.m_pString;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								else
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									src = (char *) ((uint8_t *) pEntity + offset);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
@ -1989,22 +2009,7 @@ static cell_t GetEntPropString(IPluginContext *pContext, const cell_t *params)
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	size_t len;
 | 
						size_t len;
 | 
				
			||||||
	const char *src; 
 | 
					 | 
				
			||||||
	
 | 
					 | 
				
			||||||
	if (!bIsStringIndex)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		src = (char *)((uint8_t *)pEntity + offset);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	else
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		string_t idx;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		idx = *(string_t *)((uint8_t *)pEntity + offset);
 | 
					 | 
				
			||||||
		src = (idx == NULL_STRING) ? "" : STRING(idx);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	pContext->StringToLocalUTF8(params[4], params[5], src, &len);
 | 
						pContext->StringToLocalUTF8(params[4], params[5], src, &len);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	return len;
 | 
						return len;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -2015,6 +2020,13 @@ static cell_t SetEntPropString(IPluginContext *pContext, const cell_t *params)
 | 
				
			|||||||
	int offset;
 | 
						int offset;
 | 
				
			||||||
	int maxlen;
 | 
						int maxlen;
 | 
				
			||||||
	edict_t *pEdict;
 | 
						edict_t *pEdict;
 | 
				
			||||||
 | 
						bool bIsStringIndex;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int element = 0;
 | 
				
			||||||
 | 
						if (params[0] >= 5)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							element = params[5];
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!IndexToAThings(params[1], &pEntity, &pEdict))
 | 
						if (!IndexToAThings(params[1], &pEntity, &pEdict))
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
@ -2038,17 +2050,31 @@ static cell_t SetEntPropString(IPluginContext *pContext, const cell_t *params)
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
			
 | 
								
 | 
				
			||||||
			typedescription_t *td = info.prop;
 | 
								typedescription_t *td = info.prop;
 | 
				
			||||||
			if (td->fieldType != FIELD_CHARACTER)
 | 
								if (td->fieldType != FIELD_CHARACTER
 | 
				
			||||||
 | 
									&& td->fieldType != FIELD_STRING
 | 
				
			||||||
 | 
									&& td->fieldType != FIELD_MODELNAME
 | 
				
			||||||
 | 
									&& td->fieldType != FIELD_SOUNDNAME)
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				return pContext->ThrowNativeError("Property \"%s\" is not a valid string", prop);
 | 
									return pContext->ThrowNativeError("Property \"%s\" is not a valid string", prop);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			offset = info.actual_offset;
 | 
								offset = info.actual_offset;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								bIsStringIndex = (td->fieldType != FIELD_CHARACTER);
 | 
				
			||||||
 | 
								if (bIsStringIndex)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									offset += (element * (td->fieldSizeInBytes / td->fieldSize));
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								else
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
				maxlen = td->fieldSize;
 | 
									maxlen = td->fieldSize;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	case Prop_Send:
 | 
						case Prop_Send:
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			char *prop;
 | 
								sm_sendprop_info_t info;
 | 
				
			||||||
			IServerUnknown *pUnk = (IServerUnknown *)pEntity;
 | 
								IServerUnknown *pUnk = (IServerUnknown *)pEntity;
 | 
				
			||||||
			IServerNetworkable *pNet = pUnk->GetNetworkable();
 | 
								IServerNetworkable *pNet = pUnk->GetNetworkable();
 | 
				
			||||||
			if (!pNet)
 | 
								if (!pNet)
 | 
				
			||||||
@ -2056,17 +2082,37 @@ static cell_t SetEntPropString(IPluginContext *pContext, const cell_t *params)
 | 
				
			|||||||
				return pContext->ThrowNativeError("The edict is not networkable");
 | 
									return pContext->ThrowNativeError("The edict is not networkable");
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			pContext->LocalToString(params[3], &prop);
 | 
								pContext->LocalToString(params[3], &prop);
 | 
				
			||||||
			SendProp *pSend = g_HL2.FindInSendTable(pNet->GetServerClass()->GetName(), prop);
 | 
								if (!g_HL2.FindSendPropInfo(pNet->GetServerClass()->GetName(), prop, &info))
 | 
				
			||||||
			if (!pSend)
 | 
					 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				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]);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			if (pSend->GetType() != DPT_String)
 | 
					
 | 
				
			||||||
 | 
								offset = info.prop->GetOffset();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (info.prop->GetType() != DPT_String)
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				return pContext->ThrowNativeError("Property \"%s\" is not a valid string", prop);
 | 
									return pContext->ThrowNativeError("Property \"%s\" is not a valid string", prop);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			offset = pSend->GetOffset();
 | 
								else if (element != 0)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									return pContext->ThrowNativeError("SendProp %s is not an array. Element %d is invalid.",
 | 
				
			||||||
 | 
										prop,
 | 
				
			||||||
 | 
										element);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (info.prop->GetProxyFn())
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									DVariant var;
 | 
				
			||||||
 | 
									info.prop->GetProxyFn()(info.prop, pEntity, (const void *) ((intptr_t) pEntity + offset), &var, element, params[1]);
 | 
				
			||||||
 | 
									if (var.m_pString == ((string_t *) ((intptr_t) pEntity + offset))->ToCStr())
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										bIsStringIndex = true;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								else
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
				maxlen = DT_MAX_STRING_BUFFERSIZE;
 | 
									maxlen = DT_MAX_STRING_BUFFERSIZE;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
@ -2076,10 +2122,23 @@ static cell_t SetEntPropString(IPluginContext *pContext, const cell_t *params)
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	char *src;
 | 
						char *src;
 | 
				
			||||||
	char *dest = (char *)((uint8_t *)pEntity + offset);
 | 
						size_t len;
 | 
				
			||||||
 | 
					 | 
				
			||||||
	pContext->LocalToString(params[4], &src);
 | 
						pContext->LocalToString(params[4], &src);
 | 
				
			||||||
	size_t len = strncopy(dest, src, maxlen);
 | 
					
 | 
				
			||||||
 | 
						if (bIsStringIndex)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
					#if SOURCE_ENGINE < SE_ORANGEBOX
 | 
				
			||||||
 | 
							return pContext->ThrowNativeError("Cannot set %s. Setting string_t values not supported on this game.", prop);
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
							*(string_t *) ((intptr_t) pEntity + offset) = g_HL2.AllocPooledString(src);
 | 
				
			||||||
 | 
							len = strlen(src);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							char *dest = (char *) ((uint8_t *) pEntity + offset);
 | 
				
			||||||
 | 
							len = strncopy(dest, src, maxlen);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (params[2] == Prop_Send && (pEdict != NULL))
 | 
						if (params[2] == Prop_Send && (pEdict != NULL))
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
 | 
				
			|||||||
@ -651,17 +651,15 @@ native GetEntPropString(entity, PropType:type, const String:prop[], String:buffe
 | 
				
			|||||||
/**
 | 
					/**
 | 
				
			||||||
 * Sets a network property as a string.
 | 
					 * Sets a network property as a string.
 | 
				
			||||||
 * 
 | 
					 * 
 | 
				
			||||||
 * This cannot set property fields of type PropField_String_T (such as "m_target").
 | 
					 | 
				
			||||||
 * To set such fields, you should use DispatchKeyValue() from SDKTools.
 | 
					 | 
				
			||||||
 * 
 | 
					 | 
				
			||||||
 * @param entity		Edict index.
 | 
					 * @param entity		Edict index.
 | 
				
			||||||
 * @param type			Property type.
 | 
					 * @param type			Property type.
 | 
				
			||||||
 * @param prop			Property to use.
 | 
					 * @param prop			Property to use.
 | 
				
			||||||
 * @param buffer		String to set.		
 | 
					 * @param buffer		String to set.		
 | 
				
			||||||
 | 
					 * @param element		Element # (starting from 0) if property is an array.
 | 
				
			||||||
 * @return				Number of non-null bytes written.
 | 
					 * @return				Number of non-null bytes written.
 | 
				
			||||||
 * @error				Invalid entity, offset out of reasonable bounds, or property is not a valid string.
 | 
					 * @error				Invalid entity, offset out of reasonable bounds, or property is not a valid string.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
native SetEntPropString(entity, PropType:type, const String:prop[], const String:buffer[]);
 | 
					native SetEntPropString(entity, PropType:type, const String:prop[], const String:buffer[], element=0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Retrieves the count of values that an entity property's array can store.
 | 
					 * Retrieves the count of values that an entity property's array can store.
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user