using System.Collections.Generic;
using System.Text;
using UnityEngine;
using UnityEngine.Scripting;
namespace NecromancerTome
{
///
/// necromodel <блок> - выписать в лог устройство модели блока (09.10.2026, для своей двери-книжного
/// шкафа: где у ванильной двери петля, куда она открывается, какие коллайдеры). Иерархия с местом, поворотом,
/// масштабом, мешами и коллайдерами; у аниматоров - параметры и клипы, а створка в состояниях «Open» и
/// «Close» - пробой клипа на копии префаба. Копия создаётся и тут же уничтожается.
///
[Preserve]
public class ConsoleCmdNecroModel : ConsoleCmdAbstract
{
public override string[] getCommands() => new[] { "necromodel" };
public override string getDescription() => "NecromancerTome: устройство модели блока в лог (necromodel <имя блока>)";
public override void Execute(List _params, CommandSenderInfo _senderInfo)
{
if (_params.Count < 1)
{
SdtdConsole.Instance.Output("necromodel <имя блока>");
return;
}
Block block = Block.GetBlockByName(_params[0]);
string model = block?.Properties.GetString("Model");
if (string.IsNullOrEmpty(model))
{
SdtdConsole.Instance.Output("Нет блока или у него нет Model: " + _params[0]);
return;
}
if (!model.StartsWith("@") && !model.StartsWith("#"))
{
model = "@:" + model;
}
GameObject prefab = DataLoader.LoadAsset(model);
if (prefab == null)
{
SdtdConsole.Instance.Output("Модель не загрузилась: " + model);
return;
}
var sb = new StringBuilder();
sb.AppendLine("[NecromancerTome] necromodel " + _params[0] + " = " + model + ", ModelOffset " +
block.Properties.GetString("ModelOffset") + ", MultiBlockDim " + block.Properties.GetString("MultiBlockDim"));
Dump(prefab.transform, 0, sb);
GameObject copy = Object.Instantiate(prefab);
try
{
foreach (Animator a in copy.GetComponentsInChildren(true))
{
RuntimeAnimatorController rc = a.runtimeAnimatorController;
sb.AppendLine("Animator на " + a.name + ": " + (rc != null ? rc.name : "нет контроллера"));
foreach (AnimatorControllerParameter p in a.parameters)
{
sb.AppendLine(" параметр " + p.name + " " + p.type);
}
if (rc == null)
{
continue;
}
foreach (AnimationClip clip in rc.animationClips)
{
sb.AppendLine(" клип " + clip.name + ", " + clip.length.ToString("F2") + " с");
clip.SampleAnimation(copy, clip.length);
foreach (Transform t in copy.GetComponentsInChildren(true))
{
sb.AppendLine(" в конце: " + Path(t, copy.transform) + " pos " + t.localPosition.ToString("F3") +
" rot " + t.localEulerAngles.ToString("F1"));
}
}
}
}
finally
{
Object.Destroy(copy);
}
Debug.Log(sb.ToString());
SdtdConsole.Instance.Output("necromodel: выписано в лог");
}
static void Dump(Transform _t, int _depth, StringBuilder _sb)
{
var line = new StringBuilder(new string(' ', _depth * 2));
line.Append(_t.name).Append(" pos ").Append(_t.localPosition.ToString("F3")).Append(" rot ")
.Append(_t.localEulerAngles.ToString("F1")).Append(" scale ").Append(_t.localScale.ToString("F2"))
.Append(" tag ").Append(_t.tag).Append(" layer ").Append(_t.gameObject.layer);
MeshFilter mf = _t.GetComponent();
if (mf != null && mf.sharedMesh != null)
{
line.Append(" mesh ").Append(mf.sharedMesh.name).Append(" bounds c").Append(mf.sharedMesh.bounds.center.ToString("F3"))
.Append(" size").Append(mf.sharedMesh.bounds.size.ToString("F3"));
}
foreach (Collider c in _t.GetComponents())
{
line.Append(" | ").Append(c.GetType().Name).Append(c.isTrigger ? "(trigger)" : "");
if (c is BoxCollider b)
{
line.Append(" c").Append(b.center.ToString("F3")).Append(" s").Append(b.size.ToString("F3"));
}
}
foreach (Component comp in _t.GetComponents())
{
if (!(comp is Transform) && !(comp is MeshFilter) && !(comp is MeshRenderer) && !(comp is Collider))
{
line.Append(" [").Append(comp != null ? comp.GetType().Name : "null").Append("]");
}
}
_sb.AppendLine(line.ToString());
foreach (Transform ch in _t)
{
Dump(ch, _depth + 1, _sb);
}
}
static string Path(Transform _t, Transform _root)
{
string p = _t.name;
while (_t.parent != null && _t != _root)
{
_t = _t.parent;
p = _t.name + "/" + p;
}
return p;
}
}
}