393 lines
9.6 KiB
Lua
393 lines
9.6 KiB
Lua
AddCSLuaFile()
|
|
DEFINE_BASECLASS("base_anim") -- NOTE: Not base_wire_entity! Simpler than that
|
|
ENT.PrintName = "Wire Hologram"
|
|
ENT.RenderGroup = RENDERGROUP_OPAQUE
|
|
ENT.DisableDuplicator = true
|
|
|
|
function ENT:SetPlayer(ply)
|
|
self:SetVar("Founder", ply)
|
|
self:SetVar("FounderIndex", ply:UniqueID())
|
|
|
|
self:SetNWString("FounderName", ply:Nick())
|
|
end
|
|
|
|
function ENT:GetPlayer()
|
|
return self:GetVar("Founder", NULL)
|
|
end
|
|
|
|
if CLIENT then
|
|
local blocked = {}
|
|
local scale_buffer = {}
|
|
local bone_scale_buffer = {}
|
|
local clip_buffer = {}
|
|
local vis_buffer = {}
|
|
local player_color_buffer = {}
|
|
|
|
function ENT:Initialize()
|
|
self.bone_scale = {}
|
|
self:DoScale()
|
|
local ownerid = self:GetNWInt("ownerid")
|
|
self.blocked = blocked[ownerid] or false
|
|
|
|
self.clips = {}
|
|
self:DoClip()
|
|
self:DoVisible()
|
|
self:DoPlayerColor()
|
|
end
|
|
|
|
hook.Add("PlayerBindPress", "wire_hologram_scale_setup", function() -- For initial spawn
|
|
for _, ent in pairs(ents.FindByClass("gmod_wire_hologram")) do
|
|
if ent:IsValid() and ent.DoScale then
|
|
ent:DoScale()
|
|
ent:DoClip()
|
|
ent:DoVisible()
|
|
ent:DoPlayerColor()
|
|
end
|
|
end
|
|
hook.Remove("PlayerBindPress", "wire_hologram_scale_setup")
|
|
end)
|
|
|
|
function ENT:SetupClipping()
|
|
if next(self.clips) then
|
|
self.oldClipState = render.EnableClipping(true)
|
|
|
|
for _, clip in pairs(self.clips) do
|
|
if clip.enabled and clip.normal and clip.origin then
|
|
local norm = clip.normal
|
|
local origin = clip.origin
|
|
|
|
if clip.localentid then
|
|
local localent = Entity(clip.localentid)
|
|
if localent:IsValid() then
|
|
norm = localent:LocalToWorld(norm) - localent:GetPos()
|
|
origin = localent:LocalToWorld(origin)
|
|
end
|
|
end
|
|
|
|
render.PushCustomClipPlane(norm, norm:Dot(origin))
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function ENT:FinishClipping()
|
|
if next(self.clips) then
|
|
for _, clip in pairs(self.clips) do
|
|
render.PopCustomClipPlane()
|
|
end
|
|
|
|
render.EnableClipping(self.oldClipState)
|
|
end
|
|
end
|
|
|
|
function ENT:Draw()
|
|
if self.blocked or self.notvisible then return end
|
|
|
|
if self:GetColor().a ~= 255 then
|
|
self.RenderGroup = RENDERGROUP_BOTH
|
|
else
|
|
self.RenderGroup = RENDERGROUP_OPAQUE
|
|
end
|
|
|
|
self:SetupClipping()
|
|
|
|
if self:GetNWBool("disable_shading") then
|
|
render.SuppressEngineLighting(true)
|
|
self:DrawModel()
|
|
render.SuppressEngineLighting(false)
|
|
else
|
|
self:DrawModel()
|
|
end
|
|
|
|
self:FinishClipping()
|
|
end
|
|
|
|
-- -----------------------------------------------------------------------------
|
|
|
|
function ENT:DoClip()
|
|
local eidx = self:EntIndex()
|
|
|
|
if clip_buffer[eidx] ~= nil then
|
|
table.Merge(self.clips, clip_buffer[eidx])
|
|
clip_buffer[eidx] = nil
|
|
end
|
|
end
|
|
|
|
local function CheckClip(eidx, cidx)
|
|
clip_buffer[eidx] = clip_buffer[eidx] or {}
|
|
clip_buffer[eidx][cidx] = clip_buffer[eidx][cidx] or {}
|
|
|
|
return clip_buffer[eidx][cidx]
|
|
end
|
|
|
|
local function SetClipEnabled(eidx, cidx, enabled)
|
|
local clip = CheckClip(eidx, cidx)
|
|
|
|
clip.enabled = enabled
|
|
end
|
|
|
|
local function SetClip(eidx, cidx, origin, norm, localentid)
|
|
local clip = CheckClip(eidx, cidx)
|
|
|
|
clip.normal = norm
|
|
clip.origin = origin
|
|
|
|
if localentid ~= 0 then
|
|
clip.localentid = localentid
|
|
else
|
|
clip.localentid = nil
|
|
end
|
|
end
|
|
|
|
net.Receive("wire_holograms_clip", function(netlen)
|
|
local entid = net.ReadUInt(16)
|
|
|
|
while entid ~= 0 do
|
|
local clipid = net.ReadUInt(4)
|
|
|
|
if net.ReadBit() ~= 0 then
|
|
SetClipEnabled(entid, clipid, net.ReadBit() ~= 0)
|
|
else
|
|
SetClip(entid, clipid, net.ReadVector(), Vector(net.ReadFloat(), net.ReadFloat(), net.ReadFloat()), net.ReadUInt(16))
|
|
end
|
|
local ent = Entity(entid)
|
|
if ent and ent.DoClip then
|
|
ent:DoClip()
|
|
end
|
|
entid = net.ReadUInt(16)
|
|
end
|
|
end)
|
|
|
|
-- -----------------------------------------------------------------------------
|
|
|
|
local function SetScale(entindex, scale)
|
|
scale_buffer[entindex] = scale
|
|
|
|
local ent = Entity(entindex)
|
|
|
|
if ent and ent.DoScale then
|
|
ent:DoScale()
|
|
end
|
|
end
|
|
|
|
local function SetBoneScale(entindex, bindex, scale)
|
|
if bone_scale_buffer[entindex] == nil then bone_scale_buffer[entindex] = {} end
|
|
|
|
if bindex == -1 then
|
|
bone_scale_buffer[entindex] = nil
|
|
else
|
|
bone_scale_buffer[entindex][bindex] = scale
|
|
end
|
|
|
|
local ent = Entity(entindex)
|
|
|
|
if ent and ent.DoScale then
|
|
if bindex == -1 then ent.bone_scale = {} end -- reset bone scale
|
|
ent:DoScale()
|
|
end
|
|
end
|
|
|
|
function ENT:DoScale()
|
|
local eidx = self:EntIndex()
|
|
|
|
if scale_buffer[eidx] ~= nil then
|
|
self.scale = scale_buffer[eidx]
|
|
scale_buffer[eidx] = nil
|
|
end
|
|
|
|
if bone_scale_buffer[eidx] ~= nil then
|
|
for b, s in pairs(bone_scale_buffer[eidx]) do
|
|
self.bone_scale[b] = s
|
|
end
|
|
bone_scale_buffer[eidx] = {}
|
|
end
|
|
|
|
local scale = self.scale or Vector(1, 1, 1)
|
|
|
|
if self.EnableMatrix then
|
|
local mat = Matrix()
|
|
mat:Scale(Vector(scale.x, scale.y, scale.z))
|
|
self:EnableMatrix("RenderMultiply", mat)
|
|
else
|
|
-- Some entities, like ragdolls, cannot be resized with EnableMatrix, so lets average the three components to get a float
|
|
self:SetModelScale((scale.x + scale.y + scale.z) / 3, 0)
|
|
end
|
|
|
|
if table.Count( self.bone_scale ) > 0 then
|
|
local count = self:GetBoneCount() or -1
|
|
|
|
for i = count, 0, -1 do
|
|
local bone_scale = self.bone_scale[i] or Vector(1,1,1)
|
|
self:ManipulateBoneScale(i, bone_scale) // Note: Using ManipulateBoneScale currently causes RenderBounds to be reset every frame!
|
|
end
|
|
end
|
|
|
|
local propmax = self:OBBMaxs()
|
|
local propmin = self:OBBMins()
|
|
self:SetRenderBounds(Vector(scale.x * propmin.x, scale.y * propmin.y, scale.z * propmin.z),Vector(scale.x * propmax.x, scale.y * propmax.y, scale.z * propmax.z))
|
|
end
|
|
|
|
net.Receive("wire_holograms_set_scale", function(netlen)
|
|
local index = net.ReadUInt(16)
|
|
|
|
while index ~= 0 do
|
|
SetScale(index, Vector(net.ReadFloat(), net.ReadFloat(), net.ReadFloat()))
|
|
index = net.ReadUInt(16)
|
|
end
|
|
end)
|
|
|
|
net.Receive("wire_holograms_set_bone_scale", function(netlen)
|
|
local index = net.ReadUInt(16)
|
|
local bindex = net.ReadUInt(16) - 1 -- using -1 to get negative -1 for reset
|
|
|
|
while index ~= 0 do
|
|
SetBoneScale(index, bindex, Vector(net.ReadFloat(), net.ReadFloat(), net.ReadFloat()))
|
|
index = net.ReadUInt(16)
|
|
bindex = net.ReadUInt(16) - 1
|
|
end
|
|
end)
|
|
|
|
-- -----------------------------------------------------------------------------
|
|
|
|
function ENT:DoVisible()
|
|
local eidx = self:EntIndex()
|
|
|
|
if vis_buffer[eidx] ~= nil then
|
|
self.notvisible = vis_buffer[eidx]
|
|
vis_buffer[eidx] = nil
|
|
end
|
|
end
|
|
|
|
net.Receive("wire_holograms_set_visible", function(netlen)
|
|
local index = net.ReadUInt(16)
|
|
|
|
while index ~= 0 do
|
|
|
|
local ent = Entity(index)
|
|
if ent and ent.DoVisible then
|
|
ent.notvisible = net.ReadBit() == 0
|
|
else
|
|
vis_buffer[index] = net.ReadBit() == 0
|
|
end
|
|
|
|
index = net.ReadUInt(16)
|
|
end
|
|
end)
|
|
|
|
-- -----------------------------------------------------------------------------
|
|
|
|
local function SetPlayerColor(entindex, color)
|
|
local ent = Entity(entindex)
|
|
-- For reference, here's why this works:
|
|
-- https://github.com/garrynewman/garrysmod/blob/master/garrysmod/lua/matproxy/player_color.lua
|
|
function ent:GetPlayerColor()
|
|
return color
|
|
end
|
|
end
|
|
|
|
function ENT:DoPlayerColor()
|
|
local eidx = self:EntIndex()
|
|
if player_color_buffer[eidx] ~= nil then
|
|
SetPlayerColor(eidx, player_color_buffer[eidx])
|
|
player_color_buffer[eidx] = nil
|
|
end
|
|
|
|
|
|
end
|
|
|
|
net.Receive("wire_holograms_set_player_color", function(netlen)
|
|
local index = net.ReadUInt(16)
|
|
|
|
while index ~= 0 do
|
|
local ent = Entity(index)
|
|
if IsValid(ent) and ent.DoPlayerColor then
|
|
SetPlayerColor(index, net.ReadVector())
|
|
else
|
|
player_color_buffer[index] = net.ReadVector()
|
|
end
|
|
|
|
index = net.ReadUInt(16)
|
|
end
|
|
end)
|
|
|
|
-- -----------------------------------------------------------------------------
|
|
|
|
concommand.Add("wire_holograms_block_client",
|
|
function(ply, command, args)
|
|
local toblock
|
|
for _, ply in ipairs(player.GetAll()) do
|
|
if ply:Name() == args[1] then
|
|
toblock = ply
|
|
break
|
|
end
|
|
end
|
|
if not toblock then error("Player not found") end
|
|
|
|
local id = toblock:UserID()
|
|
blocked[id] = true
|
|
for _, ent in ipairs(ents.FindByClass("gmod_wire_hologram")) do
|
|
if ent:GetNWInt("ownerid") == id then
|
|
ent.blocked = true
|
|
end
|
|
end
|
|
end,
|
|
function()
|
|
local names = {}
|
|
for _, ply in ipairs(player.GetAll()) do
|
|
table.insert(names, "wire_holograms_block_client \"" .. ply:Name() .. "\"")
|
|
end
|
|
table.sort(names)
|
|
return names
|
|
end)
|
|
|
|
concommand.Add("wire_holograms_unblock_client",
|
|
function(ply, command, args)
|
|
local toblock
|
|
for _, ply in ipairs(player.GetAll()) do
|
|
if ply:Name() == args[1] then
|
|
toblock = ply
|
|
break
|
|
end
|
|
end
|
|
if not toblock then error("Player not found") end
|
|
|
|
local id = toblock:UserID()
|
|
blocked[id] = nil
|
|
for _, ent in ipairs(ents.FindByClass("gmod_wire_hologram")) do
|
|
if ent:GetNWInt("ownerid") == id then
|
|
ent.blocked = false
|
|
end
|
|
end
|
|
end,
|
|
function()
|
|
local names = {}
|
|
for _, ply in ipairs(player.GetAll()) do
|
|
if blocked[ply:UserID()] then
|
|
table.insert(names, "wire_holograms_unblock_client \"" .. ply:Name() .. "\"")
|
|
end
|
|
end
|
|
table.sort(names)
|
|
return names
|
|
end)
|
|
|
|
-- Severe lagspikes can detach the source entity from its lua, so we need to reapply things when its reattached
|
|
hook.Add("NetworkEntityCreated", "wire_hologram_rescale", function(ent)
|
|
if ent.scale and ent.DoScale then
|
|
-- ent.scale isn't present on newly created holograms, only old ones that've been hit by a lagspike
|
|
ent:DoScale()
|
|
ent:DoClip()
|
|
ent:DoVisible()
|
|
ent:DoPlayerColor()
|
|
end
|
|
end)
|
|
|
|
return -- No more client
|
|
end
|
|
|
|
-- Server
|
|
|
|
function ENT:Initialize()
|
|
self:SetSolid(SOLID_NONE)
|
|
self:SetMoveType(MOVETYPE_NONE)
|
|
self:DrawShadow(false)
|
|
end
|