1.1 --- a/extensions/tf2/conditions.cpp Wed Jul 06 15:30:19 2011 -0400
1.2 +++ b/extensions/tf2/conditions.cpp Wed Jul 06 17:37:35 2011 -0400
1.3 @@ -33,125 +33,93 @@
1.4 #include "conditions.h"
1.5 #include "util.h"
1.6
1.7 -typedef int condflags_t;
1.8 -#define CONDITION_TAUNTING 7
1.9 +#include <iplayerinfo.h>
1.10 +
1.11 +typedef uint64_t condflags_t;
1.12 +
1.13 +condflags_t g_PlayerConds[MAXPLAYERS+1];
1.14
1.15 IForward *g_addCondForward = NULL;
1.16 IForward *g_removeCondForward = NULL;
1.17
1.18 -CDetour *detConditionAdd = NULL;
1.19 -CDetour *detConditionRemove = NULL;
1.20 -CDetour *detConditionRemoveAll = NULL;
1.21 -
1.22 int playerCondOffset = -1;
1.23 +int playerCondExOffset = -1;
1.24 int conditionBitsOffset = -1;
1.25
1.26 bool g_bIgnoreRemove;
1.27
1.28 inline condflags_t GetPlayerConds(CBaseEntity *pPlayer)
1.29 {
1.30 - condflags_t cond1 = *(condflags_t *)((intptr_t)pPlayer + playerCondOffset);
1.31 - condflags_t cond2 = *(condflags_t *)((intptr_t)pPlayer + conditionBitsOffset);
1.32 - return cond1|cond2;
1.33 -}
1.34 -
1.35 -DETOUR_DECL_MEMBER2(AddCond, void, int, condition, float, duration)
1.36 -{
1.37 - CBaseEntity *pPlayer = (CBaseEntity *)((intptr_t)this - playerSharedOffset->actual_offset);
1.38 - condflags_t oldconds = GetPlayerConds(pPlayer);
1.39 -
1.40 - DETOUR_MEMBER_CALL(AddCond)(condition, duration);
1.41 -
1.42 - int bit = 1 << condition;
1.43 + uint32_t playerCond = *(uint32_t *)((intptr_t)pPlayer + playerCondOffset);
1.44 + uint32_t condBits = *(uint32_t *)((intptr_t)pPlayer + conditionBitsOffset);
1.45 + uint32_t playerCondEx = *(uint32_t *)((intptr_t)pPlayer + playerCondExOffset);
1.46
1.47 - // The player already had this condition so bug out
1.48 - if ((oldconds & bit) == bit)
1.49 - return;
1.50 + uint64_t playerCondExAdj = playerCondEx;
1.51 + playerCondExAdj <<= 32;
1.52
1.53 - // The condition wasn't actually added (this can happen!)
1.54 - if ((GetPlayerConds(pPlayer) & bit) != bit)
1.55 - return;
1.56 -
1.57 - int client = gamehelpers->EntityToBCompatRef(pPlayer);
1.58 -
1.59 - g_addCondForward->PushCell(client);
1.60 - g_addCondForward->PushCell(condition);
1.61 - g_addCondForward->PushFloat(duration);
1.62 - g_addCondForward->Execute(NULL, NULL);
1.63 + return playerCond|condBits|playerCondExAdj;
1.64 }
1.65
1.66 -DETOUR_DECL_MEMBER2(RemoveCond, void, int, condition, bool, bForceRemove)
1.67 +void Conditions_OnGameFrame(bool simulating)
1.68 {
1.69 - if (g_bIgnoreRemove)
1.70 - {
1.71 - DETOUR_MEMBER_CALL(RemoveCond)(condition, bForceRemove);
1.72 + if (!simulating)
1.73 return;
1.74 - }
1.75
1.76 - CBaseEntity *pPlayer = (CBaseEntity *)((intptr_t)this - playerSharedOffset->actual_offset);
1.77 + condflags_t oldconds;
1.78 + condflags_t newconds;
1.79 +
1.80 + condflags_t addedconds;
1.81 + condflags_t removedconds;
1.82
1.83 - condflags_t oldconds = GetPlayerConds(pPlayer);
1.84 - int bit = 1 << condition;
1.85 -
1.86 - // If we didn't have it, it won't be removed
1.87 - if ((oldconds & bit) != bit)
1.88 + int maxClients = gpGlobals->maxClients;
1.89 + for (int i = 1; i <= maxClients; i++)
1.90 {
1.91 - DETOUR_MEMBER_CALL(RemoveCond)(condition, bForceRemove);
1.92 - return;
1.93 - }
1.94 + IGamePlayer *pPlayer = playerhelpers->GetGamePlayer(i);
1.95 + if (!pPlayer || !pPlayer->IsInGame())
1.96 + continue;
1.97 +
1.98 + IPlayerInfo *info = pPlayer->GetPlayerInfo();
1.99 + if (info->IsHLTV() || info->IsReplay())
1.100 + continue;
1.101
1.102 - DETOUR_MEMBER_CALL(RemoveCond)(condition, bForceRemove);
1.103 + CBaseEntity *pEntity = gamehelpers->ReferenceToEntity(i);
1.104 + oldconds = g_PlayerConds[i];
1.105 + newconds = GetPlayerConds(pEntity);
1.106 +
1.107 + if (oldconds == newconds)
1.108 + continue;
1.109 +
1.110 + addedconds = newconds &~ oldconds;
1.111 + removedconds = oldconds &~ newconds;
1.112 +
1.113 + int j;
1.114 + condflags_t bit;
1.115
1.116 - // Calling RemoveCond doesn't necessarily remove the cond...
1.117 - if ((GetPlayerConds(pPlayer) & bit) == bit)
1.118 - {
1.119 - return;
1.120 + for (j = 0; (bit = ((condflags_t)1 << j)) <= addedconds; j++)
1.121 + {
1.122 + if ((addedconds & bit) == bit)
1.123 + {
1.124 + g_addCondForward->PushCell(i);
1.125 + g_addCondForward->PushCell(j);
1.126 + g_addCondForward->Execute(NULL, NULL);
1.127 + }
1.128 + }
1.129 +
1.130 + for (j = 0; (bit = ((condflags_t)1 << j)) <= removedconds; j++)
1.131 + {
1.132 + if ((removedconds & bit) == bit)
1.133 + {
1.134 + g_removeCondForward->PushCell(i);
1.135 + g_removeCondForward->PushCell(j);
1.136 + g_removeCondForward->Execute(NULL, NULL);
1.137 + }
1.138 + }
1.139 +
1.140 + g_PlayerConds[i] = newconds;
1.141 }
1.142 -
1.143 - int client = gamehelpers->EntityToBCompatRef(pPlayer);
1.144 -
1.145 - DoRemoveCond(client, condition);
1.146 }
1.147
1.148 -DETOUR_DECL_MEMBER1(RemoveAllCond, void, CBaseEntity *, unknown)
1.149 -{
1.150 - // We're going to ignore Remove here since it can be called multiple times for the same cond
1.151 - g_bIgnoreRemove = true;
1.152 -
1.153 - CBaseEntity *pPlayer = (CBaseEntity *)((intptr_t)this - playerSharedOffset->actual_offset);
1.154 -
1.155 - int client = gamehelpers->EntityToBCompatRef(pPlayer);
1.156 - condflags_t conds = GetPlayerConds(pPlayer);
1.157 -
1.158 - // I don't know what the unknown is, but it's always NULL
1.159 - DETOUR_MEMBER_CALL(RemoveAllCond)(unknown);
1.160 -
1.161 - int max = sizeof(condflags_t)*8;
1.162 - for (int i = 0; i < max; i++)
1.163 - {
1.164 - // Taunt flag removal doesn't go through RemoveCond nor OnCondRemoved (or was mangled by compiler?)
1.165 - // Better to "documentedly" give no removes rather than only in some cases
1.166 - if (i == CONDITION_TAUNTING)
1.167 - continue;
1.168 -
1.169 - int bit = (1<<i);
1.170 - if ((conds & bit) == bit)
1.171 - {
1.172 - DoRemoveCond(client, i);
1.173 - }
1.174 - }
1.175 -
1.176 - g_bIgnoreRemove = false;
1.177 -}
1.178 -
1.179 -void DoRemoveCond(int client, int condition)
1.180 -{
1.181 - g_removeCondForward->PushCell(client);
1.182 - g_removeCondForward->PushCell(condition);
1.183 - g_removeCondForward->Execute(NULL, NULL);
1.184 -}
1.185 -
1.186 -bool InitialiseConditionDetours()
1.187 +bool InitialiseConditionChecks()
1.188 {
1.189 sm_sendprop_info_t prop;
1.190 if (!gamehelpers->FindSendPropInfo("CTFPlayer", "m_nPlayerCond", &prop))
1.191 @@ -170,41 +138,39 @@
1.192
1.193 conditionBitsOffset = prop.actual_offset;
1.194
1.195 - if (playerCondOffset == -1 || conditionBitsOffset == -1)
1.196 + if (!gamehelpers->FindSendPropInfo("CTFPlayer", "m_nPlayerCondEx", &prop))
1.197 + {
1.198 + g_pSM->LogError(myself, "Failed to find m_nPlayerCondEx prop offset");
1.199 return false;
1.200 + }
1.201 +
1.202 + playerCondExOffset = prop.actual_offset;
1.203
1.204 - detConditionAdd = DETOUR_CREATE_MEMBER(AddCond, "AddCondition");
1.205 - if (detConditionAdd == NULL)
1.206 + if (playerCondOffset == -1 || playerCondExOffset == -1 || conditionBitsOffset == -1)
1.207 + return false;
1.208 +
1.209 + int maxClients = gpGlobals->maxClients;
1.210 + for (int i = 1; i <= maxClients; i++)
1.211 {
1.212 - g_pSM->LogError(myself, "CTFPlayerShared::AddCond detour failed");
1.213 - return false;
1.214 + IGamePlayer *pPlayer = playerhelpers->GetGamePlayer(i);
1.215 + if (!pPlayer || !pPlayer->IsInGame())
1.216 + continue;
1.217 +
1.218 + g_PlayerConds[i] = GetPlayerConds(gamehelpers->ReferenceToEntity(i));
1.219 }
1.220
1.221 - detConditionRemove = DETOUR_CREATE_MEMBER(RemoveCond, "RemoveCondition");
1.222 - if (detConditionRemove == NULL)
1.223 - {
1.224 - g_pSM->LogError(myself, "CTFPlayerShared::RemoveCond detour failed");
1.225 - return false;
1.226 - }
1.227 -
1.228 - detConditionRemoveAll = DETOUR_CREATE_MEMBER(RemoveAllCond, "RemoveAllConditions");
1.229 - if (detConditionRemoveAll == NULL)
1.230 - {
1.231 - g_pSM->LogError(myself, "CTFPlayerShared::RemoveAllCond detour failed");
1.232 - return false;
1.233 - }
1.234 -
1.235 - detConditionAdd->EnableDetour();
1.236 - detConditionRemove->EnableDetour();
1.237 - detConditionRemoveAll->EnableDetour();
1.238 + g_pSM->AddGameFrameHook(Conditions_OnGameFrame);
1.239
1.240 return true;
1.241 }
1.242
1.243 -void RemoveConditionDetours()
1.244 +void Conditions_OnClientPutInServer(int client)
1.245 {
1.246 - detConditionAdd->Destroy();
1.247 - detConditionRemove->Destroy();
1.248 - detConditionRemoveAll->Destroy();
1.249 + g_PlayerConds[client] = 0;
1.250 }
1.251
1.252 +void RemoveConditionChecks()
1.253 +{
1.254 + g_pSM->RemoveGameFrameHook(Conditions_OnGameFrame);
1.255 +}
1.256 +