HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

HELP! Some newbie JASS questions

08-16-2008, 05:16 PM#1
xyzie
Hi there folks at WC3C! I just recently got back to War3 mapping and am trying to learn move advanced JASS (could only do simple stuff with it before). I've got quite a few questions as well as some questions I've got from reading through older threads. I'd like some pointers from the pros, thanks!
  1. "Timer Stack" - It seems to be a recommended solution to repeatedly creating and destorying timers. But I noticed some JASSers suggested there is no need to nullify the local timer variable, the statement confuses me a bit. Suppose we have the code

    Collapse JASS:
    function someCallback takes nothing returns nothing
        local timer tempTmr = GetExpiredTimer()
    
        //.... code
    
        call ReleaseTimer(tempTmr)
        
        //.... clean-ups
        set tempTmr = null  // Is this necessary here?
    
    endfunction
    
    function someFunc takes nothing returns nothing
        local timer tempTmr = NewTimer()
    
        //.... code
    
        call TimerStart(tempTmr,0,false,function someCallback)
        
        //.... clean-ups
        set tempTmr = null  // Is this necessary here?
    
    endfunction
    

    So my question is, using this Timer Stack, what would be an appropriate time to nullify the timer varible ("set xxx = null"), if there's any?
  2. Do you also need to nullify "player" handle type?
  3. If I want to do something with a short delay (eg 1 to 10 secs), is timer better or TriggerSleepAction? What about much shorter intervals, say under 1 sec to 0.05 sec? I guess I just don't understand the speciality of the two, could anybody explain?
  4. What does the native ResetTrigger do? It seemed to not remove the trigger's actions.
  5. If there's a Timer Stack, could there be a Trigger Stack, which is also favourable over creating/destorying triggers on the fly?
  6. What's a good practise to declare local handle-type variables(not Local Handle Var)? Does "local trigger T" suffice or you need "local trigger T = null"
  7. What does it mean that a gamecache has a limit of 256? Would this mean it can cause problems with Local Handle Vars when too many gamecache entries are used? Is there any workaround to that limitation?
  8. Speaking of Local Handle Vars, why is it many gosus claim it sucks? Which one can be an alternative attach system that is efficient, if I do not want to use editor hacks and mods (JASS NewGen pack, etc)?

Sorry for the bombardment of questions. That'd be all I've got, for now :) Thanks for your time!
08-16-2008, 05:41 PM#2
Anitarf
1. We only need to set local variables to null at ends of functions because war3 has a broken handle reference counter that doesn't decrease for local variables when functions end. Because of that, the game believes the handle adress where a timer or whatever was stored is still being pointed to by a variable so it doesn't recycle it. So, even if you destroy a handle (like a unit or a timer) the handle stack adress of that handle will leak if all variables pointing to it aren't set to null (or any other value).

2. Once you understand 1, the answer to 2 is easy. Players are not dynamicaly created or destroyed during the game, so it doesn't matter if the game thinks there are still a bunch of variables pointing to them because the game is never going to recycle their handle adresses anyway because we don't destroy players.

3. Typically, timers are the preferred option, at least in modern vJass. I could see why you'd want to use PolledWait in regular jass, though, and for delays longer than a second you can usually use them without a problem.

4. Don't know, I have never really seen it used.

5. No, because we can't clean up a trigger's events any other way than destroying the whole trigger.

6. Depends. If you don't do anything with the variable before initializing it then you don't need to give it an initial value when you declare it.

7. It isn't a limit on gamecache entries, but on gamecache objects.

8. It sucks because it does; there are few alternatives to it outside of vJass (maybe the old CSCache), though, that's what you get if you don't want to use editor hacks, can't be helped.
08-16-2008, 10:27 PM#3
Themerion
You will eventually realize that you want the "hack". Until then, use this:

Collapse Minimalistic HSAS/CSData:
// Minimalistic CSData/HSAS
// Paste it into your custom script section

// GetHandleIndex will return a unique number for each handle.
// Use it in combination with global arrays.

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

function GetHandleIndex takes handle h returns integer
    local integer index=H2I(h)-0x100000

// For debugging. Remove if you are very confident in that your map does not leak.
    if index>8190 then
        call BJDebugMsg("|cffff3333Attachment Warning! Index is greater than 8190.|r")
    endif

    return index
endfunction

Just notice that you have to keep your map clean. If your map leaks (or if you use a hell lot of objects), you will eventually exceed the size of an array (8190).

Collapse Example Usage:
// Create a unit array
// udg_xUnits[]

function KillUnitTimed_Expires takes nothing returns nothing
    local timer t=GetExpiredTimer()
    local integer index = GetHandleIndex(t)

// Kill Unit
    call UnitApplyTimedLife(udg_xUnits[index],'BTLF',0)
    set udg_xUnits[index]=null

    call ReleaseTimer(t)
    set t=null
endfunction

function KillUnitTimed takes unit u, integer time returns nothing
    local timer t=NewTimer()

// We now store the unit in the array.
// GetHandleIndex will return a unique number for our timer.
    set udg_xUnits[GetHandleIndex(t)] = u

    call TimerStart(t,time,false,function KillUnitTimed_Expires)

// Well. Better to be on the safe side, aight? :)
    set t=null
endfunction
08-17-2008, 12:48 AM#4
xyzie
Quote:
Originally Posted by Anitarf
1. We only need to set local variables to nul...

Wow thanks for the reply, that was timely and immensely helpful. Cleared up pretty much everything for me.

Although I've got another question concerning triggers. I read some threads on "dynamic triggers" and to my understanding it is best to avoid them at all costs and use a global trigger instead. Say we need a unit event trigger for a spell's target unit, instead of using dynamic triggers we use a global generic unit event trigger, right? But what if I want a "unit takes damage" event trigger, which has no generic counterpart, does that mean it is inevitable to still use dynamic triggers in this case?


Quote:
Originally Posted by Themerion
You will eventually realize that you want the "hack". Until then, use this:

I have been living under a rock but I gotta say this is one simple, elegant and sexy attachment system, compared to the goold ol Local Handle Vars. Thanks for the code!
08-17-2008, 10:45 AM#5
Anitarf
Quote:
Originally Posted by xyzie
Wow thanks for the reply, that was timely and immensely helpful. Cleared up pretty much everything for me.

Although I've got another question concerning triggers. I read some threads on "dynamic triggers" and to my understanding it is best to avoid them at all costs and use a global trigger instead. Say we need a unit event trigger for a spell's target unit, instead of using dynamic triggers we use a global generic unit event trigger, right? But what if I want a "unit takes damage" event trigger, which has no generic counterpart, does that mean it is inevitable to still use dynamic triggers in this case?
Recently, many implementations of damage detection systems have been going back to one static trigger to which you add specific events for all units. This results in event leaks over time, so indexing systems like the one posted above are in greater danger of hitting the array size limit. The reason why we still do this is because a)any decently designed map doesn't create too many units anyway (if you spawn 50 units every 30 seconds in an AoS, which is a lot, you still reach "only" 6000 event leaks in one hour) so if your map doesn't leak anything else you're safe and b)in vJass, you can extend the array size limit (at the cost of a bit of performance) so indexing systems like the one above can be made safe again.

Of course, some implementations of damage detection still use dynamic triggers. Since we haven't managed to completely determine what the problem with dynamic triggers is (we figured out some ways to cause problems with them such as by having waits in the trigger actions but we don't know if avoiding doing that is enough) it's possible that damage detection with dynamic triggers is completely safe, but it's also possible that it's not.
08-17-2008, 02:38 PM#6
Themerion
Well, since the code above breaks if your map leaks too much, I'll provide something better.

This script uses the same methods as TimerUtils_red and SmartTimers. It's fast, and won't be affected by other stuff leaking. It can only "attach" to timers, but since you shouldn't attach to trigger anyway... well... =)

Collapse JASS:
//***************************************************
//*                                                 *
//* XT Attachment System                            *
//* By: Themerion                                   *
//*
//*
//* Needs these variables:
//* - integer XTn
//* - integer XToffset
//* - timer   XTstack  array(200)
//*                                                 *
//***************************************************

function XT_H2I takes handle h returns integer
    return h
    return 0
endfunction
//------------------------------------------------------------------------------

function XT_New takes nothing returns timer
   set udg_XTn=udg_XTn+1
   return udg_XTstack[udg_XTn]
endfunction

function XT_Release takes timer t returns nothing
    set udg_XTstack[udg_XTn]=t
    set udg_XTn=udg_XTn-1
endfunction

function XT_Index takes timer t returns integer
    return XT_H2I(t)-udg_XToffset
endfunction
//===========================================================================
function InitTrig_XT takes nothing returns nothing

    set udg_XToffset=XT_H2I(udg_XTstack[0])

// Initial configuration check.
    if udg_XTstack[100]==null then
        call BJDebugMsg("|cffff3333Warning:|r\n|cffffcc00Increase the array size of the variable 'XTstack'.|r\n(200 recommended)")
    endif
endfunction

//===========================================================================
//====== </XT> ==============================================================
//===========================================================================

Collapse JASS:
XT_New()    // Acquires a new timer with an index! Must be released instead of destroyed.
XT_Release(t)    // Release timers acquired with XT_New()
XT_Index(t)    // You can only get indexes for timers acquired with XT_New()
08-17-2008, 04:44 PM#7
xyzie
Quote:
Originally Posted by Anitarf
Recently, many implementations of damage detection...

That's again very informative. Thanks!
I guess I will settle with event leaks, since it's unlikely I would do any map that can produce units of AoS caliber (well maybe later, but I sure hope I'd upgrade to vJass by then).

Quote:
Originally Posted by Themerion
Well, since the code above breaks if your map leaks too much, I'll provide something better

Hey thanks a bunch. You don't mind I use your code do you? Now unto (a bunch of) code rewriting... :D
08-17-2008, 05:44 PM#8
Themerion
Quote:
You don't mind I use your code do you?

I wrote it so that you would be able to use it So feel free to!

Quote:
Now unto (a bunch of) code rewriting... :D

Well, or rename the functions:

XT_Index -> GetHandleIndex
XT_New -> NewTimer
XT_Release -> ReleaseTimer
08-17-2008, 11:26 PM#9
xyzie
Question, though. The new code you gave me seems to have a limit of 200 timers? Not that this could ever become an issue for my map, just wanna make sure.
08-17-2008, 11:30 PM#10
Themerion
TimerUtils_red uses 256. But the limit is really rather arbitrary. Feel free to increase it if you think your map might ever use more than 200 timers simultaneously.

I think you can increase it up to 5000 if you want to. Karukef apparently tested this with his Safe Timers System. This might cause some problems with other less solid attachment systems (like game cache, the one I posted above, etc). Also, as Anitarf mentions below, if there are other scripts also doing a lot of stuff, then you might hit the oplimit (ouch).
08-17-2008, 11:32 PM#11
Anitarf
The biggest concern here is actually the oplimit in the init thread, so the number should be kept low. If you release timers correctly then 200 is more than enough.
08-18-2008, 08:47 PM#12
xyzie
Interesting.

One thing though, what & how much is this "oplimit"?
08-18-2008, 08:59 PM#13
Anitarf
I can't give you an exact answer on that. I've heard that initialising several (I have no idea exactly how many that is) handle arrays up to the max index (8191) in an average map can cause the map to hit the oplimit during initialization, thus not initializing some or all triggers (since trigger init comes after globals init). With 200 timers, however, you have nothing to worry about.
08-18-2008, 09:11 PM#14
Themerion
I noticed you found the graveyarded thread. That uses ExecuteFunc to avoid oplimit problems. Also, with it you should set the array size to (1) for the global timer array (easier for people who just create them).

Graveyarded XT_Attachment System
08-20-2008, 02:08 AM#15
xyzie
Quote:
Originally Posted by Anitarf
I can't give you an exact answer on that. I've heard that initialising several (I have no idea exactly how many that is) handle arrays up to the max index (8191) in an average map can cause the map to hit the oplimit during initialization, thus not initializing some or all triggers (since trigger init comes after globals init). With 200 timers, however, you have nothing to worry about.

Oh dear do we love the war3 oddities and quirks.

Quote:
Originally Posted by Themerion
I noticed you found the graveyarded thread. That uses ExecuteFunc to avoid oplimit problems. Also, with it you should set the array size to (1) for the global timer array (easier for people who just create them).

Graveyarded XT_Attachment System

Yeah I will make the changes.

Thanks again guys