417 lines
11 KiB
Lua
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
|