From 66682ea30c3ec67f825c51c6482869725c6e6064 Mon Sep 17 00:00:00 2001 From: Astralcircle <142503363+Astralcircle@users.noreply.github.com> Date: Fri, 24 Oct 2025 23:53:08 +0300 Subject: [PATCH 1/9] Add buoyancy controller --- lua/entities/gmod_wire_buoyancy.lua | 162 ++++++++++++++++++++++++++++ lua/wire/stools/buoyancy.lua | 29 +++++ 2 files changed, 191 insertions(+) create mode 100644 lua/entities/gmod_wire_buoyancy.lua create mode 100644 lua/wire/stools/buoyancy.lua diff --git a/lua/entities/gmod_wire_buoyancy.lua b/lua/entities/gmod_wire_buoyancy.lua new file mode 100644 index 0000000000..85f3f887d8 --- /dev/null +++ b/lua/entities/gmod_wire_buoyancy.lua @@ -0,0 +1,162 @@ +AddCSLuaFile() + +DEFINE_BASECLASS("base_wire_entity") +ENT.PrintName = "Wire Buoyancy" +ENT.RenderGroup = RENDERGROUP_BOTH +ENT.WireDebugName = "Buoyancy" + +if CLIENT then return end + +function ENT:Initialize() + self.Marks = {} + self:PhysicsInit(SOLID_VPHYSICS) + WireLib.CreateInputs(self, { "Percent" }) +end + +local function SetBuoyancy(ent, controller) + local phys = ent:GetPhysicsObject() + ent.WireBuoyancyController = controller + + if phys:IsValid() then + phys:SetBuoyancyRatio(controller.Percent) + phys:Wake() + end +end + +local function UpdateBuoyancy(controller) + for _, ent in ipairs(controller.Marks) do + if ent:IsValid() then + SetBuoyancy(ent, controller) + end + end +end + +function ENT:UpdateOutputs() + self:SetOverlayText(string.format("Buoyancy ratio: %.2f\nNumber of entities linked: %i", self.Percent, #self.Marks)) + WireLib.SendMarks(self) +end + +function ENT:Setup(percent) + self.Percent = math.Clamp(percent, -10, 10) + self:UpdateOutputs() + UpdateBuoyancy(self) +end + +function ENT:TriggerInput(name, value) + if name == "Percent" then + self.Percent = math.Clamp(value, -10, 10) + UpdateBuoyancy(controller) + + self:UpdateOutputs() + end +end + +-- For some reason, buoyancy is reset by the physgun and gravgun +hook.Add("PhysgunDrop", "WireBuoyancy", function(ply, ent) + if IsValid(ent.WireBuoyancyController) then + timer.Simple(0 , function() + if not IsValid(ent.WireBuoyancyController) then return end + SetBuoyancy(ent, ent.WireBuoyancyController) + end) + end +end) + +hook.Add("GravGunOnDropped", "WireBuoyancy", function(ply, ent) + if IsValid(ent.WireBuoyancyController) then + timer.Simple(0 , function() + if not IsValid(ent.WireBuoyancyController) then return end + SetBuoyancy(ent, ent.WireBuoyancyController) + end) + end +end) + +function ENT:CheckEnt(checkent) + for index, ent in ipairs(self.Marks) do + if checkent == ent then + return true, index + end + end + + return false, 0 +end + +function ENT:LinkEnt(ent) + if self:CheckEnt(ent) then return false end + + table.insert(self.Marks, ent) + SetBuoyancy(ent, self) + + ent:CallOnRemove("WireBuoyancy.Unlink", function(ent) + if self:IsValid() then + self:UnlinkEnt(ent) + end + end) + + self:UpdateOutputs() + + return true +end + +function ENT:UnlinkEnt(ent) + local bool, index = self:CheckEnt(ent) + + if bool then + table.remove(self.Marks, index) + ent.WireBuoyancyController = nil + self:UpdateOutputs() + end + + return bool +end + +function ENT:ClearEntities() + for index, ent in ipairs(self.Marks) do + if ent:IsValid() then + ent:RemoveCallOnRemove("WireBuoyancy.Unlink") + ent.WireBuoyancyController = nil + end + end + + self.Marks = {} + self:UpdateOutputs() +end + +function ENT:OnRemove() + self:ClearEntities() +end + +function ENT:BuildDupeInfo() + local info = BaseClass.BuildDupeInfo(self) or {} + + if #self.Marks > 0 then + local tab = {} + + for index, ent in ipairs(self.Marks) do + tab[index] = ent:EntIndex() + end + + info.marks = tab + end + + return info +end + +function ENT:ApplyDupeInfo(ply, ent, info, GetEntByID) + BaseClass.ApplyDupeInfo(self, ply, ent, info, GetEntByID) + + if info.marks then + self.Marks = self.Marks or {} + + for index, entid in ipairs(info.marks) do + local ent = GetEntByID(entid) + + if ent:IsValid() then + self:LinkEnt(ent) + end + end + + self:UpdateOutputs() + end +end + +duplicator.RegisterEntityClass("gmod_wire_adv_emarker", WireLib.MakeWireEnt, "Data", "Percent") diff --git a/lua/wire/stools/buoyancy.lua b/lua/wire/stools/buoyancy.lua new file mode 100644 index 0000000000..786c4ca556 --- /dev/null +++ b/lua/wire/stools/buoyancy.lua @@ -0,0 +1,29 @@ +WireToolSetup.setCategory("Physics/Force") +WireToolSetup.open("buoyancy", "Buoyancy", "gmod_wire_buoyancy", nil, "Buoyancys") + +if CLIENT then + language.Add("tool.wire_buoyancy.name", "Buoyancy Tool (Wire)") + language.Add("tool.wire_buoyancy.desc", "Spawns a Buoyancy Controller for use with the wire system.") +end + +WireToolSetup.BaseLang() +WireToolSetup.SetupMax(10) + +if SERVER then + function TOOL:GetConVars() + return self:GetClientNumber("percent"), self:GetClientInfo("model") + end +end + +TOOL.ClientConVar = { + percent = 1, + model = "models/jaanus/wiretool/wiretool_siren.mdl" +} + +WireToolSetup.SetupLinking() + +function TOOL.BuildCPanel(panel) + WireToolHelpers.MakePresetControl(panel, "wire_buoyancy") + WireDermaExts.ModelSelect(panel, "wire_buoyancy_model", list.Get("Wire_Laser_Tools_Models"), 1, true) + panel:NumSlider("Percent", "wire_buoyancy_percent", -10, 10) +end From 7f2e325a5547df2e361522acd57e1b7f770eabd0 Mon Sep 17 00:00:00 2001 From: Astralcircle <142503363+Astralcircle@users.noreply.github.com> Date: Fri, 24 Oct 2025 23:56:49 +0300 Subject: [PATCH 2/9] Critical fixes --- lua/entities/gmod_wire_buoyancy.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lua/entities/gmod_wire_buoyancy.lua b/lua/entities/gmod_wire_buoyancy.lua index 85f3f887d8..85aa7fa020 100644 --- a/lua/entities/gmod_wire_buoyancy.lua +++ b/lua/entities/gmod_wire_buoyancy.lua @@ -45,7 +45,7 @@ end function ENT:TriggerInput(name, value) if name == "Percent" then self.Percent = math.Clamp(value, -10, 10) - UpdateBuoyancy(controller) + UpdateBuoyancy(self) self:UpdateOutputs() end @@ -159,4 +159,4 @@ function ENT:ApplyDupeInfo(ply, ent, info, GetEntByID) end end -duplicator.RegisterEntityClass("gmod_wire_adv_emarker", WireLib.MakeWireEnt, "Data", "Percent") +duplicator.RegisterEntityClass("gmod_wire_buoyancy", WireLib.MakeWireEnt, "Data", "Percent") From 7b0ad3beaa0784feb53b9f47511df924b6866872 Mon Sep 17 00:00:00 2001 From: Astralcircle <142503363+Astralcircle@users.noreply.github.com> Date: Sat, 25 Oct 2025 11:30:34 +0300 Subject: [PATCH 3/9] Small cleanups --- lua/entities/gmod_wire_buoyancy.lua | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lua/entities/gmod_wire_buoyancy.lua b/lua/entities/gmod_wire_buoyancy.lua index 85aa7fa020..6a3d51b65b 100644 --- a/lua/entities/gmod_wire_buoyancy.lua +++ b/lua/entities/gmod_wire_buoyancy.lua @@ -38,8 +38,9 @@ end function ENT:Setup(percent) self.Percent = math.Clamp(percent, -10, 10) - self:UpdateOutputs() UpdateBuoyancy(self) + + self:UpdateOutputs() end function ENT:TriggerInput(name, value) @@ -154,8 +155,6 @@ function ENT:ApplyDupeInfo(ply, ent, info, GetEntByID) self:LinkEnt(ent) end end - - self:UpdateOutputs() end end From eaab831f6973f249d9a494f7e61e7e77105d6b5b Mon Sep 17 00:00:00 2001 From: Astralcircle <142503363+Astralcircle@users.noreply.github.com> Date: Sat, 25 Oct 2025 12:01:49 +0300 Subject: [PATCH 4/9] Make sure that self.Marks always contains only valid entities --- lua/entities/gmod_wire_buoyancy.lua | 53 ++++++++++++++--------------- 1 file changed, 25 insertions(+), 28 deletions(-) diff --git a/lua/entities/gmod_wire_buoyancy.lua b/lua/entities/gmod_wire_buoyancy.lua index 6a3d51b65b..7df7d83a49 100644 --- a/lua/entities/gmod_wire_buoyancy.lua +++ b/lua/entities/gmod_wire_buoyancy.lua @@ -13,9 +13,13 @@ function ENT:Initialize() WireLib.CreateInputs(self, { "Percent" }) end +function ENT:ShowOutput() + self:SetOverlayText(string.format("Buoyancy ratio: %.2f\nNumber of entities linked: %i", self.Percent, #self.Marks)) + WireLib.SendMarks(self) +end + local function SetBuoyancy(ent, controller) local phys = ent:GetPhysicsObject() - ent.WireBuoyancyController = controller if phys:IsValid() then phys:SetBuoyancyRatio(controller.Percent) @@ -23,32 +27,25 @@ local function SetBuoyancy(ent, controller) end end -local function UpdateBuoyancy(controller) - for _, ent in ipairs(controller.Marks) do - if ent:IsValid() then - SetBuoyancy(ent, controller) - end - end -end - -function ENT:UpdateOutputs() - self:SetOverlayText(string.format("Buoyancy ratio: %.2f\nNumber of entities linked: %i", self.Percent, #self.Marks)) - WireLib.SendMarks(self) -end - function ENT:Setup(percent) self.Percent = math.Clamp(percent, -10, 10) - UpdateBuoyancy(self) - self:UpdateOutputs() + for _, ent in ipairs(self.Marks) do + SetBuoyancy(ent, self) + end + + self:ShowOutput() end function ENT:TriggerInput(name, value) if name == "Percent" then self.Percent = math.Clamp(value, -10, 10) - UpdateBuoyancy(self) - self:UpdateOutputs() + for _, ent in ipairs(self.Marks) do + SetBuoyancy(ent, self) + end + + self:ShowOutput() end end @@ -56,7 +53,7 @@ end hook.Add("PhysgunDrop", "WireBuoyancy", function(ply, ent) if IsValid(ent.WireBuoyancyController) then timer.Simple(0 , function() - if not IsValid(ent.WireBuoyancyController) then return end + if not IsValid(ent) or not IsValid(ent.WireBuoyancyController) then return end SetBuoyancy(ent, ent.WireBuoyancyController) end) end @@ -65,7 +62,7 @@ end) hook.Add("GravGunOnDropped", "WireBuoyancy", function(ply, ent) if IsValid(ent.WireBuoyancyController) then timer.Simple(0 , function() - if not IsValid(ent.WireBuoyancyController) then return end + if not IsValid(ent) or not IsValid(ent.WireBuoyancyController) then return end SetBuoyancy(ent, ent.WireBuoyancyController) end) end @@ -87,13 +84,14 @@ function ENT:LinkEnt(ent) table.insert(self.Marks, ent) SetBuoyancy(ent, self) - ent:CallOnRemove("WireBuoyancy.Unlink", function(ent) + ent:CallOnRemove("WireBuoyancy_Unlink_" .. self:EntIndex(), function(ent) if self:IsValid() then self:UnlinkEnt(ent) end end) - self:UpdateOutputs() + ent.WireBuoyancyController = self + self:ShowOutput() return true end @@ -103,8 +101,9 @@ function ENT:UnlinkEnt(ent) if bool then table.remove(self.Marks, index) + ent:RemoveCallOnRemove("WireBuoyancy_Unlink_" .. self:EntIndex()) ent.WireBuoyancyController = nil - self:UpdateOutputs() + self:ShowOutput() end return bool @@ -112,14 +111,12 @@ end function ENT:ClearEntities() for index, ent in ipairs(self.Marks) do - if ent:IsValid() then - ent:RemoveCallOnRemove("WireBuoyancy.Unlink") - ent.WireBuoyancyController = nil - end + ent:RemoveCallOnRemove("WireBuoyancy_Unlink_" .. self:EntIndex()) + ent.WireBuoyancyController = nil end self.Marks = {} - self:UpdateOutputs() + self:ShowOutput() end function ENT:OnRemove() From 63302dfc4e485f6a632f396c85f0f7377463483d Mon Sep 17 00:00:00 2001 From: Astralcircle <142503363+Astralcircle@users.noreply.github.com> Date: Sat, 25 Oct 2025 12:05:30 +0300 Subject: [PATCH 5/9] Add to sents_registry --- lua/wire/server/sents_registry.lua | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lua/wire/server/sents_registry.lua b/lua/wire/server/sents_registry.lua index 3306eab2d5..9fefaec6d7 100644 --- a/lua/wire/server/sents_registry.lua +++ b/lua/wire/server/sents_registry.lua @@ -44,7 +44,7 @@ -- TIP: To return a strict-only error in _preFactory, or _postFactory, just return a string, which contains the error message. -- (If you return a string to non-strict E2, obv it will also stop spawning the entity) --- Supported types (to which can WireLib.castE2ValueToLuaValue cast E2 values): +-- Supported types (to which can WireLib.castE2ValueToLuaValue cast E2 values): -- TYPE_STRING, TYPE_NUMBER, TYPE_BOOL, TYPE_ENTITY, TYPE_VECTOR, -- TYPE_COLOR, TYPE_TABLE, TYPE_USERDATA, TYPE_ANGLE, TYPE_DAMAGEINFO, -- TYPE_MATERIAL, TYPE_EFFECTDATA, TYPE_MATRIX @@ -1317,3 +1317,8 @@ register("gmod_wire_materializer", { ["Material"] = {TYPE_STRING, "debug/env_cubemap_model", "Default material"}, ["Range"] = {TYPE_NUMBER, 2048, "Length of the materializer beam"}, }) + +register("gmod_wire_buoyancy", { + ["Model"] = {TYPE_STRING, "models/jaanus/wiretool/wiretool_siren.mdl", "Path to model"}, + ["Percent"] = {TYPE_NUMBER, 1, "Buoyancy coefficient"}, +}) From 40e66a53f63b64151c4f3d6bc14e3bcebdd70256 Mon Sep 17 00:00:00 2001 From: Astralcircle <142503363+Astralcircle@users.noreply.github.com> Date: Sun, 26 Oct 2025 09:54:14 +0300 Subject: [PATCH 6/9] Less code duplication --- lua/entities/gmod_wire_buoyancy.lua | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/lua/entities/gmod_wire_buoyancy.lua b/lua/entities/gmod_wire_buoyancy.lua index 7df7d83a49..a03b146cdd 100644 --- a/lua/entities/gmod_wire_buoyancy.lua +++ b/lua/entities/gmod_wire_buoyancy.lua @@ -50,23 +50,17 @@ function ENT:TriggerInput(name, value) end -- For some reason, buoyancy is reset by the physgun and gravgun -hook.Add("PhysgunDrop", "WireBuoyancy", function(ply, ent) +local function RestoreBuoyancy(ply, ent) if IsValid(ent.WireBuoyancyController) then timer.Simple(0 , function() if not IsValid(ent) or not IsValid(ent.WireBuoyancyController) then return end SetBuoyancy(ent, ent.WireBuoyancyController) end) end -end) +end -hook.Add("GravGunOnDropped", "WireBuoyancy", function(ply, ent) - if IsValid(ent.WireBuoyancyController) then - timer.Simple(0 , function() - if not IsValid(ent) or not IsValid(ent.WireBuoyancyController) then return end - SetBuoyancy(ent, ent.WireBuoyancyController) - end) - end -end) +hook.Add("PhysgunDrop", "WireBuoyancy", RestoreBuoyancy) +hook.Add("GravGunOnDropped", "WireBuoyancy", fRestoreBuoyancy) function ENT:CheckEnt(checkent) for index, ent in ipairs(self.Marks) do From 2e591c274e5049101bc0902919d9c238a23cf97a Mon Sep 17 00:00:00 2001 From: Astralcircle <142503363+Astralcircle@users.noreply.github.com> Date: Sun, 26 Oct 2025 09:58:17 +0300 Subject: [PATCH 7/9] Fix typo --- lua/entities/gmod_wire_buoyancy.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/entities/gmod_wire_buoyancy.lua b/lua/entities/gmod_wire_buoyancy.lua index a03b146cdd..92def3cdfc 100644 --- a/lua/entities/gmod_wire_buoyancy.lua +++ b/lua/entities/gmod_wire_buoyancy.lua @@ -60,7 +60,7 @@ local function RestoreBuoyancy(ply, ent) end hook.Add("PhysgunDrop", "WireBuoyancy", RestoreBuoyancy) -hook.Add("GravGunOnDropped", "WireBuoyancy", fRestoreBuoyancy) +hook.Add("GravGunOnDropped", "WireBuoyancy", RestoreBuoyancy) function ENT:CheckEnt(checkent) for index, ent in ipairs(self.Marks) do From c7953bc41f95a4378765c5fb05854184e460d4b6 Mon Sep 17 00:00:00 2001 From: Astralcircle <142503363+Astralcircle@users.noreply.github.com> Date: Sun, 26 Oct 2025 10:51:32 +0300 Subject: [PATCH 8/9] Small cleanups --- lua/entities/gmod_wire_buoyancy.lua | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/lua/entities/gmod_wire_buoyancy.lua b/lua/entities/gmod_wire_buoyancy.lua index 92def3cdfc..72632cdcfe 100644 --- a/lua/entities/gmod_wire_buoyancy.lua +++ b/lua/entities/gmod_wire_buoyancy.lua @@ -51,9 +51,9 @@ end -- For some reason, buoyancy is reset by the physgun and gravgun local function RestoreBuoyancy(ply, ent) - if IsValid(ent.WireBuoyancyController) then + if ent.WireBuoyancyController then timer.Simple(0 , function() - if not IsValid(ent) or not IsValid(ent.WireBuoyancyController) then return end + if not ent:IsValid() or not ent.WireBuoyancyController then return end SetBuoyancy(ent, ent.WireBuoyancyController) end) end @@ -79,9 +79,7 @@ function ENT:LinkEnt(ent) SetBuoyancy(ent, self) ent:CallOnRemove("WireBuoyancy_Unlink_" .. self:EntIndex(), function(ent) - if self:IsValid() then - self:UnlinkEnt(ent) - end + self:UnlinkEnt(ent) end) ent.WireBuoyancyController = self @@ -118,7 +116,7 @@ function ENT:OnRemove() end function ENT:BuildDupeInfo() - local info = BaseClass.BuildDupeInfo(self) or {} + local info = BaseClass.BuildDupeInfo(self) if #self.Marks > 0 then local tab = {} @@ -137,8 +135,6 @@ function ENT:ApplyDupeInfo(ply, ent, info, GetEntByID) BaseClass.ApplyDupeInfo(self, ply, ent, info, GetEntByID) if info.marks then - self.Marks = self.Marks or {} - for index, entid in ipairs(info.marks) do local ent = GetEntByID(entid) From 7d68b93e31bd8af1ec19771d251783c672cfaeb8 Mon Sep 17 00:00:00 2001 From: Astralcircle <142503363+Astralcircle@users.noreply.github.com> Date: Tue, 25 Nov 2025 20:49:52 +0300 Subject: [PATCH 9/9] Small cleanups --- lua/entities/gmod_wire_buoyancy.lua | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/lua/entities/gmod_wire_buoyancy.lua b/lua/entities/gmod_wire_buoyancy.lua index 72632cdcfe..99369fa00f 100644 --- a/lua/entities/gmod_wire_buoyancy.lua +++ b/lua/entities/gmod_wire_buoyancy.lua @@ -8,13 +8,18 @@ ENT.WireDebugName = "Buoyancy" if CLIENT then return end function ENT:Initialize() - self.Marks = {} self:PhysicsInit(SOLID_VPHYSICS) + self.Marks = {} + WireLib.CreateInputs(self, { "Percent" }) end -function ENT:ShowOutput() +function ENT:UpdateOverlay() self:SetOverlayText(string.format("Buoyancy ratio: %.2f\nNumber of entities linked: %i", self.Percent, #self.Marks)) +end + +function ENT:UpdateOutputs() + self:UpdateOverlay() WireLib.SendMarks(self) end @@ -34,7 +39,7 @@ function ENT:Setup(percent) SetBuoyancy(ent, self) end - self:ShowOutput() + self:UpdateOverlay() end function ENT:TriggerInput(name, value) @@ -45,11 +50,11 @@ function ENT:TriggerInput(name, value) SetBuoyancy(ent, self) end - self:ShowOutput() + self:UpdateOverlay() end end --- For some reason, buoyancy is reset by the physgun and gravgun +-- Buoyancy is reset by the physgun and gravgun local function RestoreBuoyancy(ply, ent) if ent.WireBuoyancyController then timer.Simple(0 , function() @@ -78,12 +83,12 @@ function ENT:LinkEnt(ent) table.insert(self.Marks, ent) SetBuoyancy(ent, self) - ent:CallOnRemove("WireBuoyancy_Unlink_" .. self:EntIndex(), function(ent) + ent:CallOnRemove("Buoyancy.Unlink" .. self:EntIndex(), function(ent) self:UnlinkEnt(ent) end) ent.WireBuoyancyController = self - self:ShowOutput() + self:UpdateOutputs() return true end @@ -93,9 +98,9 @@ function ENT:UnlinkEnt(ent) if bool then table.remove(self.Marks, index) - ent:RemoveCallOnRemove("WireBuoyancy_Unlink_" .. self:EntIndex()) + ent:RemoveCallOnRemove("Buoyancy.Unlink" .. self:EntIndex()) ent.WireBuoyancyController = nil - self:ShowOutput() + self:UpdateOutputs() end return bool @@ -103,12 +108,12 @@ end function ENT:ClearEntities() for index, ent in ipairs(self.Marks) do - ent:RemoveCallOnRemove("WireBuoyancy_Unlink_" .. self:EntIndex()) + ent:RemoveCallOnRemove("Buoyancy.Unlink" .. self:EntIndex()) ent.WireBuoyancyController = nil end self.Marks = {} - self:ShowOutput() + self:UpdateOutputs() end function ENT:OnRemove()