• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • 🏆 Hive's 6th HD Modeling Contest: Mechanical is now open! Design and model a mechanical creature, mechanized animal, a futuristic robotic being, or anything else your imagination can tinker with! 📅 Submissions close on June 30, 2024. Don't miss this opportunity to let your creativity shine! Enter now and show us your mechanical masterpiece! 🔗 Click here to enter!

[JASS] vJass is lagging

Status
Not open for further replies.
Level 3
Joined
May 26, 2009
Messages
34
Hi all,
I'm beginning with vJass, and wanted to make my first spells, but my result was, that my vJass triggers lagged extremely. Here is it in vJass:

JASS:
scope Gravity initializer Gravity

struct variables
//constants
    real grav = 4
    real duration = 50 
    real interval = 0.03
    integer ab = 'A001'
    real range = 500
//others
    unit caster
    real time = 0
endstruct

private function TriggerCond takes nothing returns boolean
return GetSpellAbilityId() == 'A001'
endfunction

private function Destroy takes timer t returns nothing
local variables dat = LoadIntegerBJ(2 , GetHandleIdBJ(t), structs)
    call dat.destroy()
    call FlushChildHashtableBJ(GetHandleIdBJ(t), structs)
    call DestroyTimer(t)
endfunction

private function TimerCallback takes nothing returns nothing
local timer t = GetExpiredTimer()
local location array p
local group g
local real facing
local variables dat = LoadIntegerBJ(2 , GetHandleIdBJ(t), structs)
    set p[1] = GetUnitLoc(dat.caster)  
    set g = GetUnitsInRangeOfLocAll(dat.range, p[1])
    loop
    exitwhen FirstOfGroup(g) == null
        if IsUnitEnemy(FirstOfGroup(g), GetOwningPlayer(dat.caster)) == true and IsUnitDeadBJ(FirstOfGroup(g)) != true and IsUnitType(FirstOfGroup(g), UNIT_TYPE_STRUCTURE) != true  then
            set p[3] = GetUnitLoc(FirstOfGroup(g))
            set facing = AngleBetweenPoints(p[3], p[1])
            if DistanceBetweenPoints(p[1], p[3]) > 80 then
            set p[2] = PolarProjectionBJ(p[3], dat.grav, facing+80)
            call SetUnitPositionLoc(FirstOfGroup(g), p[2])
            call RemoveLocation(p[2])
            set p[2] = null
            call RemoveLocation(p[3])
            set p[3] = null
            endif

        endif
        call GroupRemoveUnit(g, FirstOfGroup(g))
    endloop
    
    call RemoveLocation(p[1])
    set p[1] = null
    call DestroyGroup(g)
    set g = null
    set dat.time = dat.time + dat.interval
    
    if dat.time >= GetUnitAbilityLevel(dat.caster, 'A001') * dat.duration or IsUnitDeadBJ(dat.caster) == true  then
        call PauseTimer(t)
        call Destroy(t)
    endif
    
endfunction

private function Actions takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local timer t = CreateTimer()
local variables dat = variables.create()
    set dat.caster = caster
    call SaveTimerHandleBJ(t, 1, GetHandleIdBJ(t), structs)
    call SaveIntegerBJ(dat, 2, GetHandleIdBJ(t), structs)
    call TimerStart(t, dat.interval, true, function TimerCallback)
endfunction

//===========================================================================
private function Gravity takes nothing returns nothing
    local trigger t = CreateTrigger(  )
    call TriggerAddCondition ( t , Condition(function TriggerCond))
    call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddAction( t, function Actions )
endfunction

endscope

and now in GUI

  • Gravity1
    • Ereignisse
      • Einheit - A unit Beginnt, eine Fähigkeit zu wirken
    • Bedingungen
      • (Ability being cast) Gleich Gravity
    • Aktionen
      • Custom script: local unit u = GetSpellAbilityUnit()
      • Custom script: call SaveRealBJ(7, 1, GetHandleId(u), structs)
      • Custom script: call SaveUnitHandleBJ(u, 0, GetHandleId(u), structs)
      • Wait 50.00 seconds
      • Custom script: call FlushChildHashtable(structs, GetHandleId(u))


  • Gravity2
    • Ereignisse
      • Zeit - Every 0.03 seconds of game time
    • Bedingungen
    • Aktionen
      • Set temp_group[1] = (Units in (Playable map area))
      • Einheitengruppe - Pick every unit in temp_group[1] and do (Actions)
        • Schleifen - Aktionen
          • Custom script: if LoadUnitHandleBJ(0, GetHandleId(GetEnumUnit()), structs) != null then
          • Set temp_point[1] = (Position of (Picked unit))
          • Set temp_group[2] = (Units within 500.00 of temp_point[1] matching ((((Matching unit) is dead) Ungleich True) and (((Owner of (Matching unit)) is an enemy of (Owner of (Picked unit))) Gleich True)))
          • Einheitengruppe - Pick every unit in temp_group[2] and do (Actions)
            • Schleifen - Aktionen
              • Set temp_point[2] = (Position of (Picked unit))
              • Set temp_point[3] = (temp_point[2] offset by 4.00 towards ((Angle from temp_point[2] to temp_point[1]) + 80.00) degrees)
              • Custom script: call RemoveLocation(udg_temp_point[2])
              • Custom script: call SetUnitX(GetEnumUnit(), GetLocationX(udg_temp_point[3]))
              • Custom script: call SetUnitY(GetEnumUnit(), GetLocationY(udg_temp_point[3]))
              • Custom script: call RemoveLocation(udg_temp_point[3])
          • Custom script: call DestroyGroup(udg_temp_group[2])
          • Custom script: call RemoveLocation(udg_temp_point[1])
          • Custom script: endif
      • Custom script: call DestroyGroup(udg_temp_group[1])

Why is the vJass trigger lagging with 20 units near to the casting unit and the GUI triggers not??

//EDIT: Oh yeah, of course +rep for helpers ;)
 
Last edited:
There's a lot of optimisation to be done here, but I couldn't see anything that just said LAG. I went through and optimised it a lot (and commented the code to show what I did). Tell me if this fixes it:

JASS:
scope Gravity initializer Gravity

    struct variables
    //constants
    // if they're constants, make them constant :P
        static constant real grav = 4
        static constant real duration = 50 
        static constant real interval = 0.03
        static constant integer ab = 'A001'
        static constant real range = 500
    //others
        unit caster
        real time = 0
    endstruct

    private function TriggerCond takes nothing returns boolean
        return GetSpellAbilityId() == variables.ab 
        // why have these constants if you don't use them?
    endfunction

    private function Destroy takes timer t returns nothing
        local variables dat = LoadInteger(2 , GetHandleId(t), structs)
        // BJ = bad, find a function to replace it. In the case of hashtable functions,
        // you can just remove the "BJ"
        call dat.destroy()
        call FlushChildHashtable(GetHandleId(t), structs)
        call DestroyTimer(t)
    endfunction

    private function TimerCallback takes nothing returns nothing
        local timer t = GetExpiredTimer()
        local real array x // use x/y, not locations!
        local real array y
        local group g = CreateGroup()
        local unit u
        local real facing
        local variables dat = LoadInteger(2 , GetHandleId(t), structs)
        set x[0] = GetUnitX(dat.caster) // arrays start with 0, not 1
        set y[0] = GetUnitY(dat.caster) // this is how to get unit x/y
        call GroupEnumUnitsInRange(g, x[0], y[0], dat.range, null) 
        // this is a better alternative to GetUnitsInRangeOfLocAll
        loop
            set u = FirstOfGroup(g)
            // if we hold FirstOfGroup in a variable, it saves lots of function calls!
            exitwhen u == null
                                                                        // checking the unit's life directly to avoid BJ
            if IsUnitEnemy(FirstOfGroup(g), GetOwningPlayer(dat.caster)) == true and GetWidgetLife(dat.caster) > 0. and not IsUnitType(u, UNIT_TYPE_STRUCTURE) then
                set x[2] = GetUnitX(u)
                set y[2] = GetUnitY(u)
                set facing = Atan2(y[0] - y[2], x[0] - x[2])
                // this does the same as the function, but uses x/y instead of locations
                set x[3] = x[2] - x[0]
                set y[3] = y[2] - y[0]
                if x[3] * x[3] + y[3] * y[3] > 80. * 80. then
                // again, replaces the function
                    set x[1] = x[2] + dat.grav * Cos(facing + 80. * bj_DEGTORAD)
                    set y[1] = y[2] + dat.grav * Sin(facing + 80. * bj_DEGTORAD)
                    // replacing the function again...
                    call SetUnitPosition(u, x[1], y[1])
                endif

            endif
            
            call GroupRemoveUnit(g, u)
        endloop
        
        call DestroyGroup(g)
        set g = null
        set u = null
        
        set dat.time = dat.time + dat.interval
        if dat.time >= GetUnitAbilityLevel(dat.caster, 'A001') * dat.duration or GetWidgetLife(dat.caster) <= 0.  then
            call PauseTimer(t)
            call Destroy(t)
        endif
        
    endfunction

    private function Actions takes nothing returns nothing
        local unit caster = GetSpellAbilityUnit()
        local timer t = CreateTimer()
        local variables dat = variables.create()
        set dat.caster = caster
        call SaveTimerHandle(t, 1, GetHandleId(t), structs)
        call SaveInteger(dat, 2, GetHandleId(t), structs)
        call TimerStart(t, dat.interval, true, function TimerCallback)
    endfunction

    //===========================================================================
    private function Gravity takes nothing returns nothing
        local trigger t = CreateTrigger(  )
        call TriggerAddCondition ( t , Condition(function TriggerCond))
        // this BJ doesn't need to be avoided because it only runs once, doesn't affect speed
        call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
        call TriggerAddAction( t, function Actions )
    endfunction

endscope
 
Level 12
Joined
Apr 15, 2008
Messages
1,063
You still left one extra FirstOfGroup(g) in the consition (IsUnitEnemy) and you used SetUnitPosition instead of SetUnitX/Y.
Also, instead of using Atan2+Sin/Cos, you could use rotation matrix to rotate the coordinates. Since you use constant angle, that would save a lot of time.
JASS:
set x[1] = 0.173*x[2] - 0.984*y[2]
set y[1] = 0.173*y[2] + 0.984*x[2]
(0.173 is Cos(80) and 0.984 is Sin(80))
 
Level 3
Joined
May 26, 2009
Messages
34
So first thanks for your tips :)
I thought, that i have to load the structs in each function to use them, so now i'm a bit confused.....
then suddenly my triggers stop, when I use the function: "call Save/LoadHandle/Integer"
I don't know why, but I tested with messages, and the trigger stops always at this function...
But not only in this trigger, also in my second spell....

JASS:
//------------------------------------------------------------------------------------
//                  Firecircle                                                       |
//                  MADE BY                                                          |
//                  Da-Andy                                                          |
//------------------------------------------------------------------------------------
scope Firecircle initializer Init

globals
    private constant real timerspeed = 0.03 
    private constant real max_dist = 150
    private constant real min_dist = 0
    private constant real rot_speed = 20
    private constant real max_height = 200
    private constant integer shots = 30 
    private constant real duration = 50  //*level of ability
    private constant integer ab = 'A000'
    timer tt
endglobals

struct firedata
    unit array dummy [shots]  
    real array facing [shots] 
    real age = 0
    real distance = GetRandomReal(min_dist, max_dist)
    effect array dummy_e [shots]
    real height
    unit caster
endstruct



private function TriggerCond takes nothing returns boolean
return GetSpellAbilityId() == ab
endfunction

private function Destroy takes timer t returns nothing
local firedata dat = LoadInteger(structs , GetHandleId(t), 2)
    call dat.destroy()
    call FlushChildHashtable(structs, GetHandleId(t))
    call DestroyTimer(t)
endfunction

private function GroupCallback takes nothing returns nothing
local timer t = tt
local firedata dat = LoadInteger(structs, GetHandleId(t), 2)
      if IsUnitEnemy(GetEnumUnit(), GetOwningPlayer(dat.caster)) == true and GetUnitState(dat.caster, UNIT_STATE_LIFE ) >= 1 then
          call UnitDamageTarget(dat.caster, GetEnumUnit(), 100*GetUnitAbilityLevel(dat.caster, ab), true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS)
      endif
endfunction

private function TimerCallback takes nothing returns nothing
local timer t = GetExpiredTimer()
local integer i = 0
local real array x
local real array y
local group g = CreateGroup()
local firedata dat = LoadInteger(structs , GetHandleId(t), 2)
    set x[0] = GetUnitX(dat.caster)
    set y[0] = GetUnitY(dat.caster)
        if dat.height < 30 then
            set dat.distance = min_dist
            set dat.height = max_height
        endif
        set dat.height = dat.height - ((max_height-30)/(360/rot_speed))
        set dat.distance = dat.distance + ((max_dist-min_dist)/(360/rot_speed))
    loop
        set i = i + 1
        set dat.facing[i] = dat.facing[i] + rot_speed
        call SetUnitFlyHeight(dat.dummy[i], dat.height, 0.00)
        if dat.facing[i] > 360 then
            set dat.facing[i] = 0
        endif
        set x[1] = x[0] + dat.distance*Cos(dat.facing[i])
        set y[1] = y[0] + dat.distance*Sin(dat.facing[i])
        call SetUnitX(dat.dummy[i], x[1])
        call SetUnitY(dat.dummy[i], y[1])
        call GroupEnumUnitsInRange(g, x[1], y[1], 100, null)
        set tt = t
        call ForGroup(g, function GroupCallback)
        call DestroyGroup(g)
        set g = null
    exitwhen i == shots
    endloop
    set dat.age = dat.age + timerspeed
    
      if dat.age >= GetUnitAbilityLevel(dat.caster, ab) * duration or GetUnitState(dat.caster, UNIT_STATE_LIFE ) <= 0  then
          set i = 0
          loop
            set i = i + 1
            call DestroyEffect(dat.dummy_e[i])
            call RemoveUnit(dat.dummy[i])
        exitwhen i == shots
        call PauseTimer(t)
        call Destroy(t)
        endloop
    endif
endfunction

private function Actions takes nothing returns nothing
local real array x
local real array y
local unit caster = GetSpellAbilityUnit()
local integer i = 0
local timer t = CreateTimer()
local firedata dat = firedata.create()
    call SaveTimerHandle(structs, GetHandleId(t), 1, t)
    call SaveInteger(structs, GetHandleId(t), 2, dat)
    set dat.caster = caster
    set x[0] = GetUnitX(caster)
    set y[0] = GetUnitY(caster)
    loop
        set i = i + 1
        set x[1] = x[0] + dat.distance*Cos(I2R(i*90))
        set y[1] = y[0] + dat.distance*Sin(I2R(i*90))
        set dat.dummy[i] = CreateUnit(GetOwningPlayer(caster),'h000', x[1], y[1], (i*(360/shots))+90) 
        call SetUnitFlyHeight(dat.dummy[i], 30, 0)
        set dat.facing[i] = i*(360/shots)
        set dat.dummy_e [i] = AddSpecialEffectTarget("Abilities\\Weapons\\PhoenixMissile\\Phoenix_Missile_mini.mdl", dat.dummy[i], "chest")
        call SetUnitPathing(dat.dummy[i], false)
        exitwhen i == shots
    endloop
    call TimerStart(t, timerspeed, true, function TimerCallback)
endfunction

//===========================================================================
private function Init takes nothing returns nothing
    local trigger t = CreateTrigger(  )
    call TriggerAddAction( t, function Actions )
    call TriggerAddCondition ( t , Condition(function TriggerCond))
    call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
endfunction

endscope

Maybe it's because of my init trig?

JASS:
scope INIT initializer INIT

globals
    hashtable structs
endglobals

private function PathingCallback takes nothing returns nothing
    call SetUnitPathing(GetEnumUnit(), false)
endfunction

private function Actions takes nothing returns nothing
local group g = CreateGroup()
    call GroupEnumUnitsInRect(g, bj_mapInitialPlayableArea, null)
    call ForGroup(g, function PathingCallback)
    call DestroyGroup(g)
    set g = null    
    
    set structs = InitHashtable( )
endfunction

//===========================================================================
function INIT takes nothing returns nothing
    local trigger t = CreateTrigger(  )
    call TriggerAddAction( t, function Actions )
    call TriggerRegisterTimerEvent(t, 0.01, false)
endfunction

endscope

//EDIT: Found the misstake...
I made the init trigger to run after 0.01 secs, and then everything worked really good :)
Replaced the 2 triggers with the new ones :D
thanks for help + rep to both of you
But could you explain to me, when I can use these structs, thats the thing I don't understand....
 
Last edited:
Status
Not open for further replies.
Top