• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.
  • The Hive's 22nd Icon Contest: Creep Abilities is now concluded, time to vote for your favourite set of icons! Click here to vote!
  • ✅ The POLL for Hive's Texturing Contest #34 is OPEN! Vote for the TOP 3 SKINS! 🔗Click here to cast your vote!
  • ✅ The POLL for Hive's Techtree Contest #20 is OPEN! Vote for the TOP 3 FACTIONS! 🔗Click here to cast your vote!

RegionAddRect ~ Warcraft III Fatal Error

Status
Not open for further replies.
Level 18
Joined
Jan 21, 2006
Messages
2,552
I was addressing a bug that Bribe brought to my attention and in trying to establish a method of determining whether or not a unit has been removed (unitVar == null is not accurate) I was trying to add the entire world-bounds to a region so that it could be evaluated whether the unit in question is in that region (if not then it has been removed from the game).

JASS:
call RegionAddRect(someGlobalRegion, GetWorldBounds())
call RegionAddRect(someGlobalRegion, bj_mapInitialPlayableArea)

The above lines of code cause fatal errors, just thought (if it is not already known) that someone would find this information valuable.
 
I completely forgot about the GetUnitTypeId() == 0 check - it is because sometimes when units are removed they are still equal to null, yet all of their properties are nullified.

Does the line with GetWorldBounds() suffice to crash WC3?

Either of those two lines crashes Warcraft III.
 
The reason why it crashes the game is that GetWorldBounds() and bj_mapInitialPlayableArea both refer to an always-updating variable. (bj_mapInitialPlayableArea is just a link to, it's not the real variable)

The primary reason was to be able to change the map size ingame, however, this has never been fully implemented.

While refering to a dynamic variable (Such as the units life, which is in fact a variable too) it will add that rect to the region. Then the rect gets updated and the region has invalid data.

If you really want to check whether an unit has been removed, you can check its handle id too (GetHandleId(unit)) AFAIK.
 
I wonder how current those bugs are. There are weird ones, such as the game compiling 'this' type of rawcode of only size 1 or 4 (the rest throwing syntax errors... you would think you could get away with 2 and 3 as well, but no, it's just 1 or 4.), the stupid way strings are stored into a table causing leak throughout the game, the way chat messages leak until you press F12... the list is long... far longer than that thread.
 
While refering to a dynamic variable (Such as the units life, which is in fact a variable too) it will add that rect to the region. Then the rect gets updated and the region has invalid data.

Except if you add a rect to a region and then remove that rect from the game the region still operates properly.

Look more closely; this:

  • Untitled Trigger 001
    • Events
      • Unit - A unit enters (Entire map)
    • Conditions
    • Actions
Translates to:

JASS:
//===========================================================================
function InitTrig_Untitled_Trigger_001 takes nothing returns nothing
    set gg_trg_Untitled_Trigger_001 = CreateTrigger(  )
    call TriggerRegisterEnterRectSimple( gg_trg_Untitled_Trigger_001, GetEntireMapRect() )
    call TriggerAddAction( gg_trg_Untitled_Trigger_001, function Trig_Untitled_Trigger_001_Actions )
endfunction

The GUI trigger uses TriggerRegisterEnterRectSimple. This translates to:

JASS:
function TriggerRegisterEnterRectSimple takes trigger trig, rect r returns event
    local region rectRegion = CreateRegion()
    call RegionAddRect(rectRegion, r)
    return TriggerRegisterEnterRegion(trig, rectRegion, null)
endfunction

Now look again at the first block of JASS code; it contains GetEntireMapRect(). This looks like:

JASS:
function GetEntireMapRect takes nothing returns rect
    return GetWorldBounds()
endfunction

Now if you break it down this performs:

JASS:
local region rectRegion = CreateRegion()
call RegionAddRect(rectRegion, GetWorldBounds())
call TriggerRegisterEnterRegion(trig, rectRegion, null)

For some reason this works fine. I think there might be something else to it.

The reason why it crashes the game is that GetWorldBounds() and bj_mapInitialPlayableArea both refer to an always-updating variable. (bj_mapInitialPlayableArea is just a link to, it's not the real variable)

So I guess none of what you said here is correct either, or else the GUI would crash Warcraft III.

Okay, after further speculation it is not actually the execution of the code that makes it crash. I'll show you what I've got:

JASS:
library UnitExists initializer init
 globals
    // Config 
    // ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
    private     region      gameBounds      = CreateRegion()
 
 endglobals

 function UnitExists takes unit whichUnit returns boolean
    return IsUnitInRegion(gameBounds, whichUnit)
 
 endfunction
 
 // Initialization
 // ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
 public function init takes nothing returns nothing
    call RegionAddRect(gameBounds, GetWorldBounds())
 
 endfunction
 
endlibrary

The reason it's causing the game to crash is because CreateRegion() is in the global-declaration block instead of in the initializer. When the constructor is placed in the initializer function the game ceases to crash. I could have sworn that it wasn't working the same way initially, but it seems to be now so I'll just assume I'm a little bit crazy.

Anachron what was all that about GetWorldBounds() and bj_mapInitialPlayableArea being "dynamic" entities; they are completely static the entire game, as are all rects.
 
I don't actually do that in any of this code, I know that from personal experience though. I know you'll want proof, so here:

JASS:
library UnitExists initializer init
 globals
    // Config 
    // ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
    private     region      gameBounds      //= CreateRegion()
 
 endglobals

 function UnitExists takes unit whichUnit returns boolean
    return IsUnitInRegion(gameBounds, whichUnit)
 
 endfunction
 
 // Initialization
 // ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
 public function init takes nothing returns nothing
    local rect worldBounds = GetWorldBounds()
    local rect r = Rect(GetRectMinX(worldBounds), GetRectMinY(worldBounds), /*
                        */ GetRectMaxX(worldBounds), GetRectMaxY(worldBounds))
        set gameBounds = CreateRegion()
        call RegionAddRect(gameBounds, r)
        call RemoveRect(r)
        set r = null
        set worldBounds = null
        
 endfunction
 
endlibrary

This works properly, despite r being removed after it is added to gameBounds.
 
GetWorldBounds() returns a static rect just like any. If the world bounds somehow changed, the next time GetWorldBounds() is called would reflect that change, but no existing World Bounds rects.

RegionAddRect does something internally to the region so it no longer needs the rect, and it can then be safely removed. Even SetRect after the RegionAddRect call should not affect the size of the region because of the way it works.

Then again, that's logical thinking.
 
Bribe said:
GetWorldBounds() returns a static rect just like any. If the world bounds somehow changed, the next time GetWorldBounds() is called would reflect that change, but no existing World Bounds rects.
Then why does GetWorldBounds() == GetWorldBounds() always fail?

Where are you getting this information from Anachron.
I once had a friend whos dad was working on blizzard, and I was asking him if he could do me a favor and tell me why the world bounds are so bugged.
And that's the answer I got.
 
Anachron said:
I once had a friend whos dad was working on blizzard, and I was asking him if he could do me a favor and tell me why the world bounds are so bugged.
And that's the answer I got.

The native GetWorldBounds returns a new rect each time it is referenced. This means that if you define a new rect as newRect = GetWorldBounds() you can destroy it without hindering the reference of GetWorldBounds - if it is used twice it will return two separate, unassociated rects. This is why GetWorldBounds() != GetWorldBounds().

There is nothing buggy about GetWorldBounds(), so I really don't know what you're talking about. It makes it hard to believe this friend of yours is connected to Blizzard Entertainment in any way, I mean you got a response to a non-existent problem. There is no bug with GetWorldBounds(), so I'm curious as to where exactly this answer came from.
 
The native GetWorldBounds returns a new rect each time it is referenced. This means that if you define a new rect as newRect = GetWorldBounds() you can destroy it without hindering the reference of GetWorldBounds - if it is used twice it will return two separate, unassociated rects. This is why GetWorldBounds() != GetWorldBounds().

There is nothing buggy about GetWorldBounds(), so I really don't know what you're talking about. It makes it hard to believe this friend of yours is connected to Blizzard Entertainment in any way, I mean you got a response to a non-existent problem. There is no bug with GetWorldBounds(), so I'm curious as to where exactly this answer came from.
Yes, I am really confused about it as well, maybe he was just a wanna-be?
 
Guys, this isnt some complicated thing.
Check the fucken type ID of a unit against 0 to determine if a unit handle is still valid.

You could also try to modify the unit's custom value; If you cant modify it (GetUnitUserData always returns 0), the unit has been removed.

You dont need rects or anything complex like that.
 
Check the fucken type ID of a unit against 0 to determine if a unit handle is still valid.

I am already doing that, it was updated hours ago - you can see the results in my Projectile library submission thread. Discussion kind of just lingered on as irrelevant input was conversed upon.

You dont need rects or anything complex like that.

They're not really complex, but doing GetUnitTypeId() is a lot quicker than determining if a unit is in a region; this is the reason that I use that simple method rather than this bloated one.
 
Status
Not open for further replies.
Back
Top