Урны: бюджет дел в секунду с запасом и очередь вместо «3 за кадр» (#78)
Замер necrourn budget: тики всех урн приходят пачкой раз в ~1.4 с в порядке участков от ближних к игроку; лимит «3 за кадр» доставался трём ближним, 11 урн (сборщики, логист, дальние) не получали шага никогда - «стою в 19 м - не работают, подхожу - работают». Теперь 30 дел/с, запас 2 с, пополнение по реальному времени; отказанная урна в очереди и обслуживается первой. После: 578 с, 19 урн по ~128 шагов, отказов 0. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
a745f4eb4a
commit
108ff82914
@@ -8,7 +8,7 @@ namespace NecromancerTome
|
||||
/// <summary>
|
||||
/// Меры нагрузки урн (решение 17.10: «общий бюджет шагов работы духов за кадр (очередь по кругу - нагрузка постоянна при
|
||||
/// любом числе урн); полная анимация только ближайших ~15-20 духов; замер 100 урн»).
|
||||
/// Бюджет: дел (пробный шаг + настоящий) за кадр - не больше StepsPerFrame на все урны сейва; урна, которой не досталось,
|
||||
/// Бюджет: дел (пробный шаг + настоящий) в секунду - не больше StepsPerSecond на все урны сейва (23.10, было за кадр); урна, которой не досталось,
|
||||
/// пробует в следующем кадре. Урна делает дело раз в CinerariumWork.StepSeconds, поэтому очередь сама идёт по кругу.
|
||||
/// Анимация: двигаются (полёт, жесты, покачивание) только AnimateNearest ближайших к игроку духов, остальные замирают дома,
|
||||
/// как уснувшие (CinerariumGenieMotion); работа у всех идёт.
|
||||
@@ -17,11 +17,24 @@ namespace NecromancerTome
|
||||
/// </summary>
|
||||
public static class CinerariumLoad
|
||||
{
|
||||
public static int StepsPerFrame = 3;
|
||||
/// <summary>Дел в секунду на все урны (23.10, было «3 за кадр»). Замер: урна получает тик раз в ~1.4 с, и тики всех урн
|
||||
/// приходят пачкой в одном кадре, в порядке участков от ближних к игроку. Лимит «3 за кадр» доставался трём ближним урнам,
|
||||
/// дальние не получали шага никогда («стою в 19 м - не работают, подхожу - работают»). Теперь бюджет копится между
|
||||
/// тиками (не больше StepsPerSecond за раз), и пачка обслуживает всех, у кого подошёл срок. Консоль: necrourn budget N.</summary>
|
||||
public static float StepsPerSecond = 30f;
|
||||
/// <summary>Запас бюджета, секунд (пачка тиков раз в ~1.4 с должна уместиться целиком).</summary>
|
||||
public const float BurstSeconds = 2f;
|
||||
static float _tokens;
|
||||
static float _lastRefill;
|
||||
/// <summary>Очередь (23.10, пользователь: «нужно иметь очередь урн»): урна, которой отказали, ждёт; пока очередь не пуста,
|
||||
/// бюджет сначала ей - новая урна получит шаг, только если после всех ждущих ещё останется. Иначе ближние урны (их участки
|
||||
/// идут первыми) снова забирали бы всё. Запись старше QueueForget секунд выбрасывается (урну сняли или участок выгружен).</summary>
|
||||
static readonly Dictionary<Vector3i, float> _queue = new Dictionary<Vector3i, float>();
|
||||
const float QueueForget = 10f;
|
||||
static readonly List<Vector3i> _stale = new List<Vector3i>();
|
||||
public static int AnimateNearest = 16;
|
||||
|
||||
static int _frame = -1;
|
||||
static int _used;
|
||||
static bool _tide;
|
||||
|
||||
static void NewFrame()
|
||||
@@ -29,7 +42,23 @@ namespace NecromancerTome
|
||||
if (Time.frameCount != _frame)
|
||||
{
|
||||
_frame = Time.frameCount;
|
||||
_used = 0;
|
||||
// По реальному времени с прошлого пополнения: NewFrame зовут только кадры с тиками урн (раз в ~1.4 с), и
|
||||
// Time.deltaTime (один кадр) давал полшага на пачку (замер 23.10: 279 шагов за 600 с при лимите 30/с).
|
||||
float now = Time.time;
|
||||
_tokens = Mathf.Min(StepsPerSecond * BurstSeconds, _tokens + StepsPerSecond * Mathf.Max(0f, now - _lastRefill));
|
||||
_lastRefill = now;
|
||||
_stale.Clear();
|
||||
foreach (KeyValuePair<Vector3i, float> kv in _queue)
|
||||
{
|
||||
if (now - kv.Value > QueueForget)
|
||||
{
|
||||
_stale.Add(kv.Key);
|
||||
}
|
||||
}
|
||||
foreach (Vector3i p in _stale)
|
||||
{
|
||||
_queue.Remove(p);
|
||||
}
|
||||
_tide = SnakeMode.IsBloodTide();
|
||||
}
|
||||
}
|
||||
@@ -38,12 +67,19 @@ namespace NecromancerTome
|
||||
public static bool TryTakeStep(Vector3i _who)
|
||||
{
|
||||
NewFrame();
|
||||
if (_used >= StepsPerFrame)
|
||||
bool waiting = _queue.ContainsKey(_who);
|
||||
// Ждущая урна - если есть хоть один шаг; новая - только если хватит и всем ждущим.
|
||||
if (_tokens < 1f || (!waiting && _tokens < 1f + _queue.Count))
|
||||
{
|
||||
if (!waiting)
|
||||
{
|
||||
_queue[_who] = Time.time;
|
||||
}
|
||||
Count(_denied, _who);
|
||||
return false;
|
||||
}
|
||||
_used++;
|
||||
_tokens -= 1f;
|
||||
_queue.Remove(_who);
|
||||
Count(_granted, _who);
|
||||
return true;
|
||||
}
|
||||
@@ -65,7 +101,7 @@ namespace NecromancerTome
|
||||
{
|
||||
float sec = Time.time - _countSince;
|
||||
int frames = Time.frameCount - _frames0;
|
||||
string s = "за " + sec.ToString("0") + " с, кадров " + frames + ", лимит " + StepsPerFrame + "/кадр; дано:";
|
||||
string s = "за " + sec.ToString("0") + " с, кадров " + frames + ", лимит " + StepsPerSecond + "/с, в очереди " + _queue.Count + "; дано:";
|
||||
foreach (KeyValuePair<Vector3i, int> kv in _granted)
|
||||
{
|
||||
s += " " + kv.Key + "=" + kv.Value;
|
||||
|
||||
@@ -461,10 +461,10 @@ namespace NecromancerTome
|
||||
{
|
||||
if (_p.Count > 0 && _p[0] == "budget")
|
||||
{
|
||||
// necrourn budget [N] - кому из урн дали шаг и кому отказали с прошлого вызова; N - лимит дел на кадр (по умолчанию 3)
|
||||
// necrourn budget [N] - кому из урн дали шаг и кому отказали с прошлого вызова; N - дел в секунду на все урны (30)
|
||||
if (_p.Count > 1)
|
||||
{
|
||||
CinerariumLoad.StepsPerFrame = int.Parse(_p[1]);
|
||||
CinerariumLoad.StepsPerSecond = float.Parse(_p[1], System.Globalization.CultureInfo.InvariantCulture);
|
||||
}
|
||||
Out("necrourn budget: " + CinerariumLoad.Budget());
|
||||
return;
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user