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

417 lines
11 KiB
Lua

AddCSLuaFile()
DEFINE_BASECLASS( "base_wire_entity" )
ENT.PrintName = "Wire Holographic Emitter"
ENT.RenderGroup = RENDERGROUP_BOTH
ENT.WireDebugName = "Holographic Emitter"
if CLIENT then
local cvar = CreateClientConVar("cl_wire_holoemitter_maxfadetime",5,true,false) -- "cl_" in the cvar name isn't very neat... probably too late to change it now, though.
local keeplatest = CreateClientConVar("wire_holoemitter_keeplatestdot", "0", true, false)
-- Materials
local matbeam = Material( "tripmine_laser" )
local matpoint = Material( "sprites/gmdm_pickups/light" )
function ENT:Initialize()
self.Points = {}
self.RBound = Vector(1024,1024,1024)
end
function ENT:AddPoint( Pos, Local, Color, DieTime, LineBeam, GroundBeam, Size )
if Local ~= nil and Color ~= nil and DieTime ~= nil and LineBeam ~= nil and GroundBeam ~= nil and Size ~= nil then
local point = {}
point.Pos = Pos
point.Local = Local
point.Color = Color
point.LineBeam = LineBeam
point.GroundBeam = GroundBeam
point.Size = Size
if DieTime ~= 0 then
point.DieTime = CurTime() + DieTime
end
point.SpawnTime = CurTime()
self.Points[#self.Points+1] = point
end
end
net.Receive("WireHoloEmitterData", function(netlen)
local ent = net.ReadEntity()
if not IsValid(ent) then return end
local syncinterval = net.ReadFloat()
local count = net.ReadUInt(16)
for i=1, count do
local pos = net.ReadVector()
local lcl = net.ReadBit() ~= 0
local color = Color(net.ReadUInt(8),net.ReadUInt(8),net.ReadUInt(8))
local dietime = net.ReadUInt(16)/100
local linebeam = net.ReadBit() ~= 0
local groundbeam = net.ReadBit() ~= 0
local size = net.ReadUInt(16)/100
timer.Simple(i/count*syncinterval,function()
if IsValid(ent) then
ent:AddPoint(pos, lcl, color, dietime, linebeam, groundbeam, size)
end
end)
end
end)
function ENT:Think()
self:NextThink( CurTime() )
if (self:GetNWBool( "Clear", false ) == true) then
self.Points = {}
return true
end
if not next(self.Points) then return true end
-- To make it visible across the entire map
local p = LocalPlayer():GetPos()
self:SetRenderBoundsWS( p - self.RBound, p + self.RBound )
local cvarnum = cvar:GetFloat()
for k=#self.Points,1,-1 do
local v = self.Points[k]
if k == #self.Points and keeplatest:GetBool() then continue end -- Check keep latest convar
if v.DieTime then
v.Color.a = 255-(CurTime()-v.SpawnTime)/(v.DieTime-v.SpawnTime)*255 -- Set alpha
if v.DieTime < CurTime() then -- If the point's time has passed, remove it
table.remove( self.Points, k )
if self.Points[k-1] then self.Points[k-1].LineBeam = false end -- Don't draw a line to this point anymore
end
end
if cvarnum ~= 0 and v.SpawnTime + cvarnum < CurTime() then -- If the clientside time limit is shorter than the DieTime
table.remove( self.Points, k )
if self.Points[k-1] then self.Points[k-1].LineBeam = false end -- Don't draw a line to this point anymore
end
end
return true
end
function ENT:Draw()
BaseClass.Draw(self)
local ent = self:GetNWEntity( "Link", false )
if not IsValid(ent) then ent = self end
local forcelocal = false
if ent:GetClass() == "gmod_wire_hologrid" then
local temp = ent:GetNWEntity( "reference", false )
if IsValid(temp) then
ent = temp
forcelocal = true
end
end
local selfpos = ent:GetPos()
local n = #self.Points
if (n == 0 or self:GetNWBool("Active",true) == false) then return end
for k=1, n do
local v = self.Points[k]
local Pos = v.Pos
if (v.Local or forcelocal) then
Pos = ent:LocalToWorld( Pos )
end
if (v.GroundBeam) then
render.SetMaterial( matbeam )
render.DrawBeam(
selfpos,
Pos,
v.Size,
0,1,
v.Color
)
end
if (v.LineBeam and k < n) then
render.SetMaterial( matbeam )
local NextPoint = self.Points[k+1]
local NextPos = NextPoint.Pos
if (NextPoint.Local or forcelocal) then
NextPos = ent:LocalToWorld( NextPos )
end
render.DrawBeam(
NextPos,
Pos,
v.Size * 2,
0, 1,
v.Color
)
end
render.SetMaterial( matpoint )
render.DrawSprite(
Pos,
v.Size, v.Size,
v.Color
)
end
end
return -- No more client
end
-- Server
local cvar = CreateConVar("wire_holoemitter_interval",0.3,{FCVAR_ARCHIVE,FCVAR_NOTIFY})
function ENT:Initialize( )
self:PhysicsInit( SOLID_VPHYSICS )
self:SetMoveType( MOVETYPE_VPHYSICS )
self:SetSolid( SOLID_VPHYSICS )
self:DrawShadow( false )
self:SetNWBool( "Clear", false )
self:SetNWBool( "Active", true )
self.bools = {}
self.bools.Local = true
self.bools.LineBeam = true
self.bools.GroundBeam = true
self.Inputs = WireLib.CreateInputs( self, { "Pos [VECTOR]", "X" , "Y", "Z", "Local", "Color [VECTOR]", "FadeTime", "LineBeam", "GroundBeam", "Size", "Clear", "Active" } )
self.Outputs = WireLib.CreateOutputs( self, { "Memory" } ) -- Compatibility for older hispeed devices (such as gpu/cpu)
self.Points = {}
self.Data = {}
self.Data.Pos = Vector(0,0,0)
self.Data.Local = false
self.Data.Color = Vector(255,255,255)
self.Data.FadeTime = 1
self.Data.LineBeam = false
self.Data.GroundBeam = false
self.Data.Size = 1
self:SetOverlayText( "Holo Emitter" )
end
function ENT:AddPoint()
self.Points[#self.Points+1] = {
Pos = Vector(self.Data.Pos.x,self.Data.Pos.y,self.Data.Pos.z),
Local = self.Data.Local,
Color = Vector(self.Data.Color.x,self.Data.Color.y,self.Data.Color.z),
FadeTime = self.Data.FadeTime,
LineBeam = self.Data.LineBeam,
GroundBeam = self.Data.GroundBeam,
Size = self.Data.Size,
}
end
function ENT:TriggerInput( name, value )
if (name == "X") then -- X
if (self.Data.Pos.x != value) then
self.Data.Pos.x = value
self:AddPoint()
end
elseif (name == "Y") then -- Y
if (self.Data.Pos.y != value) then
self.Data.Pos.y = value
self:AddPoint()
end
elseif (name == "Z") then -- Z
if (self.Data.Pos.z != value) then
self.Data.Pos.z = value
self:AddPoint()
end
elseif (name == "Pos") then -- XYZ
if (self.Data.Pos != value) then
self.Data.Pos = value
self:AddPoint()
end
else
-- Clear & Active
if (name == "Clear" or name == "Active") then
self:SetNWBool(name,!(value == 0 and true) or false)
else
-- Other data
if (self.bools[name]) then value = !(value == 0 and true) or false end
self.Data[name] = value
end
end
end
-- Hispeed info
-- 0 = Draw (when changed, draws point) (if used in readcell, returns whether or not you are allowed to draw any more this interval)
-- 1 = X
-- 2 = Y
-- 3 = Z
-- 4 = Local (1/0)
-- 5 = R
-- 6 = G
-- 7 = B
-- 8 = FadeTime
-- 9 = LineBeam
-- 10 = GroundBeam
-- 11 = Size
-- 12 = Clear (removes all dots when = 1)
-- 13 = Active
function ENT:ReadCell( Address )
Address = math.floor(Address)
if (Address == 0) then
return 1
elseif (Address == 1) then
return self.Data.Pos.x
elseif (Address == 2) then
return self.Data.Pos.y
elseif (Address == 3) then
return self.Data.Pos.z
elseif (Address == 4) then
return (self.Data.Local and 1 or 0)
elseif (Address == 5) then
return self.Data.Color.x
elseif (Address == 6) then
return self.Data.Color.y
elseif (Address == 7) then
return self.Data.Color.z
elseif (Address == 8) then
return self.Data.FadeTime
elseif (Address == 9) then
return (self.Data.LineBeam and 1 or 0)
elseif (Address == 10) then
return (self.Data.GroundBeam and 1 or 0)
elseif (Address == 11) then
return self.Data.Size
elseif (Address == 12) then
return (self:GetNWBool("Clear",false) and 1 or 0)
elseif (Address == 13) then
return (self:GetNWBool("Active",true) and 1 or 0)
end
end
function ENT:WriteCell( Address, value )
Address = math.floor(Address)
if (Address == 0) then
self:AddPoint()
return true
elseif (Address == 1) then
self.Data.Pos.x = value
return true
elseif (Address == 2) then
self.Data.Pos.y = value
return true
elseif (Address == 3) then
self.Data.Pos.z = value
return true
elseif (Address == 4) then
self.Data.Local = value ~= 0
return true
elseif (Address == 5) then
self.Data.Color.x = value
return true
elseif (Address == 6) then
self.Data.Color.y = value
return true
elseif (Address == 7) then
self.Data.Color.z = value
return true
elseif (Address == 8) then
self.Data.FadeTime = value
return true
elseif (Address == 9) then
self.Data.LineBeam = !(value == 0 and true) or false
return true
elseif (Address == 10) then
self.Data.GroundBeam = !(value == 0 and true) or false
return true
elseif (Address == 11) then
self.Data.Size = value
return true
elseif (Address == 12) then
self:SetNWBool( "Clear", !(value == 0 and true) or false )
return true
elseif (Address == 13) then
self:SetNWBool( "Active", !(value == 0 and true) or false )
return true
end
return false
end
function ENT:Link( ent )
if IsValid(ent) and ent:GetClass() == "gmod_wire_hologrid" then -- Remove "Local" input if linking to a hologrid
WireLib.AdjustInputs( self, { "Pos [VECTOR]", "X" , "Y", "Z", "Color [VECTOR]", "FadeTime", "LineBeam", "GroundBeam", "Size", "Clear", "Active" } )
else
local old = self:GetNWEntity( "Link" )
if IsValid(old) and old:GetClass() == "gmod_wire_hologrid" then -- Put the "Local" input back
WireLib.AdjustInputs( self, { "Pos [VECTOR]", "X" , "Y", "Z", "Local", "Color [VECTOR]", "FadeTime", "LineBeam", "GroundBeam", "Size", "Clear", "Active" } )
end
end
self:SetNWEntity( "Link", ent )
end
function ENT:UnLink()
local old = self:GetNWEntity( "Link" )
if IsValid(old) and old:GetClass() == "gmod_wire_hologrid" then -- Put the "Local" input back
WireLib.AdjustInputs( self, { "Pos [VECTOR]", "X" , "Y", "Z", "Local", "Color [VECTOR]", "FadeTime", "LineBeam", "GroundBeam", "Size", "Clear", "Active" } )
end
self:SetNWEntity( "Link", NULL )
end
util.AddNetworkString("WireHoloEmitterData")
function ENT:Think()
self:NextThink( CurTime() + cvar:GetFloat() )
if not next(self.Points) then return true end
net.Start("WireHoloEmitterData")
net.WriteEntity(self)
net.WriteFloat(cvar:GetFloat()) -- send sync interval
net.WriteUInt(#self.Points, 16) -- send nr of points
for _,v in pairs( self.Points ) do -- send each point
net.WriteVector(v.Pos)
net.WriteBit(v.Local)
net.WriteUInt(v.Color.x,8)
net.WriteUInt(v.Color.y,8)
net.WriteUInt(v.Color.z,8)
net.WriteUInt(math.Clamp(v.FadeTime,0,100)*100,16)
net.WriteBit(v.LineBeam)
net.WriteBit(v.GroundBeam)
net.WriteUInt(math.Clamp(v.Size,0,100)*100, 16)
end
net.Broadcast()
self.Points = {}
return true
end
duplicator.RegisterEntityClass("gmod_wire_holoemitter", WireLib.MakeWireEnt, "Data")
function ENT:UpdateTransmitState()
return TRANSMIT_ALWAYS
end
function ENT:BuildDupeInfo()
local info = BaseClass.BuildDupeInfo(self) or {}
local link = self:GetNWEntity("Link",false)
if (link) then
info.holoemitter_link = link:EntIndex()
end
return info
end
function ENT:ApplyDupeInfo(ply, ent, info, GetEntByID)
BaseClass.ApplyDupeInfo(self, ply, ent, info, GetEntByID)
self:Link(GetEntByID(info.holoemitter_link))
end