HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

Light Leakless Damage Detect

08-05-2008, 11:57 PM#1
Captain Griffen
A lightweight and leakless damage detection system. Works by swapping over to another trigger, disabling the old one, and then destroying it 600 seconds later.

May not be perfectly safe, but commenting out one line can turn it to an efficient and safe (as far as we know) but leaking damage detection system, for rapid debugging or if problems appear.

Pros:

- Does not leak handle indexes or objects.
- Provides a fast base system for anything else to be added on.
- Avoids known and identified handle stack corruption issues (read directions below).
- Easy to use and very efficient.

Cons:

- May not be safe. We simply don't know enough.
- Only allows conditions (return booleans); faster, no real reason to use actions (could easily be converted). (NB: The only advantage of this would be allowing sleeps, which interfer with other actions, so you'd need to add all actions to their own triggers and execute them.)
- The swapping may cause a lag spike. Didn't for me with an empty map with 2000 units, but if the map is already near the limit, it may cause issues.

NB: Do not destroy any conditions past to this system. Heck, don't destroy conditions or boolexprs ever, anywhere, since there is no need and it can cause unrelated code to fail.

Example Code:

Expand JASS:

System Code:

Expand JASS:
08-06-2008, 01:45 AM#2
DioD
Pros:

1) it leaks GetWorldBounds() and there is no cleanup functions.
2) standart trigger condition based system, its is not faster then others.
3 and 4) There is no prove provided

Cons:

1) Actually it is safe, since no triggersleep allowed in trigger conditions.

2) There is no code type array allowed, this system cannot be moved to actions.

3) NC
08-06-2008, 01:55 AM#3
Here-b-Trollz
Does GetWorldBounds() return a new rect every time? I thought it just returned the same one over and over. If so, you lose a pro Griffen :<
08-06-2008, 02:00 AM#4
DioD
GetWorldBounds() == GetWorldBounds() will return FALSE
08-06-2008, 02:00 AM#5
darkwulfv
You could use bj_mapInitialPlayableArea, since GetWorldBounds() probably has areas in it that units can't be created in anyways. (Could be wrong, just a suggestion)

And is there a way to filter what units get detected? Because it would be kind of stupid to register dummy units and the likes since they appear in the map (thus being registered) and go away pretty quickly, wasting function calls.
08-06-2008, 02:01 AM#6
Here-b-Trollz
Quote:
Originally Posted by DioD
GetWorldBounds() == GetWorldBounds() will return FALSE
Lame.
08-06-2008, 04:08 AM#7
DioD
Lame != Wrong, remember this.
08-06-2008, 09:45 AM#8
Toadcop
// Returns full map bounds, including unplayable borders, in world coordinates
native GetWorldBounds takes nothing returns rect

kind a wtf?! why everyone is posting his own "solution" for the same problem XXXXXX times? imo such stuff must be posted in trigger/script forums. not as a submission -_-

just imagine some user wants to download some dd system from db and he find couple of them and he have no idea what to choose...
some are "better" but simple the other one more complicated but offers bit less performance.

well MAKE SOME MAPS. =)

and the Swap function is so omfg... n/c
08-06-2008, 10:25 AM#9
Deaod
Nifty system.

Quote:
And is there a way to filter what units get detected? Because it would be kind of stupid to register dummy units and the likes since they appear in the map (thus being registered) and go away pretty quickly, wasting function calls.
Yes, there is a way to do that. Simply edit the system and change the line
Collapse JASS:
    call TriggerRegisterUnitEvent(current, GetTriggerUnit(), EVENT_UNIT_DAMAGED)
to
Collapse JASS:
    if GetUnitTypeId(GetTriggerUnit())!='whateverID' then
        call TriggerRegisterUnitEvent(current, GetTriggerUnit(), EVENT_UNIT_DAMAGED)
    endif
Tip: if you want to exclude more than one unit type, i suggest creating an integer variable which holds the TypeId. If you only want one Type to be checked for incoming damage (or at least very few of your total units), i suggest changing the comparison into "==".

@DioD:
This system can be move to triggeraction. Very easily.
And by the way are conditions the fastest way i know of. If you can come up with something faster, i suggest you create another Damage Detection system for yourself.
08-06-2008, 10:40 AM#10
Captain Griffen
Quote:
Originally Posted by DioD
1) it leaks GetWorldBounds() and there is no cleanup functions.

Okay, Blizzard fails... Thanks for the spot, I'll fix it.

Quote:
2) standart trigger condition based system, its is not faster then others.

Did I say it was faster?

Quote:
3 and 4) There is no prove provided

3, feel free to go look up what we know, but I'm open about not knowing if it is perfectly safe or no.

4 needs no proof, it's self-evident, so unless you can make it

Quote:
1) Actually it is safe, since no triggersleep allowed in trigger conditions.

Actually tested the identified bug with thread created off it from TriggerExecute/ExecuteFunc? Tests indicate it is.

The bigger worry is that we don't have any actual proof that even without waits DestroyTrigger is safe; it makes it safer, but it could just be we haven't found the smoking gun.

Quote:
2) There is no code type array allowed, this system cannot be moved to actions.

Either I2C, or just running a constant trigger from a changing one.



Quote:
You could use bj_mapInitialPlayableArea, since GetWorldBounds() probably has areas in it that units can't be created in anyways. (Could be wrong, just a suggestion)

I'll just use a private global for it, better safe than sorry.

Quote:
And is there a way to filter what units get detected? Because it would be kind of stupid to register dummy units and the likes since they appear in the map (thus being registered) and go away pretty quickly, wasting function calls.

Editing Enters and AddEx. I'll document that.


Quote:
kind a wtf?! why everyone is posting his own "solution" for the same problem XXXXXX times? imo such stuff must be posted in trigger/script forums. not as a submission -_-

This system does stuff in a substantially different (probably improved, unless blizzard has some lameness stuck up there somewhere we haven't found yet) way.

We have Dusk's Intuitive Damage Detection, designed for working with all triggered spells, and Vex's Attack Detection System (probably outdated?). This is very distinct from both.
08-06-2008, 11:10 AM#11
DioD
Deaod

Code:
        loop
            exitwhen i >= funcNext
            call TriggerAddCondition(current, [u]func[i][/u])
            set i = i + 1
        endloop

Cannot be done with trigger actions, no code array allowed.

Captain Griffen
Quote:
Either I2C, or just running a constant trigger from a changing one.

I2C Async, crush on natives, cause integer overflow, corrupts arrays.

Code:
    private function Swap takes nothing returns nothing
        local integer i = 0
        
        call DisableTrigger(current)
        set toDestroy = current
        set current = CreateTrigger()        
        call GroupEnumUnitsInRect(swapGroup, GetWorldBounds(), Filter(function AddEx))        
        loop
            exitwhen i >= funcNext
            call TriggerAddCondition(current, func[i])
            set i = i + 1
        endloop
        call TriggerSleepAction(0.0)
        if toDestroy != null then
            call DestroyTrigger(toDestroy)
        endif
    endfunction
08-06-2008, 11:33 AM#12
Captain Griffen
Quote:
Originally Posted by DioD
I2C Async, crush on natives, cause integer overflow, corrupts arrays.

I2C shouldn't be asyncronous if using a C2I to start with. C2I may or may not crush on natives; setting a native to a code variable crashes the game.

As for integer overflow, that might well be possible, but I'm not sure. Test it.
08-06-2008, 01:53 PM#13
Toadcop
Captain Griffen there is also grim's dd system =) // and maybe some others i don't remember.

I2C Async - why it's async ? =) wc3 was own virtual machine so it can't depend on some CPU specifics.
+ every .j file must be the same for all players including functions. (the call might be local but i doubt what it will change the id of code...)

we need prove for Async =) the rest is shit and known. (int overflow etc.)
08-06-2008, 04:34 PM#14
Rising_Dusk
Blah, I will never, ever approve anything that claims some logic behind using DestroyTrigger(). If this recycled units of the same unit type rather than destroying triggers (Regardless of the hocus pocus used to ensure it's "safe" to do so), then I might look at it past that. Honestly, though, this is kind of... Misleading. A damage detection system as has become known over the years is something that allows distinguishing of types of damage and gives a semblence of control over the map's damage. This really just provides a way to register the EVENT_UNIT_DAMAGED event without leaking events, but it relies on dynamic triggers to do so. Lame.

Also, use bj_mapInitialPlayableArea, it's better.
08-06-2008, 06:58 PM#15
d07.RiV
How come dota uses a huge amount of dynamic triggers and releases them by disabling and removing after 60 seconds?

Btw each event takes up about 400 bytes.