HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

The difference

06-18-2006, 12:02 AM#1
Vexorian
What's the difference between:
Collapse JASS:
function List_First takes location list returns location
    return GetLocationX(list)
    return 0.
endfunction

function List_IsEmpty takes location list returns boolean
    return (List_First(list)==null)
endfunction

and

Collapse JASS:
function List_First takes location list returns location
    return GetLocationX(list)
    return 0.
endfunction

function List_IsEmpty takes location list returns boolean
 local location first=List_First(list)
 local boolean r=(first==null)
 set first=null
 return r
endfunction
?

The difference is that the second one actually works and the first one will always return true
06-18-2006, 12:38 AM#2
PipeDream
http://www.wc3campaigns.net/showthread.php?t=83194
http://www.wc3campaigns.net/showthread.php?p=804603
Heh, you even posted in the latter.

I've been thinking about rects again. What you could do is have one min/max pair be a min float and an arbitrary value, and the other min/max pair a pointer and type information. Since pointers are always positive you can flip the sign bit and use only positive numbers for type information then stash pointer in min and type in max. If you need both to be arbitrary values you can use min float in both to indicate it's arbitrary.
If you want a double linked list type with static typing, you could put two pointers in Y and a minfloat and value in X.


Edit: The really super strange thing about this bug is that warcraft *does* pass reals around in the regular integer registers. Apparently for some things it uses the floating point registers (like it should). Maybe there's a better way to force it into the integer register. Hm.. I bet something different happens on macs, any mac users care to test?
06-18-2006, 03:43 PM#3
weaaddar
Right its a terrible quirk. I do find it fun though to typecast booleans and then do something like
if(b and not b)then
call BJDebugMsg("THIS IS A SLAP IN THE FACE OF ALL LOGIC")
endif

The answer is pretty simple, if you look at my recursive thought test map I include a functioning cons car and cdr.
Although my definition of null is different, as I personally define null as well null.
I personally suggest putting the typecasting inside car and cdr, only because a less thoughtful user may forget the bug exist.

Remember that you can extract values correctly! Only comparisons are flawed.
local location r=cons(5,null)
call BJDebugMsg(I2S(car(r)))
if(car(r)==4)then
call BJDebugMsg("WTF")
endif


Remember that in Scheme and Lisp it is an error to call car or cdr on null, so while this may cause war3 to crash you are technically inline :trisomy:

Anyway, Pipedream I think hijacking a rect wouldn't be bad for a typed list. Assuming we have haskell like typed list we then only need three things: type of car, car,cdr.

Car and cdr will be stored in the max x, and max y, and the type could just use the min y, since max y is always a handle. If max x is negative we will get its absolute value and store its sign bit in min x. This should solve all our woes, although locations should be pretty suffecient otherwise.

I think its glorious that we've moved on from just abusing the gamecache, and now are truly messing up warcraft III by overtly using the return bug to hijack data structures.
06-18-2006, 04:03 PM#4
BertTheJasser
The question sounds dumb: Does the location named first actually exist?
06-18-2006, 07:39 PM#5
weaaddar
Read my post please, the value it extracts is the right one. It's the comparison that is flawed.

As my code example was demoing that would print five, but it would also somehow say that it's value was 4 (which is horribly wrong).
06-18-2006, 07:43 PM#6
Vexorian
pipedream: are you sure about it failing when comparing it to 0? (as acording to your post?)

Collapse JASS:
function List_FirstI takes location l returns integer
    return GetLocationX(l)
    return 0
endfunction

function List_FirstIH takes location l returns handle
    return List_FirstI(l)
    return null
endfunction

//works
function List_IsEmpty takes location list returns boolean
    return (List_FirstIH(list)==null)
endfunction

//also works
function List_IsEmpty takes location list returns boolean
    return (List_FirstI(list)==0)
endfunction
The names are far from being official so don't complain about them.
06-18-2006, 07:54 PM#7
BertTheJasser
I do not understand. Qas this an answer to my question?
06-18-2006, 07:59 PM#8
Vexorian
Another one that works:

Collapse JASS:
function List_IsEmpty takes location list returns boolean
return (GetLocationX(list)==CS_h2r(null))
endfunction


=
bert: Yes it does exist.
06-18-2006, 11:49 PM#9
PipeDream
My tests showed that comparisons always returned true. However, since it seems to have something to do with registers mixing up, I expect the result is pretty well undefined and just depends on what was there beforehand.

I don't understand this at all. Here's the end of GetLocationX:
Code:
.text:6F2ADA14                 mov     eax, [edi+24h]  ; edi must contain handle.  +0x24 is X, +0x28 is Y
.text:6F2ADA17                 pop     edi
.text:6F2ADA18                 pop     ebx
.text:6F2ADA19                 mov     esp, ebp
.text:6F2ADA1B                 pop     ebp
.text:6F2ADA1C                 retn
.text:6F2ADA1C GetLocationX    endp
Like xttocs has said, it clearly returns it in the integer register. No floating point shenanigans. There's nothing that could miss. *shrug*

On an unrelated note, also from GetLocationX/Y:
Code:
.text:6F2E0B90                 push    ebp
.text:6F2E0B91                 mov     ebp, esp
.text:6F2E0B93                 mov     edx, [ebp+arg_0]
.text:6F2E0B96                 test    edx, edx
.text:6F2E0B98                 mov     eax, ecx
.text:6F2E0B9A                 mov     [eax], edx
.text:6F2E0B9C                 jz      short loc_6F2E0BA1
.text:6F2E0B9E                 inc     dword ptr [edx+4]
.text:6F2E0BA1
.text:6F2E0BA1 loc_6F2E0BA1:                           ; CODE XREF: sub_6F2E0B90+Cj
.text:6F2E0BA1                 pop     ebp
.text:6F2E0BA2                 retn    4
.text:6F2E0BA2 sub_6F2E0B90    endp
Code:
.text:6F2E0320 sub_6F2E0320    proc near               ; CODE XREF: MoveLocation+81p
.text:6F2E0320                                         ; GetLocationX+87p ...
.text:6F2E0320                 mov     ecx, [ecx]
.text:6F2E0322                 test    ecx, ecx
.text:6F2E0324                 jz      short locret_6F2E032F
.text:6F2E0326                 dec     dword ptr [ecx+4]
.text:6F2E0329                 jnz     short locret_6F2E032F
.text:6F2E032B                 mov     eax, [ecx]
.text:6F2E032D                 jmp     dword ptr [eax]
.text:6F2E032F ; ---------------------------------------------------------------------------
.text:6F2E032F
.text:6F2E032F locret_6F2E032F:                        ; CODE XREF: sub_6F2E0320+4j
.text:6F2E032F                                         ; sub_6F2E0320+9j
.text:6F2E032F                 retn
.text:6F2E032F sub_6F2E0320    endp
This must be pieces of a broken reference counter. If we could hook a little code to call the decrementer on each handle when a function returns, no more set to null needed.
06-28-2006, 01:36 AM#10
Vexorian
Quote:
Originally Posted by Vexorian
Another one that works:

Collapse JASS:
function List_IsEmpty takes location list returns boolean
return (GetLocationX(list)==CS_h2r(null))
endfunction


=
bert: Yes it does exist.
What's going on? Now none of these alternative solutions seem to work, same map, same functions same everything, this is as random as it can get
06-28-2006, 01:58 AM#11
Vexorian
All right:

Collapse works:
function List_IsEmpty takes location list returns boolean
 return not(List_First(list)!=null)
endfunction

Collapse does not work:
function List_IsEmpty takes location list returns boolean
 return (List_First(list)==null)
endfunction

The new question is : Why is that the == operator is bugged?
06-28-2006, 02:43 AM#12
PipeDream
It looks like blizzard does all in game floating point with a homegrown emulator. I'm guessing that it gets confused as to which internal compare function to use. Not, like assignment, changes that type information properly.
06-28-2006, 03:01 AM#13
Vexorian
Actually, just != seems to be returning things correctly I added the not so it works.

edit:

Collapse Does not work:
function List_IsEmpty takes location list returns boolean
 return not not(List_First(list)==null)
endfunction
06-28-2006, 03:19 AM#14
PipeDream
Huh.. maybe it's related to the IsUnitType bug. In game or I'd test.
06-28-2006, 04:20 AM#15
StealthFox
It could be that JASS doesn't allow you to use functions that don't return primitive data types. The very first function is returning a location and the second function is trying to directly use the location in its return line. However, by using a local variable to store the same information, the second function returns the boolean just fine, or at least this is what I think is happening.

I could be wrong about this, but this is the only explanation I could think of.

Edit: Or it could be that the function GetLocationX returns a real and not a location so the program is reading it as null because it doesn't return anything. Also, the other functions work because they become casted into either an integer or a handle as they're being returned (just a thought).