Files
wnsrc/lua/pac3/core/client/parts/faceposer.lua
lifestorm 94063e4369 Upload
2024-08-04 22:55:00 +03:00

206 lines
4.4 KiB
Lua

--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
local BUILDER, PART = pac.PartTemplate("base")
PART.ClassName = "faceposer"
PART.FriendlyName = "face poser"
PART.Icon = 'icon16/monkey.png'
PART.Group = 'entity'
BUILDER:StartStorableVars()
:GetSet("Preset", "", {enums = function(part)
local ent = part:GetOwner()
if not ent:IsValid() then return end
local maps = {}
local toolgun = {}
for i = 0, 255 do
local name = ent:GetFlexName(i)
if name then
toolgun[name] = GetConVar("faceposer_flex" .. i):GetFloat()
end
end
maps.toolgun = util.TableToJSON({
scale = GetConVar("faceposer_scale"):GetFloat(),
weight_map = util.TableToJSON(toolgun),
})
for preset_name, map in pairs(presets.GetTable( "face" )) do
local preset = {}
for key, weight in pairs(map) do
local i = tonumber(key:match("faceposer_flex(%d+)"))
if i then
local name = ent:GetFlexName(i)
if name then
preset[name] = tonumber(weight)
end
end
end
maps[preset_name] = util.TableToJSON({
scale = tonumber(map.faceposer_scale),
weight_map = util.TableToJSON(preset),
})
end
return maps
end})
:GetSet("FlexWeights", "", {hidden = true})
:GetSet("Scale", 1)
:GetSet("Additive", false)
:EndStorableVars()
-- Make the internal flex names be more presentable, TODO: handle numbers
local function PrettifyName( name )
name = name:Replace( "_", " " )
-- Try to split text into words, where words would start with single uppercase character
local newParts = {}
for id, str in pairs( string.Explode( " ", name ) ) do
local wordStart = 1
for i = 2, str:len() do
local c = str[ i ]
if ( c:upper() == c ) then
local toAdd = str:sub(wordStart, i - 1)
if ( toAdd:upper() == toAdd ) then continue end
table.insert( newParts, toAdd )
wordStart = i
end
end
table.insert( newParts, str:sub(wordStart, str:len()))
end
-- Uppercase all first characters
for id, str in pairs( newParts ) do
if ( str:len() < 2 ) then continue end
newParts[ id ] = str:Left( 1 ):upper() .. str:sub( 2 )
end
return table.concat( newParts, " " )
end
function PART:GetDynamicProperties()
local ent = self:GetOwner()
if not ent:IsValid() then return end
if ent.GetFlexNum and ent:GetFlexNum() and ent:GetFlexNum() == 0 then return end
local tbl = {}
for i = 0, ent:GetFlexNum() - 1 do
local name = ent:GetFlexName(i)
tbl[name] = {
key = name,
sort_key = -i,
get = function()
local weight_map = util.JSONToTable(self:GetFlexWeights()) or {}
return weight_map[name] or 0
end,
set = function(val)
local weight_map = util.JSONToTable(self:GetFlexWeights()) or {}
weight_map[name] = tonumber(val) or 0
self:SetFlexWeights(util.TableToJSON(weight_map))
end,
udata = {
editor_friendly = PrettifyName(name),
group = "flexes",
editor_sensitivity = 0.1,
editor_onchange = function(self, num)
local min, max = ent:GetFlexBounds(i)
return math.Clamp(num, min, max)
end,
},
}
end
return tbl
end
function PART:SetPreset(json)
local preset = util.JSONToTable(json)
if preset then
self:SetFlexWeights(preset.weight_map)
self:SetScale(preset.scale)
end
self.Preset = ""
end
function PART:GetNiceName()
return "face pose"
end
function PART:GetWeightMap()
local data = self:GetFlexWeights()
if data ~= self.last_data then
self.weight_map = util.JSONToTable(data) or {}
self.last_data = data
end
return self.weight_map
end
function PART:UpdateFlex()
local ent = self:GetOwner()
if not ent:IsValid() then return end
ent:SetFlexScale(self.Scale)
ent.pac_touching_flexes = ent.pac_touching_flexes or {}
for name, weight in pairs(self:GetWeightMap()) do
local id = ent:GetFlexIDByName(name)
if id then
if self.Additive then
weight = ent:GetFlexWeight(id) + weight
end
ent:SetFlexWeight(id, weight)
ent.pac_touching_flexes[id] = pac.RealTime + 0.1
end
end
end
function PART:OnThink()
local ent = self:GetOwner()
if not ent:IsPlayer() then
self:UpdateFlex()
end
end
function PART:OnBuildBonePositions()
self:UpdateFlex()
end
function PART:OnShow(from_rendering)
self:UpdateFlex()
end
function PART:OnHide()
self:UpdateFlex()
end
function PART:OnRemove()
self:UpdateFlex()
end
BUILDER:Register()