System slows game down

Dirac

22710180
Reaction score
147
Hello, i coded this system that allows you to get the position of a unit seconds ago, it's supposed to be very accurate. But it drops the FPS roughly. Is there a way to prevent the FPS drop?

EDIT: forgot to mention, it has a 5 second maximum storage per unit, and only indexes units that belong to player 9
JASS:
library UnitHistory uses TimerUtils,AIDS
    private struct UH extends array
    
        private static method AIDS_filter takes unit u returns boolean
            return GetOwningPlayer(u)==Player(8)
        endmethod
        
        hashtable x
        hashtable y
        timer t
        
        private static method periodic takes nothing returns nothing
            local integer i=50
            local thistype this=GetTimerData(GetExpiredTimer())
            loop
                exitwhen i<1
                call SaveReal(.x,GetUnitIndex(.unit),i,LoadReal(.x,GetUnitIndex(.unit),i-1))
                call SaveReal(.y,GetUnitIndex(.unit),i,LoadReal(.y,GetUnitIndex(.unit),i-1))
                set i=i-1
            endloop
            call SaveReal(.x,GetUnitIndex(.unit),0,GetUnitX(.unit))
            call SaveReal(.y,GetUnitIndex(.unit),0,GetUnitY(.unit))
        endmethod
        
        
        private method AIDS_onCreate takes nothing returns nothing
            local integer i=50
            local real x=GetUnitX(.unit)
            local real y=GetUnitY(.unit)
            set .t=NewTimer()
            set .x=InitHashtable()
            set .y=InitHashtable()
            call SetTimerData(.t,this)
            call TimerStart(.t,0.1,true,function thistype.periodic)
            loop
                exitwhen i<0
                call SaveReal(.x,GetUnitIndex(.unit),i,x)
                call SaveReal(.y,GetUnitIndex(.unit),i,y)
                set i=i-1
            endloop
        endmethod
        
        private method AIDS_onDestroy takes nothing returns nothing
            call ReleaseTimer(.t)
            call FlushParentHashtable(.x)
            call FlushParentHashtable(.y)
        endmethod
        //! runtextmacro AIDS()
    endstruct
    
    function GetXSecondsAgo takes unit whichUnit,real seconds returns real
        return LoadReal(UH[whichUnit].x,GetUnitIndex(whichUnit),R2I(seconds*10))
    endfunction
    
    function GetYSecondsAgo takes unit whichUnit,real seconds returns real
        return LoadReal(UH[whichUnit].y,GetUnitIndex(whichUnit),R2I(seconds*10))
    endfunction
endlibrary

Also, how do i see the FPS ingame? i only can tell by how slow the game flows
 

tooltiperror

Super Moderator
Reaction score
231
>Also, how do i see the FPS ingame? i only can tell by how slow the game flows
/fps
 

Tom_Kazansky

--- wraith it ! ---
Reaction score
157
so you only use this for Player(8) ? and how many units does this player have?
maybe too many units => lag?

I probably won't be any helps but I just ask that, my purpose is answer the question below :p

how do i see the FPS ingame?

use /fps command

p.s: great! two minutes slower :(
 

Dirac

22710180
Reaction score
147
"Kinda" solved it myself. Now the system keeps track of EVERY position of the unit since it was created, and runs A LOT faster.
JASS:
library UnitHistory uses TimerUtils,AIDS
    private struct UH extends array
    
        private static method AIDS_filter takes unit u returns boolean
            return GetOwningPlayer(u)==Player(8)
        endmethod
        
        hashtable x
        hashtable y
        timer t
        integer time
        
        static method periodic takes nothing returns nothing
            local integer i=50
            local thistype this=GetTimerData(GetExpiredTimer())
            set .time=.time+1
            call SaveReal(.x,GetUnitIndex(.unit),.time,GetUnitX(.unit))
            call SaveReal(.y,GetUnitIndex(.unit),.time,GetUnitY(.unit))
        endmethod
        
        private method AIDS_onCreate takes nothing returns nothing
            local integer i=50
            local real x=GetUnitX(.unit)
            local real y=GetUnitY(.unit)
            set .t=NewTimer()
            set .x=InitHashtable()
            set .y=InitHashtable()
            set .time=50
            call SetTimerData(.t,this)
            call TimerStart(.t,0.1,true,function thistype.periodic)
            loop
                exitwhen i<0
                call SaveReal(.x,GetUnitIndex(.unit),i,x)
                call SaveReal(.y,GetUnitIndex(.unit),i,y)
                set i=i-1
            endloop
        endmethod
        
        private method AIDS_onDestroy takes nothing returns nothing
            call ReleaseTimer(.t)
            call FlushParentHashtable(.x)
            call FlushParentHashtable(.y)
        endmethod
        //! runtextmacro AIDS()
    endstruct
    
    function GetXSecondsAgo takes unit whichUnit,real seconds returns real
        return LoadReal(UH[whichUnit].x,GetUnitIndex(whichUnit),R2I(UH[whichUnit].time-seconds*10))
    endfunction
    
    function GetYSecondsAgo takes unit whichUnit,real seconds returns real
        return LoadReal(UH[whichUnit].y,GetUnitIndex(whichUnit),R2I(UH[whichUnit].time-seconds*10))
    endfunction
    
    function KeepRecording takes unit whichUnit returns nothing
        call TimerStart(UH[whichUnit].t,0.1,true,function UH.periodic)
    endfunction
    
    function StopRecording takes unit whichUnit returns nothing
        call PauseTimer(UH[whichUnit].t)
    endfunction
endlibrary

Any suggestions? Are hashtables really that slow?
 

Rllulium

New Member
Reaction score
10
Keeping track of every position will hit a memory limit at some point.

Also, why do you need this? There might be other implementations to consider.
 

WaterKnight

Member
Reaction score
7
Why do you need own hashtables for each unit? They already reserve their space by integrating them in the keys. Also you can only have 255 hashtables, so this part alone allows no more than 127 registered units.
 

NoobImbaPro

You can change this now in User CP.
Reaction score
60
I think the below solution is faster than hashtables and better than your infinite data storage.

Use array variables, witch are like
JASS:
globals
    real array[][] UnitX
    real array[][] UnitY
    integer array Index
endglobals

with initial value on AIDS_OnCreate "0"
the first array is your unit's UserData or anything else AIDS uses
Also on create store the x and y of unit in every array 0-50 to avoid bugs

On periodic use this
JASS:

local integer i = GetUnitUserData(.unit)
set Index<i> = Index<i> + 1
if Index<i> &gt; 50 then
    set Index<i> = 0
endif
set UnitX<i>[Index<i>] = GetWidgetX(.unit)
set UnitY<i>[Index<i>] = GetWidgetY(.unit)
</i></i></i></i></i></i></i></i>


Its something that writes or overrides values on arrays 0-50 like this world's earth time but its year time is 5 seconds. Fast I know :D
So if we want something that happened 2,6 seconds ago, we get the current time witch is Index and get the Index-26 value.
What happens if this value is equal to -6, we haven't got any UnitX[][-6] value stored. So we get previous year's day witch is 50-6 = 44
The location of unit on 44 day. With day I mean the 0.1 seconds
So we have this.
JASS:

local integer i = GetUnitUserData(.unit)
local real x
local real y
local integer j = Index<i> - R2I(time*10)
if Index<i> &lt; 0 then
    set j = 50 + j
endif
set x = UnitX<i>[j]
set y = UnitY<i>[j]
</i></i></i></i>


Because I don't use AIDS I don't know if the units user data or number of indexed unit can be parsed directly, so I just used the local integer i to get the unit's id.
 

Sevion

The DIY Ninja
Reaction score
413
The array method will have serious drawbacks if you hit the limit (which will occur very fast since you have a jagged array).

Instead, you should use the hashtable approach. However, you only need one.

Combine it with an array and you have your method.

JASS:
local integer i = GetHandleId(unit)
local integer n

if ( not HaveSavedInteger(hashtable, i, -1) ) then
    call SaveInteger(hashtable, i, -1, 0)
endif

set n = LoadInteger(hashtable, i, -1)

if ( n &gt; /*MAX_STEPS_TO_SAVE*/ 8190 ) then
    set n = 0
endif

call SaveReal(hashtable, i, n, GetUnitX(unit))
call SaveReal(hashtable, i, n, GetUnitY(unit))


n is simply the "step".

You could then combine this script with a timer and IsUnitMoving (which can be found on Hive or WC3, can't remember which).

You could also change n to "time" via a GetGameTime script (which is another script that can be found here).
 

NoobImbaPro

You can change this now in User CP.
Reaction score
60
tell me how the heck he will reach the limit??
its something like real UnitX[8190][50]
 

Sevion

The DIY Ninja
Reaction score
413
8190*50=409500

And according to my math skills, 409500 > 8192

That will result in trigger evaluations.
 

Dirac

22710180
Reaction score
147
Thanks Sevion and Waterknight both made very helpful suggestions.

I though about the IsUnitMoving thing before too. But then i realized it makes no sense to ignore as "timeline" when a unit isn't moving, it's still spending time doing something.

Didn't know much about the jagged arrays, they don't sound very useful since [n]*[m]<8190, that's one big limitation right there. Thanks for that too there
 

NoobImbaPro

You can change this now in User CP.
Reaction score
60
ok, but I don't think you might track more than 163 units positions constantly, do you?
If you want use your hashtables but think about the idea I gave you. You just need 50 arrays for each unit.
And at the beginning save the unit's position to all arrays. 8190 instances is such a waste.
 

Sevion

The DIY Ninja
Reaction score
413
ok, but I don't think you might track more than 163 units positions constantly, do you?
If you want use your hashtables but think about the idea I gave you. You just need 50 arrays for each unit.
And at the beginning save the unit's position to all arrays. 8190 instances is such a waste.

That really depends on the context of the map... Generality is a better approach than specificity.

But then that limits each unit to 50 steps.

8190 instances isn't necessarily a waste. It really depends, again, on the context.

Thanks Sevion and Waterknight both made very helpful suggestions.

I though about the IsUnitMoving thing before too. But then i realized it makes no sense to ignore as "timeline" when a unit isn't moving, it's still spending time doing something.

Didn't know much about the jagged arrays, they don't sound very useful since [n]*[m]<8190, that's one big limitation right there. Thanks for that too there

They are useful, and the only limitation is that after 8192 instances (0 to 8191) vJASS resorts to trigger evaluations, which are slow.
 

NoobImbaPro

You can change this now in User CP.
Reaction score
60
For 5 seconds 50 he needs, if he needs 8 minutes he may use 8000 indexes.
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Staff online

      Members online

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top