From 08bd3ecdf1377a36dd1ad938635c346c6dac5176 Mon Sep 17 00:00:00 2001 From: toasterpanic Date: Thu, 4 Jun 2026 13:03:20 -0400 Subject: [PATCH] Finally, an actually good unfake animation <3 --- lua/entities/npc_ragdoll_unfaker.lua | 143 +++++++++----------- lua/entities/v4.old | 191 +++++++++++++++++++++++++++ lua/zcnpci/modules/falling_legs.lua | 2 + 3 files changed, 256 insertions(+), 80 deletions(-) create mode 100644 lua/entities/v4.old diff --git a/lua/entities/npc_ragdoll_unfaker.lua b/lua/entities/npc_ragdoll_unfaker.lua index af12317..e4ffbef 100644 --- a/lua/entities/npc_ragdoll_unfaker.lua +++ b/lua/entities/npc_ragdoll_unfaker.lua @@ -4,8 +4,6 @@ ENT.Type = "anim" ENT.Base = "base_anim" ENT.AutomaticFrameAdvance = true - - local bones_to_animate = { "ValveBiped.Bip01_Pelvis", "ValveBiped.Bip01_Spine2", @@ -24,6 +22,15 @@ local bones_to_animate = { "ValveBiped.Bip01_L_Hand", } +-- Copy pasted directly from the GMOD wiki with small edits +local function SetRagdollPos(ragdoll, pos) + for i = 0, ragdoll:GetPhysicsObjectCount() - 1 do + local phys = ragdoll:GetPhysicsObjectNum(i) + local localPos = ragdoll:WorldToLocal( phys:GetPos() ) + phys:SetPos(pos + localPos) + end +end + function ENT:Initialize() if SERVER then print("I AM SERVERSIDE") @@ -32,116 +39,92 @@ function ENT:Initialize() if CLIENT then print("I AM CLIENTSIDE") - timer.Simple(0.2, function() - - end) end end -function ENT:Draw() +function ENT:Think() if CLIENT then + + hook.Add("physics") local old_ragdoll = self:GetNWEntity("parent") local old_npc = self:GetNWEntity("parent_npc") if IsValid(old_ragdoll) and IsValid(old_npc) then - if !self.ready_to_unfake then - self:SetModel(old_ragdoll:GetModel()) + local ragdoll = self.ragdoll - self.bone_list = {} - self.bone_list_end = {} - - self:SetupBones() + if !self.ready_to_animate then + self.ragdoll = ClientsideRagdoll(old_ragdoll:GetModel()) - local i = 0 - while i < self:GetBoneCount() do - local name = self:GetBoneName(i) - if name == "__INVALIDBONE__" then - i = i + 1 - continue - end + ragdoll = self.ragdoll - table.insert(bones_to_animate, name) + self.ragdoll:SetNoDraw(false) + self.ragdoll:DrawShadow(true) - - local matrix = Matrix() - - local position, angle = old_ragdoll:GetBonePosition(i) - if position == old_ragdoll:GetPos() then - get_matrix = old_ragdoll:GetBoneMatrix(i) - if get_matrix then - position = get_matrix:GetTranslation() - end - end - matrix:Translate(position) - matrix:Rotate(angle) + SetRagdollPos(self.ragdoll, old_ragdoll:GetPos()) - self.bone_list[name] = matrix + print(self.ragdoll) + print("SHOW UP YOU PIECE OF SHIT") - local matrix = Matrix() + for i, name in pairs(bones_to_animate) do + local object = ragdoll:GetPhysicsObjectNum(ragdoll:TranslateBoneToPhysBone(ragdoll:LookupBone(name))) + local parent_object = old_ragdoll:GetBoneMatrix(old_ragdoll:LookupBone(name)) + print(old_ragdoll) - local position, angle = old_npc:GetBonePosition(i) - if position == old_npc:GetPos() then - get_matrix = old_npc:GetBoneMatrix(i) - if get_matrix then - position = get_matrix:GetTranslation() - end - end - matrix:Translate(position) - matrix:Rotate(angle) - + --if !IsValid(parent_object) then continue end - self.bone_list_end[name] = matrix - - i = i + 1 + object:SetPos(parent_object:GetTranslation()) + object:SetAngles(parent_object:GetAngles()) end - PrintTable(bones_to_animate) - - --[[for i,name in pairs(bones_to_animate) do - local bone_index = old_ragdoll:LookupBone(name) - if bone_index == nil then continue end - - self.bone_list[name] = Matrix(old_ragdoll:GetBoneMatrix(bone_index)) - end]] - - print("BONES:"..self:GetBoneCount()) - - self.ready_to_unfake = true + self.ready_to_animate = true end + + local fake_start = self:GetNWFloat("fake_start") + local fake_end = self:GetNWFloat("fake_end") - self:SetPos(old_ragdoll:GetPos()) + local progress = (CurTime() - fake_start) / (fake_end - fake_start) - self:SetupBones() + for i, name in pairs(bones_to_animate) do + local object = ragdoll:GetPhysicsObjectNum(ragdoll:TranslateBoneToPhysBone(ragdoll:LookupBone(name))) + local parent_bone = old_npc:LookupBone(name) - for name,matrix in pairs(self.bone_list) do - local bone_index = self:LookupBone(name) - if bone_index == -1 then - print(name.." does not exist, skipping...") - continue - end + if parent_bone == -1 then continue end + local parent_bone_matrix = old_npc:GetBoneMatrix(parent_bone) + if !parent_bone_matrix then continue end - --print(name) - --local bone_matrix = old_ragdoll:GetBoneMatrix(bone_index) + local parent_bone_pos, parent_bone_angle = parent_bone_matrix:GetTranslation(), parent_bone_matrix:GetAngles() + local old_bone_pos, old_bone_angle = object:GetPos(), object:GetAngles() + --parent_bone_angle.y = parent_bone_angle.y + 90 - if matrix:GetTranslation():DistToSqr(self:GetPos()) == 1 then continue end + local shadow_data = { + secondstoarrive = 0.01, + pos = LerpVector(progress, old_bone_pos, parent_bone_pos), + angle = LerpAngle(progress, old_bone_angle, parent_bone_angle), + maxspeed = 400 * 4, + maxangular = 2000 * 4, + maxspeeddamp = 120 * 4, + maxangularspeeddamp = 600 * 4, + } - self:SetBoneMatrix(bone_index, matrix) + -- Can't set position inside physics tick, crashes the game instantly. + -- Instead, send a shadow for it to follow (I think? I don't know GMod is kinda funky) + object:ComputeShadowControl(shadow_data) + + object:Wake() + + --i = i + 1 end end end - self:DrawModel() -end - -function ENT:Think() - + self:NextThink(CurTime() + 0.1) return true end function ENT:OnRemove() if CLIENT then - --[[if self.anim_ragdoll then - self.anim_ragdoll:Remove() - end]] + if self.ragdoll then + self.ragdoll:Remove() + end end -end \ No newline at end of file +end diff --git a/lua/entities/v4.old b/lua/entities/v4.old new file mode 100644 index 0000000..1341984 --- /dev/null +++ b/lua/entities/v4.old @@ -0,0 +1,191 @@ +AddCSLuaFile() + +ENT.Type = "anim" +ENT.Base = "base_anim" +ENT.AutomaticFrameAdvance = true + + + +local bones_to_animate = { + "ValveBiped.Bip01_Pelvis", + "ValveBiped.Bip01_Spine2", + "ValveBiped.Bip01_Head1", + "ValveBiped.Bip01_R_Thigh", + "ValveBiped.Bip01_L_Thigh", + "ValveBiped.Bip01_L_Calf", + "ValveBiped.Bip01_R_Calf", + "ValveBiped.Bip01_R_Foot", + "ValveBiped.Bip01_L_Foot", + "ValveBiped.Bip01_R_Upperarm", + "ValveBiped.Bip01_L_Upperarm", + "ValveBiped.Bip01_R_Forearm", + "ValveBiped.Bip01_L_Forearm", + "ValveBiped.Bip01_R_Hand", + "ValveBiped.Bip01_L_Hand", +} + +local function GetBoneLocalOffsetMatrix(ent, bone_index) + local parent = ent:GetBoneParent(bone_index) + local parent_matrix = Matrix(ent:GetBoneMatrix(parent)) + parent_matrix:Invert() + parent_matrix:Mul(ent:GetBoneMatrix(bone_index)) + + return parent_matrix +end + +local function GetGlobalMatrixFromLocal(ent, bone_index, local_matrix) + local parent = ent:GetBoneParent(bone_index) + local parent_matrix = Matrix(ent:GetBoneMatrix(parent)) + parent_matrix:Mul(local_matrix) + + return parent_matrix +end + +function ENT:Initialize() + if SERVER then + print("I AM SERVERSIDE") + self:SetModel("models/dav0r/hoverball.mdl") + end + + if CLIENT then + print("I AM CLIENTSIDE") + timer.Simple(0.2, function() + + end) + end +end + +function ENT:Draw() + if CLIENT then + local old_ragdoll = self:GetNWEntity("parent") + local old_npc = self:GetNWEntity("parent_npc") + if IsValid(old_ragdoll) and IsValid(old_npc) then + if !self.ready_to_unfake then + self:SetModel(old_ragdoll:GetModel()) + + self.bone_list = {} + self.bone_list_end = {} + self.bone_list_end_offset = {} + + self:SetupBones() + + local i = 0 + while i < self:GetBoneCount() do + local name = self:GetBoneName(i) + if name == "__INVALIDBONE__" then + i = i + 1 + continue + end + + table.insert(bones_to_animate, name) + + local matrix = Matrix() + + local position, angle = old_ragdoll:GetBonePosition(i) + if position == old_ragdoll:GetPos() then + get_matrix = old_ragdoll:GetBoneMatrix(i) + if get_matrix then + position = get_matrix:GetTranslation() + end + end + matrix:Translate(position) + matrix:Rotate(angle) + + self.bone_list[name] = matrix + + local matrix = Matrix() + + local npc_bone_index = old_npc:LookupBone(name) + + local position, angle = old_npc:GetBonePosition(npc_bone_index) + if position == old_npc:GetPos() then + print("DINGUS!!!! "..name) + self.bone_list_end_offset[name] = GetBoneLocalOffsetMatrix(self, npc_bone_index) + + get_matrix = old_npc:GetBoneMatrix(npc_bone_index) + if get_matrix then + position = get_matrix:GetTranslation() + end + else + matrix:Translate(position) + matrix:Rotate(angle) + + + self.bone_list_end[name] = matrix + end + + + + i = i + 1 + end + + PrintTable(bones_to_animate) + + --[[for i,name in pairs(bones_to_animate) do + local bone_index = old_ragdoll:LookupBone(name) + if bone_index == nil then continue end + + self.bone_list[name] = Matrix(old_ragdoll:GetBoneMatrix(bone_index)) + end]] + + print("BONES:"..self:GetBoneCount()) + + self.ready_to_unfake = true + end + + self:SetPos(old_ragdoll:GetPos()) + + self:SetupBones() + + local fake_start = self:GetNWFloat("fake_start") + local fake_end = self:GetNWFloat("fake_end") + + local progress = (CurTime() - fake_start) / (fake_end - fake_start) + + for name,matrix in pairs(self.bone_list) do + local bone_index = self:LookupBone(name) + if bone_index == -1 then + print(name.." does not exist, skipping...") + continue + end + + local matrix_end = self.bone_list_end[name] + + if matrix_end == nil then + if (self.bone_list_end_offset[name] == nil) then + print("OH FUCKKKKKKKK! No matrix end for "..name) + continue + end + + matrix_end = GetGlobalMatrixFromLocal(self, bone_index, self.bone_list_end_offset[name]) + end + + local final_matrix = Matrix() + final_matrix:Translate(LerpVector(progress, matrix:GetTranslation(), matrix_end:GetTranslation())) + final_matrix:Rotate(LerpAngle(progress, matrix:GetAngles(), matrix_end:GetAngles())) + + --print(name) + --local bone_matrix = old_ragdoll:GetBoneMatrix(bone_index) + + if matrix:GetTranslation():DistToSqr(self:GetPos()) == 1 then continue end + + self:SetBoneMatrix(bone_index, final_matrix) + end + end + end + + self:DrawModel() +end + +function ENT:Think() + + return true +end + +function ENT:OnRemove() + if CLIENT then + --[[if self.anim_ragdoll then + self.anim_ragdoll:Remove() + end]] + end +end \ No newline at end of file diff --git a/lua/zcnpci/modules/falling_legs.lua b/lua/zcnpci/modules/falling_legs.lua index 4d26177..a877a8d 100644 --- a/lua/zcnpci/modules/falling_legs.lua +++ b/lua/zcnpci/modules/falling_legs.lua @@ -494,6 +494,8 @@ function MODULE:PhysicsSimulate(phys, dt) self.unfaker:SetPos(target:GetPos()) self.unfaker:SetNWEntity("parent", target) self.unfaker:SetNWEntity("parent_npc", ent) + self.unfaker:SetNWFloat("fake_start", self.FakeUpStart) + self.unfaker:SetNWFloat("fake_end", self.FakeUpEnd) target:SetRenderMode(RENDERMODE_NONE)