From 054897eb7818a8cbe03893898d71338a92f55c6f Mon Sep 17 00:00:00 2001 From: AlexCube Date: Fri, 23 Oct 2026 16:42:44 +0300 Subject: [PATCH] =?UTF-8?q?necrourn=20budget=20[N]:=20=D1=83=D1=87=D1=91?= =?UTF-8?q?=D1=82=20=D0=B8=20=D0=BB=D0=B8=D0=BC=D0=B8=D1=82=20=D0=BE=D0=B1?= =?UTF-8?q?=D1=89=D0=B5=D0=B3=D0=BE=20=D0=B1=D1=8E=D0=B4=D0=B6=D0=B5=D1=82?= =?UTF-8?q?=D0=B0=20=D1=88=D0=B0=D0=B3=D0=BE=D0=B2=20=D1=83=D1=80=D0=BD;?= =?UTF-8?q?=20necrourn=20info=20-=20=D1=81=D0=BE=D1=81=D1=82=D0=BE=D1=8F?= =?UTF-8?q?=D0=BD=D0=B8=D0=B5=20=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D1=8B=20?= =?UTF-8?q?=D1=83=D1=80=D0=BD=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 --- HarmonySrc/Cinerarium.cs | 11 +++++++++- HarmonySrc/CinerariumLoad.cs | 40 ++++++++++++++++++++++++++++++++-- HarmonySrc/CinerariumZone.cs | 2 +- HarmonySrc/NecroDevCommands.cs | 12 +++++++++- 4 files changed, 60 insertions(+), 5 deletions(-) diff --git a/HarmonySrc/Cinerarium.cs b/HarmonySrc/Cinerarium.cs index d2de829..3da4ed5 100644 --- a/HarmonySrc/Cinerarium.cs +++ b/HarmonySrc/Cinerarium.cs @@ -741,6 +741,15 @@ namespace NecromancerTome bool _pending; float _actAt; + /// Состояние работы для necrourn info (23.10: «стою в 19 м - не работают», проба находит урожай, дела нет). + public string WorkState() + { + float now = Time.time; + return "дело ждёт " + _pending + (_pending ? " (через " + (_actAt - now).ToString("0.0") + " с)" : "") + + ", следующий шаг через " + (_nextWork - now).ToString("0.0") + " с, прилив " + CinerariumLoad.Tide + + ", дух " + (_genie != null); + } + /// Работа духа (CinerariumWork): раз в StepSeconds одно дело, только с черепом и только на сервере. /// Сначала пробный шаг (ничего не меняет) - куда лететь; само дело - когда дух долетел и машет руками. Если за это /// время что-то поменялось, настоящий шаг сделает то, что нужно на тот момент. @@ -773,7 +782,7 @@ namespace NecromancerTome _nextWork = Time.time + CinerariumWork.StepSeconds; return; } - if (Time.time < _nextWork || !CinerariumLoad.TryTakeStep()) + if (Time.time < _nextWork || !CinerariumLoad.TryTakeStep(ToWorldPos())) { return; // не время или бюджет кадра на дела духов выбран - в следующем кадре } diff --git a/HarmonySrc/CinerariumLoad.cs b/HarmonySrc/CinerariumLoad.cs index b57cf8e..acdccc4 100644 --- a/HarmonySrc/CinerariumLoad.cs +++ b/HarmonySrc/CinerariumLoad.cs @@ -34,18 +34,54 @@ namespace NecromancerTome } } - /// Взять одно дело из бюджета кадра. - public static bool TryTakeStep() + /// Взять одно дело из бюджета кадра. _who - урна (учёт для necrourn budget). + public static bool TryTakeStep(Vector3i _who) { NewFrame(); if (_used >= StepsPerFrame) { + Count(_denied, _who); return false; } _used++; + Count(_granted, _who); return true; } + // Учёт бюджета (23.10: сборщики 600 с не получили ни одного шага, логист рядом - получал): кому дали, кому отказали. + static readonly Dictionary _granted = new Dictionary(); + static readonly Dictionary _denied = new Dictionary(); + static float _countSince; + static int _frames0; + + static void Count(Dictionary _d, Vector3i _who) + { + _d.TryGetValue(_who, out int n); + _d[_who] = n + 1; + } + + /// Сводка с прошлого вызова и сброс (команда necrourn budget). + public static string Budget() + { + float sec = Time.time - _countSince; + int frames = Time.frameCount - _frames0; + string s = "за " + sec.ToString("0") + " с, кадров " + frames + ", лимит " + StepsPerFrame + "/кадр; дано:"; + foreach (KeyValuePair kv in _granted) + { + s += " " + kv.Key + "=" + kv.Value; + } + s += "; отказано:"; + foreach (KeyValuePair kv in _denied) + { + s += " " + kv.Key + "=" + kv.Value; + } + _granted.Clear(); + _denied.Clear(); + _countSince = Time.time; + _frames0 = Time.frameCount; + return s; + } + /// Идёт ли кровавый прилив (раз за кадр). public static bool Tide { diff --git a/HarmonySrc/CinerariumZone.cs b/HarmonySrc/CinerariumZone.cs index 7bfc71b..e295f44 100644 --- a/HarmonySrc/CinerariumZone.cs +++ b/HarmonySrc/CinerariumZone.cs @@ -246,7 +246,7 @@ namespace NecromancerTome { ScanColumns(_world); } - if (Time.time < _zoneNext || !CinerariumLoad.TryTakeStep()) + if (Time.time < _zoneNext || !CinerariumLoad.TryTakeStep(ToWorldPos())) { return; } diff --git a/HarmonySrc/NecroDevCommands.cs b/HarmonySrc/NecroDevCommands.cs index 299dedf..12464ca 100644 --- a/HarmonySrc/NecroDevCommands.cs +++ b/HarmonySrc/NecroDevCommands.cs @@ -459,6 +459,16 @@ namespace NecromancerTome static void Urn(World _w, List _p) { + if (_p.Count > 0 && _p[0] == "budget") + { + // necrourn budget [N] - кому из урн дали шаг и кому отказали с прошлого вызова; N - лимит дел на кадр (по умолчанию 3) + if (_p.Count > 1) + { + CinerariumLoad.StepsPerFrame = int.Parse(_p[1]); + } + Out("necrourn budget: " + CinerariumLoad.Budget()); + return; + } Vector3i pos = P(_p, 0); TEFeatureCinerarium u = CinerariumThreads.UrnAt(_w, pos); if (u == null) @@ -497,7 +507,7 @@ namespace NecromancerTome } Out("necrourn: " + pos + " " + _w.GetBlock(pos).Block?.GetBlockName() + ", череп " + u.HasSkull + ", застрял " + u.Stuck + ", мигание " + blink + ", откуда " + u.ThreadFrom.Count + ", куда " + (u.HasThreadTo ? u.ThreadTo.ToString() : "нет") + ", от урны " + u.ThreadOut.Count + - ", зона " + (u.IsBigZone ? u.ZoneSideNow + (u.ZoneRunning ? " идёт" : " ждёт") + (u.ZoneLacking ? " нехватка" : "") + " курсор " + u.ZoneCursor : "-") + ", образец " + (u.Sample == null || u.Sample.IsEmpty() ? "нет" : u.Sample.itemValue.ItemClass?.GetItemName() + "x" + u.Sample.count)); + ", зона " + (u.IsBigZone ? u.ZoneSideNow + (u.ZoneRunning ? " идёт" : " ждёт") + (u.ZoneLacking ? " нехватка" : "") + " курсор " + u.ZoneCursor : "-") + ", образец " + (u.Sample == null || u.Sample.IsEmpty() ? "нет" : u.Sample.itemValue.ItemClass?.GetItemName() + "x" + u.Sample.count) + "; " + u.WorkState()); } }