Skip to content

Instantly share code, notes, and snippets.

@NeatNit
Last active April 4, 2017 19:00
Show Gist options
  • Save NeatNit/a0d67229734888009ca12e7639f78856 to your computer and use it in GitHub Desktop.
Save NeatNit/a0d67229734888009ca12e7639f78856 to your computer and use it in GitHub Desktop.
render hooks reverse engineering
local gmod = gmod
local pairs = pairs
local isfunction = isfunction
local isstring = isstring
local IsValid = IsValid
if CLIENT_DLL then require( "draw" ) end
local draw = draw
local render = render
local table = table
local CLIENT = CLIENT_DLL
local unpack = unpack
local print = print
local ipairs = ipairs
local tostring = tostring
local Color = Color
local cam = cam
local math = math
module( "hook" )
local Hooks = {}
--[[---------------------------------------------------------
Name: GetTable
Desc: Returns a table of all hooks.
-----------------------------------------------------------]]
function GetTable() return Hooks end
--[[---------------------------------------------------------
Name: Add
Args: string hookName, any identifier, function func
Desc: Add a hook to listen to the specified event.
-----------------------------------------------------------]]
function Add( event_name, name, func )
if ( !isfunction( func ) ) then return end
if ( !isstring( event_name ) ) then return end
if ( Hooks[ event_name ] == nil ) then
Hooks[ event_name ] = {}
end
Hooks[ event_name ][ name ] = func
end
--[[---------------------------------------------------------
Name: Remove
Args: string hookName, identifier
Desc: Removes the hook with the given indentifier.
-----------------------------------------------------------]]
function Remove( event_name, name )
if ( !isstring( event_name ) ) then return end
if ( !Hooks[ event_name ] ) then return end
Hooks[ event_name ][ name ] = nil
end
--[[---------------------------------------------------------
Name: Run
Args: string hookName, vararg args
Desc: Calls hooks associated with the hook name.
-----------------------------------------------------------]]
function Run( name, ... )
return Call( name, gmod and gmod.GetGamemode() or nil, ... )
end
--[[---------------------------------------------------------
Name: Run
Args: string hookName, table gamemodeTable, vararg args
Desc: Calls hooks associated with the hook name.
-----------------------------------------------------------]]
local function OrigCall( name, gm, ... )
--
-- Run hooks
--
local HookTable = Hooks[ name ]
if ( HookTable != nil ) then
local a, b, c, d, e, f;
for k, v in pairs( HookTable ) do
if ( isstring( k ) ) then
--
-- If it's a string, it's cool
--
a, b, c, d, e, f = v( ... )
else
--
-- If the key isn't a string - we assume it to be an entity
-- Or panel, or something else that IsValid works on.
--
if ( IsValid( k ) ) then
--
-- If the object is valid - pass it as the first argument ( self )
--
a, b, c, d, e, f = v( k, ... )
else
--
-- If the object has become invalid - remove it
--
HookTable[ k ] = nil
end
end
--
-- Hook returned a value - it overrides the gamemode function
--
if ( a != nil ) then
return a, b, c, d, e, f
end
end
end
--
-- Call the gamemode function
--
if ( !gm ) then return end
local GamemodeFunction = gm[ name ]
if ( GamemodeFunction == nil ) then return end
return GamemodeFunction( gm, ... )
end
local function ConcatTable( t, sep )
local r = {}
for _, v in ipairs( t ) do
table.insert( r, tostring( v ) )
end
return table.concat( r, sep )
end
local active = false
local info = {}
local rendering = false
local currentindex = 0
local retindex = 1
local retval = nil
local red = Color( 255, 0, 0 )
local green = Color( 0, 255, 0 )
local white = Color( 255, 255, 255 )
local black = Color( 0, 0, 0 )
local function CustomCall( name, ... )
if not active then return OrigCall( name, ... ) end
local ret = { OrigCall( name, ... ) }
if name == "PreRender" then -- "PreRender" then
rendering = true
currentindex = 0
info = {}
end
if rendering then
currentindex = currentindex + 1
table.insert( info, { rt = render.GetRenderTarget(), name = name, output = ConcatTable( ret, ", " ) } )
end
if name == "PostRender" then
rendering = false
cam.Start2D()
local pointercolor = white
if retval then
pointercolor = green
elseif retval == false then
pointercolor = red
end
draw.SimpleTextOutlined( "►", "Trebuchet18", 5, retindex*22 + 10, pointercolor, nil, nil, 1, black )
for i, v in ipairs( info ) do
local tcolor = white
local outputtext = v.output
if i == retindex then
tcolor = pointercolor
if retval != nil then
if outputtext == "" then
outputtext = " ( instead of nothing )"
else
outputtext = " ( instead of: " .. outputtext .. " )"
end
outputtext = tostring( retval ) .. outputtext
end
end
draw.SimpleTextOutlined( tostring(v.rt), "Trebuchet18", 20, i*22 + 10, tcolor, nil, nil, 1, black )
draw.SimpleTextOutlined( v.name, "Trebuchet18", 250, i*22 + 10, tcolor, nil, nil, 1, black )
draw.SimpleTextOutlined( outputtext, "Trebuchet18", 500, i*22 + 10, tcolor, nil, nil, 1, black )
end
cam.End2D()
end
if retindex == currentindex then
currentindex = -1
if retval ~= nil then return retval end
end
return unpack( ret )
end
function Call( ... )
if CLIENT then
return CustomCall( ... )
end
return OrigCall( ... )
end
function SetActive( b ) active = b end
function ToggleActive() active = not active end
function PointerUp()
retindex = math.max( retindex-1, 1 )
retval = nil
end
function PointerDown()
retindex = math.min( retindex+1, 55 ) -- artificial limit because I don't know how to calculate a proper one
retval = nil
end
function ToggleOutput()
if not retval then
retval = true
else
retval = false
end
end
-- bind p "lua_run_cl hook.ToggleActive()"
-- bind [ "lua_run_cl hook.PointerUp()"
-- bind ] "lua_run_cl hook.PointerDown()"
-- bind ' "lua_run_cl hook.ToggleOutput()"
-- one line:
-- bind p "lua_run_cl hook.ToggleActive()" ; bind [ "lua_run_cl hook.PointerUp()" ; bind ] "lua_run_cl hook.PointerDown()" ; bind ' "lua_run_cl hook.ToggleOutput()"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment