From 1fc2126b08fbcaf39c7dbeff9389831ad1c64878 Mon Sep 17 00:00:00 2001 From: Astralcircle <142503363+Astralcircle@users.noreply.github.com> Date: Sat, 24 Oct 2026 17:35:06 +0300 Subject: [PATCH 1/5] Refactor gimbal code --- lua/entities/gmod_wire_gimbal.lua | 187 ++++++++++++++++-------------- 1 file changed, 99 insertions(+), 88 deletions(-) diff --git a/lua/entities/gmod_wire_gimbal.lua b/lua/entities/gmod_wire_gimbal.lua index 3ea552cc48..3c077771f0 100644 --- a/lua/entities/gmod_wire_gimbal.lua +++ b/lua/entities/gmod_wire_gimbal.lua @@ -1,124 +1,135 @@ AddCSLuaFile() -DEFINE_BASECLASS( "base_wire_entity" ) -ENT.PrintName = "Wire Gimbal" -ENT.WireDebugName = "Gimbal" - -local ORIGIN_COLOR = Color(255, 150, 50) -local FORWARD_COLOR = Color(255, 100, 100) -local RIGHT_COLOR = Color(100, 255, 100) -local UP_COLOR = Color(100, 100, 255) - -local function DrawOutlinedBeam(startPos, endPos, size, color) - render.DrawBeam(startPos, endPos, size + 0.2, 0, 1, color_black) - render.DrawBeam(startPos, endPos, size, 0, 1, color) -end +DEFINE_BASECLASS("base_wire_entity") +ENT.PrintName = "Wire Gimbal" +ENT.WireDebugName = "Gimbal" -function ENT:DrawWorldTip() - BaseClass.DrawWorldTip(self) - - cam.Start3D() - local origin = self:GetPos() - local mi, ma = self:GetModelRenderBounds() - local forwardSize = math.max(math.abs(mi[1]), ma[1]) - local rightSize = math.max(math.abs(mi[2]), ma[2]) - local upSize = math.max(math.abs(mi[3]), ma[3]) - - local forward = self:GetForward() * forwardSize - local right = self:GetRight() * rightSize - local up = self:GetUp() * upSize - - render.SetColorMaterialIgnoreZ() - - DrawOutlinedBeam(origin, origin + forward, 0.2, FORWARD_COLOR) - DrawOutlinedBeam(origin, origin + right, 0.2, RIGHT_COLOR) - DrawOutlinedBeam(origin, origin + up, 0.2, UP_COLOR) - - render.DrawSphere(origin, 0.35, 8, 8, color_black) - render.DrawSphere(origin, 0.2, 8, 8, ORIGIN_COLOR) - cam.End3D() -end +if CLIENT then + local function DrawOutlinedBeam(start_pos, end_pos, size, color) + render.DrawBeam(start_pos, end_pos, size + 0.2, 0, 1, color_black) + render.DrawBeam(start_pos, end_pos, size, 0, 1, color) + end + + function ENT:DrawWorldTip() + BaseClass.DrawWorldTip(self) + + cam.Start3D() + local origin = self:GetPos() + local mins, maxs = self:GetModelRenderBounds() + + local forward = self:GetForward() + forward:Mul(math.max(math.abs(mins[1]), maxs[1])) + + local right = self:GetRight() + right:Mul(math.max(math.abs(mins[2]), maxs[2])) -if CLIENT then return end -- No more client + local up = self:GetUp() + up:Mul(math.max(math.abs(mins[3]), maxs[3])) + + render.SetColorMaterialIgnoreZ() + DrawOutlinedBeam(origin, origin + forward, 0.2, Color(255, 100, 100)) + DrawOutlinedBeam(origin, origin + right, 0.2, Color(100, 255, 100)) + DrawOutlinedBeam(origin, origin + up, 0.2, Color(100, 100, 255)) + + render.DrawSphere(origin, 0.35, 8, 8, color_black) + render.DrawSphere(origin, 0.2, 8, 8, Color(255, 150, 50)) + cam.End3D() + end + + return +end function ENT:Initialize() - self:PhysicsInit( SOLID_VPHYSICS ) - self:SetMoveType( MOVETYPE_VPHYSICS ) - self:SetSolid( SOLID_VPHYSICS ) - self:GetPhysicsObject():EnableGravity(false) + self:PhysicsInit(SOLID_VPHYSICS) + + local phys = self:GetPhysicsObject() - self.Inputs = WireLib.CreateInputs(self,{"On", "X", "Y", "Z", "Target [VECTOR]", "Direction [VECTOR]", "Angle [ANGLE]", "AngleOffset [ANGLE]"}) + if phys:IsValid() then + phys:EnableGravity(false) + end - self.XYZ = Vector() - self.TargetAngOffset = Matrix() - self.TargetAngOffset:SetAngles(Angle(90,0,0)) + self.XYZ = Vector(0, 0, 0) + self.TargetAngOffset = Angle(90, 0, 0) + + WireLib.CreateInputs(self, { "On", "X", "Y", "Z", "Target [VECTOR]", "Direction [VECTOR]", "Angle [ANGLE]", "AngleOffset [ANGLE]" }) end -function ENT:TriggerInput(name,value) +function ENT:TriggerInput(name, value) + local tab = self:GetTable() + if name == "On" then - self.On = value ~= 0 + tab.On = value ~= 0 else - self.TargetPos = nil - self.TargetDir = nil - self.TargetAng = nil + tab.TargetPos = nil + tab.TargetDir = nil + tab.TargetAng = nil if name == "X" then - self.XYZ.x = value - self.TargetPos = self.XYZ + tab.XYZ.x = value + tab.TargetPos = tab.XYZ elseif name == "Y" then - self.XYZ.y = value - self.TargetPos = self.XYZ + tab.XYZ.y = value + tab.TargetPos = tab.XYZ elseif name == "Z" then - self.XYZ.z = value - self.TargetPos = self.XYZ + tab.XYZ.z = value + tab.TargetPos = tab.XYZ elseif name == "Target" then - self.XYZ = Vector(value.x, value.y, value.z) - self.TargetPos = self.XYZ + tab.XYZ = Vector(value) + tab.TargetPos = tab.XYZ elseif name == "Direction" then - self.TargetDir = value + tab.TargetDir = value elseif name == "Angle" then - self.TargetAng = value + tab.TargetAng = value elseif name == "AngleOffset" then - self.TargetAngOffset = Matrix() - self.TargetAngOffset:SetAngles(value) + tab.TargetAngOffset = value end end - self:ShowOutput() - return true end - function ENT:Think() - if self.On then + local tab = self:GetTable() + + if tab.On then local ang - if self.TargetPos then - ang = (self.TargetPos - self:GetPos()):Angle() - elseif self.TargetDir then - ang = self.TargetDir:Angle() - elseif self.TargetAng then - ang = self.TargetAng + + if tab.TargetPos then + local pos = self:GetPos() + pos:Negate() + pos:Add(tab.TargetPos) + ang = pos:Angle() + elseif tab.TargetDir then + ang = tab.TargetDir:Angle() + elseif tab.TargetAng then + ang = tab.TargetAng end + if ang then - local m = Matrix() - m:SetAngles(ang) - m = m * self.TargetAngOffset - self:SetAngles(m:GetAngles()) + ang:Mul(tab.TargetAngOffset) + self:SetAngles(ang) + end + + local phys = self:GetPhysicsObject() + + if phys:IsValid() then + phys:Wake() end - -- TODO: Put an option in the CPanel for Angle(90,0,0), and other useful directions - self:GetPhysicsObject():Wake() end + self:NextThink(CurTime()) + return true end -function ENT:ShowOutput() - if not self.On then - self:SetOverlayText("Off") - elseif self.TargetPos then - self:SetOverlayText(string.format("Aiming towards (%.2f, %.2f, %.2f)", self.XYZ.x, self.XYZ.y, self.XYZ.z)) - elseif self.TargetDir then - self:SetOverlayText(string.format("Aiming (%.4f, %.4f, %.4f)", self.TargetDir.x, self.TargetDir.y, self.TargetDir.z)) - elseif self.TargetAng then - self:SetOverlayText(string.format("Aiming (%.1f, %.1f, %.1f)", self.TargetAng.pitch, self.TargetAng.yaw, self.TargetAng.roll)) +function ENT:PrepareOverlayData() + local tab = self:GetTable() + + if not tab.On then + tab.SetOverlayText(self, "Off") + elseif tab.TargetPos then + tab.SetOverlayText(self, string.format("Aiming position (%.2f, %.2f, %.2f)", tab.XYZ:Unpack())) + elseif tab.TargetDir then + tab.SetOverlayText(self, string.format("Aiming direction (%.4f, %.4f, %.4f)", tab.TargetDir:Unpack())) + elseif tab.TargetAng then + tab.SetOverlayText(self, string.format("Aiming angle (%.1f, %.1f, %.1f)", tab.TargetAng:Unpack())) end end From 434173bb559d7f4dd30d1bc7fa78a3e49a59effc Mon Sep 17 00:00:00 2001 From: Astralcircle <142503363+Astralcircle@users.noreply.github.com> Date: Sat, 24 Oct 2026 17:43:03 +0300 Subject: [PATCH 2/5] Fix --- lua/entities/gmod_wire_gimbal.lua | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lua/entities/gmod_wire_gimbal.lua b/lua/entities/gmod_wire_gimbal.lua index 3c077771f0..2beaffa346 100644 --- a/lua/entities/gmod_wire_gimbal.lua +++ b/lua/entities/gmod_wire_gimbal.lua @@ -103,7 +103,9 @@ function ENT:Think() end if ang then - ang:Mul(tab.TargetAngOffset) + local p, y, r = ang:Unpack() + local offset_p, offset_y, offset_r = tab.TargetAngOffset:Unpack() + ang:SetUnpacked(p + offset_p, y + offset_y, r + offset_r) self:SetAngles(ang) end From dd54fc2d0a5c9bf86724dc13b3673a0290edcfa9 Mon Sep 17 00:00:00 2001 From: Astralcircle <142503363+Astralcircle@users.noreply.github.com> Date: Sat, 24 Oct 2026 17:51:29 +0300 Subject: [PATCH 3/5] Simplify --- lua/entities/gmod_wire_gimbal.lua | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lua/entities/gmod_wire_gimbal.lua b/lua/entities/gmod_wire_gimbal.lua index 2beaffa346..0e2a28eae8 100644 --- a/lua/entities/gmod_wire_gimbal.lua +++ b/lua/entities/gmod_wire_gimbal.lua @@ -103,9 +103,7 @@ function ENT:Think() end if ang then - local p, y, r = ang:Unpack() - local offset_p, offset_y, offset_r = tab.TargetAngOffset:Unpack() - ang:SetUnpacked(p + offset_p, y + offset_y, r + offset_r) + ang:Add(tab.TargetAngOffset) self:SetAngles(ang) end From 60cb70992459c379fbffc0070dca6b6b9766d38d Mon Sep 17 00:00:00 2001 From: Astralcircle <142503363+Astralcircle@users.noreply.github.com> Date: Sun, 25 Oct 2026 15:10:16 +0300 Subject: [PATCH 4/5] Fix TargetAng getting mutated + add message when aiming nothing --- lua/entities/gmod_wire_gimbal.lua | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lua/entities/gmod_wire_gimbal.lua b/lua/entities/gmod_wire_gimbal.lua index 0e2a28eae8..494b0f6783 100644 --- a/lua/entities/gmod_wire_gimbal.lua +++ b/lua/entities/gmod_wire_gimbal.lua @@ -99,7 +99,7 @@ function ENT:Think() elseif tab.TargetDir then ang = tab.TargetDir:Angle() elseif tab.TargetAng then - ang = tab.TargetAng + ang = Angle(tab.TargetAng) end if ang then @@ -130,6 +130,8 @@ function ENT:PrepareOverlayData() tab.SetOverlayText(self, string.format("Aiming direction (%.4f, %.4f, %.4f)", tab.TargetDir:Unpack())) elseif tab.TargetAng then tab.SetOverlayText(self, string.format("Aiming angle (%.1f, %.1f, %.1f)", tab.TargetAng:Unpack())) + else + tab.SetOverlayText(self, "Aiming nothing") end end From 96ce35a744afddc3d14b1acec50e1458575a8e2f Mon Sep 17 00:00:00 2001 From: Astralcircle <142503363+Astralcircle@users.noreply.github.com> Date: Sun, 25 Oct 2026 15:29:08 +0300 Subject: [PATCH 5/5] Keep matrix because it have diffrent behaivor --- lua/entities/gmod_wire_gimbal.lua | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/lua/entities/gmod_wire_gimbal.lua b/lua/entities/gmod_wire_gimbal.lua index 494b0f6783..a6362b4e09 100644 --- a/lua/entities/gmod_wire_gimbal.lua +++ b/lua/entities/gmod_wire_gimbal.lua @@ -48,7 +48,8 @@ function ENT:Initialize() end self.XYZ = Vector(0, 0, 0) - self.TargetAngOffset = Angle(90, 0, 0) + self.TargetAngOffset = Matrix() + self.TargetAngOffset:SetAngles(Angle(90, 0, 0)) WireLib.CreateInputs(self, { "On", "X", "Y", "Z", "Target [VECTOR]", "Direction [VECTOR]", "Angle [ANGLE]", "AngleOffset [ANGLE]" }) end @@ -80,7 +81,7 @@ function ENT:TriggerInput(name, value) elseif name == "Angle" then tab.TargetAng = value elseif name == "AngleOffset" then - tab.TargetAngOffset = value + tab.TargetAngOffset:SetAngles(value) end end end @@ -103,8 +104,10 @@ function ENT:Think() end if ang then - ang:Add(tab.TargetAngOffset) - self:SetAngles(ang) + local matrix = Matrix() + matrix:SetAngles(ang) + matrix:Mul(tab.TargetAngOffset) + self:SetAngles(matrix:GetAngles()) end local phys = self:GetPhysicsObject()