• 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.

Performance Question

Status
Not open for further replies.
Level 12
Joined
May 22, 2015
Messages
1,051
I am working on a map where I want full control of casting animations and abilities. There won't even be the regular attacks in it.

However, I am still at a very early stage. I'm just importing / building systems to be used as building blocks down the road. I'm using only JASS in the native wc3 map editor. I'm fairly well versed in it. Pseudo code or JASS are preferred if you are trying to explain a code strategy to me.

I thought of two ways to handle abilities. They will generally have a duration to them but need to be capable of handling cases where they are interrupted (most likely due to a stun effect). For example, the first enemy I will implement is a giant beetle who charges at the player units. If it gets stunned, I want it to stop charging and slide a little bit in the direction it was charging (can't just stop so suddenly so easily and I want it to look smooth - I already have knockback system in place).

Note that I don't plan to have a ton of units fighting at the same time - maybe around 50-100 at once will be an absolute upper limit (though it's undecided in this early stage of development - doubt it will get that high but who knows).


Method 1
Create a timer that handles the entire charge (or other ability), firing frequently to create smooth movement and apply its effects. If the unit is affected by something that should stop it, recycle the timer and handle the "interrupted" case (for the beetle, apply a small knockback in the direction it was charging).

Method 2
Create a system where I input triggers to fire with just one central timer to handle each currently active ability. I know the trigger condition trick to increase performance (don't use trigger action, just use trigger condition and always return false) but I have no idea if firing a trigger every 0.03 seconds for every active ability will cause any problems, or if it will be slower or faster than method 1.


TL;DR: What will have better performance: A new timer for each instance of an ability or one central timer where I fire a trigger for each instance of the same ability?
 
Not sure I see the clear difference in question, as a trigger per se is probably only needed if some kind of events are wanted. 1 timer for all vs. 1 timer per instance could both require no triggers.

The good thing with using 1 timer per instance is, you can directly bind data, like maybe an used index to the timer (hashtable). With using the binded index, all instance-relevant data can be accessed.

With 1 global timer instead, there is no direct connection to an instance. Instead, one must use an array list, or just some other data structure. So when timer expires, one loops through all list-elements, and make appropriate actions through the list loop.

I would use 1 timer per instace, as it's easier, and more flexible.
On other side, sometimes it can make sense for one element to have direct access to all other elements, and then a list can become handy, too. ( though actually still, one can have a list AND still use 1 timer per instance)

But if it's about 100 instances, it does not really matter, I believe, if it's about saving some handle creations as long you properly destroy them again.

A related resource, Attack System v1.1 [vJass | + GUI Support]. In vJass by @AGD, but maybe still interesting.^^
 
Level 12
Joined
May 22, 2015
Messages
1,051
Thanks IcemanBo. The reason I was thinking of one central timer is because I noticed a pattern with my abilities. Most of them will have some duration (ones that execute instantly with no lingering effects will be easy either way) and have to handle being interrupted uniquely. There's a bunch of other small things like some effects will block the effects of an ability which could be added into the central system. I'm not sure what else, but a central system would let me avoid duplicating logic.

I just use the triggers as function pointers. So to make a new ability with this central timer system, my ability code will be a bit like this:
- Create a trigger that executes one step of the ability (will be fired every 0.03 seconds)
- Create a trigger that handles if the ability is interrupted (will only fire if the central loop sees that the acting unit gets interrupted)
- Create a trigger that cleans up the ability (clear hashtable entries, clear unit groups, etc. - it will fire when the ability is done or if the ability is interrupted)

None of the triggers would have events that cause them to fire. They are just variables to pass into a function in the central system that adds the information to a list. I would reuse the same triggers for every instance of the same ability and rely on global variables to know which objects to use in it (most likely just pass the acting unit's index and the rest of the info will be tied to that).


If I do it without the system, I will end up checking if the unit is interrupted in a lot of places rather than just one main place. I will still need functions for all those things, they just won't be wrapped into triggers. I think, code-wise, I would rather do the central system, I just don't want to do that if it is going to be slow to run. I was just worried it might be laggy if I do it this way. It would suck if I do it one way and then have to redo it the other way if I have a lot of abilities implemented.

Maybe I should just implement one ability and stress test it with a lot of instances of the ability.
 
A central system can definitely be relevant. Before, I probably a bit misunderstood, so it's not too relevant, but anyways, also inside the central system I still would create 1 timer per instance.

The periodic 1) action, 2) interrupt event, or 3) clean up - should the actions that happen there be customizable? If they are part of the core system, maybe calling normal jass functions would do the same, instead of running triggers.

A possible draft:
JASS:
System Beetle Charge{

function doCharge(){
    // charge towards unit / damage nearby enemies
}

function doCleanup(){
    // removes data that was used by an instance
}

function periodic_check(){
    // check element or whole list, binded to expired timer

    if (unit_has_stun_buff) {
       // nothing or disable or pause timer // stuff like this
    }
    elseif (time_has_expired) {
        doCleanup()
    }  
    else{
       doCharge()
    }
    endif
}

function start_new_instance(){
    // bind instance to some timer, or list, that runs periodically
}

}
.. responsibility would exist from outside, setting a stun-buff, stun-flag or stuff like this, to see that the unit is stunned. And also to apply a knockback.

It would be also possible to create instant reactions, or without usage of a buff applied or so, instead of "waiting" for next loop iteration(maybe not always relevant, though). Then the spell system itself needs to take usage of some overall spell-handler system. The user can from anywhere call a trigger from the overall spell-handler, to indicate for example "disable active spells", and then the handler-system internally runs a trigger "disable active spells trigger", and so all single spell systems that were registered to that trigger now get to know that a unit got this state, and can make changes. For example it could run for damaged units, that were hit by the Beetle charge.

Do you use vJASS in vanilla editor (since new patch allows it). structs, or possibly interface could make life easier. Not needed if you don't want, but in case, there are some spell systems that tried to generalize such things, or tried to ease usage.
 
Level 12
Joined
May 22, 2015
Messages
1,051
Thanks. Ya this is what I was sort of thinking. I'm not using vJASS. I learned JASS by itself in plain editor before the recent patch so I still use that.

The cleanup and other functions would be different for each ability, though. The beetle charge is just one example (and the first one I will implement). I figured then the periodic_check() function would do the exact same thing except fire specific triggers (it would have to loop over a list) for whatever the ability happens to be.

So instead it will be a bit more like this:
JASS:
function periodic_check(){
    local integer i = 0
    loop
        if (unit_has_stun_buff) {
            call TriggerEvaluate(udg_abilityInterrupt[i])
            // Possibly also use cleanup here.
        }
        elseif (time_has_expired) {
            call TriggerEvaluate(udg_abilityCleanup[i])
            // Then call some function that removes this ability from the list.
        }  
        else{
            call TriggerEvaluate(udg_abilityStep[i])
        }
        endif

        set i = i + 1
        exitwhen i == udg_activeAbilities
    endloop
}

function start_new_instance(unit u, trigger step, trigger cleanup, trigger interrupt){
    set udg_abilityUnit[udg_activeAbilities] = u
    set udg_abilityStep[udg_activeAbilities] = step
    set udg_abilityCleanup[udg_activeAbilities] = cleanup
    set udg_abilityInterrupt[udg_activeAbilities] = interrupt

    set udg_activeAbilities = udg_activeAbilities + 1
}
 
Ah, I see. Yes, such system would be helpful, in a sense that it reduces repetetive need for specific spells writing loop and finish checks. Some people thought to bundle as much generic stuff together, that might be used by most spells, and create a Spell System out of it. Example:
It can make writing spells some shorter, and provide relevant info when firing triggers. What features the system provides, or what makes sense to let specific spells let handle them, is maybe just preference, from some point on.

I would not really debate with performance difference, but if you see sense writing such system can combine general logics for many spells, and speed up spell making, you for sure should give it a try. :)
 
Status
Not open for further replies.
Top