153 lines
5.2 KiB
C#
153 lines
5.2 KiB
C#
using System.Collections.Generic;
|
|
using System.Globalization;
|
|
using UnityEngine;
|
|
using UnityEngine.Scripting;
|
|
|
|
namespace NecromancerTome
|
|
{
|
|
/// <summary>
|
|
/// Подбор посадки модели предмета в руке прямо в игре (10.10.2026, череп): как necropose для жестов. Сдвиг, поворот
|
|
/// и масштаб применяются к дочерним узлам модели в руке (корень модели держит игра) каждый кадр - переживают смену
|
|
/// слота. Итог - строкой в лог, затем переносится в настройку модели (NecroSkullSetup и т.п.) и бандл пересобирается
|
|
/// при закрытой игре.
|
|
/// </summary>
|
|
public static class HeldTweak
|
|
{
|
|
public static bool Enabled;
|
|
public static Vector3 Pos; // метры, в осях модели
|
|
public static Vector3 Rot; // градусы, добавка к исходному повороту
|
|
public static float Scale = 1f;
|
|
/// <summary>Предмет, для которого подбирается посадка (тот, что был в руке при первой команде). Другие предметы
|
|
/// не трогаются: 10.10 без этого поворот черепа применился и к книге, взятой следом.</summary>
|
|
public static string Item;
|
|
|
|
/// <summary>Исходные локальные значения детей модели (по экземпляру узла).</summary>
|
|
static readonly Dictionary<int, (Vector3 p, Quaternion r, Vector3 s)> _base = new Dictionary<int, (Vector3, Quaternion, Vector3)>();
|
|
|
|
public static Transform Model()
|
|
{
|
|
EntityPlayerLocal pl = GameManager.Instance?.World?.GetPrimaryPlayer();
|
|
return pl?.inventory?.GetHoldingItemTransform();
|
|
}
|
|
|
|
public static string HeldName()
|
|
{
|
|
EntityPlayerLocal pl = GameManager.Instance?.World?.GetPrimaryPlayer();
|
|
return pl?.inventory?.holdingItem?.Name;
|
|
}
|
|
|
|
public static void Apply()
|
|
{
|
|
Transform m = Model();
|
|
if (m == null || (Enabled && HeldName() != Item))
|
|
{
|
|
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);
|
|
}
|
|
|
|
/// <summary>
|
|
/// necroheld - посадка модели в руке:
|
|
/// pos x y z (см) | add x y z (см) | rot x y z (градусы) | scale s | off | show
|
|
/// </summary>
|
|
[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<string> _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<string> _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<string> _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")
|
|
{
|
|
if (!HeldTweak.Enabled)
|
|
{
|
|
HeldTweak.Item = HeldTweak.HeldName();
|
|
}
|
|
HeldTweak.Enabled = true;
|
|
}
|
|
Transform m = HeldTweak.Model();
|
|
Out("предмет " + HeldTweak.Item + ", модель " + (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);
|
|
}
|
|
}
|
|
}
|