HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

How to fix this problem?

09-20-2006, 11:58 AM#1
Fireeye
I've built a "little" Fireballspell, it works perfectly, but WC3 crashs after 100+ Runs without a warning.
How to fix that Problem?
Here's the Code:
Hidden information:
Collapse JASS:
//You might change from here on
constant function FireballID takes nothing returns integer
    return 'A001'
endfunction

constant function FireballPeriod takes nothing returns real
    return 0.02
endfunction

constant function FireballSpeed takes nothing returns real
    return 10.00
endfunction

constant function FireballIsUnitAllowed takes unit u, unit fireball returns boolean
    return IsUnitEnemy(u,GetOwningPlayer(fireball))
endfunction

constant function SplashRange takes nothing returns real
    return 300.00
endfunction

//End of changeable area
//Here begins the spell itself now
function FireballDamage takes unit fireball, unit target, group g, integer level returns nothing
local unit u
local integer n=1
local location array temp_point
set temp_point[0] = GetUnitLoc(fireball)
    loop
    set u = FirstOfGroup(g)
        exitwhen u == null or n >=8192
            if(FireballIsUnitAllowed(u,fireball)) then
                if (u==target) then
                    call UnitDamageTargetBJ( fireball, u, ( 100.00 * I2R(level) ), ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL )
                else
                    call UnitDamageTargetBJ( fireball, u, ( 50.00 * I2R(level) ), ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL )
                endif
            endif
            set n = n + 1
        call GroupRemoveUnit(g,u)
       set u = null
    endloop
    call DestroyGroup(g)
    call CreateNUnitsAtLoc(1,'h002', GetOwningPlayer(fireball), temp_point[0], bj_UNIT_FACING)
    call KillUnit(GetLastCreatedUnit())
set n=1
loop
exitwhen n > 24
    set temp_point[1] = PolarProjectionBJ(temp_point[0], GetRandomReal(0, SplashRange()), GetRandomDirectionDeg())
    call CreateNUnitsAtLoc( 1, 'h001', GetOwningPlayer(fireball), temp_point[1], bj_UNIT_FACING )
    call UnitApplyTimedLifeBJ( 5.00, 'BTLF', GetLastCreatedUnit() )
    set n = n + 1
    call RemoveLocation(temp_point[1])
endloop
endfunction

function FireballCore takes nothing returns nothing
    local string s = I2S(H2I(GetExpiredTimer()))
    local real d = GetStoredReal(udg_gamecache,s,"d")
    local integer level = GetStoredInteger(udg_gamecache,s,"level")
    local real angle
    local unit fireball
    local unit target
    local location a
    local location b
    local location c
    local group g
    local integer check = GetStoredInteger(udg_gamecache,s,"check")
    if (check == 1) then
        call PauseTimer(GetExpiredTimer())
        call DestroyTimer(GetExpiredTimer())
        call FlushStoredMission(udg_gamecache,s)
        return  
    elseif (d < 60.0) then
        set fireball = I2U(GetStoredInteger(udg_gamecache,s,"fireball"))
        set target = I2U(GetStoredInteger(udg_gamecache,s,"target"))
        set a = GetUnitLoc(fireball)
        set g = GetUnitsInRangeOfLocAll(SplashRange(), a)
        call FireballDamage(fireball, target, g, level)
        set check = 1
        call StoreInteger(udg_gamecache,s,"check",check)
        call RemoveUnit( fireball )
    endif
        set fireball = I2U(GetStoredInteger(udg_gamecache,s,"fireball"))
        set target = I2U(GetStoredInteger(udg_gamecache,s,"target"))
        set a = GetUnitLoc(fireball)
        set b = GetUnitLoc(target)
        set angle = AngleBetweenPoints(a, b)
        set c = PolarProjectionBJ(a, FireballSpeed(), angle)
        call SetUnitPositionLocFacingBJ( fireball, c, angle )
        set d = DistanceBetweenPoints(a, b)
        call StoreReal(udg_gamecache,s,"d",d)
set fireball = null
set target = null
call RemoveLocation(a)
call RemoveLocation(b)
call RemoveLocation(c)
call DestroyGroup(g)
endfunction

function Fireball_callback takes nothing returns nothing
    call ExecuteFunc("FireballCore")
endfunction

function Trig_Fireball_Actions takes nothing returns nothing
local unit fireball
local unit target=GetSpellTargetUnit()
local timer t
local string s
local location array l
local real d
local integer level = GetUnitAbilityLevel(GetSpellAbilityUnit(),FireballID())
local integer check
    if(FireballID() != GetSpellAbilityId()) then
        set fireball = null
        return
    endif
    set l[0] = GetUnitLoc(GetSpellAbilityUnit())
    call CreateNUnitsAtLoc( 1, 'h000', GetOwningPlayer(GetSpellAbilityUnit()), l[0], GetUnitFacing(GetSpellAbilityUnit()) )
    set fireball = GetLastCreatedUnit()
    set l[1] = GetUnitLoc(GetSpellTargetUnit())
    set d = DistanceBetweenPoints(l[0], l[1])
    set check = 0
    set t = CreateTimer()
    set s = I2S(H2I(t))
    call StoreInteger(udg_gamecache,s,"fireball",H2I(fireball))
    call StoreInteger(udg_gamecache,s,"target",H2I(target))
    call StoreInteger(udg_gamecache,s,"level",level)
    call StoreReal(udg_gamecache,s,"d",d)
    call StoreInteger(udg_gamecache,s,"check",check)
    call TimerStart(t,FireballPeriod(),true,function Fireball_callback)
    set fireball = null
    set target = null
    set t = null
    call RemoveLocation(l[0])
    call RemoveLocation(l[1])
endfunction

//===========================================================================
function InitTrig_Fireball takes nothing returns nothing
    set gg_trg_Fireball = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_Fireball, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddAction( gg_trg_Fireball, function Trig_Fireball_Actions )
endfunction

09-20-2006, 12:34 PM#2
Daelin
Try removing the array. I do not know why but I have a hunch that the problem may be with their allocation. Tell me if the error does not occur again and maybe then a new bug has been discovered.

I found a problem though in the timer. When the timer ends, if you simply use "return" without nulling or removing anything, all leaks remain. Also you use too much GetExpiredTimer(). I suggest you try to avoid the timer bug by using the timer as a parameter in timer's function. Replace that function with one which simply calls it, using the timer as a parameter.

~Daelin
09-20-2006, 01:22 PM#3
Fireeye
I rebuild everything as you told, but WC3 still crashs.
Needs a bit longer till crash, but it still crashs, damn it, i still can't find the proplem.
09-20-2006, 01:35 PM#4
Daelin
You have a leak in the fireball function. If you return, "target" will leak. Use natives instead of those non-natives. These are not stuff that should cause a crash though.

I don't get this: set s = I2S(H2I(t)). I also suspect this: call TimerStart(t,FireballPeriod(),true,function Fireball_callback)
set fireball = null. I'm not sure if this cannot cause the timer bug too. And no, callback is not like this.

Collapse JASS:
function FireballCore takes timer t returns nothing
//blah blah, no nullification for t needed
endfunction

function Fireball_callback takes nothing returns nothing
    call FireballCore(GetExpiredTimer())
endfunction

exitwhen u == null or n >=8192. Does crash occur after a savegame? You know the maximum array size limit which is 8191 after a savegame. u, in first function, is never nullified. The code is still really messy. Modify it, especially replace the non-natives, and then we'll see.

~Daelin
09-20-2006, 02:23 PM#5
Fireeye
Got the exact number when WC3 crashs, it crashs after 202 runs.
I'm not using:
Collapse JASS:
function Fireball_callback takes nothing returns nothing
    call FireballCore(GetExpiredTimer())
endfunction

I use
Collapse JASS:
function Fireball_callback takes nothing returns nothing
    call ExecuteFunc("FireballCore")
endfunction

H2I is just this
Collapse JASS:
function H2I takes handle h returns integer
    return h
    return 0
endfunction

And this
Collapse JASS:
call TimerStart(t,FireballPeriod(),true,function Fireball_callback)
works fine

Also i don't think that
Collapse JASS:
set fireball = null
cause this crash

And no the crash doesn't occour after a loaded save game and i nullify u always.
Collapse JASS:
    loop
    set u = FirstOfGroup(g)
        exitwhen u == null or n >=8192
            if(FireballIsUnitAllowed(u,fireball)) then
                if (u==target) then
                    call UnitDamageTargetBJ( fireball, u, ( 100.00 * I2R(level) ), ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL )
                else
                    call UnitDamageTargetBJ( fireball, u, ( 50.00 * I2R(level) ), ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL )
                endif
            endif
            set n = n + 1
        call GroupRemoveUnit(g,u)
        set u = null
    endloop

I also tried the natives but the game still crashs.
09-20-2006, 04:04 PM#6
Daelin
Mno, I meant use Fireball_callback how I said, sorry for the misunderstanding. There's no point in executing a function from timer's function. It's the same thing. Call a function with the timer as a parameter and avoid using GetExpiredTimer() loads of times, just because you are afraid of nullifying timer pointer.

~Daelin