From b44401928fea5e9bf3bfd7dec147144eead01615 Mon Sep 17 00:00:00 2001 From: penolakushari <45951611+penolakushari@users.noreply.github.com> Date: Sat, 4 Sep 2021 12:58:40 +0300 Subject: [PATCH 01/13] Fixed prp_ (and some other cases for workshop models) bones not being set by the stand pose --- lua/autorun/standpose.lua | 28 +++---- lua/weapons/gmod_tool/stools/ragdollstand.lua | 84 +++++++++++++++---- 2 files changed, 77 insertions(+), 35 deletions(-) diff --git a/lua/autorun/standpose.lua b/lua/autorun/standpose.lua index 314b1c1..557b5ef 100644 --- a/lua/autorun/standpose.lua +++ b/lua/autorun/standpose.lua @@ -32,23 +32,17 @@ propt.Receive = function( self, length, player ) local angle = (tr.HitPos - player:GetPos()):Angle() ent:SetAngles(Angle(0,angle.y-180,0)) ent:Spawn() - for i=0,rag:GetPhysicsObjectCount()-1 do - local phys = rag:GetPhysicsObjectNum(i) - local b = rag:TranslatePhysBoneToBone(i) - local pos,ang = ent:GetBonePosition(b) - phys:EnableMotion(true) - phys:Wake() - phys:SetPos(pos) - phys:SetAngles(ang) - if string.sub(rag:GetBoneName(b),1,4) == "prp_" then - phys:EnableMotion(true) - phys:Wake() - else - phys:EnableMotion(false) - phys:Wake() - end - end - ent:Remove() + + if CLIENT then return true end + local PhysObjects = rag:GetPhysicsObjectCount()-1 + + timer.Simple(0.1, function() + net.Start("StandPoser_Client") + net.WriteEntity(rag) + net.WriteEntity(ent) + net.WriteInt(PhysObjects, 8) + net.Send(player) + end) end diff --git a/lua/weapons/gmod_tool/stools/ragdollstand.lua b/lua/weapons/gmod_tool/stools/ragdollstand.lua index 185e961..880d776 100644 --- a/lua/weapons/gmod_tool/stools/ragdollstand.lua +++ b/lua/weapons/gmod_tool/stools/ragdollstand.lua @@ -1,3 +1,33 @@ +if SERVER then +util.AddNetworkString("StandPose_Server") +util.AddNetworkString("StandPoser_Client") + +net.Receive("StandPose_Server", function() + local rag = net.ReadEntity() + local ent = net.ReadEntity() + + for i=0,rag:GetPhysicsObjectCount()-1 do + local phys = rag:GetPhysicsObjectNum(i) + local b = rag:TranslatePhysBoneToBone(i) + local pos = net.ReadVector() + local ang = net.ReadAngle() + phys:EnableMotion(true) + phys:Wake() + phys:SetPos(pos) + phys:SetAngles(ang) +-- if string.sub(rag:GetBoneName(b),1,4) == "prp_" then +-- phys:EnableMotion(true) +-- phys:Wake() +-- else + phys:EnableMotion(false) + phys:Wake() +-- end + end + ent:Remove() +end) + +end + TOOL.Category = "Poser" TOOL.Name = "Stand Pose" @@ -24,7 +54,7 @@ function TOOL:LeftClick(tr) return true end - if CLIENT then return true end + local ent = ents.Create("prop_dynamic") ent:SetModel(rag:GetModel()) @@ -32,23 +62,17 @@ function TOOL:LeftClick(tr) local angle = (tr.HitPos - self:GetOwner():GetPos()):Angle() ent:SetAngles(Angle(0,angle.y-180,0)) ent:Spawn() - for i=0,rag:GetPhysicsObjectCount()-1 do - local phys = rag:GetPhysicsObjectNum(i) - local b = rag:TranslatePhysBoneToBone(i) - local pos,ang = ent:GetBonePosition(b) - phys:EnableMotion(true) - phys:Wake() - phys:SetPos(pos) - phys:SetAngles(ang) - if string.sub(rag:GetBoneName(b),1,4) == "prp_" then - phys:EnableMotion(true) - phys:Wake() - else - phys:EnableMotion(false) - phys:Wake() - end - end - ent:Remove() + + if CLIENT then return true end + local PhysObjects = rag:GetPhysicsObjectCount()-1 + + timer.Simple(0.1, function() + net.Start("StandPoser_Client") + net.WriteEntity(rag) + net.WriteEntity(ent) + net.WriteInt(PhysObjects, 8) + net.Send(self:GetOwner()) + end) self:SetStage(0) return true @@ -65,6 +89,30 @@ end if CLIENT then +net.Receive("StandPoser_Client", function() + local rag = net.ReadEntity() + local ent = net.ReadEntity() + local PhysObjects = net.ReadInt(8) + + net.Start("StandPose_Server") + net.WriteEntity(rag) + net.WriteEntity(ent) + for i=0,PhysObjects do + local phys = rag:GetPhysicsObjectNum(i) + local b = rag:TranslatePhysBoneToBone(i) + local pos,ang = ent:GetBonePosition(b) + if pos == ent:GetPos() then + local matrix = ent:GetBoneMatrix(b) + pos = matrix:GetTranslation() + ang = matrix:GetAngles() + end + net.WriteVector(pos) + net.WriteAngle(ang) + end + net.SendToServer() +end) + + language.Add("tool.ragdollstand.name","Stand Pose") language.Add("tool.ragdollstand.desc","Position ragdolls in a standing pose.") language.Add("tool.ragdollstand.0","Left Click to select a ragdoll.") From 813e7da0e1b16ffcca8041be3299100c63a7987b Mon Sep 17 00:00:00 2001 From: penolakushari <45951611+penolakushari@users.noreply.github.com> Date: Sun, 12 Sep 2021 22:17:22 +0300 Subject: [PATCH 02/13] Fixed an issue with some ragdolls breaking stand pose tool due to bonematrix being nil for some reason --- lua/weapons/gmod_tool/stools/ragdollstand.lua | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lua/weapons/gmod_tool/stools/ragdollstand.lua b/lua/weapons/gmod_tool/stools/ragdollstand.lua index 880d776..0dbef5f 100644 --- a/lua/weapons/gmod_tool/stools/ragdollstand.lua +++ b/lua/weapons/gmod_tool/stools/ragdollstand.lua @@ -103,8 +103,10 @@ net.Receive("StandPoser_Client", function() local pos,ang = ent:GetBonePosition(b) if pos == ent:GetPos() then local matrix = ent:GetBoneMatrix(b) - pos = matrix:GetTranslation() - ang = matrix:GetAngles() + if matrix then + pos = matrix:GetTranslation() + ang = matrix:GetAngles() + end end net.WriteVector(pos) net.WriteAngle(ang) From c4b02ce4da44189b38412ab2428e63801952aa8b Mon Sep 17 00:00:00 2001 From: penolakushari <45951611+penolakushari@users.noreply.github.com> Date: Thu, 16 Sep 2021 19:22:00 +0300 Subject: [PATCH 03/13] Made it so tool will revert to previous behavior if it is in mulstiplayer, as client-server net messaging breaks when player has too crap connection and starts dropping packets --- lua/autorun/standpose.lua | 34 ++++++++++++++---- lua/weapons/gmod_tool/stools/ragdollstand.lua | 35 ++++++++++++++----- 2 files changed, 54 insertions(+), 15 deletions(-) diff --git a/lua/autorun/standpose.lua b/lua/autorun/standpose.lua index 557b5ef..04ebabd 100644 --- a/lua/autorun/standpose.lua +++ b/lua/autorun/standpose.lua @@ -36,13 +36,33 @@ propt.Receive = function( self, length, player ) if CLIENT then return true end local PhysObjects = rag:GetPhysicsObjectCount()-1 - timer.Simple(0.1, function() - net.Start("StandPoser_Client") - net.WriteEntity(rag) - net.WriteEntity(ent) - net.WriteInt(PhysObjects, 8) - net.Send(player) - end) + if game.SinglePlayer() then + timer.Simple(0.1, function() + net.Start("StandPoser_Client") + net.WriteEntity(rag) + net.WriteEntity(ent) + net.WriteInt(PhysObjects, 8) + net.Send(player) + end) + else -- if we're in multiplayer, we revert back to the old way stand pose worked, otherwise stuff will get weird + for i=0,PhysObjects do + local phys = rag:GetPhysicsObjectNum(i) + local b = rag:TranslatePhysBoneToBone(i) + local pos,ang = ent:GetBonePosition(b) + phys:EnableMotion(true) + phys:Wake() + phys:SetPos(pos) + phys:SetAngles(ang) + if string.sub(rag:GetBoneName(b),1,4) == "prp_" then + phys:EnableMotion(true) + phys:Wake() + else + phys:EnableMotion(false) + phys:Wake() + end + end + ent:Remove() + end end diff --git a/lua/weapons/gmod_tool/stools/ragdollstand.lua b/lua/weapons/gmod_tool/stools/ragdollstand.lua index 0dbef5f..d040bde 100644 --- a/lua/weapons/gmod_tool/stools/ragdollstand.lua +++ b/lua/weapons/gmod_tool/stools/ragdollstand.lua @@ -65,14 +65,33 @@ function TOOL:LeftClick(tr) if CLIENT then return true end local PhysObjects = rag:GetPhysicsObjectCount()-1 - - timer.Simple(0.1, function() - net.Start("StandPoser_Client") - net.WriteEntity(rag) - net.WriteEntity(ent) - net.WriteInt(PhysObjects, 8) - net.Send(self:GetOwner()) - end) + if game.SinglePlayer() then + timer.Simple(0.1, function() + net.Start("StandPoser_Client") + net.WriteEntity(rag) + net.WriteEntity(ent) + net.WriteInt(PhysObjects, 8) + net.Send(self:GetOwner()) + end) + else -- if we're in multiplayer, we revert back to the old way stand pose worked, otherwise stuff will get weird + for i=0,PhysObjects do + local phys = rag:GetPhysicsObjectNum(i) + local b = rag:TranslatePhysBoneToBone(i) + local pos,ang = ent:GetBonePosition(b) + phys:EnableMotion(true) + phys:Wake() + phys:SetPos(pos) + phys:SetAngles(ang) + if string.sub(rag:GetBoneName(b),1,4) == "prp_" then + phys:EnableMotion(true) + phys:Wake() + else + phys:EnableMotion(false) + phys:Wake() + end + end + ent:Remove() + end self:SetStage(0) return true From 80dc2b632dd2de9d71cffe9abe281ff32e599d45 Mon Sep 17 00:00:00 2001 From: penolakushari <45951611+penolakushari@users.noreply.github.com> Date: Mon, 20 Sep 2021 13:52:19 +0300 Subject: [PATCH 04/13] Switched around net messages from the tool lua to the autorun, that probably should make it initialize faster as autorun should generally be installed before tool stuff does --- lua/autorun/standpose.lua | 59 +++++++++++++++++++ lua/weapons/gmod_tool/stools/ragdollstand.lua | 56 ------------------ 2 files changed, 59 insertions(+), 56 deletions(-) diff --git a/lua/autorun/standpose.lua b/lua/autorun/standpose.lua index 04ebabd..52d91d1 100644 --- a/lua/autorun/standpose.lua +++ b/lua/autorun/standpose.lua @@ -1,3 +1,62 @@ +if SERVER then + +util.AddNetworkString("StandPose_Server") +util.AddNetworkString("StandPoser_Client") + +net.Receive("StandPose_Server", function() + local rag = net.ReadEntity() + local ent = net.ReadEntity() + + for i=0,rag:GetPhysicsObjectCount()-1 do + local phys = rag:GetPhysicsObjectNum(i) + local b = rag:TranslatePhysBoneToBone(i) + local pos = net.ReadVector() + local ang = net.ReadAngle() + phys:EnableMotion(true) + phys:Wake() + phys:SetPos(pos) + phys:SetAngles(ang) +-- if string.sub(rag:GetBoneName(b),1,4) == "prp_" then +-- phys:EnableMotion(true) +-- phys:Wake() +-- else + phys:EnableMotion(false) + phys:Wake() +-- end + end + ent:Remove() +end) + +end + +if CLIENT then + +net.Receive("StandPoser_Client", function() + local rag = net.ReadEntity() + local ent = net.ReadEntity() + local PhysObjects = net.ReadInt(8) + + net.Start("StandPose_Server") + net.WriteEntity(rag) + net.WriteEntity(ent) + for i=0,PhysObjects do + local phys = rag:GetPhysicsObjectNum(i) + local b = rag:TranslatePhysBoneToBone(i) + local pos,ang = ent:GetBonePosition(b) + if pos == ent:GetPos() then + local matrix = ent:GetBoneMatrix(b) + if matrix then + pos = matrix:GetTranslation() + ang = matrix:GetAngles() + end + end + net.WriteVector(pos) + net.WriteAngle(ang) + end + net.SendToServer() +end) + +end local propt = {} diff --git a/lua/weapons/gmod_tool/stools/ragdollstand.lua b/lua/weapons/gmod_tool/stools/ragdollstand.lua index d040bde..bf0a024 100644 --- a/lua/weapons/gmod_tool/stools/ragdollstand.lua +++ b/lua/weapons/gmod_tool/stools/ragdollstand.lua @@ -1,33 +1,3 @@ -if SERVER then -util.AddNetworkString("StandPose_Server") -util.AddNetworkString("StandPoser_Client") - -net.Receive("StandPose_Server", function() - local rag = net.ReadEntity() - local ent = net.ReadEntity() - - for i=0,rag:GetPhysicsObjectCount()-1 do - local phys = rag:GetPhysicsObjectNum(i) - local b = rag:TranslatePhysBoneToBone(i) - local pos = net.ReadVector() - local ang = net.ReadAngle() - phys:EnableMotion(true) - phys:Wake() - phys:SetPos(pos) - phys:SetAngles(ang) --- if string.sub(rag:GetBoneName(b),1,4) == "prp_" then --- phys:EnableMotion(true) --- phys:Wake() --- else - phys:EnableMotion(false) - phys:Wake() --- end - end - ent:Remove() -end) - -end - TOOL.Category = "Poser" TOOL.Name = "Stand Pose" @@ -108,32 +78,6 @@ end if CLIENT then -net.Receive("StandPoser_Client", function() - local rag = net.ReadEntity() - local ent = net.ReadEntity() - local PhysObjects = net.ReadInt(8) - - net.Start("StandPose_Server") - net.WriteEntity(rag) - net.WriteEntity(ent) - for i=0,PhysObjects do - local phys = rag:GetPhysicsObjectNum(i) - local b = rag:TranslatePhysBoneToBone(i) - local pos,ang = ent:GetBonePosition(b) - if pos == ent:GetPos() then - local matrix = ent:GetBoneMatrix(b) - if matrix then - pos = matrix:GetTranslation() - ang = matrix:GetAngles() - end - end - net.WriteVector(pos) - net.WriteAngle(ang) - end - net.SendToServer() -end) - - language.Add("tool.ragdollstand.name","Stand Pose") language.Add("tool.ragdollstand.desc","Position ragdolls in a standing pose.") language.Add("tool.ragdollstand.0","Left Click to select a ragdoll.") From 9ef7a20b9bd64a9980140537d7b2fa3a2a1e55ce Mon Sep 17 00:00:00 2001 From: penolakushari <45951611+penolakushari@users.noreply.github.com> Date: Thu, 23 Sep 2021 00:59:57 +0300 Subject: [PATCH 05/13] Made the properties version of the tool run a check if a ragdoll is within map's bounds, and if it is not, it'll run a trace upwards 10 units instead of downwards 3000 units --- lua/autorun/standpose.lua | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/lua/autorun/standpose.lua b/lua/autorun/standpose.lua index 52d91d1..b0adc19 100644 --- a/lua/autorun/standpose.lua +++ b/lua/autorun/standpose.lua @@ -35,7 +35,7 @@ net.Receive("StandPoser_Client", function() local rag = net.ReadEntity() local ent = net.ReadEntity() local PhysObjects = net.ReadInt(8) - + net.Start("StandPose_Server") net.WriteEntity(rag) net.WriteEntity(ent) @@ -83,15 +83,18 @@ propt.Receive = function( self, length, player ) if ( !IsValid( player ) ) then return end if ( rag:GetClass() != "prop_ragdoll" ) then return end - local tr = util.TraceLine({start = rag:GetPos(),endpos = rag:GetPos() - Vector(0,0,3000),filter = rag}) - + local adjust = Vector(0,0,3000) + if not rag:IsInWorld() then adjust = Vector(0,0, -10) end + + local tr = util.TraceLine({start = rag:GetPos(),endpos = rag:GetPos() - adjust,filter = rag}) + local ent = ents.Create("prop_dynamic") ent:SetModel(rag:GetModel()) ent:SetPos(tr.HitPos) local angle = (tr.HitPos - player:GetPos()):Angle() ent:SetAngles(Angle(0,angle.y-180,0)) ent:Spawn() - + if CLIENT then return true end local PhysObjects = rag:GetPhysicsObjectCount()-1 From ba3472cffdba5d6139a2fc30957125b79eeff300 Mon Sep 17 00:00:00 2001 From: penolakushari <45951611+penolakushari@users.noreply.github.com> Date: Fri, 5 Jan 2024 20:35:22 +0300 Subject: [PATCH 06/13] Fix to an exploit related to the new net message --- lua/autorun/standpose.lua | 110 +++++++++-------- lua/weapons/gmod_tool/stools/ragdollstand.lua | 115 +++++++++--------- 2 files changed, 112 insertions(+), 113 deletions(-) diff --git a/lua/autorun/standpose.lua b/lua/autorun/standpose.lua index b0adc19..54d7dde 100644 --- a/lua/autorun/standpose.lua +++ b/lua/autorun/standpose.lua @@ -1,60 +1,62 @@ -if SERVER then +if game.SinglePlayer() then -util.AddNetworkString("StandPose_Server") -util.AddNetworkString("StandPoser_Client") + if SERVER then -net.Receive("StandPose_Server", function() - local rag = net.ReadEntity() - local ent = net.ReadEntity() - - for i=0,rag:GetPhysicsObjectCount()-1 do - local phys = rag:GetPhysicsObjectNum(i) - local b = rag:TranslatePhysBoneToBone(i) - local pos = net.ReadVector() - local ang = net.ReadAngle() - phys:EnableMotion(true) - phys:Wake() - phys:SetPos(pos) - phys:SetAngles(ang) --- if string.sub(rag:GetBoneName(b),1,4) == "prp_" then --- phys:EnableMotion(true) --- phys:Wake() --- else + util.AddNetworkString("StandPose_Server") + util.AddNetworkString("StandPoser_Client") + + net.Receive("StandPose_Server", function() + local rag = net.ReadEntity() + local ent = net.ReadEntity() + if (rag == ent) or not IsValid(rag) or not IsValid(ent) then return end + if rag:GetClass() ~= "prop_ragdoll" or ent:GetClass() ~= "prop_dynamic" then return end + + for i = 0, rag:GetPhysicsObjectCount() - 1 do + local phys = rag:GetPhysicsObjectNum(i) + local b = rag:TranslatePhysBoneToBone(i) + local pos = net.ReadVector() + local ang = net.ReadAngle() + phys:EnableMotion(true) + phys:Wake() + phys:SetPos(pos) + phys:SetAngles(ang) phys:EnableMotion(false) phys:Wake() --- end + + end + ent:Remove() + end) + end - ent:Remove() -end) -end + if CLIENT then -if CLIENT then + net.Receive("StandPoser_Client", function() + local rag = net.ReadEntity() + local ent = net.ReadEntity() + local PhysObjects = net.ReadInt(8) -net.Receive("StandPoser_Client", function() - local rag = net.ReadEntity() - local ent = net.ReadEntity() - local PhysObjects = net.ReadInt(8) - - net.Start("StandPose_Server") - net.WriteEntity(rag) - net.WriteEntity(ent) - for i=0,PhysObjects do - local phys = rag:GetPhysicsObjectNum(i) - local b = rag:TranslatePhysBoneToBone(i) - local pos,ang = ent:GetBonePosition(b) - if pos == ent:GetPos() then - local matrix = ent:GetBoneMatrix(b) - if matrix then - pos = matrix:GetTranslation() - ang = matrix:GetAngles() + net.Start("StandPose_Server") + net.WriteEntity(rag) + net.WriteEntity(ent) + for i = 0, PhysObjects do + local phys = rag:GetPhysicsObjectNum(i) + local b = rag:TranslatePhysBoneToBone(i) + local pos, ang = ent:GetBonePosition(b) + if pos == ent:GetPos() then + local matrix = ent:GetBoneMatrix(b) + if matrix then + pos = matrix:GetTranslation() + ang = matrix:GetAngles() + end end + net.WriteVector(pos) + net.WriteAngle(ang) end - net.WriteVector(pos) - net.WriteAngle(ang) + net.SendToServer() + end) + end - net.SendToServer() -end) end @@ -83,16 +85,16 @@ propt.Receive = function( self, length, player ) if ( !IsValid( player ) ) then return end if ( rag:GetClass() != "prop_ragdoll" ) then return end - local adjust = Vector(0,0,3000) - if not rag:IsInWorld() then adjust = Vector(0,0, -10) end + local adjust = Vector(0, 0, 3000) + if not rag:IsInWorld() then adjust = Vector(0, 0, -10) end - local tr = util.TraceLine({start = rag:GetPos(),endpos = rag:GetPos() - adjust,filter = rag}) + local tr = util.TraceLine({start = rag:GetPos(), endpos = rag:GetPos() - adjust, filter = rag}) local ent = ents.Create("prop_dynamic") ent:SetModel(rag:GetModel()) ent:SetPos(tr.HitPos) local angle = (tr.HitPos - player:GetPos()):Angle() - ent:SetAngles(Angle(0,angle.y-180,0)) + ent:SetAngles(Angle(0, angle.y - 180, 0)) ent:Spawn() if CLIENT then return true end @@ -107,15 +109,15 @@ propt.Receive = function( self, length, player ) net.Send(player) end) else -- if we're in multiplayer, we revert back to the old way stand pose worked, otherwise stuff will get weird - for i=0,PhysObjects do + for i=0, PhysObjects do local phys = rag:GetPhysicsObjectNum(i) local b = rag:TranslatePhysBoneToBone(i) - local pos,ang = ent:GetBonePosition(b) + local pos, ang = ent:GetBonePosition(b) phys:EnableMotion(true) phys:Wake() phys:SetPos(pos) phys:SetAngles(ang) - if string.sub(rag:GetBoneName(b),1,4) == "prp_" then + if string.sub(rag:GetBoneName(b), 1, 4) == "prp_" then phys:EnableMotion(true) phys:Wake() else @@ -128,4 +130,4 @@ propt.Receive = function( self, length, player ) end -properties.Add("standpose",propt) \ No newline at end of file +properties.Add("standpose", propt) \ No newline at end of file diff --git a/lua/weapons/gmod_tool/stools/ragdollstand.lua b/lua/weapons/gmod_tool/stools/ragdollstand.lua index bf0a024..260afda 100644 --- a/lua/weapons/gmod_tool/stools/ragdollstand.lua +++ b/lua/weapons/gmod_tool/stools/ragdollstand.lua @@ -6,65 +6,62 @@ TOOL.ConfigName = nil function TOOL:LeftClick(tr) if self:GetStage() == 0 then - - if !IsValid(tr.Entity) then return false end - if tr.Entity:GetClass() != "prop_ragdoll" then return false end - - if CLIENT then return true end - - self.SelectedEnt = tr.Entity - self:SetStage(1) - return true - - else - - local rag = self.SelectedEnt - if !IsValid(rag) then - self:SetStage(0) - return true - end - - - - local ent = ents.Create("prop_dynamic") - ent:SetModel(rag:GetModel()) - ent:SetPos(tr.HitPos) - local angle = (tr.HitPos - self:GetOwner():GetPos()):Angle() - ent:SetAngles(Angle(0,angle.y-180,0)) - ent:Spawn() - - if CLIENT then return true end - local PhysObjects = rag:GetPhysicsObjectCount()-1 - if game.SinglePlayer() then - timer.Simple(0.1, function() - net.Start("StandPoser_Client") - net.WriteEntity(rag) - net.WriteEntity(ent) - net.WriteInt(PhysObjects, 8) - net.Send(self:GetOwner()) - end) - else -- if we're in multiplayer, we revert back to the old way stand pose worked, otherwise stuff will get weird - for i=0,PhysObjects do - local phys = rag:GetPhysicsObjectNum(i) - local b = rag:TranslatePhysBoneToBone(i) - local pos,ang = ent:GetBonePosition(b) - phys:EnableMotion(true) - phys:Wake() - phys:SetPos(pos) - phys:SetAngles(ang) - if string.sub(rag:GetBoneName(b),1,4) == "prp_" then + + if !IsValid(tr.Entity) then return false end + if tr.Entity:GetClass() != "prop_ragdoll" then return false end + + if CLIENT then return true end + self.SelectedEnt = tr.Entity + self:SetStage(1) + return true + else + + local rag = self.SelectedEnt + if !IsValid(rag) then + self:SetStage(0) + return true + end + + + local ent = ents.Create("prop_dynamic") + ent:SetModel(rag:GetModel()) + ent:SetPos(tr.HitPos) + local angle = (tr.HitPos - self:GetOwner():GetPos()):Angle() + ent:SetAngles(Angle(0, angle.y - 180, 0)) + ent:Spawn() + + if CLIENT then return true end + local PhysObjects = rag:GetPhysicsObjectCount() - 1 + if game.SinglePlayer() then + timer.Simple(0.1, function() + net.Start("StandPoser_Client") + net.WriteEntity(rag) + net.WriteEntity(ent) + net.WriteInt(PhysObjects, 8) + net.Send(self:GetOwner()) + end) + else -- if we're in multiplayer, we revert back to the old way stand pose worked, otherwise stuff will get weird + for i = 0, PhysObjects do + local phys = rag:GetPhysicsObjectNum(i) + local b = rag:TranslatePhysBoneToBone(i) + local pos, ang = ent:GetBonePosition(b) phys:EnableMotion(true) phys:Wake() - else - phys:EnableMotion(false) - phys:Wake() + phys:SetPos(pos) + phys:SetAngles(ang) + if string.sub(rag:GetBoneName(b), 1, 4) == "prp_" then + phys:EnableMotion(true) + phys:Wake() + else + phys:EnableMotion(false) + phys:Wake() + end end + ent:Remove() end - ent:Remove() - end - self:SetStage(0) - return true - + self:SetStage(0) + return true + end end @@ -78,9 +75,9 @@ end if CLIENT then -language.Add("tool.ragdollstand.name","Stand Pose") -language.Add("tool.ragdollstand.desc","Position ragdolls in a standing pose.") -language.Add("tool.ragdollstand.0","Left Click to select a ragdoll.") -language.Add("tool.ragdollstand.1","Now click on a position where you want the ragdoll to stand or Right Click to cancel.") +language.Add("tool.ragdollstand.name", "Stand Pose") +language.Add("tool.ragdollstand.desc", "Position ragdolls in a standing pose.") +language.Add("tool.ragdollstand.0", "Left Click to select a ragdoll.") +language.Add("tool.ragdollstand.1", "Now click on a position where you want the ragdoll to stand or Right Click to cancel.") end \ No newline at end of file From b7dc7b3b57d2d940bb6a4385d01a4b003c97592c Mon Sep 17 00:00:00 2001 From: penolakushari <45951611+penolakushari@users.noreply.github.com> Date: Fri, 5 Jan 2024 20:37:46 +0300 Subject: [PATCH 07/13] Formatting --- lua/autorun/standpose.lua | 2 +- lua/weapons/gmod_tool/stools/ragdollstand.lua | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lua/autorun/standpose.lua b/lua/autorun/standpose.lua index 54d7dde..39f1d1a 100644 --- a/lua/autorun/standpose.lua +++ b/lua/autorun/standpose.lua @@ -130,4 +130,4 @@ propt.Receive = function( self, length, player ) end -properties.Add("standpose", propt) \ No newline at end of file +properties.Add("standpose", propt) diff --git a/lua/weapons/gmod_tool/stools/ragdollstand.lua b/lua/weapons/gmod_tool/stools/ragdollstand.lua index 260afda..4762bbe 100644 --- a/lua/weapons/gmod_tool/stools/ragdollstand.lua +++ b/lua/weapons/gmod_tool/stools/ragdollstand.lua @@ -80,4 +80,4 @@ language.Add("tool.ragdollstand.desc", "Position ragdolls in a standing pose.") language.Add("tool.ragdollstand.0", "Left Click to select a ragdoll.") language.Add("tool.ragdollstand.1", "Now click on a position where you want the ragdoll to stand or Right Click to cancel.") -end \ No newline at end of file +end From fa25016e916f1e55f65a3af46362ebe0ed73b99a Mon Sep 17 00:00:00 2001 From: penolakushari <45951611+penolakushari@users.noreply.github.com> Date: Fri, 20 Sep 2024 21:26:41 +0300 Subject: [PATCH 08/13] Improvements for positioning stuff if raytrace goes outside of the map, models with their root not at the bottom of the model should now get posed properly (like hl2 striders) --- lua/autorun/standpose.lua | 29 ++++++++++++++----- lua/weapons/gmod_tool/stools/ragdollstand.lua | 11 +++++-- 2 files changed, 29 insertions(+), 11 deletions(-) diff --git a/lua/autorun/standpose.lua b/lua/autorun/standpose.lua index 39f1d1a..a7ae662 100644 --- a/lua/autorun/standpose.lua +++ b/lua/autorun/standpose.lua @@ -84,21 +84,34 @@ propt.Receive = function( self, length, player ) if ( !IsValid( rag ) ) then return end if ( !IsValid( player ) ) then return end if ( rag:GetClass() != "prop_ragdoll" ) then return end - - local adjust = Vector(0, 0, 3000) - if not rag:IsInWorld() then adjust = Vector(0, 0, -10) end - local tr = util.TraceLine({start = rag:GetPos(), endpos = rag:GetPos() - adjust, filter = rag}) + local ragpos = rag:GetPos() + local adjust = vector_origin + if not rag:IsInWorld() then + local _, max = rag:WorldSpaceAABB() + ragpos.z = max.z + end + + local tr = util.TraceLine({start = ragpos + adjust, endpos = ragpos - Vector(0, 0, 3000), filter = rag}) + if not util.IsInWorld(tr.HitPos) then + tr = util.TraceLine({start = player:EyePos(), endpos = ragpos, filter = {rag, player}}) + end + local hpos = tr.HitPos local ent = ents.Create("prop_dynamic") ent:SetModel(rag:GetModel()) - ent:SetPos(tr.HitPos) - local angle = (tr.HitPos - player:GetPos()):Angle() + ent:SetPos(hpos) + local min = ent:WorldSpaceAABB() + local diff = hpos.z - min.z + if diff > 100 then + ent:SetPos(hpos + Vector(0, 0, diff)) + end + local angle = (hpos - player:GetPos()):Angle() ent:SetAngles(Angle(0, angle.y - 180, 0)) ent:Spawn() if CLIENT then return true end - local PhysObjects = rag:GetPhysicsObjectCount()-1 + local PhysObjects = rag:GetPhysicsObjectCount() - 1 if game.SinglePlayer() then timer.Simple(0.1, function() @@ -109,7 +122,7 @@ propt.Receive = function( self, length, player ) net.Send(player) end) else -- if we're in multiplayer, we revert back to the old way stand pose worked, otherwise stuff will get weird - for i=0, PhysObjects do + for i = 0, PhysObjects do local phys = rag:GetPhysicsObjectNum(i) local b = rag:TranslatePhysBoneToBone(i) local pos, ang = ent:GetBonePosition(b) diff --git a/lua/weapons/gmod_tool/stools/ragdollstand.lua b/lua/weapons/gmod_tool/stools/ragdollstand.lua index 4762bbe..5aab65c 100644 --- a/lua/weapons/gmod_tool/stools/ragdollstand.lua +++ b/lua/weapons/gmod_tool/stools/ragdollstand.lua @@ -22,11 +22,16 @@ function TOOL:LeftClick(tr) return true end - + local hpos = tr.HitPos local ent = ents.Create("prop_dynamic") ent:SetModel(rag:GetModel()) - ent:SetPos(tr.HitPos) - local angle = (tr.HitPos - self:GetOwner():GetPos()):Angle() + ent:SetPos(hpos) + local min = ent:WorldSpaceAABB() + local diff = hpos.z - min.z + if diff > 100 then + ent:SetPos(hpos + Vector(0, 0, diff)) + end + local angle = (hpos - self:GetOwner():GetPos()):Angle() ent:SetAngles(Angle(0, angle.y - 180, 0)) ent:Spawn() From d89fdf95056862a73d6bea6427aab566bf288832 Mon Sep 17 00:00:00 2001 From: penolakushari <45951611+penolakushari@users.noreply.github.com> Date: Fri, 20 Sep 2024 21:28:53 +0300 Subject: [PATCH 09/13] oops --- lua/autorun/standpose.lua | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lua/autorun/standpose.lua b/lua/autorun/standpose.lua index a7ae662..6cbdde7 100644 --- a/lua/autorun/standpose.lua +++ b/lua/autorun/standpose.lua @@ -86,13 +86,12 @@ propt.Receive = function( self, length, player ) if ( rag:GetClass() != "prop_ragdoll" ) then return end local ragpos = rag:GetPos() - local adjust = vector_origin if not rag:IsInWorld() then local _, max = rag:WorldSpaceAABB() ragpos.z = max.z end - local tr = util.TraceLine({start = ragpos + adjust, endpos = ragpos - Vector(0, 0, 3000), filter = rag}) + local tr = util.TraceLine({start = ragpos, endpos = ragpos - Vector(0, 0, 3000), filter = rag}) if not util.IsInWorld(tr.HitPos) then tr = util.TraceLine({start = player:EyePos(), endpos = ragpos, filter = {rag, player}}) end From 7604665a03079937df0f51f126a1692c9604f0a6 Mon Sep 17 00:00:00 2001 From: penolakushari <45951611+penolakushari@users.noreply.github.com> Date: Tue, 3 Dec 2024 19:51:08 +0300 Subject: [PATCH 10/13] Made it so tool will decide to adjust the position of the ragdoll only if its bounding box gets 10% submerged outside of the map, however this does still present an issue if we'd try to stand pose some ragdolls on inside-map stuff like bridges --- lua/autorun/standpose.lua | 10 +++++++--- lua/weapons/gmod_tool/stools/ragdollstand.lua | 10 +++++++--- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/lua/autorun/standpose.lua b/lua/autorun/standpose.lua index 6cbdde7..40a7403 100644 --- a/lua/autorun/standpose.lua +++ b/lua/autorun/standpose.lua @@ -100,10 +100,14 @@ propt.Receive = function( self, length, player ) local ent = ents.Create("prop_dynamic") ent:SetModel(rag:GetModel()) ent:SetPos(hpos) - local min = ent:WorldSpaceAABB() + local min, max = ent:WorldSpaceAABB() local diff = hpos.z - min.z - if diff > 100 then - ent:SetPos(hpos + Vector(0, 0, diff)) + local low = Vector(hpos.x, hpos.y, min.z) + if not util.IsInWorld(low) then + low.z = low.z + (max.z - min.z) * 0.1 + if not util.IsInWorld(low) then + ent:SetPos(hpos + Vector(0, 0, diff)) + end end local angle = (hpos - player:GetPos()):Angle() ent:SetAngles(Angle(0, angle.y - 180, 0)) diff --git a/lua/weapons/gmod_tool/stools/ragdollstand.lua b/lua/weapons/gmod_tool/stools/ragdollstand.lua index 5aab65c..9ba2ebf 100644 --- a/lua/weapons/gmod_tool/stools/ragdollstand.lua +++ b/lua/weapons/gmod_tool/stools/ragdollstand.lua @@ -26,10 +26,14 @@ function TOOL:LeftClick(tr) local ent = ents.Create("prop_dynamic") ent:SetModel(rag:GetModel()) ent:SetPos(hpos) - local min = ent:WorldSpaceAABB() + local min, max = ent:WorldSpaceAABB() local diff = hpos.z - min.z - if diff > 100 then - ent:SetPos(hpos + Vector(0, 0, diff)) + local low = Vector(hpos.x, hpos.y, min.z) + if not util.IsInWorld(low) then + low.z = low.z + (max.z - min.z) * 0.1 + if not util.IsInWorld(low) then + ent:SetPos(hpos + Vector(0, 0, diff)) + end end local angle = (hpos - self:GetOwner():GetPos()):Angle() ent:SetAngles(Angle(0, angle.y - 180, 0)) From 7a83dc4d0d8e08b69598a58c2866edb80a587633 Mon Sep 17 00:00:00 2001 From: penolakushari <45951611+penolakushari@users.noreply.github.com> Date: Fri, 6 Dec 2024 00:08:32 +0300 Subject: [PATCH 11/13] Using lowest coordinate of the bounding box for positioning stand posed ragdoll is now enabled manually through tool's menu/through a ragdollstand_use_bbox console command --- lua/autorun/standpose.lua | 11 ++++------ lua/weapons/gmod_tool/stools/ragdollstand.lua | 20 ++++++++++++------- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/lua/autorun/standpose.lua b/lua/autorun/standpose.lua index 40a7403..814bd8a 100644 --- a/lua/autorun/standpose.lua +++ b/lua/autorun/standpose.lua @@ -100,14 +100,11 @@ propt.Receive = function( self, length, player ) local ent = ents.Create("prop_dynamic") ent:SetModel(rag:GetModel()) ent:SetPos(hpos) - local min, max = ent:WorldSpaceAABB() + local min = ent:WorldSpaceAABB() local diff = hpos.z - min.z - local low = Vector(hpos.x, hpos.y, min.z) - if not util.IsInWorld(low) then - low.z = low.z + (max.z - min.z) * 0.1 - if not util.IsInWorld(low) then - ent:SetPos(hpos + Vector(0, 0, diff)) - end + local tool = player:GetTool("ragdollstand") + if tool and tool:GetClientNumber("use_bbox") == 1 then + ent:SetPos(hpos + Vector(0, 0, diff)) end local angle = (hpos - player:GetPos()):Angle() ent:SetAngles(Angle(0, angle.y - 180, 0)) diff --git a/lua/weapons/gmod_tool/stools/ragdollstand.lua b/lua/weapons/gmod_tool/stools/ragdollstand.lua index 9ba2ebf..1ce5cbb 100644 --- a/lua/weapons/gmod_tool/stools/ragdollstand.lua +++ b/lua/weapons/gmod_tool/stools/ragdollstand.lua @@ -4,6 +4,8 @@ TOOL.Name = "Stand Pose" TOOL.Command = nil TOOL.ConfigName = nil +TOOL.ClientConVar["use_bbox"] = 0 + function TOOL:LeftClick(tr) if self:GetStage() == 0 then @@ -26,14 +28,10 @@ function TOOL:LeftClick(tr) local ent = ents.Create("prop_dynamic") ent:SetModel(rag:GetModel()) ent:SetPos(hpos) - local min, max = ent:WorldSpaceAABB() + local min = ent:WorldSpaceAABB() local diff = hpos.z - min.z - local low = Vector(hpos.x, hpos.y, min.z) - if not util.IsInWorld(low) then - low.z = low.z + (max.z - min.z) * 0.1 - if not util.IsInWorld(low) then - ent:SetPos(hpos + Vector(0, 0, diff)) - end + if self:GetClientNumber("use_bbox") == 1 then + ent:SetPos(hpos + Vector(0, 0, diff)) end local angle = (hpos - self:GetOwner():GetPos()):Angle() ent:SetAngles(Angle(0, angle.y - 180, 0)) @@ -89,4 +87,12 @@ language.Add("tool.ragdollstand.desc", "Position ragdolls in a standing pose.") language.Add("tool.ragdollstand.0", "Left Click to select a ragdoll.") language.Add("tool.ragdollstand.1", "Now click on a position where you want the ragdoll to stand or Right Click to cancel.") +function TOOL.BuildCPanel(CPanel) + local CB = vgui.Create("DCheckBoxLabel", CPanel) + CB:SetText("Use Bounding Box") + CB:SetConVar("ragdollstand_use_bbox") + CB:SetDark(true) + CPanel:AddItem(CB) +end + end From 7d8d6d2a8745508101e578a0653bbf451c3ff081 Mon Sep 17 00:00:00 2001 From: Astralcircle <142503363+Astralcircle@users.noreply.github.com> Date: Tue, 10 Dec 2024 16:55:40 +0300 Subject: [PATCH 12/13] Fix incompatibility with prop protections --- lua/autorun/standpose.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lua/autorun/standpose.lua b/lua/autorun/standpose.lua index 814bd8a..b3cbbcb 100644 --- a/lua/autorun/standpose.lua +++ b/lua/autorun/standpose.lua @@ -65,9 +65,10 @@ local propt = {} propt.MenuLabel = "Stand Pose" propt.Order = 5000 -propt.Filter = function( self, ent ) +propt.Filter = function( self, ent, ply ) if ( !IsValid( ent ) ) then return false end if ( ent:GetClass() != "prop_ragdoll" ) then return false end + if ( !gamemode.Call( "CanProperty", ply, "standpose", ent ) ) then return false end return true end From 729daa104a41e5a263a5d4b8dccffec660790919 Mon Sep 17 00:00:00 2001 From: Astralcircle <142503363+Astralcircle@users.noreply.github.com> Date: Wed, 11 Dec 2024 06:55:02 +0300 Subject: [PATCH 13/13] Improve even more --- lua/autorun/standpose.lua | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lua/autorun/standpose.lua b/lua/autorun/standpose.lua index b3cbbcb..3f23594 100644 --- a/lua/autorun/standpose.lua +++ b/lua/autorun/standpose.lua @@ -85,6 +85,8 @@ propt.Receive = function( self, length, player ) if ( !IsValid( rag ) ) then return end if ( !IsValid( player ) ) then return end if ( rag:GetClass() != "prop_ragdoll" ) then return end + if ( !properties.CanBeTargeted( rag, player ) ) then return end + if ( !self:Filter( rag, player ) ) then return end local ragpos = rag:GetPos() if not rag:IsInWorld() then