HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

Lag where no lag has gone before

12-12-2004, 12:40 AM#1
Panto
Greetings.

I have this trigger. It notices when units enter a region and shuffles them off to the next appropriate region. I have four pathways on the map, and previously, I had a separate trigger that did this for each pathway. However, since they all did virtually the same thing, I combined them into one.

So, granted, there's more going on in this trigger than before.

However, it's not a lot more stuff. Basically it just checks a larger loop of regions now than it did before. Where before the trigger didn't lag at all, now it noticeably lags every few seconds. So, what can be causing this lag? I'll be blunt: it's generally running for around 60 units every several seconds. However, like I mentioned, it didn't lag when it was separate triggers.
Code:
//======================
//   Functi0ns
//======================

function Trig_Router_Actions takes nothing returns nothing
//== Loc4ls ============
    local unit unitEnter = GetEnteringUnit()
    local unit unitPicker
    local player playerOwner = (GetOwningPlayer(unitEnter))
    local integer intLoop
    local integer intDirection = 1
    local integer intInGroup = 12
    local integer intWaves = 0
    local integer intCustom
    local integer intLoopWave
    local group groupInRegion = CreateGroup()
    local group groupInLast = CreateGroup()
    local group array groupArWave
    local location locOrder

//== Ac7ions ===========
    if ((playerOwner == Player(PLAYER_NEUTRAL_PASSIVE)) or (playerOwner == Player(bj_PLAYER_NEUTRAL_VICTIM))) then
        call DisplayTextToForce(GetPlayersAll(), "Router runs.")
        call PolledWait(0.25)
        set intLoop = 0
        loop
            exitwhen intLoop >= 79
            if ((RectContainsCoords(udg_rectArPathCollect[intLoop], GetUnitX(unitEnter), GetUnitY(unitEnter)) == true) and (intLoop == GetUnitUserData(unitEnter))) then
                if (playerOwner == Player(PLAYER_NEUTRAL_PASSIVE)) then
                    set intDirection = 1
                elseif (playerOwner == Player(bj_PLAYER_NEUTRAL_VICTIM)) then
                    set intDirection = -1
                endif
                call DisplayTextToForce(GetPlayersAll(), "Region: " + I2S(intLoop))
                call GroupEnumUnitsInRect(groupInRegion, udg_rectArPathCollect[intLoop], null)
                call GroupEnumUnitsInRect(groupInLast, udg_rectArPathCollect[intLoop - intDirection], null)
                loop
                    set unitPicker = FirstOfGroup(groupInLast)
                    exitwhen unitPicker == null
                    call GroupAddUnit(groupInRegion, unitPicker)
                    call GroupRemoveUnit(groupInLast, unitPicker)
                endloop
                call DestroyGroup(groupInLast)
                call DisplayTextToForce(GetPlayersAll(), "groupInRegion size: " + I2S(CountUnitsInGroup(groupInRegion)))
                loop
                    set unitPicker = FirstOfGroup(groupInRegion)
                    exitwhen unitPicker == null
                    set intCustom = GetUnitUserData(unitPicker)
                    if ((intCustom == intLoop) and (GetOwningPlayer(unitPicker) == playerOwner) and (GetWidgetLife(unitPicker) > 0)) then
                        set intInGroup = intInGroup + 1
                        if (intInGroup >= 13) then
                            set intInGroup = 0
                            set intWaves = intWaves + 1
                            set groupArWave[intWaves] = CreateGroup()
                        endif
                        call GroupAddUnit(groupArWave[intWaves],unitPicker)
                        call SetUnitUserData(unitPicker, (intCustom + intDirection))
                    endif
                    call GroupRemoveUnit(groupInRegion, unitPicker)
                endloop
                call DestroyGroup(groupInRegion)
//                call DisplayTextToForce(GetPlayersAll(), "Waves: " + I2S(intWaves))
                set locOrder = GetRectCenter(udg_rectArPathEnter[intLoop + intDirection])
                set intLoopWave = 1
                loop
                    exitwhen intLoopWave > intWaves
                    call GroupPointOrderLoc(groupArWave[intLoopWave], "attack", locOrder)
                    set intLoopWave = intLoopWave + 1
                endloop
                set intLoop = 79
            endif
            set intLoop = intLoop + 1
        endloop
        call DisplayTextToForce(GetPlayersAll(), "Router finishes.")
    endif

//== Cl3anup ===========
    set unitEnter = null
    set unitPicker = null
    call DestroyGroup(groupInRegion)
    set groupInRegion = null
    call DestroyGroup(groupInLast)
    set groupInLast = null
    set intLoop = 1
    loop
        exitwhen intLoop > intWaves
        call DestroyGroup(groupArWave[intLoop])
        set groupArWave[intLoop] = null
    endloop
    call RemoveLocation(locOrder)
    set locOrder = null
endfunction

//======================
//  Event5
//======================

function InitTrig_Router takes nothing returns nothing
    set gg_trg_Router = CreateTrigger()
    call TriggerAddAction(gg_trg_Router, function Trig_Router_Actions)
endfunction
12-13-2004, 07:16 AM#2
PitzerMike
Quote:
Originally Posted by Panto
However, like I mentioned, it didn't lag when it was separate triggers.

You already give the answer yourself. It's because of the program flow. As you mentioned it used to be different threads (because of different triggers) before, meaning that when 1 trigger finished, control returned to another thread (also other things might have been executed between the execution of these different triggers)

As it is now, you don't have any statement that gives control away in between (like a TriggerSleepAction(0) or something that would give control to other waiting threads) so it HAS TO execute the whole big loop before other things can be done whereas it only had to execute parts before.
12-13-2004, 08:56 AM#3
Pheonix-IV
So basically, add a line of code which gives control to other waiting threads after each check, or take the easy (and probably more reliable) way out and make it seperate triggers again. Whats the problem with having more than 1 trigger?

Actually, it'd probably be easier to set up waygates instead of using triggers, solves lag and pathing problems.
12-13-2004, 05:05 PM#4
Panto
PolledWait won't let it move on to another thread?

If I used TriggerSleepAction, it might improve performance?
12-13-2004, 07:46 PM#5
PitzerMike
I think polled wait would also do the job, provided that you call it from within the loop (which you're not doing atm).
12-13-2004, 07:52 PM#6
Vexorian
TriggerSleepAction(0) would do it
12-13-2004, 08:49 PM#7
Panto
Well, PolledWait can't go below 0.25, and it's only in there right now to give time for the triggering unit to get within the rect that it triggered. I'll try throwing a sleep into the loop, then.
12-13-2004, 10:27 PM#8
Pheonix-IV
I still dont see why you cant just use modified waygates.
12-14-2004, 02:54 AM#9
Panto
Could you be more specific; what do you mean exactly when you say "waygates"?
12-14-2004, 11:20 AM#10
Ryude
Panto, would you mind explaining how that trigger works?

Because if it does what I think it does, I could really learn from it.

Right now I'm using almost 40 triggers to route spawned units from 1 region to the next, but if I understand your trigger correctly it loops through each region in a variable and automatically routes them?
12-14-2004, 01:51 PM#11
Panto
It does. Except right now, it's pretty laggy, so the standard method, like yours, will be more playable.
12-14-2004, 09:16 PM#12
Ryude
Actually, I figured out how to do what I wanted.

I took your code, them chopped off the parts I needed and twiddled it down until it worked.

At first, sometimes the regions would not see the units inside the rects, until I put a TriggerSleepAction(0.10) at the very start of the actions.

Code:
//======================
//   Functions
//======================

function Router_Actions takes nothing returns nothing
//== Locals ============
    local unit unitEnter=GetEnteringUnit()
    local player playerOwner=GetOwningPlayer(unitEnter)
    local location loc

//== Actions ===========
    call TriggerSleepAction(0.10)
    if playerOwner==Player(0) or playerOwner==Player(6) then

//== Top Lane ==========
        if (RectContainsCoords(gg_rct_War_N,GetUnitX(unitEnter),GetUnitY(unitEnter)) or RectContainsCoords(gg_rct_Lore_N,GetUnitX(unitEnter),GetUnitY(unitEnter))) and playerOwner==Player(0) then
            set loc=GetRectCenter(gg_rct_Attack_Point_N)
        elseif (RectContainsCoords(gg_rct_Crypt_W,GetUnitX(unitEnter),GetUnitY(unitEnter)) or RectContainsCoords(gg_rct_Temple_W,GetUnitX(unitEnter),GetUnitY(unitEnter))) and playerOwner==Player(6) then
            set loc=GetRectCenter(gg_rct_Attack_Point_N)
        elseif RectContainsCoords(gg_rct_Attack_Point_N,GetUnitX(unitEnter),GetUnitY(unitEnter)) then
            if playerOwner==Player(0) then
                set loc=GetRectCenter(gg_rct_necropolis)
            endif
            if playerOwner==Player(6) then
                set loc=GetRectCenter(gg_rct_tree_of_life)
            endif
        endif
        call TriggerSleepAction(0)

//== Middle Lane =======
        if (RectContainsCoords(gg_rct_War_NE,GetUnitX(unitEnter),GetUnitY(unitEnter)) or RectContainsCoords(gg_rct_Lore_NE,GetUnitX(unitEnter),GetUnitY(unitEnter))) and playerOwner==Player(0) then
            set loc=GetRectCenter(gg_rct_Attack_Point_Center)
        elseif (RectContainsCoords(gg_rct_Crypt_SW,GetUnitX(unitEnter),GetUnitY(unitEnter)) or RectContainsCoords(gg_rct_Temple_SW,GetUnitX(unitEnter),GetUnitY(unitEnter))) and playerOwner==Player(6) then
            set loc=GetRectCenter(gg_rct_Attack_Point_Center)
        elseif RectContainsCoords(gg_rct_Attack_Point_Center,GetUnitX(unitEnter),GetUnitY(unitEnter)) then
            if playerOwner==Player(0) then
                set loc=GetRectCenter(gg_rct_necropolis)
            endif
            if playerOwner==Player(6) then
                set loc=GetRectCenter(gg_rct_tree_of_life)
            endif
        endif
        call TriggerSleepAction(0)

//== Bottom Lane =======
        if (RectContainsCoords(gg_rct_War_E,GetUnitX(unitEnter),GetUnitY(unitEnter)) or RectContainsCoords(gg_rct_Lore_E,GetUnitX(unitEnter),GetUnitY(unitEnter))) and playerOwner==Player(0) then
            set loc=GetRectCenter(gg_rct_Attack_Point_E)
        elseif (RectContainsCoords(gg_rct_Crypt_S,GetUnitX(unitEnter),GetUnitY(unitEnter)) or RectContainsCoords(gg_rct_Temple_S,GetUnitX(unitEnter),GetUnitY(unitEnter))) and playerOwner==Player(6) then
            set loc=GetRectCenter(gg_rct_Attack_Point_E)
        elseif RectContainsCoords(gg_rct_Attack_Point_E,GetUnitX(unitEnter),GetUnitY(unitEnter)) then
            if playerOwner==Player(0) then
                set loc=GetRectCenter(gg_rct_necropolis)
            endif
            if playerOwner==Player(6) then
                set loc=GetRectCenter(gg_rct_tree_of_life)
            endif
        endif
        call IssuePointOrderLocBJ(unitEnter,"attack",loc)
    endif

//== Cleanup ===========
    set unitEnter=null
    call RemoveLocation(loc)
    set loc=null
endfunction

//======================
//  Events
//======================

function InitTrig_Router takes nothing returns nothing
    set gg_trg_Router = CreateTrigger()
    call TriggerRegisterEnterRectSimple( gg_trg_Router, gg_rct_War_N )
    call TriggerRegisterEnterRectSimple( gg_trg_Router, gg_rct_War_NE )
    call TriggerRegisterEnterRectSimple( gg_trg_Router, gg_rct_War_E )
    call TriggerRegisterEnterRectSimple( gg_trg_Router, gg_rct_Lore_N )
    call TriggerRegisterEnterRectSimple( gg_trg_Router, gg_rct_Lore_NE )
    call TriggerRegisterEnterRectSimple( gg_trg_Router, gg_rct_Lore_E )
    call TriggerRegisterEnterRectSimple( gg_trg_Router, gg_rct_Crypt_W )
    call TriggerRegisterEnterRectSimple( gg_trg_Router, gg_rct_Crypt_SW )
    call TriggerRegisterEnterRectSimple( gg_trg_Router, gg_rct_Crypt_S )
    call TriggerRegisterEnterRectSimple( gg_trg_Router, gg_rct_Temple_W )
    call TriggerRegisterEnterRectSimple( gg_trg_Router, gg_rct_Temple_SW )
    call TriggerRegisterEnterRectSimple( gg_trg_Router, gg_rct_Temple_S )
    call TriggerRegisterEnterRectSimple( gg_trg_Router, gg_rct_Attack_Point_N )
    call TriggerRegisterEnterRectSimple( gg_trg_Router, gg_rct_Attack_Point_Center )
    call TriggerRegisterEnterRectSimple( gg_trg_Router, gg_rct_Attack_Point_E )
    call TriggerAddAction(gg_trg_Router, function Router_Actions)
endfunction
12-14-2004, 11:26 PM#13
Pheonix-IV
Quote:
Originally Posted by Panto
Could you be more specific; what do you mean exactly when you say "waygates"?
A waygate allows you to place a building (or an invisible one if you want) which will automatically transport units through it to the target location if they want to go there. Aka:

I have 2 islands, seperated by a long, twisty land bridge. Each island has a waygate that transports to the other island, i could send my units over the land bridge, but if i tell them to just move to the other island they will automatically take the shorter route and use the waygate. It requires no triggers (waygate destinations can be set in the editor.) and is compatable with WCIII Pathing.
12-14-2004, 11:55 PM#14
PitzerMike
I don't think Panto wants the units to teleport around, he wants them simply to walk to the next waypoint.
But yeah, the waypoint idea is quite useful in some situations.
12-15-2004, 01:35 AM#15
Panto
Ryude, the reason you need the wait is thus:

The "Unit Enters Region" event is triggered when a unit's collision intersects a region (or rather, a rect). However, when checking to see if a unit is within a rect, it checks for its center point. So, you need to give the unit just a split second to fully enter the rect so that the check will catch it.

At least, this was roughly how it was explained to me, and it holds up to inspection.