1. Updated Resource Submission Rules: All model & skin resource submissions must now include an in-game screenshot. This is to help speed up the moderation process and to show how the model and/or texture looks like from the in-game camera.
    Dismiss Notice
  2. DID YOU KNOW - That you can unlock new rank icons by posting on the forums or winning contests? Click here to customize your rank or read our User Rank Policy to see a list of ranks that you can unlock. Have you won a contest and still havn't received your rank award? Then please contact the administration.
    Dismiss Notice
  3. The Lich King demands your service! We've reached the 19th edition of the Icon Contest. Come along and make some chilling servants for the one true king.
    Dismiss Notice
  4. The 4th SFX Contest has started. Be sure to participate and have a fun factor in it.
    Dismiss Notice
  5. The poll for the 21st Terraining Contest is LIVE. Be sure to check out the entries and vote for one.
    Dismiss Notice
  6. The results are out! Check them out.
    Dismiss Notice
  7. Don’t forget to sign up for the Hive Cup. There’s a 555 EUR prize pool. Sign up now!
    Dismiss Notice
  8. The Hive Workshop Cup contest results have been announced! See the maps that'll be featured in the Hive Workshop Cup tournament!
    Dismiss Notice
  9. Check out the Staff job openings thread.
    Dismiss Notice
Dismiss Notice
60,000 passwords have been reset on July 8, 2019. If you cannot login, read this.

Debugging: how-to log all trigger executions?

Discussion in 'World Editor Help Zone' started by Ricola3D, Sep 13, 2019.

  1. Ricola3D

    Ricola3D

    Joined:
    Feb 27, 2019
    Messages:
    227
    Resources:
    2
    Maps:
    1
    Spells:
    1
    Resources:
    2
    Hello,

    I am trying to debug a desync issue. For this I am already doing hooks on functions known for causing desync that write logs in a local file.

    However, I'd like to also log trigger executions. This way I may be able to know what last triggers execute before desync.

    Do you know how I can do that ?

    Would a hook on "TriggerExecute" and/or "TriggerEvaluate" catch all trigger executions ?


    Plus, from a hook with parameter "trigger whichTrigger", how could I get the trigger name ? I don't see any native to get the name of a trigger..

    Thanks in advance for your advices :)
     
  2. Pyrogasm

    Pyrogasm

    Joined:
    Feb 27, 2007
    Messages:
    3,149
    Resources:
    1
    Spells:
    1
    Resources:
    1
    No, a trigger actually triggered by its event doesn't use either execute or evaluate. You will have to log this information yourself manually by adding a couple extra lines to each trigger.
    You can't, there's no native for this. However, this is a case where GUI does something worthwhile that you can take advantage of. There is a "Name of the current trigger" string that is populated with the proper name of the trigger at compile time. For triggers that are already in GUI you can use this directly, but for JASS triggers you will have to name them yourself.
    • Actions
      • -------- put first in the trigger actions --------
      • Set TrigName = (Name of the current trigger)
      • Set ExecTime = (Elapsed time of GAMETIMECLOCK) //start a timer on map init for max duration and you can use it to timestamp your trigger executions, just a suggestion
      • Custom script: call DoWhateverToLogThisInfo(udg_TrigName, udg_ExecTime)

    Code (vJASS):
    call DoWhateverToLogThisInfo("your trigger name here", TimerGetElapsed(udg_GAMETIMECLOCK))
     
  3. Ricola3D

    Ricola3D

    Joined:
    Feb 27, 2019
    Messages:
    227
    Resources:
    2
    Maps:
    1
    Spells:
    1
    Resources:
    2
    Thanks, it is as I thought :(
     
  4. Dr Super Good

    Dr Super Good

    Spell Reviewer

    Joined:
    Jan 18, 2005
    Messages:
    25,611
    Resources:
    3
    Maps:
    1
    Spells:
    2
    Resources:
    3
    With maps using the Lua VM one can override all registration functions to apply some sort of logging. Issue is without the stack trace it is difficult to know what is being run.
     
  5. Ricola3D

    Ricola3D

    Joined:
    Feb 27, 2019
    Messages:
    227
    Resources:
    2
    Maps:
    1
    Spells:
    1
    Resources:
    2
    I am still stuck, I'd really need a way to Get current trigger name.

    Indeed I just discovered that one can hook the two following functions:
    - TriggerAddCondition
    - TriggerAddAction

    So it is quite easy to add a log action to every trigger in the map automatically (just be careful of avoiding infinite loop), like:

    Code (Text):
        public function TriggerLogAction takes nothing returns nothing
                call DisplayTimedTextToForce( GetPlayersAll(), 3.00, "Xxxxxxxxxxxxxxxxxxxx" )
        endfunction

        public function onTriggerAddAction takes trigger whichTrigger, code actionFunc returns nothing
            if ( actionFunc != function TriggerLogAction ) then
                call TriggerAddAction(whichTrigger, function TriggerLogAction)
            endif
        endfunction

        hook TriggerAddAction onTriggerAddAction
     
    However this is useless if I cannot log or write in file any information that identifies the trigger being executed...
     
    Last edited: Sep 23, 2019
  6. Dr Super Good

    Dr Super Good

    Spell Reviewer

    Joined:
    Jan 18, 2005
    Messages:
    25,611
    Resources:
    3
    Maps:
    1
    Spells:
    2
    Resources:
    3
    Triggers have no name.
    In general Lua the debug functions can be used for this. However all debug functions are disabled in Wacraft III as far as I am aware.
     
  7. Ricola3D

    Ricola3D

    Joined:
    Feb 27, 2019
    Messages:
    227
    Resources:
    2
    Maps:
    1
    Spells:
    1
    Resources:
    2
    Well actually anything that allows to identify the trigger/function can be usefull, not only trigger name.
    For example is there any info I can get from the HandleId ? In order for the developer to retrieve the source code corresponding to the handle ? ^^
     
  8. Tasyen

    Tasyen

    Joined:
    Jul 18, 2010
    Messages:
    1,356
    Resources:
    17
    Tools:
    2
    Maps:
    2
    Spells:
    8
    Tutorials:
    4
    JASS:
    1
    Resources:
    17
    if all triggers are created in gui or at map init their handleIds should be the same over multiple runs. You could get the handleId of the executing trigger using GetHandleId(GetTriggeringTrigger()).
     
  9. Pyrogasm

    Pyrogasm

    Joined:
    Feb 27, 2007
    Messages:
    3,149
    Resources:
    1
    Spells:
    1
    Resources:
    1
    Unfortunately this is not true. Here's a sample of the generated main() function from a custom map in my folder:
    Code (vJASS):
    function main takes nothing returns nothing
        call SetCameraBounds(- 3328.0 + GetCameraMargin(CAMERA_MARGIN_LEFT), - 3584.0 + GetCameraMargin(CAMERA_MARGIN_BOTTOM), 3328.0 - GetCameraMargin(CAMERA_MARGIN_RIGHT), 3072.0 - GetCameraMargin(CAMERA_MARGIN_TOP), - 3328.0 + GetCameraMargin(CAMERA_MARGIN_LEFT), 3072.0 - GetCameraMargin(CAMERA_MARGIN_TOP), 3328.0 - GetCameraMargin(CAMERA_MARGIN_RIGHT), - 3584.0 + GetCameraMargin(CAMERA_MARGIN_BOTTOM))
        call SetDayNightModels("Environment\\DNC\\DNCLordaeron\\DNCLordaeronTerrain\\DNCLordaeronTerrain.mdl", "Environment\\DNC\\DNCLordaeron\\DNCLordaeronUnit\\DNCLordaeronUnit.mdl")
        call NewSoundEnvironment("Default")
        call SetAmbientDaySound("LordaeronSummerDay")
        call SetAmbientNightSound("LordaeronSummerNight")
        call SetMapMusic("Music", true, 0)

        //regions and units are created here
        call CreateRegions()
        call CreateAllUnits()
        call InitBlizzard()

    // Initalizers happen here
    call ExecuteFunc("jasshelper__initstructs88292093")
    call ExecuteFunc("DamagedEventAdder__init")
    call ExecuteFunc("othertestes__init")

    // Globals happen here
        call InitGlobals()

    // ==== TRIGGERS CREATED HERE
        call InitCustomTriggers()
    // ==== TRIGGERS CREATED HERE

        call RunInitializationTriggers()

    endfunction

    So any changes to the replaced units, preplaced regions, or any scope/library/module initializers that allocate handles will change the assigned handle ID for the triggers. Also any globals like groups and timers that default to an allocated handle simply existing will change the handle id.
     
  10. Ricola3D

    Ricola3D

    Joined:
    Feb 27, 2019
    Messages:
    227
    Resources:
    2
    Maps:
    1
    Spells:
    1
    Resources:
    2
    Are function & variable names also lost in the last steps of compilation ? Where the .j becomes a binary files. Private & public ones ?
    Is there any JASS type that we can dump ? :)

    Mhh...

    At first, I could hook the following functions:

    - TriggerRegisterXXXXXXEventXXXX
    - TriggerAddCondition
    - TriggerAddAction
    Then save in a hashtable, with the trigger handle id as key, the events count & types, conditions count & actions count. Log them when the trigger is first executed.

    - TriggerExecute
    - TriggerEvaluate
    And log that the trigger has been manually called.

    - TriggerAddCondition
    - TriggerAddAction
    And add a "log" action to the trigger that would display "Trigger <handleid> executed".

    However this is still very tough for the developper to retrieve the matching trigger...
     
  11. Dr Super Good

    Dr Super Good

    Spell Reviewer

    Joined:
    Jan 18, 2005
    Messages:
    25,611
    Resources:
    3
    Maps:
    1
    Spells:
    2
    Resources:
    3
    I just thought of a possible solution.

    One can iterate through the Lua main name space node and resolve all the functions in key (function name) value (function value) pairs. These values will be the same as the ones that get passed to the trigger and timer registration functions and hence one can perform an inverse map lookup to get the associated function name from the function value at the time the registration proxy function is called. This function name can then be mapped to the trigger or timer value and so from the trigger or timer value, which one can get from threads the trigger or timer spawns, one can get the associated function names that were registered to it and print or log these.
     
  12. Ricola3D

    Ricola3D

    Joined:
    Feb 27, 2019
    Messages:
    227
    Resources:
    2
    Maps:
    1
    Spells:
    1
    Resources:
    2
    The concept looks nice ! However I don't know LUA yet. It is a script language that compiles to JASS right isn't ?
    So what you say here only applies to maps fully made in LUA ?
     
  13. Dr Super Good

    Dr Super Good

    Spell Reviewer

    Joined:
    Jan 18, 2005
    Messages:
    25,611
    Resources:
    3
    Maps:
    1
    Spells:
    2
    Resources:
    3
    No it is an alternative virtual machine for Warcraft III to use. WC3 can either run a map with the JASS virtual machine or with the Lua virtual machine. These need the script to be completely in the appropriate language.
    Yes everything discussed here only applies to maps using the Lua virtual machine.
     
  14. Ceday

    Ceday

    Joined:
    Feb 22, 2010
    Messages:
    1,092
    Resources:
    0
    Resources:
    0
    I think what Tasyen wanted to say is handle id of the triggers with respect to each other will always be same, if you create another object within the map that might change the starting offset but distance between handle id of any two triggers will remain same.
     
  15. Pyrogasm

    Pyrogasm

    Joined:
    Feb 27, 2007
    Messages:
    3,149
    Resources:
    1
    Spells:
    1
    Resources:
    1
    Yeah that’s reasonable and probably true.

    Variable names are not available in any way either. DSG’s suggestion requires the whole map script to be Lua (no JASS whatsoever), so if you can’t/won’t transpile all existing code then your only option is to provide each trigger/timer with a string variable identifying the function name or handle name associated with the action. You can save these in a hashtable with the associated handle’s ID as a key, then retrieve it and print it whenever appropriate.

    With some textmacroes, automatically printing this information could be relatively simple. You could wrap TriggerAddAction and TriggerAddCondition to also add an additional action/condition function first that prints the trigger name (and checks to see if this action/condition has already been added to the trigger and if so skips adding it multiple times).
     
  16. Pyrogasm

    Pyrogasm

    Joined:
    Feb 27, 2007
    Messages:
    3,149
    Resources:
    1
    Spells:
    1
    Resources:
    1
    Here, I felt that this would be a fun project so I made something relatively simple that can show trigger evaluation/execution info:
    Code (vJASS):

    library Monitor initializer init
      //==========================================================================================
      //    Monitor - v1.0 - 9/24/19
      //       by Pyrogasm
      //
      // Have you wondered what the last trigger run before an error was? Did you wish you could
      // see a printout of what ran when and how many times? Have you always wanted to name your
      // triggers? Well... sometimes I have, but mostly Ricola3D has so I made this for them. If
      // this interests you or sounds like it might help, you should use this system to aid in
      // your debugging quest.
      //
      // It requires one small change on your part:
      // For any trigger you wish to register with Monitor, you must replace all calls to
      //       CreateTrigger()
      // with
      //       Monitor_CreateTrigger("your trigger name here")
      // which still returns the created trigger as the vanilla function does.
      //
      // The system automatically detects when you call TriggerAddCondition and TriggerAddAction
      // and assigns its own TC/TA first before the first time you use them on a trigger so that
      // its functions are called right before any of the trigger's real TCs and TAs. It requires
      // no further input from you.
      //
      // Data is automatically cleaned when using DestroyTrigger, TriggerClearActions, and
      // TriggerClearConditions, no input required.
      //
      // Monitor can output the following information immediately before that trigger's
      // Conditions or Actions are evaluated/executed:
      //  - Name of the trigger
      //  - Execution count of the conditions/actions since the trigger was created
      //  - Timestamp (in seconds since map init) at which the conditions/actions were run
      //
      // Monitor features two further functions you may find useful in your debugging quest:
      //  - Monitor_GetTriggerName(triggerVariable)
      //  - Monitor_DumpLast(triggerVariable)
      //    This prints the most recently stored information about execution count & timestamp
      //
      // If you have further questions, contact me directly by PM at hiveworkshop.com
      // Anyone is free to use all or part of this resource for any reason, all I ask
      // is that you credit me with the original code.
      //
      //==========================================================================================


      globals
        //These globals enable/disable tracking & printing of various parts of the system (compiletime static ifs)
        private constant boolean DO_CONDITIONS = true
        private constant boolean DO_ACTIONS    = true
        private constant boolean DO_TIMESTAMP  = true
        private constant boolean DO_EXEC_COUNT = true
       
        //This global enables/disables the system entirely while keeping the Monitor_CreateTrigger calls functional (compiletime static ifs)
        private constant boolean ENABLED = true
        private keyword ht
      endglobals
     
      globals
        //Probably don't fuck with these
        private hashtable ht
        private timer clock
        private boolexpr cPrint
        private code     aPrint
        private boolean  recursion = false
       
        private constant integer KEY_NAME   = 1
        private constant integer KEY_COND   = 2
        private constant integer KEY_ACT    = 3
        private constant integer KEY_TIME_C = 4
        private constant integer KEY_TIME_A = 5
        private constant integer KEY_EXEC_C = 6
        private constant integer KEY_EXEC_A = 7
      endglobals
     
      //====================
      //  PUBLIC FUNCTIONS  
      //====================
     
      // This function has to have no public/private prefix because of how I've named it;
      // calling it 'public function CreateTrigger' would produce a namespace conflict.
      function Monitor_CreateTrigger takes string triggerName returns trigger
        local trigger t = CreateTrigger()
       
        static if ENABLED then
          local integer ind = GetHandleId(t)
          call FlushChildHashtable(ht, ind) //probably not necessary
          call SaveStr(ht, ind, KEY_NAME, triggerName)
        endif
       
        return t
      endfunction

      public function GetTriggerName takes trigger t returns string
        local string p = LoadStr(ht, GetHandleId(t), KEY_NAME)
        static if ENABLED then
          if p == "" then
            debug call BJDebugMsg("Monitor Warning: name requested of trigger not registered with Monitor (or name left blank)")
          endif
        endif
        return p
      endfunction
     
      public function DumpLast takes trigger t returns nothing
        local integer ind = GetHandleId(t)
        local string p
       
        static if DO_CONDITIONS then
          set p = LoadStr(ht, ind, KEY_NAME)+" - dump of last condition(s):"
         
          static if DO_TIMESTAMP then
            set p = p + "\nTimestamp: "+R2S(LoadReal(ht, ind, KEY_TIME_C))
          endif
          static if DO_EXEC_COUNT then
            set p = p + "\nExec Count: "+I2S(LoadInteger(ht, ind, KEY_EXEC_C))
          endif
        endif
        call BJDebugMsg(p)
       
        static if DO_ACTIONS then
          set p = LoadStr(ht, ind, KEY_NAME)+" - dump of last action(s):"
         
          static if DO_TIMESTAMP then
            set p = p + "\nTimestamp: "+R2S(LoadReal(ht, ind, KEY_TIME_A))
          endif
          static if DO_EXEC_COUNT then
            set p = p + "\nExec Count: "+I2S(LoadInteger(ht, ind, KEY_EXEC_A))
          endif
        endif
        call BJDebugMsg(p)
      endfunction
      //====================
     
     
     
      //! textmacro MonitorInfoDump takes APPEND, DESCRIPTION
        local integer ind = GetHandleId(GetTriggeringTrigger())
        local real t
        local integer c
        local string p = LoadStr(ht, ind, KEY_NAME)+" - $DESCRIPTION$"

        static if DO_TIMESTAMP then
          set t = TimerGetElapsed(clock)
          call SaveReal(ht, ind, KEY_TIME_$APPEND$, t)
          set p = p + "\nTimestamp: "+R2S(t)
        endif
       
        static if DO_EXEC_COUNT then
          set c = LoadInteger(ht, ind, KEY_EXEC_$APPEND$) + 1
          call SaveInteger(ht, ind, KEY_EXEC_$APPEND$, c)
          set p = p + "\nExec Count: "+I2S(c)
        endif

        call BJDebugMsg(p)
      //! endtextmacro
     
      private function ConditionPrint takes nothing returns boolean
        //! runtextmacro MonitorInfoDump("C", "checking conditions:")
        return true
      endfunction
     
      private function ActionPrint takes nothing returns nothing
        //! runtextmacro MonitorInfoDump("A", "executing actions:")
      endfunction
     
      private function Monitor_TriggerAddCondition takes trigger t, boolexpr f returns nothing
        static if ENABLED and DO_CONDITIONS then
          local integer ind = GetHandleId(t)
          if not recursion and LoadBoolean(ht, ind, KEY_COND) == false then
            call SaveBoolean(ht, ind, KEY_COND, true)
            set recursion = true
            call TriggerAddCondition(t, cPrint)
            set recursion = false
          endif
        endif
      endfunction

      private function Monitor_TriggerAddAction takes trigger t, code f returns nothing
        static if ENABLED and DO_ACTIONS then
          local integer ind = GetHandleId(t)
          if not recursion and LoadBoolean(ht, ind, KEY_ACT) == false then
            call SaveBoolean(ht, ind, KEY_ACT, true)
            set recursion = true
            call TriggerAddAction(t, aPrint)
            set recursion = false
          endif
        endif
      endfunction
     
      private function Monitor_DestroyTrigger takes trigger t returns nothing
        call FlushChildHashtable(ht, GetHandleId(t))
      endfunction

      private function Monitor_TriggerClearConditions takes trigger t returns nothing
        static if ENABLED and DO_CONDITIONS then
          call RemoveSavedBoolean(ht, GetHandleId(t), KEY_COND)
        endif
      endfunction
     
      private function Monitor_TriggerClearActions takes trigger t returns nothing
        static if ENABLED and DO_ACTIONS then
          call RemoveSavedBoolean(ht, GetHandleId(t), KEY_ACT)
        endif
      endfunction
     
      private function Monitor_CreateTriggerWarning takes nothing returns nothing
        static if ENABLED then
          debug call BJDebugMsg("Monitor Warning: trigger created by native CreateTrigger without registering in the system. If you meant to do this, ignore this message.")
        endif
      endfunction

      hook CreateTrigger          Monitor_CreateTriggerWarning
      hook DestroyTrigger         Monitor_DestroyTrigger
      hook TriggerAddCondition    Monitor_TriggerAddCondition
      hook TriggerAddAction       Monitor_TriggerAddAction
      hook TriggerClearConditions Monitor_TriggerClearConditions
      hook TriggerClearActions    Monitor_TriggerClearActions
     
      private function init takes nothing returns nothing
        static if ENABLED then
          set ht = InitHashtable()
          set clock = CreateTimer()
          call TimerStart(clock, 999999999., true, null)
          set cPrint = Condition(function ConditionPrint)
          set aPrint = function ActionPrint
        endif
      endfunction
    endlibrary
     

    And here's a simple demo library to show that it works:
    Monitor Demo
    Code (vJASS):
    library MonitorTest initializer init requires Monitor
      private function c1 takes nothing returns boolean
        call BJDebugMsg("c1")
        return true
      endfunction
     
      private function c2 takes nothing returns boolean
        call BJDebugMsg("c2")
        return true
      endfunction
     
      private function c3 takes nothing returns boolean
        call BJDebugMsg("c3")
        return true
      endfunction
     
      private function c4 takes nothing returns boolean
        call BJDebugMsg("c4")
        return true
      endfunction
     
      private function a1 takes nothing returns nothing
          call BJDebugMsg("a1")
      endfunction
     
      private function a2 takes nothing returns nothing
          call BJDebugMsg("a2")
      endfunction
     
      private function a3 takes nothing returns nothing
          call BJDebugMsg("a3")
      endfunction
     
      private function a4 takes nothing returns nothing
          call BJDebugMsg("a4")
      endfunction

      private function init takes nothing returns nothing
        local trigger t1
        local trigger t2
        local trigger t3
        local trigger t4
     
        set t1 = Monitor_CreateTrigger("trig 1")
        call TriggerAddCondition(t1, Condition(function c1))
        call TriggerAddAction(t1, function a1)

        set t2 = Monitor_CreateTrigger("trig 1")
        call TriggerAddCondition(t2, Condition(function c2))
        call TriggerAddAction(t2, function a2)
        call TriggerAddAction(t2, function a1)
     
        set t3 = Monitor_CreateTrigger("trig 1")
        call TriggerAddCondition(t3, Condition(function c3))
        call TriggerAddAction(t3, function a3)
     
        set t4 = Monitor_CreateTrigger("trig 1")
        call TriggerAddCondition(t4, Condition(function c4))
        call TriggerAddAction(t4, function a4)
     
        call TriggerSleepAction(1.0)
        call ConditionalTriggerExecute(t1)
        call ConditionalTriggerExecute(t2)
        call ConditionalTriggerExecute(t2)
        call TriggerSleepAction(1.0)
        call Monitor_DumpLast(t2)

      endfunction
    endlibrary
     
    Last edited: Sep 24, 2019
  17. Ricola3D

    Ricola3D

    Joined:
    Feb 27, 2019
    Messages:
    227
    Resources:
    2
    Maps:
    1
    Spells:
    1
    Resources:
    2
    Nice !! I was still waiting for a solution for GUI before doing anything myself.

    So you made a solution for all JASS and vJASS developers that only requires to replace CreateTrigger() by Monitor_CreateTrigger("<name for logs>") right ?
    Correct me if I am wrong, this is system is pure vJASS, no additionnal systems are required isn't ?

    About GUI, I am thinkin about another approach (use of macros to automatically generate 1 actionfunc per trigger & gathering all of the code modifications to one place):
    For the moment the only solution I can forsee would be to ask the user to add calls for a text macro manually at the end of his triggers. A macro call per global trigger. The macro will take as input the name of a trigger global variable, and create a log action function for this name and register it as a new action for the trigger variable. Stop me if this is impossible, I'm a newbie with text macros^^

    The developer would have to manually update the list, and add the text macro manually each time he create a local trigger variable.

    At the beginning, to help the developer, I would create an external script (shell, python or anyother langage) that you feed with your war3map.j file. It would list all global triggers with a regex search for "set gg_trg_[:alnum:]+\s?=\sCreateTrigger\(\)".

    I could also add all non-anonymous local triggers with a regex search for "set [:alnum:]+\s?=\sCreateTrigger\(\)". Then it's free to the user to complete the holes thanks to this list^^

    Then the script returns either a list of global variable names, either the code to copy/paste (list of calls for the macro I talke about earlier).

    Do you see any simpler idea ?
     
    Last edited: Sep 24, 2019
  18. Pyrogasm

    Pyrogasm

    Joined:
    Feb 27, 2007
    Messages:
    3,149
    Resources:
    1
    Spells:
    1
    Resources:
    1
    Yes it only works for JASS and only for triggers (not timers). GUI is much simpler.

    Note this won’t work for conditions but I doubt those would be problems anyway.
     
  19. Ricola3D

    Ricola3D

    Joined:
    Feb 27, 2019
    Messages:
    227
    Resources:
    2
    Maps:
    1
    Spells:
    1
    Resources:
    2
    Edit:
    - I found a way to register the log action as first and remove the Init function (by using a hook on TriggerAddAction).
    - Currently my logger writes in file when a user leaves or an error happens. Sadly it does not occur when the only or the last player leaves... I could not find a way to fix that for the moment.




    I did the following code. It uses macro to create new actions and add them to triggers.

    I used notepadd++ & some regular expression searchs to generate the list of all my global triggers and call the 2 macros for them. I could automatize it with an external script that you feed with your war3map.j.

    Pros:
    - All the code at the same place. Easy to maintain, edit.
    - Only a few minutes to implement (if you know Notepad++ or if I do a script to help you).
    - In may incude all GUI triggers, and any JASS triggers stored in a global variable. Even works for perfectionnists who use "TriggerAddCondition" instead of "TriggerAddAction" because it runs faster!
    - For JASS triggers stored in local variables, you can call the macros yourself!
    - One can easy replace my logger by his own code.
    - We can easily improve the system, with other MACROS to declare better log actions:
    - Log with trigger unit
    - Log with trigger player
    ...​

    Cons:
    - Because the log happens in the 2nd trigger action, the log displays only after code execution.
    - Because of the high quantity of logs:
    - I decided to only write them to file when a player leaves (I have another trigger for that).
    - I only keep the 8192 last log entries.​


    Dependencies (you can easily replace them by your own clock & logger)

    Clock System
    • Clock VariableCreator
      • Events
        • Map initialization
      • Conditions
      • Actions
        • Countdown Timer - Start ClockTimer as a Repeating timer that will expire in 99999.00 seconds


    DebugLogger
    - Displays INFO/WARN/ERROR logs only to user "Ricola3".
    - On player leaves, writes all logs in a text file all logs.
    - Rolling logs (if more than 8192 log entries)
    Code (vJASS):

    library DebugLogger
        globals
            // --------------------------------------------------------------------
            // Enum log levels
            // --------------------------------------------------------------------
            public constant integer LVL_DEBUG = 0
            public constant integer LVL_INFO = 1
            public constant integer LVL_WARN = 2
            public constant integer LVL_ERROR = 3

            // --------------------------------------------------------------------
            // Config:  log limit (everything of lower level is skipped)
            // --------------------------------------------------------------------
            private constant integer LOG_LEVEL = LVL_DEBUG

            // --------------------------------------------------------------------
            // Config: display limit (everytjong of lower level is not displayed)
            // --------------------------------------------------------------------
            private constant integer DISPLAY_LEVEL = LVL_INFO

            // Logs (actualy last 8192 logs. Indexes 0 to 8191)
            private string array logs

            // Iterators to read & write in logs
            private integer firstLogIndex = -1
            private integer lastLogIndex = -1
        endglobals

        private function DebugUserFilter takes nothing returns boolean
            // Filter only players whose user name is a developer
            if ( GetPlayerName(GetEnumPlayer()) == "Ricola3D" ) then
                return true
            endif
            if ( GetPlayerName(GetEnumPlayer()) == "lajr" ) then
                return true
            endif
            return false
        endfunction

        public function WriteInFile takes string filename returns nothing
            local integer index
     
            // There are logs to write in file
            call PreloadGenClear()
            call PreloadGenStart()
            if ( (firstLogIndex != -1) and (lastLogIndex != -1) ) then
                set index = firstLogIndex
                loop
                    call Preload(logs[index])
                    set index = index + 1
                    if ( index == 8192 ) then
                        set index = 0
                    endif
                    exitwhen index == lastLogIndex
                endloop
            else
                call Preload("<Empty log file>")
            endif
            call PreloadGenEnd(filename)
        endfunction

        private function InternalDebugLog takes integer level, string message returns nothing
            local force logForce
            local string color = ""
            local string formatedMessage = ""
            local string printMessage = ""
            local real elapsedTime = TimerGetElapsed(udg_ClockTimer)

            // Move last cursor
            set lastLogIndex = lastLogIndex + 1
            if ( lastLogIndex == 8192 ) then
                set lastLogIndex = 0
            endif
            // Move first cursor
            if ( (firstLogIndex) == -1 or (firstLogIndex == lastLogIndex) ) then
                set firstLogIndex = firstLogIndex + 1
            endif
            if ( firstLogIndex == 8192 ) then
                set firstLogIndex = 0
            endif

            // Prepare message format
            if (level == LVL_DEBUG) then
                set formatedMessage = "[DEBUG] "
                set printMessage = "[DEBUG] "
            elseif (level == LVL_INFO) then
                set formatedMessage = "[INFO] "
                set printMessage = "[INFO] "
            elseif (level == LVL_WARN) then
                set formatedMessage = "[WARN] "
                set printMessage = "[WARN] "
            elseif (level == LVL_ERROR) then
                set formatedMessage = "[ERROR] "
                set printMessage = "[ERROR] "
            endif

            if (level >= DISPLAY_LEVEL ) then
                // Log formating
                if (level == LVL_WARN) then
                    set color = "ff7f00"
                elseif (level == LVL_ERROR) then
                    set color = "ff0000"
                endif
                if (color != "") then
                    set formatedMessage = formatedMessage + "|c00" + color + message +"|r"
                else
                    set formatedMessage = formatedMessage + message
                endif
                set logForce = GetPlayersMatching(Condition(function DebugUserFilter))
                call DisplayTimedTextToForce( logForce, 3.00, formatedMessage )
                call DestroyForce(logForce)
                set logForce = null
            endif

            // Print formating
            set printMessage = printMessage + "[" + R2S(elapsedTime) + "] " + message

            // Save logs in a string array
            set logs[lastLogIndex] = printMessage
        endfunction

        public function DebugLog takes integer level, string message returns nothing
            if (level >= LOG_LEVEL ) then
                call InternalDebugLog(level, message)
            endif
        endfunction

        // ----------------------------------------------------------------------------
        public function onTriggerAddAction takes trigger whichTrigger, code actionFunc returns nothing
            // If somehow you find a way to log a trigger or function name, you can add another TriggerAction with log inside
        endfunction

        public function onGetDestructableName takes destructable d returns nothing
            call DebugLog(LVL_DEBUG, "GetDestructableName")
        endfunction

        public function onGetSoundDuration takes sound soundHandle returns nothing
            call DebugLog(LVL_WARN, "GetSoundDuration")
        endfunction

        public function onGetSoundFileDuration takes string musicFileName returns nothing
            call DebugLog(LVL_WARN, "GetSoundFileDuration")
        endfunction

        public function onGetCameraBoundMinX takes nothing returns nothing
            call DebugLog(LVL_WARN, "GetCameraBoundMinX")
        endfunction

        public function onGetCameraBoundMinY takes nothing returns nothing
            call DebugLog(LVL_WARN, "GetCameraBoundMinY")
        endfunction

        public function onGetCameraBoundMaxX takes nothing returns nothing
            call DebugLog(LVL_WARN, "GetCameraBoundMaxX")
        endfunction

        public function onGetCameraBoundMaxY takes nothing returns nothing
            call DebugLog(LVL_WARN, "GetCameraBoundMaxY")
        endfunction

        public function GetCameraField takes camerafield whichField returns nothing
            call DebugLog(LVL_WARN, "GetCameraField")
        endfunction

        public function onGetCameraTargetPositionX takes nothing returns nothing
            call DebugLog(LVL_WARN, "GetCameraTargetPositionX")
        endfunction

        public function onGetCameraTargetPositionY takes nothing returns nothing
            call DebugLog(LVL_WARN, "GetCameraTargetPositionY")
        endfunction

        public function onGetCameraTargetPositionZ takes nothing returns nothing
            call DebugLog(LVL_ERROR, "GetCameraTargetPositionZ")
        endfunction

        public function onGetCameraTargetPositionLoc takes nothing returns nothing
            call DebugLog(LVL_WARN, "GetCameraTargetPositionLoc")
        endfunction

        public function onGetCameraEyePositionX takes nothing returns nothing
            call DebugLog(LVL_WARN, "GetCameraEyePositionX")
        endfunction

        public function onGetCameraEyePositionY takes nothing returns nothing
            call DebugLog(LVL_WARN, "GetCameraEyePositionY")
        endfunction

        public function onGetCameraEyePositionZ takes nothing returns nothing
            call DebugLog(LVL_ERROR, "GetCameraEyePositionZ")
        endfunction

        public function onGetCameraEyePositionLoc takes nothing returns nothing
            call DebugLog(LVL_WARN, "GetCameraEyePositionLoc")
        endfunction

        public function onGetObjectName takes integer objectId returns nothing
            call DebugLog(LVL_DEBUG, "GetObjectName")
        endfunction

        public function onIsMultiboardMinimized takes multiboard lb returns nothing
            call DebugLog(LVL_ERROR, "IsMultiboardMinimized")
        endfunction

        public function onGetLocalPlayer takes nothing returns nothing
            call DebugLog(LVL_ERROR, "GetLocalPlayer")
        endfunction

        public function onGetLocationZ takes location whichLocation returns nothing
            call DebugLog(LVL_ERROR, "GetLocationZ")
        endfunction

        public function onGetLocalizedString takes string source returns nothing
            call DebugLog(LVL_DEBUG, "GetLocalizedString")
        endfunction

        public function onGetLocalizedHotkey takes string source returns nothing
            call DebugLog(LVL_DEBUG, "GetLocalizedHotkey")
        endfunction

        public function onGetUnitName takes unit whichUnit returns nothing
            call DebugLog(LVL_DEBUG, "GetUnitName")
        endfunction

        public function onBlzGetLocalUnitZ takes unit whichUnit returns nothing
            call DebugLog(LVL_ERROR, "BlzGetLocalUnitZ")
        endfunction

        public function onBlzGetUnitZ takes unit whichUnit returns nothing
            call DebugLog(LVL_ERROR, "BlzGetUnitZ")
        endfunction

        public function onGetItemName takes item whichItem returns nothing
            call DebugLog(LVL_DEBUG, "GetItemName")
        endfunction

        public function onBlzGetItemDescription takes item whichItem returns nothing
            call DebugLog(LVL_WARN, "BlzGetItemDescription")
        endfunction

        public function onBlzGetItemTooltip takes item whichItem returns nothing
            call DebugLog(LVL_WARN, "BlzGetItemTooltip")
        endfunction

        public function onBlzGetItemExtendedTooltip takes item whichItem returns nothing
            call DebugLog(LVL_WARN, "BlzGetItemExtendedTooltip")
        endfunction

        public function onSmartCameraPanBJ takes player whichPlayer, location loc, real duration returns nothing
            call DebugLog(LVL_ERROR, "SmartCameraPanBJ")
        endfunction

        public function onGetPlayerSlotState takes player whichPlayer returns nothing
            call DebugLog(LVL_WARN, "GetPlayerSlotState - Player " + GetPlayerName(whichPlayer))
        endfunction

        public function onGetPlayerController takes player whichPlayer returns nothing
            call DebugLog(LVL_WARN, "GetPlayerController - Player " + GetPlayerName(whichPlayer))
        endfunction

        public function onBlzGetLocalSpecialEffectX takes effect whichEffect returns nothing
            call DebugLog(LVL_WARN, "BlzGetLocalSpecialEffectX")
        endfunction

        public function onBlzGetLocalSpecialEffectY takes effect whichEffect returns nothing
            call DebugLog(LVL_WARN, "BlzGetLocalSpecialEffectY")
        endfunction

        public function onBlzGetLocalSpecialEffectZ takes effect whichEffect returns nothing
            call DebugLog(LVL_ERROR, "BlzGetLocalSpecialEffectZ")
        endfunction

        //hook TriggerAddAction onTriggerAddAction
        //hook GetDestructableName onGetDestructableName
        //hook GetSoundDuration onGetSoundDuration
        //hook GetSoundFileDuration onGetSoundFileDuration
        //hook GetCameraBoundMinX onGetCameraBoundMinX
        //hook GetCameraBoundMinX onGetCameraBoundMinY
        //hook GetCameraBoundMinX onGetCameraBoundMaxX
        //hook GetCameraBoundMinX onGetCameraBoundMaxY
        //hook GetCameraField onGetCameraField
        //hook GetCameraTargetPositionX onGetCameraTargetPositionX
        //hook GetCameraTargetPositionY onGetCameraTargetPositionY
        //hook GetCameraTargetPositionZ onGetCameraTargetPositionZ
        //hook GetCameraTargetPositionLoc onGetCameraTargetPositionLoc
        //hook GetCameraEyePositionX onGetCameraEyePositionX
        //hook GetCameraEyePositionY onGetCameraEyePositionY
        //hook GetCameraEyePositionZ onGetCameraEyePositionZ
        //hook GetCameraEyePositionLoc onGetCameraEyePositionLoc
        //hook GetObjectName onGetObjectName
        //hook IsMultiboardMinimized onIsMultiboardMinimized
        hook GetLocalPlayer onGetLocalPlayer
        hook GetLocationZ onGetLocationZ
        //hook GetLocalizedString onGetLocalizedString
        //hook GetLocalizedHotkey onGetLocalizedHotkey
        //hook GetUnitName onGetUnitName
        hook BlzGetLocalUnitZ onBlzGetLocalUnitZ
        hook BlzGetUnitZ onBlzGetUnitZ
        //hook GetItemName onGetItemName
        //hook BlzGetItemDescription onBlzGetItemDescription
        //hook BlzGetItemTooltip onBlzGetItemTooltip
        //hook BlzGetItemExtendedTooltip onBlzGetItemExtendedTooltip
        //hook SmartCameraPanBJ onSmartCameraPanBJ
        hook GetPlayerSlotState onGetPlayerSlotState
        hook GetPlayerController onGetPlayerController
        //hook BlzGetLocalSpecialEffectX onBlzGetLocalSpecialEffectX
        //hook BlzGetLocalSpecialEffectY onBlzGetLocalSpecialEffectY
        //hook BlzGetLocalSpecialEffectZ onBlzGetLocalSpecialEffectZ
    endlibrary
     


    DebugLogger - WriteInFile (only on player leave)
    • WriteInFile
      • Events
        • Player - Player 1 (Red) leaves the game
        • Player - Player 2 (Blue) leaves the game
        • Player - Player 3 (Teal) leaves the game
        • Player - Player 4 (Purple) leaves the game
        • Player - Player 5 (Yellow) leaves the game
        • Player - Player 6 (Orange) leaves the game
        • Player - Player 7 (Green) leaves the game
        • Player - Player 8 (Pink) leaves the game
      • Conditions
      • Actions
        • Custom script: call DebugLogger_WriteInFile("XndHeroSiegeLogs.txt")



    DebugLoggerAutomation

    Code (vJASS):
    // Macro to be called outside of a function context, in a library context (or remove the private)
    //! textmacro DECLARE_LOG_ACTION takes GLOBALVARIABLENAME
        globals
       private triggeraction LogAction_$GLOBALVARIABLENAME$
        endglobals

        // Create a log action function just for this trigger
        function Log_$GLOBALVARIABLENAME$ takes nothing returns nothing
            call DebugLogger_DebugLog(DebugLogger_LVL_DEBUG, "Trigger $GLOBALVARIABLENAME$ executed")
        endfunction
    //! endtextmacro

    // Macro to be called inside of a function cuntext, once all global trigger variables have been initialized
    //! textmacro ADD_LOG_ACTION takes GLOBALVARIABLENAME
            set LogAction_$GLOBALVARIABLENAME$ = TriggerAddAction($GLOBALVARIABLENAME$, function Log_$GLOBALVARIABLENAME$)
    //! endtextmacro


    library DebugLoggerAutomation
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Alliances")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Buildings")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_DarkUnits")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Flags")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_LightHeroes")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Invulnerables")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_ItemTypes")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Music")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Points")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Quests")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Regions")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Times")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_UnitStats")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_UnitTypes")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Check")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_StartGame")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_OptionsGame")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_OptionsDifficulty")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_OptionsHeroes")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_OptionsTimeOut")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_ModeNormal")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_ModeRandom")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_ModeExtreme")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_ModeEasy")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_ReviveTrees")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_CastleUnderAttack")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_StopAttackCastle")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_MuradinHelp")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_MuradinAttacked")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_BuyLevels")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_BuyTomes")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_CloseWay")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_ExtremeLevel")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Fog")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Info")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Kick")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_OpenWay")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Random")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_RandomNumber")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Repick")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_RepickTip")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Host")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_FullRestoration")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_SuperItems")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_LeaderBoard")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_LeaderBoardAdd")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_HeroSelect1a")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_HeroSelect1b")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_HeroSelect2a")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_HeroSelect2b")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_HeroSelect3a")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_HeroSelect3b")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_HeroSelect4a")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_HeroSelect4b")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_HeroSelect5a")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_HeroSelect5b")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_HeroSelect6a")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_HeroSelect6b")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_HeroSelect7a")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_HeroSelect7b")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_HeroSelect8a")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_HeroSelect8b")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_HeroSetup")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_HeroDead")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_ControlSharing")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_EasyPowerUp")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_HeroSetupDual")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_HeroDeadDual")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_DualHeroChange")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_DualHeroChangeShared")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_DualHeroStats")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_DualHeroLevel")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_DualHeroMoveItem")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_DualHeroUseItem")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_DualHeroAcquireItem")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_DualHeroLoseItem")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_BoostLevel")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_EnableHeroAbilities")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_EnableItemAbilities")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Level20Abilities")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Armor")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_AttributeBonusPerLevel")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_AuraOfBlight")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Bomb")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_CommandAura")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_CooldownsReduction")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_CriticalStrikeAura")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_CursedClaws")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_DamageDealtMalus")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_DamageTakenMalus")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_DebilitationAura")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Earthquake")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_EarthquakeStop")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Ensnare")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_FanOfKnives")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_FrostParalysisAura")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Immolation")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_ImmolationGhost")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Hex")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_HolyLight")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_InnerFire")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_LifeRegenerationAura")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_LightFrenzy")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_LightningAttackOnOff")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_MagicDefenseOnOff")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_MorphingCopyStats")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_OwlScout")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_PermanentLightning")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Polymorph")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_RealmOfSoul")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_RefreshCooldownChance")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_RefreshCooldowns")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_RuneClockCreate")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_RuneClockDestroy")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_RunicWeaponCreate")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_ThunderClap")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_ShadowStrike")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_ShockWave")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_SpiritPig")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_SpiritualPresence")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_StormBolt")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_WarDrumsAura")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_WarStomp")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Kills100")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Kills500")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Kills1000")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Kills2000")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_AttackStart")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_AttackCome")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_AttackCheck")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_AttackTower")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_AttackNecropolis")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_ExtremePowerUp")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_DragonAttack")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_HeroAttack")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_LightningAttack")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_SilentAssassin")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Rune")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_GameLevel1")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_WarnBeforeGameLevel2")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_GameLevel2")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_GameLevel3")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_GameLevel4")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_WaveTimer")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_WaveAttack")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_WaveKills20")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_WaveKills40")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_WaveKills60")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_WaveKills80")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_FinalWaveReady")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_FinalWaveStart")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_BossUnregister")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_BossRearFlankAttack")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Survival1Ready")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Survival1Start")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Survival1Attack")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Teleport")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Boss1Teleport")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Boss1Dead")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Survival2Start")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Survival2Attack")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Boss2Dead")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Boss2Leave")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Boss3Dead")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Boss4Dead")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Boss5Dead")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Survival3Start")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Survival3Attack")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Boss6Come")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Boss6Teleport")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Boss6Dead")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Boss7Come")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Boss7Colour")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Boss7Power")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Boss7Dead")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Special4Agree")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Special4Won")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Special4Leave")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Special5Agree")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Special5EnableAbilities")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Special5Won")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Special5Leave")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Special8Timer")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Special8Start")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Special8Attack")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Special8Stop")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Special8Dead")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Special8Teleport")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Special8Leave")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Special8AntiHack")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Special8Move")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_MuradinClap")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_MuradinBolt")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Special1Timer")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Special1Start")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Special1Attack")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Special1Corpse")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Special1Stop")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Special1Dead")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Special2Start")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Special2Stop")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Special2Dead")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Special2TimeOut")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Special2Teleport")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Special3Start")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Special3Stop")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Special3Count")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Special3Dead")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Special3TimeOut")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Special3Teleport")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Special6Agree")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Special7Agree")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_SpecialXDialog")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_SpecialXStart")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_SpecialXDisagree")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_SpecialXRevive")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_SpecialXTeleport")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_SpecialXPause")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_SpecialXResume")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_SpecialXCancel")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Victory")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_YouLose")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_EndGame")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Disconnect")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_RemovePlayer")
        //! runtextmacro DECLARE_LOG_ACTION("gg_trg_EndPitch")

        public function Init takes nothing returns nothing
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Alliances")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Buildings")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_DarkUnits")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Flags")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_LightHeroes")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Invulnerables")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_ItemTypes")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Music")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Points")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Quests")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Regions")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Times")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_UnitStats")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_UnitTypes")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Check")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_StartGame")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_OptionsGame")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_OptionsDifficulty")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_OptionsHeroes")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_OptionsTimeOut")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_ModeNormal")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_ModeRandom")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_ModeExtreme")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_ModeEasy")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_ReviveTrees")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_CastleUnderAttack")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_StopAttackCastle")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_MuradinHelp")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_MuradinAttacked")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_BuyLevels")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_BuyTomes")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_CloseWay")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_ExtremeLevel")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Fog")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Info")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Kick")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_OpenWay")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Random")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_RandomNumber")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Repick")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_RepickTip")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Host")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_FullRestoration")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_SuperItems")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_LeaderBoard")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_LeaderBoardAdd")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_HeroSelect1a")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_HeroSelect1b")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_HeroSelect2a")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_HeroSelect2b")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_HeroSelect3a")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_HeroSelect3b")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_HeroSelect4a")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_HeroSelect4b")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_HeroSelect5a")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_HeroSelect5b")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_HeroSelect6a")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_HeroSelect6b")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_HeroSelect7a")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_HeroSelect7b")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_HeroSelect8a")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_HeroSelect8b")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_HeroSetup")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_HeroDead")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_ControlSharing")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_EasyPowerUp")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_HeroSetupDual")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_HeroDeadDual")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_DualHeroChange")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_DualHeroChangeShared")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_DualHeroStats")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_DualHeroLevel")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_DualHeroMoveItem")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_DualHeroUseItem")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_DualHeroAcquireItem")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_DualHeroLoseItem")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_BoostLevel")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_EnableHeroAbilities")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_EnableItemAbilities")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Level20Abilities")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Armor")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_AttributeBonusPerLevel")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_AuraOfBlight")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Bomb")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_CommandAura")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_CooldownsReduction")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_CriticalStrikeAura")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_CursedClaws")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_DamageDealtMalus")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_DamageTakenMalus")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_DebilitationAura")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Earthquake")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_EarthquakeStop")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Ensnare")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_FanOfKnives")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_FrostParalysisAura")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Immolation")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_ImmolationGhost")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Hex")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_HolyLight")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_InnerFire")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_LifeRegenerationAura")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_LightFrenzy")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_LightningAttackOnOff")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_MagicDefenseOnOff")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_MorphingCopyStats")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_OwlScout")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_PermanentLightning")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Polymorph")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_RealmOfSoul")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_RefreshCooldownChance")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_RefreshCooldowns")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_RuneClockCreate")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_RuneClockDestroy")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_RunicWeaponCreate")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_ThunderClap")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_ShadowStrike")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_ShockWave")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_SpiritPig")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_SpiritualPresence")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_StormBolt")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_WarDrumsAura")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_WarStomp")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Kills100")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Kills500")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Kills1000")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Kills2000")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_AttackStart")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_AttackCome")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_AttackCheck")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_AttackTower")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_AttackNecropolis")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_ExtremePowerUp")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_DragonAttack")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_HeroAttack")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_LightningAttack")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_SilentAssassin")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Rune")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_GameLevel1")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_WarnBeforeGameLevel2")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_GameLevel2")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_GameLevel3")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_GameLevel4")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_WaveTimer")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_WaveAttack")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_WaveKills20")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_WaveKills40")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_WaveKills60")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_WaveKills80")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_FinalWaveReady")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_FinalWaveStart")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_BossUnregister")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_BossRearFlankAttack")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Survival1Ready")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Survival1Start")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Survival1Attack")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Teleport")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Boss1Teleport")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Boss1Dead")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Survival2Start")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Survival2Attack")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Boss2Dead")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Boss2Leave")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Boss3Dead")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Boss4Dead")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Boss5Dead")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Survival3Start")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Survival3Attack")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Boss6Come")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Boss6Teleport")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Boss6Dead")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Boss7Come")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Boss7Colour")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Boss7Power")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Boss7Dead")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Special4Agree")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Special4Won")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Special4Leave")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Special5Agree")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Special5EnableAbilities")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Special5Won")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Special5Leave")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Special8Timer")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Special8Start")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Special8Attack")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Special8Stop")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Special8Dead")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Special8Teleport")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Special8Leave")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Special8AntiHack")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Special8Move")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_MuradinClap")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_MuradinBolt")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Special1Timer")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Special1Start")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Special1Attack")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Special1Corpse")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Special1Stop")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Special1Dead")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Special2Start")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Special2Stop")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Special2Dead")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Special2TimeOut")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Special2Teleport")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Special3Start")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Special3Stop")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Special3Count")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Special3Dead")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Special3TimeOut")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Special3Teleport")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Special6Agree")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Special7Agree")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_SpecialXDialog")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_SpecialXStart")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_SpecialXDisagree")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_SpecialXRevive")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_SpecialXTeleport")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_SpecialXPause")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_SpecialXResume")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_SpecialXCancel")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Victory")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_YouLose")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_EndGame")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_Disconnect")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_RemovePlayer")
        //! runtextmacro ADD_LOG_ACTION("gg_trg_EndPitch")
       endfunction
    endlibrary


    Init
    • Init
      • Events
        • Time - Elapsed game time is 0.00 seconds
      • Conditions
      • Actions
        • Custom script: call DebugLoggerAutomation_Init()




    I'm not pro of JASS, so I couldn't find a way to do the following:
    - One macro only that both declares a new function & execute some instructions (once needs out of function context, the other needs within a function context...).
    - Add the log action as 1st, not 2nd. For GUI triggers, it would mean find a way to do it after the CreateTrigger() but before the "TriggerAddAction" that are automatically generated code...
     
    Last edited: Sep 27, 2019