Events and Hooks

From GMod Wiki

Revision as of 00:21, 6 November 2011 by Michael (Talk | contribs)
Jump to: navigation, search
Lua: Events and Hooks
Page white text.png Description:An introduction in hooks.
link=User:Assault_Trooper Original Author:Assault_Trooper
Group.png Contributors:theJ89, Deco Da Man
Calendar.png Created:October 24th 2010

Contents

Introduction

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.

Explaining events

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.

Explaining Hooks

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.
Example:

 
// 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.
Example:

 
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.

Example hooks

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)
 

Hook Arguments

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:

DescriptionTells victims who killed them in chat.
Used onNewerServer.png
Code
 
function sayThatName(victim, inflictor, killer) //Use the same arguments as the original function you're hooking to
	if killer:IsPlayer()then --Only prints the killer if he was a player.
		victim:PrintMessage(HUD_PRINTTALK, killer:Nick().." killed you!\n")
	end
end
hook.Add("PlayerDeath","informTheVictims",sayThatName)
 
Output"Pwnd has killed you!" in the victim's chat (assuming that the killer was named Pwnd)


TODO (Deco Da Man 13:41, 3 November 2010 (GMT)): Inform about different types of hooks

Server-side, Shared and Client-side 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

Yarin Kaul Icon ArrowSquare32 left.png Garry's Mod Instances

Yarin Kaul Icon ArrowSquare32.png Back to Lua Tutorial Series

ConVars Yarin Kaul Icon ArrowSquare32 right.png


Personal tools
Namespaces
Variants
Actions
Navigation
Lua Scripting
Functions
Hooks
Toolbox