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_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,28 +876,35 @@ 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:
{
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,
@ -1255,6 +1306,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;
}
case Prop_Send:
@ -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<IHandleEntity *>(pHandleEntity)->GetRefEHandle())
CBaseEntity *pHandleEntity = g_HL2.ReferenceToEntity(hndl->GetEntryIndex());
if (!pHandleEntity || hndl != &reinterpret_cast<IHandleEntity *>(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:

View File

@ -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. */
};
/**