Hammer Inputs and Outputs: Wiring a Button to a Door
Inputs and outputs in Hammer explained: the fields of the Outputs tab, a button and door example, !activator, logic_relay and debugging with ent_fire.
In Hammer you connect entities through outputs and inputs: an output of one entity fires an input of another, and the target is found by its name (targetname). For a button that opens a door, you give the door a name and add the output OnPressed with the door's input Open to the func_button. A connection like this usually breaks because of a mistyped or duplicate name, a target that has been removed, or two outputs that arrive at the same moment.
How outputs and inputs fit together
An output is an event an entity reports: a button was pressed, a door is fully open, someone entered a trigger. An input is a command an entity accepts, such as Open, Close or Kill. Which outputs and inputs a class has is defined in the FGD.
Every fired output is placed in an event queue inside the engine and delivered after the delay you set. Only at that moment does the engine look up the target by name. Two pieces of information travel along: the activator, usually the entity that started the chain (for a button, the player), and the caller, the entity whose output is firing.
You set the name in the Name field of the Object Properties (Alt+Enter). An entity without a name can send outputs, but can only be targeted through its classname or a special target such as !activator. The basics of the editor are covered in getting started with the Hammer editor.
The fields of the Outputs tab
On the Outputs tab of the Object Properties you create a connection with Add.... In the Hammer that ships with GMod, the edit fields and the columns of the list are labelled slightly differently:
| Field | Column | Meaning |
|---|---|---|
My output named | My Output | The event of this entity that triggers the connection |
Targets entities named | Target Entity | Name of the target, alternatively a classname, wildcard or special target |
Via this input | Target Input | The command the target carries out |
With a parameter override of | Parameter | Value for the input, if it expects one |
After a delay in seconds of | Delay | Waiting time between the event and delivery |
Fire once only | Once | The connection is deleted after it has fired once |
Hammer++ replaces the checkbox with the field Limit to this many fires ( -1 = infinite ) and the column "Refires". The Inputs tab shows the opposite direction, meaning all connections that point at this entity. Mark jumps to the other end.
Example: a button opens a door and closes it again
- Build the door as a brush, press
Ctrl+Tand choosefunc_door. Name itdoor_1. - Set
Move Direction (Pitch Yaw Roll)to the opening direction andDelay Before Reset (-1 stay)to-1. The door then stays open. - On the
Flagstab, untickTouch Opens. It is ticked by default and would open the door on touch. - Build the button as a brush and turn it into a
func_button. TheUse Activatesflag is already set. WithDelay Before Reset (-1 stay)set to5, it cannot be pressed again for at least five seconds. - On the button's
Outputstab, add two connections:
My Output Target Entity Target Input Parameter Delay
OnPressed door_1 Open 0.00
OnPressed door_1 Close 5.00
The door opens immediately and closes five seconds after the press. It works without the second connection too: a door with Delay Before Reset at 5 closes by itself. How to call a lift with the same pattern is covered in the article on elevators and trains.
Special targets and logic building blocks
Instead of a name, the target field can hold a special target:
| Target | Meaning |
|---|---|
!activator | The entity that started the chain, such as the player at the button |
!caller | The entity whose output is firing |
!self | As a target the same as !caller, as a parameter the entity receiving the input |
!player | The player, in multiplayer the first one who joined the server |
!picker | The entity under the crosshair, meant for debugging |
On a server, !player is therefore almost never right. Use !activator for the player who triggered the chain, or the classname player for everyone. Wildcards only work at the end: door_* matches every name that starts with door_. A pattern such as *_door does not work, because the engine ignores everything after the *. A classname such as func_door is a valid target too, unless an entity carries exactly that text as its name.
A handful of logic entities turn this into larger circuits:
logic_relaybundles several outputs under one name: inputTrigger, outputOnTrigger.Disablebreaks the chain,CancelPendingdiscards the relay's events that are still waiting. While delayed outputs are pending it cannot be triggered again, unless theAllow fast retriggerflag is set.logic_timerfiresOnTimerat the pace of itsRefire Interval.math_countercounts withAddandSubtractand firesOnHitMaxorOnHitMinonce a limit is reached.trigger_multipleis a volume withOnStartTouch,OnEndTouchandOnTrigger. The flags andFilter Namewith afilter_activator_nameorfilter_activator_classdefine who may trigger it.
Debugging in game
Before compiling, Map > Check for Problems (Alt+P) lists entities with invalid connections. In game, these console commands help:
developer 2
ent_messages_draw 1
ent_fire door_1 Open
ent_fire !picker Kill
developer 2prints every output and every input to the console.dumpeventqueuelists the events still waiting for their delay.ent_messages_draw 1shows the same messages in the 3D world at the entities.ent_fire <target> <input> [parameter] [delay]fires an input by hand. This lets you test the target independently of whatever triggers it.
Test in single player or as the host, because according to the Valve wiki a client connected to a server cannot use ent_fire. If the console asks for cheats, enter sv_cheats 1 first. With developer 2, the console lines follow the pattern below. The block is assembled from the message formats in GMod's server.dll, with the names from the example and an invented time. It is not a recording of a real session:
(12.50) output: (func_button,button_1) -> (door_1,Open)()
(12.50) input button_1: door_1.Open()
unhandled input: (Open) -> (door_2), from (func_button,button_1); target entity not found
The first line is the firing output, the second its delivery. The third is the one to look for: it appears when no entity carries the target name at the moment of delivery, in this illustration door_2.
Typical mistakes
- Name missing or mistyped: Hammer shows the target in red, and "Check for Problems" reports the connection. Do not use "Fix" there blindly: according to the error text, Hammer deletes the bad connections instead of repairing them. Wildcards and classnames also appear in red although they work in game.
- Name used twice: Hammer shows the target in bold. The input goes to every entity with that name. That is intended for two door leaves, not for a copied door in the next room.
- Target removed:
Killdeletes an entity together with its children in the parent hierarchy. Delayed outputs that arrive afterwards go nowhere, and the removed entity fires no new outputs. The same happens with!activatorif the player leaves the server first. - Timing races: Two outputs with the same delay arrive in the same tick. Do not rely on their order. If B depends on A, give B a small delay. The Valve wiki uses at least 0.02 seconds in such a case.
Outputs can also trigger a lua_run, which then executes Lua code. The Map Scanner finds risky entities of this kind in a BSP. More checks are listed in the article on checking a BSP before release.
FAQ
Can one output address several entities at once?
Yes. The input goes to every entity the target matches: a shared name, a wildcard such as door_* or a classname.
What is the difference between OnPressed and OnIn on a func_button?
OnPressed fires as soon as the button is pressed. OnIn only fires once it has reached its pressed end position, and OnOut when it is back in its starting position.
Can I change outputs while the game is running?
Yes, with the AddOutput input. The format is <output> <target>:<input>:<parameter>:<delay>:<max times to fire>. The FGD calls it "very dangerous, use with care", and circuits that rewire themselves in game are hard to follow later.