Skip to content

Instantly share code, notes, and snippets.

@swampservers
Last active July 10, 2021 18:56
Show Gist options
  • Save swampservers/15f48ea3c0898a369a61e9e84e347e8d to your computer and use it in GitHub Desktop.
Save swampservers/15f48ea3c0898a369a61e9e84e347e8d to your computer and use it in GitHub Desktop.
Garrysmod - Clientside material override patch
-- Mostly-fix for https://github.com/Facepunch/garrysmod-issues/issues/3362 and 4953
-- This won't well if you're trying to set material overrides on the same entity on both the server and client.
-- Also calling SetMaterial() or SetSubMaterial() will reset both materials and submaterials.
-- Put this in lua/autorun/client/materialfix.lua
-- A set of entities which have appeared recently and have clientside material overrides
local watchlist = {}
-- It seems to take about 5 ticks/0.2 sec from when the entity enters PVS to
-- when it reapplies its server material setting (but the time is inconsistent)
-- I couldn't find any hacky way to detect it so this is what you get.
hook.Add("Tick", "ClientForceMaterial", function()
local cutoff = CurTime() - (0.5 + (IsValid(LocalPlayer()) and LocalPlayer():Ping() / 1000 or 1))
for ent, _ in pairs(watchlist) do
if not IsValid(ent) or (ent.CFM_AppearTime or 0) < cutoff or not ent.CLIENTFORCEDMATERIAL then
watchlist[ent] = nil
else
for idx, mat in pairs(ent.CLIENTFORCEDMATERIAL) do
if idx == -1 then
ent:BasedSetMaterial(mat)
else
ent:BasedSetSubMaterial(idx, mat)
end
end
end
end
end)
hook.Add("NetworkEntityCreated", "ClientForceMaterial2", function(ent)
ent.CFM_AppearTime = CurTime()
if ent.CLIENTFORCEDMATERIAL then
watchlist[ent] = true
end
end)
hook.Add("NotifyShouldTransmit", "ClientForceMaterial3", function(ent, trans)
ent.CFM_AppearTime = CurTime()
watchlist[ent] = (ent.CLIENTFORCEDMATERIAL and trans) or nil
end)
local Entity = FindMetaTable("Entity")
Entity.BasedGetMaterial = Entity.BasedGetMaterial or Entity.GetMaterial
Entity.BasedSetMaterial = Entity.BasedSetMaterial or Entity.SetMaterial
Entity.BasedGetSubMaterial = Entity.BasedGetSubMaterial or Entity.GetSubMaterial
Entity.BasedSetSubMaterial = Entity.BasedSetSubMaterial or Entity.SetSubMaterial
function Entity:GetMaterial()
return (self.CLIENTFORCEDMATERIAL or {})[-1] or self:BasedGetMaterial()
end
function Entity:GetSubMaterial(idx)
return (self.CLIENTFORCEDMATERIAL or {})[idx] or self:BasedGetSubMaterial(idx)
end
function Entity:SetMaterial(mat)
self:SetSubMaterial(-1, mat)
end
function Entity:SetSubMaterial(idx, mat)
if idx == nil or (idx == -1 and mat == nil) then
self.CLIENTFORCEDMATERIAL = nil
watchlist[self] = nil
else
local t = self.CLIENTFORCEDMATERIAL
if not t then
t = {}
self.CLIENTFORCEDMATERIAL = t
end
t[idx] = mat
watchlist[self] = true
end
if idx == -1 then
self:BasedSetMaterial(mat)
else
self:BasedSetSubMaterial(idx, mat)
end
if idx then
local t = self.CLIENTFORCEDMATERIAL
if not t then
t = {}
self.CLIENTFORCEDMATERIAL = t
end
t[idx] = mat
else
self.CLIENTFORCEDMATERIAL = nil
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment