Add support for getting and setting output variables with Get/SetEntProp*.

This commit is contained in:
Nicholas Hastings 2017-02-04 17:31:54 -05:00
parent 113a4a55c6
commit af9852a68f
2 changed files with 180 additions and 25 deletions

View File

@ -91,6 +91,24 @@ enum PropFieldType
PropField_Vector, /**< Valid for SendProp and Data fields */ PropField_Vector, /**< Valid for SendProp and Data fields */
PropField_String, /**< Valid for SendProp and Data fields */ PropField_String, /**< Valid for SendProp and Data fields */
PropField_String_T, /**< Valid for Data fields. Read only! */ 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) 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; *pType = PropField_Integer;
*pSize = 32; *pSize = 32;
break; return;
} }
case FIELD_VECTOR: case FIELD_VECTOR:
case FIELD_POSITION_VECTOR: case FIELD_POSITION_VECTOR:
@ -830,13 +848,13 @@ static void GuessDataPropTypes(typedescription_t *td, cell_t * pSize, cell_t * p
{ {
*pType = PropField_Integer; *pType = PropField_Integer;
*pSize = 16; *pSize = 16;
break; return;
} }
case FIELD_BOOLEAN: case FIELD_BOOLEAN:
{ {
*pType = PropField_Integer; *pType = PropField_Integer;
*pSize = 1; *pSize = 1;
break; return;
} }
case FIELD_CHARACTER: case FIELD_CHARACTER:
{ {
@ -850,7 +868,7 @@ static void GuessDataPropTypes(typedescription_t *td, cell_t * pSize, cell_t * p
*pType = PropField_String; *pType = PropField_String;
*pSize = 8 * td->fieldSize; *pSize = 8 * td->fieldSize;
} }
break; return;
} }
case FIELD_MODELNAME: case FIELD_MODELNAME:
case FIELD_SOUNDNAME: case FIELD_SOUNDNAME:
@ -858,27 +876,34 @@ static void GuessDataPropTypes(typedescription_t *td, cell_t * pSize, cell_t * p
{ {
*pSize = sizeof(string_t); *pSize = sizeof(string_t);
*pType = PropField_String_T; *pType = PropField_String_T;
break; return;
} }
case FIELD_FLOAT: case FIELD_FLOAT:
case FIELD_TIME: case FIELD_TIME:
{ {
*pType = PropField_Float; *pType = PropField_Float;
*pSize = 32; *pSize = 32;
break; return;
} }
case FIELD_EHANDLE: case FIELD_EHANDLE:
{ {
*pType = PropField_Entity; *pType = PropField_Entity;
*pSize = 32; *pSize = 32;
break; return;
} }
default: case FIELD_CUSTOM:
{ {
*pType = PropField_Unsupported; if ((td->flags & FTYPEDESC_OUTPUT) == FTYPEDESC_OUTPUT)
*pSize = 0; {
*pType = PropField_Variant;
*pSize = 0;
return;
}
} }
} }
*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)
@ -1050,6 +1075,26 @@ static cell_t SetEntDataString(IPluginContext *pContext, const cell_t *params)
\ \
offset = info.actual_offset + (element * (td->fieldSizeInBytes / td->fieldSize)); 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) \ #define FIND_PROP_SEND(type, type_name) \
sm_sendprop_info_t info;\ sm_sendprop_info_t info;\
SendProp *pProp; \ 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_TICK:
case FIELD_MODELINDEX: case FIELD_MODELINDEX:
@ -1139,6 +1184,12 @@ inline int MatchFieldAsInteger(int field_type)
case FIELD_INTEGER: case FIELD_INTEGER:
case FIELD_COLOR32: case FIELD_COLOR32:
return 32; return 32;
case FIELD_CUSTOM:
if ((flags & FTYPEDESC_OUTPUT) == FTYPEDESC_OUTPUT)
{
// Variant, read as int32.
return 32;
}
case FIELD_SHORT: case FIELD_SHORT:
return 16; return 16;
case FIELD_CHARACTER: case FIELD_CHARACTER:
@ -1246,7 +1297,7 @@ static cell_t GetEntProp(IPluginContext *pContext, const cell_t *params)
FIND_PROP_DATA(td); 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)", return pContext->ThrowNativeError("Data field %s is not an integer (%d)",
prop, prop,
@ -1254,6 +1305,17 @@ static cell_t GetEntProp(IPluginContext *pContext, const cell_t *params)
} }
CHECK_SET_PROP_DATA_OFFSET(); 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; break;
} }
@ -1347,7 +1409,7 @@ static cell_t SetEntProp(IPluginContext *pContext, const cell_t *params)
FIND_PROP_DATA(td); 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)", return pContext->ThrowNativeError("Data field %s is not an integer (%d)",
prop, prop,
@ -1356,6 +1418,21 @@ static cell_t SetEntProp(IPluginContext *pContext, const cell_t *params)
CHECK_SET_PROP_DATA_OFFSET(); 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; break;
} }
case Prop_Send: case Prop_Send:
@ -1454,6 +1531,8 @@ static cell_t GetEntPropFloat(IPluginContext *pContext, const cell_t *params)
CHECK_SET_PROP_DATA_OFFSET(); CHECK_SET_PROP_DATA_OFFSET();
CHECK_TYPE_VALID_IF_VARIANT(FIELD_FLOAT, "float");
break; break;
} }
case Prop_Send: case Prop_Send:
@ -1513,6 +1592,8 @@ static cell_t SetEntPropFloat(IPluginContext *pContext, const cell_t *params)
CHECK_SET_PROP_DATA_OFFSET(); CHECK_SET_PROP_DATA_OFFSET();
SET_TYPE_IF_VARIANT(FIELD_FLOAT);
break; break;
} }
case Prop_Send: case Prop_Send:
@ -1542,9 +1623,11 @@ static cell_t SetEntPropFloat(IPluginContext *pContext, const cell_t *params)
enum PropEntType enum PropEntType
{ {
PropEnt_Unknown,
PropEnt_Handle, PropEnt_Handle,
PropEnt_Entity, PropEnt_Entity,
PropEnt_Edict, PropEnt_Edict,
PropEnt_Variant,
}; };
static cell_t GetEntPropEnt(IPluginContext *pContext, const cell_t *params) 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 offset;
int bit_count; int bit_count;
edict_t *pEdict; edict_t *pEdict;
PropEntType type; PropEntType type = PropEnt_Unknown;
int element = 0; int element = 0;
if (params[0] >= 4) if (params[0] >= 4)
@ -1588,7 +1671,16 @@ static cell_t GetEntPropEnt(IPluginContext *pContext, const cell_t *params)
case FIELD_EDICT: case FIELD_EDICT:
type = PropEnt_Edict; type = PropEnt_Edict;
break; 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)", return pContext->ThrowNativeError("Data field %s is not an entity nor edict (%d)",
prop, prop,
td->fieldType); td->fieldType);
@ -1596,6 +1688,8 @@ static cell_t GetEntPropEnt(IPluginContext *pContext, const cell_t *params)
CHECK_SET_PROP_DATA_OFFSET(); CHECK_SET_PROP_DATA_OFFSET();
CHECK_TYPE_VALID_IF_VARIANT(FIELD_EHANDLE, "ehandle");
break; break;
} }
case Prop_Send: case Prop_Send:
@ -1613,11 +1707,22 @@ static cell_t GetEntPropEnt(IPluginContext *pContext, const cell_t *params)
switch (type) switch (type)
{ {
case PropEnt_Handle: case PropEnt_Handle:
case PropEnt_Variant:
{ {
CBaseHandle &hndl = *(CBaseHandle *) ((uint8_t *) pEntity + offset); CBaseHandle *hndl;
CBaseEntity *pHandleEntity = g_HL2.ReferenceToEntity(hndl.GetEntryIndex()); 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<IHandleEntity *>(pHandleEntity)->GetRefEHandle()) CBaseEntity *pHandleEntity = g_HL2.ReferenceToEntity(hndl->GetEntryIndex());
if (!pHandleEntity || hndl != &reinterpret_cast<IHandleEntity *>(pHandleEntity)->GetRefEHandle())
return -1; return -1;
return g_HL2.EntityToBCompatRef(pHandleEntity); return g_HL2.EntityToBCompatRef(pHandleEntity);
@ -1647,7 +1752,7 @@ static cell_t SetEntPropEnt(IPluginContext *pContext, const cell_t *params)
int offset; int offset;
int bit_count; int bit_count;
edict_t *pEdict; edict_t *pEdict;
PropEntType type; PropEntType type = PropEnt_Unknown;
int element = 0; int element = 0;
if (params[0] >= 5) if (params[0] >= 5)
@ -1683,7 +1788,16 @@ static cell_t SetEntPropEnt(IPluginContext *pContext, const cell_t *params)
if (!pEdict) if (!pEdict)
return pContext->ThrowNativeError("Edict %d is invalid", params[1]); return pContext->ThrowNativeError("Edict %d is invalid", params[1]);
break; 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)", return pContext->ThrowNativeError("Data field %s is not an entity nor edict (%d)",
prop, prop,
td->fieldType); td->fieldType);
@ -1691,6 +1805,8 @@ static cell_t SetEntPropEnt(IPluginContext *pContext, const cell_t *params)
CHECK_SET_PROP_DATA_OFFSET(); CHECK_SET_PROP_DATA_OFFSET();
SET_TYPE_IF_VARIANT(FIELD_EHANDLE);
break; break;
} }
case Prop_Send: case Prop_Send:
@ -1714,9 +1830,20 @@ static cell_t SetEntPropEnt(IPluginContext *pContext, const cell_t *params)
switch (type) switch (type)
{ {
case PropEnt_Handle: case PropEnt_Handle:
case PropEnt_Variant:
{ {
CBaseHandle &hndl = *(CBaseHandle *) ((uint8_t *) pEntity + offset); CBaseHandle *hndl;
hndl.Set((IHandleEntity *) pOther); 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)) 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(); 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; break;
} }
case Prop_Send: case Prop_Send:
@ -1865,6 +2003,17 @@ static cell_t SetEntPropVector(IPluginContext *pContext, const cell_t *params)
CHECK_SET_PROP_DATA_OFFSET(); 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; break;
} }
case Prop_Send: case Prop_Send:
@ -1926,10 +2075,11 @@ static cell_t GetEntPropString(IPluginContext *pContext, const cell_t *params)
FIND_PROP_DATA(td); FIND_PROP_DATA(td);
if (td->fieldType != FIELD_CHARACTER if ((td->fieldType != FIELD_CHARACTER
&& td->fieldType != FIELD_STRING && td->fieldType != FIELD_STRING
&& td->fieldType != FIELD_MODELNAME && td->fieldType != FIELD_MODELNAME
&& td->fieldType != FIELD_SOUNDNAME) && 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)", return pContext->ThrowNativeError("Data field %s is not a string (%d != %d)",
prop, prop,
@ -2071,10 +2221,11 @@ 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_STRING
&& td->fieldType != FIELD_MODELNAME && td->fieldType != FIELD_MODELNAME
&& td->fieldType != FIELD_SOUNDNAME) && 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); 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; maxlen = td->fieldSize;
} }
SET_TYPE_IF_VARIANT(FIELD_STRING);
break; break;
} }
case Prop_Send: case Prop_Send:

View File

@ -72,6 +72,8 @@ enum PropFieldType
thus FindDataMapOffs() will return the constant size thus FindDataMapOffs() will return the constant size
of the string_t container (which is 32 bits right now). 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. */
}; };
/** /**