• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

UnitAlive issue...

Status
Not open for further replies.
Level 29
Joined
Mar 10, 2009
Messages
5,016
I have issues with UnitAlive:

method #1
native UnitAlive takes unit u returns boolean

method #2
JASS:
function UnitAlive takes unit u returns boolean
   return not IsUnitType(u,UNIT_TYPE_DEAD)
endmethod

I used method #2 in my system http://www.hiveworkshop.com/forums/spells-569/summonedescort-v1-4-a-221902/?prev=r=20&page=2 and doesnt work if I dont add and u!=null

On the other hand method 1 works...the 2 methods suppose to work the same, my question is why?...

#1 is hardcoded and maybe the setup is like this?
return not IsUnitType(u,UNIT_TYPE_DEAD) and u!=null
 
Level 17
Joined
Apr 27, 2008
Messages
2,455
It's quite obvious, a null, or let's say on a general manner an invalid unit can't be considered by a native jass function, then both UnitAlive and IsUnitType... return false, but you use a not with the IsUnitType function, and "not false" -> "true".
Also the check != null is not enough with ghost units, a better one is GetUnitTypeId(< unit >) != 0
 
Level 17
Joined
Apr 27, 2008
Messages
2,455
Ive tested it with some instances and they both work the same way, without the and u!=null in method #2, its really
weird that it doesnt work on the map that I give, if you have time to test that, you will see what I exactly mean...
when unit is 'really' alive, #1 returns true while #2 returns false, idk why...

Wait, you're so confusing.

So what ? #2 doesn't work with invalid units if you don't add an extra check like and GetUnitTypeId(u) != 0 ?
As said, this is intended.
AFAIK all native jass functions return the default value if you use an invalid argument, since here the returned value is a boolean, then it's false for these both functions.
But "not false" == "true", hence the reason of the behavior.

Now plz elaborate if it's not the case, a demo script is enough, no need of a whole map.
Because the error is coming most likely from yourself, even if there is still the chance for a new jass bug, it's however very unlikely.
Then we can catch it with a simple web browser without wc3 installed, and if we want to test it we just have to copy/paste in a new map anyway.
 
Level 17
Joined
Apr 27, 2008
Messages
2,455
The problem is that i don't have wc3 installed, and again the error is most likely from you, hence the reason why i ask a script, now if you're confident about yourself maybe someone else will download the map *shrugs*

You've put some debug messages to ensure the unit is a valid one ?

Oh and btw i don't remember how units which are being resurrected are considered by these functions, i guess they are considered to be alive.
 
Level 29
Joined
Mar 10, 2009
Messages
5,016
You dont need a WC3 coz the map is in the spell's section and the script is posted there...

ATM, the script is like this:
#1 return not IsUnitType(u,UNIT_TYPE_DEAD) and u!=null, and works perfectly

But when I just do like this:
#2 return not IsUnitType(u,UNIT_TYPE_DEAD), it doesnt

I wanna know why coz the native suppose to work the same as #2...

Magtheridon96 said:
You don't need the native declaration because Bribe confirmed that UnitAlive returns the same thing as (not IsUnitType(u, UNIT_TYPE_DEAD)).
I've proven in many ways that the above quote is true...

But why is it false in the map I posted above?...

EDIT:
Im sorry to bother anybody's time...If this can't be answered then I'll let it be...and BTW I put a debug messages and unit returns null...
 
Level 26
Joined
Aug 18, 2009
Messages
4,097
Null units do not possess types. Therefore, IsUnitType will return false when asked for deadness.

You stated however that it does not work on existing, alive units. Maybe it is about the IsUnitType bug I heard of before that could return a false value when being directly placed as a return value of a filter function. I suspect that it would even work if you wrote return not IsUnitType(u, UNIT_TYPE_DEAD) and true.
 
Level 17
Joined
Apr 27, 2008
Messages
2,455
Then read me again, i'ts pretty logical that not IsUnitType(u, UNIT_TYPE_DEAD) returns true with an invalid unit (null or not).
Your quote is incorrect, Bribe is wrong.

And again the check "!= null " could be not enough if you can have ghost units (unit removed of the game but the variable is not nulled).
Now if you use this function only with ForForce and GroupEnum then this check is enough, since there is no way that you will got a ghost unit.
 
Level 29
Joined
Mar 10, 2009
Messages
5,016
Null units do not possess types. Therefore, IsUnitType will return false when asked for deadness.
Yes I know and I tested on to those and works perfectly, I'm reffering to unit is alive (or not null), still returns a null unit in
the map above, if that's a bug then Ima leave it be as we cant do anything about it except to add another
'and' to the condition...also I dont need to add 'true' coz the UnitType(if there is) is already true...

@Troll
The 2 methods works the same with 99.9% of all my tests, the other 0.1% is from the map I posted above
and the ghost units you mentioned which I havent tested...
So Bribe should not be wrong and maybe WaterKnight is correct, it's a bug...
 
Level 26
Joined
Aug 18, 2009
Messages
4,097
I said to add "and true" to correct the bug, because as it was described back then, IsUnitType would not return a proper boolean value. Booleans are afaik stored as a byte although only representing true/false. IsUnitType maybe returned a weird format which would however been fixed by "== true" or other links. I do not find the original description of the bug now but here they said it should be fixed.
 
Level 29
Joined
Mar 10, 2009
Messages
5,016
You did not see coz the structure is not like what you see in the script above (method #2)...

The map contains like this (different from method #2)...
JASS:
private static method UnitAlive takes unit u returns boolean
   return not IsUnitType(u,UNIT_TYPE_DEAD) and u!=null
endmethod
remove the and u!=null and it will not work...but the native UnitAlive works perfectly...
 
Level 17
Joined
Apr 27, 2008
Messages
2,455
Well, just tested and all i've said is true ...

JASS:
scope Test initializer init

    native UnitAlive takes unit u returns boolean
    
    function B2S takes boolean b returns string
        if b then
            return "TRUE"
        endif
        return "FALSE"
    endfunction
    
    function IsUnitAlive takes unit u returns boolean
        return not IsUnitType(u,UNIT_TYPE_DEAD)
    endfunction

    private function init takes nothing returns nothing
        local unit u = CreateUnit(Player(0),'hpea',0,0,0)
        call RemoveUnit(u)
        call TriggerSleepAction(0) // because removing an unit is not instant
        call BJDebugMsg(B2S(UnitAlive(null)))
        call BJDebugMsg(B2S(IsUnitAlive(null)))
        call BJDebugMsg(B2S(UnitAlive(u)))
        call BJDebugMsg(B2S(IsUnitAlive(u)))
    endfunction
    
endscope
As expected it displays :

FALSE
TRUE
FALSE
TRUE

Now, add the check GetUnitTypeId(u) != 0 in the IsUnitAlive function and it will return false.

So yes Bribe was wrong.
Again that makes sense, read what i've said before.

Btw i've removed the extra check and u != null in the Summoned escort map, and it works just fine.
And it makes sense coz there is no way that you could have an invalid unit since they are used with GroupEnum filters.

EDIT :

Since the GetClosestWidget library use this fugly bj_lastCreatedGroup variable, instead of its own, make sure this variable always point to a valid group.
 
Level 17
Joined
Apr 27, 2008
Messages
2,455
1- Did you remove the native?
2- Cast infernal, it will follow you and kill the dreadlord while battling the golem

1) I can't remove something which is not there.
2) And what's supposed to do ?
After the hero resurrection, the infernal still follow the dreadlord.

Well, i'm done with it, you're just way too much inaccurate (euphemism), i'm bored.
 
Level 29
Joined
Mar 10, 2009
Messages
5,016
1- well you posted in your test code so I assumed that you posted in mine also...
2- No it will not, also before it ressurect, it supppose to follow another hero but not, if I put the native instead of method#2, it works perfect...

There's no inaccuracy there, from what I see, this is a bug and cannot be answered atm...This thread should be closed...
 
Level 26
Joined
Aug 18, 2009
Messages
4,097
Yes, you are inaccurate: you did not tell how to exactly track the problem, which actions we should execute, what falsely should happen. And how should we know method #1, which is not an actual native function, and you removed it from the map.

When I said I tested the issue in your map, of course I deleted the "unit != null" part since this was the sole input you gave next to that it would return false otherwise for an alive unit. Still, there was no visible difference to be spotted, which is why I asked how to reconstruct it.

Just upload a map that already contains the bug in a simplified scenario.
 
Level 29
Joined
Mar 10, 2009
Messages
5,016
Yes, you are inaccurate: you did not tell how to exactly track the problem
sorry, I thought the code was inaccurate, not my explanation...anyway here's how to track the problem:
1- Remove the 'and u != null'
2- Cast infernal or Waterelemental or Ferral spirit away from other heroes, probably at far bottom of the map
3- Kill the hero using your summoned unit
4- When hero dies, the summoned unit follows a new hero (if that hero is nearby)

now, method #1 (the native) works perfect, method #2 does not, why?, I really dont know coz many of my tests,
both methods works the same like Troll-Brain's sample code on post#15...

I hopw you got it now, btw if nobody answers this, then I'll leave it be...thanks!
 
Level 17
Joined
Apr 27, 2008
Messages
2,455
Hmm.
Alrighty then, UnitAlive it is o_O

Thank you for your time Troll-Brain.

Importing a whole common.j to avoid an extra check and GetUnitTypeId(u) != 0.

Speedfreak and overkill : 1
Wisdom: 0

@Mckill2009 : You see when you want ...
However, i still can't reproduce the trouble, but i've noticed some wrong things in your methods.
First you don't use the index 0 of the array, yes that doesn't really matter i know.
But much worse, in your method looper even if you have 0 instance, the loop will still fire once, and you set insAR[instance] to this instead of 0.
It could be the source of the bug, using the instance 0, with null unit members. (i'm only guessing)

Using the index 0 or not of an array is not really something important, excepted probably with small sized array (struct member or dynamic array).
But it's definetely a good practice to make the loop not run if it's not needed, in other words place the exitwhen in the very first loop body lines, and make sure the condition for the exitwhen will be valid for an empty loop.

So try if with the suggestions below, the problem is fixed or not :

JASS:
private static method create takes unit summoningUnit, unit summonedUnit returns thistype
...
     set insAR[instance] = this
     set instance = instance + 1
...
endmethod
JASS:
private static method looper takes nothing returns nothing
...
        local integer index = instance
...
        loop
        exitwhen index == 0
            set index = index-1
            set this = insAR[index]
...
                call .destroy()
                set instance = instance - 1
                set insAR[index] = insAR[instance]
                set insAR[instance] = 0 // even if this last one is not really needed i suppose it still should be done
...
endmethod
 
Level 17
Joined
Apr 27, 2008
Messages
2,455
It does matter since the IsUnitType way does work if you add "u != null", so it means that sometimes you handle a null unit, as shown in your replay.

The suggestions i have said could fix it, they are not random ones.
So if you don't care to test it we can't do anything more to you ...
 
Level 17
Joined
Apr 27, 2008
Messages
2,455
I've found the problem, somewhere in the looper method there is a thread crash or something like that, because of one (or more) variable not initialized.
I've fixed the bug simply by given to locals variables a default value.
And yes ofc i have not used the native function UnitAlive, but only IsUnitType... without any extra check.
It's just a good practice to always use a default value for variables anyway.
As expected the only bug there is yourself :p

Also plz next time use some empty lines for block of codes, such as "if" and "loops", like i did, it just makes it much more readable.

Here is my full edited code :

JASS:
    private static method looper takes nothing returns nothing
        local thistype this
        local unit target = null
        local integer orderSum = 0
        local integer index = instance
        local real angle = 0
        local real xMaster = 0
        local real yMaster = 0
        local real xSummoned = 0
        local real ySummoned = 0
        
        loop
        exitwhen index == 0
        set index = index-1
        
            set this = insAR[index]
            
            if UnitAlive(.sum) then
            
                set angle = GetRandomReal(0,6.28)
                set orderSum = GetUnitCurrentOrder(.sum)
                
                if UnitAlive(.master) then
                
                    if orderSum==0 then
                    
                        set xMaster = GetUnitX(.master)+OFFSET*Cos(angle)
                        set yMaster = GetUnitY(.master)+OFFSET*Sin(angle)
                        call IssuePointOrderById(.sum,ATTACK,xMaster,yMaster)
                        set DATA = this
                        set target = GetClosestUnitInRange(xMaster,yMaster,CLOSEST_ENEMY,Filter(function thistype.closestEnemy))
                        
                        if target!=null then
                        
                            if IsUnitType(target,UNIT_TYPE_SLEEPING) then
                                call IssueTargetOrderById(.sum,ATTACK,target)
                            else
                                call IssuePointOrderById(.sum,ATTACK,GetUnitX(target),GetUnitY(target))
                            endif
                            set target = null
                            
                        endif
                        
                    endif
                    
                else
                
                    set DATA = this
                    set xSummoned = GetUnitX(.sum)
                    set ySummoned = GetUnitY(.sum)
                    static if ALLY_IN_RANGE then
                        set .master = GetClosestUnitInRange(xSummoned,ySummoned,CLOSEST_ALLY,Filter(function thistype.closestAlly))
                    else
                        set .master = GetClosestUnit(xSummoned,ySummoned,Filter(function thistype.closestAlly))   
                    endif
                    if .master==null and orderSum==0 then
                        call IssuePointOrderById(.sum,ATTACK,.xUnit+OFFSET*Cos(angle),.yUnit+OFFSET*Sin(angle))
                    endif
                    
                endif
                
            else
            
                call .destroy()
                set instance = instance - 1
                set insAR[index] = insAR[instance]
                set insAR[instance] = 0
                
                if instance==0 then
                    call PauseTimer(t)
                endif
                
            endif 
            
        endloop
    endmethod   
    
    private static method create takes unit summoningUnit, unit summonedUnit returns thistype
        local thistype this = 0
        if instance==8190 then
            call BJDebugMsg("summoned ERROR: Too many instances!")
        else
            set this = allocate()
            set .master = summoningUnit
            set .sum = summonedUnit
            set .xUnit = GetUnitX(summonedUnit)
            set .yUnit = GetUnitY(summonedUnit)
            if instance==0 then
                call TimerStart(t,1.0,true,function thistype.looper)
            endif
            set insAR[instance] = this
            set instance = instance + 1
            call RemoveGuardPosition(summonedUnit)
        endif
        return this
    endmethod
 
Level 29
Joined
Mar 10, 2009
Messages
5,016
As expected the only bug there is yourself :p

Before I left home I tested your code and here's the video...

Still doesnt work if I remove the and u != null...I really dont mind to make an extra check but it brings back to my original question, why?

If you really are persistent or not in finding the said 'bug' then I thank you very much and sorry for the waste of time I gave to you...

You dont need to reply this as I have said it before, Ima let it be even if no answers are available, except that bug Waterknight mentioned...

EDIT:
In the video btw I added the and u != null that's why it worked just like my original code which is the way I want it to...
 
Level 17
Joined
Apr 27, 2008
Messages
2,455
Ok my bad, that was just a matter of range (ALLY_RANGE). My last test was bad because i didn't considered this factor.

But it's still a bug from a logical error, indeed you don't handle the case where there is no ally available AND the summoning unit has still an order.

As said it's totally logic that not IsUnit... will return true with an invalid unit.
 
Level 29
Joined
Mar 10, 2009
Messages
5,016
not sure about this but have you only tested the value of "u" with a hero? heroes are not nulled when they die because they can be ressurected at an altar, unless you changed the game constants list of heroes ikd maybe try this with a normal unit

even though the hero is relivable, when it dies, the variable points to a null instance since the hero is not there, check post#23 video for more info...
 
Status
Not open for further replies.
Top