- Череп-ретранслятор: нить урны проходит через черепа-декор (цепочка), каждый пролёт до 15 м; черепа хранятся у нити (запись урны v5, старые - без черепов). ПКМ ножом по черепу - провести нить, ЛКМ - снять нити через него; убрали череп - нить снимается. - Прилив: ночью кровавой луны духи всех урн исчезают, работа стоит, утром - сама. - Нагрузка: общий бюджет дел духов на кадр (3), анимируются только 16 ближайших духов; лимит урн сборщика смягчён - одна на 200 убийств (было 500), тексты на 13 языках. - Описание логиста (кадило, два вида, маленький дух, мигание), черепа-декора (передаёт нить), подсказки ножа - на 13 языках. - Разработка: necrogod, necrofps [uncap], necrotide, necroshot серией, necroclick по клетке, necrobox fill, necrourn с черепами на пути. Проверено в игре (test8): мигание, нить 28 м через череп и её разрыв, прилив, 63 урны сборщика: 13.0 мс на кадр против 11.8 мс без работы урн. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
171 lines
6.5 KiB
C#
171 lines
6.5 KiB
C#
using System.Collections.Generic;
|
||
using System.IO;
|
||
using UnityEngine;
|
||
using UnityEngine.Scripting;
|
||
|
||
namespace NecromancerTome
|
||
{
|
||
/// <summary>
|
||
/// Почтовый ящик консоли - только для разработки (03.10: ассистент подбирает позу рук сам, без
|
||
/// клавиатуры). Работает, лишь если есть папка %APPDATA%\7DaysToDie\NecroMailbox - у игроков её
|
||
/// нет. Раз в полсекунды: команды из cmd.txt (по строке) выполняются в консоли игры, как набранные
|
||
/// вручную, файл удаляется, ответ - в лог строками «[NecromancerTome] mailbox:».
|
||
/// </summary>
|
||
public static class NecroMailbox
|
||
{
|
||
public static string Dir => Path.Combine(GameIO.GetUserGameDataDir(), "NecroMailbox");
|
||
static string CmdFile => Path.Combine(Dir, "cmd.txt");
|
||
static float _next;
|
||
|
||
public static void Init()
|
||
{
|
||
ModEvents.UnityUpdate.RegisterHandler(OnUnityUpdate);
|
||
}
|
||
|
||
static void OnUnityUpdate(ref ModEvents.SUnityUpdateData _data)
|
||
{
|
||
if (Time.unscaledTime < _next)
|
||
{
|
||
return;
|
||
}
|
||
_next = Time.unscaledTime + 0.5f;
|
||
if (!File.Exists(CmdFile) || SdtdConsole.Instance == null)
|
||
{
|
||
return;
|
||
}
|
||
string[] lines;
|
||
try
|
||
{
|
||
lines = File.ReadAllLines(CmdFile);
|
||
File.Delete(CmdFile);
|
||
}
|
||
catch (IOException)
|
||
{
|
||
return; // файл ещё пишется - в следующий раз
|
||
}
|
||
foreach (string raw in lines)
|
||
{
|
||
string line = raw.Trim();
|
||
if (line.Length == 0)
|
||
{
|
||
continue;
|
||
}
|
||
Debug.Log("[NecromancerTome] mailbox: > " + line);
|
||
try
|
||
{
|
||
List<string> res = SdtdConsole.Instance.ExecuteSync(line, null);
|
||
if (res != null)
|
||
{
|
||
foreach (string r in res)
|
||
{
|
||
Debug.Log("[NecromancerTome] mailbox: " + r);
|
||
}
|
||
}
|
||
}
|
||
catch (System.Exception ex)
|
||
{
|
||
Debug.LogWarning("[NecromancerTome] mailbox: ошибка - " + ex);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>necroshot [имя] - снимок экрана игры в %APPDATA%\7DaysToDie\NecroMailbox\shots\имя.png
|
||
/// (как F9, только в известное место). Файл появляется в конце кадра.</summary>
|
||
[Preserve]
|
||
public class ConsoleCmdNecroShot : ConsoleCmdAbstract
|
||
{
|
||
public override string[] getCommands() => new[] { "necroshot" };
|
||
public override string getDescription() => "NecromancerTome: снимок экрана в NecroMailbox/shots/<имя>.png";
|
||
|
||
public override void Execute(List<string> _params, CommandSenderInfo _senderInfo)
|
||
{
|
||
string dir = Path.Combine(NecroMailbox.Dir, "shots");
|
||
Directory.CreateDirectory(dir);
|
||
string name = _params.Count > 0 ? _params[0] : System.DateTime.Now.ToString("HHmmss");
|
||
// necroshot имя N интервал - серия из N кадров (имя1..имяN) через интервал секунд (18.10: мигание, полёт духа).
|
||
if (_params.Count >= 3 && int.TryParse(_params[1], out int n) &&
|
||
float.TryParse(_params[2], System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out float dt))
|
||
{
|
||
ThreadManager.StartCoroutine(Burst(dir, name, n, dt));
|
||
SdtdConsole.Instance.Output("серия: " + n + " кадров через " + dt + " с");
|
||
return;
|
||
}
|
||
string path = Path.Combine(dir, name + ".png");
|
||
ScreenCapture.CaptureScreenshot(path);
|
||
SdtdConsole.Instance.Output("снимок: " + path);
|
||
}
|
||
|
||
static System.Collections.IEnumerator Burst(string _dir, string _name, int _n, float _dt)
|
||
{
|
||
for (int i = 1; i <= _n; i++)
|
||
{
|
||
ScreenCapture.CaptureScreenshot(Path.Combine(_dir, _name + i + ".png"));
|
||
yield return new WaitForSecondsRealtime(_dt);
|
||
}
|
||
Debug.Log("[NecromancerTome] mailbox: серия " + _name + " готова");
|
||
}
|
||
}
|
||
|
||
/// <summary>necrospawn - нажать «Появиться» в окне появления (18.10: ассистент сам запускает игру с сейвом
|
||
/// -LoadSaveGame=true и входит в мир без мыши). То же, что кнопка: XUiC_SpawnSelectionWindow.SpawnButtonPressed.</summary>
|
||
[Preserve]
|
||
public class ConsoleCmdNecroSpawn : ConsoleCmdAbstract
|
||
{
|
||
public override string[] getCommands() => new[] { "necrospawn" };
|
||
public override string getDescription() => "NecromancerTome: нажать «Появиться» (разработка, почтовый ящик)";
|
||
public override bool AllowedInMainMenu => false;
|
||
|
||
public override void Execute(List<string> _params, CommandSenderInfo _senderInfo)
|
||
{
|
||
foreach (LocalPlayerUI ui in LocalPlayerUI.PlayerUIs)
|
||
{
|
||
XUiC_SpawnSelectionWindow w = ui?.xui?.GetWindowByType<XUiC_SpawnSelectionWindow>();
|
||
if (w != null && w.IsOpen)
|
||
{
|
||
w.SpawnButtonPressed(SpawnMethod.Invalid);
|
||
SdtdConsole.Instance.Output("necrospawn: нажато «Появиться»");
|
||
return;
|
||
}
|
||
}
|
||
SdtdConsole.Instance.Output("necrospawn: окно появления не открыто");
|
||
}
|
||
}
|
||
|
||
/// <summary>necroexit [quit] - выйти из мира с сохранением, как «Выход» в меню паузы (GameManager.Disconnect); с quit -
|
||
/// затем закрыть игру. Нужно перед сборкой бандлов и заменой DLL (игра держит файлы).</summary>
|
||
[Preserve]
|
||
public class ConsoleCmdNecroExit : ConsoleCmdAbstract
|
||
{
|
||
public override string[] getCommands() => new[] { "necroexit" };
|
||
public override string getDescription() => "NecromancerTome: выйти из мира с сохранением [quit - и закрыть игру] (разработка)";
|
||
public override bool AllowedInMainMenu => true;
|
||
|
||
public override void Execute(List<string> _params, CommandSenderInfo _senderInfo)
|
||
{
|
||
bool quit = _params.Count > 0 && _params[0] == "quit";
|
||
SdtdConsole.Instance.Output("necroexit: выход" + (quit ? " и закрытие игры" : " в меню"));
|
||
ThreadManager.StartCoroutine(ExitCo(quit));
|
||
}
|
||
|
||
static System.Collections.IEnumerator ExitCo(bool _quit)
|
||
{
|
||
if (GameManager.Instance.World != null)
|
||
{
|
||
GameManager.Instance.Disconnect();
|
||
while (GameManager.Instance.World != null)
|
||
{
|
||
yield return null;
|
||
}
|
||
Debug.Log("[NecromancerTome] necroexit: мир сохранён и закрыт");
|
||
}
|
||
if (_quit)
|
||
{
|
||
yield return new WaitForSecondsRealtime(2f);
|
||
Debug.Log("[NecromancerTome] necroexit: закрываю игру");
|
||
Application.Quit();
|
||
}
|
||
}
|
||
}
|
||
}
|