Skip to content

Instantly share code, notes, and snippets.

@Python1320
Last active June 26, 2023 16:56
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save Python1320/96e654c7a784a97121bd to your computer and use it in GitHub Desktop.
Save Python1320/96e654c7a784a97121bd to your computer and use it in GitHub Desktop.
[GMod] individual player metatables with __index function now only a table (performance maybe)
local entity = FindMetaTable( "Entity" )
local meta = FindMetaTable( "Player" )
local panel = CLIENT and FindMetaTable( "Panel" )
local GetEngineTable = entity.GetTable
local pltostring = FindMetaTable"Player".__tostring
local R=debug.getregistry()
local lowest = math.huge
local setted = meta
local function SetPlyMeta(t) if R[lowest]~=setted then ErrorNoHalt("1WOO".. (R[lowest]==panel and "<A>" or '<B>') .."OT\n") end setted = t R[lowest]=t end
local function GetPlyMeta() if R[lowest]~=setted then ErrorNoHalt( "2WOO".. (R[lowest]==panel and "<A>" or '<B>') .."OT\n") end return R[lowest] end
local fufu={}
MsgN"Finding Player meta from registry:"
for k,v in next,R do
if v==meta then
print(" > ",k)
if tonumber(k) and lowest>tonumber(k) then
fufu[k]=true
end
end
end
local idx=0
local function NewPlyMeta()
idx=idx+1
local myid=idx
local data = {MetaName = "Player"}
local datameta = {__index=meta}
setmetatable(data,datameta)
local t={
__index = data,
__newindex = data,
__tostring = function(self) return "PlayerIDX"..myid..pltostring(self) end,
--__metatable = meta,
--__len = function() end,
MetaName = "Player",
}
return t
end
hook.Add("Initialize","a",function()
MsgN"Finding Player meta from registry with filter:"
for k,v in next,R do
if v==meta then
print(">",k,fufu[k])
end
end
lowest=-1
for k,v in next,R do
if v==meta then
if fufu[k] and tonumber(k) and lowest<tonumber(k) then
lowest = k
print("GOTCHA",k)
end
end
end
SetPlyMeta(NewPlyMeta())
end)
local created=setmetatable({},{__mode='k'})
hook.Add("OnEntityCreated","a",function(pl)
if created[pl] then
ErrorNoHalt("WAT RECREATE ",pl)
return
end
local plMeta_ = GetPlyMeta()
local plMeta = getmetatable(pl)
if plMeta==FindMetaTable"Player" then
ErrorNoHalt("WTF "..pltostring(pl).."\n")
end
if plMeta==FindMetaTable"Entity" then
return
end
if plMeta_ ~= plMeta then return end
SetPlyMeta(NewPlyMeta())
created[pl]=true
local dat = plMeta.__newindex
local datmeta = getmetatable(dat)
local tbl = GetEngineTable(pl)
if tbl==dat then ErrorNoHalt"WTF REINIT!!?!?!?!?\n" return end
setmetatable(tbl,datmeta)
plMeta.__index = tbl
plMeta.__newindex = tbl
for k,v in next,dat do
tbl[k]=tbl[k] or v
end
end)
local meta2={} meta2=getmetatable(meta)
if not meta2 then meta2={} setmetatable(meta,meta2) end
meta2.__index = entity
if ( !sql.TableExists( "playerpdata" ) ) then
sql.Query( "CREATE TABLE IF NOT EXISTS playerpdata ( infoid TEXT NOT NULL PRIMARY KEY, value TEXT );" )
end
-- This is totally in the wrong place.
function player.GetByUniqueID( ID )
for _, pl in pairs( player.GetAll() ) do
if ( IsValid( pl ) && pl:IsPlayer() && pl:UniqueID() == ID ) then
return pl
end
end
return false
end
--[[---------------------------------------------------------
Name: DebugInfo
Params:
Desc: Prints debug information for the player
( this is just an example )
-----------------------------------------------------------]]
function meta:DebugInfo()
Msg( "Name: " .. self:Name() .. "\n" )
Msg( "Pos: " .. tostring( self:GetPos() ) .. "\n" )
end
-- Helpful aliases
meta.GetName = meta.Nick
meta.Name = meta.Nick
--[[---------------------------------------------------------
Name: ConCommand
Params:
Desc: Overrides the default ConCommand function
-----------------------------------------------------------]]
if ( CLIENT ) then
local SendConCommand = meta.ConCommand
local CommandList = nil
function meta:ConCommand( command, bSkipQueue )
if ( bSkipQueue ) then
SendConCommand( self, command )
else
CommandList = CommandList or {}
table.insert( CommandList, command )
end
end
local function SendQueuedConsoleCommands()
if (!CommandList) then return end
local BytesSent = 0
for k, v in pairs( CommandList ) do
SendConCommand( LocalPlayer(), v )
CommandList[ k ] = nil
-- Only send x bytes per tick
BytesSent = BytesSent + v:len()
if ( BytesSent > 128 ) then
break
end
end
-- Turn the table into a nil so we can return easy
if ( table.Count( CommandList ) == 0 ) then
CommandList = nil
end
end
hook.Add( "Tick", "SendQueuedConsoleCommands", SendQueuedConsoleCommands )
end
--[[---------------------------------------------------------
GetPData
- Saves persist data for this player
-----------------------------------------------------------]]
function meta:GetPData( name, default )
name = Format( "%s[%s]", self:UniqueID(), name )
local val = sql.QueryValue( "SELECT value FROM playerpdata WHERE infoid = " .. SQLStr(name) .. " LIMIT 1" )
if ( val == nil ) then return default end
return val
end
--[[---------------------------------------------------------
SetPData
- Set persistant data
-----------------------------------------------------------]]
function meta:SetPData( name, value )
name = Format( "%s[%s]", self:UniqueID(), name )
sql.Query( "REPLACE INTO playerpdata ( infoid, value ) VALUES ( "..SQLStr(name)..", "..SQLStr(value).." )" )
end
--[[---------------------------------------------------------
RemovePData
- Remove persistant data
-----------------------------------------------------------]]
function meta:RemovePData( name )
name = Format( "%s[%s]", self:UniqueID(), name )
sql.Query( "DELETE FROM playerpdata WHERE infoid = "..SQLStr(name) )
end
--
-- If they have their preferred default weapon then switch to it
--
function meta:SwitchToDefaultWeapon( name )
local weapon = self:GetInfo( "cl_defaultweapon" )
if ( self:HasWeapon( weapon ) ) then
self:SelectWeapon( weapon )
end
end
--
-- Can use flashlight?
--
function meta:AllowFlashlight( bAble ) self.m_bFlashlight = bAble end
function meta:CanUseFlashlight() return self.m_bFlashlight end
-- A function to set up player hands, so coders don't have to copy all the code everytime.
-- Call this in PlayerSpawn hook
function meta:SetupHands( ply )
local oldhands = self:GetHands()
if ( IsValid( oldhands ) ) then
oldhands:Remove()
end
local hands = ents.Create( "gmod_hands" )
if ( IsValid( hands ) ) then
hands:DoSetup( self, ply )
hands:Spawn()
end
end
--
-- Those functions have been removed from the engine since AddFlag and RemoveFlag
-- made them obsolete, but we'll keep a Lua version of them for backward compatibility
--
if SERVER then
--[[---------------------------------------------------------
Freeze
- Freezes or unfreezes the player
-----------------------------------------------------------]]
function meta:Freeze( b )
if ( b ) then
self:AddFlags( FL_FROZEN )
else
self:RemoveFlags( FL_FROZEN )
end
end
--[[---------------------------------------------------------
GodEnable
- Enables godmode on the player
-----------------------------------------------------------]]
function meta:GodEnable()
self:AddFlags( FL_GODMODE )
end
--[[---------------------------------------------------------
GodDisable
- Disables godmode on the player
-----------------------------------------------------------]]
function meta:GodDisable()
self:RemoveFlags( FL_GODMODE )
end
end
--[[---------------------------------------------------------
IsFrozen
- Returns true if the player is frozen
-----------------------------------------------------------]]
function meta:IsFrozen()
return self:IsFlagSet( FL_FROZEN )
end
--[[---------------------------------------------------------
HasGodMode
- Returns true if the player is in godmode
-----------------------------------------------------------]]
function meta:HasGodMode()
return self:IsFlagSet( FL_GODMODE )
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment