Events and Hooks
From GMod Wiki
|Lua: Events and Hooks|
|Description:||An introduction in hooks.|
|Contributors:||theJ89, Deco Da Man|
|Created:||October 24th 2010|
This article will teach you the basics of a couple important concepts in Garry's Mod Lua scripting: events and hooks.
Events are specific happenings in the game world. One example of an event is when a player dies.
More examples are when a player spawns, takes damage, or disconnects.
There are even some events for non-game world things, such as drawing graphics on the Heads Up Display (or HUD, for short).
Sometimes, events even carry associated information. For example, if a player died, then the event might also carry information about which player died.
Whenever an event occurs, Garry's Mod tells Lua that the event has happened.
Lua responds to an event by running hooks. Hooks are functions that are "hooked up" to an event.
So, what's the difference between an event and a hook?
The important thing to keep in mind is that events "happen", and any number of hooks (including 0 hooks) can "respond" to this event.
Events are an important programming topic in general, but especially so in Garry's Mod.
One reason that events are so important is because they make interactions between players and the game world possible.
For example, one kind of event is "player presses key". Information that gets passed with this event is the player who pressed the key, and the key he pressed.
The game hooks into this event. The hook checks that the [USE] key was pressed, and looks for an object in front of "player 5". If it finds one, the game tries to trigger a "Use" event involving the object.
Another reason events are important is that they allow scripters to change or add onto Garry's Mod.
This makes practically everything related to Lua in Garry's Mod possible, such as addons, scripted weapons, and scripted entities.
For example, say a player is holding an AK47. He presses his primary fire key, and the game triggers a "primary fire" event on the weapon.
The "PrimaryFire" hook on the AK47 will respond to the event by making the weapon shoot bullets, deplete ammo, etc.
Because events play such an important role, Garry's Mod is said to be event driven.
A "Hook" is a way to make a function run whenever something happens in the game.
A list of game-related hooks can be found here.
When a script is run, the file is executed and when it reaches the end execution stops.
// myscript.lua if LocalPlayer():KeyDown(IN_ATTACK) then // IN_ATTACK is the attack button (usually left mouse) Msg("I'm attackin ya!\n") end // end of file
This script will run once when you load a game. After that, GMod does not even consider it. It has run - that is it.
If you wanted to print that message whenever your player presses a key, you would need to use a hook.
local MyHookFunction = function() if LocalPlayer():KeyDown(IN_ATTACK) then Msg("I'm attackin ya!\n") end end hook.Add("Think", "My button hook", MyHookFunction)
The function hook.Add takes three arguments (please read the Functions section if you haven't already).
The first argument is the "type" of hook.
There are many different types of hooks. There is one for when a player spawns, when a player dies, when someone connects, when someone takes damage, when someone presses a key, etc.
The full list is available at the Gamemode Hooks page.
The second argument is a unique name.
This name can be anything: a string, a number.. even a boolean, a table or a function! The most common names are strings, however.
This name should identify what your hook function (known as a callback) does. If your hook is for your "BananaPlayers" addon, and it turns players that spawn randomly into bananas, you might called it "BananaPlayers.PlayerSpawn".
The third argument is your hook function.
You can either store your hook function in a variable, and then pass that to this argument (like above), or you can do it inline:
hook.Add("Think", "blah blah", function() code code code end)
Many coders use this way because it looks nicer.
The problem with the "My button hook" hook used in the example above is that it runs in a "Think" hook.
"Think" hooks are called EVERY frame (about 30 times a second). "Think" is very handy for running code that needs to be run as fast as possible (moving a bullet, a dancing melon, any type of animation, etc).
Because the code will be run every frame, whenever you press the attack button it will print "I'm attackin ya!" to your console... at 30 times a second, that's a f***tonne of console spam!
Instead, you're looking for a hook that is called whenever the player presses the button
There is such a hook available:
hook.Add("KeyPress", "My button hook", function() if LocalPlayer():KeyDown(IN_ATTACK) then Msg("I'm attackin ya!\n") end end)
The function will be run whenever the player spawns (just after they spawn, actually).
Some hooks provide handy information about what has happened (e.g: which player has spawned, how much damage was taken, what button was pressed, etc).
When a "KeyPress" hook function (callback) is called, it is passed two arguments:
local MyHookFunction = function(the_player, key_number) end hook.Add("KeyPress", "My button hook", MyHookFunction)
Notice that if you look at the arguments found on the KeyPress function page:
function KeyPressed (P, key) Msg (P:GetName().." pressed "..key.."\n") end hook.Add( "KeyPress", "KeyPressedHook", KeyPressed )
They are defined as P and key. So the name of the arguments don't have to be the same in both functions. (Although it will probably be easier to understand.) However, what is important is that they are in the same order, and that they are the same type of variable as the ones found on the original function you are hooking into.
Consider this example from the Hook.Add page:
TODO (Deco Da Man 13:41, 3 November 2010 (GMT)): Inform about different types of hooks
TODO (Deco Da Man 13:41, 3 November 2010 (GMT)): Explain different states
Other hook functions
Hooks can be removed.
TODO (Deco Da Man 13:41, 3 November 2010 (GMT)): Explain hook.Remove and hook.GetTable