Руки одержимого: аниматор включается; necroarms anim|mat|set|trigger|tint для подбора в игре

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
AlexCube
2026-10-13 16:06:18 +03:00
co-authored by Claude Opus 5.5
parent cfcd9d33a5
commit 0c42714416
+161 -3
View File
@@ -33,7 +33,9 @@ namespace NecromancerTome
"zombieUtilityWorker", "zombieYo",
};
public static readonly Color Tint = new Color(0.55f, 0.56f, 0.55f, 1f);
public static Color Tint = new Color(0.55f, 0.56f, 0.55f, 1f);
/// <summary>Параметры аниматора рук, выставленные necroarms set (подбор «пустых рук»), - ставятся и при пересборке.</summary>
static readonly Dictionary<string, float> _animParams = new Dictionary<string, float>();
/// <summary>Сдвиг рук от камеры (подбор necroarms pos). У персонажа игра опускает руки на 1.7 м: начало их
/// скелета - у ног (vp_FPWeapon PositionOffset 0,-1.7,0.02 для SDCS).</summary>
public static Vector3 Offset = new Vector3(0f, -1.7f, 0.02f);
@@ -127,7 +129,19 @@ namespace NecromancerTome
}
// Префаб рук выключен: у персонажа его включает BodyAnimator (State = Visible) - тест 13.10: «активны False».
_rig.SetActive(true);
Debug.Log("[NecromancerTome] FpArms: снято скриптов " + stripped);
// Аниматор у персонажа включает тот же BodyAnimator (тест 13.10: «рука одна и без анимации»).
Animator anim = _rig.GetComponent<Animator>();
if (anim != null)
{
anim.enabled = true;
anim.cullingMode = AnimatorCullingMode.AlwaysAnimate;
anim.Rebind();
foreach (KeyValuePair<string, float> kv in _animParams)
{
SetParam(anim, kv.Key, kv.Value);
}
}
Debug.Log("[NecromancerTome] FpArms: снято скриптов " + stripped + ", аниматор " + (anim != null ? anim.runtimeAnimatorController?.name : "нет"));
_rig.name = "necroZombieArmsFP";
int layer = LayerMask.NameToLayer("HoldingItem");
int tinted = 0;
@@ -188,6 +202,122 @@ namespace NecromancerTome
return s;
}
static Animator Anim => _rig != null ? _rig.GetComponent<Animator>() : null;
static bool SetParam(Animator _a, string _name, float _v)
{
foreach (AnimatorControllerParameter p in _a.parameters)
{
if (p.name != _name)
{
continue;
}
switch (p.type)
{
case AnimatorControllerParameterType.Float: _a.SetFloat(_name, _v); break;
case AnimatorControllerParameterType.Int: _a.SetInteger(_name, (int)_v); break;
case AnimatorControllerParameterType.Bool: _a.SetBool(_name, _v != 0f); break;
default: _a.SetTrigger(_name); break;
}
return true;
}
return false;
}
/// <summary>necroarms set: параметр аниматора (запоминается для пересборки; у триггера - только срабатывание).</summary>
public static string Set(string _name, float _v)
{
Animator a = Anim;
if (a == null)
{
return "рук нет";
}
if (!SetParam(a, _name, _v))
{
return "нет параметра " + _name;
}
_animParams[_name] = _v;
return _name + " = " + _v.ToString(CultureInfo.InvariantCulture);
}
public static string Trigger(string _name)
{
Animator a = Anim;
if (a == null)
{
return "рук нет";
}
a.SetTrigger(_name);
return "триггер " + _name;
}
/// <summary>Аниматор рук: вкл, контроллер, текущие клипы по слоям и все параметры со значениями.</summary>
public static string DumpAnim()
{
Animator a = Anim;
if (a == null)
{
return "рук нет";
}
string s = "аниматор вкл " + a.enabled + ", контроллер " + a.runtimeAnimatorController?.name + ", слоёв " + a.layerCount;
for (int l = 0; l < a.layerCount; l++)
{
string clips = "";
foreach (AnimatorClipInfo ci in a.GetCurrentAnimatorClipInfo(l))
{
clips += " " + ci.clip?.name + "(" + ci.weight.ToString("F2") + ")";
}
s += "\n слой " + l + " " + a.GetLayerName(l) + " вес " + a.GetLayerWeight(l).ToString("F2") + ":" + clips;
}
foreach (AnimatorControllerParameter p in a.parameters)
{
string v = p.type == AnimatorControllerParameterType.Float ? a.GetFloat(p.name).ToString("F2", CultureInfo.InvariantCulture)
: p.type == AnimatorControllerParameterType.Int ? a.GetInteger(p.name).ToString()
: p.type == AnimatorControllerParameterType.Bool ? a.GetBool(p.name).ToString() : "trigger";
s += "\n " + p.name + " = " + v;
}
return s;
}
/// <summary>Материалы рук: шейдер и его цветовые/текстурные свойства (подбор серого).</summary>
public static string DumpMat()
{
if (_rig == null)
{
return "рук нет";
}
string s = "";
foreach (SkinnedMeshRenderer smr in _rig.GetComponentsInChildren<SkinnedMeshRenderer>(true))
{
foreach (Material m in smr.sharedMaterials)
{
if (m == null)
{
continue;
}
s += "\n " + smr.name + " / " + m.name + " / " + m.shader.name + ":";
for (int i = 0; i < m.shader.GetPropertyCount(); i++)
{
UnityEngine.Rendering.ShaderPropertyType t = m.shader.GetPropertyType(i);
string n = m.shader.GetPropertyName(i);
if (t == UnityEngine.Rendering.ShaderPropertyType.Color)
{
s += " " + n + "=" + m.GetColor(n);
}
else if (t == UnityEngine.Rendering.ShaderPropertyType.Texture)
{
s += " " + n + "[" + (m.GetTexture(n) != null ? m.GetTexture(n).name : "-") + "]";
}
else
{
s += " " + n + "=" + m.GetFloat(n).ToString("F2", CultureInfo.InvariantCulture);
}
}
}
}
return s;
}
/// <summary>Пересобрать руки на месте (после necroarms pos/parent).</summary>
public static void Rebuild()
{
@@ -226,7 +356,7 @@ namespace NecromancerTome
public class ConsoleCmdNecroArms : ConsoleCmdAbstract
{
public override string[] getCommands() => new[] { "necroarms" };
public override string getDescription() => "NecromancerTome: руки одержимого от первого лица - [pos x y z | parent cam|ufps]";
public override string getDescription() => "NecromancerTome: руки одержимого от первого лица - [pos x y z | parent cam|ufps | anim | mat | set <param> <value> | trigger <name> | tint r g b]";
void Out(string _s)
{
@@ -250,6 +380,34 @@ namespace NecromancerTome
FpArms.ParentCamera = _params[1] != "ufps";
FpArms.Rebuild();
}
else if (cmd == "anim")
{
Out(FpArms.DumpAnim());
return;
}
else if (cmd == "mat")
{
Out(FpArms.DumpMat());
return;
}
else if (cmd == "set" && _params.Count >= 3 && float.TryParse(_params[2].Replace(',', '.'), NumberStyles.Float, CultureInfo.InvariantCulture, out float v))
{
Out(FpArms.Set(_params[1], v));
return;
}
else if (cmd == "trigger" && _params.Count >= 2)
{
Out(FpArms.Trigger(_params[1]));
return;
}
else if (cmd == "tint" && _params.Count >= 4 &&
float.TryParse(_params[1].Replace(',', '.'), NumberStyles.Float, CultureInfo.InvariantCulture, out float r) &&
float.TryParse(_params[2].Replace(',', '.'), NumberStyles.Float, CultureInfo.InvariantCulture, out float g) &&
float.TryParse(_params[3].Replace(',', '.'), NumberStyles.Float, CultureInfo.InvariantCulture, out float b))
{
FpArms.Tint = new Color(r, g, b, 1f);
FpArms.Rebuild();
}
Out(FpArms.Dump());
}
}