using Content.Server.GameTicking;
using Content.Server.GameTicking.Events;
using Content.Shared._Horizon.CCVar;
using Content.Shared.GameTicking;
using Content.Shared.Tag;
using Robust.Shared.Configuration;
using Robust.Shared.Containers;
using Robust.Shared.Timing;
namespace Content.Server._Horizon.TrashCleanup;
///
/// Система автоматического удаления мусорных сущностей с периодической очисткой.
/// Активируется только после задержки от начала раунда.
///
public sealed class TrashCleanupSystem : EntitySystem
{
[Dependency] private readonly IConfigurationManager _cfg = default!;
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly TagSystem _tag = default!;
[Dependency] private readonly GameTicker _gameTicker = default!;
[Dependency] private readonly SharedContainerSystem _container = default!;
private bool _enabled;
private float _cleanupInterval;
private float _startDelay;
///
/// Время начала текущего раунда.
///
private TimeSpan _roundStartTime;
///
/// Активна ли система (после истечения задержки).
///
private bool _isActive;
///
/// Время последней очистки.
///
private TimeSpan _lastCleanupTime;
///
/// Теги, определяющие сущности для очистки.
///
private static readonly string[] CleanupTags = { "Cartridge" };
///
/// Префикс ID прототипа для мусорных сущностей.
///
private const string TrashPrefix = "Trash";
public override void Initialize()
{
base.Initialize();
_cfg.OnValueChanged(HorizonCCVars.TrashCleanupEnabled, OnEnabledChanged, true);
_cfg.OnValueChanged(HorizonCCVars.TrashCleanupInterval, OnIntervalChanged, true);
_cfg.OnValueChanged(HorizonCCVars.TrashCleanupStartDelay, OnStartDelayChanged, true);
// Подписываемся на события раунда
SubscribeLocalEvent(OnRoundStarting);
SubscribeLocalEvent(OnRoundRestart);
}
private void OnEnabledChanged(bool value)
{
_enabled = value;
if (_enabled)
{
Log.Info("TrashCleanup: Система включена.");
// Если раунд уже идёт и у нас нет времени старта, устанавливаем его сейчас
if (_roundStartTime == TimeSpan.Zero && _gameTicker.RunLevel == GameRunLevel.InRound)
{
_roundStartTime = _timing.CurTime;
Log.Info($"TrashCleanup: Раунд уже идёт. Система активируется через {_startDelay} секунд.");
}
}
else
{
Log.Info("TrashCleanup: Система отключена.");
}
}
private void OnIntervalChanged(float value)
{
_cleanupInterval = value;
Log.Info($"TrashCleanup: Интервал очистки установлен на {value} секунд.");
}
private void OnStartDelayChanged(float value)
{
_startDelay = value;
Log.Info($"TrashCleanup: Задержка старта установлена на {value} секунд.");
}
private void OnRoundStarting(RoundStartingEvent ev)
{
_roundStartTime = _timing.CurTime;
_isActive = false;
_lastCleanupTime = TimeSpan.Zero;
if (_enabled)
Log.Info($"TrashCleanup: Раунд {ev.Id} начался. Система активируется через {_startDelay} секунд.");
}
private void OnRoundRestart(RoundRestartCleanupEvent ev)
{
_isActive = false;
_roundStartTime = TimeSpan.Zero;
_lastCleanupTime = TimeSpan.Zero;
}
public override void Update(float frameTime)
{
base.Update(frameTime);
if (!_enabled)
return;
// Проверяем, нужно ли активировать систему
if (!_isActive && _roundStartTime != TimeSpan.Zero)
{
var timeSinceRoundStart = _timing.CurTime - _roundStartTime;
if (timeSinceRoundStart.TotalSeconds >= _startDelay)
{
_isActive = true;
_lastCleanupTime = _timing.CurTime;
Log.Info($"TrashCleanup: Система активирована после {_startDelay} секунд задержки.");
}
else
{
return; // Ещё ждём задержку
}
}
if (!_isActive)
return;
// Проверяем, нужно ли выполнить очистку
var curTime = _timing.CurTime;
var timeSinceLastCleanup = curTime - _lastCleanupTime;
if (timeSinceLastCleanup.TotalSeconds < _cleanupInterval)
return;
// Выполняем очистку
_lastCleanupTime = curTime;
PerformCleanup();
}
private void PerformCleanup()
{
var deletedCount = 0;
var query = EntityQueryEnumerator();
var entitiesToDelete = new List();
// Собираем все сущности с нужными тегами, которые не в контейнерах
while (query.MoveNext(out var uid, out var tagComponent))
{
// Пропускаем сущности в контейнерах (в руках, рюкзаках и т.д.)
if (_container.IsEntityInContainer(uid))
continue;
// Проверяем, есть ли у сущности какой-либо из тегов очистки
var hasCleanupTag = false;
foreach (var tag in CleanupTags)
{
if (_tag.HasTag(uid, tag))
{
hasCleanupTag = true;
break;
}
}
// Также проверяем префикс прототипа для мусора
if (!hasCleanupTag)
{
var meta = MetaData(uid);
var prototypeId = meta.EntityPrototype?.ID;
if (prototypeId != null && prototypeId.StartsWith(TrashPrefix, StringComparison.OrdinalIgnoreCase))
{
hasCleanupTag = true;
}
}
if (hasCleanupTag)
{
entitiesToDelete.Add(uid);
}
}
// Удаляем собранные сущности
foreach (var uid in entitiesToDelete)
{
var name = MetaData(uid).EntityName;
Log.Debug($"TrashCleanup: Удаление '{name}' ({uid}).");
QueueDel(uid);
deletedCount++;
}
if (deletedCount > 0)
Log.Info($"TrashCleanup: Удалено {deletedCount} мусорных сущностей.");
}
}