Add support for getting and setting output variables with Get/SetEntProp*.
This commit is contained in:
parent
113a4a55c6
commit
af9852a68f
@ -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:
|
||||
|
@ -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. */
|
||||
};
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user