6
2026-01-24 12:49:55 +03:00

145 lines
5.4 KiB
C#

using System.Numerics;
using Content.Server._White.Spawners.Components;
using Content.Server.Atmos.Components;
using Content.Shared.Maps;
using Robust.Server.GameObjects;
using Robust.Shared.Map;
using Robust.Shared.Map.Components;
using Robust.Shared.Log;
using Robust.Shared.Random;
using Robust.Shared.Spawners;
using Robust.Shared.Timing;
namespace Content.Server._White.Spawners.Systems;
public sealed class AreaSpawnerSystem : EntitySystem
{
private readonly ISawmill _sawmill = Logger.GetSawmill("TEST.areaspawner");
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly IMapManager _mapManager = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly MapSystem _map = default!;
[Dependency] private readonly TransformSystem _transform = default!;
private readonly List<Vector2> _offsets = new List<Vector2>
{
new Vector2(0, 1),
new Vector2(-1, 0), new Vector2(1, 0),
new Vector2(0, -1)
};
public override void Initialize()
{
_sawmill.Debug("AreaSpawnerSystem initialized");
SubscribeLocalEvent<AreaSpawnerComponent, ComponentShutdown>(OnShutdown);
}
private void OnShutdown(EntityUid uid, AreaSpawnerComponent component, ComponentShutdown args)
{
_sawmill.Debug($"OnShutdown: uid={uid}, spawnedCount={component.Spawneds.Count}");
foreach (var spawned in component.Spawneds)
{
var despawnComponent = new TimedDespawnComponent
{
Lifetime = _random.NextFloat(component.MinTime, component.MaxTime)
};
AddComp(spawned, despawnComponent);
_sawmill.Debug($"OnShutdown: added TimedDespawnComponent to spawned={spawned}, lifetime={despawnComponent.Lifetime}");
}
}
public override void Update(float frameTime)
{
base.Update(frameTime);
var time = _timing.CurTime;
var query = EntityQueryEnumerator<AreaSpawnerComponent>();
while (query.MoveNext(out var uid, out var areaSpawner))
{
if (time < areaSpawner.SpawnAt)
continue;
_sawmill.Debug($"Update: spawning for uid={uid}, prototype={areaSpawner.SpawnPrototype}");
areaSpawner.SpawnAt = time + areaSpawner.SpawnDelay;
var validTiles = GetValidTilesInRadius(uid, areaSpawner);
_sawmill.Debug($"Update: found {validTiles.Count} valid tiles");
foreach (var tile in validTiles)
{
var spawnedUid = Spawn(areaSpawner.SpawnPrototype, Transform(uid).Coordinates.Offset(tile));
areaSpawner.Spawneds.Add(spawnedUid);
_sawmill.Debug($"Update: spawned entity={spawnedUid} at tile={tile}");
}
}
}
public List<Vector2> GetValidTilesInRadius(EntityUid uid, AreaSpawnerComponent component)
{
_sawmill.Debug($"GetValidTilesInRadius: uid={uid}, radius={component.Radius}");
var validTiles = new List<Vector2>();
for (var y = -component.Radius; y <= component.Radius; y++)
{
for (var x = -component.Radius; x <= component.Radius; x++)
{
var tile = new Vector2(x, y);
if (IsTileValidForSpawn(uid, component, tile))
validTiles.Add(tile);
}
}
_sawmill.Debug($"GetValidTilesInRadius: found {validTiles.Count} valid tiles");
return validTiles;
}
public bool IsTileValidForSpawn(EntityUid uid, AreaSpawnerComponent component, Vector2 offset)
{
_sawmill.Debug($"IsTileValidForSpawn: uid={uid}, offset={offset}");
var xform = Transform(uid);
if (_transform.GetGrid((uid, xform)) is not { } gridUid
|| !TryComp<MapGridComponent>(gridUid, out var mapGridComponent))
{
_sawmill.Debug($"IsTileValidForSpawn: no grid found, returning false");
return false;
}
var coords = xform.Coordinates.Offset(offset);
var tile = coords.GetTileRef(EntityManager, _mapManager);
if (!tile.HasValue || tile.Value.Tile.IsEmpty)
{
_sawmill.Debug($"IsTileValidForSpawn: tile empty, returning false");
return false;
}
foreach (var entity in _map.GetAnchoredEntities((gridUid, mapGridComponent), coords))
{
if (TryComp<AirtightComponent>(entity, out var airtight) && airtight.AirBlocked
|| Prototype(entity) != null && Prototype(entity)! == component.SpawnPrototype
|| Prototype(entity) == Prototype(uid))
{
_sawmill.Debug($"IsTileValidForSpawn: entity blocking tile, returning false");
return false;
}
}
foreach (var checkOffset in _offsets)
{
var checkCoords = coords.Offset(checkOffset);
foreach (var entity in _map.GetAnchoredEntities((gridUid, mapGridComponent), checkCoords))
{
if (component.Spawneds.Contains(entity) || entity == uid)
{
_sawmill.Debug($"IsTileValidForSpawn: valid tile found, returning true");
return true;
}
}
}
_sawmill.Debug($"IsTileValidForSpawn: no valid neighbor found, returning false");
return false;
}
}