From af9852a68fb4a12c26410d8f4decfe08e47a3471 Mon Sep 17 00:00:00 2001 From: Nicholas Hastings Date: Sat, 4 Feb 2017 17:31:54 -0500 Subject: [PATCH] Add support for getting and setting output variables with Get/SetEntProp*. --- core/smn_entities.cpp | 203 ++++++++++++++++++++++++++++++++----- plugins/include/entity.inc | 2 + 2 files changed, 180 insertions(+), 25 deletions(-) diff --git a/core/smn_entities.cpp b/core/smn_entities.cpp index 9e6cef80..179d4335 100644 --- a/core/smn_entities.cpp +++ b/core/smn_entities.cpp @@ -91,6 +91,24 @@ enum PropFieldType PropField_Vector, /**< Valid for SendProp and Data fields */ PropField_String, /**< Valid for SendProp and Data fields */ PropField_String_T, /**< Valid for Data fields. Read only! */ + PropField_Variant, /**< Valid for variants/any. (User must know type) */ +}; + +class variant_t +{ +public: + union + { + bool bVal; + string_t iszVal; + int iVal; + float flVal; + float vecVal[3]; + color32 rgbaVal; + }; + + CBaseHandle eVal; + fieldtype_t fieldType; }; inline bool CanSetPropName(const char *pszPropName) @@ -817,7 +835,7 @@ static void GuessDataPropTypes(typedescription_t *td, cell_t * pSize, cell_t * p { *pType = PropField_Integer; *pSize = 32; - break; + return; } case FIELD_VECTOR: case FIELD_POSITION_VECTOR: @@ -830,13 +848,13 @@ static void GuessDataPropTypes(typedescription_t *td, cell_t * pSize, cell_t * p { *pType = PropField_Integer; *pSize = 16; - break; + return; } case FIELD_BOOLEAN: { *pType = PropField_Integer; *pSize = 1; - break; + return; } case FIELD_CHARACTER: { @@ -850,7 +868,7 @@ static void GuessDataPropTypes(typedescription_t *td, cell_t * pSize, cell_t * p *pType = PropField_String; *pSize = 8 * td->fieldSize; } - break; + return; } case FIELD_MODELNAME: case FIELD_SOUNDNAME: @@ -858,27 +876,34 @@ static void GuessDataPropTypes(typedescription_t *td, cell_t * pSize, cell_t * p { *pSize = sizeof(string_t); *pType = PropField_String_T; - break; + return; } case FIELD_FLOAT: case FIELD_TIME: { *pType = PropField_Float; *pSize = 32; - break; + return; } case FIELD_EHANDLE: { *pType = PropField_Entity; *pSize = 32; - break; + return; } - default: + case FIELD_CUSTOM: { - *pType = PropField_Unsupported; - *pSize = 0; + if ((td->flags & FTYPEDESC_OUTPUT) == FTYPEDESC_OUTPUT) + { + *pType = PropField_Variant; + *pSize = 0; + return; + } } } + + *pType = PropField_Unsupported; + *pSize = 0; } static cell_t FindDataMapOffs(IPluginContext *pContext, const cell_t *params) @@ -1050,6 +1075,26 @@ static cell_t SetEntDataString(IPluginContext *pContext, const cell_t *params) \ offset = info.actual_offset + (element * (td->fieldSizeInBytes / td->fieldSize)); +#define CHECK_TYPE_VALID_IF_VARIANT(type, typeName) \ + if (td->fieldType == FIELD_CUSTOM && (td->flags & FTYPEDESC_OUTPUT) == FTYPEDESC_OUTPUT) \ + { \ + auto *pVariant = (variant_t *)((intptr_t)pEntity + offset); \ + if (pVariant->fieldType != type) \ + { \ + return pContext->ThrowNativeError("Variant value for %s is not %s (%d)", \ + prop, \ + typeName, \ + pVariant->fieldType); \ + } \ + } + +#define SET_TYPE_IF_VARIANT(type) \ + if (td->fieldType == FIELD_CUSTOM && (td->flags & FTYPEDESC_OUTPUT) == FTYPEDESC_OUTPUT) \ + { \ + auto *pVariant = (variant_t *)((intptr_t)pEntity + offset); \ + pVariant->fieldType = type; \ + } + #define FIND_PROP_SEND(type, type_name) \ sm_sendprop_info_t info;\ SendProp *pProp; \ @@ -1129,9 +1174,9 @@ static cell_t SetEntDataString(IPluginContext *pContext, const cell_t *params) } -inline int MatchFieldAsInteger(int field_type) +inline int MatchTypeDescAsInteger(_fieldtypes type, int flags) { - switch (field_type) + switch (type) { case FIELD_TICK: case FIELD_MODELINDEX: @@ -1139,6 +1184,12 @@ inline int MatchFieldAsInteger(int field_type) case FIELD_INTEGER: case FIELD_COLOR32: return 32; + case FIELD_CUSTOM: + if ((flags & FTYPEDESC_OUTPUT) == FTYPEDESC_OUTPUT) + { + // Variant, read as int32. + return 32; + } case FIELD_SHORT: return 16; case FIELD_CHARACTER: @@ -1246,7 +1297,7 @@ static cell_t GetEntProp(IPluginContext *pContext, const cell_t *params) FIND_PROP_DATA(td); - if ((bit_count = MatchFieldAsInteger(td->fieldType)) == 0) + if ((bit_count = MatchTypeDescAsInteger(td->fieldType, td->flags)) == 0) { return pContext->ThrowNativeError("Data field %s is not an integer (%d)", prop, @@ -1254,6 +1305,17 @@ static cell_t GetEntProp(IPluginContext *pContext, const cell_t *params) } CHECK_SET_PROP_DATA_OFFSET(); + + if (td->fieldType == FIELD_CUSTOM && (td->flags & FTYPEDESC_OUTPUT) == FTYPEDESC_OUTPUT) + { + auto *pVariant = (variant_t *)((intptr_t)pEntity + offset); + if ((bit_count = MatchTypeDescAsInteger(pVariant->fieldType, 0)) == 0) + { + return pContext->ThrowNativeError("Variant value for %s is not an integer (%d)", + prop, + pVariant->fieldType); + } \ + } break; } @@ -1347,7 +1409,7 @@ static cell_t SetEntProp(IPluginContext *pContext, const cell_t *params) FIND_PROP_DATA(td); - if ((bit_count = MatchFieldAsInteger(td->fieldType)) == 0) + if ((bit_count = MatchTypeDescAsInteger(td->fieldType, td->flags)) == 0) { return pContext->ThrowNativeError("Data field %s is not an integer (%d)", prop, @@ -1356,6 +1418,21 @@ static cell_t SetEntProp(IPluginContext *pContext, const cell_t *params) CHECK_SET_PROP_DATA_OFFSET(); + if (td->fieldType == FIELD_CUSTOM && (td->flags & FTYPEDESC_OUTPUT) == FTYPEDESC_OUTPUT) + { + auto *pVariant = (variant_t *)((intptr_t)pEntity + offset); + // These are the only three int-ish types that variants support. If set to valid one that isn't + // (32-bit) integer, leave it alone. It's probably the intended type. + if (pVariant->fieldType != FIELD_COLOR32 && pVariant->fieldType != FIELD_BOOLEAN) + { + pVariant->fieldType = FIELD_INTEGER; + } + + bit_count = MatchTypeDescAsInteger(pVariant->fieldType, 0); + } + + SET_TYPE_IF_VARIANT(FIELD_INTEGER); + break; } case Prop_Send: @@ -1454,6 +1531,8 @@ static cell_t GetEntPropFloat(IPluginContext *pContext, const cell_t *params) CHECK_SET_PROP_DATA_OFFSET(); + CHECK_TYPE_VALID_IF_VARIANT(FIELD_FLOAT, "float"); + break; } case Prop_Send: @@ -1513,6 +1592,8 @@ static cell_t SetEntPropFloat(IPluginContext *pContext, const cell_t *params) CHECK_SET_PROP_DATA_OFFSET(); + SET_TYPE_IF_VARIANT(FIELD_FLOAT); + break; } case Prop_Send: @@ -1542,9 +1623,11 @@ static cell_t SetEntPropFloat(IPluginContext *pContext, const cell_t *params) enum PropEntType { + PropEnt_Unknown, PropEnt_Handle, PropEnt_Entity, PropEnt_Edict, + PropEnt_Variant, }; static cell_t GetEntPropEnt(IPluginContext *pContext, const cell_t *params) @@ -1554,7 +1637,7 @@ static cell_t GetEntPropEnt(IPluginContext *pContext, const cell_t *params) int offset; int bit_count; edict_t *pEdict; - PropEntType type; + PropEntType type = PropEnt_Unknown; int element = 0; if (params[0] >= 4) @@ -1588,7 +1671,16 @@ static cell_t GetEntPropEnt(IPluginContext *pContext, const cell_t *params) case FIELD_EDICT: type = PropEnt_Edict; break; - default: + case FIELD_CUSTOM: + if ((td->flags & FTYPEDESC_OUTPUT) == FTYPEDESC_OUTPUT) + { + type = PropEnt_Variant; + } + break; + } + + if (type == PropEnt_Unknown) + { return pContext->ThrowNativeError("Data field %s is not an entity nor edict (%d)", prop, td->fieldType); @@ -1596,6 +1688,8 @@ static cell_t GetEntPropEnt(IPluginContext *pContext, const cell_t *params) CHECK_SET_PROP_DATA_OFFSET(); + CHECK_TYPE_VALID_IF_VARIANT(FIELD_EHANDLE, "ehandle"); + break; } case Prop_Send: @@ -1613,11 +1707,22 @@ static cell_t GetEntPropEnt(IPluginContext *pContext, const cell_t *params) switch (type) { case PropEnt_Handle: + case PropEnt_Variant: { - CBaseHandle &hndl = *(CBaseHandle *) ((uint8_t *) pEntity + offset); - CBaseEntity *pHandleEntity = g_HL2.ReferenceToEntity(hndl.GetEntryIndex()); + CBaseHandle *hndl; + if (type == PropEnt_Handle) + { + hndl = (CBaseHandle *)((uint8_t *)pEntity + offset); + } + else // PropEnt_Variant + { + auto *pVariant = (variant_t *)((intptr_t)pEntity + offset); + hndl = &pVariant->eVal; + } - if (!pHandleEntity || hndl != reinterpret_cast(pHandleEntity)->GetRefEHandle()) + CBaseEntity *pHandleEntity = g_HL2.ReferenceToEntity(hndl->GetEntryIndex()); + + if (!pHandleEntity || hndl != &reinterpret_cast(pHandleEntity)->GetRefEHandle()) return -1; return g_HL2.EntityToBCompatRef(pHandleEntity); @@ -1647,7 +1752,7 @@ static cell_t SetEntPropEnt(IPluginContext *pContext, const cell_t *params) int offset; int bit_count; edict_t *pEdict; - PropEntType type; + PropEntType type = PropEnt_Unknown; int element = 0; if (params[0] >= 5) @@ -1683,7 +1788,16 @@ static cell_t SetEntPropEnt(IPluginContext *pContext, const cell_t *params) if (!pEdict) return pContext->ThrowNativeError("Edict %d is invalid", params[1]); break; - default: + case FIELD_CUSTOM: + if ((td->flags & FTYPEDESC_OUTPUT) == FTYPEDESC_OUTPUT) + { + type = PropEnt_Variant; + } + break; + } + + if (type == PropEnt_Unknown) + { return pContext->ThrowNativeError("Data field %s is not an entity nor edict (%d)", prop, td->fieldType); @@ -1691,6 +1805,8 @@ static cell_t SetEntPropEnt(IPluginContext *pContext, const cell_t *params) CHECK_SET_PROP_DATA_OFFSET(); + SET_TYPE_IF_VARIANT(FIELD_EHANDLE); + break; } case Prop_Send: @@ -1714,9 +1830,20 @@ static cell_t SetEntPropEnt(IPluginContext *pContext, const cell_t *params) switch (type) { case PropEnt_Handle: + case PropEnt_Variant: { - CBaseHandle &hndl = *(CBaseHandle *) ((uint8_t *) pEntity + offset); - hndl.Set((IHandleEntity *) pOther); + CBaseHandle *hndl; + if (type == PropEnt_Handle) + { + hndl = (CBaseHandle *)((uint8_t *)pEntity + offset); + } + else // PropEnt_Variant + { + auto *pVariant = (variant_t *)((intptr_t)pEntity + offset); + hndl = &pVariant->eVal; + } + + hndl->Set((IHandleEntity *) pOther); if (params[2] == Prop_Send && (pEdict != NULL)) { @@ -1799,6 +1926,17 @@ static cell_t GetEntPropVector(IPluginContext *pContext, const cell_t *params) CHECK_SET_PROP_DATA_OFFSET(); + if (td->fieldType == FIELD_CUSTOM && (td->flags & FTYPEDESC_OUTPUT) == FTYPEDESC_OUTPUT) + { + auto *pVariant = (variant_t *)((intptr_t)pEntity + offset); + if (pVariant->fieldType != FIELD_VECTOR && pVariant->fieldType != FIELD_POSITION_VECTOR) + { + return pContext->ThrowNativeError("Variant value for %s is not vector (%d)", + prop, + pVariant->fieldType); + } + } + break; } case Prop_Send: @@ -1865,6 +2003,17 @@ static cell_t SetEntPropVector(IPluginContext *pContext, const cell_t *params) CHECK_SET_PROP_DATA_OFFSET(); + if (td->fieldType == FIELD_CUSTOM && (td->flags & FTYPEDESC_OUTPUT) == FTYPEDESC_OUTPUT) + { + auto *pVariant = (variant_t *)((intptr_t)pEntity + offset); + // Both of these are supported and we don't know which is intended. But, if it's already + // a pos vector, we probably want to keep that. + if (pVariant->fieldType != FIELD_POSITION_VECTOR) + { + pVariant->fieldType = FIELD_VECTOR; + } + } + break; } case Prop_Send: @@ -1926,10 +2075,11 @@ static cell_t GetEntPropString(IPluginContext *pContext, const cell_t *params) FIND_PROP_DATA(td); - if (td->fieldType != FIELD_CHARACTER + if ((td->fieldType != FIELD_CHARACTER && td->fieldType != FIELD_STRING && td->fieldType != FIELD_MODELNAME && td->fieldType != FIELD_SOUNDNAME) + || (td->fieldType == FIELD_CUSTOM && (td->flags & FTYPEDESC_OUTPUT) != FTYPEDESC_OUTPUT)) { return pContext->ThrowNativeError("Data field %s is not a string (%d != %d)", prop, @@ -2071,10 +2221,11 @@ static cell_t SetEntPropString(IPluginContext *pContext, const cell_t *params) } 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) + || (td->fieldType == FIELD_CUSTOM && (td->flags & FTYPEDESC_OUTPUT) != FTYPEDESC_OUTPUT)) { return pContext->ThrowNativeError("Property \"%s\" is not a valid string", prop); } @@ -2117,6 +2268,8 @@ static cell_t SetEntPropString(IPluginContext *pContext, const cell_t *params) maxlen = td->fieldSize; } + SET_TYPE_IF_VARIANT(FIELD_STRING); + break; } case Prop_Send: diff --git a/plugins/include/entity.inc b/plugins/include/entity.inc index 52b9b625..840f2dac 100644 --- a/plugins/include/entity.inc +++ b/plugins/include/entity.inc @@ -72,6 +72,8 @@ enum PropFieldType thus FindDataMapOffs() will return the constant size of the string_t container (which is 32 bits right now). */ + PropField_Variant, /**< Valid for Data fields only Type is not known at the field level, + (for this call), but dependent on current field value. */ }; /**