| 08-16-2008, 05:16 PM | #1 |
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!
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 |
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 |
You will eventually realize that you want the "hack". Until then, use this: 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). 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 | ||
Quote:
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:
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 | |
Quote:
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 |
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... =) 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> ============================================================== //=========================================================================== 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 | ||
Quote:
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:
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 | ||
Quote:
I wrote it so that you would be able to use it So feel free to!Quote:
Well, or rename the functions: XT_Index -> GetHandleIndex XT_New -> NewTimer XT_Release -> ReleaseTimer |
| 08-17-2008, 11:26 PM | #9 |
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 |
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 |
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 |
Interesting. One thing though, what & how much is this "oplimit"? |
| 08-18-2008, 08:59 PM | #13 |
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 |
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 | ||
Quote:
Oh dear do we love the war3 oddities and quirks. Quote:
Yeah I will make the changes. Thanks again guys ![]() |
