From c2644b2f94d4ff7121b9d801a4af0ab8ed41e092 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 19 Oct 2007 08:51:05 +0000 Subject: [PATCH] - added GetClientAimTarget() - fixed a bug where GetClientEyeAngles() was basically bogus --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%401617 --- extensions/sdktools/extension.cpp | 2 + extensions/sdktools/vhelpers.cpp | 64 +++++++++++- extensions/sdktools/vhelpers.h | 3 + extensions/sdktools/vnatives.cpp | 137 +++++++++++++++++++++---- plugins/include/sdktools_functions.inc | 40 +++++--- 5 files changed, 211 insertions(+), 35 deletions(-) diff --git a/extensions/sdktools/extension.cpp b/extensions/sdktools/extension.cpp index 50638e66..9a3a26b2 100644 --- a/extensions/sdktools/extension.cpp +++ b/extensions/sdktools/extension.cpp @@ -104,6 +104,8 @@ bool SDKTools::SDK_OnLoad(char *error, size_t maxlength, bool late) SH_ADD_HOOK_MEMFUNC(IServerGameDLL, LevelInit, gamedll, this, &SDKTools::LevelInit, true); + MathLib_Init(2.2f, 2.2f, 0.0f, 2); + return true; } diff --git a/extensions/sdktools/vhelpers.cpp b/extensions/sdktools/vhelpers.cpp index c41fd88b..41b6ae73 100644 --- a/extensions/sdktools/vhelpers.cpp +++ b/extensions/sdktools/vhelpers.cpp @@ -34,6 +34,7 @@ CallHelper s_Teleport; CallHelper s_GetVelocity; +CallHelper s_EyeAngles; bool SetupTeleport() { @@ -53,7 +54,7 @@ bool SetupTeleport() s_Teleport.call = g_pBinTools->CreateVCall(offset, 0, 0, NULL, info, 3); - if (s_Teleport.call) + if (s_Teleport.call != NULL) { s_Teleport.supported = true; } @@ -101,7 +102,7 @@ bool SetupGetVelocity() s_GetVelocity.call = g_pBinTools->CreateVCall(offset, 0, 0, NULL, info, 2); - if (s_GetVelocity.call) + if (s_GetVelocity.call != NULL) { s_GetVelocity.supported = true; } @@ -130,6 +131,65 @@ bool IsGetVelocitySupported() return SetupGetVelocity(); } +bool SetupGetEyeAngles() +{ + if (s_EyeAngles.setup) + { + return s_EyeAngles.supported; + } + + int offset; + if (g_pGameConf->GetOffset("EyeAngles", &offset)) + { + PassInfo info[2]; + info[0].flags = info[1].flags = PASSFLAG_BYVAL; + info[0].size = info[1].size = sizeof(void *); + info[0].type = info[1].type = PassType_Basic; + + s_EyeAngles.call = g_pBinTools->CreateVCall(offset, 0, 0, &info[0], &info[1], 1); + + if (s_EyeAngles.call != NULL) + { + s_EyeAngles.supported = true; + } + } + + s_EyeAngles.setup = true; + + return s_EyeAngles.supported; +} + +bool GetEyeAngles(CBaseEntity *pEntity, QAngle *pAngles) +{ + if (!IsEyeAnglesSupported()) + { + return false; + } + + QAngle *pRetAngle = NULL; + unsigned char params[sizeof(void *)]; + unsigned char *vptr = params; + + *(CBaseEntity **)vptr = pEntity; + vptr += sizeof(CBaseEntity *); + + s_EyeAngles.call->Execute(params, &pRetAngle); + + if (pRetAngle == NULL) + { + return false; + } + + *pAngles = *pRetAngle; + + return true; +} + +bool IsEyeAnglesSupported() +{ + return SetupGetEyeAngles(); +} + void ShutdownHelpers() { s_Teleport.Shutdown(); diff --git a/extensions/sdktools/vhelpers.h b/extensions/sdktools/vhelpers.h index aaea0fd5..573dac34 100644 --- a/extensions/sdktools/vhelpers.h +++ b/extensions/sdktools/vhelpers.h @@ -63,6 +63,9 @@ bool IsTeleportSupported(); void GetVelocity(CBaseEntity *pEntity, Vector *velocity, AngularImpulse *angvelocity); bool IsGetVelocitySupported(); +bool GetEyeAngles(CBaseEntity *pEntity, QAngle *pAngles); +bool IsEyeAnglesSupported(); + void ShutdownHelpers(); #endif //_INCLUDE_SDKTOOLS_VHELPERS_H_ diff --git a/extensions/sdktools/vnatives.cpp b/extensions/sdktools/vnatives.cpp index a86b59e0..381abbf4 100644 --- a/extensions/sdktools/vnatives.cpp +++ b/extensions/sdktools/vnatives.cpp @@ -113,6 +113,23 @@ bool CreateBaseCall(const char *name, return false; } +class CTraceFilterSimple : public CTraceFilterEntitiesOnly +{ +public: + CTraceFilterSimple(const IHandleEntity *passentity): m_pPassEnt(passentity) + { + } + virtual bool ShouldHitEntity(IHandleEntity *pServerEntity, int contentsMask) + { + if (pServerEntity == m_pPassEnt) + { + return false; + } + return true; + } +private: + const IHandleEntity *m_pPassEnt; +}; static cell_t RemovePlayerItem(IPluginContext *pContext, const cell_t *params) { @@ -567,31 +584,39 @@ static cell_t GetClientEyePosition(IPluginContext *pContext, const cell_t *param static cell_t GetClientEyeAngles(IPluginContext *pContext, const cell_t *params) { - static ValveCall *pCall = NULL; - if (!pCall) + int client = params[1]; + IGamePlayer *pPlayer = playerhelpers->GetGamePlayer(client); + + if (!pPlayer) { - ValvePassInfo retinfo[1]; - InitPass(retinfo[0], Valve_POD, PassType_Basic, PASSFLAG_BYVAL); - if (!CreateBaseCall("EyeAngles", ValveCall_Player, retinfo, NULL, 0, &pCall)) - { - return pContext->ThrowNativeError("\"EyeAngles\" not supported by this mod"); - } else if (!pCall) { - return pContext->ThrowNativeError("\"EyeAngles\" wrapper failed to initialized"); - } + return pContext->ThrowNativeError("Invalid client index %d", client); + } + else if (!pPlayer->IsInGame()) + { + return pContext->ThrowNativeError("Client %d is not in game", client); } - QAngle *ang; - START_CALL(); - DECODE_VALVE_PARAM(1, thisinfo, 0); - FINISH_CALL_SIMPLE(&ang); + edict_t *pEdict = pPlayer->GetEdict(); + CBaseEntity *pEntity = pEdict->GetUnknown() ? pEdict->GetUnknown()->GetBaseEntity() : NULL; + + /* We always set the angles for backwards compatibility -- + * The original function had no return value. + */ + QAngle angles; + bool got_angles = false; + + if (pEntity == NULL) + { + got_angles = GetEyeAngles(pEntity, &angles); + } cell_t *addr; pContext->LocalToPhysAddr(params[2], &addr); - addr[0] = sp_ftoc(ang->x); - addr[1] = sp_ftoc(ang->y); - addr[2] = sp_ftoc(ang->z); + addr[0] = sp_ftoc(angles.x); + addr[1] = sp_ftoc(angles.y); + addr[2] = sp_ftoc(angles.z); - return 1; + return got_angles ? 1 : 0; } static cell_t FindEntityByClassname(IPluginContext *pContext, const cell_t *params) @@ -638,7 +663,8 @@ static cell_t IsPlayerAlive(IPluginContext *pContext, const cell_t *params) if (player == NULL) { return pContext->ThrowNativeError("Invalid client index %d", params[1]); - } else if (!player->IsInGame()) + } + else if (!player->IsInGame()) { return pContext->ThrowNativeError("Client %d is not in game", params[1]); } @@ -814,6 +840,78 @@ static cell_t DispatchKeyValueVector(IPluginContext *pContext, const cell_t *par return (ret) ? 1 : 0; } +static cell_t GetClientAimTarget(IPluginContext *pContext, const cell_t *params) +{ + int client = params[1]; + IGamePlayer *pPlayer = playerhelpers->GetGamePlayer(client); + + if (!pPlayer) + { + return pContext->ThrowNativeError("Invalid client index %d", client); + } + else if (!pPlayer->IsInGame()) + { + return pContext->ThrowNativeError("Client %d is not in game", client); + } + + edict_t *pEdict = pPlayer->GetEdict(); + CBaseEntity *pEntity = pEdict->GetUnknown() ? pEdict->GetUnknown()->GetBaseEntity() : NULL; + + if (pEntity == NULL) + { + return -1; + } + + Vector eye_position; + QAngle eye_angles; + + /* Get the private information we need */ + serverClients->ClientEarPosition(pEdict, &eye_position); + if (!GetEyeAngles(pEntity, &eye_angles)) + { + return -2; + } + + Vector aim_dir; + AngleVectors(eye_angles, &aim_dir); + VectorNormalize(aim_dir); + + Vector vec_end = eye_position + aim_dir * 8000; + + Ray_t ray; + ray.Init(eye_position, vec_end); + + trace_t tr; + CTraceFilterSimple simple(pEdict->GetIServerEntity()); + + enginetrace->TraceRay(ray, MASK_SOLID|CONTENTS_DEBRIS|CONTENTS_HITBOX, &simple, &tr); + + if (tr.fraction == 1.0f || tr.m_pEnt == NULL) + { + return -1; + } + + edict_t *pTarget = gameents->BaseEntityToEdict(tr.m_pEnt); + if (pTarget == NULL) + { + return -1; + } + + int ent_index = engine->IndexOfEdict(pTarget); + + IGamePlayer *pTargetPlayer = playerhelpers->GetGamePlayer(ent_index); + if (pTargetPlayer != NULL && !pTargetPlayer->IsInGame()) + { + return -1; + } + else if (params[2] && pTargetPlayer == NULL) + { + return -1; + } + + return ent_index; +} + sp_nativeinfo_t g_Natives[] = { {"ExtinguishPlayer", ExtinguishEntity}, @@ -838,5 +936,6 @@ sp_nativeinfo_t g_Natives[] = {"DispatchKeyValue", DispatchKeyValue}, {"DispatchKeyValueFloat", DispatchKeyValueFloat}, {"DispatchKeyValueVector", DispatchKeyValueVector}, + {"GetClientAimTarget", GetClientAimTarget}, {NULL, NULL}, }; diff --git a/plugins/include/sdktools_functions.inc b/plugins/include/sdktools_functions.inc index 03d637e5..4959ea73 100644 --- a/plugins/include/sdktools_functions.inc +++ b/plugins/include/sdktools_functions.inc @@ -137,16 +137,16 @@ native FindEntityByClassname(startEnt, const String:classname[]); * * @param client Player's index. * @param ang Destination vector to store the client's eye angles. - * @noreturn + * @return True on success, false on failure. * @error Invalid client index, client not in game, or no mod support. */ -native GetClientEyeAngles(client, Float:ang[3]); +native bool:GetClientEyeAngles(client, Float:ang[3]); /** * Returns if the client is alive or dead. * * @param client Player's index. - * @return True if the client is alive, false otherwise. + * @return True if the client is alive, false otherwise. * @error Invalid client index, client not in game, or no mod support. */ native bool:IsPlayerAlive(client); @@ -156,10 +156,10 @@ native bool:IsPlayerAlive(client); * If ForceEdictIndex is not -1, then it will use the edict by that index. If the index is * invalid or there is already an edict using that index, it will error out. * - * @param classname Entity classname. + * @param classname Entity classname. * @param ForceEdictIndex Edict index used by the created entity. - * @return Entity index on success, or -1 on failure. - * @error Invalid edict index, or no mod support. + * @return Entity index on success, or -1 on failure. + * @error Invalid edict index, or no mod support. */ native CreateEntityByName(const String:classname[], ForceEdictIndex=-1); @@ -167,8 +167,8 @@ native CreateEntityByName(const String:classname[], ForceEdictIndex=-1); * Spawns an entity into the game. * * @param entity Entity index of the created entity. - * @return True on success, false otherwise. - * @error Invalid entity index, or no mod support. + * @return True on success, false otherwise. + * @error Invalid entity index, or no mod support. */ native bool:DispatchSpawn(entity); @@ -178,8 +178,8 @@ native bool:DispatchSpawn(entity); * @param entity Destination entity index. * @param keyName Name of the key. * @param value String value. - * @return True on success, false otherwise. - * @error Invalid entity index, or no mod support. + * @return True on success, false otherwise. + * @error Invalid entity index, or no mod support. */ native bool:DispatchKeyValue(entity, const String:keyName[], const String:value[]); @@ -189,8 +189,8 @@ native bool:DispatchKeyValue(entity, const String:keyName[], const String:value[ * @param entity Destination entity index. * @param keyName Name of the key. * @param value Floating point value. - * @return True on success, false otherwise. - * @error Invalid entity index, or no mod support. + * @return True on success, false otherwise. + * @error Invalid entity index, or no mod support. */ native bool:DispatchKeyValueFloat(entity, const String:keyName[], Float:value); @@ -200,11 +200,23 @@ native bool:DispatchKeyValueFloat(entity, const String:keyName[], Float:value); * @param entity Destination entity index. * @param keyName Name of the key. * @param vec Vector value. - * @return True on success, false otherwise. - * @error Invalid entity index, or no mod support. + * @return True on success, false otherwise. + * @error Invalid entity index, or no mod support. */ native bool:DispatchKeyValueVector(entity, const String:keyName[], const Float:vector[3]); +/** + * Returns the entity a client is aiming at. + * + * @param client Client performing the aiming. + * @param only_clients True to exclude all entities but clients. + * @return Entity index being aimed at. + * -1 if no entity is being aimed at. + * -2 if the function is not supported. + * @error Invalid client index. + */ +native GetClientAimTarget(client, bool:only_clients=true); + /** * @deprecated */