I’m pretty sure everyone covered this, but again… A function and hook are the same. A variable can store a reference to anything, even functions. You can create functions many different ways. Lua is a language of tables, everything is stored in a table, even global variables and functions.
Think of hooks, or functions, that get called when an event happens as a broadcast receiver. These are implemented to make modifying the game easier. Functions that make things happen help us simplify problems, think of these as building blocks; they reduce the amount of code we need to write, they also reduce repetition ( I always create a function out of code when I re-use something more than once or twice )…
I have a few examples, and some starter docs that may help… So, you can create your own hooks.
Example, there is no PlayerDroppedWeapon or CanPlayerDropWeapon hooks, but these can be quite useful to have.
CanPlayerDropWeapon will be a hook.Call ( This broadcasts out looking for any hook.Adds that use CanPlayerDropWeapon to see if the behavior will be modified [ think: Can the player drop the weapon, or not? ] before calling the main function [ default behavior; many are left blank ] – note, if you use hook.Add to modify behavior, only use return for your specific behavior, don’t do else return false; end just because it looks nice because that will prevent all other hook.Adds and the main function from running at all )…
PlayerDroppedWeapon will be called after the player successfully dropped the weapon.
The only way we can add this behavior is by redirecting ( rewrite ) a function in the Player Meta-Table - META_PLAYER = FindMetaTable( “Player” ); - DropWeapon… Since we’re adding new behavior and we want to preserve the old behavior we need to create a variable that references the original function so we can use the original function when we over-write it. This needs to be auto-refresh compatible ( meaning it needs to be global variable set like this: var = var || original_function; – or something we set 1 time such as if ( !META_PLAYER.__DropWeapon ) then META_PLAYER.__DropWeapon = META_PLAYER.DropWeapon; end – and this method can be used interchangeably; some prefer one way, others pefer another way…
3 files… Now, I also add additional behavior so the default function I define for function GM:PlayerDroppedWeapon( … ); is to unlink the data ( this is part of another data / networking system so private data belonging to the weapon is known by the player holding it and no one else because no one else needs it )
I chose to use: __META_PLAYER_DROP_WEAPON as the reference to the original function ( I’ll be changing this next update to my dev-base to keep it internal with the player meta-table )…
This is the file that changes the logic… Notice I create the reference and used the data = data || original_function; method of preserving the original function… The first thing I do is hook.Call CanPlayerDropWeapon so that I can prevent the weapon being dropped ( by not calling the original function ) if a hook.Add or the main GM function for the hook returns false ( which means do not allow drop ). If drop is allowed, I proceed to call the original function ( and because we have a reference to the function via . when the function was created using : [ where self is inferred ] I need to add self as the first variable [ which is the player ] to preserve the original functionality even though the only argument is the weapon, more on this later… I then call a second hook, which informs any code that needs to be informed when the player dropped the weapon successfully. The networking:CallHook is part of my networking system which simply calls the same hook on the client as a notification so if client-side code needs to know anything about the weapon drop, it can be done since this is a server-side function…
Since the GM: function needs to exist if we call a hook on GAMEMODE table, and because I needed default behavior for it… I added this with data ( normally, override functions are empty ). debug.print is part of a debugging system that lets you enable / disable debug output based on category. The data:Unlink is part of the system I mentioned earlier…
CanPlayerDropWeapon I added a few things that come into play with my dev_base ( a lot will be moved into libraries soon ) but it prevents a weapon from being dropped if it is invalid, it also, by default, prevents weapons from being dropped if the SWEP:Holster function prevent it from being holstered ( to allow default behavior ), then I check to see if the weapon class is listed in the un-droppable weapons table ( such as physgun, admin baton, etc… ) and if all of those pass I return true to allow dropping the weapon. Now, any hook.Add can return true or false to override this entire default function…
I hope that provides some insight in terms of why we use hooks and why some functions do tasks while others are “rang” / broadcasted.
Always test and develop code using SRCDS: Setting up a Local Development SRCDS
Here are some beginner docs:
Generalized tips ( many simple mistakes cost in terms of running-cost [ performance ] ): https://dl.dropboxusercontent.com/u/26074909/tutoring/optimization/_generalized_optimization_guide.lua.html
[ NOTE ] Remove .html to view / copy .Lua …
I have written over 500 tutorials and completed “systems” in Lua for Garry’s Mod. I tutor for negotiable rates / free / donations, and answer questions one on one for free / donations; feel free to add me on Steam if you need some guidance. Here are some resources to help you get started:
Generalized Lua Help ( Links to Wikis, Answers the question of “Where do I post a simple question or DarkRP Specific question”, links to other resources compiled by forum members )
Useful Programs ( SteamCMD, Autosizer, Desktops, Process Explorer ) and Notepad++ Upgrades