CGUnit_C::CalculateThreat menu

User Tag List

Results 1 to 14 of 14
  1. #1
    nitrogrlie's Avatar Member
    Reputation
    11
    Join Date
    Oct 2009
    Posts
    81
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    CGUnit_C::CalculateThreat

    I was playing with the Lua function UnitDetailedThreatSituation (UnitDetailedThreatSituation - World of Warcraft Programming: A Guide and Reference for Creating WoW Addons) for my bot and found it a bit limiting due to the fact that the mob of interest had to be either your target or your focus. I wanted to know my threat with any mob without having to select them in order to determine my threat. So I took a look at the Lua function to find the underlying WoW function that does the calculation.

    Code:
    typedef char __thiscall CGUnit_C__CalculateThreat(void * pThis, WGUID& playerGuid, int& status, int& rawPercentage, float& scaledPercentage, int& threatValue);
    My function wrapping around it
    Code:
    void CGUnit_C::CalculateThreat( WGUID& guid, int& status, float& scaledPercent, int& rawPercent, int& threatValue) {
        typedef char (CGUnit_C::* tCalculateThreat)(WGUID& wguid, int& st, int& rawP, float& scaleP, int& threatV);
        tCalculateThreat oCalculateThreat = 0;
    
        DWORD dwAddr = 0x006CA410;
        memcpy(&oCalculateThreat, &dwAddress, sizeof(DWORD));
    
        (this->oCalculateThreat)(guid, status, rawPercent, scaledPercent, threatValue);
        status -= 1;
    }
    I wrote the above from memory and it's 6:05am here when I got into work so if I mixed up the order of rawPercent and scaledPercent I apologize. I'll post the IDA decompiled version later today when I get home from work.

    The reason I subtract 1 from status is to get it into the same format as the Lua function (which under the hood does exactly the same thing). The only difference between the Lua and the WoW functions is that the WoW one takes a WGUID reference allowing you to essentially check any units threat against another unit/player. Lua's isTanking return value is hardcoded to a 1 or a nil under the hood, which you don't really need if you have the rest of the info.

    CGUnit_C::CalculateThreat
  2. #2
    Robske's Avatar Contributor
    Reputation
    305
    Join Date
    May 2007
    Posts
    1,062
    Thanks G/R
    3/4
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Awesome for the perfectionists amongst us, thanks +rep
    "Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live." - Martin Golding
    "I cried a little earlier when I had to poop" - Sku

  3. #3
    Xarg0's Avatar Member
    Reputation
    61
    Join Date
    Jan 2008
    Posts
    389
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Why don't you use
    Code:
     tCalculateThreat oCalculateThreat = reinterpret_cast<tCalculateThreat>(0x006CA410);
    instead memcpy?
    I hacked 127.0.0.1

  4. #4
    nitrogrlie's Avatar Member
    Reputation
    11
    Join Date
    Oct 2009
    Posts
    81
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Originally Posted by Xarg0 View Post
    Why don't you use
    Code:
     tCalculateThreat oCalculateThreat = reinterpret_cast<tCalculateThreat>(0x006CA410);
    instead memcpy?
    That was my original intention, but MSVC compiler doesn't like that. And gives:
    Code:
    error C2440: 'reinterpret_cast': cannot convert from 'int' to 'tCalculateThreat'

  5. #5
    nitrogrlie's Avatar Member
    Reputation
    11
    Join Date
    Oct 2009
    Posts
    81
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Here is IDA decompilation...

    Code:
    char __thiscall CGUnit_C_CalculateThreat(void *this, int ptrGuid, int status, int rawPercent, int scaledPercent, int threatValue)
    {
      int v6; // eax@1
      int copyV6; // ebx@1
      void *CGUnitObjPtr; // esi@1
      int GuidHigh; // edx@1
      int GuidHigh2; // edi@8
      int v11; // edi@11
      int v12; // eax@12
      char result; // al@17
      char v14; // [sp+Ch] [bp-Ch]@12
      int GuidLow; // [sp+10h] [bp-8h]@1
      int copyGuidHigh; // [sp+14h] [bp-4h]@1
      float v17; // [sp+24h] [bp+Ch]@12
    
      GuidHigh = *(_DWORD *)(ptrGuid + 4);
      CGUnitObjPtr = this;
      GuidLow = *(_DWORD *)ptrGuid;
      copyGuidHigh = GuidHigh;
      v6 = CGUnit_C__GetThreatEntry((int)((char *)this + 4064), GuidLow, (int)&GuidLow);
      copyV6 = v6;
      if ( *((_QWORD *)CGUnitObjPtr + 507) && v6 )
      {
        if ( status )
          *(_BYTE *)status = *(_BYTE *)(v6 + 40);
        if ( rawPercent )
          *(_BYTE *)rawPercent = *(_BYTE *)(v6 + 41);
        if ( scaledPercent )
        {
          GuidHigh2 = *(_DWORD *)(ptrGuid + 4);
          if ( *(_DWORD *)ptrGuid != *((_DWORD *)CGUnitObjPtr + 1014) || GuidHigh2 != *((_DWORD *)CGUnitObjPtr + 1015) )
          {
            v11 = ClntObjMgrObjectPtr(*(_DWORD *)ptrGuid, GuidHigh2, 8);
            if ( v11
              && (v17 = sub_49BCE0(v11 + 208),
                  v12 = (*(int (__thiscall **)(int, char *))(*(_DWORD *)v11 + 40))(v11, &v14),
                  v17 * v17 >= sub_49C170(v12)) )
              *(float *)scaledPercent = (double)*(_BYTE *)(copyV6 + 41) * 0.9090908765792847;
            else
              *(float *)scaledPercent = (double)*(_BYTE *)(copyV6 + 41) * 0.7692307829856873;
          }
          else
          {
            *(float *)scaledPercent = 100.0;
          }
        }
        if ( threatValue )
          *(_DWORD *)threatValue = *(_DWORD *)(copyV6 + 44);
        result = 1;
      }
      else
      {
        if ( status )
          *(_BYTE *)status = v6 != 0;
        if ( rawPercent )
          *(_BYTE *)rawPercent = 0;
        if ( scaledPercent )
          *(float *)scaledPercent = 0.0;
        if ( threatValue )
          *(_DWORD *)threatValue = 0;
        result = 0;
      }
      return result;
    }
    And of the Lua function that got me started on it:
    Code:
    signed int __cdecl lua_UnitDetailedThreatSituation(int LuaStack)
    {
      char *v1; // eax@1
      char *v2; // eax@2
      int CGUnitObjPtr; // edi@3
      signed int result; // eax@9
      int v5; // ST18_4@11
      int ptrGuid; // [sp+10h] [bp-1Ch]@1
      int GuidHigh; // [sp+14h] [bp-18h]@6
      int threatValue; // [sp+18h] [bp-14h]@4
      float scaledPercent; // [sp+1Ch] [bp-10h]@4
      int v10; // [sp+20h] [bp-Ch]@2
      int tankingStatus; // [sp+24h] [bp-8h]@3
      unsigned __int8 rawPercent; // [sp+2Ah] [bp-2h]@4
      unsigned __int8 rawStatus; // [sp+2Bh] [bp-1h]@4
    
      v1 = (char *)FrameScript_ToLString(LuaStack, 1, 0);
      if ( (unsigned __int8)GetGUIDByKeyword(v1, (int)&ptrGuid, 0)
        && (v2 = (char *)FrameScript_ToLString(LuaStack, 2, 0), (unsigned __int8)GetGUIDByKeyword(v2, (int)&v10, 0)) )
      {
        CGUnitObjPtr = ClntObjMgrObjectPtr(v10, tankingStatus, 8);
        if ( CGUnitObjPtr
          && (CGUnit_C_CalculateThreat(
                (void *)CGUnitObjPtr,
                (int)&ptrGuid,
                (int)&rawStatus,
                (int)&rawPercent,
                (int)&scaledPercent,
                (int)&threatValue),
              rawStatus) )
        {
          if ( *(_DWORD *)(CGUnitObjPtr + 4056) != ptrGuid || *(_DWORD *)(CGUnitObjPtr + 4060) != GuidHigh )
            FrameScript_pushnil(LuaStack);
          else
            FrameScript_PushNumber(LuaStack, 1.0);
          tankingStatus = rawStatus - 1;
          FrameScript_PushNumber(LuaStack, (double)tankingStatus);
          FrameScript_PushNumber(LuaStack, scaledPercent);
          tankingStatus = rawPercent;
          FrameScript_PushNumber(LuaStack, (double)rawPercent);
          FrameScript_PushNumber(LuaStack, (double)threatValue);
          result = 5;
        }
        else
        {
          result = 0;
        }
      }
      else
      {
        FrameScript_DisplayError(LuaStack, "Usage: UnitDetailedThreatSituation(\"unit\" [, \"mob\"])", v5);
        result = 0;
      }
      return result;
    }
    Last edited by nitrogrlie; 01-18-2010 at 11:40 AM.

  6. #6
    akh's Avatar Member
    Reputation
    4
    Join Date
    Mar 2008
    Posts
    39
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    This is how I get threat between units:

    Code:
    THREATINFO* CGUnit_C::GetThreatInfo( CGUnit_C *pAttacker )
    {
    	if( !pAttacker )
    		return 0;
    
    	BYTE status, rawThreatPercent;
    	float fThreatPercent;
    	unsigned long dwThreatValue;
    
    	typedef bool ( __thiscall * tGetThreatInfo ) ( CGUnit_C*, WGUID* , BYTE* , BYTE* , float*, unsigned long* );
    	tGetThreatInfo oGetThreatInfo = ( tGetThreatInfo )gpWoWX->GetFindPattern()->GetAddress( "GetThreatInfo" );
    	oGetThreatInfo( this, &pAttacker->GetGuid(), &status , &rawThreatPercent , &fThreatPercent, &dwThreatValue );
    
    	return new THREATINFO( status, rawThreatPercent, fThreatPercent, dwThreatValue );
    }
    More or less the same thing.

  7. #7
    amadmonk's Avatar Active Member
    Reputation
    124
    Join Date
    Apr 2008
    Posts
    772
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Heh, I've been using this function for a while, just to avoid calling a Lua function (although, as you point out, it does exactly the same thing). I don't have to select the unit, because I use other methods to not need to select units when I call UnitXXXX Lua methods.

    The downside with this method is the same downside as the Lua function; it only works for mobs which *you* (the player) have threat with. You simply cannot query the threat of mob X against player Y unless your player ALSO has threat with mob X. The reason is that, as far as I can tell, the server doesn't start sending threat update/threat status packets to your client until you get on the threat list. This makes the threat functions much less useful to multi-bot controllers unless you have all bots merge threat and create a "unified" threat picture (which I'd recommend anyway, this is one of the most important things to do for multi-bot apps). Even then you'll have problems with non-bot friendlies gaining threat, or with pets (since pet aggro doesn't give owner aggro until the owner does damage).

    So, as long as you remember this limitation, it's a useful function
    Last edited by amadmonk; 01-18-2010 at 01:28 PM.
    Don't believe everything you think.

  8. #8
    Nesox's Avatar ★ Elder ★
    Reputation
    1280
    Join Date
    Mar 2007
    Posts
    1,238
    Thanks G/R
    0/3
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

  9. #9
    adaephon's Avatar Active Member
    Reputation
    76
    Join Date
    May 2009
    Posts
    167
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    @amadmonk from memory you'd notice the same thing playing if u have threat info displayed on unit frames: it won't display anything on ur frame until you have done something to get on the unit's threat table

  10. #10
    Cypher's Avatar Kynox's Sister's Pimp
    Reputation
    1358
    Join Date
    Apr 2006
    Posts
    5,368
    Thanks G/R
    0/6
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Originally Posted by nitrogrlie View Post
    That was my original intention, but MSVC compiler doesn't like that. And gives:
    Code:
    error C2440: 'reinterpret_cast': cannot convert from 'int' to 'tCalculateThreat'
    That's because you're using a pointer-to-member typedef.

    Do this instead:

    typedef char (__thiscall* tCalculateThreat)(CGUnit_C* pThis, WGUID& wguid, int& st, int& rawP, float& scaleP, int& threatV);
    Last edited by Cypher; 01-19-2010 at 12:50 AM.

  11. #11
    nitrogrlie's Avatar Member
    Reputation
    11
    Join Date
    Oct 2009
    Posts
    81
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Originally Posted by Cypher View Post
    That's because you're using a pointer-to-member typedef.

    Do this instead:

    typedef char (__thiscall* tCalculateThreat)(CGUnit_C* pThis, WGUID& wguid, int& st, int& rawP, float& scaleP, int& threatV);
    Right, but then I have to pass "this" as an argument which I was trying to avoid. No real reason, just experimenting.

  12. #12
    Cypher's Avatar Kynox's Sister's Pimp
    Reputation
    1358
    Join Date
    Apr 2006
    Posts
    5,368
    Thanks G/R
    0/6
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Originally Posted by nitrogrlie View Post
    Right, but then I have to pass "this" as an argument which I was trying to avoid. No real reason, just experimenting.
    You have to explicitly use 'this' either way, the syntax is just a little different (and the initialization becomes a lot less ugly).

    (this->oCalculateThreat)(guid, status, rawPercent, scaledPercent, threatValue);

    becomes

    oCalculateThreat(this, guid, status, rawPercent, scaledPercent, threatValue);

  13. #13
    amadmonk's Avatar Active Member
    Reputation
    124
    Join Date
    Apr 2008
    Posts
    772
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Originally Posted by adaephon View Post
    @amadmonk from memory you'd notice the same thing playing if u have threat info displayed on unit frames: it won't display anything on ur frame until you have done something to get on the unit's threat table
    Yuppers. This is why the magic function isn't much of an improvement over the Lua version; you don't get any more information and you have to do more work.

    The client simply doesn't *have* that information.
    Don't believe everything you think.

  14. #14
    adaephon's Avatar Active Member
    Reputation
    76
    Join Date
    May 2009
    Posts
    167
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Run ur pr0xeez in ring0 and get threat off the server :-p

All times are GMT -5. The time now is 03:22 AM. Powered by vBulletin® Version 4.2.3
Copyright © 2025 vBulletin Solutions, Inc. All rights reserved. User Alert System provided by Advanced User Tagging (Pro) - vBulletin Mods & Addons Copyright © 2025 DragonByte Technologies Ltd.
Google Authenticator verification provided by Two-Factor Authentication (Free) - vBulletin Mods & Addons Copyright © 2025 DragonByte Technologies Ltd.
Digital Point modules: Sphinx-based search