diff --git a/lua/autorun/standpose.lua b/lua/autorun/standpose.lua index 314b1c1..3f23594 100644 --- a/lua/autorun/standpose.lua +++ b/lua/autorun/standpose.lua @@ -1,12 +1,74 @@ +if game.SinglePlayer() then + + if SERVER then + + 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 + 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 + +end 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 @@ -23,33 +85,65 @@ 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 tr = util.TraceLine({start = rag:GetPos(),endpos = rag:GetPos() - Vector(0,0,3000),filter = rag}) - + 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 + local _, max = rag:WorldSpaceAABB() + ragpos.z = max.z + end + + 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 + + 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:SetAngles(Angle(0,angle.y-180,0)) + ent:SetPos(hpos) + local min = ent:WorldSpaceAABB() + local diff = hpos.z - min.z + 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)) 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 + + 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(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() - 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 - end ent:Remove() + end 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 185e961..1ce5cbb 100644 --- a/lua/weapons/gmod_tool/stools/ragdollstand.lua +++ b/lua/weapons/gmod_tool/stools/ragdollstand.lua @@ -4,54 +4,71 @@ TOOL.Name = "Stand Pose" TOOL.Command = nil TOOL.ConfigName = nil +TOOL.ClientConVar["use_bbox"] = 0 + 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 - - if CLIENT then 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() - 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() + + 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 - phys:EnableMotion(false) - phys:Wake() + + local rag = self.SelectedEnt + if !IsValid(rag) then + self:SetStage(0) + return true end - end - ent:Remove() - self:SetStage(0) - return true - + + local hpos = tr.HitPos + local ent = ents.Create("prop_dynamic") + ent:SetModel(rag:GetModel()) + ent:SetPos(hpos) + local min = ent:WorldSpaceAABB() + local diff = hpos.z - min.z + 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)) + 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 + phys:EnableMotion(true) + phys:Wake() + else + phys:EnableMotion(false) + phys:Wake() + end + end + ent:Remove() + end + self:SetStage(0) + return true + end end @@ -65,9 +82,17 @@ 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.") + +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 \ No newline at end of file +end