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

404 lines
12 KiB
Lua

AddCSLuaFile()
DEFINE_BASECLASS( "base_wire_entity" )
ENT.PrintName = "Wire Socket"
ENT.Purpose = "Links with a plug"
ENT.Instructions = "Move a plug close to a plug to link them, and data will be transferred through the link."
ENT.WireDebugName = "Socket"
local PositionOffsets = {
["models/wingf0x/isasocket.mdl"] = Vector(0,0,0),
["models/wingf0x/altisasocket.mdl"] = Vector(0,0,2.6),
["models/wingf0x/ethernetsocket.mdl"] = Vector(0,0,0),
["models/wingf0x/hdmisocket.mdl"] = Vector(0,0,0),
["models/props_lab/tpplugholder_single.mdl"] = Vector(5, 13, 10),
["models/bull/various/usb_socket.mdl"] = Vector(8,0,0),
["models/hammy/pci_slot.mdl"] = Vector(0,0,0),
["models//hammy/pci_slot.mdl"] = Vector(0,0,0), -- For some reason, GetModel on this model has two / on the client... Bug?
}
local AngleOffsets = {
["models/wingf0x/isasocket.mdl"] = Angle(0,0,0),
["models/wingf0x/altisasocket.mdl"] = Angle(0,0,0),
["models/wingf0x/ethernetsocket.mdl"] = Angle(0,0,0),
["models/wingf0x/hdmisocket.mdl"] = Angle(0,0,0),
["models/props_lab/tpplugholder_single.mdl"] = Angle(0,0,0),
["models/bull/various/usb_socket.mdl"] = Angle(0,0,0),
["models/hammy/pci_slot.mdl"] = Angle(0,0,0),
["models//hammy/pci_slot.mdl"] = Angle(0,0,0), -- For some reason, GetModel on this model has two / on the client... Bug?
}
local SocketModels = {
["models/wingf0x/isasocket.mdl"] = "models/wingf0x/isaplug.mdl",
["models/wingf0x/altisasocket.mdl"] = "models/wingf0x/isaplug.mdl",
["models/wingf0x/ethernetsocket.mdl"] = "models/wingf0x/ethernetplug.mdl",
["models/wingf0x/hdmisocket.mdl"] = "models/wingf0x/hdmiplug.mdl",
["models/props_lab/tpplugholder_single.mdl"] = "models/props_lab/tpplug.mdl",
["models/bull/various/usb_socket.mdl"] = "models/bull/various/usb_stick.mdl",
["models/hammy/pci_slot.mdl"] = "models/hammy/pci_card.mdl",
["models//hammy/pci_slot.mdl"] = "models//hammy/pci_card.mdl", -- For some reason, GetModel on this model has two / on the client... Bug?
}
function ENT:GetLinkPos()
return self:LocalToWorld(PositionOffsets[self:GetModel()] or Vector(0,0,0)), self:LocalToWorldAngles(AngleOffsets[self:GetModel()] or Angle(0,0,0))
end
function ENT:CanLink( Target )
if (Target.Socket and Target.Socket:IsValid()) then return false end
if (SocketModels[self:GetModel()] ~= Target:GetModel()) then return false end
return true
end
function ENT:GetClosestPlug()
local Pos, _ = self:GetLinkPos()
local plugs = ents.FindInSphere( Pos, (CLIENT and self:GetNWInt( "AttachRange", 5 ) or self.AttachRange) )
local ClosestDist
local Closest
for k,v in pairs( plugs ) do
if (v:GetClass() == self:GetPlugClass() and not v:GetNWBool( "Linked", false )) then
local Dist = v:GetPos():Distance( Pos )
if (ClosestDist == nil or ClosestDist > Dist) then
ClosestDist = Dist
Closest = v
end
end
end
return Closest
end
function ENT:GetPlugClass()
return "gmod_wire_plug"
end
if CLIENT then
function ENT:DrawEntityOutline()
if (GetConVar("wire_plug_drawoutline"):GetBool()) then
BaseClass.DrawEntityOutline( self )
end
end
-- hook.Add("HUDPaint","Wire_Socket_DrawLinkHelperLine",function()
-- local sockets = ents.FindByClass("gmod_wire_socket")
-- for k,self in pairs( sockets ) do
-- local Pos, _ = self:GetLinkPos()
-- local Closest = self:GetClosestPlug()
-- if IsValid(Closest) and self:CanLink(Closest) and Closest:GetNWBool( "PlayerHolding", false ) and Closest:GetClosestSocket() == self then
-- local plugpos = Closest:GetPos():ToScreen()
-- local socketpos = Pos:ToScreen()
-- surface.SetDrawColor(255,255,100,255)
-- surface.DrawLine(plugpos.x, plugpos.y, socketpos.x, socketpos.y)
-- end
-- end
-- end)
return -- No more client
end
local NEW_PLUG_WAIT_TIME = 2
local LETTERS = { "A", "B", "C", "D", "E", "F", "G", "H" }
local LETTERS_INV = {}
for k,v in pairs( LETTERS ) do
LETTERS_INV[v] = k
end
function ENT:Initialize()
self:PhysicsInit( SOLID_VPHYSICS )
self:SetMoveType( MOVETYPE_VPHYSICS )
self:SetSolid( SOLID_VPHYSICS )
self:SetNWBool( "Linked", false )
self.Memory = {}
self.DoNextThink = CurTime() + 5 -- wait 5 seconds
end
function ENT:Setup( ArrayInput, WeldForce, AttachRange )
local old = self.ArrayInput
self.ArrayInput = ArrayInput or false
if not (self.Inputs and self.Outputs and self.ArrayInput == old) then
if (self.ArrayInput) then
self.Inputs = WireLib.CreateInputs( self, { "In [ARRAY]" } )
self.Outputs = WireLib.CreateOutputs( self, { "Out [ARRAY]" } )
else
self.Inputs = WireLib.CreateInputs( self, LETTERS )
self.Outputs = WireLib.CreateOutputs( self, LETTERS )
end
end
self.WeldForce = WeldForce or 5000
self.AttachRange = AttachRange or 5
self:SetNWInt( "AttachRange", self.AttachRange )
self:ShowOutput()
end
function ENT:TriggerInput( name, value )
if (self.Plug and self.Plug:IsValid()) then
self.Plug:SetValue( name, value )
end
self:ShowOutput()
end
function ENT:SetValue( name, value )
if not (self.Plug and self.Plug:IsValid()) then return end
if (name == "In") then
if (self.ArrayInput) then -- Both have array
WireLib.TriggerOutput( self, "Out", table.Copy( value ) )
else -- Target has array, this does not
for i=1,#LETTERS do
local val = (value or {})[i]
if isnumber(val) then
WireLib.TriggerOutput( self, LETTERS[i], val )
end
end
end
else
if (self.ArrayInput) then -- Target does not have array, this does
if (value ~= nil) then
local data = table.Copy( self.Outputs.Out.Value )
data[LETTERS_INV[name]] = value
WireLib.TriggerOutput( self, "Out", data )
end
else -- Niether have array
if (value ~= nil) then
WireLib.TriggerOutput( self, name, value )
end
end
end
self:ShowOutput()
end
------------------------------------------------------------
-- WriteCell
-- Hi-speed support
------------------------------------------------------------
function ENT:WriteCell( Address, Value, WriteToMe )
Address = math.floor(Address)
if (WriteToMe) then
self.Memory[Address or 1] = Value or 0
return true
else
if (self.Plug and self.Plug:IsValid()) then
self.Plug:WriteCell( Address, Value, true )
return true
else
return false
end
end
end
------------------------------------------------------------
-- ReadCell
-- Hi-speed support
------------------------------------------------------------
function ENT:ReadCell( Address )
Address = math.floor(Address)
return self.Memory[Address or 1] or 0
end
function ENT:ResetValues()
if (self.ArrayInput) then
WireLib.TriggerOutput( self, "Out", {} )
else
for i=1,#LETTERS do
WireLib.TriggerOutput( self, LETTERS[i], 0 )
end
end
self.Memory = {}
self:ShowOutput()
end
------------------------------------------------------------
-- ResendValues
-- Resends the values when plugging in
------------------------------------------------------------
function ENT:ResendValues()
if (not self.Plug) then return end
if (self.ArrayInput) then
self.Plug:SetValue( "In", self.Inputs.In.Value )
else
for i=1,#LETTERS do
self.Plug:SetValue( LETTERS[i], self.Inputs[LETTERS[i]].Value )
end
end
end
function ENT:OnWeldRemoved()
self.Weld = nil
self.Plug:SetNWBool( "Linked", false )
self:SetNWBool( "Linked", false )
self.Plug.Socket = nil
self.Plug:ResetValues()
self.Plug = nil
self:ResetValues()
self.DoNextThink = CurTime() + NEW_PLUG_WAIT_TIME
end
function ENT:AttachWeld(weld)
if self.Plug then self.Plug:DeleteOnRemove( weld ) end
self:DeleteOnRemove( weld )
if self.Weld then self.Weld:RemoveCallOnRemove("wire_socket_remove_on_weld") end
self.Weld = weld
weld:CallOnRemove("wire_socket_remove_on_weld",function() self:OnWeldRemoved() end)
end
-- helper function
local function FindConstraint( ent, plug )
if IsValid(ent) then
local welds = constraint.FindConstraints( ent, "Weld" )
for k,v in pairs( welds ) do
if (v.Ent2 == plug) then
return v.Constraint
end
end
end
if IsValid(plug) then
local welds = constraint.FindConstraints( plug, "Weld" )
for k,v in pairs( welds ) do
if (v.Ent2 == ent) then
return v.Constraint
end
end
end
end
------------------------------------------------------------
-- Think
-- Find nearby plugs and connect to them
------------------------------------------------------------
function ENT:Think()
BaseClass.Think(self)
if self.DoNextThink then
self:NextThink( self.DoNextThink )
self.DoNextThink = nil
return true
end
if not IsValid(self.Plug) then -- currently not linked, check for nearby links
local Pos, Ang = self:GetLinkPos()
local Closest = self:GetClosestPlug()
if (Closest and Closest:IsValid() and self:CanLink( Closest ) and not Closest:IsPlayerHolding() and Closest:GetClosestSocket() == self) then
self.Plug = Closest
Closest.Socket = self
-- Move
Closest:SetPos( Pos )
Closest:SetAngles( Ang )
-- Weld
local weld = FindConstraint(self,Closest)
if not weld then
weld = constraint.Weld( self, Closest, 0, 0, self.WeldForce, true )
end
if weld and weld:IsValid() then self:AttachWeld(weld) end
-- Resend all values
Closest:ResendValues()
self:ResendValues()
Closest:SetNWBool( "Linked", true )
self:SetNWBool( "Linked", true )
end
self:NextThink( CurTime() + 0.05 )
return true
else
self:NextThink( CurTime() + 1 ) -- while linked, there's no point in running any faster than this
return true
end
end
function ENT:ShowOutput()
local OutText = "Socket [" .. self:EntIndex() .. "]\n"
if (self.ArrayInput) then
OutText = OutText .. "Array input/outputs."
else
OutText = OutText .. "Number input/outputs."
end
if (self.Plug and self.Plug:IsValid()) then
OutText = OutText .. "\nLinked to plug [" .. self.Plug:EntIndex() .. "]"
end
self:SetOverlayText(OutText)
end
duplicator.RegisterEntityClass( "gmod_wire_socket", WireLib.MakeWireEnt, "Data", "ArrayInput", "WeldForce", "AttachRange" )
------------------------------------------------------------
-- Adv Duplicator Support
------------------------------------------------------------
function ENT:BuildDupeInfo()
local info = BaseClass.BuildDupeInfo(self) or {}
info.Socket = {}
info.Socket.ArrayInput = self.ArrayInput
info.Socket.WeldForce = self.WeldForce
info.Socket.AttachRange = self.AttachRange
if self.Plug then
info.Socket.Plug = self.Plug:EntIndex()
else
-- if we don't write -1 here then sockets will somehow remember which plugs they used to be
-- connected to in the past after paste even though that reference no longer exists. I have no clue why
info.Socket.Plug = -1
end
return info
end
function ENT:GetApplyDupeInfoParams(info)
return info.Socket.ArrayInput, info.Socket.WeldForce, info.Socket.AttachRange
end
function ENT:ApplyDupeInfo(ply, ent, info, GetEntByID, GetConstByID)
BaseClass.ApplyDupeInfo(self, ply, ent, info, GetEntByID)
if (info.Socket) then
ent:Setup( self:GetApplyDupeInfoParams(info) )
if info.Socket.Plug ~= -1 then -- check for the strangely required -1 here (see BuildDupeInfo)
local plug = GetEntByID( info.Socket.Plug )
if IsValid(plug) then
ent.Plug = plug
plug.Socket = ent
ent.Weld = nil
plug:SetNWBool( "Linked", true )
ent:SetNWBool( "Linked", true )
-- Resend all values
plug:ResendValues()
ent:ResendValues()
-- Attempt to find connected plug
timer.Simple(0.5,function()
local weld = FindConstraint( ent, plug )
if not IsValid(weld) then
weld = constraint.Weld( self, plug, 0, 0, self.WeldForce, true )
end
if IsValid(weld) then
self:AttachWeld(weld)
end
end)
end
end
else -- OLD DUPES COMPATIBILITY
ent:Setup() -- default values
-- Attempt to find connected plug
timer.Simple(0.5,function()
local weld = FindConstraint( ent )
if IsValid(weld) then
self:AttachWeld(weld)
end
end)
end -- /OLD DUPES COMPATIBILITY
end