| 01-22-2010, 08:43 PM | #1 |
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 |
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 | |
Quote:
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 |
"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: 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: 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: JASS:// missing [private] function Init takes nothing returns nothing |
| 01-24-2010, 01:57 AM | #5 | |
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:
|
| 01-24-2010, 07:41 AM | #6 | |
Quote:
|
| 01-24-2010, 07:54 AM | #7 |
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 |
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 |
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 | |
Quote:
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 |
It would help if we knew what kind of ability 'A00O' is. |
| 01-29-2010, 10:21 PM | #12 |
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 |
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 |
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. 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 | |
Quote:
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. |
