How to: Complex logic entity systems without any wait times

Hello,

I’ve wondered if one could build complex logic systems that don’t have any delays whatsoever in them and basically deliver the results instantly.
Insights into how that works are useful when designing complex logic entity systems such as keypads, board games, etc. that work in all Source Engine games regardless of Lua support.
I remember that long ago, I’ve managed to put together a keypad like that, but the stuff is gone now and it was time for a new structured attempt at figuring this out.

So here are my findings.

Hammer 4.1 + Half-Life 2: Episode 2, 2015-08-15

  • in the output events panel of an entity, output events are displayed in the alphabetical order of their output type, but in the VMF, they are listed in precisely the order they were added/pasted - that order can be manipulated comfortably with a text editor, but not in Hammer itself
  • there is some kind of buffer in which output events are scheduled
  • the order of output events as listed in the VMF determines the order of scheduling/execution directly, and one can seemingly depend on that order
  • the output events are scheduled from last added to first added, following the natural order of output events added in reverse
  • additions to the schedule in the form of a triggered relay come after all direct output events

This is my sample setup, where messages are output with a point_clientcommand entity.
The order of output events in the VMF is the order written down here.



button:
  message seq1
  message seq2
  trigger relay r1
  trigger relay r2
  message seq3
  message seq3

relay r1:
  trigger relay r1_1
  message r1seq1
  message r1seq2
  trigger relay r1_1

relay r2:
  message r2seq1
  message r2seq2

relay r1_1 ("Allow fast retrigger" spawnflag set):
  message r1_1seq1
  message r1_1seq2


I got the messages in this order:



seq3
seq3
seq2
seq1
r2seq2
r2seq1
r1seq2
r1seq1
r1_1seq2
r1_1seq1
r1_1seq2
r1_1seq1


At first, all direct output events from the button were processed.
The triggering of a relay basically caused its output events to be appended at the end of the overall workload.
Without the “Allow fast retrigger” spawnflag, the relay r1_1 only fired once, effectively turning it into a synchronization point.
If relays were processed in-place, I’d have seen the messages in this order:



seq3
seq3
r2seq2
r2seq1
r1_1seq2
r1_1seq1
r1seq2
r1seq1
r1_1seq2
r1_1seq1
seq2
seq1


So my thought model based on my findings is this:

  1. Triggering an entity so that its output events are scheduled too basically means putting it into an event queue (that explains why the relays are processed after direct output events, and the player using the button has the same effect).
  2. The output events of one entity are always processed in the reverse natural order, last to first.

One consequence of this would be that I could fire relay r1_1 once, then disable it, and then try firing it again, all from relay r1 (while minding the precise event order).
And I’ve just tested that and it really works like that, so the relay output its messages r1_1seq2 and r1_1seq1 only once.

The .vmf sample file is here.

Hope that helps. :slight_smile: