Skip to content

Instantly share code, notes, and snippets.

@CaptainPRICE
Last active September 13, 2016 15:52
Show Gist options
  • Save CaptainPRICE/b495058446b86ddb97f85791b58f43e5 to your computer and use it in GitHub Desktop.
Save CaptainPRICE/b495058446b86ddb97f85791b58f43e5 to your computer and use it in GitHub Desktop.
Steam. IDs... IDs... IDs... Let's clean this mess up (GMod).
-- Made/Published to clear up misinformation, for you to possibly learn something new from it. - CaptainPRICE
-- Tell me in the comments (below) if you have spot bug(s), or if you have any suggestions or improvements as I would like to hear them!
-- See my comment here: https://github.com/wiremod/wire/pull/1217#issuecomment-246211364
local game = game
local IS_DEDICATED, IS_SINGLEPLAYER, MAX_NUM_PLAYERS = game.IsDedicated(), game.SinglePlayer(), game.MaxPlayers()
print(CLIENT and "CLIENT" or (SERVER and "SERVER" or "MENU"), IS_SINGLEPLAYER and "SP" or "MP", IS_DEDICATED and "DEDICATED" or "LISTEN", "MAX=" .. MAX_NUM_PLAYERS, "v" .. VERSION, BRANCH)
if not debug then return print("debug library is missing") end
local debug = debug
if not string then return print("string library is missing") end
local string = string
if not player then return print("player library is missing") end
local player = player
local _R = debug.getregistry()
local ENTITY = FindMetaTable("Entity")
if not ENTITY then
ENTITY = _R.Entity
if not ENTITY then return end
end
local PLAYER = FindMetaTable("Player")
local PLAYER_BASE
if not PLAYER then
PLAYER = _R.Player
if not PLAYER then return end
end
PLAYER_BASE = PLAYER.MetaBaseClass
if not PLAYER_BASE then return end
--print(PLAYER.MetaName .. " inherits from " .. PLAYER_BASE.MetaName) -- Prints: "Player inherits from Entity"
local print = print
local tostring = tostring
local typeof = type
local gsub = string.gsub
local formatvar = function(str, var)
if not isstring(str) then return end
str = gsub(gsub(str, "{:tostring:}", (isstring(var) and ('"' .. var .. '"')) or tostring(var)), "{:typeof:}", typeof(var))
return str
end
local FormatVar = function(name, var)
return formatvar(name .. " = {:tostring:} ({:typeof:})", var)
end
local PrintValue = function(actor, name)
if not IsValid(actor) or not isstring(name) then return end
local is_bot = actor:IsBot()
local func = is_bot and ENTITY[name] or (PLAYER[name] or PLAYER_BASE[name]) -- Use Entity for bots; otherwise use Player, if it is not found in Player, then search the Player's base class (Entity)
if not isfunction(func) then return end
local value = func(actor)
name = (is_bot and "Bot:" or "Ply:") .. name .. "()"
print(FormatVar(name, value))
end
local CAN_HAVE_BOTS = not IS_SINGLEPLAYER or (MAX_NUM_PLAYERS > 1)
local humans = player.GetHumans()
local Bot = CAN_HAVE_BOTS and player.GetBots()[1] or NULL
local Ply = (CAN_HAVE_BOTS and CLIENT) and LocalPlayer() or humans[math.random(1, #humans)]
print(FormatVar("Bot", Bot), FormatVar("Ply", Ply))
if CLIENT then
local GetPlayerInfo = PLAYER.GetPlayerInfo or _R.Player.GetPlayerInfo
if isfunction(GetPlayerInfo) then
if IsValid(Bot) then
print(FormatVar("Bot:GetPlayerInfo().friendid", GetPlayerInfo(Bot).friendid))
end
if IsValid(Ply) then
print(FormatVar("Ply:GetPlayerInfo().friendid", GetPlayerInfo(Ply).friendid))
end
--print(FormatVar("NULL:GetPlayerInfo().friendid", GetPlayerInfo(NULL).friendid)) -- ERROR!
end
end
for _, func_name in next, { "AccountID", "EntIndex", "SteamID", "SteamID64", "UniqueID", "UserID" } do
PrintValue(Bot, func_name)
PrintValue(Ply, func_name)
end
-- First run in singleplayer (SP) on serverside, then clientside.
-- Second run in multiplayer (MP) on serverside, then clientside.
-- Script output (at version: 160905 - dev branch):
--[[
SERVER SP LISTEN MAX=1 v160905 dev
Bot = [NULL Entity] (Entity) Ply = Player [1][CaptainPRICE] (Player)
Ply:AccountID() = nil (nil)
Ply:EntIndex() = 1 (number)
Ply:SteamID() = "STEAM_0:0:0" (string)
Ply:SteamID64() = nil (nil)
Ply:UniqueID() = "1" (string)
Ply:UserID() = 2 (number)
CLIENT SP LISTEN MAX=1 v160905 dev
Bot = [NULL Entity] (Entity) Ply = Player [1][CaptainPRICE] (Player)
Ply:GetPlayerInfo().friendid = 131959820 (number)
Ply:AccountID() = 131959820 (number)
Ply:EntIndex() = 1 (number)
Ply:SteamID() = "STEAM_0:0:65979910" (string)
Ply:SteamID64() = "76561198092225548" (string)
Ply:UniqueID() = "1" (string)
Ply:UserID() = 2 (number)
SERVER MP LISTEN MAX=128 v160905 dev
Bot = Player [2][Bot01] (Player) Ply = Player [1][CaptainPRICE] (Player)
Bot:AccountID() = 0 (number)
Ply:AccountID() = 131959820 (number)
Bot:EntIndex() = 2 (number)
Ply:EntIndex() = 1 (number)
Bot:SteamID() = "BOT" (string)
Ply:SteamID() = "STEAM_0:0:65979910" (string)
Bot:SteamID64() = "90071996842377216" (string)
Ply:SteamID64() = "76561198092225548" (string)
Bot:UniqueID() = "1513418020" (string)
Ply:UniqueID() = "445831337" (string)
Bot:UserID() = 4 (number)
Ply:UserID() = 3 (number)
CLIENT MP LISTEN MAX=128 v160905 dev
Bot = Player [2][Bot01] (Player) Ply = Player [1][CaptainPRICE] (Player)
Bot:GetPlayerInfo().friendid = 0 (number)
Ply:GetPlayerInfo().friendid = 131959820 (number)
Bot:AccountID() = nil (nil)
Ply:AccountID() = 131959820 (number)
Bot:EntIndex() = 2 (number)
Ply:EntIndex() = 1 (number)
Bot:SteamID() = "NULL" (string)
Ply:SteamID() = "STEAM_0:0:65979910" (string)
Bot:SteamID64() = nil (nil)
Ply:SteamID64() = "76561198092225548" (string)
Bot:UniqueID() = "1513418020" (string)
Ply:UniqueID() = "445831337" (string)
Bot:UserID() = 4 (number)
Ply:UserID() = 3 (number)
]]
-- Made/Published to clear up misinformation, for you to possibly learn something new from it. - CaptainPRICE
-- Tell me in the comments (below) if you have spot bug(s), or if you have any suggestions or improvements as I would like to hear them!
local game = game
local IS_DEDICATED, IS_SINGLEPLAYER, MAX_NUM_PLAYERS = game.IsDedicated(), game.SinglePlayer(), game.MaxPlayers()
print(CLIENT and "CLIENT" or (SERVER and "SERVER" or "MENU"), IS_SINGLEPLAYER and "SP" or "MP", IS_DEDICATED and "DEDICATED" or "LISTEN", "MAX=" .. MAX_NUM_PLAYERS, "v" .. VERSION, BRANCH)
if not debug then return print("debug library is missing") end
local debug = debug
if not math then return print("math library is missing") end
local math = math
if not string then return print("string library is missing") end
local string = string
if not player then return print("player library is missing") end
local player = player
--if not team then return print("team library is missing") end
--local team = team
local _R = debug.getregistry()
local ENTITY = FindMetaTable("Entity")
if not ENTITY then
ENTITY = _R.Entity
if not ENTITY then return end
end
local PLAYER = FindMetaTable("Player")
local PLAYER_BASE
if not PLAYER then
PLAYER = _R.Player
if not PLAYER then return end
end
PLAYER_BASE = PLAYER.MetaBaseClass
if not istable(PLAYER_BASE) then return end -- It must have a base class
--print(PLAYER.MetaName .. " inherits from " .. PLAYER_BASE.MetaName) -- Prints: "Player inherits from Entity"
local VEHICLE = FindMetaTable("Vehicle")
local VEHICLE_BASE
if not VEHICLE then
VEHICLE = _R.Vehicle
if not VEHICLE then return end
end
VEHICLE_BASE = VEHICLE.MetaBaseClass
if not istable(VEHICLE_BASE) then return end -- It must have a base class
--print(VEHICLE.MetaName .. " inherits from " .. VEHICLE_BASE.MetaName) -- Prints: "Vehicle inherits from Entity"
local print = print
local tostring = tostring
local typeof = type
local gsub = string.gsub
-- A small function to make variable display nicer
local formatvar = function(var, str)
if not isstring(str) then return end
str = gsub(gsub(str, "{:tostring:}", (isstring(var) and ('"' .. var .. '"')) or tostring(var)), "{:typeof:}", typeof(var))
return str
end
local FormatVar = function(var, name)
return formatvar(var, name .. " = {:tostring:} ({:typeof:})")
end
-- Attempts to find a function in a class (from metatable and registry) for the given Entity/Player/Vehicle (it is specifically for entities)
local GetFunctionFromClass = function(actor, name, force)
if not force and (not IsValid(actor) or not isentity(actor)) then return end
if actor:IsPlayer() then
-- Use Player class, if it is not found in Player, then search the Player's base class (Entity)
return ((PLAYER[name] or _R.Player[name]) or PLAYER_BASE[name]) or _R.Entity[name], ((isfunction(PLAYER[name]) and PLAYER.MetaName) or isfunction(PLAYER_BASE[name]) and PLAYER_BASE.MetaName) or --[[typeof(actor)]]"Player"
end
if actor:IsVehicle() then
-- Use Vehicle class, if it is not found in Vehicle, then search the Vehicle's base class (Entity)
return ((VEHICLE[name] or _R.Vehicle[name]) or VEHICLE_BASE[name]) or _R.Entity[name], ((isfunction(VEHICLE[name]) and VEHICLE.MetaName) or isfunction(VEHICLE_BASE[name]) and VEHICLE_BASE.MetaName) or --[[typeof(actor)]]"Vehicle"
end
-- Else, it is some other type of entity such as CSEnt (we don't really care about here, or do we?)
-- But, just look up Entity class for it
return ENTITY[name] or _R.Entity[name], ENTITY.MetaName or --[[typeof(actor)]]"Entity" -- Entity is the base class
end
-- Addition to FormatVar function above, returns nicely formatted string of var. var is expected to be Entity/Player/Vehicle (it will evaluate a (name) function on its class)
local FormatClassVar = function(var, name, force)
local class_func, class_name = GetFunctionFromClass(var, name, force)
if isfunction(class_func) and isstring(class_name) then
return FormatVar(class_func(var), class_name .. ":" .. name .. "()") -- Like it? :)
end
-- Else, it is a failure - should not happen, please report if it does
ErrorNoHalt("typeof(class_func) = " .. typeof(class_func), '\n', "typeof(class_name) = " .. typeof(class_name), '\n')
return var, name, class_func, class_name
end
-- Prints it out nicely, use specifically for entities
local PrintEvalEntityValue = function(actor, name, force)
if force or (IsValid(actor) and isstring(name)) then
print(FormatClassVar(actor, name, force))
end
end
---------------------------------------------------------------------------------------------------------------------------------------
local CAN_HAVE_BOTS = not IS_SINGLEPLAYER or (MAX_NUM_PLAYERS > 1)
local humans = player.GetHumans()
local Bot = CAN_HAVE_BOTS and player.GetBots()[1] or NULL
local Ply = (CAN_HAVE_BOTS and CLIENT) and LocalPlayer() or humans[math.random(1, #humans)]
print(FormatVar(Bot, "Bot"), FormatVar(Ply, "Ply"))
local FORCE = true -- Set to true to bypass validation checks; otherwise false
-- Simply alter the data table as you please ˘\_(^^)_/˘
local data = {
{
"Ply", -- 1. (n) Text which is printed before evaluation
Ply, -- 2. (e) Entity value to use (it will automatically detect its class, but it has to inherit from Entity class as that is the "ultimate" base class for any entity)
"EntIndex", -- 3. (fn) Name of the function to evaluate on the class with above entity value (it is smart about finding it)
Color(70, 200, 70) -- 4. (c) *OPTIONAL* Color to use for text specified at slot/index 1
},
{
"Ply",
Ply,
"UserID",
team.GetColor(Ply:Team()) -- Use Ply's team color
},
{
"NULL",
NULL, -- Note: NULL is an instance of Entity class (not Player/Vehicle/etc...)
"EntIndex"
}
}
if CAN_HAVE_BOTS and IsValid(Bot) then
table.Merge(data, {
{
"Bot",
Bot,
"EntIndex",
Color(0, 100, 240)
},
{
"Bot",
Bot,
"UserID",
team.GetColor(Bot:Team()) -- Use Bot's team color
}
})
end
for i, v in next, data do
local n, e, fn, c = v[1], v[2], v[3], v[4]
if not isentity(e) or not isstring(fn) then
ErrorNoHalt("data table contains values of wrong types (possibly incorrect order at index " .. i .. "?)", '\n', "typeof(n) = " .. typeof(n), '\n', "typeof(e) = " .. typeof(e), '\n', "typeof(fn) = " .. typeof(fn), '\n', "typeof(c) = " .. typeof(c), '\n')
print(i, v, n, e, fn, c)
break
end
if not isstring(n) or #n < 1 then n = "-" end -- Default text
--print(n, FormatClassVar(e, fn)) -- Display results (FormatClassVar function will run the named function and print it nicely)
if IsColor(c) then
MsgC(c, n)
else
Msg(n)
end
Msg('\t')
PrintEvalEntityValue(e, fn, FORCE)
end
for k, v in next, player.GetAll() do -- Print all
print(k .. " - " .. tostring(v) .. " { EntIndex = " .. v:EntIndex() .. ", UserID = " .. v:UserID() .. " }")
end
-- _G.Entity function expects Entity EntIndex - not Player UserID! (No matter what.)
-- _G.Player function expects Player UserID - not Entity EntIndex! (No matter what.)
-- Screenshot (proof): https://cloud.githubusercontent.com/assets/9789070/18476543/c67d332a-79ca-11e6-9d1e-d3ff5dc64e15.png
-- First run in singleplayer (SP) on serverside, then clientside.
-- Second run in multiplayer (MP) on serverside, then clientside.
-- Script output (at version: 160905 - dev branch):
--[[
SERVER SP LISTEN MAX=1 v160905 dev
Bot = [NULL Entity] (Entity) Ply = Player [1][CaptainPRICE] (Player)
Ply Entity:EntIndex() = 1 (number)
Ply Player:UserID() = 2 (number)
NULL Entity:EntIndex() = 0 (number)
1 - Player [1][CaptainPRICE] { EntIndex = 1, UserID = 2 }
CLIENT SP LISTEN MAX=1 v160905 dev
Bot = [NULL Entity] (Entity) Ply = Player [1][CaptainPRICE] (Player)
Ply Entity:EntIndex() = 1 (number)
Ply Player:UserID() = 2 (number)
NULL Entity:EntIndex() = 0 (number)
1 - Player [1][CaptainPRICE] { EntIndex = 1, UserID = 2 }
SERVER MP LISTEN MAX=128 v160905 dev
Bot = Player [2][Bot01] (Player) Ply = Player [1][CaptainPRICE] (Player)
Bot Entity:EntIndex() = 2 (number)
Bot Player:UserID() = 4 (number)
NULL Entity:EntIndex() = 0 (number)
1 - Player [1][CaptainPRICE] { EntIndex = 1, UserID = 3 }
2 - Player [2][Bot01] { EntIndex = 2, UserID = 4 }
CLIENT MP LISTEN MAX=128 v160905 dev
Bot = Player [2][Bot01] (Player) Ply = Player [1][CaptainPRICE] (Player)
Bot Entity:EntIndex() = 2 (number)
Bot Player:UserID() = 4 (number)
NULL Entity:EntIndex() = 0 (number)
1 - Player [1][CaptainPRICE] { EntIndex = 1, UserID = 3 }
2 - Player [2][Bot01] { EntIndex = 2, UserID = 4 }
]]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment