Skip to content

Commit

Permalink
printColor improvements
Browse files Browse the repository at this point in the history
Add:
- Dynamic perf on printColor (1 op per bit sent)
- ConVar to disable warnings on printColor
Change:
- Rewrote printColor
- printColor now uses modified normal print max length to limit
- Print max length now use server's maxlength in singleplayer
- printColor warning now fires only once per session
  • Loading branch information
Denneisk committed Dec 11, 2023
1 parent 33d3fac commit d0cbe42
Show file tree
Hide file tree
Showing 2 changed files with 155 additions and 71 deletions.
46 changes: 32 additions & 14 deletions lua/entities/gmod_wire_expression2/core/cl_debug.lua
Original file line number Diff line number Diff line change
@@ -1,30 +1,48 @@
CreateClientConVar( "wire_expression2_print_max", 15, true, true )
CreateClientConVar( "wire_expression2_print_max_length", 1000, true, true )
CreateClientConVar( "wire_expression2_print_delay", 0.3, true, true )
local cvar_warn = CreateClientConVar("wire_expression2_printcolor_warn", 1, true, true, "Shows a warning when someone uses printColorDriver on you")

local chips = {}
local not_warned = true

hook.Add("EntityRemoved", "wire_expression2_printColor", function(ent)
chips[ent] = nil
end)
local RED = Color(255, 0, 0)

local printcolor_readers = {
[1] = function() return tostring(net.ReadDouble()) end,
[2] = function() return net.ReadString() end,
[3] = function() return net.ReadColor(false) end,
[4] = function()
local e = net.ReadEntity() -- Passing directly will set color as the player's color which isn't desirable I believe
return e:IsValid() and (e:IsPlayer() and e:GetName() or e:GetClass()) or "NULL" -- Also, MsgC doesn't have this feature, so adds parity
end
}

net.Receive("wire_expression2_printColor", function( len, ply )
local chip = net.ReadEntity()
net.Receive("wire_expression2_printColor", function()
local ply = net.ReadEntity()
local console = net.ReadBool()
if chip and not chips[chip] then
chips[chip] = true
-- printColorDriver is used for the first time on us by this chip
chat.AddText(Color(255,0,0),"While in somone's seat/car/whatever, printColorDriver can be used to 100% realistically fake people talking, including admins.")
chat.AddText(Color(255,0,0),"Don't trust a word you hear while in a seat after seeing this message!")

local msg = {}

for i = 1, 1024 do
local head = net.ReadUInt(4)
if head == 0 then break end
msg[i] = printcolor_readers[head]()
end

if console then
MsgC(unpack(net.ReadTable()))
MsgC(unpack(msg))
else
chat.AddText(unpack(net.ReadTable()))
if not_warned and ply ~= LocalPlayer() then
not_warned = false
if cvar_warn:GetBool() and not game.SinglePlayer() then
chat.AddText(RED, "While in somone's seat/car/whatever, printColorDriver can be used to 100% realistically fake people talking, including admins.\
Don't trust a word you hear while in a seat after seeing this message!")
end
end
chat.AddText(unpack(msg))
end
end)

net.Receive("wire_expression2_print", function(len, ply)
net.Receive("wire_expression2_print", function()
chat.AddText(net.ReadString())
end)
180 changes: 123 additions & 57 deletions lua/entities/gmod_wire_expression2/core/debug.lua
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ local defaultPrintDelay = 0.3
-- the amount of "charges" a player has by default
local defaultMaxPrints = 15
-- default max print length
local defaultMaxLength = 1000
local defaultMaxLength = game.SinglePlayer() and 10000 or 1000

-- Contains the amount of "charges" a player has, i.e. the amount of print-statements can be executed before
-- the messages being omitted. The defaultPrintDelay is the time required to add one additional charge to the
Expand Down Expand Up @@ -303,94 +303,160 @@ __e2setcost(150)
util.AddNetworkString("wire_expression2_printColor")
util.AddNetworkString("wire_expression2_print")

local printColor_typeids = {
n = tostring,
s = function(text) return string.Left(text,249) end,
v = function(v) return Color(v[1],v[2],v[3]) end,
xv4 = function(v) return Color(v[1],v[2],v[3],v[4]) end,
e = function(e) return IsValid(e) and e:IsPlayer() and e or "" end,
}

local function printColorVarArg(chip, ply, console, typeids, vararg)
if not IsValid(ply) then return end
if not checkDelay(ply) then return end
local bytes = 0
local max_len = 0

-- Proprietary type IDs just for placebo network saving:
-- 0 - EOF
-- 1 - number
-- 2 - string
-- 3 - color
-- 4 - entity
local function pc_number_writer(n)
bytes = bytes + 8
net.WriteUInt(1, 4)
net.WriteDouble(n)
end

local i = 1
for i,tp in ipairs(typeids) do
if printColor_typeids[tp] then
vararg[i] = printColor_typeids[tp](vararg[i])
else
vararg[i] = ""
end
if i == 256 then break end
i = i + 1
local function pc_string_writer(text)
local len = bytes + #text
net.WriteUInt(2, 4)
if len >= max_len then
net.WriteString(string.sub(text, 1, max_len - bytes))
else
net.WriteString(text)
end
bytes = len + 1
end

net.Start("wire_expression2_printColor")
net.WriteEntity(chip)
net.WriteBool(console)
net.WriteTable(vararg)
net.Send(ply)
local function pc_entity_writer(e)
bytes = bytes + 2 -- edict is 13 bits oh well
net.WriteUInt(4, 4)
net.WriteEntity(e)
end

local function pc_vector_writer(v)
bytes = bytes + 24
net.WriteUInt(3, 4)
net.WriteUInt(v[1], 8)
net.WriteUInt(v[2], 8)
net.WriteUInt(v[3], 8)
end

local printColor_types = {
number = tostring,
string = function(text) return string.Left(text,249) end,
Vector = function(v) return Color(v[1],v[2],v[3]) end,
table = function(tbl)
for i,v in pairs(tbl) do
if not isnumber(i) then return "" end
if not isnumber(v) then return "" end
if i < 1 or i > 4 then return "" end
local printcolor_writers = {
[TYPE_NUMBER] = pc_number_writer,
[TYPE_STRING] = pc_string_writer,
[TYPE_VECTOR] = pc_vector_writer,
[TYPE_TABLE] = function(t)
if IsColor(t) then
bytes = bytes + 24
net.WriteUInt(3, 4)
net.WriteColor(t, false)
else
for i, v in pairs(t) do
if not isnumber(i) then return end
if not isnumber(v) then return end
if i < 1 or i > 4 then return end
end
bytes = bytes + 24
net.WriteUInt(3, 4)
net.WriteUInt(t[1], 8)
net.WriteUInt(t[2], 8)
net.WriteUInt(t[3], 8)
end
return Color(tbl[1] or 0, tbl[2] or 0,tbl[3] or 0,tbl[4])
end,
Player = function(e) return IsValid(e) and e:IsPlayer() and e or "" end,
[TYPE_ENTITY] = pc_entity_writer,

n = pc_number_writer,
s = pc_string_writer,
v = pc_vector_writer,
e = pc_entity_writer,
xv4 = function(t)
bytes = bytes + 24
net.WriteUInt(3, 4)
net.WriteUInt(t[1], 8)
net.WriteUInt(t[2], 8)
net.WriteUInt(t[3], 8)
end,
}

local function printColorArray(chip, ply, console, arr)
local function printColorVarArg(self, ply, console, typeids, vararg)
if not IsValid(ply) then return end
if not checkDelay( ply ) then return end
if not checkDelay(ply) then return end
bytes = 0

local send_array = {}
max_len = math.min(maxLength:GetInt(), self.player:GetInfoNum("wire_expression2_print_max_length", defaultMaxLength))
max_len = math.min(max_len + math.floor(max_len / 3), 65532) -- Add a third just to be nice

local i = 1
for i,tp in ipairs_map(arr,type) do
if printColor_types[tp] then
send_array[i] = printColor_types[tp](arr[i])
else
send_array[i] = ""
net.Start("wire_expression2_printColor")
net.WriteEntity(self.entity:GetPlayer()) -- CHANGE THIS TO WritePlayer LATER!!!
net.WriteBool(console)

for i, tp in ipairs(typeids) do
local fn = printcolor_writers[tp]
if fn then
fn(vararg[i])
else
pc_string_writer(repr(self, vararg[i], tp))
end
if bytes >= max_len then break end
end
if i == 256 then break end
i = i + 1
end

net.WriteUInt(0, 4)

net.Send(ply)

self.prf = self.prf + bytes / 8
end

local function printColorArray(self, ply, console, arr)
if not IsValid(ply) then return end
if not checkDelay(ply) then return end
bytes = 0

max_len = math.min(maxLength:GetInt(), self.player:GetInfoNum("wire_expression2_print_max_length", defaultMaxLength))
max_len = math.min(max_len + math.floor(max_len / 3), 65532)

net.Start("wire_expression2_printColor")
net.WriteEntity(chip)
net.WriteEntity(self.entity:GetPlayer())
net.WriteBool(console)
net.WriteTable(send_array)

for _, v in ipairs(arr) do
local fn = printcolor_writers[TypeID(v)]
if fn then
fn(v)
else
pc_string_writer(tostring(v))
end
if bytes >= max_len then break end
end

net.WriteUInt(0, 4)

net.Send(ply)

self.prf = self.prf + bytes / 8
end


--- Works like [[chat.AddText]](...). Parameters can be any amount and combination of numbers, strings, player entities, color vectors (both 3D and 4D).
e2function void printColor(...args)
printColorVarArg(nil, self.player, false, typeids, args)
printColorVarArg(self, self.player, false, typeids, args)
end

--- Like printColor(...), except taking an array containing all the parameters.
e2function void printColor(array arr)
printColorArray(nil, self.player, false, arr)
printColorArray(self, self.player, false, arr)
end

--- Works like MsgC(...). Parameters can be any amount and combination of numbers, strings, player entities, color vectors (both 3D and 4D).
e2function void printColorC(...args)
printColorVarArg(nil, self.player, true, typeids, args)
printColorVarArg(self, self.player, true, typeids, args)
end

--- Like printColorC(...), except taking an array containing all the parameters.
e2function void printColorC(array arr)
printColorArray(nil, self.player, true, arr)
printColorArray(self, self.player, true, arr)
end

--- Like printColor(...), except printing in <this>'s driver's chat area instead of yours.
Expand All @@ -402,7 +468,7 @@ e2function void entity:printColorDriver(...args)

if not checkDelay( driver ) then return end

printColorVarArg(self.entity, driver, false, typeids, args)
printColorVarArg(self, driver, false, typeids, args)
end

--- Like printColor(R), except printing in <this>'s driver's chat area instead of yours.
Expand All @@ -414,5 +480,5 @@ e2function void entity:printColorDriver(array arr)

if not checkDelay( driver ) then return end

printColorArray(self.entity, driver, false, arr)
printColorArray(self, driver, false, arr)
end

0 comments on commit d0cbe42

Please sign in to comment.