• 🏆 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!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

[GUI-Friendly] Trigger Logger System

  • Like
Reactions: deepstrasz
Thanks to Darkfang for the idea of creating this system for GUI users.

Welcome to the Trigger Logging System. This instrumentation based system can be used to debug trigger run order or nested trigger execution related errors. It offers the following features:

Trigger registration - A requirement in this system, this allows GUI and JASS users alike to register which triggers they want to monitor for execution. Only triggers which are registered can be monitored by the system.

Commands - Includes commands such as display, allow, and discard. You can type the name of a certain trigger after those commands in order to influence that trigger only. With these commands you can log the sequence of triggers being run and potentially observe if any unexpected nesting is occurring.​

Nested trigger execution is when the action of a trigger fires the event of another during execution. Since only 1 trigger thread can run at any time the causing trigger thread yields to allow the fired trigger thread to run fully before execution of the causing trigger thread can resume. This can be a common cause of hard to spot errors in GUI based maps. For example if both triggers use the same variables, such as variables holding temporary values, the fired trigger will overwrite the values while the causing trigger thread is still using them resulting in unexpected behaviour. Especially people new to Warcraft III map making might not be aware of all the actions which cause this and all the events they will fire.

It can also be used to detect if triggers are being run at unexpected times. For example if a trigger which is only intended to run once is being run several times.

This system is not a full blown trigger debugger. Its instrumentation only allows one to monitor the sequence triggers are run, and not the state of execution of trigger threads.

JASS API

GUI Readme

Notes

Variables

Version history



JASS:
//! novjass
Here are some available functions for JASSers:

function DebugTrigger_SetTraceTrigger(trigger, boolean)
    If the trigger is in the system, this enables the tracing of the trigger in the evaluation
    of conditions.
 
    Also, if udg_DebugTrigger_Trace_DISABLE is true, the boolean flag determines the state of the
    trigger such that setting it to true would enable it, and the inverse is true.
 
function DebugTrigger_SetWatchTrigger(trigger, boolean)
    If the trigger is in the system, this enables the watching of the trigger. This is enabled by
    default. When tracing is enabled, a trace message will be displayed.

function DebugTrigger_WatchTrigger(trigger, string)
    If the trigger is in the system, an error will be displayed. Otherwise, if the name of the
    trigger, which the string represents, has already been cached, the system will display
    a notification, printing the new name of the trigger.

The variable types enclosed in parentheses are the arguments of the function.
//! endnovjass


Nearly all variables in the system are private. Here are some of the public variables, which you can tamper with:

udg_DebugTrigger_ParamTrigger - The trigger which you want to affect.
udg_DebugTrigger_ParamTriggerName - The assigned name of the trigger.
udg_DebugTrigger_Instruction - The assigned instruction.

You can assign the instruction variable into these values:

0 - Makes the system watch the trigger above, with the assigned name.
1 - Enables stack-tracing of the trigger. This will display info on every triggerevaluation.
2 - Disables stack-tracing of the trigger. If udg_DebugTrigger_Trace_DISABLE is set to true,
this also disables the trigger.

There are helper variables specifically for that purpose. They are

udg_DEBUGTRIGGER_REGISTER -> 0
udg_DEBUGTRIGGER_TRACE -> 0
udg_DEBUGTRIGGER_UNTRACE -> 0

Once you have assigned the instruction and the parameter values, you can then execute the trigger
<gen> Debug Trigger GUI.

Due to StringHash potentially causing collisions, the system might erroneously suffix a trigger name even when the name in question has only been introduced. Otherwise, the system is quite equipped to handle unusual test cases.

When a certain trigger runs, the trigger conditions get fired first. All of the trigger conditions must return true in order for the trigger to proceed to the list of trigger actions. This system does not take into account the disparity between the number of executions and the number of evaluations.

JASS:
//! novjass
DebugTrigger_EnumPlayer
    An extra variable that has no other practical purpose after initialization.
    Consider this a free variable to use.

DebugTrigger_ListenerCountKey = 0
    The key to the hashtable that stores the number of iterations a trigger
    has made.

DebugTrigger_ListenerKey = 0
    The key to the hashtable that stores the flag that determines whether
    subsequent trigger iterations will be counted.

DebugTrigger_ListenerTrace = 0
    The key to the hashtable that stores the flag that determines whether
    subsequent trigger iterations will display information.

DebugTrigger_StringKey = 0
    The key ... that stores the indices of hashed strings.

DebugTrigger_SubString[] = <Empty String>
    A string array variable that is used whenever <gen> Debug Trigger
    Core catches a player chat event. Indices used are 0, 1, and 2.

DebugTrigger_TriggerHandle = 0
    The key ... that stores the triggers, bound to their indices.

DebugTrigger_TriggerIndex = 0
    The key ... that stores the indices of the triggers, bound to their
    Handle id or Key of, in GUI.

DebugTrigger_TriggerList = 0
    A static linked list that stores all the indices relevant to the system
    (e.g, indices generated by another system that are used to store
    registered triggers)

DebugTrigger_TriggerKey = 0
    The key ... that acts as the allocator variable.

DebugTrigger_TriggerNameKey = 0
    The key ... that stores the name of each and every trigger.

DebugTrigger_TriggerNameCount = 0
    The key ... that stores the number of times the same trigger name
    has been used.
//! novjass


  • v.1.0.0.0 - Introduction of the resource!
  • v.1.1.0.0 - Included some constants for readability purposes (mostly for GUI)
Contents

[GUI-Friendly] Trigger Debugger (Map)

Reviews
Dr Super Good
Comments and Suggestions: Potentially useful for people who are having problems with trigger run sequence or nested trigger execution related bugs. Can also be used to diagnose if triggers are firing unintentionally. Possibly some method of...
Level 12
Joined
Mar 24, 2011
Messages
1,082
@Darkfang , oh, well lad, I guess you are sorter ;)

How Is it implemented? Do you have to manually add each trigger or it does it all?
It looks like you have to do the following for EACH trigger you want to look at:
  • Register trigger
    • Events
      • Map Initialization
    • Conditions
    • Actions
      • -------------------------------------- TRIGGER 1 ------------------------------------
      • --------- The trigger you want to track
      • Set DebugTrigger_ParamTrigger = SomeTrigger
      • --------- String name of trigger you want to track
      • Set DebugTrigger_ParamTriggerName = "Whatever's easier for you"
      • --------- Instruction for the tracking
      • Set DebugTrigger_Instruction = 0 / 1 / 2
      • --------- Run registration
      • Trigger - Run Debug Trigger GUI
      • -------------------------------------- TRIGGER 2 --------------------------------------
      • --------- The second trigger you want to track
      • Set DebugTrigger_ParamTrigger = SomeTrigger2
      • --------- String name of second trigger you want to track
      • Set DebugTrigger_ParamTriggerName = "Meh"
      • --------- Instruction for the tracking
      • Set DebugTrigger_Instruction = 0 / 1 / 2
      • --------- Run registration
      • Trigger - Run Debug Trigger GUI
regards
-Ned
 

Dr Super Good

Spell Reviewer
Level 63
Joined
Jan 18, 2005
Messages
27,178
I do not think debugger is the right word for this. It is more a trigger execution logger since it is missing practically every feature one would expect in a decent debugger such as stack traces, variable inspection, break points, stepped execution, etc.

One concern is that the sort of person who runs into bugs caused by trigger stacking issues is the sort of person who would not know that a system like this could help detect them.
 
One concern is that the sort of person who runs into bugs caused by trigger stacking issues is the sort of person who would not know that a system like this could help detect them.

In such a case, would improving both the documentation and demonstration of the system in GUI be helpful for them?

I do not think debugger is the right word for this. It is more a trigger execution logger since it is missing practically every feature one would expect in a decent debugger such as stack traces, variable inspection, break points, stepped execution, etc.

Interesting. I'm not quite sure if those can be implemented in this system without a substantial amount of user effort, so I'll rename them.
 

Dr Super Good

Spell Reviewer
Level 63
Joined
Jan 18, 2005
Messages
27,178
In such a case, would improving both the documentation and demonstration of the system in GUI be helpful for them?
The sort of person who could benefit from this would likely be unaware it exists. The sort of person who is aware this exists does not need this as they are well aware of how global variables work and so actively avoid overlapping global variable usage and can manually notice if any does occur without the need for wiring in instrumentation. Then the people beyond that start to use JASS with local variables which do not allow for overlapping usage of temporary storage.

Then let us not forget that this is quite confusing to use. One has to enter text commands and get listings and test out which has to be looked through in message logs (not possible in multiplayer) due to the potential volume of data involved.
Interesting. I'm not quite sure if those can be implemented in this system without a substantial amount of user effort, so I'll rename them.
You cannot implement such a thing. It has to be done at an engine level which is why no one has already, outside of abusing arbitrary code execution exploits in older versions of Warcraft III that have now been patched out.

The main reason I suggest changing the name is because currently it is overselling itself. People might look at it and think it can do a lot more than it actually can. They might think it is some magic which will help them spot the logical error in their GUI triggers or see where things go wrong. In reality it just can be used to help detect trigger thread overlap or triggers firing which might help them if they know what they are doing.
 
Level 38
Joined
Feb 27, 2007
Messages
4,951
The sort of person who could benefit from this would likely be unaware it exists.
...
The main reason I suggest changing the name is because currently it is overselling itself. People might look at it and think it can do a lot more than it actually can. They might think it is some magic which will help them spot the logical error in their GUI triggers or see where things go wrong. In reality it just can be used to help detect trigger thread overlap or triggers firing which might help them if they know what they are doing.
IMO this is a big, important nail in the coffin on this resource, but who are we to decide that nobody would use something so it shouldn't exist? With a proper (non-deceptive) description this resource is just as valid as anything else in the Spells section (also, deceptively not all the things in it are spells for instance) that does a simple job efficiently.
 

Dr Super Good

Spell Reviewer
Level 63
Joined
Jan 18, 2005
Messages
27,178
I have changed the submission name and description slightly so as to be less misleading to people. I think Trigger Logging System better describes what this does. Additionally I tried to clearly explain what it actually does and how it can be used to debug some specific kinds of errors.

If you disagree with the changes or if they are inaccurate you are free to modify them.
 

Dr Super Good

Spell Reviewer
Level 63
Joined
Jan 18, 2005
Messages
27,178
Comments and Suggestions:
Potentially useful for people who are having problems with trigger run sequence or nested trigger execution related bugs. Can also be used to diagnose if triggers are firing unintentionally.

Possibly some method of displaying the logged trigger information using a multiboard would be useful. Alternatively if file based IO is used one could write out the logs to files to be looked at outside the game.​
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
Is there a way to get a more thorough variant that does not require registration? I think having sort of autologger is a big deal in debugging issues, notably desync.
Using Lua, it would be straightforward to hack into the _G table, extract all variables starting with "gg_trg_", which then allows you to get both the trigger and its variable name and register them however you need.
 
Using Lua, it would be straightforward to hack into the _G table, extract all variables starting with "gg_trg_", which then allows you to get both the trigger and its variable name and register them however you need.
This really shows how Lua got a crazy edge in my opinion.
 

Dr Super Good

Spell Reviewer
Level 63
Joined
Jan 18, 2005
Messages
27,178
Lua also allows the insertion of a proxy in front of the trigger functions by proxying all the trigger natives that accept callbacks. Callbacks from the trigger can call this proxy function rather than the function directly allowing other forms of debugging.

For example with Lua this lets you catch any exceptions thrown by the callback function which can help detect Lua runtime errors. When the map is in a production state the trigger native proxies can be disabled with a switch to avoid the additional overhead.

It is also theoretically possible to make a variable explorer. This could allow the inspection of the value of any variable during run time. Main difficult would be creating the custom UI to convey all this information to the user.
 
Top