HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

Crash Without Error

05-07-2009, 05:52 AM#1
Karawasa
I'm using Earth-Fury's SetUnitMaxState system in my map, and under certain conditions it causes the game to crash without an error screen (i.e. poof right to desktop). I did some debugging, and I noticed that the system crashes when the difference between max hp and current hp is greater than ~2.4 million (max hp - current hp). To be more clear, the system crashes when it has to change max hp (in this case decrease it) by more than ~2.4 million. As you can see I am using a sufficiently high max power of 2. What can I do about this? Here is the system code;

Collapse JASS:
//////////////////////////////////////////////////////////////////////////////////////////
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//@     SetUnitMaxState
//@=======================================================================================
//@ Credits:
//@---------------------------------------------------------------------------------------
//@     Written by:
//@         Earth-Fury
//@     Based on the work of:
//@         Blade.dk
//@
//@ If you use this system, please credit all of the people mentioned above in your map.
//@=======================================================================================
//@ SetUnitMaxState Readme
//@---------------------------------------------------------------------------------------
//@
//@ SetUnitMaxState() is a function origionally written by Blade.dk. It takes advantage of
//@ a bug which was introduced in one of the patches: Bonus life and mana abilitys will
//@ only ever add the bonus ammount for level 1. However, when removed, they will remove
//@ the ammount they should have added at their current level. This allows you to change a
//@ units maximum life and mana, without adding a perminent ability to the unit.
//@
//@---------------------------------------------------------------------------------------
//@ Adding SetUnitMaxState to your map:
//@ 
//@ Simply copy this library in to a trigger which has been converted to custom text.
//@ After that, you must copy over the abilitys. This is made easy by the ObjectMerger in
//@ JASS NewGen. Distributed with this system are //! external calls to the ObjectMerger.
//@ Simply copy both of them in to your map, save your map, close and reopen your map in
//@ the editor, and remove the external calls. (Or otherwise disable them. Removing the !
//@ after the // works.)
//@
//@---------------------------------------------------------------------------------------
//@ Using SetUnitMaxState:
//@
//@ nothing SetUnitMaxState(unit <target>, unitstate <state>, real <new value>)
//@
//@     This function changes <target>'s unitstate <state> to be eqal to <new value>. Note
//@ that the only valid unitstates this function will use are UNIT_STATE_MAX_MAN and
//@ UNIT_STATE_MAX_LIFE. Use SetUnitState() to change other unitstates.
//@
//@ nothing AddUnitMaxState(unit <target>, unitstate <state>, real <add value>)
//@
//@     This function adds <add value> to <target>'s <state> unitstate. <add value> can be
//@ less than 0, making this function reduce the specified unitstate. This function will
//@ only work with the unitstates UNIT_STATE_MAX_LIFE and UNIT_STATE_MAX_MANA.
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//////////////////////////////////////////////////////////////////////////////////////////
library SetUnitMaxState initializer Initialize
globals
//========================================================================================
// Configuration
//========================================================================================

    // The rawcode of the life ability:
    private constant integer MAX_STATE_LIFE_ABILITY = 'A03W'
    
    // The maximum power of two the abilitys use:
    private constant integer MAX_STATE_MAX_POWER = 22
endglobals

//========================================================================================
// System Code
//----------------------------------------------------------------------------------------
// Do not edit below this line unless you wish to change the way the system works.
//========================================================================================

globals
    private integer array PowersOf2
endglobals

function SetUnitMaxState takes unit u, unitstate state, real newValue returns nothing
    local integer stateAbility
    local integer newVal = R2I(newValue)
    local integer i = MAX_STATE_MAX_POWER
    local integer offset
    
    if state == UNIT_STATE_MAX_LIFE then
        set stateAbility = MAX_STATE_LIFE_ABILITY
    else
        debug call BJDebugMsg("SetUnitMaxState Error: Invalid unitstate")
        return
    endif
    
    set newVal = newVal - R2I(GetUnitState(u, state))
    
    if newVal > 0 then
        set offset = MAX_STATE_MAX_POWER + 3
    elseif newVal < 0 then
        set offset = 2
        set newVal = -newVal
    else
        return
    endif
    
    loop
        exitwhen newVal == 0 or i < 0
        if newVal >= PowersOf2[i] then
            call UnitAddAbility(u, stateAbility)
            call SetUnitAbilityLevel(u, stateAbility, offset + i)
            call UnitRemoveAbility(u, stateAbility)
            set newVal = newVal - PowersOf2[i]
        else
            set i = i - 1
        endif
    endloop
endfunction

function AddUnitMaxState takes unit u, unitstate state, real addValue returns nothing
    call SetUnitMaxState(u, state, GetUnitState(u, state) + addValue)
endfunction

private function Initialize takes nothing returns nothing
    local integer i = 1
    
    set PowersOf2[0] = 1
    loop
        set PowersOf2[i] = PowersOf2[i - 1] * 2
        set i = i + 1
        exitwhen i == MAX_STATE_MAX_POWER + 3
    endloop
endfunction
endlibrary
05-07-2009, 06:28 AM#2
akolyt0r
maybe try to add some additional levels to the ability, and increase MAX_STATE_MAX_POWER 2^22 is roughly 4 million ..at the moment so AFAIK that shouldnt be a problem ...should it ?? ah well ...give it a try anyway...
05-07-2009, 08:12 AM#3
Karawasa
I tried to the 26th but no change. I don't think increasing it is the solution.
05-07-2009, 10:39 AM#4
Earth-Fury
Increasing the max power of 2 only increase efficiency, not the actual systems range.

It basically adds (or subtracts) the highest power of 2 the system has that is less-than or equal to the difference between the current value and the desired one, until the difference is gone. (It abuses a bug to do the actual life/mana altering, but I've never read of an ill effect from (ab)using that bug.)

The problem may lay in the fact that the amount added by the life ability it too high/low at any one time. (Too high a power of 2.)

You did actually modify the life (and/or mana) ability to match the new range set with the MAX_STATE_MAX_POWER variable, right..? (I always meant to write better documentation..)
05-07-2009, 11:23 AM#5
Karawasa
Yes, with MAX_STATE_MAX_POWER == 22 my ability has +/- ~4 million.
05-07-2009, 11:57 AM#6
DioD
Just add exceptions* to your system, if difference more then %many% use different function with steps like 2400000
05-07-2009, 02:37 PM#7
Strilanc
Try to cause the crash with a hardcoded case (ie replace the function argument with a fixed local, then remove the unused if statement branches, then unroll the loop, etc).

You should end up with a function with no IFs, no LOOPs, and a really obvious problem.
05-08-2009, 08:49 AM#8
Karawasa
Quote:
Originally Posted by Strilanc
Try to cause the crash with a hardcoded case (ie replace the function argument with a fixed local, then remove the unused if statement branches, then unroll the loop, etc).

You should end up with a function with no IFs, no LOOPs, and a really obvious problem.

The problem is not obvious to me, would you care to help/elaborate?
05-08-2009, 11:58 AM#9
Strilanc
Well first you need to find a simple case to cause it. These things are always simple in hindsight. I have no idea what it is yet, either.

You need to simplify the function while preserving the crash, so you can find out what's causing it. It's bug-finding 101.
05-08-2009, 12:50 PM#10
DioD
Crush without error is thread lockup.

To improve your chances to get answer post map, with this function cause 100% crush all time.

Random errors is nearly impossible to fix.
05-08-2009, 06:55 PM#11
ImmolatusBurn
Does this bug occur when testing for the same max health change in a different map, or does it only occur in EleTD?

I was trying to find this system to do some tests regarding it, but I couldn't find it anywhere, could someone link me?
05-08-2009, 08:23 PM#12
cosmicat
http://www.wc3jass.com/viewtopic.php?t=2652

I can't seem to reproduce the bug...
05-10-2009, 10:40 AM#13
Karawasa
A good base case would be this (since it is what I am doing)...

Take a unit with 5 million hp, set its health to 50%, make its max life equal to current.

Crash?
05-10-2009, 04:42 PM#14
Strilanc
Great, now provide code for that exact test case, and simplify it as much as you can while preserving the crash.