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

trigger stops , too long?

Status
Not open for further replies.
Level 4
Joined
Jan 20, 2011
Messages
65
hello

i am working on a little map where i made a movement and collision system

sadly i have a really annoying bug which i cant seem to solve

im useing a quadtree system to determine round collisions
but the trigger stops anywhere during the execution when there are more units on the map
the only thing which changes is really the lenght of the executed code
since i remember reading somewhere ages ago, that triggers have a limit of how many lines it may execute at once, i wanted to ask if this really exists

is there a limit of lines a trigger can execute?
and if, any solutions?


some info:
- im useing the periodic time event
- everything is in jass
- if needed i can post the code too

mfg alfalfa
 
Level 4
Joined
Jan 20, 2011
Messages
65
ohhh ok thank you so much!!

is it something like only 5000 lines of code per minute?
or is it something like only 5000 lines of code after one event?
 
Level 17
Joined
Apr 27, 2008
Messages
2,455
No it's more how many jass code "executed" in a thread.
You can open a new thread with TriggerExecute/Evaluate (.execute/.evaluate of vJass), ExecuteFunc, ForForce and in general each native jass function which has a code or boolexpr argument.

Though, the jass is not multi-threaded, if you open a new thread it will halt the previous one. (works like a normal call but resets the limit op and is less efficient)

ForForce is the most efficient, but TriggerEvaluate is quite closed, so vJass function interfaces with .evaluate are good enough.
There are also plenty of timer systems.

A good way to figure how much code you can run is displaying a text message at the end of the thread, if it displays you can add more code, if not you must decrease it (ofc for this test you can use a not periodic timer, it will work as intented).
 
Level 4
Joined
Jan 20, 2011
Messages
65
oh ok, so if i allways use ExecuteTrigger to call the QuadTree function, maybe give parameters useing globals then, will it work?
edit: or just ExecuteFunc?


here the code, udg_QuadTreeUnitGroupParameter[i2] is a global unit array
it basically splits the given unit group into smaller ones dependant on their position, then either splits it again or processes the group
JASS:
function QuadTree takes real MaxX, real MinX, real MaxY, real MinY returns nothing
local unit fog
local unit array tempg1
local unit array tempg2
local unit array tempg3
local unit array tempg4
local integer count1 = 0
local integer count2 = 0
local integer count3 = 0
local integer count4 = 0
local boolean bool1 = false
local boolean bool2 = false
local boolean bool3 = false
local boolean bool4 = false
local integer i = 100 // 170/2 == maximum used unit collision size / 2 // downstairs it needs to be changed too if this is changed
local integer i2 = 0
local integer unituserdata
local real SubMiddleX = MinX + (MaxX - MinX) * 0.5 - i
local real SubMiddleY = MinY + (MaxY - MinY) * 0.5 - i
local real AddMiddleX = MinX + (MaxX - MinX) * 0.5 + i
local real AddMiddleY = MinY + (MaxY - MinY) * 0.5 + i
local real unitx
local real unity
loop
exitwhen udg_QuadTreeUnitGroupParameter[i2] == null
        set fog = udg_QuadTreeUnitGroupParameter[i2]
        set unituserdata = GetUnitUserData(fog)
        set unitx = GetUnitX(fog)
        set unity = GetUnitY(fog)
        if( unitx > MinX and unitx < AddMiddleX ) then
            if( unity > MinY and unity < AddMiddleY ) then
                if( not(bool1) and not(udg_StaticObject[unituserdata]) ) then
                    set bool1 = true
                endif
                set tempg1[count1] = fog
                set count1 = count1 + 1
            endif
            if( unity < MaxY and unity > SubMiddleY ) then
                if( not(bool2) and not(udg_StaticObject[unituserdata]) ) then
                    set bool2 = true
                endif
                set tempg2[count2] = fog
                set count2 = count2 + 1
            endif
        endif
        if( unitx < MaxX and unitx > SubMiddleX ) then
            if( unity > MinY and unity < AddMiddleY ) then
                if( not(bool3) and not(udg_StaticObject[unituserdata]) ) then
                    set bool3 = true
                endif
                set tempg3[count3] = fog
                set count3 = count3 + 1
            endif
            if( unity < MaxY and unity > SubMiddleY ) then
                if( not(bool4) and not(udg_StaticObject[unituserdata]) ) then
                    set bool4 = true
                endif
                set tempg4[count4] = fog
                set count4 = count4 + 1
            endif
        endif
set i2=i2+1
endloop
set fog = null

set tempg1[count1] = null
set tempg2[count2] = null
set tempg3[count3] = null
set tempg4[count4] = null

set i = 500 //170 // *2
set i2 = 0
if( bool1 ) then
  //call ClearQuadTreeUnitGroupParameter()
  set i2 = 0
  loop
    set udg_QuadTreeUnitGroupParameter[i2] = tempg1[i2]
    exitwhen tempg1[i2] == null
    set tempg1[i2] = null
    set i2=i2+1
  endloop
  if( count1 > 20 and AddMiddleX-MinX > i and AddMiddleY-MinY > i ) then
    call QuadTree(AddMiddleX,MinX, AddMiddleY,MinY)
  else
    call ProcessQuadTreeGroup()
  endif
else
  loop
    exitwhen tempg1[i2] == null
    set tempg1[i2] = null
    set i2=i2+1
  endloop
endif
set i2 = 0
if( bool2 ) then
  //call ClearQuadTreeUnitGroupParameter()
  loop
    set udg_QuadTreeUnitGroupParameter[i2] = tempg2[i2]
    exitwhen tempg2[i2] == null
    set tempg2[i2] = null
    set i2=i2+1
  endloop
  if( count2 > 20 and AddMiddleX-MinX > i and MaxY-SubMiddleY > i ) then
    call QuadTree(AddMiddleX,MinX, MaxY,SubMiddleY)
  else
    call ProcessQuadTreeGroup()
  endif
else
  loop
    exitwhen tempg2[i2] == null
    set tempg2[i2] = null
    set i2=i2+1
  endloop
endif
set i2 = 0
if( bool3 ) then
  //call ClearQuadTreeUnitGroupParameter()
  set i2 = 0
  loop
    set udg_QuadTreeUnitGroupParameter[i2] = tempg3[i2]
    exitwhen tempg3[i2] == null
    set tempg3[i2] = null
    set i2=i2+1
  endloop
  if( count3 > 20 and MaxX-SubMiddleX > i and AddMiddleY-MinY > i ) then
    call QuadTree(MaxX,SubMiddleX, AddMiddleY,MinY)
  else
    call ProcessQuadTreeGroup()
  endif
else
  loop
    exitwhen tempg3[i2] == null
    set tempg3[i2] = null
    set i2=i2+1
  endloop
endif
set i2 = 0
if( bool4 ) then
  //call ClearQuadTreeUnitGroupParameter()
  set i2 = 0
  loop
    set udg_QuadTreeUnitGroupParameter[i2] = tempg4[i2]
    exitwhen tempg4[i2] == null
    set tempg4[i2] = null
    set i2=i2+1
  endloop
  if( count4 > 20 and MaxX-SubMiddleX > i and MaxY-SubMiddleY > i ) then
    call QuadTree(MaxX,SubMiddleX, MaxY,SubMiddleY)
  else
    call ProcessQuadTreeGroup()
  endif
else
  loop
    exitwhen tempg4[i2] == null
    set tempg4[i2] = null
    set i2=i2+1
  endloop
endif

// fog alleady set to null upstairs
endfunction
 
Level 17
Joined
Apr 27, 2008
Messages
2,455
I prefer ForForce(bj_FORCE_PLAYER[0], code), than either ExecuteFunc/
TriggerExecute/Evaluate. I'd like to run some benchmarks to see which
is faster.

From an old test (really not perfect but good enough to know the most efficient way)

JASS:
library TestExecuteCode initializer init



globals // keep unit variables as short as possible because else it will run the code slower (yes it's a known thing of the jass virtual machine)

    unit U

    force F

endglobals



function interface Func takes nothing returns nothing



function gogo takes nothing returns nothing // boolean

    call SetUnitX(U,0)

    call SetUnitY(U,0)

    

    // return false

endfunction



private function Action takes nothing returns nothing

    local integer i=0

    local string s

    local code c

    local boolexpr b

    local Func f // just an integer in jass

    

    loop

    exitwhen i == 500

    set i = i+1

        

    /*  

        set s = "gogo"

        call ExecuteFunc(s)


    */

    

    

    /*

        set c = function gogo

        call ForForce(F,c)


    */

    

    

    /*

        set f = Func.gogo

        call f.evaluate()  // or you could just do         call gogo.evaluate()

    */

    



    /*

        set f = Func.gogo

        call f.execute()  // or you could just do         call gogo.execute()

    */

    

    

    /*

        // just note that you can use also Condition(), Filter() is just the same but slightly faster to write ...

        // also boolexpr created with Condition() and Filter() are specials, they are created if it's not already done

        // and next time it gives the pointer to it

        // ex : Condition(function haha) == Condition(function haha), if you use it in several trigger conditions and then call DestroyBoolExpr(Condition(function haha))

        // all your already created conditions will be fucked

        // but care And() and Or() creates a new boolexpr each time they are called, but these functions can be used for advanced stuff

        

        set c = function gogo

        call ForceEnumPlayers(F,Filter(c)) // have to edit the function gogo to returns a false boolean

        set c = null

    */        

    

    endloop

endfunction



private function init takes nothing returns nothing

    local trigger trig = CreateTrigger()

    call TriggerAddAction(trig,function Action)

    set U = CreateUnit(GetLocalPlayer(),'hpea',0,0,0)

    set F = CreateForce()

    call ForceAddPlayer(F,GetLocalPlayer())

    call PanCameraTo(0,0)

    call TriggerSleepAction(3.)

    call BJDebugMsg("gogo")

    call TriggerRegisterTimerEvent(trig,0.01,true)

endfunction



endlibrary

ExecuteFunc -> 16 fps

ForForce -> 47 fps

evaluate -> 40 fps

ForceEnumPlayers -> 44 fps

execute -> 16 fps

But the problem using ForForce is that you have to handle the function position in the map script (probably not a problem with vJass though).
A better test should be done (with cJass or so) but for now i would still choice TriggerEvaluate.

Also i think there is a problem using ForForce but can't remember right now.

EDIT : But forget ForceEnumPlayers, it will obviously fire for each (human ?) player in the map, like GroumEnum... with units.
 
The only problem with ForForce is that if you have more than one player in the force, and nest a ForForce call from within the ForForce call, then the first callback code pointer will be overwritten by the second.

However, in this case you will only have one player in ForForce, so it's better to do it this way.

I don't know why you'd think TriggerExecute would be better here, you have to handle a boolexpr, a trigger and a function that returns false, instead of a function that returns nothing.

The only time I'd use evaluations is with dynamic function callbacks, in which case I'd use ForceEnumPlayersCounted to evaluate the boolexpr.
 
Level 17
Joined
Apr 27, 2008
Messages
2,455
The only problem with ForForce is that if you have more than one player in the force, and nest a ForForce call from within the ForForce call, then the first callback code pointer will be overwritten by the second.

However, in this case you will only have one player in ForForce, so it's better to do it this way.

I don't know why you'd think TriggerExecute would be better here, you have to handle a boolexpr, a trigger and a function that returns false, instead of a function that returns nothing.

The only time I'd use evaluations is with dynamic function callbacks, in which case I'd use ForceEnumPlayersCounted to evaluate the boolexpr.

Well i think using a ForForce inside a ForForce will bug or something (i said that i can't remember what was wrong, maybe it was just me xD)

And i say use TriggerEvaluate because it seems to be closed to ForForce performance and it's easier to use for a jass preprocessor, it also keeps response events. (hey, maybe that was the thing ^^)
Hell, i suppose it could even be faster with an efficient script.

@Magtheridon, i don't why but jasshelper add each time an one line space between each line of code for log files (probably related to how jasshelper handles the input script), it was the generated inputwar3map.j file in the subfolder logs of the JNGP.
In the original script i didn't add so much empty lines myself, but i copied this script when i was on linux (no wc3 editor).
And removing useless empty lines was just to much work :p
 
Level 17
Joined
Apr 27, 2008
Messages
2,455
Well how often will you need the value of GetEnumPlayer/GetFilterPlayer from within evaluated code?

If you have a ForForce inside your "executed code", i personally don't use it so much but it's really used from people.
(Again it's just a vague memory, need to be tested)

TriggerExecute messes with the value of GetTriggeringTrigger ;)

Nothing is perfect, but it's the only one native, against all responses events in the case of ForForce, no deal.
Or that was i think at least, also need to be tested.
Plus this "flaw" is pretty obvious when you know what .evaluate() do in jass.
 
Status
Not open for further replies.
Top