Snippet Handle Counter

emjlr3

Change can be a good thing
Reaction score
395
Handle Counter

A sure fire way to determine whether you're map is leaking handles.

Simply copy the JASS script into a trigger named HandleCounter, configure the options, and enjoy!

Credits to Cohadar for first interesting me in this concept.

JASS:
scope HandleCounter

globals
//=====Config. Options=====\\
    private constant string Title = "Handle Counter" // Title of your leaderboard
    private constant string HandlesTitle = "Handles" // Text to display in handle count row
    private constant string SecondsTitle = "Time (sec.)" // Text to display in time row
    private constant real Timeout = 1. // Interval to update at ( I recommend a whole number, or your time elapsed displayed could bug)
    private constant player DisplayTo = Player(0) // What player to display the leaderboard to
    private constant player Row1 = Player(0) // The time text will be displayed in this players color
    private constant player Row2 = Player(1) // The handle count text will be displayed in this players color
    private constant boolean Single_Only = true // Whether to display the Handle Counter leaderboard in single player only

//=====No Touching Past This Point!!!!=====\\
    private trigger Trigger = CreateTrigger()
    private leaderboard Lead = null
    
    private integer Seconds = 0
    private location L = null
endglobals

private function H2I takes handle h returns integer
    return h
    return 0
endfunction

private function HandleCounter_Conditions takes nothing returns boolean
    return not Single_Only or bj_isSinglePlayer
endfunction
private function Update takes nothing returns nothing
    set Seconds = Seconds + Timeout
    call LeaderboardSetItemValue(Lead,0,Seconds)
    set L = Location(5.,5.)
    call LeaderboardSetItemValue(Lead,1,H2I(L)-0x100000)
    call RemoveLocation(L)
endfunction
private function HandleCounter_Actions takes nothing returns nothing
    call DestroyTrigger(Trigger)
    set Trigger = CreateTrigger()
    call TriggerRegisterTimerEvent(Trigger,Timeout,true)
    call TriggerAddAction(Trigger,function Update)
    
    set Lead = CreateLeaderboard()
    call LeaderboardSetLabel(Lead, Title)
    call PlayerSetLeaderboard(DisplayTo,Lead)
    call LeaderboardDisplay(Lead,true)
    call LeaderboardAddItem(Lead,SecondsTitle,Seconds,Row1)
    call LeaderboardAddItem(Lead,HandlesTitle,0,Row2)
    call LeaderboardSetSizeByItemCount(Lead,2)
endfunction

//===========================================================================
public function InitTrig takes nothing returns nothing
    call TriggerRegisterTimerEvent(Trigger,.001,false)
    call TriggerAddCondition(Trigger,Condition(function HandleCounter_Conditions))
    call TriggerAddAction( Trigger, function HandleCounter_Actions )
endfunction

endscope
 

emjlr3

Change can be a good thing
Reaction score
395
you are correct about that, updated

and what is the problem with globals, or NewGen??

bump!!!
 

N-a-z-g-u-l

New Member
Reaction score
30
the problem is, i had some errors with newGen, and im not using it...

and with it comes, that adding many variables by hand is VERY annoying^^

for me, i made my own non-newGen system now:

JASS:
globals
	leaderboard udg_HandleBoard
endglobals

function HandleCounter_L2I takes location P returns integer
	return P
	return 0
endfunction

function HandleCounter_Update takes nothing returns nothing
	local integer i = 1
	local integer id
	local integer idmax = 0
	local location array P
	loop
		exitwhen i > 100
		set P<i> = Location(0,0)
		set id = HandleCounter_L2I(P<i>)
		if id&gt;idmax then
			set idmax =id
		endif
		set i = i + 1
	endloop
	loop
		set i = i - 1
		exitwhen i &lt; 1
		call RemoveLocation(P<i>)
		set P<i> = null
	endloop
	call LeaderboardSetItemValue(udg_HandleBoard,0,idmax-0x100000-100)
endfunction

function HandleCounter_Actions takes nothing returns nothing
	set udg_HandleBoard = CreateLeaderboard()
	call LeaderboardSetLabel(udg_HandleBoard, &quot;Handle Counter&quot;)
	call PlayerSetLeaderboard(GetLocalPlayer(),udg_HandleBoard)
	call LeaderboardDisplay(udg_HandleBoard,true)
	call LeaderboardAddItem(udg_HandleBoard,&quot;Handles&quot;,0,Player(0))
	call LeaderboardSetSizeByItemCount(udg_HandleBoard,1)
	call HandleCounter_Update()
	call TimerStart(GetExpiredTimer(),0.2,true,function HandleCounter_Update)
endfunction

//===========================================================================
function InitTrig_HandleCounter takes nothing returns nothing
	call TimerStart(CreateTimer(),0,false,function HandleCounter_Actions)
endfunction</i></i></i></i>


it works slightly different, as i create 100 locations and not only one...
lets assume handle id-allocating works like this:

#########[]####[][]#####[]#####[]

# means filled
[] means a not-used handle id

so if you only create one location, you get the position of the first empty handle id... now, i create 100 locations, so it fills 100 spaces, and then i get the handle-id of the location with the highest id and substract 100 for the 100 locations i created...

theoretically, this should work, but i find it weird that my value usually jumps not at all, and i dont believe that my map Battle Tanks is absolutely leak-free

when i had only 1 location, it jumped between 8190 and 8195 periodically, but sometimes returned 3600 or something like that... now, using 100 locations, i get a constant value, which extremely grows when i use a nuclear bomb with lots of single special effects (about ~500 additional handles), but then those stay... and if i use the bomb again, it wont go back...
oh well, while writing this i found a reason... i use a timer stack and perhaps i create a lot of new timers here, or perhaps even groups or locations (i use stacks for every handle types where it is possible^^), so might be ok

nevertheless, i feel more confident with 100 locations than only one^^
(would be interesting to see in which order they get their handle ids, if its really always ascending, then my handle-id-allocating-theory could be right^^) i will try this later or tomorrow and post here

by the way, a leaderboard might be a good solution, but if the map already has a leaderboard in use, then this will hide the old leaderboard... i was trying a text-tag based way (the text-tag should follow the camera), but even with a refresh rate of 0.001 and a hide and show every period it did not work... text messages would be ugly, multiboards have the same problem... maybe a timer window?

EDIT: weird, tested it, i get the same result all the time for the highest handle-id, but alternating it finds a new id 100 times (like expected), and then only one time (so it starts off with the highest value, then probably jumps to the smallest and fills the rest) i believe that there is some problem with cleaning up handles in general... i often experienced such a behavior, not only with globals (perhaps you know the test with globals, where RemoveLocation(P) and then set P = Location(0,0), then again, as a proof that you dont have to nullify globals)

EDIT2: weird again...
for the first case: 100 times a new maximum is found, so it is constantly ascending
for the second case: 1 time a new maximum is found, and only 1 time the id is higher than the last id created (which means, the ids are allocated like 100, 99, 98, 97, 96... )

i should try cleaning them 100, 99, 98, 97,... instead of 1,2,3,4,5,...

EDIT3: now i clean them up like 100,99,98,97,... and the result is, i always get the smallest handle-id first...

as a conclusion:
A newly created handle always gets the id of the last destroyed handle. If there is no id of a destroyed handle left, the handle id is ascending.

so it becomes harder to find the real amount of handles... you could search till you find a constantly ascending order of handle ids, then you may have found the end of used ids, and then you could sort all your locations by their handle id to restore that ascending order for the handle-id-allocator... then you could start off doing the same, and next time your script will recognize your ordered handle ids as the constantly ascending of handle ids which displays the end of used handles... but performance and op-limit hate you^^

now, if you have those 100 locations, it is better to clean them 100,99,98,..., because if another handle gets destroyed, this script wont find its location with the highest id first, but will start off with smaller ids... i will change that in the script above... done

EDIT4: funny, how this post looks like a work-diary^^

perhaps i will create a working handle-counter tomorrow (would take quite a lot performance), but for today (it is 00:42 AM) its over, i have to get up at 06:30^^
 

emjlr3

Change can be a good thing
Reaction score
395
i thought newly created handles were allocated in the first available slot, per say, not the last destroyed handles slot
 

N-a-z-g-u-l

New Member
Reaction score
30
it actually works like a stack:

1,2,3,4,5,6,7,8,9,10,...

are free in the beginning, then, 3 handles are created

4,5,6,7,8,9,10,... are still there

then, handle #1 is destroyed

1,4,5,6,7,8,9,10,... are now free

then, handle #3 is destroyed

3,1,4,5,6,7,8,9,10,... are free

now, lets assume handle #2 does not get destroyed

you have "3,1,4,5,6,7,8,9,10,..." and need to find, how many handles are used... well^^

you could create 256k locations and then count, how many numbers are missing to form a perfect sequence^^ however, thats a little bit time-consuming^^

what i currently do is checking the first 100 ids in the stack for the highest id i can find, and return it, but it isnt precise... assuming you have created 100 locations at initialization, then after 1 minute clean them up, the handle count would be like 0, because ids 0 to 100 are allocated

now, the idea i described before is taking many ids out of the stack and sort them, but it is not safe either
 

emjlr3

Change can be a good thing
Reaction score
395
lol, so my way is decent enough, not perfect, but not terrible either, it gives you a good estimation, and more to the point, shows you if your leaknig handles
 

N-a-z-g-u-l

New Member
Reaction score
30
JASS:
globals
	leaderboard udg_HandleBoard
endglobals

function HandleCounter_L2I takes location P returns integer
	return P
	return 0
endfunction

function HandleCounter_Update takes nothing returns nothing
	local integer i = 0
	local integer id
	local location array P
	local real result=0
	loop
		exitwhen i &gt;= 50
		set i = i + 1
		set P<i> = Location(0,0)
		set id = HandleCounter_L2I(P<i>)
		set result = result + (id-0x100000)
	endloop
	set result = result/i-i/2
	loop
		call RemoveLocation(P<i>)
		set P<i> = null
		exitwhen i &lt;= 1
		set i = i - 1
	endloop
	call LeaderboardSetItemValue(udg_HandleBoard,0,R2I(result))
endfunction

function HandleCounter_Actions takes nothing returns nothing
	set udg_HandleBoard = CreateLeaderboard()
	call LeaderboardSetLabel(udg_HandleBoard, &quot;Handle Counter&quot;)
	call PlayerSetLeaderboard(GetLocalPlayer(),udg_HandleBoard)
	call LeaderboardDisplay(udg_HandleBoard,true)
	call LeaderboardAddItem(udg_HandleBoard,&quot;Handles&quot;,0,Player(0))
	call LeaderboardSetSizeByItemCount(udg_HandleBoard,1)
	call HandleCounter_Update()
	call TimerStart(GetExpiredTimer(),0.05,true,function HandleCounter_Update)
endfunction

//===========================================================================
function InitTrig_HandleCounter takes nothing returns nothing
	call TimerStart(CreateTimer(),0,false,function HandleCounter_Actions)
endfunction</i></i></i></i>


thats what i got now...
it should take the first 50 values and form the arithmetic average of those ids, then substract 25 to do not count the locations just created
it isnt precisely either, but it could be a good approximation
 

emjlr3

Change can be a good thing
Reaction score
395
christ your gonig through a 100 loop every .05...

also just noticed that if ppl changed their timeout, since i added 1 to the total seconds every loop it would have bugged, fixed that
 

N-a-z-g-u-l

New Member
Reaction score
30
christ your gonig through a 100 loop every .05...

also just noticed that if ppl changed their timeout, since i added 1 to the total seconds every loop it would have bugged, fixed that

this is not meant as a system, but for tests :D i wanted to see if the result is jumping.. it is not
(it only jumps in between 92...192 if i have another periodic function which creates 1...100 locations and destroys them in the order 1...100)
 
Reaction score
456
I'd call this Leak Detector or something :p..

Helps those who do leaking code :).
 

emjlr3

Change can be a good thing
Reaction score
395
thats a product of the system, not its purpose, its purpose is to tell you how many handles are currently in your map

I think the name fits, and the description mentions such an ability
 

emjlr3

Change can be a good thing
Reaction score
395
i prefer lamens terms
 

emjlr3

Change can be a good thing
Reaction score
395
moved, poke me if you disagree
 

AdamGriffith

You can change this now in User CP.
Reaction score
69
JASS:
    private constant real Timeout = 1.


JASS:
    private integer Seconds = 0


JASS:
    set Seconds = Seconds + Timeout


Should 'Seconds' not be a real aswell? Because if the timeout is changed to say 0.5 then adding 0.5 to the seconds will not actually change it because it is an integer so it will round down.
 

cr4xzZz

Also known as azwraith_ftL.
Reaction score
51
Well, it should. It gives me a syntax error. But it's not a problem for me, I just make Timeout to be an integer and everything works perfectly. Maybe it's a little thing he missed.
 
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