using System.Collections.Generic; using System.Text; using UnityEngine; using UnityEngine.Scripting; namespace NecromancerTome { /// /// necrobones - разведка к жестам (BACKLOG «Заклинания с руки и жесты», 1.7.0). Свой хват - /// это неподвижная поза рук от первого лица, как у браслета (кулак к противнику, без движения /// при действии): кости рига ставятся в нужную комбинацию после аниматора. Сначала надо знать /// кости: команда пишет в лог дерево рига рук от первого лица (EModelSDCS.baseRigFP, его создаёт /// SDCSUtils.CreateVizFP под Camera/UFPSRoot) с локальными поворотами и позициями, и параметры /// аниматора FPPlayerController (WeaponHoldType и прочие) с текущими значениями. /// [Preserve] public class ConsoleCmdNecroBones : ConsoleCmdAbstract { const string Tag = "[NecromancerTome] necrobones: "; public override string[] getCommands() => new[] { "necrobones" }; public override string getDescription() => "NecromancerTome: дерево костей рук от первого лица и параметры аниматора - в лог"; public override void Execute(List _params, CommandSenderInfo _senderInfo) { EntityPlayerLocal player = GameManager.Instance.World?.GetPrimaryPlayer(); if (player == null) { return; } if (!(player.emodel is EModelSDCS sdcs) || sdcs.baseRigFP == null) { SdtdConsole.Instance.Output("риг рук от первого лица не найден (EModelSDCS.baseRigFP)"); return; } Transform root = sdcs.baseRigFP.transform; ItemClass held = player.inventory?.holdingItem; Debug.Log(Tag + "в руке " + (held != null ? held.GetItemName() + ", HoldType " + held.HoldType.Value : "ничего") + ", вид от первого лица " + sdcs.IsFPV); Debug.Log(Tag + "путь рига: " + PathOf(root)); int count = 0; var sb = new StringBuilder(); Dump(root, 0, sb, ref count); foreach (string line in sb.ToString().Split('\n')) { if (line.Length > 0) { Debug.Log(Tag + line); } } Animator anim = root.GetComponentInChildren(true) ?? root.GetComponentInParent(); if (anim != null) { Debug.Log(Tag + "аниматор на " + anim.name + ", контроллер " + (anim.runtimeAnimatorController != null ? anim.runtimeAnimatorController.name : "нет")); foreach (AnimatorControllerParameter p in anim.parameters) { string v = p.type == AnimatorControllerParameterType.Float ? anim.GetFloat(p.nameHash).ToString("0.###") : p.type == AnimatorControllerParameterType.Int ? anim.GetInteger(p.nameHash).ToString() : p.type == AnimatorControllerParameterType.Bool ? anim.GetBool(p.nameHash).ToString() : "trigger"; Debug.Log(Tag + " параметр " + p.name + " (" + p.type + ") = " + v); } for (int l = 0; l < anim.layerCount; l++) { AnimatorClipInfo[] clips = anim.GetCurrentAnimatorClipInfo(l); string names = ""; foreach (AnimatorClipInfo c in clips) { names += (names.Length > 0 ? ", " : "") + (c.clip != null ? c.clip.name : "?") + " x" + c.weight.ToString("0.##"); } Debug.Log(Tag + " слой " + l + " " + anim.GetLayerName(l) + " вес " + anim.GetLayerWeight(l).ToString("0.##") + ": " + names); } } else { Debug.Log(Tag + "аниматор не найден"); } SdtdConsole.Instance.Output("костей рук: " + count + " - дерево и параметры аниматора в логе (строки necrobones)"); } static void Dump(Transform _t, int _depth, StringBuilder _sb, ref int _count) { _count++; Vector3 e = _t.localEulerAngles; Vector3 p = _t.localPosition; _sb.Append(new string(' ', _depth * 2)).Append(_t.name) .Append(_t.gameObject.activeSelf ? "" : " [выкл]") .Append(" пов. ").Append(e.x.ToString("0.#")).Append(' ').Append(e.y.ToString("0.#")).Append(' ').Append(e.z.ToString("0.#")) .Append(" поз. ").Append(p.x.ToString("0.###")).Append(' ').Append(p.y.ToString("0.###")).Append(' ').Append(p.z.ToString("0.###")) .Append('\n'); for (int i = 0; i < _t.childCount; i++) { Dump(_t.GetChild(i), _depth + 1, _sb, ref _count); } } static string PathOf(Transform _t) { string s = _t.name; for (Transform p = _t.parent; p != null; p = p.parent) { s = p.name + "/" + s; } return s; } } }