HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

This Spell Crashes My Map

01-22-2010, 08:43 PM#1
thehellman
Collapse JASS:
scope Cleave initializer Init

private struct data
    unit target          = null
    unit caster          = null
    group knockGroup     = null
    real v               = 0.  
    real angle           = 0.
endstruct

globals
    private boolexpr filter = null
    private data tempData   
endglobals

private function Conditions takes nothing returns boolean
    return GetSpellAbilityId() == 'A00N'
endfunction

private function Filt takes nothing returns boolean 
    local unit t = GetFilterUnit()
    if( IsUnitEnemy(t,GetOwningPlayer(tempData.caster)) and GetWidgetLife(t)>0.405 and not IsUnitType(t, UNIT_TYPE_MECHANICAL)and not IsUnitInGroup(t, tempData.knockGroup) ) then
        call GroupAddUnit(tempData.knockGroup, t) 
        call UnitAddAbility(t, 'A00O')
    endif    
    set t = null
    return FALSE
endfunction

private function KnockbackGroup takes nothing returns nothing 
    local unit u = GetEnumUnit()
    local real dx = 0.
    local real dy = 0.
    
    set dx = PolarProjectionX(GetUnitX(u), tempData.v, tempData.angle)
    set dy = PolarProjectionY(GetUnitY(u), tempData.v, tempData.angle)     
   
    if IsTerrainWalkable(dx, dy) then
        call SetUnitX(u, dx)
        call SetUnitY(u, dy)
    endif    
endfunction
 
private function Callback takes nothing returns nothing 
    local timer myTimer = GetExpiredTimer()
    local data d = GetTimerData(myTimer)
    local unit target = null
    
    set d.v = d.v*0.925
    
    set tempData = d
    // Enum and add new units to the knockback group
    call GroupEnumUnitsInRange(tempGroup, GetUnitX(d.target), GetUnitY(d.target), 125, filter)  
     // Knockback the entire group
    call ForGroup(d.knockGroup, function KnockbackGroup)     
    
    if d.v <= 5 then       
        loop
            set target = FirstOfGroup(d.knockGroup)
            exitwhen target == null 
            call UnitRemoveAbility(target, 'A00O')
            call GroupRemoveUnit(d.knockGroup, target)
        endloop

        call DestroyGroup(d.knockGroup)       
        call ReleaseTimer(myTimer)
        call d.destroy()
    endif    
endfunction

private function Actions takes nothing returns nothing
    local timer myTimer = NewTimer()
    local unit u = GetTriggerUnit()
    local unit t = GetSpellTargetUnit()
    local real amount = 50+GetHeroLevel(u)*10+GetUnitStat(u, ATTACK_POWER)*0.4*BarbarianDamageModifier(u,t)    
    local data d = data.create()
   
    set d.caster = u
    set d.target = t
    set d.knockGroup = CreateGroup()
    set d.angle = AngleBetweenPointsXY(GetUnitX(u), GetUnitY(u), GetUnitX(t), GetUnitY(t))
    set d.v = 40.
    
    call GroupAddUnit(d.knockGroup, t)
    call UnitAddAbility(t, 'A00O')    
    
    call UnitDamage(u, t, PHYSICAL, amount)
    
    call SetTimerData(myTimer, d)
    call TimerStart(myTimer, 0.03, true, function Callback)
endfunction

function Init takes nothing returns nothing
    local trigger t = CreateTrigger()
    set filter = Condition(function Filt)
    call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition( t, Condition( function Conditions ) )
    call TriggerAddAction( t, function Actions )
endfunction
endscope

Why?

Additional information:
When I comment out the timer stuff, the spell does not crash. This means the spell crash is related either to the timer itself or to the timer callback. It also crashes instantly, which leads me to believe that it doesn't occur in the if-statement

Code:
if d.v <= 5 then       
        loop
            set target = FirstOfGroup(d.knockGroup)
            exitwhen target == null 
            call UnitRemoveAbility(target, 'A00O')
            call GroupRemoveUnit(d.knockGroup, target)
        endloop

        call DestroyGroup(d.knockGroup)       
        call ReleaseTimer(myTimer)
        call d.destroy()
    endif    
01-22-2010, 09:18 PM#2
Ammorth
call GroupEnumUnitsInRange(tempGroup, GetUnitX(d.target), GetUnitY(d.target), 125, filter) You use tempGroup here but I don't see it anywhere else...
01-22-2010, 09:55 PM#3
thehellman
Quote:
Originally Posted by Ammorth
call GroupEnumUnitsInRange(tempGroup, GetUnitX(d.target), GetUnitY(d.target), 125, filter) You use tempGroup here but I don't see it anywhere else...

It's a global declared in a seperate library. tempGroup is a Group variable used for all instant enumeration of units. The group is never filled.
01-22-2010, 11:26 PM#4
Themerion
"Comment out the timer stuff"
?

You should be able to debug this a bit more yourself. For instance, in order to determine if the error lies in the looping code or in the setup, try to make the timer call an empty function:

Collapse JASS:
function Empty takes nothing returns nothing
endfunction

// .... [lots of important code] ....

function TimerStart(myTimer, false, 0.3, function Empty)

Just comment out lines as you say, and print out whatever you can with BJDebugMsg (group count, etc.). You should be able to determine the exact location of the line which is causing the crash.

You could, for instance, check if the timer is valid:
Collapse JASS:
if myTimer != null then
    call BJDebugMsg("Timer exists")
else
    call BJDebugMsg("Timer is imaginary")
endif

-----

You do have a flaw in the code, but I doubt it's related... Without the 'private' keyword, this will give you compiler errors if you try the same thing again:

Collapse JASS:
// missing [private] 
function Init takes nothing returns nothing
01-24-2010, 01:57 AM#5
thehellman
Thanks for the help.

I've commented out everything, and here is the result.

The crash is related to one of these 2 lines.

Quote:
call UnitAddAbility(t, 'A00O')
call GroupAddUnit(d.knockGroup, t)
01-24-2010, 07:41 AM#6
Anitarf
Quote:
Originally Posted by thehellman
Thanks for the help.

I've commented out everything, and here is the result.

The crash is related to one of these 2 lines.
If you have narrowed it down this far, could you possibly narrow it down to one line, then post the code again with that line highlighted?
01-24-2010, 07:54 AM#7
chobibo
Are you using a pre-1.24 version of the TimerUtils? If so upgrade to the latest build, else disregard my post.

Oh, I forgot to ask if you're using 1.24 or later?
01-24-2010, 03:35 PM#8
thehellman
I'm using 1.24+ and the latest TimerUtils.

I'm currently testing, the problem is the crash doesn't happen instantly. It usually happens in the middle of the map when the spell is used, and I can't reproduce it in single-player.

Each test usually takes 30-40 minutes so I'[ll update the post when I've isolated the line.
01-24-2010, 10:07 PM#9
Themerion
I suppose you do not have access to multiple computers, or patient friends?

(I mean, the debugging would go a hell lot faster if you could just cast the spell directly after map has loaded...)
01-28-2010, 04:29 PM#10
thehellman
Quote:
(I mean, the debugging would go a hell lot faster if you could just cast the spell directly after map has loaded...)

Yes, I already do this, but the spell doesn't crash until 30-40 minutes in. It makes it harder because I can't host, so I can never get a game going (usually my friends host for me).

Anyway, I did manage to find the bug. When I commented out the UnitAddAbility(t, 'A000') line, the spell hasn't crashed since. I have no idea why this is though.. any thoughts?
01-28-2010, 07:47 PM#11
Anitarf
It would help if we knew what kind of ability 'A00O' is.
01-29-2010, 10:21 PM#12
thehellman
After 3 tests, it crashes again. Very strange... The frequency of the crashes went down when I commented out that like, but it still happens.

The ability is Tornado Slow Aura dummy, it is used in conjunction with the KnockbackDust effect from one of Vile1s old resources. It's a visual thing, allows me to show a knockback effect without DestroyEffect(CreateEffect())
02-01-2010, 07:58 PM#13
thehellman
I've decided to attach said-map.

This is a full-fledged map that normally wouldn't be unprotected. I'm only doing it on these forums because I may just not work on it anymore, so I don't care what happens to it. With this Cleave bug, I can't really work on it anymore because it just crashes

If anyone can fix it, please tell me. The problem could very well lie somewhere else in the triggering. I understand it's quite a large project, and therefore will be a large thing to go through, but I could really use the help.

You'll need JassNewGen.

EDIT: Map removed.
02-01-2010, 09:48 PM#14
Themerion
As far as Cleave's concerned, there's not much to say. I'd still use a private tempGroup, but I doubt that matters. I'd say your problem lies elsewhere.

For the rest of the map, well. I really hope you sort out this issue.

PS.
I did get a debug message from JASSHelper's debug mode when I killed the splitting spider (seems like you call .destroy on the same struct twice). You might want to check that.
02-02-2010, 12:34 AM#15
thehellman
Quote:
I did get a debug message from JASSHelper's debug mode when I killed the splitting spider (seems like you call .destroy on the same struct twice). You might want to check that.

Can you go into detail about this? Did you use Cleave? In that build there is an issue with UnitPile, about a double free timer being released - I fixed that, thanks for pointing it out. However, I can't get any error messages when using Cleave.