dobrograd-13-06-2022/garrysmod/addons/feature-wire/lua/entities/gmod_wire_hologram.lua
Jonny_Bro (Nikita) e4d5311906 first commit
2023-11-16 15:01:19 +05:00

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