HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

Lagg after undefined gametime

02-09-2009, 08:51 PM#1
XieLong
Yea, I have got the following problem:
A timer in my map (I am sure that it is the source of the lagg, because I use only this timer) makes the game lagging after an undefined time of playing.
I disabled any component of code which is executed by the timer - and the laggs disappear, of course. Than I enabled step by step any of the components to find out which of them is causing the lagg. And no one of the components laggs if it is the only one runned by the timer.
But together they cause a lagg after some time - a lagg which make it impossible to play.
Collapse So, here's the code:
globals
   
    timer Timer = null
    
    boolean GameIsPaused = true
    
    constant player NEUTRAL_PLAYER = Player(11)
    
    dialog DefeatDialog = DialogCreate()
    button array DefeatDialog_Button
    
    unit Ball    
    real Ball_FallSpeed = 800 * DISPLAY_INTERVAL
    real Ball_MovementSpeed = 600 * DISPLAY_INTERVAL
    real Ball_Radius = 80
    integer Ball_Movement = 0
    constant integer BALL_MOVEMENT_NONE = 0
    constant integer BALL_MOVEMENT_LEFT = 1
    constant integer BALL_MOVEMENT_RIGHT = 2
    boolean resetBallMovement = false

    real Line_MovementSpeed = 200 * DISPLAY_INTERVAL
    group Line_Dummies
    real Line_MaxDistance = 1000
    real Line_Distance = Line_MaxDistance
    
    real GapSize = 500
    real DashWidth = 42
    
    // Coordinates of the playable map
    real MIN_X
    real MAX_X
    real MIN_Y
    real MAX_Y
    
    multiboard Multiboard
    real Score = 0
    real ScorePerInterval = 1    
    integer ScoreLevel = 0
    integer array ScoreThreshold
    
endglobals

//===========================================================================
//
function MoveLineDummiesUp takes nothing returns nothing
    local unit Dummy = GetEnumUnit()
    local real y = GetUnitY(Dummy) + Line_MovementSpeed
    if y > GetRectMinY(gg_rct_Top) then
        call GroupRemoveUnit(Line_Dummies, Dummy)
        call RemoveUnit(Dummy)
    else
        call SetUnitY(Dummy, y)
    endif
    set Dummy = null
endfunction

function MoveLines takes nothing returns nothing
    //call DMsg("MoveLines")
    call ForGroup(Line_Dummies, function MoveLineDummiesUp)
endfunction
//
//===========================================================================

//===========================================================================
//
function CreateNewLine takes nothing returns nothing
    local real GapStart = GetRandomReal(MIN_X, MAX_X - GapSize)
    local real x = MIN_X + DashWidth
    local unit Dummy
    set GapStart = (MIN_X + MAX_X) / 2
    loop
        exitwhen x >= MAX_X
        if x >= GapStart and x <= (GapStart + GapSize) then
            set x = GapStart + GapSize + DashWidth
        endif
        set Dummy = CreateUnit(NEUTRAL_PLAYER, 'dash', x, MIN_Y + DashWidth, 0)
        call GroupAddUnit(Line_Dummies, Dummy)
        set x = x + DashWidth
    endloop
    set Dummy = null
endfunction
//
//===========================================================================

//===========================================================================
//
function IsDash takes nothing returns boolean
    return GetUnitTypeId(GetFilterUnit()) == 'dash'
endfunction

function MoveBall takes nothing returns nothing
    local unit u
    local real AngleBetweenUnits
    local real x = GetUnitX(Ball)
    local real y = GetUnitY(Ball)
    local real dx
    local real dy
    local real newY
    local boolean isOnLine = false
    local real distance = 0
    
    call GroupEnumUnitsOfPlayer(TempGroup, NEUTRAL_PLAYER, Condition(function IsDash))
    loop
        set u = FirstOfGroup(TempGroup)
        exitwhen u == null
        call GroupRemoveUnit(TempGroup, u)
        set dx = x - GetUnitX(u)
        set dy = y - GetUnitY(u)
        set distance = SquareRoot(dx * dx + dy * dy)
        if distance <= Ball_Radius then
            set isOnLine = true
            exitwhen true
        endif
    endloop
    call GroupClear(TempGroup)
    set u = null
    if isOnLine then
        if Line_MovementSpeed + distance >= Ball_Radius then
            set newY = y + Line_MovementSpeed
        else
            set newY = y + Line_MovementSpeed + Ball_Radius - distance
        endif
        if newY > GetRectMinY(gg_rct_Top) then
            call DialogSetMessage( DefeatDialog, "Defeated!|nScore: " + I2S(R2I(Score + .5)))
            call DialogDisplay(Player(0), DefeatDialog, true)
            set GameIsPaused = true
        else
            call SetUnitY(Ball, newY)
        endif
    else
        set newY = y - Ball_FallSpeed
        if newY >= MIN_Y + DashWidth + Ball_Radius then
            call SetUnitY(Ball, newY)
        endif
    endif
endfunction
//
//===========================================================================

//===========================================================================
//
function ControlBall takes nothing returns nothing
    local real x
    if Ball_Movement != BALL_MOVEMENT_NONE then
        set x = GetUnitX(Ball)
        if Ball_Movement == BALL_MOVEMENT_RIGHT then
            set x = x + Ball_MovementSpeed
        elseif Ball_Movement == BALL_MOVEMENT_LEFT then
            set x = x - Ball_MovementSpeed
        endif
        if x >= MIN_X and x <= MAX_X then
            call SetUnitX(Ball, x)
        else
            set Ball_Movement = BALL_MOVEMENT_NONE
        endif
        if resetBallMovement then
            set resetBallMovement = false
            set Ball_Movement = BALL_MOVEMENT_NONE
        endif
    endif
endfunction
//
//===========================================================================

//===========================================================================
//
function AdjustScore takes nothing returns nothing
    set Score = Score + ScorePerInterval
    if Score >= ScoreThreshold[ScoreLevel] then
        call UpdateOnScoreThreshold()
    endif
    call MBSetItemText(Multiboard, 1, 1, I2S(R2I(Score + .5)))
    call MBSetItemText(Multiboard, 3, 1, I2S(R2I(ScoreThreshold[ScoreLevel] - Score + .5)))
endfunction
//
//===========================================================================

function Timer_Actions takes nothing returns nothing
    
    if not GameIsPaused then
        
        // Lock Camera
        call SetCameraField(CAMERA_FIELD_TARGET_DISTANCE, CameraSetupGetField(gg_cam_StartCam, CAMERA_FIELD_TARGET_DISTANCE), 0)
        call SetCameraField(CAMERA_FIELD_ANGLE_OF_ATTACK, 270.00, 0)
        
        // Move existing lines
        call ExecuteFunc("MoveLines")
        set Line_Distance = Line_Distance + Line_MovementSpeed
        
        if Line_Distance >= Line_MaxDistance then
            set Line_Distance = 0
            // Create a new line
            call ExecuteFunc("CreateNewLine")
        endif
        
        // Ball-Movement
        call ExecuteFunc("MoveBall")
        
        // Ball-Control
        call ExecuteFunc("ControlBall")
        
        // Increase the score
        call ExecuteFunc("AdjustScore")       
        
    endif

endfunction

//===========================================================================
function InitTrig_Timer_Copy takes nothing returns nothing
    set Timer = CreateTimer()
    call TimerStart(Timer, DISPLAY_INTERVAL, true, function Timer_Actions)
    set Line_Dummies = CreateGroup()
endfunction
I hope someone can tell me the reason for this lag or how to fix it.

Thanks in advance.
02-09-2009, 09:01 PM#2
Zerzax
Well, there are some ways you can optimize this code. I don't know exactly what the problem is, that would take deeper inspection. But I do know that ExecuteFunc is pretty outdated, and I've heard it's slow - just call the function itself. I was going to recommend using structs but it appears you really only need one instance of these globals.
02-12-2009, 10:39 AM#3
XieLong
Why should ExecuteFunc be outdated? There aren't any faster methods to run code in a custom thread :)
I know that a simple function-call is faster than an ExecuteFunc. But I already tested it by replacing all ExecuteFuncs with calls, but that doesn't fix the main-problem: A lagg which nearly kills the game after some time :\
02-12-2009, 11:09 AM#4
Zerzax
You're leaking conditions: use a global boolexpr or filterfunc instead of creating one each time you call MoveBall.
02-12-2009, 11:11 AM#5
XieLong
I'm sure that boolexpr where cached by warcraft instead of creating them every time.
02-12-2009, 11:36 AM#6
Vexorian
Quote:
Why should ExecuteFunc be outdated? There aren't any faster methods to run code in a custom thread :)
Hell yes there are.

You do not need a thread here man, if just calling the functions causes a limit op then your functions are way too heavy for a periodic timer and that's the cause of your lag.

---
Regarding your leak, The native called "Condition" does not 'leak' , but I am kind of sure you have a leak in that MBSetItemText function, please post it.
02-12-2009, 01:42 PM#7
DioD
DISPLAY_INTERVAL equal to ?
02-12-2009, 08:31 PM#8
Zerzax
I didn't know that conditions were leakless... I'll stop telling people that. Storing it on init will reduce the function calls to 1 though...
02-12-2009, 09:05 PM#9
XieLong
Ok, I will call the functions in the normal way.

Collapse function MBSetItemText:
function MBSetItemText takes multiboard mb, integer row, integer col, string text returns nothing
    local multiboarditem mbitem = MultiboardGetItem(mb, row, col)
    call MultiboardSetItemValue(mbitem, text )
    call MultiboardReleaseItem(mbitem)
    set mbitem = null
endfunction

constant real DISPLAY_INTERVAL = 1. / 32.

They strange thing is that the game runs all time stable, there aren't any performance issue but suddenly there's a huge lagg...

And thanks alot to you all for your help :)
02-13-2009, 04:48 AM#10
Bobo_The_Kodo
Quote:
I didn't know that conditions were leakless... I'll stop telling people that. Storing it on init will reduce the function calls to 1 though...
I thought the same thing for awhile, then posted about it just like you in a thread on wc3c. Someone did a benchmark with global boolexpr initialized in Init vs inlining it, and the global was only slightly faster -- though the inlined one got faster the more you ran it -- up to a point
02-13-2009, 12:40 PM#11
emjlr3
when you say lagging - do you mean the game slowly approaches unplayableness - or that you get random lag spikes later into the game?

the latter most likely being some op limit or some preload your forgot to do

otherwise, you are probably leaking memory prety heavily some place, or creating too many units you never get rid of, etc. ( you get the idea)

as far as your script goes - i see not reason for massive lag all of a sudden, which begs the question, what else are you triggering in your map?
02-13-2009, 04:53 PM#12
XieLong
When I say lagg I ment the second thing - sudden lagg spikes.

There are nearly no other triggers in the map. Just some DialogClickings and Init-Triggers. As I said, when I turn out this timer, there isn't any lagg at all.

There's only one function-call in my code which wasn't explained by me yet
Collapse function UpdateOnScoreThreshold:
    function Update_Ball_MovementSpeed takes nothing returns nothing
        set Ball_MovementSpeed = 1.1 * Ball_MovementSpeed 
    endfunction

    function Update_Line_MovementSpeed takes nothing returns nothing
        set Line_MovementSpeed = 1.15 * Line_MovementSpeed 
    endfunction

    function Update_Line_MaxDistance takes nothing returns nothing
        set Line_MaxDistance = 0.975 * Line_MaxDistance 
    endfunction

    function Update_ScorePerInterval takes nothing returns nothing
        set ScorePerInterval = ScorePerInterval + 1
    endfunction

    function UpdateOnScoreThreshold takes nothing returns nothing
        set ScoreLevel = ScoreLevel + 1
        call MBSetItemText(Multiboard, 2, 1, I2S(ScoreLevel))
        call Update_Ball_MovementSpeed()
        call Update_Line_MovementSpeed()
        call Update_Line_MaxDistance()
        call Update_ScorePerInterval()
    endfunction
02-17-2009, 08:35 PM#13
XieLong
Sorry for doubleposting - but this lagg really makes me sick... Until now I tried everything I could imagine to fix, but nothing helps. And it seems to me nobody else out there knows the reason...
I think the reason can't be a leak, because the memory usage of war.exe remains the same when the lagg appears (or just increase a little, not to mind).
This seems to be a really strange issue :(
02-22-2009, 10:57 PM#14
Anitarf
Are you maybe displaying large amounts of game messages, debug or otherwise?
02-23-2009, 08:07 AM#15
XieLong
No, in this case I just show at the beginning of the game a little instruction via textmessages
Collapse JASS:
    call DisplayTimedTextToPlayer(Player(0), 0.5, 0, 9999, "Willkommen bei " + GAMETITLE)
    call DisplayTimedTextToPlayer(Player(0), 0.5, 0, 9999, " ")
    call DisplayTimedTextToPlayer(Player(0), 0.5, 0, 9999, "           Nutze <- und ->")
    call DisplayTimedTextToPlayer(Player(0), 0.5, 0, 9999, "        um den Ball zu steuern")
    call DisplayTimedTextToPlayer(Player(0), 0.5, 0, 9999, "   Bleibe unter der Bildoberkante!")
    call DisplayTimedTextToPlayer(Player(0), 0.5, 0, 9999, "         <ESC> zum Pausieren")
    call DisplayTimedTextToPlayer(Player(0), 0.5, 0, 9999, "     Drücke <- oder -> zum starten")
All other debug-messages are disabled.