• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • 🏆 Hive's 6th HD Modeling Contest: Mechanical is now open! Design and model a mechanical creature, mechanized animal, a futuristic robotic being, or anything else your imagination can tinker with! 📅 Submissions close on June 30, 2024. Don't miss this opportunity to let your creativity shine! Enter now and show us your mechanical masterpiece! 🔗 Click here to enter!

memory leak problems

Status
Not open for further replies.
Level 3
Joined
Jun 2, 2015
Messages
45
Hello guys, my name is SC_player, I'm working on a defense map currently. I'm wondering how to fix the trigger and triggeraction leaks in this spell.


Trigger:
JASS:
function income takes nothing returns nothing
    local group g = CreateGroup()
    local integer i =0
    local integer count = 0
    local unit first
    set playerInc=0
    loop
        exitwhen i==10
        set tmpInt = incBuildings[i]
        set count=0
        call GroupEnumUnitsOfPlayer(g, Player(0), Filter(function GenFilter))
        loop
            set first=FirstOfGroup(g)
            exitwhen first==null
            set count=count+1
            call GroupRemoveUnit(g,first)
        endloop
        set playerInc=playerInc+count*incAmountPer[i]
        set i=i+1
        call LeaderboardSetItemValue(P_Income, LeaderboardGetPlayerIndex(P_Income, Player(0)), playerInc)
    endloop
    call SetPlayerState(Player(0), PLAYER_STATE_RESOURCE_GOLD, GetPlayerState(Player(0), PLAYER_STATE_RESOURCE_GOLD)+playerInc)
    call DestroyGroup(g)
    set g = null
    set first=null
endfunction
function Order takes unit u returns nothing
    if GetUnitCurrentOrder(u) != OrderId("attack") and GetUnitCurrentOrder(u) != OrderId("firebolt") then
        call IssuePointOrder(u, "attack", GetRandomReal(-5200, 3275), GetRandomReal(-1400, 1400))
    endif
endfunction
function spawnFilter takes nothing returns boolean
    local integer id=GetUnitTypeId(GetFilterUnit())
    if id == 'o000' or id == 'o001' or id == 'o002' or id == 'o004' or id == 'o00O' or id == 'o00E' or id == 'o00P' or id == 'o00Q' or id == 'o00B' or id == 'o00R' or id == 'o00A' then
        return true
    endif
    return false
endfunction
function spawn takes unit spawner returns nothing
    local unit u
    local integer chance=GetRandomInt(0, spawnDiff)
    if chance>3 then
        if chance >=47 then
            set u = CreateUnit(Player(10), 'o00B', GetUnitX(spawner), GetUnitY(spawner), bj_UNIT_FACING)
        endif
        if chance >=37 and chance <47 then
            set u = CreateUnit(Player(10), 'o004', GetUnitX(spawner), GetUnitY(spawner), bj_UNIT_FACING)
        endif
        if chance >=27 and chance <37 then
            set u = CreateUnit(Player(10), 'o002', GetUnitX(spawner), GetUnitY(spawner), bj_UNIT_FACING)
        endif
        if chance>=17 and chance <27 then
            set u = CreateUnit(Player(10), 'o001', GetUnitX(spawner), GetUnitY(spawner), bj_UNIT_FACING)
        endif
        if chance<17 then
            set u = CreateUnit(Player(10), 'o000', GetUnitX(spawner), GetUnitY(spawner), bj_UNIT_FACING)
        endif
    endif
    set u = null
endfunction
function spawnPlus takes unit spawner returns nothing
    local unit u
    if spawnDiff==55 then
        set u = CreateUnit(Player(10), 'o00R', GetUnitX(spawner), GetUnitY(spawner), 0)
//        set HealWave_boss = u
//        call HealWave_init()
    endif
    if spawnDiff==45 then
        set u = CreateUnit(Player(10), 'o00Q', GetUnitX(spawner), GetUnitY(spawner), 0)
    endif
    if spawnDiff==35 then
        set u = CreateUnit(Player(10), 'o00P', GetUnitX(spawner), GetUnitY(spawner), 0)
    endif
    if spawnDiff==25 then
        set u = CreateUnit(Player(10), 'o00E', GetUnitX(spawner), GetUnitY(spawner), bj_UNIT_FACING)
    endif
    if spawnDiff == 15 then
        set u = CreateUnit(Player(10), 'o00O', GetUnitX(spawner), GetUnitY(spawner), bj_UNIT_FACING)
    endif
    if spawnDiff >=50 then
        set u = CreateUnit(Player(10), 'o00B', GetUnitX(spawner), GetUnitY(spawner), bj_UNIT_FACING)
        set u = CreateUnit(Player(10), 'o00B', GetUnitX(spawner), GetUnitY(spawner), bj_UNIT_FACING)
    endif
    if spawnDiff >=40 and spawnDiff < 50 then
        set u = CreateUnit(Player(10), 'o004', GetUnitX(spawner), GetUnitY(spawner), bj_UNIT_FACING)
        set u = CreateUnit(Player(10), 'o004', GetUnitX(spawner), GetUnitY(spawner), bj_UNIT_FACING)
    endif
    if spawnDiff >=30 and spawnDiff < 40 then
        set u = CreateUnit(Player(10), 'o002', GetUnitX(spawner), GetUnitY(spawner), bj_UNIT_FACING)
        set u = CreateUnit(Player(10), 'o002', GetUnitX(spawner), GetUnitY(spawner), bj_UNIT_FACING)
    endif
    if spawnDiff >=20 and spawnDiff < 30 then
        set u = CreateUnit(Player(10), 'o001', GetUnitX(spawner), GetUnitY(spawner), bj_UNIT_FACING)
        set u = CreateUnit(Player(10), 'o001', GetUnitX(spawner), GetUnitY(spawner), bj_UNIT_FACING)
    endif
    if spawnDiff >=3 and spawnDiff<20 then
        set u = CreateUnit(Player(10), 'o000', GetUnitX(spawner), GetUnitY(spawner), bj_UNIT_FACING)
        set u = CreateUnit(Player(10), 'o000', GetUnitX(spawner), GetUnitY(spawner), bj_UNIT_FACING)
    endif
    set u = null
endfunction
function Trig_Gametime_Actions takes nothing returns nothing
    local integer i = 0
    local integer a = 0
    local unit first
    local group g = CreateGroup()
    if(counter==0) then
        call TimerDialogDisplay(GameTime, true)
        set P_Income=CreateLeaderboard()
        call PlayerSetLeaderboard(Player(0), P_Income)
        call LeaderboardAddItem(P_Income, GetPlayerName(Player(0)), 0, Player(0))
        call LeaderboardSetLabel(P_Income, "Income")
        call LeaderboardSetSizeByItemCount(P_Income, LeaderboardGetItemCount(P_Income))
        call LeaderboardDisplay(P_Income, true)
    endif
    call TimerStart(gameTimer, counter, false, null)
    call PauseTimer(gameTimer)
    call GroupEnumUnitsOfPlayer(g, Player(10), Filter(function spawnFilter))
    loop
        set first=FirstOfGroup(g)
        exitwhen first==null
        call Order(first)
        call GroupRemoveUnit(g,first)
    endloop
    if counter==5 then
        call DisplayTextToPlayer(Player(0), 0, 0, "Defend from the endless waves...")
    endif
    if counter==10 then
        call DisplayTextToPlayer(Player(0), 0, 0, "The horde arrives at 4:00.")
    endif
    if counter==240 then
        set spawnDiff=3
    endif
    if counter==270 then
        set spawnDiff=4
    endif
    if counter==300 then
        set spawnDiff=5
    endif
    if counter==330 then
        set spawnDiff=6
    endif
    if counter==360 then
        set spawnDiff=7
    endif
    if counter==390 then
        set spawnDiff=8
    endif
    if counter==420 then
        set spawnDiff=9
    endif
    if counter==450 then
        set spawnDiff=10
    endif
    if counter==480 then
        set spawnDiff=11
    endif
    if counter==510 then
        set spawnDiff=12
    endif
    if counter==540 then
        set spawnDiff=13
    endif
    if counter==570 then
        set spawnDiff=14
    endif
    if counter==600 then
        set spawnDiff=15
    endif
    if counter==620 then
        set spawnDiff=16
    endif
    if counter==660 then
        set spawnDiff=17
    endif
    if counter==690 then
        set spawnDiff=18
    endif
    if counter==720 then
        set spawnDiff=19
    endif
    if counter==750 then
        set spawnDiff=20
    endif
    if counter==780 then
        set spawnDiff=21
    endif
    if counter==810 then
        set spawnDiff=22
    endif
    if counter==840 then
        set spawnDiff=23
    endif
    if counter==870 then
        set spawnDiff=24
    endif
    if counter==900 then
        set spawnDiff=25
    endif
    if counter==920 then
        set spawnDiff=26
    endif
    if counter==960 then
        set spawnDiff=27
    endif
    if counter==990 then
        set spawnDiff=28
    endif
    if counter==1020 then
        set spawnDiff=29
    endif
    if counter==1050 then
        set spawnDiff=30
    endif
    if counter==1080 then
        set spawnDiff=31
    endif
    if counter==1110 then
        set spawnDiff=32
    endif
    if counter==1140 then
        set spawnDiff=33
    endif
    if counter==1170 then
        set spawnDiff=34
    endif
    if counter==1200 then
        set spawnDiff=35
    endif
    if counter==1220 then
        set spawnDiff=36
    endif
    if counter==1260 then
        set spawnDiff=37
    endif
    if counter==1290 then
        set spawnDiff=38
    endif
    if counter==1320 then
        set spawnDiff=39
    endif
    if counter==1350 then
        set spawnDiff=40
    endif
    if counter==1380 then
        set spawnDiff=41
    endif
    if counter==1410 then
        set spawnDiff=42
    endif
    if counter==1440 then
        set spawnDiff=43
    endif
    if counter==1470 then
        set spawnDiff=44
    endif
    if counter==1500 then
        set spawnDiff=45
    endif
    if counter==1520 then
        set spawnDiff=46
    endif
    if counter==1560 then
        set spawnDiff=47
    endif
    if counter==1590 then
        set spawnDiff=48
    endif
    if counter==1620 then
        set spawnDiff=49
    endif
    if counter==1650 then
        set spawnDiff=50
    endif
    if counter==1680 then
        set spawnDiff=51
    endif
    if counter==1710 then
        set spawnDiff=52
    endif
    if counter==1740 then
        set spawnDiff=53
    endif
    if counter==1770 then
        set spawnDiff=54
    endif
    if counter==1800 then
        set spawnDiff=55
    endif
    if counter==1820 then
        set spawnDiff=56
    endif
    if counter==1860 then
        set spawnDiff=57
    endif
    if counter==1890 then
        set spawnDiff=58
    endif
    if counter==1920 then
        set spawnDiff=59
    endif
    if counter==1950 then
        set spawnDiff=60
    endif
    if counter==1980 then
        set spawnDiff=61
    endif
    if counter==2010 then
        set spawnDiff=62
    endif
    if counter==2040 then
        set spawnDiff=63
    endif
    if counter==2070 then
        set spawnDiff=64
    endif
    if counter==2100 then
        set spawnDiff=65
    endif
    if counter == 2120 then
        set spawnDiff=66
    endif
    if counter-(counter/5)*5==0 then
        call income()
    endif
    if counter-(counter/20)*20==0 then
        set tmpInt= 'h01Y'
        call GroupEnumUnitsOfPlayer(g, Player(10), Filter(function GenFilter))
        loop
            set first=FirstOfGroup(g)
            exitwhen first==null
            call spawn(first)
            call GroupRemoveUnit(g,first)
        endloop
        set tmpInt= 'h01L'
        call GroupEnumUnitsOfPlayer(g, Player(10), Filter(function GenFilter))
        loop
            set first=FirstOfGroup(g)
            exitwhen first==null
            call spawnPlus(first)
            call GroupRemoveUnit(g,first)
        endloop
    endif
    call GroupEnumUnitsOfPlayer(g, Player(10), Filter(function spawnFilter))
    loop
        set first=FirstOfGroup(g)
        exitwhen first==null
        call Order(first)
        call GroupRemoveUnit(g,first)
    endloop
    call RemoveAllGuardPositions(Player(10))
    set counter=counter+1
    call DestroyGroup(g)
    set g=null
    set first=null
endfunction

//===========================================================================
function InitTrig_Gametime takes nothing returns nothing
    set gg_trg_Gametime = CreateTrigger(  )
    call TriggerRegisterTimerEvent( gg_trg_Gametime, 1.00, true )
    call TriggerAddAction( gg_trg_Gametime, function Trig_Gametime_Actions )
endfunction
Here is an explanation of the map, thanks to anyone who can offer insight to what is causing the problem.
http://www.hiveworkshop.com/forums/introductions-360/hey-guys-266475/
146040d1434150252-memory-leak-problems-error.jpg
 

Attachments

  • defense map 1.w3x
    100.2 KB · Views: 62
Last edited:
Level 3
Joined
Jun 2, 2015
Messages
45
oh you are right about that but actually that used to be all the same function, using the same local group, that was nulled. My mistake there but I believe there must be another one somewhere because it leaked before I separated out those functions. I will test anyways just to make sure :) thanks for pointing out the obvious /facepalm

edit: so after testing the error has changed, 0x000000 referenced at 0x000000 instead of some other code at 23:000000000
 
Last edited:
I don't see leaks beyond that. How do you know that you have memory leaks? Are you using a handle counter, or is it just lagging frame-wise? (i.e. fps drop)

The whole script could be optimized so that you don't have to do as many enumerations. Enumeration is expensive, and if you're doing it every second many times--it may cause spikey performance. Rather than enumerating all the units of that unit-type every time the timer ticks, you should just maintain 1 group (since it seems they all go to the "Order" function). Whenever you create a unit of any of the selected types, add it to the group. This will massively cut down the performance requirement of the script.

You can also make minor optimizations such as this:
JASS:
    if counter==240 then
        set spawnDiff=3
    endif
    if counter==270 then
        set spawnDiff=4
    endif
    if counter==300 then
        set spawnDiff=5
    endif
    if counter==330 then
        set spawnDiff=6
    endif
    if counter==360 then
        set spawnDiff=7
    endif
    if counter==390 then
        set spawnDiff=8
    endif
    if counter==420 then
        set spawnDiff=9
    endif
    if counter==450 then
        set spawnDiff=10
    endif
    if counter==480 then
        set spawnDiff=11
    endif
    if counter==510 then
        set spawnDiff=12
    endif
    if counter==540 then
        set spawnDiff=13
    endif
    if counter==570 then
        set spawnDiff=14
    endif
    if counter==600 then
        set spawnDiff=15
    endif
    if counter==620 then
        set spawnDiff=16
    endif
    if counter==660 then
        set spawnDiff=17
    endif
    if counter==690 then
        set spawnDiff=18
    endif
    if counter==720 then
        set spawnDiff=19
    endif
    if counter==750 then
        set spawnDiff=20
    endif
    if counter==780 then
        set spawnDiff=21
    endif
    if counter==810 then
        set spawnDiff=22
    endif
    if counter==840 then
        set spawnDiff=23
    endif
    if counter==870 then
        set spawnDiff=24
    endif
    if counter==900 then
        set spawnDiff=25
    endif
    if counter==920 then
        set spawnDiff=26
    endif
    if counter==960 then
        set spawnDiff=27
    endif
    if counter==990 then
        set spawnDiff=28
    endif
    if counter==1020 then
        set spawnDiff=29
    endif
    if counter==1050 then
        set spawnDiff=30
    endif
    if counter==1080 then
        set spawnDiff=31
    endif
    if counter==1110 then
        set spawnDiff=32
    endif
    if counter==1140 then
        set spawnDiff=33
    endif
    if counter==1170 then
        set spawnDiff=34
    endif
    if counter==1200 then
        set spawnDiff=35
    endif
    if counter==1220 then
        set spawnDiff=36
    endif
    if counter==1260 then
        set spawnDiff=37
    endif
    if counter==1290 then
        set spawnDiff=38
    endif
    if counter==1320 then
        set spawnDiff=39
    endif
    if counter==1350 then
        set spawnDiff=40
    endif
    if counter==1380 then
        set spawnDiff=41
    endif
    if counter==1410 then
        set spawnDiff=42
    endif
    if counter==1440 then
        set spawnDiff=43
    endif
    if counter==1470 then
        set spawnDiff=44
    endif
    if counter==1500 then
        set spawnDiff=45
    endif
    if counter==1520 then
        set spawnDiff=46
    endif
    if counter==1560 then
        set spawnDiff=47
    endif
    if counter==1590 then
        set spawnDiff=48
    endif
    if counter==1620 then
        set spawnDiff=49
    endif
    if counter==1650 then
        set spawnDiff=50
    endif
Can become:
JASS:
set spawnDiff = counter/30 - 5
If there is a chance that it is any number in between those values above, you can always just add an if statement such as if (counter >= 240) and (counter <= 1650) and (ModuloInt(counter, 30) == 0) then. eh, something like that.

You can also cache some things like GetUnitX(GetEnumUnit())/GetUnitY() in spawnPlus. But the key thing is to avoid the enumerations.
 
Level 3
Joined
Jun 2, 2015
Messages
45
it crashes after a long period about 25-30 minutes. before I had the last memory leak that you just pointed out it crashed around 23-25 minutes. its always at a different time though at least its never the same time twice in a row.

I see what your saying about the group, so I should use a global group to keep track of the "horde" as I call it? And should I make a group array to hold each player's income buildings?

As for the counter, the problem I had is that spawns are every 20 seconds, but the difficulty changes every 30 seconds, therefore at 25, 35, and 45, where the bosses are spawned, it will spawn 2 bosses, so I must change the difficulty 20 seconds after the boss wave in order to prevent that. I was under the impression that it was more of a clarity problem than efficiency, but I might be mistaken.

Edit: I have made the optimizations that you have suggested with the groups, I keep track of all spawned units in a single group and call the order function to this group every second, and I add income buildings to a group when they are created. However, the map still crashes at about 27:00.

Edit 2: I updated the trigger in the first post to the new trigger. If anyone could give some insight on what might be causing the crash, that would be quite helpful. I know its quite a large, bulky trigger so I appreciate the effort =/
 
Last edited:
Level 3
Joined
Jun 2, 2015
Messages
45
So I attempted to use a handle counter, and for some reason it stopped my income trigger from working. however, it was going up by 3 every second or so, almost exactly along with the countdown timer... seems like it has something to do with this trigger. No units or income were being spawned yet.
 
Level 3
Joined
Jun 2, 2015
Messages
45
the timer must be paused to count from 0 upwards, I update the timer's amount every second to give the appearance of it counting upwards. I will take a look at that later. Thanks for the insight. Do you think that enumerating too many units in the old way could crash the map? Or enumerating that way too many times?

Edit: after reading, it seems to me that the firstofgroup method would work well for the income and spawning part, however I think it would make more sense having the spawned enemies stored in a group that I call order on every second. Is that an ok method?

Edit 2: also, what is the difference between forgroup and a firstofgroup loop, wouldn't that be the same thing, except forgroup preserves the group?
 
Last edited:
the timer must be paused to count from 0 upwards, I update the timer's amount every second to give the appearance of it counting upwards. I will take a look at that later. Thanks for the insight. Do you think that enumerating too many units in the old way could crash the map? Or enumerating that way too many times?
No, forGroup works, but it's way slower than FoG and also requires a lot of useless extra code, as you can't easily pass over data to ForGroup loops.
In a FoG loop, you can just use locals. No need to store any data in globals or attach them to units.

Edit: after reading, it seems to me that the firstofgroup method would work well for the income and spawning part, however I think it would make more sense having the spawned enemies stored in a group that I call order on every second. Is that an ok method?
Using groups over a longer period of time is not a good idea anyway, as they are vulnerable to so-called shadow references. Any unit that dies or gets removed will leave a reference in any group it was added to. This only gets cleaned up if a group gets cleared or destroyed. This might not be a big deal early on, but in hour-long games, groups get slower and slower, especially on maps with high spawn rates like tower defenses.

Edit 2: also, what is the difference between forgroup and a firstofgroup loop, wouldn't that be the same thing, except forgroup preserves the group?
It practically does the same, except a firstofgroup loop basicly clears the group in the process.
However, FoG has several advantages over ForGroup:
1) easy passing of data
2) much faster
3) can be terminated early by using exitwhen or return
4) easier to read, as it doesn't require a seperate function

It's generally a good practice to use FoG whenever you don't need a group be preserved.
 
Level 3
Joined
Jun 2, 2015
Messages
45
so im guessing whats causing my crash is these shadow references then, within my "horde" group, as every unit would die eventually

edit: I changed all the enum's to first of group loops, however my map still crashes at about 28 minutes. any ideas?

Edit: added error message thought it might be helpful
 

Attachments

  • error.JPG
    error.JPG
    29.6 KB · Views: 298
Last edited:
so im guessing whats causing my crash is these shadow references then, within my "horde" group, as every unit would die eventually

edit: I changed all the enum's to first of group loops, however my map still crashes at about 28 minutes. any ideas?

Edit: added error message thought it might be helpful
Are you actually sure it's this trigger? Can't find anything wrong with it.
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,202
Leaks should not be causing that kind of error. More likely some bug somewhere (eg passing null to a function that cannot cope with it).

With persistent groups be aware that removed units still exist inside. Unless you remove the unit from the group before it gets removed from the game you will need to perform a group swap to flush out the removed units. This is where you iterate through all units in the group (ForGroup as I think FirstOfGroup might break) and reject all "null" units that you get from the group adding any non null unit to a clean group. After you have done swapping the group contents across you can clear the group and re-cycle it.
 
Level 3
Joined
Jun 2, 2015
Messages
45
I cant see what else it would be nothing else runs at the times that it crashes... I only have a few other small triggers in the map

edit: I also tried disabling the "order" function and just allowing the units to sit there and it didn't crash after 30 minutes, never made it that far... is it possible that its just too many units? that would be really sad

edit 2: I no longer use any persistent groups

edit 3: I did some more testing. only calling order every 5 seconds instead of 1 had no effect.
 
Last edited:
Level 3
Joined
Jun 2, 2015
Messages
45
sorry for the double post, im attaching the map in case anyone wants to take a look at it, however, in its current state it is quite difficult because I am planning on adding bonuses later. In order to reach the spot where it bugs, you have to reach about 30 minutes. Im going to be away from my computer for the next couple days so if anyone could look at it, that would be wonderful... I am at the end of my capabilities, unfortunately =/
 
I just noticed you null the unit variables passed via the spawn functions! Don't do this as you keep using them in the main thread! Only null local variables created inside the same function.

remove:
set spawner=null
on the bottom of your "spawn" and "spawnplus" functions.
And also the set u=null at the bottom of your order function.
 
Level 3
Joined
Jun 2, 2015
Messages
45
ah so because I nulled those they were not actually getting removed from the group?

edit: so, magical new problem appeared while I was gone, newgen crashes every time I save now...

edit 2: so somehow in the recently opened list I have 2 copies of my map from the same path, one of them crashes when I save and the other doesn't... hopefully it doesn't turn up again but it seems very strange

edit 3: I no longer null the function parameters, however, it still crashes around the same time. I have noticed that it is at least on a multiple of 5 seconds, but could be on a multiple of 20 seconds. Another thing that I noticed is that over time, the enemies will begin to get stuck and pile up in the base. I believe this is because one unit is trying to walk through to the other side of the spawners, but all the other units are trying to walk out of that space. Could this pile-up be the problem?
 
Last edited:
Level 3
Joined
Jun 2, 2015
Messages
45
sooooo... I apologize for running you guys on a wild goose chase, but I had forgotten one of my spells had been triggered, and in fact, leaks a trigger action I believe... I'm not sure how to deal with this. Thank you again.

JASS:
library ShieldofFrost initializer init uses IntuitiveDamageSystem 
    private function IK takes nothing returns boolean
        if GetUnitTypeId(GetTriggerDamageTarget()) == 'h026' then
            return true
        endif
        return false
    endfunction
    private function slow takes nothing returns nothing
        local unit u=CreateUnit(GetOwningPlayer(GetTriggerDamageTarget()), 'n002', GetUnitX(GetTriggerDamageTarget()), GetUnitY(GetTriggerDamageTarget()), 0)
        call IssueTargetOrder(u, "slow", GetTriggerDamageSource())
        call RemoveUnit(u)
        set u=null
    endfunction
    private function init takes nothing returns nothing
        local trigger SoFTrg = CreateTrigger()
        call TriggerRegisterDamageEvent(SoFTrg, 0)
        call TriggerAddCondition(SoFTrg, Condition(function IK))
        call TriggerAddAction(SoFTrg, function slow)
    endfunction
endlibrary
 
Level 3
Joined
Jun 2, 2015
Messages
45
don't I have to destroy local trigger? also, when I tried to use a triggerdata struct in order to avoid leaking a trigger, the spell stopped working but the game no longer crashed...
started at about 130 mb and rose to 168, around... crashed at 32 this time

edit: disabling this trigger caused it not to crash at all, I quit at 37:30 about
 
Last edited:
You seem to have a misconception about what leaks actually are.

You never destroy triggers, unless you create them dynamically.
You can null a local trigger pointer to avoid a lost reference, but since you only create them on map init and not create them dynamically, it doesn't really matter.

Look, I've been coding for WC3 since the day the game was released. The trigger above is fine, I'll guarantee you that.
What I can not guarantee you, is that this "IntuitiveDamageSystem" you are using in these triggers is working flawlessly, though.

So if this last trigger you posted actually crashes your game, then your problem is the damage system.


Also, 130mb to 168mb is not a terribly large rise in memory usage for WC3. In fact, that's pretty normal.
 
Level 3
Joined
Jun 2, 2015
Messages
45
well I would agree with you that this trigger seems fine, however, when I disable the trigger the crash goes away. changing the intuitive damage system to normal event unit attack and etc had no effect, still crashes at the same time

Edit: also on a sort of related note, would this trigger be better using a scope or a library? I understand the differences, not so much when to use each.
 
Last edited:
well I would agree with you that this trigger seems fine, however, when I disable the trigger the crash goes away. changing the intuitive damage system to normal event unit attack and etc had no effect, still crashes at the same time

Edit: also on a sort of related note, would this trigger be better using a scope or a library? I understand the differences, not so much when to use each.
Btw, very simple question: do you have any events that fire on spellcast in your map? If so, do they have a condition not to fire on the dummy spell you use in this script?
I suspect a trigger loop caused by the spellcast event.

Library, scope, doesn't matter.
Usually you use libraries for systems and scopes for spells, as scopes are lower in hirarchy.

The order of initialization is basicly:

Library <-- Scope <-- normal code

If you make spells scopes and systems libraries, you don't have to write a large dependency list for your spells, as scopes are always initialized after libraries.
 
Level 3
Joined
Jun 2, 2015
Messages
45
i do not have any events that fire on spell cast, but I do have one that fires when a unit is trained or a structure is constructed... I don't think that would count when I create a unit from a trigger, unless im mistaken. The only other events I have are when a unit gets attacked and when the main builder dies, besides the periodic one second timer.

edit: one other thing, I heard that locust ability can cause problems with removing units, is this true?
edit 2: don't think this is the problem after testing... seems to remove fine
 
Last edited:
i do not have any events that fire on spell cast, but I do have one that fires when a unit is trained or a structure is constructed... I don't think that would count when I create a unit from a trigger, unless im mistaken. The only other events I have are when a unit gets attacked and when the main builder dies, besides the periodic one second timer.

edit: one other thing, I heard that locust ability can cause problems with removing units, is this true?
edit 2: don't think this is the problem after testing... seems to remove fine
The only problem with removing locust units comes when you try to enumerate all units on the map via GroupEnumUnitsInRect.
Locust units basicly ignore Enumeration calls - except for EnumUnitsOfPlayer for some odd reason.

But usually, locust units ignoring Enum calls is a desirable behaviour. You don't want scripted spells to mess with your locust units after all.


Do you have any "Enter Rect" events? Or simply anything that could fire if you create a unit or issue an order? If so, deactivate those temporarily and check if it works now.
I'm out of ideas, tbh.
 
Level 3
Joined
Jun 2, 2015
Messages
45
These are the only 3 triggers I have enabled right now, and it crashes still:
JASS:
globals
    //To hold spawned units, to be filled later.
    integer spawnDiff = 0
    //Income per building, the unit types of the buildings, and each players income.
    integer array incAmountPer
    integer array incBuildings
    integer playerInc
    //Timers
    timer gameTimer
    timer endTimer
    timerdialog GameTime
    //Counter for game time counter that counts up.
    integer counter = 0
    leaderboard P_Income
    unit builder
    integer tmpInt
endglobals

library GlobalFilters
    function Unit takes nothing returns boolean
        return GetUnitMoveSpeed(GetFilterUnit())>0
    endfunction
    function Structure takes nothing returns boolean
        return GetUnitMoveSpeed(GetFilterUnit())<=0
    endfunction
    function GenFilter takes nothing returns boolean
        if GetUnitTypeId(GetFilterUnit())==tmpInt then 
            return true
        else 
            return false
        endif
    endfunction
    function HordeFilter takes nothing returns boolean
        if GetOwningPlayer(GetFilterUnit()) == Player(10) and GetUnitState(GetFilterUnit(), UNIT_STATE_LIFE) >= .405 then
            return true
        endif
        return false
    endfunction
endlibrary
JASS:
scope Init initializer init
    //Done on initialization.
    private function init takes nothing returns nothing
        //Populate player array and get total players.
        local unit u
        call FogMaskEnable(false)
        set u=CreateUnit(Player(0), 'h000', GetStartLocationX(GetPlayerStartLocation(Player(0))), GetStartLocationY(GetPlayerStartLocation(Player(0))), bj_UNIT_FACING)
        set builder=u
        call SetPlayerState(Player(0), PLAYER_STATE_RESOURCE_GOLD, 100)
        call SetPlayerState(Player(10), PLAYER_STATE_GIVES_BOUNTY, 1)
        //Populate income arrays, to keep track of the order of upgrades and to keep track of how much income they give.
        set incBuildings[0]='h004'
        set incAmountPer[0]=1
        set incBuildings[1]='h01O'
        set incAmountPer[1]=3
        set incBuildings[2]='h01P'
        set incAmountPer[2]=5
        set incBuildings[3]='h01Q'
        set incAmountPer[3]=7
        set incBuildings[4]='h01R'
        set incAmountPer[4]=10
        set incBuildings[5]='h01S'
        set incAmountPer[5]=15
        set incBuildings[6]='h01T'
        set incAmountPer[6]=25
        set incBuildings[7]='h01V'
        set incAmountPer[7]=40
        set incBuildings[8]='h01U'
        set incAmountPer[8]=65
        set incBuildings[9]='h01W'
        set incAmountPer[9]=100
        set incBuildings[10]='h01X'
        set incAmountPer[10]=150
        set counter=0
        set gameTimer=CreateTimer()
        set GameTime=CreateTimerDialog(gameTimer)
        call TimerDialogSetTitle(GameTime, "Game Time")
        call TimerDialogSetRealTimeRemaining(GameTime, 0)
        call TimerStart(gameTimer,0,false,null)
        call SetCameraField(CAMERA_FIELD_TARGET_DISTANCE, 2000, 0)
        set u=null
    endfunction
endscope
JASS:
function income takes nothing returns nothing
    local group g = CreateGroup()
    local integer i =0
    local integer count = 0
    local unit first
    set playerInc=0
    loop
        exitwhen i==10
        set tmpInt = incBuildings[i]
        set count=0
        call GroupEnumUnitsOfPlayer(g, Player(0), Filter(function GenFilter))
        loop
            set first=FirstOfGroup(g)
            exitwhen first==null
            set count=count+1
            call GroupRemoveUnit(g,first)
        endloop
        set playerInc=playerInc+count*incAmountPer[i]
        set i=i+1
        call LeaderboardSetItemValue(P_Income, LeaderboardGetPlayerIndex(P_Income, Player(0)), playerInc)
    endloop
    call SetPlayerState(Player(0), PLAYER_STATE_RESOURCE_GOLD, GetPlayerState(Player(0), PLAYER_STATE_RESOURCE_GOLD)+playerInc)
    call DestroyGroup(g)
    set g = null
    set first=null
endfunction
function Order takes unit u returns nothing
    if GetUnitCurrentOrder(u) != OrderId("attack") and GetUnitCurrentOrder(u) != OrderId("firebolt") then
        call IssuePointOrder(u, "attack", GetRandomReal(-5200, 3275), GetRandomReal(-1400, 1400))
    endif
endfunction
function spawnFilter takes nothing returns boolean
    local integer id=GetUnitTypeId(GetFilterUnit())
    if id == 'o000' or id == 'o001' or id == 'o002' or id == 'o004' or id == 'o00O' or id == 'o00E' or id == 'o00P' or id == 'o00Q' or id == 'o00B' or id == 'o00R' or id == 'o00A' then
        return true
    endif
    return false
endfunction
function spawn takes unit spawner returns nothing
    local unit u
    local integer chance=GetRandomInt(0, spawnDiff)
    if chance>3 then
        if chance >=47 then
            set u = CreateUnit(Player(10), 'o00B', GetUnitX(spawner), GetUnitY(spawner), bj_UNIT_FACING)
        endif
        if chance >=37 and chance <47 then
            set u = CreateUnit(Player(10), 'o004', GetUnitX(spawner), GetUnitY(spawner), bj_UNIT_FACING)
        endif
        if chance >=27 and chance <37 then
            set u = CreateUnit(Player(10), 'o002', GetUnitX(spawner), GetUnitY(spawner), bj_UNIT_FACING)
        endif
        if chance>=17 and chance <27 then
            set u = CreateUnit(Player(10), 'o001', GetUnitX(spawner), GetUnitY(spawner), bj_UNIT_FACING)
        endif
        if chance<17 then
            set u = CreateUnit(Player(10), 'o000', GetUnitX(spawner), GetUnitY(spawner), bj_UNIT_FACING)
        endif
    endif
    set u = null
endfunction
function spawnPlus takes unit spawner returns nothing
    local unit u
    if spawnDiff==55 then
        set u = CreateUnit(Player(10), 'o00R', GetUnitX(spawner), GetUnitY(spawner), 0)
//        set HealWave_boss = u
//        call HealWave_init()
    endif
    if spawnDiff==45 then
        set u = CreateUnit(Player(10), 'o00Q', GetUnitX(spawner), GetUnitY(spawner), 0)
    endif
    if spawnDiff==35 then
        set u = CreateUnit(Player(10), 'o00P', GetUnitX(spawner), GetUnitY(spawner), 0)
    endif
    if spawnDiff==25 then
        set u = CreateUnit(Player(10), 'o00E', GetUnitX(spawner), GetUnitY(spawner), bj_UNIT_FACING)
    endif
    if spawnDiff == 15 then
        set u = CreateUnit(Player(10), 'o00O', GetUnitX(spawner), GetUnitY(spawner), bj_UNIT_FACING)
    endif
    if spawnDiff >=50 then
        set u = CreateUnit(Player(10), 'o00B', GetUnitX(spawner), GetUnitY(spawner), bj_UNIT_FACING)
        set u = CreateUnit(Player(10), 'o00B', GetUnitX(spawner), GetUnitY(spawner), bj_UNIT_FACING)
    endif
    if spawnDiff >=40 and spawnDiff < 50 then
        set u = CreateUnit(Player(10), 'o004', GetUnitX(spawner), GetUnitY(spawner), bj_UNIT_FACING)
        set u = CreateUnit(Player(10), 'o004', GetUnitX(spawner), GetUnitY(spawner), bj_UNIT_FACING)
    endif
    if spawnDiff >=30 and spawnDiff < 40 then
        set u = CreateUnit(Player(10), 'o002', GetUnitX(spawner), GetUnitY(spawner), bj_UNIT_FACING)
        set u = CreateUnit(Player(10), 'o002', GetUnitX(spawner), GetUnitY(spawner), bj_UNIT_FACING)
    endif
    if spawnDiff >=20 and spawnDiff < 30 then
        set u = CreateUnit(Player(10), 'o001', GetUnitX(spawner), GetUnitY(spawner), bj_UNIT_FACING)
        set u = CreateUnit(Player(10), 'o001', GetUnitX(spawner), GetUnitY(spawner), bj_UNIT_FACING)
    endif
    if spawnDiff >=3 and spawnDiff<20 then
        set u = CreateUnit(Player(10), 'o000', GetUnitX(spawner), GetUnitY(spawner), bj_UNIT_FACING)
        set u = CreateUnit(Player(10), 'o000', GetUnitX(spawner), GetUnitY(spawner), bj_UNIT_FACING)
    endif
    set u = null
endfunction
function Trig_Gametime_Actions takes nothing returns nothing
    local integer i = 0
    local integer a = 0
    local unit first
    local group g = CreateGroup()
    if(counter==0) then
        call TimerDialogDisplay(GameTime, true)
        set P_Income=CreateLeaderboard()
        call PlayerSetLeaderboard(Player(0), P_Income)
        call LeaderboardAddItem(P_Income, GetPlayerName(Player(0)), 0, Player(0))
        call LeaderboardSetLabel(P_Income, "Income")
        call LeaderboardSetSizeByItemCount(P_Income, LeaderboardGetItemCount(P_Income))
        call LeaderboardDisplay(P_Income, true)
    endif
    call TimerStart(gameTimer, counter, false, null)
    call PauseTimer(gameTimer)
    call GroupEnumUnitsOfPlayer(g, Player(10), Filter(function spawnFilter))
    loop
        set first=FirstOfGroup(g)
        exitwhen first==null
        call Order(first)
        call GroupRemoveUnit(g,first)
    endloop
    if counter==5 then
        call DisplayTextToPlayer(Player(0), 0, 0, "Defend from the endless waves...")
    endif
    if counter==10 then
        call DisplayTextToPlayer(Player(0), 0, 0, "The horde arrives at 4:00.")
    endif
    if counter==240 then
        set spawnDiff=3
    endif
    if counter==270 then
        set spawnDiff=4
    endif
    if counter==300 then
        set spawnDiff=5
    endif
    if counter==330 then
        set spawnDiff=6
    endif
    if counter==360 then
        set spawnDiff=7
    endif
    if counter==390 then
        set spawnDiff=8
    endif
    if counter==420 then
        set spawnDiff=9
    endif
    if counter==450 then
        set spawnDiff=10
    endif
    if counter==480 then
        set spawnDiff=11
    endif
    if counter==510 then
        set spawnDiff=12
    endif
    if counter==540 then
        set spawnDiff=13
    endif
    if counter==570 then
        set spawnDiff=14
    endif
    if counter==600 then
        set spawnDiff=15
    endif
    if counter==620 then
        set spawnDiff=16
    endif
    if counter==660 then
        set spawnDiff=17
    endif
    if counter==690 then
        set spawnDiff=18
    endif
    if counter==720 then
        set spawnDiff=19
    endif
    if counter==750 then
        set spawnDiff=20
    endif
    if counter==780 then
        set spawnDiff=21
    endif
    if counter==810 then
        set spawnDiff=22
    endif
    if counter==840 then
        set spawnDiff=23
    endif
    if counter==870 then
        set spawnDiff=24
    endif
    if counter==900 then
        set spawnDiff=25
    endif
    if counter==920 then
        set spawnDiff=26
    endif
    if counter==960 then
        set spawnDiff=27
    endif
    if counter==990 then
        set spawnDiff=28
    endif
    if counter==1020 then
        set spawnDiff=29
    endif
    if counter==1050 then
        set spawnDiff=30
    endif
    if counter==1080 then
        set spawnDiff=31
    endif
    if counter==1110 then
        set spawnDiff=32
    endif
    if counter==1140 then
        set spawnDiff=33
    endif
    if counter==1170 then
        set spawnDiff=34
    endif
    if counter==1200 then
        set spawnDiff=35
    endif
    if counter==1220 then
        set spawnDiff=36
    endif
    if counter==1260 then
        set spawnDiff=37
    endif
    if counter==1290 then
        set spawnDiff=38
    endif
    if counter==1320 then
        set spawnDiff=39
    endif
    if counter==1350 then
        set spawnDiff=40
    endif
    if counter==1380 then
        set spawnDiff=41
    endif
    if counter==1410 then
        set spawnDiff=42
    endif
    if counter==1440 then
        set spawnDiff=43
    endif
    if counter==1470 then
        set spawnDiff=44
    endif
    if counter==1500 then
        set spawnDiff=45
    endif
    if counter==1520 then
        set spawnDiff=46
    endif
    if counter==1560 then
        set spawnDiff=47
    endif
    if counter==1590 then
        set spawnDiff=48
    endif
    if counter==1620 then
        set spawnDiff=49
    endif
    if counter==1650 then
        set spawnDiff=50
    endif
    if counter==1680 then
        set spawnDiff=51
    endif
    if counter==1710 then
        set spawnDiff=52
    endif
    if counter==1740 then
        set spawnDiff=53
    endif
    if counter==1770 then
        set spawnDiff=54
    endif
    if counter==1800 then
        set spawnDiff=55
    endif
    if counter==1820 then
        set spawnDiff=56
    endif
    if counter==1860 then
        set spawnDiff=57
    endif
    if counter==1890 then
        set spawnDiff=58
    endif
    if counter==1920 then
        set spawnDiff=59
    endif
    if counter==1950 then
        set spawnDiff=60
    endif
    if counter==1980 then
        set spawnDiff=61
    endif
    if counter==2010 then
        set spawnDiff=62
    endif
    if counter==2040 then
        set spawnDiff=63
    endif
    if counter==2070 then
        set spawnDiff=64
    endif
    if counter==2100 then
        set spawnDiff=65
    endif
    if counter == 2120 then
        set spawnDiff=66
    endif
    if counter-(counter/5)*5==0 then
        call income()
    endif
    if counter-(counter/20)*20==0 then
        set tmpInt= 'h01Y'
        call GroupEnumUnitsOfPlayer(g, Player(10), Filter(function GenFilter))
        loop
            set first=FirstOfGroup(g)
            exitwhen first==null
            call spawn(first)
            call GroupRemoveUnit(g,first)
        endloop
        set tmpInt= 'h01L'
        call GroupEnumUnitsOfPlayer(g, Player(10), Filter(function GenFilter))
        loop
            set first=FirstOfGroup(g)
            exitwhen first==null
            call spawnPlus(first)
            call GroupRemoveUnit(g,first)
        endloop
    endif
    call GroupEnumUnitsOfPlayer(g, Player(10), Filter(function spawnFilter))
    loop
        set first=FirstOfGroup(g)
        exitwhen first==null
        call Order(first)
        call GroupRemoveUnit(g,first)
    endloop
    call RemoveAllGuardPositions(Player(10))
    set counter=counter+1
    call DestroyGroup(g)
    set g=null
    set first=null
endfunction

//===========================================================================
function InitTrig_Gametime takes nothing returns nothing
    set gg_trg_Gametime = CreateTrigger(  )
    call TriggerRegisterTimerEvent( gg_trg_Gametime, 1.00, true )
    call TriggerAddAction( gg_trg_Gametime, function Trig_Gametime_Actions )
endfunction
 
At this point, I'm completely out of ideas. Checked your code twice now and could not find anything that could lead to crashes.

What are the numbers in your game? I see that you grant players a huge amount of gold every second (especially if they maxed out their buildings) and you also create masses of units. Anything unusual here that you haven't seen in other maps?
 
Level 3
Joined
Jun 2, 2015
Messages
45
the last 6 tiers of units I haven't used yet, its not that much gold. The only thing I can think of is the large amount of units that have to be ordered... I'm starting to think its not possible in Warcraft 3.

Edit: so the units don't stack up very much, at most theres like 50 units on the small test map I made.
 
Level 3
Joined
Jun 2, 2015
Messages
45
After more testing, I have figured out that if I do not build any income buildings (or only a few) the game does not crash. In a normal game I would have filled all available space. The spawning and the ordering seem to work fine for hours. This leads me to believe that it is the income part of the trigger that crashes. I have also noticed on the few times that I was looking at the timer right when it crashed it seemed to crash on a multiple of 5. But if the amount of income buildings were crashing it, why would it only crash after working many times with the same amount? I usually max out the income buildings by about 14 minutes or so.
 
Level 3
Joined
Jun 2, 2015
Messages
45
i cant see how that's possible. I only use a couple arrays to hold values and never add to them. as for integers the counter gets to the highest and it definitely isn't causing the crash, as it will count up past an hour when I don't make a lot of income buildings. As far as the count of income buildings at most it would make it to 200... is there a way to output your messages into a txt file so I can read it afterwords? that way I could find exactly where it crashes in the income function.
 
Yes, you can use the preload bug:

JASS:
                local integer maxindex = 1
                local string array text

                set text[0] = "bla"
                set text[1] = "blubb"

                call PreloadGenClear()
                call PreloadGenStart()
                loop
                    exitwhen i > maxindex
                    call Preload("\")\n\n"+"    "+ text[i] +"    "+"\n\n//")
                    set i = i + 1
                endloop
                call PreloadGenEnd( ".\\MyDebugLog\\Log.txt")
 
Level 3
Joined
Jun 2, 2015
Messages
45
i shall try this. after testing I can safely say that the amount of income is not what crashes it, nor the amount of income buildings. it seems that the crash only happens when I play the game as it was meant to be played, whenever I try to test one part of it it works but they all don't work together. I did have spawning going however I placed a powerful unit on the map to catch all the spawns so I could leave it and see if it crashed after building as many income buildings as I can fit. Did not crash. Also tried building and upgrading and got my income much higher than it was when it crashed, and left it for a while and still no crash. :vw_wtf:

Edit: so after testing it seems that the crash does not happen every game. It seems to always happen if I have any of my vjass scopes or libraries enabled, but if I have them disabled it only happens sometimes...
 
Last edited:
Status
Not open for further replies.
Top