Basic use for Prop ragdoll tool now works as was intended, using secondary fire will make it select all constrained entities that player aimed at, which would allow to set a custom skeleton for prop ragdoll through drag and drop feature. Pressing reload on entities with Prop Ragdoll data will dissolve the prop ragdoll. Removing one of the entities that make up a prop ragdoll will dissolve it too. Constrained entities tab in ragdoll mover will now ignore props that are parented to something. IK Chains creator tool now supports saving prop ragdoll IKs

This commit is contained in:
penolakushari 2023-08-17 20:20:39 +03:00
parent 1263e56dea
commit 630d23955d
4 changed files with 652 additions and 92 deletions

View File

@ -115,7 +115,7 @@ local function rgmGetConstrainedEntities(parent)
local count = 1
for _, ent in pairs(conents) do
if not IsValid(ent) or ent:IsWorld() or ent:IsConstraint() or not util.IsValidModel(ent:GetModel()) then continue end
if not IsValid(ent) or ent:IsWorld() or ent:IsConstraint() or not util.IsValidModel(ent:GetModel()) or IsValid(ent:GetParent()) then continue end
if ent:GetPhysicsObjectCount() > 0 then
children[count] = ent
count = count + 1

View File

@ -121,6 +121,8 @@ net.Receive("rgmikRequestSave", function(len, pl)
local ent = tool.SelectedSaveEnt
if not ent or not ent.rgmIKChains then rgmSendNotif(6, pl) return end
local ispropragdoll = ent.rgmPRidtoent and true or false
local num = 0
local iks = {}
@ -131,29 +133,51 @@ net.Receive("rgmikRequestSave", function(len, pl)
net.Start("rgmikSave")
net.WriteBool(ispropragdoll)
net.WriteEntity(ent)
net.WriteUInt(num,4)
for i = 1, num do
net.WriteUInt(iks[i].type, 4)
net.WriteUInt(ent:TranslatePhysBoneToBone(iks[i].hip), 10)
net.WriteUInt(ent:TranslatePhysBoneToBone(iks[i].knee), 10)
net.WriteUInt(ent:TranslatePhysBoneToBone(iks[i].foot), 10)
if not ispropragdoll then
for i = 1, num do
net.WriteUInt(iks[i].type, 4)
net.WriteUInt(ent:TranslatePhysBoneToBone(iks[i].hip), 10)
net.WriteUInt(ent:TranslatePhysBoneToBone(iks[i].knee), 10)
net.WriteUInt(ent:TranslatePhysBoneToBone(iks[i].foot), 10)
end
else
for i = 1, num do
net.WriteUInt(iks[i].type, 4)
net.WriteUInt(iks[i].hip, 13)
net.WriteUInt(iks[i].knee, 13)
net.WriteUInt(iks[i].foot, 13)
end
end
net.Send(pl)
end)
net.Receive("rgmikLoad", function(len, pl)
local ispropragdoll = net.ReadBool()
local num = net.ReadUInt(4)
local iktable = {}
for i = 1, num do
iktable[i] = {}
iktable[i].type = net.ReadUInt(4)
iktable[i].hip = net.ReadUInt(10)
iktable[i].knee = net.ReadUInt(10)
iktable[i].foot = net.ReadUInt(10)
if not ispropragdoll then
for i = 1, num do
iktable[i] = {}
iktable[i].type = net.ReadUInt(4)
iktable[i].hip = net.ReadUInt(10)
iktable[i].knee = net.ReadUInt(10)
iktable[i].foot = net.ReadUInt(10)
end
else
for i = 1, num do
iktable[i] = {}
iktable[i].type = net.ReadUInt(4)
iktable[i].hip = net.ReadUInt(13)
iktable[i].knee = net.ReadUInt(13)
iktable[i].foot = net.ReadUInt(13)
end
end
local tool = pl:GetTool("ragmover_ikchains")
@ -162,11 +186,23 @@ net.Receive("rgmikLoad", function(len, pl)
local ent = tool.SelectedSaveEnt
if not ent then return end
ent.rgmIKChains = {}
if not ispropragdoll then
ent.rgmIKChains = {}
for k, ik in ipairs(iktable) do
if ik.hip == 1023 or ik.knee == 1023 or ik.foot == 1023 then continue end
table.insert(ent.rgmIKChains, {hip = rgm.BoneToPhysBone(ent, ik.hip), knee = rgm.BoneToPhysBone(ent, ik.knee), foot = rgm.BoneToPhysBone(ent, ik.foot), type = ik.type})
for k, ik in ipairs(iktable) do
if ik.hip == 1023 or ik.knee == 1023 or ik.foot == 1023 then continue end
table.insert(ent.rgmIKChains, {hip = rgm.BoneToPhysBone(ent, ik.hip), knee = rgm.BoneToPhysBone(ent, ik.knee), foot = rgm.BoneToPhysBone(ent, ik.foot), type = ik.type})
end
else
if not ent.rgmPRidtoent or not ent:GetClass() == "prop_physics" then return end
for id, ent in pairs(ent.rgmPRidtoent) do
ent.rgmIKChains = {}
for k, ik in ipairs(iktable) do
table.insert(ent.rgmIKChains, {hip = ik.hip, knee = ik.knee, foot = ik.foot, type = ik.type})
end
end
end
rgmSendNotif(7, pl)
@ -269,7 +305,7 @@ end
function TOOL:RightClick(tr)
local ent = tr.Entity
if ent:GetClass() == "prop_ragdoll" then
if ent:GetClass() == "prop_ragdoll" or (ent:GetClass() == "prop_physics" and ent.rgmPRidtoent) then
if SERVER then
if self.SelectedSaveEnt == ent then return false end
rgmSendEnt(ent, self:GetOwner())
@ -365,12 +401,22 @@ local function ChainSaver(cpanel)
local iktable = util.JSONToTable(json)
net.Start("rgmikLoad")
net.WriteBool(iktable.ispropragdoll)
net.WriteUInt(#iktable, 4)
for k, ik in ipairs(iktable) do
net.WriteUInt(ik.type, 4)
net.WriteUInt(SelectedEnt:LookupBone(ik.hip) or 1023, 10)
net.WriteUInt(SelectedEnt:LookupBone(ik.knee) or 1023, 10)
net.WriteUInt(SelectedEnt:LookupBone(ik.foot) or 1023, 10)
if not iktable.ispropragdoll then
for k, ik in ipairs(iktable) do
net.WriteUInt(ik.type, 4)
net.WriteUInt(SelectedEnt:LookupBone(ik.hip) or 1023, 10)
net.WriteUInt(SelectedEnt:LookupBone(ik.knee) or 1023, 10)
net.WriteUInt(SelectedEnt:LookupBone(ik.foot) or 1023, 10)
end
else
for k, ik in ipairs(iktable) do
net.WriteUInt(ik.type, 4)
net.WriteUInt(ik.hip, 13)
net.WriteUInt(ik.knee, 13)
net.WriteUInt(ik.foot, 13)
end
end
net.SendToServer()
end
@ -589,14 +635,27 @@ end)
net.Receive("rgmikSave", function(len)
local iktable = {}
local ispropragdoll = net.ReadBool()
local ent = net.ReadEntity()
local count = net.ReadUInt(4)
for i = 1, net.ReadUInt(4) do
iktable[i] = {}
iktable[i].type = net.ReadUInt(4)
iktable[i].hip = ent:GetBoneName(net.ReadUInt(10))
iktable[i].knee = ent:GetBoneName(net.ReadUInt(10))
iktable[i].foot = ent:GetBoneName(net.ReadUInt(10))
if not ispropragdoll then
for i = 1, count do
iktable[i] = {}
iktable[i].type = net.ReadUInt(4)
iktable[i].hip = ent:GetBoneName(net.ReadUInt(10))
iktable[i].knee = ent:GetBoneName(net.ReadUInt(10))
iktable[i].foot = ent:GetBoneName(net.ReadUInt(10))
end
else
iktable.ispropragdoll = true
for i = 1, count do
iktable[i] = {}
iktable[i].type = net.ReadUInt(4)
iktable[i].hip = net.ReadUInt(13)
iktable[i].knee = net.ReadUInt(13)
iktable[i].foot = net.ReadUInt(13)
end
end
local json = util.TableToJSON(iktable, true)

View File

@ -3,7 +3,21 @@ TOOL.Category = "Poser"
TOOL.Command = nil
TOOL.ConfigName = ""
CVMaxPRBones = CreateConVar("sv_ragdollmover_max_prop_ragdoll_bones", 32, FCVAR_ARCHIVE + FCVAR_NOTIFY, "Maximum amount of bones that can be used in single Prop Ragdoll", 0, 4096)
local function ClearPropRagdoll(ent)
ent.rgmPRidtoent = nil
ent.rgmPRenttoid = nil
ent.rgmPRparent = nil
duplicator.ClearEntityModifier(ent, "Ragdoll Mover Prop Ragdoll")
end
if SERVER then
util.AddNetworkString("rgmprSendConEnts")
util.AddNetworkString("rgmprApplySkeleton")
duplicator.RegisterEntityModifier("Ragdoll Mover Prop Ragdoll", function(pl, ent, data)
ent.rgmPRenttoid = table.Copy(data.enttoid)
@ -31,6 +45,7 @@ if SERVER then
local newdata = {}
newdata.enttoid = {}
for e, id in pairs(ent.rgmPRenttoid) do
if type(e) ~= "Entity" or not IsValid(e) then continue end
newdata.enttoid[e:EntIndex()] = id
end
newdata.idtoent = table.Copy(ent.rgmPRidtoent)
@ -39,94 +54,579 @@ if SERVER then
duplicator.ClearEntityModifier(ent, "Ragdoll Mover Prop Ragdoll")
duplicator.StoreEntityModifier(ent, "Ragdoll Mover Prop Ragdoll", newdata)
for id, e in pairs(ent.rgmPRidtoent) do
for e, id in pairs(ent.rgmPRenttoid) do
if type(e) ~= "Entity" or (type(e) == "Entity" and not IsValid(e)) then -- if some of those entities don't exist, then we gotta dissolve the "ragdoll"
ent.rgmPRidtoent = nil
ent.rgmPRenttoid = nil
ent.rgmPRparent = nil
duplicator.ClearEntityModifier(ent, "Ragdoll Mover Prop Ragdoll")
ClearPropRagdoll(ent)
break
end
end
end
end)
hook.Add("EntityRemoved", "rgmPropRagdollEntRemoved", function(ent)
if ent.rgmPRidtoent then
for id, ent in pairs(ent.rgmPRidtoent) do
if not IsValid(ent) then continue end
ClearPropRagdoll(ent)
end
end
end)
net.Receive("rgmprApplySkeleton", function(len, pl)
local count = net.ReadUInt(13)
local ents = {}
local fail = false
for i = 0, count - 1 do
ents[i] = {}
ents[i].ent = net.ReadEntity()
ents[i].id = net.ReadUInt(13)
local parent = net.ReadUInt(13)
ents[i].parent = parent ~= 4100 and parent or nil
if not IsValid(ents[i].ent) or not ents[i].ent:GetClass() == "prop_physics" then
fail = true
end
end
if fail or count > CVMaxPRBones:GetInt() then return end
for id, data in pairs(ents) do
local ent = data.ent
if ent.rgmPRidtoent then
for id, ent in pairs(ent.rgmPRidtoent) do
ClearPropRagdoll(ent)
end
end
ent.rgmPRidtoent = {}
ent.rgmPRenttoid = {}
ent.rgmPRparent = data.parent
for id, moredata in pairs(ents) do
ent.rgmPRidtoent[moredata.id] = moredata.ent
ent.rgmPRenttoid[moredata.ent] = moredata.id
end
local data = {}
data.idtoent = table.Copy(ent.rgmPRidtoent)
data.enttoid = {}
for ent, id in pairs(ent.rgmPRenttoid) do
data.enttoid[ent:EntIndex()] = id
end
data.parent = ent.rgmPRparent
duplicator.StoreEntityModifier(ent, "Ragdoll Mover Prop Ragdoll", data)
end
end)
end
function TOOL:LeftClick(tr)
local stage = self:GetStage()
local ent = tr.Entity
if ent:GetClass() ~= "prop_physics" then return false end
return false
end
if stage == 0 then
ent.rgmPRidtoent = {}
ent.rgmPRenttoid = {}
ent.rgmPRidtoent[0] = ent
ent.rgmPRenttoid[ent] = 0
function TOOL:RightClick(tr)
if SERVER then
local ent = tr.Entity
local doweusethis = false
local conents = {}
local count = 0
self.idtoent = ent.rgmPRidtoent
self.enttoid = ent.rgmPRenttoid
print("One")
self:SetStage(1)
return true
elseif stage == 1 then
if self.enttoid[ent] then return false end
self.idtoent[1] = ent
self.enttoid[ent] = 1
ent.rgmPRidtoent = self.idtoent
ent.rgmPRenttoid = self.enttoid
ent.rgmPRparent = 0
print("Two")
self:SetStage(2)
return true
elseif stage == 2 then
if self.enttoid[ent] then return false end
self.idtoent[2] = ent
self.enttoid[ent] = 2
ent.rgmPRidtoent = self.idtoent
ent.rgmPRenttoid = self.enttoid
ent.rgmPRparent = 1
print("Three")
self:SetStage(3)
return true
else
if self.enttoid[ent] then return false end
self.idtoent[3] = ent
self.enttoid[ent] = 3
ent.rgmPRidtoent = self.idtoent
ent.rgmPRenttoid = self.enttoid
ent.rgmPRparent = 2
print("Four")
self:SetStage(0)
if SERVER then
for id, ent in pairs(ent.rgmPRidtoent) do
local data = {}
data.idtoent = table.Copy(ent.rgmPRidtoent)
data.enttoid = {}
for e, id in pairs(ent.rgmPRenttoid) do
data.enttoid[e:EntIndex()] = id
if IsValid(ent) and ent:GetClass("prop_physics") then
doweusethis = true
local ents = constraint.GetAllConstrainedEntities(ent)
for ent, _ in pairs(ents) do
if ent:GetClass() == "prop_physics" and not IsValid(ent:GetParent()) then
conents[ent] = true
end
data.parent = ent.rgmPRparent
duplicator.StoreEntityModifier(ent, "Ragdoll Mover Prop Ragdoll", data)
end
for ent, _ in pairs(conents) do
count = count + 1
end
end
self.idtoent = nil
self.enttoid = nil
return true
net.Start("rgmprSendConEnts")
net.WriteBool(doweusethis)
if doweusethis then
net.WriteUInt(count, 13)
for ent, _ in pairs(conents) do
net.WriteEntity(ent)
end
end
net.Send(self:GetOwner())
end
return false
return true
end
function TOOL:Reload(tr)
local ent = tr.Entity
if not IsValid(ent) or not ent.rgmPRidtoent then return false end
if SERVER then
for id, ent in pairs(ent.rgmPRidtoent) do
ClearPropRagdoll(ent)
end
end
return true
end
if CLIENT then
local PRUI
local HoveredEnt
local function RGMCallApplySkeleton()
if not PRUI or not PRUI.PRTree or not PRUI.PRTree.Nodes then return end
if not next(PRUI.PRTree.Nodes) then return end
local tree = PRUI.PRTree
net.Start("rgmprApplySkeleton")
net.WriteUInt(tree.Bones, 13)
for id, node in pairs(tree.Nodes) do
net.WriteEntity(node.ent)
net.WriteUInt(node.id, 13)
net.WriteUInt(node.parent or 4100,13)
end
net.SendToServer()
end
local function DeleteNodeRecursive(node)
if IsValid(node) then
node:SetParent(nil)
node:Remove()
for _, child in ipairs(node:GetChildNodes()) do
DeleteNodeRecursive(child)
end
end
end
local function FindSelfRecursive(nodestart, nodefind)
if nodestart == nodefind then return true end
for _, node in ipairs(nodestart:GetChildNodes()) do
if node == nodefind then return true end
if FindSelfRecursive(node, nodefind) then return true end
end
return false
end
local function TreeUpdateHBar()
local width = 0
for id, node in pairs(PRUI.PRTree.Nodes) do
local labelsize = node.Label:GetTextSize()
local curwidth = labelsize + (node.depth * 17)
if curwidth > width then
width = curwidth
end
end
PRUI.PRTree:UpdateWidth(width + 8 + 32 + 16)
end
local function AddHBar(self) -- There is no horizontal scrollbars in gmod, so I guess we'll override vertical one from GMod
self.HBar = vgui.Create("DVScrollBar")
self.HBar.btnUp.Paint = function(panel, w, h) derma.SkinHook("Paint", "ButtonLeft", panel, w, h) end
self.HBar.btnDown.Paint = function(panel, w, h) derma.SkinHook("Paint", "ButtonRight", panel, w, h) end
self.PanelWidth = 100
self.LastWidth = 1
self.HBar.SetScroll = function(self, scrll)
if (not self.Enabled) then self.Scroll = 0 return end
self.Scroll = math.Clamp( scrll, 0, self.CanvasSize )
self:InvalidateLayout()
local func = self:GetParent().OnHScroll
if func then
func(self:GetParent(), self:GetOffset())
end
end
self.HBar.OnMousePressed = function(self)
local x, y = self:CursorPos()
local PageSize = self.BarSize
if (x > self.btnGrip.x) then
self:SetScroll(self:GetScroll() + PageSize)
else
self:SetScroll(self:GetScroll() - PageSize)
end
end
self.HBar.OnCursorMoved = function(self, x, y)
if (not self.Enabled) then return end
if (not self.Dragging) then return end
local x, y = self:ScreenToLocal(gui.MouseX(), 0)
x = x - self.btnUp:GetWide()
x = x - self.HoldPos
local BtnHeight = self:GetTall()
if (self:GetHideButtons()) then BtnHeight = 0 end
local TrackSize = self:GetWide() - BtnHeight * 2 - self.btnGrip:GetWide()
x = x / TrackSize
self:SetScroll(x * self.CanvasSize)
end
self.HBar.Grip = function(self)
if (!self.Enabled) then return end
if (self.BarSize == 0) then return end
self:MouseCapture(true)
self.Dragging = true
local x, y = self.btnGrip:ScreenToLocal(gui.MouseX(), 0)
self.HoldPos = x
self.btnGrip.Depressed = true
end
self.HBar.PerformLayout = function(self)
local Tall = self:GetTall()
local BtnHeight = Tall
if (self:GetHideButtons()) then BtnHeight = 0 end
local Scroll = self:GetScroll() / self.CanvasSize
local BarSize = math.max(self:BarScale() * (self:GetWide() - (BtnHeight * 2)), 10)
local Track = self:GetWide() - (BtnHeight * 2) - BarSize
Track = Track + 1
Scroll = Scroll * Track
self.btnGrip:SetPos(BtnHeight + Scroll, 0)
self.btnGrip:SetSize(BarSize, Tall)
if (BtnHeight > 0) then
self.btnUp:SetPos(0, 0)
self.btnUp:SetSize(BtnHeight, Tall)
self.btnDown:SetPos(self:GetWide() - BtnHeight, 0)
self.btnDown:SetSize(BtnHeight, Tall)
self.btnUp:SetVisible( true )
self.btnDown:SetVisible( true )
else
self.btnUp:SetVisible( false )
self.btnDown:SetVisible( false )
self.btnDown:SetSize(BtnHeight, Tall)
self.btnUp:SetSize(BtnHeight, Tall)
end
end
self.OnVScroll = function(self, iOffset)
local x = self.pnlCanvas:GetPos()
self.pnlCanvas:SetPos(x, iOffset)
end
self.OnHScroll = function(self, iOffset)
local _, y = self.pnlCanvas:GetPos()
self.pnlCanvas:SetPos(iOffset, y)
end
self.PerformLayoutInternal = function(self)
local HTall, VTall = self:GetTall(), self.pnlCanvas:GetTall()
local HWide, VWide = self:GetWide(), self.PanelWidth
local XPos, YPos = 0, 0
self:Rebuild()
self.VBar:SetUp(self:GetTall(), self.pnlCanvas:GetTall())
self.HBar:SetUp(self:GetWide(), self.pnlCanvas:GetWide())
YPos = self.VBar:GetOffset()
XPos = self.HBar:GetOffset()
if (self.VBar.Enabled) then VWide = VWide - self.VBar:GetWide() end
if (self.HBar.Enabled) then HTall = HTall - self.HBar:GetTall() end
self.pnlCanvas:SetPos(XPos, YPos)
self.pnlCanvas:SetSize(VWide, HTall)
self:Rebuild()
if (HWide ~= self.LastWidth) then
self.HBar:SetScroll(self.HBar:GetScroll())
end
if (VTall ~= self.pnlCanvas:GetTall()) then
self.VBar:SetScroll(self.VBar:GetScroll())
end
self.LastWidth = HWide
end
self.PerformLayout = function(self)
self:PerformLayoutInternal()
end
self.UpdateWidth = function(self, newwidth)
self.PanelWidth = newwidth
self:InvalidateLayout()
end
end
local function CCol(cpanel,text, notexpanded)
local cat = vgui.Create("DCollapsibleCategory",cpanel)
cat:SetExpanded(1)
cat:SetLabel(text)
cpanel:AddItem(cat)
local col = vgui.Create("DPanelList")
col:SetAutoSize(true)
col:SetSpacing(5)
col:EnableHorizontal(false)
col:EnableVerticalScrollbar(true)
col.Paint = function()
surface.DrawRect(0, 0, 500, 500)
end
cat:SetContents(col)
cat:SetExpanded(not notexpanded)
return col, cat
end
local function AddPRNode(parent, node)
HoveredEnt = nil
if node.used then return end
if not PRUI then return end
local bones = PRUI.PRTree.Bones
if bones + 1 > CVMaxPRBones:GetInt() then return end
local id = 0
while PRUI.PRTree.Nodes[id] do
id = id + 1
end
PRUI.PRTree.Nodes[id] = parent:AddNode(id .. " [" .. node.text .. "]", "icon16/brick.png")
PRUI.PRTree.Nodes[id].ent = node.ent
PRUI.PRTree.Nodes[id].id = id
PRUI.PRTree.Nodes[id].parent = parent.id or nil
PRUI.PRTree.Nodes[id].depth = parent.depth and parent.depth + 1 or 1
PRUI.PRTree.Nodes[id]:Droppable("rgmPRMove")
PRUI.PRTree.Nodes[id].DoRightClick = function()
local deletemenu = DermaMenu(false, PRUI.PRTree)
local deletebutt = deletemenu:AddOption("Remove from list", function()
local parent = PRUI.PRTree.Nodes[id]:GetParent()
parent:SetVisible(false)
DeleteNodeRecursive(PRUI.PRTree.Nodes[id])
if next(parent:GetChildren()) then
parent:SetVisible(true)
else
parent:GetParent().ChildNodes = nil
end
end)
deletebutt:SetIcon("icon16/cross.png")
deletemenu:Open()
return true
end
PRUI.PRTree.Nodes[id]:Receiver("rgmprNew", function(self, received, dropped)
PRUI.PRTree:SetSelectedItem(PRUI.PRTree.Nodes[id])
if not dropped then return end
for k, v in ipairs(received) do
AddPRNode(PRUI.PRTree.Nodes[id], v)
end
end)
PRUI.PRTree.Nodes[id]:Receiver("rgmPRMove", function(self, received, dropped)
PRUI.PRTree:SetSelectedItem(PRUI.PRTree.Nodes[id])
if not dropped then return end
for k, v in ipairs(received) do
if FindSelfRecursive(v, self) then continue end
local parent = v:GetParent()
parent:SetVisible(false)
self:InsertNode(v)
v.parent = id
v.depth = self.depth + 1
if next(parent:GetChildren()) then
parent:SetVisible(true)
else
parent:GetParent().ChildNodes = nil
end
TreeUpdateHBar()
end
end)
PRUI.PRTree.Nodes[id].OnRemove = function()
if not PRUI.PRTree.Nodes[id] then return end
node.used = false
node:SetIcon("icon16/brick.png")
PRUI.PRTree.Bones = PRUI.PRTree.Bones - 1
PRUI.PRTree.Nodes[id] = nil
end
node.used = true
node:SetIcon("icon16/delete.png")
if IsValid(PRUI.PRTree.Nodes[id]:GetParent()) then
PRUI.PRTree.Nodes[id]:GetParent():SetVisible(true)
end
PRUI.PRTree.Bones = bones + 1
TreeUpdateHBar()
end
local function PropRagdollCreator(cpanel)
local helptext = vgui.Create("DLabel", cpanel)
helptext:SetWrap(true)
helptext:SetAutoStretchVertical(true)
helptext:SetDark(true)
helptext:SetText("Drag nodes from Constrained Entities tab into Prop Ragdoll tab to create skeleton for your prop ragdoll and then apply it. This tool can not read Prop Ragdoll skeleton data from existing Prop Ragdolls")
cpanel:AddItem(helptext)
local PropRagdollUI = {}
local constrainedents = CCol(cpanel, "Constrained Entities")
PropRagdollUI.EntTree = vgui.Create("DTree", constrainedents)
PropRagdollUI.EntTree:SetTall(300)
constrainedents:AddItem(PropRagdollUI.EntTree)
local creatorpanel = CCol(cpanel, "Prop Ragdoll")
PropRagdollUI.PRTree = vgui.Create("DTree", creatorpanel)
PropRagdollUI.PRTree:SetTall(300)
PropRagdollUI.PRTree.Bones = 0
PropRagdollUI.PRTree:Receiver("rgmprNew", function(self, received, dropped)
if not dropped then return end
for k, v in ipairs(received) do
AddPRNode(PropRagdollUI.PRTree, v)
end
end)
PropRagdollUI.PRTree:Receiver("rgmPRMove", function(self, received, dropped)
if not dropped then return end
for k, v in ipairs(received) do
local parent = v:GetParent()
parent:SetVisible(false)
self:Root():InsertNode(v)
v.parent = nil
if next(parent:GetChildren()) then
parent:SetVisible(true)
else
parent:GetParent().ChildNodes = nil
end
TreeUpdateHBar()
end
end)
AddHBar(PropRagdollUI.PRTree)
creatorpanel:AddItem(PropRagdollUI.PRTree)
creatorpanel:AddItem(PropRagdollUI.PRTree.HBar)
local applybutt = vgui.Create("DButton", creatorpanel)
applybutt:SetText("Apply Skeleton")
applybutt.DoClick = RGMCallApplySkeleton
creatorpanel:AddItem(applybutt)
return PropRagdollUI
end
local function GetModelName(ent)
local name = ent:GetModel()
local splitname = string.Split(name, "/")
return splitname[#splitname]
end
local function UpdateConstrainedEnts(ents)
if not PRUI then return end
PRUI.EntTree:Clear()
PRUI.PRTree:Clear()
PRUI.EntNodes = {}
PRUI.PRTree.Bones = 0
PRUI.PRTree.Nodes = {}
if not next(ents) then return end
for _, ent in ipairs(ents) do
local text = GetModelName(ent)
PRUI.EntNodes[ent] = PRUI.EntTree:AddNode(text, "icon16/brick.png")
PRUI.EntNodes[ent]:Droppable("rgmprNew")
PRUI.EntNodes[ent].ent = ent
PRUI.EntNodes[ent].text = text
PRUI.EntNodes[ent].used = false
PRUI.EntNodes[ent].Label.OnCursorEntered = function()
if PRUI.EntNodes[ent].used then return end
HoveredEnt = ent
end
PRUI.EntNodes[ent].Label.OnCursorExited = function()
HoveredEnt = nil
end
end
end
function TOOL.BuildCPanel(CPanel)
PRUI = PropRagdollCreator(CPanel)
end
local COLOR_RGMGREEN = Color(0,200,0,255)
function TOOL:DrawHUD()
if PRUI and PRUI.PRTree and PRUI.PRTree.Nodes then
for id, node in pairs(PRUI.PRTree.Nodes) do
local ent = node.ent
local pos = ent:GetPos():ToScreen()
local textpos = { x = pos.x+5, y = pos.y-5 }
surface.DrawCircle(pos.x, pos.y, 3.5, COLOR_RGMGREEN)
draw.SimpleText(node.id,"Default",textpos.x,textpos.y,COLOR_RGMGREEN,TEXT_ALIGN_LEFT,TEXT_ALIGN_BOTTOM)
if not node.parent then continue end
local parent = PRUI.PRTree.Nodes[node.parent].ent
local parentpos = parent:GetPos():ToScreen()
surface.SetDrawColor(255, 255, 255)
surface.DrawLine(pos.x, pos.y, parentpos.x, parentpos.y)
end
end
if IsValid(HoveredEnt) then
rgm.DrawEntName(HoveredEnt)
end
end
net.Receive("rgmprSendConEnts", function(len, pl)
local validents = net.ReadBool()
local ents = {}
if validents then
local count = net.ReadUInt(13)
for i = 1, count do
ents[i] = net.ReadEntity()
end
end
UpdateConstrainedEnts(ents)
end)
end

View File

@ -149,5 +149,6 @@ tool.ragmover_ikchains.upperarm=Upperarm
tool.ragmover_ikchains.knee=Knee
tool.ragmover_ikchains.elbow=Elbow
tool.ragmover_propragdoll.name=Ragdoll Mover - Prop Ragdoll
tool.ragmover_propragdoll.name2=Rag Mover - Prop Ragdoll