Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
125 changes: 81 additions & 44 deletions lua/entities/gmod_wire_expression2/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,13 @@ function ENT:Initialize()
self.error = true
self:UpdateOverlay(true)
self:SetColor(Color(255, 0, 0, self:GetColor().a))

local owner = self.player

if IsValid(owner) then
E2Lib.PlayerChips[owner] = E2Lib.PlayerChips[owner] or {}
table.insert(E2Lib.PlayerChips[owner], self)
end
end

function ENT:OnRestore()
Expand Down Expand Up @@ -287,14 +294,56 @@ function ENT:Think()
context.prf = 0
context.time = 0

if e2_timequota > 0 and context.timebench > e2_timequota then
self:Error("Expression 2 (" .. selfTbl.name .. "): time quota exceeded", "time quota exceeded")
self:PCallHook("destruct")
end

return true
end

E2Lib.PlayerChips = E2Lib.PlayerChips or {}

hook.Add("Think", "E2_Think", function()
if e2_timequota < 0 then return end

for ply, chips in pairs(E2Lib.PlayerChips) do
local total_time = 0

for _, chip in ipairs(chips) do
local tab = chip:GetTable()
if tab.error then continue end

local context = tab.context
if not context then continue end

total_time = total_time + context.timebench
end

while total_time > e2_timequota do
local max_time = 0
local max_chip

for _, chip in ipairs(chips) do
local tab = chip:GetTable()
if tab.error then continue end

local context = tab.context
if not context then continue end

if context.timebench > max_time then
max_time = context.timebench
max_chip = chip
end
end

if max_chip then
total_time = total_time - max_time
max_chip:Error("Expression 2 (" .. max_chip.name .. "): Per-player time quota exceeded", "per-player time quota exceeded")
max_chip:Destruct()
else
-- It shouldn't happen, but if something breaks, it will prevent an infinity loop
break
end
end
end
end)

local CallHook = wire_expression2_CallHook
function ENT:CallHook(hookname, ...)
local context = self.context
Expand All @@ -308,6 +357,22 @@ function ENT:OnRemove()
self:Destruct()
end

local owner = self.player
if not IsValid(owner) then return end

local chips = E2Lib.PlayerChips[owner]

for index, chip in ipairs(chips) do
if chip == self then
table.remove(chips, index)
break
end
end

if #chips == 0 then
E2Lib.PlayerChips[owner] = nil
end

BaseClass.OnRemove(self)
end

Expand Down Expand Up @@ -718,52 +783,24 @@ end
--[[
Player Disconnection Magic
--]]
local cvar = CreateConVar("wire_expression2_pause_on_disconnect", 0, 0, "Decides if chips should pause execution on their owner's disconnect.\n0 = no, 1 = yes, 2 = non-admins only.")
-- This is a global function so it can be overwritten for greater control over whose chips are frozenated
function wire_expression2_ShouldFreezeChip(ply)
return not ply:IsAdmin()
end
hook.Add("PlayerDisconnected", "Wire_Expression2_Player_Disconnected", function(ply)
E2Lib.PlayerChips[ply] = nil

-- It uses EntityRemoved because PlayerDisconnected doesn't catch all disconnects.
hook.Add("EntityRemoved", "Wire_Expression2_Player_Disconnected", function(ent)
if (not (ent and ent:IsPlayer())) then
return
end
local ret = cvar:GetInt()
if (ret == 0 or (ret == 2 and not wire_expression2_ShouldFreezeChip(ent))) then
return
end
for _, v in ipairs(ents.FindByClass("gmod_wire_expression2")) do
if (v.player == ent) then
v:SetOverlayText(v.name .. "\n(Owner disconnected.)")
local oldColor = v:GetColor()
v:SetColor(Color(255, 0, 0, v:GetColor().a))
v.disconnectPaused = oldColor
v.error = true
if v.player == ply and not v.error then
v:Error("Owner disconnected")
v:Destruct()
end
end
end)

hook.Add("PlayerAuthed", "Wire_Expression2_Player_Authed", function(ply, sid, uid)
for _, ent in ipairs(ents.FindByClass("gmod_wire_expression2")) do
if ent.uid == uid and ent.context then
ent.context.player = ply
ent.player = ply
if ent.uid == uid then
E2Lib.PlayerChips[ply] = E2Lib.PlayerChips[ply] or {}
table.insert(E2Lib.PlayerChips[ply], ent)
ent:SetNWEntity("player", ply)
ent:SetPlayer(ply)

if ent.disconnectPaused then
ent:SetColor(ent.disconnectPaused)
ent:SetRenderMode(ent:GetColor().a == 255 and RENDERMODE_NORMAL or RENDERMODE_TRANSALPHA)
ent.error = false
ent.disconnectPaused = nil
ent:SetOverlayText(ent.name)
end
end
end
for _, ent in ipairs(ents.FindByClass("gmod_wire_hologram")) do
if ent.steamid == sid then
ent:SetPlayer(ply)
ent.player = ply
end
end
end)
Expand All @@ -781,10 +818,10 @@ function MakeWireExpression2(player, Pos, Ang, model, buffer, name, inputs, outp
self:SetModel(model)
self:SetAngles(Ang)
self:SetPos(Pos)
self:Spawn()
self:SetPlayer(player)
self.player = player
self:SetNWEntity("player", player)
self.player = player
self:Spawn()

if isstring( buffer ) then -- if someone dupes an E2 with compile errors, then all these values will be invalid
buffer = string.Replace(string.Replace(buffer, string.char(163), "\""), string.char(128), "\n")
Expand Down
2 changes: 1 addition & 1 deletion lua/entities/gmod_wire_expression2/shared.lua
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ CreateConVar("wire_expression2_unlimited", "0", {FCVAR_REPLICATED})
CreateConVar("wire_expression2_quotasoft", "10000", {FCVAR_REPLICATED})
CreateConVar("wire_expression2_quotahard", "100000", {FCVAR_REPLICATED})
CreateConVar("wire_expression2_quotatick", "25000", {FCVAR_REPLICATED})
CreateConVar("wire_expression2_quotatime", "-1", {FCVAR_REPLICATED}, "Time in (ms) the e2 can consume before killing (-1 is infinite)")
CreateConVar("wire_expression2_quotatime", "-1", {FCVAR_REPLICATED}, "Time in (ms) that all E2s of one player can consume before killing (-1 is infinite)")

include("core/e2lib.lua")
include("base/debug.lua")
Expand Down
Loading