• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

[JASS] Attack indexing seems impossible...

Status
Not open for further replies.
I've been writing an AttackIndexer, but I just realized something troubling... if the attacking unit is removed during an attack, EventDamageSource will return null, meaning that the following script displays 0. I made priest have like 3000 range and 9000 sight radius and 4500 acquisition range and .01 cooldown on attack with 1 dmg per attack, lol...

Anyone know a way to fix this? : O

Unit recycling isn't an answer as the abilities and what not screw it up as well as the techs ;O... if a tech goes between players, yea... if an ability is permanent, yea...

Well, I could hook RemoveUnit and have a dummy for it somewhere in the background that stores it's data (in AttackIndexer) until all of its attacks are done ; |, but GetEventDamageSource would still return null... I can't hook RemoveUnit and make it stop calling : |... I could just say don't remove units and use RemoveUnitEx instead >.>. I could fix this with cJASS definitions if cJASS actually worked... /cry

JASS:
struct tester extends array
    private static unit u1
    private static unit u2
    private static method onD takes nothing returns boolean
        call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, I2S(DamageEvent.sourceId))
        return false
    endmethod
    private static method run2 takes nothing returns nothing
        call RemoveUnit(u1)
        call DestroyTimer(GetExpiredTimer())
    endmethod
    private static method run takes nothing returns nothing
        local fogmodifier f = CreateFogModifierRect(Player(0), FOG_OF_WAR_VISIBLE, WorldBounds.world, false, false)
        call FogModifierStart(f)
        set u1 = CreateUnit(Player(0), 'hmpr', WorldBounds.centerX-2500, WorldBounds.centerY, 0)
        set u2 = CreateUnit(Player(8), 'hpea', WorldBounds.centerX, WorldBounds.centerY, 0)
        call IssueTargetOrder(u1, "attack", u2)
        call TimerStart(GetExpiredTimer(), 2, false, function thistype.run2)
    endmethod
    private static method onInit takes nothing returns nothing
        call TimerStart(CreateTimer(), 0, false, function thistype.run)
        call DamageEvent.EVENT.register(Condition(function thistype.onD))
    endmethod
endstruct
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,286
Fix what? Its working as intended as far as I can tell. A unit which no longer exists should never be returned from a native.

You can add a conditional statement to check if it returns null, and if so then ignore the rest of the code.

You could also try adding some kind of hyrisitc, for example a unit that has attacked but was removed still did attack so if the attack lands within a time after that unit started attacking, the source must be the removed unit. However that still is not useful at all as the unit was removed...
 
Well, attacks have data attached to them. Once an attack is created, it doesn't matter whether the unit exists or not. It's difficult to retrieve attack data if said unit was removed ;P.

If you have 3 projectiles and 3 units were removed, there's no way to know which projectile belongs to which unit.

Each unit has its own attack recycling (50 instances per unit). The attack struct itself is retrieved by the unit id + the unit's current attack id (this way few objects are needed for insano stability ;D).

8190 attacks can be on the map at one time. Obviously, not all units can fill out their complete attack queues, but the overall script is very stable.

Now, I could do global attack indexing, but that'd require at least 500 objects to even approach stability (a lot more than 50)

Actually, what I could do to decrease the total object count is do 4 sets of 10 objects, thus achieving around 10000 total possible instances with an overhead of 44 objects.

edit
I think I'll do that ; |, well, I have to do that rofl, haha ;D.

edit
nvm, I just remembered that buffs can't have levels : |
 
Last edited:
There's another issue... I found a game bug...

Wc3 projectiles are cleaned up every 60ish seconds. After the first cleanup, projectile damage is applied to the unit...

I was firing projectiles across a map towards a unit (super slow ones). First cleanup (on old projectiles), they were applied with 0 damage. Second cleanup, they were applied with damage... third cleanup killed the unit. Fourth cleanup removed all projectiles as the unit went out of scope (decayed).

Bugs anyone? I'd submit to Bliz, but I don't feel like logging on to their forums. Can someone let them know? Tx ;D.


Also tell that that it would be really cool to be able to get the handle id or w/e of an attack ;O (whatever id is associated with it) and to havel ike GetEventAttack ;D. Furthermore, it'd be cool to GetEventAttackAbility =D.

Done making this until that wc3 bug gets fixed as that destroys the entire system + gameplay ofc.

Also, it doesn't appear that wc3 has any limits on how many attacks can be up at one point, so... I might just have to spam 8000 abilities for attack indexing, rofl.
 
Ok, this is what I have learned from all my tests on attacks


A unit's maximum possible attack speed is 10 attacks per second (.1 cooldown). I know this because I looked at the change in time between attacks with 0 backswing animation and 0 cd and it was always .1.

An attack will always expire at 60 seconds (+ between .006 and .013).

Because attacks always expire at 60 seconds, a unit can only ever have 600 attacks up on the map at one time.

When an attack expires, it deals its damage to the target unit (always). Should it do this? Probably not =\. This can be easily fixed as a timestamp can be assigned to each attack and if the attack expired, the damage it dealt can be undone.

You can have infinite attacks on the map at one point.

An attack does not allocate a handle.

Also 8000 levels on an ability is smaller than like 15 custom abilities ; |.
 
Last edited:
Well, atm I'm seeing how big a map is with 8000 custom buffs in it (will test load time too).

We shall see just how feasible a fully stable attack indexer is ; P.

Otherwise, if worst comes to worst, I can just say-

No Remove Unit while attacks are up
Decay time must be >60


Or we could be cool and do a fully custom attack system for wc3... given I can inject into attacks, all we'd need is a dummy unit in the background for each unit for storing attacks =O. The gear etc would be on this dummy unit, it's position would be set to the main unit whenever an attack is issued and then set back. It may be messy, but it's still faster than a full scale projectile system ;o.

So far this script has been running for like the last hour, still not done yet. I'll edit post or reply when it's done to let people know just how big my map got ;D.

ETA to script finish: 3 hours
Total time so far: 1 hour

edit
Dunno... stopped the script which stopped the compilation.. I'll be editing the lua scripts a bit as jasshelper can't seem to parse certain things because vex didn't treat it as a literal string.................................................................................................................................................. *emphasis added*
 
Ok, Attack Indexing will create 8191 custom buff objects for attack indexing as well as 1 ability object with 8191 levels.

What would be the overhead for this?
27 or so kb

How much does it add to load time?
Virtually nothing


What I have learned is that the only data saved into the map for objects is custom data. This means that when making custom objects, use as little custom data as possible to decrease overhead.

Proof-
JASS:
//! externalblock extension=lua ObjectMerger $FILENAME$
    //! i setobjecttype("buffs")
    //! i local count = 8000
    //! i local base = "BNcg"
    //! i while (count > 0) do
        //! i createobject(base, generateid(base))
        //! i makechange(current, "ftip", "")
        //! i count = count - 1
    //! i end
//! endexternalblock

The object id used there has no art associated with it (which is why I used it). I doubt it even shows up on a unit in the UI.

edit
This just in, the buff above does not show up on a unit at all >: ).
 
So these are latest updates to my Attack Indexer ;o.

Wonderful ini code >: D
JASS:
//! externalblock extension=lua ObjectMerger $FILENAME$
    //! runtextmacro LUA_FILE_HEADER()
    
    //! i dofile("DummyPhysicalAbility")
    
    //! i local MAX_ATTACKS = 8191
    
    //! i local object = getdummyphysicalability("ATTACK_INDEXER_ABILITY", MAX_ATTACKS, false)
    
    //! i local jass = 
        //! i [[//! textmacro ATTACK_INDEXER_GLOB_1
            //! i globals
                //! i private hashtable buffTable = InitHashtable()
                //! i private constant integer DUMMY_ABILITY = ']] .. object.ability .. [['
            //! i endglobals
            //! i private function AttackIndexerGlobalsInit takes nothing returns nothing]]
            
    //! i do
        //! i local cur = MAX_ATTACKS
        //! i while (cur > 0) do
            //! i jass = jass .. "\ncall SaveInteger(buffTable, '" .. object.buffs[cur] .. "', 0, " .. tostring(cur) .. ")"
            //! i cur = cur - 1
        //! i end
    //! i end
    
    //! i jass = jass .. "\n" .. [[
            //! i endfunction
            //! i private module InitMod
                //! i call ExecuteFunc(SCOPE_PRIVATE + "AttackIndexerGlobalsInit")
            //! i endmodule
        //! i //! endtextmacro]]
    
    //! i writejass("AttackIndexer_GLOBALS", jass)
    
    //! i updateobjects()
//! endexternalblock

Generates this (8202 lines)

http://www.hiveworkshop.com/forums/pastebin.php?id=r8dtex

That script + all of the objects adds around 80 kb to the map (most of it from script).

The ini script takes around 1 minute to run on my laptop.

I tested to make sure that the code I posted does not hit op limit (and it doesn't).

I tested the load time and it was fast with the system in place. All that's left is the actual system code (rofl rofl, the easy part).

Updating LUA_GET_VAR_OBJECT to be fast enough to run this in a reasonable amount of time was probably what I spent the most time working on : P.

I'll probably get the rest of AttackIndexer finished tomorrow. Until then, you can stare at my crazy initialization code (AttackIndexer is so far only 8202 lines of code, how exciting).


Thank you everyone for your continuing support = ).

edit
Still working on many things having to do with this... like figuring out a good way to see what buffs are on a unit ;P.
 
Last edited:
Status
Not open for further replies.
Top