wc3campaigns
WC3C Homepage - www.wc3c.netUser Control Panel (Requires Log-In)Engage in discussions with other users and join contests in the WC3C forums!Read one of our many tutorials, ranging in difficulty from beginner to advanced!Show off your artistic talents in the WC3C Gallery!Download quality models, textures, spells (vJASS/JASS), systems, and scripts!Download maps that have passed through our rigorous approval process!

Go Back   Wc3C.net > Warcraft III Modding > Developer's Corner > General Development
User Name
Password
Register Rules Get Hosted! Chat Pastebin FAQ and Rules Members List Calendar



Reply
 
Thread Tools Search this Thread
Old 03-18-2014, 11:24 AM   #1
MasterofSickness
User
 
MasterofSickness's Avatar
 
Join Date: Feb 2006
Posts: 218

MasterofSickness is on a distinguished road (23)

BUG accurate movement between waypoints/ regions (4 bugs you should be aware of)

NOTE: You have been redirected in order for our attachments to be made available to you. This will only last two minutes; these measures where taken to avoid hotlinking and bandwidth theft.
To avoid these restrictions Log in or Register

Imaging you are playing a really nice tower defense map. It gets hard, but you have a good feeling that you will beat the next waves. But whats that?? Suddenly there is no next wave... You realize that one or more units are stuck anywhere.
I often ran into this situation with random tower defense maps. As im also into wc3 editing, i didn't want to release a map where these problems could happen too. So i digged into this issue.

1st warcraft 3 bug: region size
situation:
in the final game, regions are bigger than the size they were created/ set. their width & length respectively is increased by 32 units, extending the top edge & the right edge of the original region (the one in the editor).
solution:
when creating regions, appropriately make them smaller!
example:
when creating regions via rectangles instead of "Rect(-32, -32, 32, 32)" do "Rect(-32, -32, 0, 0)".
info:
Rect(min x, min y, max x, max y)
links:
http://www.wc3c.net/showpost.php?p=1077324
http://www.wc3c.net/showpost.php?p=1077401

Hidden information:
the image beneath shows a region placed at 0, 0 with a size of 64 x 64 units (the blue one) in the editor. the fields colored in light blue & the fields colored in normal blue result in the region you have while playing in game. note that the event "TriggerRegisterEnterRegion" already fires in that moment a unit is located in the outermost border (see the given values for crossing in the example beneath). with "unit is located in" i'm not talking about any collision radius touching the said coordinates (in fact collision size doesn't matter for firing the entered region event), im talking about one point every created unit has, one exact location, one specific X & Y value you can get through the natives "GetUnitX" & "GetUnitY".
Zoom (requires log in)
note:
when receiving min & max coordinates from rectangles (functions follow), those values are correct. but when you add those rectangles to regions (function follows) you have to be aware that the regions right & top edges are 32 units bigger.
Collapse JASS:
native GetRectMaxX              takes rect whichRect returns real
native GetRectMaxY              takes rect whichRect returns real
native RegionAddRect            takes region whichRegion, rect r returns nothing


2nd warcraft 3 "bug": movement order (IssuePointOrderLoc)
situation:
when you order a unit to a desired location, the units final actual location isn't the same in 99% cases. the causing factor of these deviations isn't the units collision size, scale or model file. after enough tests (to express it in numbers: in sum not less than 312k) i was able to prove that it is the movement speed & document how much the max & min differences are!
solution:
when you order units to a random point of the next region, you have two choices i think. the easy one: just order them to the next random location inside a region inside a 16 units big border. the hard one: receive the default movement speed of the entering unit & order it with the help of a custom system in reference to the values in the table attached at the end of this passage. however, keep in mind that these values still doesn't seem to be exact as they vary for different directions sometimes. i dont think that the direction is the cause of that, it is just some random factor & still too less tests. anyway in my map i will use the simple workarround with a fixed border of 16 units.
here are some pics:
Hidden information:
Zoom (requires log in)
Zoom (requires log in)
Zoom (requires log in)

the following table shows the final results. for interpreting, just ignore whether the value is positive or negative. i just kept the algebraic sign from my interim results. and ignore the values in light grey! those values still counts to too little although they are placed in the column for too much, but as they represent the counterpart to the dearth limit, namely the overmuch limit, i didnt erase them.
info:
the thick line in column movement speed between row 320 & 340 just reminds me that i had to change the desired location (increased by 10 respectively) to be more far away from my triggering region. otherwise my test configuration didn't work for units movement speed higher than 340 inclusive.

Zoom (requires log in)


3rd warcraft 3 bug: regions intersecting or bordering on each other
situation:
when regions intersect or border on each other the 'unit entering event' of the 2nd region won't fire.
example:
region 1: Rect(-32, -32, 0, 0) in editor = Rect(-32, -32, 32, 32) in game
region 2: Rect(-32, 32, 0, 64) in editor = Rect(-32, 32, 32, 96) in game
when a unit enters 1 & you order it to 2, the unit will walk to 2, but the event from 2 isn't fired, meaning that the unit will get stuck at 2!
when a unit enters 2 & you order it to 1, the unit will walk to 1, but the event from 1 isn't fired, meaning that the unit will get stuck at 1!

solution:
when placing regions, leave at least 32 units empty space between them! why exactly 32 units? because the regions coordinate system is a multiple of 32 units of the default warcraft 3 coordinate system. leaving 32 units space between regions already is the smallest possible distance. the next bigger distance would be 64, then 96, and so on...
Hidden information:
the image beneath shows 2 examples: on the left is a region bordering on another region (leads to problems), on the right is a region with 32 units space to another region (the way to go).
left example: in the editor you think that you have 32 units space between the 2 regions (colored normal blue), but in the game there is no space (colored normal blue & light blue). (compare "1st warcraft 3 bug: region size".)
right example: in the editor you even think that you have 64 units space between the 2 regions, but in the game there is only 32 units space left (smallest possible distance between regions). so, at least you should have 64 units distance between nearest regions in the editor.Zoom (requires log in)


4th warcraft 3 bug: units blocking each other caused by their collision radius size
situation:
when there are too many units with decent collision radius blocking each other, it happens quite often that one or a few of them lose their location orders & get stuck.
solution:
you can either turn collision off which completely solves this issue or (because no collision seems strange) you can add a periodical timer (for example every 3 seconds) to every creep unit which temporarily turns off collision for a few seconds & orders it to the last given location if the unit's current orderid was null. in my map i will use the approach with the timer as i dont want to miss the funny effects of collision. perhaps i will even mix it. some waves with collision, some without :-p
Hidden information:
the easy fix: turn of collision.
you can either edit your units in the object editor & set their collision to zero permanently. the concerning row in mode "CTRL" + "d" is "collison", in normal mode it should be something like "Pathing - Collision size" & the corresponding token is "ucol". or you can leave the collision sizes from the object editor as they are & instead use a trigger dynamically. the concering function in GUI is settled somewhere in the functions group "units". the corresponding jass-code is:
Collapse JASS:
native          SetUnitPathing      takes unit whichUnit, boolean flag returns nothing
// flag = true = collision on
// flag = false = collision off

the sophisticated fix: use periodic timers.
in my map im using following jass code (only copied the parts concerning this issue). if you want to use it, you can copy & paste it from here into an empty trigger inside your trigger editor of your map (be warned, im no pro in jass). in order that the system can work properly, when spawning/ creating units, you must give every unit the appropriate UnitUserData. the number of the next waypoint is saved inside the "unit user data" automatically, but for the 1st time you have to set it manually right after creating the unit so that the system can receive the 1st unit user data. this is done like: call SetUnitUserData(u, 1). to make use of this system you have to setup two globals. first you have to register all waypoints in your map as rectangles for the global private rect array gRectA. for a 128x128 big waypoint this would look like: set gRectA[1] = Rect(256 ,640 ,352 ,736 ). the second global is the private integer array gIntA_NextWayP. this variable must contain the information for the units current waypoint & the units next waypoint. the units current waypoint is the key (1st parameter) & the units next waypoint is the index (2nd parameter). an example: set gIntA_NextWayP[1] = 2. in the last example the "key" (1st parameter) is 1 & the "index" (2nd parameter) is 2. additionally, note that you need the following libraries:
library TimerUtils from Vexorian/ Anitarf
library DamageModifiers from Anitarf
library Table from Vexorian/ Anitarf

Collapse JASS:
// Version 2014_04_16 {yyyy_mm_dd}:
library InitWaypointSystem initializer Init requires TimerUtils, DamageModifiers, Table

    globals
        private rect array gRectA
        private integer array gIntA_NextWayP[1000] // if you have more than 1k wps, simply increase the keys
        // EXPLANATION:
        // KEY: [0-999] = NUMBER OF CURRENT WAYPOINT
        // INDEX: [0-999] = NUMBERS OF NEXT WAYPOINT
    endglobals

    private struct Data_Stuck // This is the struct used to pass data to the delayed function
        unit u
    endstruct

    private function Timer_Collision takes nothing returns nothing
        local Data_Stuck d = Data_Stuck( GetTimerData(GetExpiredTimer()) ) // requires library "TimerUtils"
        call ReleaseTimer( GetExpiredTimer() ) // requires library "TimerUtils"
        call SetUnitPathing(d.u, true)
    endfunction

    private function Timer_Stuck takes nothing returns nothing
        local integer i_WP
        local real r_XnxtWP
        local real r_YnxtWP
        local timer t
        local Data_Stuck d = Data_Stuck( GetTimerData(GetExpiredTimer()) ) // requires library "TimerUtils"
        //call DisplayTimedTextToForce( GetPlayersAll(), 10, "checking live & OrderId. orderid = " + OrderId2String(GetUnitCurrentOrder(d.u)) )
        
        // IF UNIT'S LIFE IS 0, RELEASE & STOP ITS PERIODIC TIMER:
        if GetUnitLife(d.u) == 0 then // requires library "DamageModifiers"
            //call DisplayTimedTextToForce( GetPlayersAll(), 10, "unit is dead! timer & struct gets recycled!")
            call ReleaseTimer( GetExpiredTimer() ) // requires library "TimerUtils"
            call d.destroy()
            return
        endif
        
        // IF UNIT'S OrderId IS null (TREATED AS STUCK UNIT CAUSED BY COLLISION OF OTHER UNITS), TEMPORARILY TURN STUCK UNIT'S COLLISION OFF & REORDER IT TO THE WAYPOINT SAVED IN IT'S UnitUserData
        if OrderId2String(GetUnitCurrentOrder(d.u)) == null then
            set i_WP = GetUnitUserData(d.u)
            set r_XnxtWP = GetRectCenterX( gRectA[i_WP] ) + 16.0 // = X OF CENTER OF UNIT'S CURRENT AIMING WAYPOINT, RECEIVED FROM UnitUserData (INFO: "+ 16.0" TO GET THE REAL WP CENTER IN GAME, NOT THE WP CENTER IN EDITOR!)
            set r_YnxtWP = GetRectCenterY( gRectA[i_WP] ) + 16.0 // = Y OF CENTER OF UNIT'S CURRENT AIMING WAYPOINT, RECEIVED FROM UnitUserData (INFO: "+ 16.0" TO GET THE REAL WP CENTER IN GAME, NOT THE WP CENTER IN EDITOR!)
            
            call SetUnitPathing(d.u, false)
            set t = NewTimer() // requires library "TimerUtils" (default blue timers, max = 8190 timers)
            call SetTimerData( t, integer(d) ) // requires library "TimerUtils"
            call TimerStart(t, 2.0, false, function Timer_Collision) // RUN function Timer_Collision ONCE (TURN COLLISION ON AGAIN)
            
            call IssuePointOrderById(d.u, 851986, r_XnxtWP, r_YnxtWP) // 851986 = "move"
        endif
        
        set t = null
    endfunction

    // ACTION FOR STUCK UNITS (CAUSED BY COLLISION BLOCKS OF OTHER UNITS)
    private function Waypoint_ActionStuck takes nothing returns nothing
        local timer t
        local unit u = GetEnteringUnit()
        local Data_Stuck d
        
        // CHECK EVERY CREATED UNIT FOR UnitUserData
        // IF UnitUserData ISN'T 0, THE UNIT GETS A PERIODIC TIMER CHECKING FOR OrderId
        // IF OrderId IS "", THEN THE UNIT IS STUCK (PROBABLY CAUSED BY COLLISION BLOCKING THROUGH OTHER UNITS)
        // INFO: CHECKING UnitUserData HERE,
        // BECAUSE WHEN USED EARLIER (-> INSIDE A boolexpr INSIDE THE Init function), THE UnitUserData ALWAYS IS "0"
        // (UnitUserData IS SET IN THE SPAWNER TRIGGER RIGHT AFTER UNIT CREATION)
        if GetUnitUserData(u) != 0 then // UnitUserData SHOULD ONLY BE USED AS AN INFORMATION HOLDER ABOUT NEXT WAYPOINT NUMBER
            set d = d.create()
            set d.u = u
            set t = NewTimer() // requires library "TimerUtils" (default blue timers, max = 8190 timers)
            call SetTimerData( t, integer(d) ) // requires library "TimerUtils"
            call TimerStart(t, 3.0, true, function Timer_Stuck)
        endif
        
        set t = null
        set u = null
    endfunction

    private function Init takes nothing returns nothing
        local rect rec = GetWorldBounds()
        local trigger tri_Stuck = CreateTrigger() // TRIGGER FOR REORDERING STUCK UNITS
        local region reg_Stuck = CreateRegion() // REGION USED IN TRIGGER EVENT FOR STUCK UNITS
        call RegionAddRect(reg_Stuck, rec)
        // LEAK TREATMENT: LOCAL HANDLE VARS HAVE TO BE SET TO NULL:
        call RemoveRect(rec)
        set rec = null
        // TRIGGER (EVENTS, CONDITIONS & ACTIONS): ADD PERIODIC TIMER TO EVERY NEW UNIT WHICH HAS UnitUserData (UnitUserData USED FOR STORING NEXT WAYPOINT NUMBER):
        call TriggerRegisterEnterRegion(tri_Stuck, reg_Stuck, null) // MOVED CONDITION INTO THE TRIGGERS ACTIONS, BECAUSE WHEN RECEIVING UnitUserData FROM CONDITION, UnitUserData ALWAYS IS 0!
        call TriggerAddAction(tri_Stuck, function Waypoint_ActionStuck )
    endfunction
endlibrary

all of the above informations were gathered in Warcraft 3 The Frozen Throne Version Build 1.26.0.6401 (Patch 1.26a). So if there comes out another patch, I cannot guarantee if everything mentioned here still is valid.



Thanks:
Anitarf for the nice talks via chat for remembering me to also change the gameplay constants of min & max movement speed first before i run my tests! i already had some wrong results giving me a headache finding out a pattern.
MindWorX for helping & assisting me in running up to 12 instances of warcraft 3 in singleplayer without autopause on 1 notebook simultaneously. (kLoader & Cheat Engine & appropriate memory key)
all I forgot to add here! ;-p

PS:
concerning bug 2 I would have attached the original Excel-file if someone wanted to make further tests or just for reference, but it is 11 MB in size. Even with 7zip i can only reduce it to 8 MB.

EDIT:
bug 2 picture explanations are somewhat less described from me. if you need more informations on this, just let me know. but for now i want to resume editing my map instead of enhancing this thread even more...
Attached Images
File Type: png 01.png (5.9 KB, 101 views)
File Type: png 02.png (26.8 KB, 105 views)
File Type: png 03.png (53.4 KB, 100 views)
File Type: png 04.png (25.5 KB, 92 views)
File Type: png _RegionBehaviour(Bug2).png (34.7 KB, 91 views)
File Type: png _RegionBehaviour(Bug1).png (27.6 KB, 106 views)
__________________
my nicknames:
20002006200720102012
Master of SicknessDesignatusKakarotEdwardElricSourceSeeker

Last edited by MasterofSickness : 04-16-2014 at 07:32 PM.
MasterofSickness is offline   Reply With Quote
Sponsored Links - Login to hide this ad!
Old 04-10-2014, 09:50 AM   #2
iNfraNe
PhD
 
iNfraNe's Avatar


Cinematics Moderator
 
Join Date: Dec 2003
Posts: 2,283

Submissions (7)

iNfraNe is just really nice (266)iNfraNe is just really nice (266)iNfraNe is just really nice (266)iNfraNe is just really nice (266)iNfraNe is just really nice (266)

Approved Map: Mortar Ball

Send a message via MSN to iNfraNe
Default

Great work! I don't really like regions to begin with, but it's great that you did this work :)
__________________
Ever so slightly active.
Table:
Past Projects:
The Spirit of Vengeance (Cinematic, Blizzard contest winner)
Elimination Tournament
Mortar Ball
iNfraNe is offline   Reply With Quote
Old 04-16-2014, 05:44 PM   #3
MasterofSickness
User
 
MasterofSickness's Avatar
 
Join Date: Feb 2006
Posts: 218

MasterofSickness is on a distinguished road (23)

Default

Thanks for the kind words iNfraNe & therefor the motivation!

updated post #1:
  1. section "1st warcraft 3 bug":
    • added important informations to the image description concerning the moment when an entered region event fires
  2. section "4th warcraft 3 bug":
    • enhanced explanation in "solution"
    • extended JASS-code by two comments in "the easy fix: turn of collision"
    • rewrote/changed/added some major parts in the JASS-code in "the sophisticated fix: use periodic timers"
    • also added a comment for version number (for the purpose of distinguishing old & new code for users) to the first line in the JASS-code in "the sophisticated fix: use periodic timers"
  3. added used version build of warcraft 3 on which all tests for all findings were made
__________________
my nicknames:
20002006200720102012
Master of SicknessDesignatusKakarotEdwardElricSourceSeeker

Last edited by MasterofSickness : 04-16-2014 at 07:34 PM.
MasterofSickness is offline   Reply With Quote
Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off


All times are GMT. The time now is 10:01 AM.


Affiliates
The Hubb The JASS Vault Clan WEnW Campaign Creations Clan CBS GamesModding Flixreel Videos

Powered by vBulletin (Copyright ©2000 - 2019, Jelsoft Enterprises Ltd).
Hosted by www.OICcam.com
IT Support and Services provided by Executive IT Services