Skip to content

Hook Library

Person8880 edited this page Apr 6, 2024 · 27 revisions

Overview

The hook library provides a more advanced hooking mechanism for NS2's event hooks and for other parts of the game.

Available hooks:

You can add more events using the SetupClassHook and SetupGlobalHook functions. Note that these lists are not comprehensive as plugins may define their own hooks. See the source code for an up to date list of hooks.

Server hooks

-- Called by the voice chat system when a player is talking.
-- Return true to allow, false to deny.
CanPlayerHearPlayer( Gamerules, Listener, Speaker )

-- Called when a player casts a vote through the request menu (e.g. concede).
-- Return a value to stop the vote.
CastVoteByPlayer( Gamerules, VoteID, Player ) 

-- Use this and UpdatePregame to alter game starting rules.
CheckGameStart( Gamerules )

-- Called the moment a client spawns into the game.
ClientConnect( Client )

-- Called when the client first presses a button after joining.
ClientConfirmConnect( Client )

ClientDisconnect( Client )

CommLoginPlayer( Building, Player )

CommLogout( Building )

EndGame( Gamerules, WinningTeam )

-- Called before a player joins a new team, except during a shuffle.
-- Return a team number to alter the new team, return false to halt.
JoinTeam( Gamerules, Player, NewTeam, Force, ShineForce )

-- Called the moment before the map is changed.
MapChange()

MapLoadEntity( MapName, GroupName, Values )

-- Called after the server has finished loading the map.
MapPostLoad()

-- Called just before the server is going to load the map.
MapPreLoad()

-- Called when an event is being hooked with the built in system. Return true and a replacement function to override.
NS2EventHook( Name, Func )

OnBuildingRecycled( Building, ID )

OnCommanderNotify( Commander, LocationID, TechID )

OnCommanderTechTreeAction( Commander, TechNode, Position, Normal, IsCommanderPicked, Orientation, Entity, Trace )

OnConstructInit( Building )

-- Called when the map cycle system tries to change map.
-- Return a value to stop the map cycling
OnCycleMap()

OnEntityKilled( Gamerules, TargetEntity, Attacker, Inflictor, Point, Direction )

OnRecycle( Building, ID )

PlayerNameChange( Player, NewName, OldName )

-- Called when a player sends a chat message.
-- Return a string to change the message contents, or an empty string to hide the message.
PlayerSay( Client, MessageTable )

-- Called after a successful team join, including during a shuffle.
PostJoinTeam( Gamerules, Player, OldTeam, NewTeam, Force, ShineForce )

SetGameState( Gamerules, NewState, OldState )

-- Called when the map cycle system wants to know if it can cycle the map.
-- Return false to stop the map cycling.
ShouldCycleMap()

-- Called every server tick.
Think( DeltaTime )

-- Called on the first think after loading.
OnFirstThink()

-- Return a value to override the default function.
UpdatePregame( Gamerules, TimePassed )

Client hooks:

-- Called when the local client disconnects from the server.
ClientDisconnected( Reason )

-- Called once the map's loaded.
OnMapLoad()

-- Called on screen resolution change.
OnResolutionChanged( OldX, OldY, NewX, NewY )

-- Called when a player presses a key. Return true to halt the input from going any further.
PlayerKeyPress( Key, Down, Amount )

-- Called for typing into text elements, return true to halt the input from going any further.
PlayerType( Char )

-- Called when the player is starting to text chat.
StartChat( TeamOnly )

-- Called every frame rendered.
Think( DeltaTime )

Adding and Removing Hook Listeners

Shine.Hook.Add

Shine.Hook.Add( string HookName, string UniqueID, function HookFunction [, int Priority ] )

Registers a function under the given unique ID to the given hook. This function will be run when this hook is called and passed any arguments that were passed to Call. Priority is an optional value between -20 and 20 expressing where in the list of listeners the function should be placed relative to other listeners (default value is 0). The hook listener with the lowest priority value (i.e. sorted to the front of the list) is run first.

Example:

Shine.Hook.Add( "ClientConnect", "PrintConnection", function( Client )
    Print( "Client with NS2ID %s connected.", Client:GetUserId() )
end )

Note

Plugins can use hooks by adding a given hook name as a method, they do not need to use Shine.Hook.Add directly. For example:

function Plugin:Think( DeltaTime )
    -- This is automatically registered against the "Think" hook, passing 'self' implicitly.
end

Shine.Hook.Remove

Shine.Hook.Remove( string HookName, string UniqueID )

Removes the hook with the given unique ID that is registered to the given hook.

Example:

Shine.Hook.Remove( "ClientConnect", "PrintConnection" )

Calling Hooks

Shine.Hook.Broadcast

Shine.Hook.Broadcast( string HookName, ... )
Shine.Hook.BroadcastOnce( string HookName, ... )

Broadcasts the given hook name, running any registered functions and passing them all arguments contained in the vararg (...). All registered functions are invoked, regardless of whether any of them return a non-nil value, and no value is returned.

This allows for read-only hooks that do not need to modify behaviour to observe events without being suppressed.

The Once variant invokes the hook exactly once, then removes all registered listener functions.

Shine.Hook.Call

Shine.Hook.Call( string HookName, ... )
Shine.Hook.CallOnce( string HookName, ... )

Calls the given hook name, running any registered functions and passing them all arguments contained in the vararg (...). The first registered function to return a non-nil value will have its value(s) returned by Call/CallOnce.

Unlike Broadcast, this is suitable for hooks that need to return a value, e.g. to modify the return values of a function. Earlier listeners will suppress the invocation of later listeners if they return a non-nil value.

The Once variant invokes the hook exactly once, then removes all registered listener functions.

Example:

Shine.Hook.Call( "CustomHook", Shared.GetTime() )

Tip

Consider using SetupClassHook and SetupGlobalHook (see below) instead of using Broadcast or Call directly, as they make hooking into existing functions easier.

Setting Up Hooks

Shine.Hook.SetupClassHook

Shine.Hook.SetupClassHook( string Class, string Method, string HookName, string or function Mode )

Hooks into the given class method (from the game's registered classes, i.e. from the class function), calling the Shine hook with the name HookName. The last argument decides the exact behaviour of the hook. There are a few preset hooking methods, or you can specify the function to replace the class method with directly.

Preset hooking modes:

  • Replace: Replaces the function with a Shine hook call.
  • PassivePre: Broadcasts the given Shine hook, then runs the original function and returns its value(s).
  • PassivePost: Runs and stores the return values of the original function, then broadcasts the Shine hook, then returns the original return values.
  • ActivePre: Calls the given Shine hook and returns its values if it returned any. Otherwise it returns the original function's values.
  • ActivePost: Runs and stores the return values of the original function, then calls the Shine hook. If the Shine hook returned values, they are returned. Otherwise, the original values are returned.
  • Halt: Calls the given Shine hook. If it returns a non-nil value, the method is stopped and returns nothing. Otherwise the original method is returned.

These modes implement optimal replacement of a function for minimal overhead (no var-args, compiler friendly). Most use cases should be fine with these presets.

Examples:

Hooking using a preset mode:

Shine.Hook.SetupClassHook( "Player", "AddKill", "OnPlayerAddKill", "PassivePost" )

Hooking using a custom function:

Shine.Hook.SetupClassHook( "Player", "AddKill", "OnPlayerAddKill", function( OldFunc, self )
    OldFunc( self )
    
    Shine.Hook.Call( "OnPlayerAddKill", self )
end )

Note that here OldFunc represents the original function and should be used to call it in your custom function.

Shine.Hook.SetupGlobalHook

Shine.Hook.SetupGlobalHook( string FunctionName, string HookName, string or function Mode )

Hooks into a global function (i.e. available in _G) in a similar way to the class hooker. The function name argument can be either something like "func" or "table.function" to replace a function nested within another table.

The Mode argument has the same presets as for classes.

Examples:

Hooking using a preset mode:

Shine.Hook.SetupGlobalHook( "print", "OnLuaPrint", "ActivePre" )

Hooking using a custom function:

Shine.Hook.SetupGlobalHook( "print", "OnLuaPrint", function( OldFunc, ... )
    local Ret = Shine.Hook.Call( "OnLuaPrint", ... )

    if Ret ~= nil then return end

    return OldFunc( ... )
end )

Shine.Hook.ReplaceLocalFunction

Shine.Hook.ReplaceLocalFunction( function ContainerFunction, string FunctionName, function ReplacementFunction[, table DifferingValues, boolean Recurisive ] )

Takes the local function named FunctionName that ContainerFunction has, and replaces it with ReplacementFunction.

In doing so, ReplacementFunction receives all upvalues that the original function has. If you pass in DifferingValues, then the upvalues with names in this table will be replaced in your replacement function with the values given.

This function returns the replaced local function.

Example

local GetCriticalHivePosition
local AssignPlayerToEgg
local OldUpdateAlienSpectators

local function UpdateAlienSpectators( self )
    --Do your cool replacement stuff here.
end

OldUpdateAlienSpectators = Shine.Hook.ReplaceLocalFunction( AlienTeam.Update, "UpdateAlienSpectators", UpdateAlienSpecators )

Caution

Replacing local functions can be brittle and have impacts on performance. Consider carefully whether replacing a local function is necessary.

Clone this wiki locally