diff --git a/HarmonySrc/HandPosePose.cs b/HarmonySrc/HandPosePose.cs index 631104e..6422981 100644 --- a/HarmonySrc/HandPosePose.cs +++ b/HarmonySrc/HandPosePose.cs @@ -323,6 +323,7 @@ namespace NecromancerTome { HandHolds.Update(); HandPose.Apply(); + HeldTweak.Apply(); } } diff --git a/HarmonySrc/HeldTweak.cs b/HarmonySrc/HeldTweak.cs new file mode 100644 index 0000000..a3b461c --- /dev/null +++ b/HarmonySrc/HeldTweak.cs @@ -0,0 +1,139 @@ +using System.Collections.Generic; +using System.Globalization; +using UnityEngine; +using UnityEngine.Scripting; + +namespace NecromancerTome +{ + /// + /// Подбор посадки модели предмета в руке прямо в игре (10.10.2026, череп): как necropose для жестов. Сдвиг, поворот + /// и масштаб применяются к дочерним узлам модели в руке (корень модели держит игра) каждый кадр - переживают смену + /// слота. Итог - строкой в лог, затем переносится в настройку модели (NecroSkullSetup и т.п.) и бандл пересобирается + /// при закрытой игре. + /// + public static class HeldTweak + { + public static bool Enabled; + public static Vector3 Pos; // метры, в осях модели + public static Vector3 Rot; // градусы, добавка к исходному повороту + public static float Scale = 1f; + + /// Исходные локальные значения детей модели (по экземпляру узла). + static readonly Dictionary _base = new Dictionary(); + + public static Transform Model() + { + EntityPlayerLocal pl = GameManager.Instance?.World?.GetPrimaryPlayer(); + return pl?.inventory?.GetHoldingItemTransform(); + } + + public static void Apply() + { + Transform m = Model(); + if (m == null) + { + return; + } + for (int i = 0; i < m.childCount; i++) + { + Transform c = m.GetChild(i); + int id = c.GetInstanceID(); + if (!_base.TryGetValue(id, out var b)) + { + if (!Enabled) + { + continue; + } + b = (c.localPosition, c.localRotation, c.localScale); + _base[id] = b; + } + if (Enabled) + { + c.localPosition = Scale * b.p + Pos; + c.localRotation = Quaternion.Euler(Rot) * b.r; + c.localScale = b.s * Scale; + } + else + { + c.localPosition = b.p; + c.localRotation = b.r; + c.localScale = b.s; + _base.Remove(id); + } + } + } + + public static string F(float _v) => _v.ToString("0.###", CultureInfo.InvariantCulture); + public static string F(Vector3 _v) => F(_v.x) + " " + F(_v.y) + " " + F(_v.z); + } + + /// + /// necroheld - посадка модели в руке: + /// pos x y z (см) | add x y z (см) | rot x y z (градусы) | scale s | off | show + /// + [Preserve] + public class ConsoleCmdNecroHeld : ConsoleCmdAbstract + { + public override string[] getCommands() => new[] { "necroheld" }; + public override string getDescription() => "NecromancerTome: посадка модели в руке - pos x y z (см)|add x y z (см)|rot x y z|scale s|off|show"; + + static bool Num(List _p, int _i, out float _v) + { + _v = 0f; + return _p.Count > _i && float.TryParse(_p[_i].Replace(',', '.'), NumberStyles.Float, CultureInfo.InvariantCulture, out _v); + } + + static bool Vec(List _p, out Vector3 _v) + { + bool ok = Num(_p, 1, out float x) & Num(_p, 2, out float y) & Num(_p, 3, out float z); + _v = new Vector3(x, y, z); + return ok; + } + + public override void Execute(List _params, CommandSenderInfo _senderInfo) + { + string cmd = _params.Count > 0 ? _params[0] : "show"; + Vector3 v; + switch (cmd) + { + case "pos" when Vec(_params, out v): + HeldTweak.Pos = v / 100f; + break; + case "add" when Vec(_params, out v): + HeldTweak.Pos += v / 100f; + break; + case "rot" when Vec(_params, out v): + HeldTweak.Rot = v; + break; + case "scale" when Num(_params, 1, out float s) && s > 0f: + HeldTweak.Scale = s; + break; + case "off": + HeldTweak.Enabled = false; + HeldTweak.Pos = Vector3.zero; + HeldTweak.Rot = Vector3.zero; + HeldTweak.Scale = 1f; + Out("посадка сброшена"); + return; + case "show": + break; + default: + Out(getDescription()); + return; + } + if (cmd != "show") + { + HeldTweak.Enabled = true; + } + Transform m = HeldTweak.Model(); + Out("модель " + (m != null ? m.name : "нет") + ": сдвиг (см) " + HeldTweak.F(HeldTweak.Pos * 100f) + ", поворот " + + HeldTweak.F(HeldTweak.Rot) + ", масштаб " + HeldTweak.F(HeldTweak.Scale) + (HeldTweak.Enabled ? "" : " (выключено)")); + } + + static void Out(string _s) + { + SdtdConsole.Instance.Output(_s); + Debug.Log("[NecromancerTome] necroheld: " + _s); + } + } +} diff --git a/NecromancerHarmony.dll b/NecromancerHarmony.dll index 2a6a242..a770afa 100644 Binary files a/NecromancerHarmony.dll and b/NecromancerHarmony.dll differ