TraceLine implementation menu

Shout-Out

User Tag List

Results 1 to 8 of 8
  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)

    TraceLine implementation

    This is mostly in reply to the following thread which is now too old for me to reply directly to it: http://www.mmowned.com/forums/wow-me...tersect-2.html

    I've put together the following implementation:
    Code:
    #define ADDR_TRACELINE 0x0077D1A0
    enum eHitType {
    	HIT_NONE = 0x0,
    	HIT_GROUND = 0x1,
    	HIT_OBJECT = 0x2,
    };
    
    #define HIT_LOS 0x100171
    
    unsigned char CActions::TraceLine(WOWPOS &pEnd, WOWPOS &pStart, WOWPOS &pResult, float &fDistance)
    {
    	typedef unsigned char (__cdecl* tTraceLine)(WOWPOS &pointEnd, WOWPOS &pointStart, WOWPOS &pointResult, float &pDistance, unsigned int dwFlag, unsigned int uiOptional);
    	tTraceLine oTraceLine = (tTraceLine)ADDR_TRACELINE;
    
    	return oTraceLine(pEnd, pStart, pResult, fDistance, HIT_LOS, 0);
    }
    With the following use case:
    Code:
    bool CSpellMgr::HasLineOfSight(sSpell * pSpell, WOWPOS * pPos)
    {
    	if( pSpell )
    	{
    		// If the spell has no range... true of self-cast spells
    		if( pSpell->uiMinRange == 0 && pSpell->uiMaxRange == 0 )
    			return true;
    
    		WOWPOS posMe;
    		gpBot->GetCurMgr()->GetLocalPlayer()->GetPosition( &posMe );
    		posMe.Facing = gpBot->GetCurMgr()->GetLocalPlayer()->GetFacing();
    		// Increase our z-axis (height) so we check from top of head, not bottom of feet
    		posMe.Z += gpBot->GetCurMgr()->GetLocalPlayer()->GetHeight();
    
    		DBGLOG( "My Position X: " << posMe.X << ", Y: " << posMe.Y << ", Z: " << posMe.Z );
    
    		if( pPos == NULL )
    		{
    			CGUnit_C * target = gpBot->GetCurMgr()->GetCurrentTarget();
    			if( target == NULL ) 
    			{
    				DBGLOG( "[HasLineOfSight] Spell Check for '" << pSpell->sName << "' attempted but no target!!!" );
    				return false; 
    			}
    
    			pPos = new WOWPOS();
    			target->GetPosition( pPos );
    			pPos->Facing = target->GetFacing();
    			// Increase target's z-axis (height) so we check from top of our head to their's
    			//DBGLOG( "Target's Height: " << target->GetHeight() );
    			pPos->Z += target->GetHeight();
    
    			DBGLOG( "Target Position X: " << pPos->X << ", Y: " << pPos->Y << ", Z: " << pPos->Z );
    		}
    
    		WOWPOS posResult;
    		float  fDistance;
    		eHitType hitResult = (eHitType)gpBot->GetActions()->TraceLine( *pPos, posMe, posResult, fDistance );
    
    		DBGLOG( "[HasLineOfSight] 0x" << std::hex << hitResult << std::dec << " " << fDistance << " yards away!" );
    		DBGLOG( "[HasLineOfSight] pResult X: " << posResult.X << ", Y: " << posResult.Y << ", Z: " << posResult.Z );
    
    		if( HIT_NONE == hitResult )
    		{
    			return true;
    		}
    		else if( HIT_OBJECT == hitResult )
    		{
    			//DBGLOG( "[HasLineOfSight] Check failed due to hitting an object " << fDistance << " yards away!" );
    			return false;
    		}
    		else if( HIT_GROUND == hitResult )
    		{
    			//DBGLOG( "[HasLineOfSight] Check failed due to hitting the ground " << fDistance << " yards away!" );
    			return false;
    		}
    		else 
    		{
    			//DBGLOG( "[HasLineOfSight] Check failed due to 0x" << std::hex << hitResult << std::dec << " " << fDistance << " yards away!" );
    			return false;
    		}
    	}
    	return false;
    }
    When casting at a target behind a wall of a building I get the following log message:
    Code:
    [696901184] :: My Position X: 1923.74, Y: 1546.27, Z: 89.3905
    [696901184] :: Target Position X: 1939.89, Y: 1545.96, Z: 92.1927
    [696901184] :: [HasLineOfSight] 0x0 2.40741E-035 yards away!
    [696901184] :: [HasLineOfSight] pResult X: 0, Y: 0, Z: 0
    [696901184] :: Casting: CastSpellByName("Immolate") [Rank 1]
    [696901376] :: [EVENT]: 'UI_ERROR_MESSAGE' 'Target not in line of sight'
    So clearly something isn't working. Any chance for some help?

    TraceLine implementation
  2. #2
    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)
    It might be that the flags passed to the TraceLine function is wrong. I suspect that you might test for intersection with your own playermodel and get the intersection distance to be 2.40741E-035 yards.

    I use these flags when I test for LoS between units: 0x100151
    Last edited by akh; 01-22-2010 at 05:14 PM.

  3. #3
    MaiN's Avatar Elite User
    Reputation
    335
    Join Date
    Sep 2006
    Posts
    1,047
    Thanks G/R
    0/10
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Your WOWPOS is wrong. It should be a vector 3 with 3 units:
    struct WOWPOS
    {
    float X;
    float Y;
    float Z;
    }

    I see your "Facing" field in there, and that will definitely screw it up.

    Edit: Depends on if the gpBot->GetActions()->TraceLine is just another wrapper.

    Also, TraceLine returns a boolean; true for intersection, false for no hit.

    Code:
    // Thanks to Apoc.
    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
    private delegate byte TraceLineDelegate(ref WoWPoint start, ref WoWPoint end, ref WoWPoint hitPoint, ref float distance, uint flag, uint optional);
    
    private static readonly TraceLineDelegate TraceLineHandler = Magic.Instance.RegisterDelegate<TraceLineDelegate>(Offsets.TraceLine);
    
    public static bool TraceLine(WoWPoint start, WoWPoint end, CGWorldFrameHitFlags hitFlags, out WoWPoint intersectionPoint, out float completedBeforeIntersection)
    {
        completedBeforeIntersection = 1;
        intersectionPoint = new WoWPoint();
        byte traceLine = TraceLineHandler(ref start, ref end, ref intersectionPoint, ref completedBeforeIntersection, (uint)hitFlags, 0);
        if (traceLine != 0 && traceLine != 1)
        {
            Logging.Write("Traceline {0:L} {1:L} {2} didn't return 0 or 1! Returned {3}", start, end, hitFlags, traceLine);
        }
        bool retn = Convert.ToBoolean(traceLine);
        completedBeforeIntersection *= 100;
        return retn;
    }
    Here are the hit flags:

    Code:
    [Flags]
    public enum CGWorldFrameHitFlags : uint
    {
        HitTestNothing = 0x0,
        /// <summary>
        /// Models' bounding, ie. where you can't walk on a model. (Trees, smaller structures etc.)
        /// </summary>
        HitTestBoundingModels = 0x1,
        /// <summary>
        /// Structures like big buildings, Orgrimmar etc.
        /// </summary>
        HitTestWMO = 0x10,
        /// <summary>
        /// Used in ClickTerrain.
        /// </summary>
        HitTestUnknown = 0x40,
        /// <summary>
        /// The terrain.
        /// </summary>
        HitTestGround = 0x100,
        /// <summary>
        /// Tested on water - should work on lava and other liquid as well.
        /// </summary>
        HitTestLiquid = 0x10000,
        /// <summary>
        /// This flag works for liquid as well, but it also works for something else that I don't know (this hit while the liquid flag didn't hit) - called constantly by WoW.
        /// </summary>
        HitTestUnknown2 = 0x20000,
        /// <summary>
        /// Hits on movable objects - tested on UC elevator doors.
        /// </summary>
        HitTestMovableObjects = 0x100000,
    
        HitTestLOS = HitTestWMO | HitTestBoundingModels | HitTestMovableObjects,
        HitTestGroundAndStructures = HitTestLOS | HitTestGround
    }

    EDIT 2: Your problem is that you're passing 0 as the fDistance. Always pass 1.
    It seems to be a way to limit the length of the traceline. If you pass 0,0,0 and 100, 100, 100 and then 0.5 as the distance, it will only traceline from 0,0,0 to 50,50,50 (is my guess).

    Edit 3: To clarify, after the method is done, the fDistance (which should be passed as a float pointer) contains the percent it reached before intersection. 0.5 means it was half done with the line when it hit something.
    Last edited by MaiN; 01-22-2010 at 05:12 PM.
    [16:15:41] Cypher: caus the CPU is a dick
    [16:16:07] kynox: CPU is mad
    [16:16:15] Cypher: CPU is all like
    [16:16:16] Cypher: whatever, i do what i want

  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 MaiN View Post
    Your WOWPOS is wrong. It should be a vector 3 with 3 units:
    struct WOWPOS
    {
    float X;
    float Y;
    float Z;
    }

    I see your "Facing" field in there, and that will definitely screw it up.
    This shouldn't matter as you pass it by reference, I allocate the space for what it fills out, as long as what I pass is big enough, who cares if it has 1 billion extra bytes of space. Having 4 floats versus 3 floats won't break it.

    Originally Posted by MaiN View Post
    Edit: Depends on if the gpBot->GetActions()->TraceLine is just another wrapper.
    My code paste included the implementation of what it was, a wrapper around the actual code.

    Originally Posted by MaiN View Post
    Also, TraceLine returns a boolean; true for intersection, false for no hit.
    From my investigation of the WoW-Alpha client it returns an enum, not a boolean. But playing with it some more it seems you are probably right.

    Originally Posted by MaiN View Post
    EDIT 2: Your problem is that you're passing 0 as the fDistance. Always pass 1.
    [/B]It seems to be a way to limit the length of the traceline. If you pass 0,0,0 and 100, 100, 100 and then 0.5 as the distance, it will only traceline from 0,0,0 to 50,50,50 (is my guess).

    Edit 3: To clarify, after the method is done, the fDistance (which should be passed as a float pointer) contains the percent it reached before intersection. 0.5 means it was half done with the line when it hit something.
    Thank you, that was indeed my problem. +rep

  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)
    Also, since you need to increment the Z-axis by the model height's for accurate LoS here is the code I use:

    Code:
    float CGUnit_C::GetHeight() {
    	return *(float*)((char*)this + 0x854);
    }

  6. #6
    MaiN's Avatar Elite User
    Reputation
    335
    Join Date
    Sep 2006
    Posts
    1,047
    Thanks G/R
    0/10
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Originally Posted by nitrogrlie View Post
    This shouldn't matter as you pass it by reference, I allocate the space for what it fills out, as long as what I pass is big enough, who cares if it has 1 billion extra bytes of space. Having 4 floats versus 3 floats won't break it.
    Of course it shouldn't, but it's still stupid to allocate the extra bytes. And I couldn't know if you had it as X Y Z Facing or Facing X Y Z. The latter obviously wouldn't work.
    Originally Posted by nitrogrlie View Post
    From my investigation of the WoW-Alpha client it returns an enum, not a boolean. But playing with it some more it seems you are probably right.
    Then again, the alpha client is almost 7 years old.
    You are right, at that time it returned an enum, and those flags were right at that time, but it has all updated. It returns a bool, and the flags have also updated quite a bit.
    [16:15:41] Cypher: caus the CPU is a dick
    [16:16:07] kynox: CPU is mad
    [16:16:15] Cypher: CPU is all like
    [16:16:16] Cypher: whatever, i do what i want

  7. #7
    vulcanaoc's Avatar Member
    Reputation
    31
    Join Date
    Jul 2008
    Posts
    125
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Anyone tried using TraceLine for pathfinding?

    It's a bitch.

  8. #8
    namreeb's Avatar Legendary

    Reputation
    668
    Join Date
    Sep 2008
    Posts
    1,029
    Thanks G/R
    8/222
    Trade Feedback
    0 (0%)
    Mentioned
    9 Post(s)
    Tagged
    0 Thread(s)
    We use it to correct rounding errors returned from our mesh. Our Z values seldom land precisely at the level of the terrain.

Similar Threads

  1. How do I implement a db
    By mtdewrush in forum WoW EMU Questions & Requests
    Replies: 2
    Last Post: 05-05-2009, 07:28 PM
  2. Implement wowhead item tooltips/mouseovers
    By mudfish in forum Suggestions
    Replies: 4
    Last Post: 12-21-2008, 06:46 AM
  3. implementing ~T6 lock wings~
    By fame22 in forum WoW ME Questions and Requests
    Replies: 3
    Last Post: 09-22-2007, 05:10 AM
  4. Player housing will be implemented!
    By Rekei in forum World of Warcraft General
    Replies: 6
    Last Post: 06-16-2007, 01:52 PM
All times are GMT -5. The time now is 10:34 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