Kills TurfHelpers (#37939)

* Create TurfSystem equivalent for and obsolete TurfHelpers.GetTileRef

* Fix EntitySystem uses of TurfHelpers.GetTileRef

* Fix EntitySystem uses of TurfHelpers.TryGetTileRef

* Fix construction condition uses of TurfHelpers.GetTileRef

* Fix last use of TurfHelpers.IsBlockedTurf

* Create TurfSystem equivalent to and obsolete TurfHelpers.GetContentTileDefinition

* Fix uses of TurfHelpers.GetContentTileDefinition(TileRef)

* Fix uses of TurfHelpers.GetContentTileDefinition(Tile)

* Create TurfSystem equivalent to and obsolete TurfHelpers.IsSpace

* Fix EntitySystem uses of TurfHelpers.IsSpace(Tile)

* Fix EntitySystem uses of TurfHelpers.IsSpace(TileRef)

* Fix remaining uses of TurfHelpers.IsSpace

* Fix uses of TurfHelpers.GetEntitiesInTile

* Delete TurfHelpers.cs

* Add GetEntitiesInTile lookup methods

* Convert some GetEntitiesInTile methods to LookupSystem extension methods

* Use new GetEntitiesInTile methods

* Recycle spiderweb hashset

* Recycle floor tile hashset
This commit is contained in:
TemporalOroboros
2025-06-21 08:23:19 -07:00
committed by GitHub
parent 334dc61d4d
commit d4876be6f0
37 changed files with 251 additions and 229 deletions

View File

@@ -793,7 +793,7 @@ public sealed class MappingState : GameplayStateBase
if (_mapMan.TryFindGridAt(mapPos, out var gridUid, out var grid) &&
_entityManager.System<SharedMapSystem>().TryGetTileRef(gridUid, grid, coords, out var tileRef) &&
_allPrototypesDict.TryGetValue(tileRef.GetContentTileDefinition(), out button))
_allPrototypesDict.TryGetValue(_entityManager.System<TurfSystem>().GetContentTileDefinition(tileRef), out button))
{
OnSelected(button);
return true;

View File

@@ -82,7 +82,7 @@ namespace Content.Server.Abilities.Mime
// Get the tile in front of the mime
var offsetValue = xform.LocalRotation.ToWorldVec();
var coords = xform.Coordinates.Offset(offsetValue).SnapToGrid(EntityManager, _mapMan);
var tile = coords.GetTileRef(EntityManager, _mapMan);
var tile = _turf.GetTileRef(coords);
if (tile == null)
return;

View File

@@ -10,7 +10,6 @@ namespace Content.Server.Administration.Commands;
public sealed class VariantizeCommand : IConsoleCommand
{
[Dependency] private readonly IEntityManager _entManager = default!;
[Dependency] private readonly ITileDefinitionManager _tileDefManager = default!;
public string Command => "variantize";
@@ -40,10 +39,11 @@ public sealed class VariantizeCommand : IConsoleCommand
var mapsSystem = _entManager.System<SharedMapSystem>();
var tileSystem = _entManager.System<TileSystem>();
var turfSystem = _entManager.System<TurfSystem>();
foreach (var tile in mapsSystem.GetAllTiles(euid.Value, gridComp))
{
var def = tile.GetContentTileDefinition(_tileDefManager);
var def = turfSystem.GetContentTileDefinition(tile);
var newTile = new Tile(tile.Tile.TypeId, tile.Tile.Flags, tileSystem.PickVariant(def));
mapsSystem.SetTile(euid.Value, gridComp, tile.GridIndices, newTile);
}

View File

@@ -41,33 +41,33 @@ public sealed partial class CreateEntityTileReaction : ITileReaction
IEntityManager entityManager,
List<ReagentData>? data)
{
if (reactVolume >= Usage)
if (reactVolume < Usage)
return FixedPoint2.Zero;
if (Whitelist != null)
{
if (Whitelist != null)
var lookup = entityManager.System<EntityLookupSystem>();
int acc = 0;
foreach (var ent in lookup.GetEntitiesInTile(tile, LookupFlags.Static))
{
int acc = 0;
foreach (var ent in tile.GetEntitiesInTile())
{
var whitelistSystem = entityManager.System<EntityWhitelistSystem>();
if (whitelistSystem.IsWhitelistPass(Whitelist, ent))
acc += 1;
var whitelistSystem = entityManager.System<EntityWhitelistSystem>();
if (whitelistSystem.IsWhitelistPass(Whitelist, ent))
acc += 1;
if (acc >= MaxOnTile)
return FixedPoint2.Zero;
}
if (acc >= MaxOnTile)
return FixedPoint2.Zero;
}
var random = IoCManager.Resolve<IRobustRandom>();
var xoffs = random.NextFloat(-RandomOffsetMax, RandomOffsetMax);
var yoffs = random.NextFloat(-RandomOffsetMax, RandomOffsetMax);
var center = entityManager.System<TurfSystem>().GetTileCenter(tile);
var pos = center.Offset(new Vector2(xoffs, yoffs));
entityManager.SpawnEntity(Entity, pos);
return Usage;
}
return FixedPoint2.Zero;
var random = IoCManager.Resolve<IRobustRandom>();
var xoffs = random.NextFloat(-RandomOffsetMax, RandomOffsetMax);
var yoffs = random.NextFloat(-RandomOffsetMax, RandomOffsetMax);
var center = entityManager.System<TurfSystem>().GetTileCenter(tile);
var pos = center.Offset(new Vector2(xoffs, yoffs));
entityManager.SpawnEntity(Entity, pos);
return Usage;
}
}

View File

@@ -58,9 +58,7 @@ namespace Content.Server.Construction.Conditions
if (!entityManager.System<SharedMapSystem>().TryGetTileRef(transform.GridUid.Value, grid, indices, out var tile))
return !HasEntity;
var entities = tile.GetEntitiesInTile(LookupFlags.Approximate | LookupFlags.Static, lookup);
foreach (var ent in entities)
foreach (var ent in lookup.GetEntitiesInTile(tile, flags: LookupFlags.Approximate | LookupFlags.Static))
{
if (entityManager.HasComponent(ent, type))
return HasEntity;

View File

@@ -54,8 +54,9 @@ namespace Content.Server.Decals.Commands
}
var mapSystem = _entManager.System<MapSystem>();
var turfSystem = _entManager.System<TurfSystem>();
var coordinates = new EntityCoordinates(gridIdRaw.Value, new Vector2(x, y));
if (mapSystem.GetTileRef(gridIdRaw.Value, grid, coordinates).IsSpace())
if (turfSystem.IsSpace(mapSystem.GetTileRef(gridIdRaw.Value, grid, coordinates)))
{
shell.WriteError($"Cannot create decal on space tile at {coordinates}.");
return;

View File

@@ -29,7 +29,6 @@ namespace Content.Server.Decals
{
[Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly IAdminManager _adminManager = default!;
[Dependency] private readonly ITileDefinitionManager _tileDefMan = default!;
[Dependency] private readonly IParallelManager _parMan = default!;
[Dependency] private readonly ChunkingSystem _chunking = default!;
[Dependency] private readonly IConfigurationManager _conf = default!;
@@ -37,6 +36,7 @@ namespace Content.Server.Decals
[Dependency] private readonly IAdminLogManager _adminLogger = default!;
[Dependency] private readonly SharedMapSystem _mapSystem = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!;
[Dependency] private readonly TurfSystem _turf = default!;
private readonly Dictionary<NetEntity, HashSet<Vector2i>> _dirtyChunks = new();
private readonly Dictionary<ICommonSession, Dictionary<NetEntity, HashSet<Vector2i>>> _previousSentChunks = new();
@@ -167,7 +167,7 @@ namespace Content.Server.Decals
foreach (var change in args.Changes)
{
if (!change.NewTile.IsSpace(_tileDefMan))
if (!_turf.IsSpace(change.NewTile))
continue;
var indices = GetChunkIndices(change.GridIndices);
@@ -308,7 +308,7 @@ namespace Content.Server.Decals
if (!TryComp(gridId, out MapGridComponent? grid))
return false;
if (_mapSystem.GetTileRef(gridId.Value, grid, coordinates).IsSpace(_tileDefMan))
if (_turf.IsSpace(_mapSystem.GetTileRef(gridId.Value, grid, coordinates)))
return false;
if (!TryComp(gridId, out DecalGridComponent? comp))

View File

@@ -21,7 +21,6 @@ namespace Content.Server.Dragon;
public sealed partial class DragonSystem : EntitySystem
{
[Dependency] private readonly CarpRiftsConditionSystem _carpRifts = default!;
[Dependency] private readonly ITileDefinitionManager _tileDef = default!;
[Dependency] private readonly MovementSpeedModifierSystem _movement = default!;
[Dependency] private readonly NpcFactionSystem _faction = default!;
[Dependency] private readonly PopupSystem _popup = default!;
@@ -30,6 +29,7 @@ public sealed partial class DragonSystem : EntitySystem
[Dependency] private readonly SharedTransformSystem _transform = default!;
[Dependency] private readonly SharedMapSystem _map = default!;
[Dependency] private readonly MobStateSystem _mobState = default!;
[Dependency] private readonly TurfSystem _turf = default!;
private EntityQuery<CarpRiftsConditionComponent> _objQuery;
@@ -159,7 +159,7 @@ public sealed partial class DragonSystem : EntitySystem
// cant put a rift on solars
foreach (var tile in _map.GetTilesIntersecting(xform.GridUid.Value, grid, new Circle(_transform.GetWorldPosition(xform), RiftTileRadius), false))
{
if (!tile.IsSpace(_tileDef))
if (!_turf.IsSpace(tile))
continue;
_popup.PopupEntity(Loc.GetString("carp-rift-space-proximity", ("proximity", RiftTileRadius)), uid, uid);

View File

@@ -57,6 +57,7 @@ public sealed class ElectrocutionSystem : SharedElectrocutionSystem
[Dependency] private readonly SharedStutteringSystem _stuttering = default!;
[Dependency] private readonly TagSystem _tag = default!;
[Dependency] private readonly MetaDataSystem _metaData = default!;
[Dependency] private readonly TurfSystem _turf = default!;
[ValidatePrototypeId<StatusEffectPrototype>]
private const string StatusEffectKey = "Electrocution";
@@ -137,7 +138,7 @@ public sealed class ElectrocutionSystem : SharedElectrocutionSystem
return false;
if (electrified.NoWindowInTile)
{
var tileRef = transform.Coordinates.GetTileRef(EntityManager, _mapManager);
var tileRef = _turf.GetTileRef(transform.Coordinates);
if (tileRef != null)
{

View File

@@ -74,6 +74,7 @@ public sealed class EntityEffectSystem : EntitySystem
[Dependency] private readonly TemperatureSystem _temperature = default!;
[Dependency] private readonly SharedTransformSystem _xform = default!;
[Dependency] private readonly VomitSystem _vomit = default!;
[Dependency] private readonly TurfSystem _turf = default!;
public override void Initialize()
{
@@ -529,7 +530,7 @@ public sealed class EntityEffectSystem : EntitySystem
return;
}
if (_spreader.RequiresFloorToSpread(args.Effect.PrototypeId) && tileRef.Tile.IsSpace())
if (_spreader.RequiresFloorToSpread(args.Effect.PrototypeId) && _turf.IsSpace(tileRef))
return;
var coords = _map.MapToGrid(gridUid, mapCoords);

View File

@@ -20,6 +20,7 @@ public sealed class SmokeOnTriggerSystem : SharedSmokeOnTriggerSystem
[Dependency] private readonly SmokeSystem _smoke = default!;
[Dependency] private readonly TransformSystem _transform = default!;
[Dependency] private readonly SpreaderSystem _spreader = default!;
[Dependency] private readonly TurfSystem _turf = default!;
public override void Initialize()
{
@@ -39,7 +40,7 @@ public sealed class SmokeOnTriggerSystem : SharedSmokeOnTriggerSystem
return;
}
if (_spreader.RequiresFloorToSpread(comp.SmokePrototype.ToString()) && tileRef.Tile.IsSpace())
if (_spreader.RequiresFloorToSpread(comp.SmokePrototype.ToString()) && _turf.IsSpace(tileRef))
return;
var coords = _map.MapToGrid(gridUid, mapCoords);

View File

@@ -47,7 +47,6 @@ public sealed partial class PuddleSystem : SharedPuddleSystem
[Dependency] private readonly SharedMapSystem _map = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly ITileDefinitionManager _tileDefMan = default!;
[Dependency] private readonly AudioSystem _audio = default!;
[Dependency] private readonly EntityLookupSystem _lookup = default!;
[Dependency] private readonly ReactiveSystem _reactive = default!;
@@ -59,6 +58,7 @@ public sealed partial class PuddleSystem : SharedPuddleSystem
[Dependency] private readonly SpeedModifierContactsSystem _speedModContacts = default!;
[Dependency] private readonly TileFrictionController _tile = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!;
[Dependency] private readonly TurfSystem _turf = default!;
[ValidatePrototypeId<ReagentPrototype>]
private const string Blood = "Blood";
@@ -686,7 +686,7 @@ public sealed partial class PuddleSystem : SharedPuddleSystem
}
// If space return early, let that spill go out into the void
if (tileRef.Tile.IsEmpty || tileRef.IsSpace(_tileDefMan))
if (tileRef.Tile.IsEmpty || _turf.IsSpace(tileRef))
{
puddleUid = EntityUid.Invalid;
return false;

View File

@@ -32,7 +32,6 @@ public sealed class NukeSystem : EntitySystem
[Dependency] private readonly ChatSystem _chatSystem = default!;
[Dependency] private readonly ExplosionSystem _explosions = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly ITileDefinitionManager _tileDefManager = default!;
[Dependency] private readonly ItemSlotsSystem _itemSlots = default!;
[Dependency] private readonly NavMapSystem _navMap = default!;
[Dependency] private readonly PointLightSystem _pointLight = default!;
@@ -45,6 +44,7 @@ public sealed class NukeSystem : EntitySystem
[Dependency] private readonly StationSystem _station = default!;
[Dependency] private readonly UserInterfaceSystem _ui = default!;
[Dependency] private readonly AppearanceSystem _appearance = default!;
[Dependency] private readonly TurfSystem _turf = default!;
/// <summary>
/// Used to calculate when the nuke song should start playing for maximum kino with the nuke sfx
@@ -210,7 +210,7 @@ public sealed class NukeSystem : EntitySystem
foreach (var tile in _map.GetTilesIntersecting(xform.GridUid.Value, grid, new Circle(worldPos, component.RequiredFloorRadius), false))
{
if (!tile.IsSpace(_tileDefManager))
if (!_turf.IsSpace(tile))
continue;
var msg = Loc.GetString("nuke-component-cant-anchor-floor");

View File

@@ -19,6 +19,7 @@ public sealed class ConveyorController : SharedConveyorController
[Dependency] private readonly DeviceLinkSystem _signalSystem = default!;
[Dependency] private readonly MaterialReclaimerSystem _materialReclaimer = default!;
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
[Dependency] private readonly TurfSystem _turf = default!;
public override void Initialize()
{
@@ -123,7 +124,7 @@ public sealed class ConveyorController : SharedConveyorController
var xform = ent.Comp;
var beltTileRef = xform.Coordinates.GetTileRef(EntityManager, MapManager);
var beltTileRef = _turf.GetTileRef(xform.Coordinates);
if (beltTileRef != null)
{

View File

@@ -28,7 +28,7 @@ public sealed partial class NavMapSystem : SharedNavMapSystem
[Dependency] private readonly SharedTransformSystem _transformSystem = default!;
[Dependency] private readonly IMapManager _mapManager = default!;
[Dependency] private readonly IGameTiming _gameTiming = default!;
[Dependency] private readonly ITileDefinitionManager _tileDefManager = default!;
[Dependency] private readonly TurfSystem _turfSystem = default!;
public const float CloseDistance = 15f;
public const float FarDistance = 30f;
@@ -118,7 +118,7 @@ public sealed partial class NavMapSystem : SharedNavMapSystem
var relative = SharedMapSystem.GetChunkRelative(tile, ChunkSize);
ref var tileData = ref chunk.TileData[GetTileIndex(relative)];
if (change.NewTile.IsSpace(_tileDefManager))
if (_turfSystem.IsSpace(change.NewTile))
{
tileData = 0;
if (PruneEmpty((ev.Entity, navMap), chunk))

View File

@@ -30,7 +30,7 @@ public sealed partial class DungeonJob
SharedPathfindingSystem.GridCast(startTile, position, tile =>
{
if (!_maps.TryGetTileRef(_gridUid, _grid, tile, out var tileRef) ||
tileRef.Tile.IsSpace(_tileDefManager))
_turf.IsSpace(tileRef.Tile))
{
return true;
}

View File

@@ -42,6 +42,7 @@ public sealed partial class DungeonJob : Job<List<Dungeon>>
private readonly EntityTableSystem _entTable;
private readonly TagSystem _tags;
private readonly TileSystem _tile;
private readonly TurfSystem _turf;
private readonly SharedMapSystem _maps;
private readonly SharedTransformSystem _transform;
@@ -70,6 +71,7 @@ public sealed partial class DungeonJob : Job<List<Dungeon>>
DungeonSystem dungeon,
EntityLookupSystem lookup,
TileSystem tile,
TurfSystem turf,
SharedTransformSystem transform,
DungeonConfig gen,
MapGridComponent grid,
@@ -89,6 +91,7 @@ public sealed partial class DungeonJob : Job<List<Dungeon>>
_dungeon = dungeon;
_lookup = lookup;
_tile = tile;
_turf = turf;
_tags = _entManager.System<TagSystem>();
_maps = _entManager.System<SharedMapSystem>();
_entTable = _entManager.System<EntityTableSystem>();

View File

@@ -36,6 +36,7 @@ public sealed partial class DungeonSystem : SharedDungeonSystem
[Dependency] private readonly DecalSystem _decals = default!;
[Dependency] private readonly EntityLookupSystem _lookup = default!;
[Dependency] private readonly TileSystem _tile = default!;
[Dependency] private readonly TurfSystem _turf = default!;
[Dependency] private readonly MapLoaderSystem _loader = default!;
[Dependency] private readonly SharedMapSystem _maps = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!;
@@ -212,6 +213,7 @@ public sealed partial class DungeonSystem : SharedDungeonSystem
this,
_lookup,
_tile,
_turf,
_transform,
gen,
grid,
@@ -244,6 +246,7 @@ public sealed partial class DungeonSystem : SharedDungeonSystem
this,
_lookup,
_tile,
_turf,
_transform,
gen,
grid,

View File

@@ -17,7 +17,6 @@ namespace Content.Server.Respawn;
public sealed class SpecialRespawnSystem : SharedSpecialRespawnSystem
{
[Dependency] private readonly IAdminLogManager _adminLog = default!;
[Dependency] private readonly ITileDefinitionManager _tileDefinitionManager = default!;
[Dependency] private readonly AtmosphereSystem _atmosphere = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!;
@@ -108,7 +107,7 @@ public sealed class SpecialRespawnSystem : SharedSpecialRespawnSystem
foreach (var tile in _map.GetTilesIntersecting(entityGridUid.Value, grid, circle))
{
if (tile.IsSpace(_tileDefinitionManager)
if (_turf.IsSpace(tile)
|| _turf.IsTileBlocked(tile, CollisionGroup.MobMask)
|| !_atmosphere.IsTileMixtureProbablySafe(entityGridUid, entityMapUid.Value,
_map.TileIndicesFor((entityGridUid.Value, grid), mapPos)))
@@ -179,7 +178,7 @@ public sealed class SpecialRespawnSystem : SharedSpecialRespawnSystem
foreach (var newTileRef in _map.GetTilesIntersecting(targetGrid, grid, circle))
{
if (newTileRef.IsSpace(_tileDefinitionManager) || _turf.IsTileBlocked(newTileRef, CollisionGroup.MobMask) || !_atmosphere.IsTileMixtureProbablySafe(targetGrid, targetMap, mapTarget))
if (_turf.IsSpace(newTileRef) || _turf.IsTileBlocked(newTileRef, CollisionGroup.MobMask) || !_atmosphere.IsTileMixtureProbablySafe(targetGrid, targetMap, mapTarget))
continue;
found = true;

View File

@@ -45,6 +45,7 @@ public sealed partial class RevenantSystem : EntitySystem
[Dependency] private readonly StoreSystem _store = default!;
[Dependency] private readonly TagSystem _tag = default!;
[Dependency] private readonly VisibilitySystem _visibility = default!;
[Dependency] private readonly TurfSystem _turf = default!;
[ValidatePrototypeId<EntityPrototype>]
private const string RevenantShopId = "ActionRevenantShop";
@@ -164,7 +165,7 @@ public sealed partial class RevenantSystem : EntitySystem
return false;
}
var tileref = Transform(uid).Coordinates.GetTileRef();
var tileref = _turf.GetTileRef(Transform(uid).Coordinates);
if (tileref != null)
{
if(_physics.GetEntitiesIntersectingBody(uid, (int) CollisionGroup.Impassable).Count > 0)

View File

@@ -679,7 +679,7 @@ public sealed partial class ShuttleSystem
// only toss if its on lattice/space
var tile = _mapSystem.GetTileRef(shuttleEntity, shuttleGrid, childXform.Coordinates);
if (!tile.IsSpace(_tileDefManager))
if (!_turf.IsSpace(tile))
return;
var throwDirection = childXform.LocalPosition - shuttleBody.LocalCenter;

View File

@@ -275,7 +275,7 @@ public sealed partial class ShuttleSystem
foreach (var tileRef in _mapSystem.GetLocalTilesIntersecting(uid, grid, new Circle(centerTile, radius)))
{
var def = (ContentTileDefinition)_tileDefManager[tileRef.Tile.TypeId];
var def = _turf.GetContentTileDefinition(tileRef);
mass += def.Mass;
tileCount++;
@@ -402,7 +402,7 @@ public sealed partial class ShuttleSystem
continue;
// Mark tiles for breaking/effects
var def = (ContentTileDefinition)_tileDefManager[_mapSystem.GetTileRef(uid, grid, tileData.Tile).Tile.TypeId];
var def = _turf.GetContentTileDefinition(_mapSystem.GetTileRef(uid, grid, tileData.Tile));
if (tileData.Energy > def.Mass * _tileBreakEnergyMultiplier)
brokenTiles.Add((tileData.Tile, Tile.Empty));

View File

@@ -28,6 +28,7 @@ using Robust.Shared.Physics.Systems;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
using Robust.Shared.Timing;
using Content.Shared.Maps;
namespace Content.Server.Shuttles.Systems;
@@ -40,7 +41,6 @@ public sealed partial class ShuttleSystem : SharedShuttleSystem
[Dependency] private readonly IMapManager _mapManager = default!;
[Dependency] private readonly IPrototypeManager _protoManager = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly ITileDefinitionManager _tileDefManager = default!;
[Dependency] private readonly BiomeSystem _biomes = default!;
[Dependency] private readonly BodySystem _bobby = default!;
[Dependency] private readonly BuckleSystem _buckle = default!;
@@ -62,6 +62,7 @@ public sealed partial class ShuttleSystem : SharedShuttleSystem
[Dependency] private readonly ThrowingSystem _throwing = default!;
[Dependency] private readonly ThrusterSystem _thruster = default!;
[Dependency] private readonly UserInterfaceSystem _uiSystem = default!;
[Dependency] private readonly TurfSystem _turf = default!;
private EntityQuery<BuckleComponent> _buckleQuery;
private EntityQuery<MapGridComponent> _gridQuery;

View File

@@ -26,13 +26,13 @@ namespace Content.Server.Shuttles.Systems;
public sealed class ThrusterSystem : EntitySystem
{
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly ITileDefinitionManager _tileDefManager = default!;
[Dependency] private readonly SharedMapSystem _mapSystem = default!;
[Dependency] private readonly AmbientSoundSystem _ambient = default!;
[Dependency] private readonly FixtureSystem _fixtureSystem = default!;
[Dependency] private readonly DamageableSystem _damageable = default!;
[Dependency] private readonly SharedPointLightSystem _light = default!;
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
[Dependency] private readonly TurfSystem _turf = default!;
// Essentially whenever thruster enables we update the shuttle's available impulses which are used for movement.
// This is done for each direction available.
@@ -97,7 +97,7 @@ public sealed class ThrusterSystem : EntitySystem
foreach (var change in args.Changes)
{
// If the old tile was space but the new one isn't then disable all adjacent thrusters
if (change.NewTile.IsSpace(_tileDefManager) || !change.OldTile.IsSpace(_tileDefManager))
if (_turf.IsSpace(change.NewTile) || !_turf.IsSpace(change.OldTile))
continue;
var tilePos = change.GridIndices;
@@ -457,7 +457,7 @@ public sealed class ThrusterSystem : EntitySystem
var mapGrid = Comp<MapGridComponent>(xform.GridUid.Value);
var tile = _mapSystem.GetTileRef(xform.GridUid.Value, mapGrid, new Vector2i((int)Math.Floor(x), (int)Math.Floor(y)));
return tile.Tile.IsSpace();
return _turf.IsSpace(tile);
}
#region Burning

View File

@@ -10,6 +10,13 @@ namespace Content.Server.Spider;
public sealed class SpiderSystem : SharedSpiderSystem
{
[Dependency] private readonly PopupSystem _popup = default!;
[Dependency] private readonly EntityLookupSystem _lookup = default!;
[Dependency] private readonly TurfSystem _turf = default!;
/// <summary>
/// A recycled hashset used to check turfs for spiderwebs.
/// </summary>
private readonly HashSet<EntityUid> _webs = [];
public override void Initialize()
{
@@ -66,7 +73,9 @@ public sealed class SpiderSystem : SharedSpiderSystem
private bool IsTileBlockedByWeb(EntityCoordinates coords)
{
foreach (var entity in coords.GetEntitiesInTile())
_webs.Clear();
_turf.GetEntitiesInTile(coords, _webs);
foreach (var entity in _webs)
{
if (HasComp<SpiderWebObjectComponent>(entity))
return true;

View File

@@ -23,6 +23,7 @@ public sealed class SpreaderSystem : EntitySystem
[Dependency] private readonly IRobustRandom _robustRandom = default!;
[Dependency] private readonly SharedMapSystem _map = default!;
[Dependency] private readonly TagSystem _tag = default!;
[Dependency] private readonly TurfSystem _turf = default!;
/// <summary>
/// Cached maximum number of updates per spreader prototype. This is applied per-grid.
@@ -246,7 +247,7 @@ public sealed class SpreaderSystem : EntitySystem
if (!_map.TryGetTileRef(neighborEnt, neighborGrid, neighborPos, out var tileRef) || tileRef.Tile.IsEmpty)
continue;
if (spreaderPrototype.PreventSpreadOnSpaced && tileRef.Tile.IsSpace())
if (spreaderPrototype.PreventSpreadOnSpaced && _turf.IsSpace(tileRef))
continue;
var directionEnumerator = _map.GetAnchoredEntitiesEnumerator(neighborEnt, neighborGrid, neighborPos);

View File

@@ -14,6 +14,7 @@ public sealed class SimpleFloorPlanPopulatorSystem : BaseWorldSystem
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly ITileDefinitionManager _tileDefinition = default!;
[Dependency] private readonly SharedMapSystem _map = default!;
[Dependency] private readonly TurfSystem _turf = default!;
/// <inheritdoc />
public override void Initialize()
@@ -30,7 +31,7 @@ public sealed class SimpleFloorPlanPopulatorSystem : BaseWorldSystem
while (enumerator.MoveNext(out var tile))
{
var coords = _map.GridTileToLocal(uid, grid, tile.Value.GridIndices);
var selector = tile.Value.Tile.GetContentTileDefinition(_tileDefinition).ID;
var selector = _turf.GetContentTileDefinition(tile.Value).ID;
if (!component.Caches.TryGetValue(selector, out var cache))
continue;

View File

@@ -55,7 +55,7 @@ public sealed class GoliathTentacleSystem : EntitySystem
foreach (var pos in spawnPos)
{
if (!_map.TryGetTileRef(grid, gridComp, pos, out var tileRef) ||
tileRef.IsSpace() ||
_turf.IsSpace(tileRef) ||
_turf.IsTileBlocked(tileRef, CollisionGroup.Impassable))
{
continue;

View File

@@ -31,6 +31,7 @@ public sealed partial class BlockingSystem : EntitySystem
[Dependency] private readonly EntityLookupSystem _lookup = default!;
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
[Dependency] private readonly ExamineSystemShared _examine = default!;
[Dependency] private readonly TurfSystem _turf = default!;
public override void Initialize()
{
@@ -165,7 +166,7 @@ public sealed partial class BlockingSystem : EntitySystem
}
//Don't allow someone to block if someone else is on the same tile
var playerTileRef = xform.Coordinates.GetTileRef();
var playerTileRef = _turf.GetTileRef(xform.Coordinates);
if (playerTileRef != null)
{
var intersecting = _lookup.GetLocalEntitiesIntersecting(playerTileRef.Value, 0f);

View File

@@ -1,4 +1,5 @@
using Content.Shared.Maps;
using Content.Shared.Physics;
using JetBrains.Annotations;
using Robust.Shared.Map;
@@ -14,24 +15,25 @@ public sealed partial class TileNotBlocked : IConstructionCondition
public bool Condition(EntityUid user, EntityCoordinates location, Direction direction)
{
var tileRef = location.GetTileRef();
if (!IoCManager.Resolve<IEntityManager>().TrySystem<TurfSystem>(out var turfSystem))
return false;
if (tileRef == null)
if (!turfSystem.TryGetTileRef(location, out var tileRef))
{
return false;
}
if (tileRef.Value.IsSpace() && _failIfSpace)
if (turfSystem.IsSpace(tileRef.Value) && _failIfSpace)
{
return false;
}
if (!tileRef.Value.GetContentTileDefinition().Sturdy && _failIfNotSturdy)
if (!turfSystem.GetContentTileDefinition(tileRef.Value).Sturdy && _failIfNotSturdy)
{
return false;
}
return !tileRef.Value.IsBlockedTurf(_filterMobs);
return !turfSystem.IsTileBlocked(tileRef.Value, _filterMobs ? CollisionGroup.MobMask : CollisionGroup.Impassable);
}
public ConstructionGuideEntry GenerateGuideEntry()

View File

@@ -20,12 +20,13 @@ namespace Content.Shared.Construction.Conditions
public bool Condition(EntityUid user, EntityCoordinates location, Direction direction)
{
var tileFound = location.GetTileRef();
if (tileFound == null)
if (!IoCManager.Resolve<IEntityManager>().TrySystem<TurfSystem>(out var turfSystem))
return false;
var tile = tileFound.Value.Tile.GetContentTileDefinition();
if (!turfSystem.TryGetTileRef(location, out var tileFound))
return false;
var tile = turfSystem.GetContentTileDefinition(tileFound.Value);
foreach (var targetTile in TargetTiles)
{
if (tile.ID == targetTile)

View File

@@ -62,6 +62,7 @@ public abstract class SharedMagicSystem : EntitySystem
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly SharedMindSystem _mind = default!;
[Dependency] private readonly SharedStunSystem _stun = default!;
[Dependency] private readonly TurfSystem _turf = default!;
private static readonly ProtoId<TagPrototype> InvalidForGlobalSpawnSpellTag = "InvalidForGlobalSpawnSpell";
@@ -158,7 +159,7 @@ public abstract class SharedMagicSystem : EntitySystem
if (!TryComp<MapGridComponent>(casterXform.GridUid, out var mapGrid))
return new List<EntityCoordinates>();
if (!directionPos.TryGetTileRef(out var tileReference, EntityManager, _mapManager))
if (!_turf.TryGetTileRef(directionPos, out var tileReference))
return new List<EntityCoordinates>();
var tileIndex = tileReference.Value.GridIndices;
@@ -171,7 +172,7 @@ public abstract class SharedMagicSystem : EntitySystem
if (!TryComp<MapGridComponent>(casterXform.GridUid, out var mapGrid))
return new List<EntityCoordinates>();
if (!directionPos.TryGetTileRef(out var tileReference, EntityManager, _mapManager))
if (!_turf.TryGetTileRef(directionPos, out var tileReference))
return new List<EntityCoordinates>();
var tileIndex = tileReference.Value.GridIndices;

View File

@@ -1,144 +0,0 @@
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Runtime.CompilerServices;
using Content.Shared.Physics;
using Robust.Shared.Map;
using Robust.Shared.Map.Components;
using Robust.Shared.Random;
namespace Content.Shared.Maps
{
// TODO move all these methods to LookupSystem or TurfSystem
// That, or make the interface arguments non-optional so people stop failing to pass them in.
public static class TurfHelpers
{
/// <summary>
/// Attempts to get the turf at a certain coordinates or null if no such turf is found.
/// </summary>
public static TileRef? GetTileRef(this EntityCoordinates coordinates, IEntityManager? entityManager = null, IMapManager? mapManager = null)
{
entityManager ??= IoCManager.Resolve<IEntityManager>();
if (!coordinates.IsValid(entityManager))
return null;
mapManager ??= IoCManager.Resolve<IMapManager>();
var pos = entityManager.System<SharedTransformSystem>().ToMapCoordinates(coordinates);
if (!mapManager.TryFindGridAt(pos, out _, out var grid))
return null;
if (!grid.TryGetTileRef(coordinates, out var tile))
return null;
return tile;
}
public static bool TryGetTileRef(this EntityCoordinates coordinates, [NotNullWhen(true)] out TileRef? turf, IEntityManager? entityManager = null, IMapManager? mapManager = null)
{
return (turf = coordinates.GetTileRef(entityManager, mapManager)) != null;
}
/// <summary>
/// Returns the content tile definition for a tile.
/// </summary>
public static ContentTileDefinition GetContentTileDefinition(this Tile tile, ITileDefinitionManager? tileDefinitionManager = null)
{
tileDefinitionManager ??= IoCManager.Resolve<ITileDefinitionManager>();
return (ContentTileDefinition)tileDefinitionManager[tile.TypeId];
}
/// <summary>
/// Returns whether a tile is considered space.
/// </summary>
public static bool IsSpace(this Tile tile, ITileDefinitionManager? tileDefinitionManager = null)
{
return tile.GetContentTileDefinition(tileDefinitionManager).MapAtmosphere;
}
/// <summary>
/// Returns the content tile definition for a tile ref.
/// </summary>
public static ContentTileDefinition GetContentTileDefinition(this TileRef tile, ITileDefinitionManager? tileDefinitionManager = null)
{
return tile.Tile.GetContentTileDefinition(tileDefinitionManager);
}
/// <summary>
/// Returns whether a tile ref is considered space.
/// </summary>
public static bool IsSpace(this TileRef tile, ITileDefinitionManager? tileDefinitionManager = null)
{
return tile.Tile.IsSpace(tileDefinitionManager);
}
/// <summary>
/// Helper that returns all entities in a turf.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[Obsolete("Use the lookup system")]
public static IEnumerable<EntityUid> GetEntitiesInTile(this TileRef turf, LookupFlags flags = LookupFlags.Static, EntityLookupSystem? lookupSystem = null)
{
lookupSystem ??= EntitySystem.Get<EntityLookupSystem>();
if (!GetWorldTileBox(turf, out var worldBox))
return Enumerable.Empty<EntityUid>();
return lookupSystem.GetEntitiesIntersecting(turf.GridUid, worldBox, flags);
}
/// <summary>
/// Helper that returns all entities in a turf.
/// </summary>
[Obsolete("Use the lookup system")]
public static IEnumerable<EntityUid> GetEntitiesInTile(this EntityCoordinates coordinates, LookupFlags flags = LookupFlags.Static, EntityLookupSystem? lookupSystem = null)
{
var turf = coordinates.GetTileRef();
if (turf == null)
return Enumerable.Empty<EntityUid>();
return GetEntitiesInTile(turf.Value, flags, lookupSystem);
}
/// <summary>
/// Checks if a turf has something dense on it.
/// </summary>
[Obsolete("Use turf system")]
public static bool IsBlockedTurf(this TileRef turf, bool filterMobs, EntityLookupSystem? physics = null)
{
CollisionGroup mask = filterMobs
? CollisionGroup.MobMask
: CollisionGroup.Impassable;
return IoCManager.Resolve<IEntitySystemManager>().GetEntitySystem<TurfSystem>().IsTileBlocked(turf, mask);
}
/// <summary>
/// Creates a box the size of a tile, at the same position in the world as the tile.
/// </summary>
[Obsolete]
private static bool GetWorldTileBox(TileRef turf, out Box2Rotated res)
{
var entManager = IoCManager.Resolve<IEntityManager>();
var xformSystem = entManager.System<SharedTransformSystem>();
if (entManager.TryGetComponent<MapGridComponent>(turf.GridUid, out var tileGrid))
{
var gridRot = xformSystem.GetWorldRotation(turf.GridUid);
// This is scaled to 90 % so it doesn't encompass walls on other tiles.
var tileBox = Box2.UnitCentered.Scale(0.9f);
tileBox = tileBox.Scale(tileGrid.TileSize);
var worldPos = tileGrid.GridTileToWorldPos(turf.GridIndices);
tileBox = tileBox.Translated(worldPos);
// Now tileBox needs to be rotated to match grid rotation
res = new Box2Rotated(tileBox, gridRot, worldPos);
return true;
}
// Have to "return something"
res = Box2Rotated.UnitCentered;
return false;
}
}
}

View File

@@ -1,8 +1,11 @@
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Numerics;
using Content.Shared.Physics;
using Robust.Shared.Map;
using Robust.Shared.Map.Components;
using Robust.Shared.Physics;
using Robust.Shared.Toolshed.Commands.Values;
namespace Content.Shared.Maps;
@@ -11,8 +14,43 @@ namespace Content.Shared.Maps;
/// </summary>
public sealed class TurfSystem : EntitySystem
{
[Dependency] private readonly IMapManager _mapManager = default!;
[Dependency] private readonly EntityLookupSystem _entityLookup = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!;
[Dependency] private readonly SharedMapSystem _mapSystem = default!;
[Dependency] private readonly ITileDefinitionManager _tileDefinitions = default!;
/// <summary>
/// Attempts to get the turf at or under some given coordinates or null if no such turf exists.
/// </summary>
/// <param name="coordinates">The coordinates to search for a turf.</param>
/// <returns>A <see cref="TileRef"/> for the turf found at the given coordinates or null if no such turf exists.</returns>
public TileRef? GetTileRef(EntityCoordinates coordinates)
{
if (!coordinates.IsValid(EntityManager))
return null;
var pos = _transform.ToMapCoordinates(coordinates);
if (!_mapManager.TryFindGridAt(pos, out var gridUid, out var gridComp))
return null;
if (!_mapSystem.TryGetTileRef(gridUid, gridComp, coordinates, out var tile))
return null;
return tile;
}
/// <summary>
/// Attempts to get the turf at or under some given coordinates.
/// </summary>
/// <param name="coordinates">The coordinates to search for a turf.</param>
/// <param name="tile">Returns the turf found at the given coordinates if any.</param>
/// <returns>True if a turf was found at the given coordinates, false otherwise.</returns>
public bool TryGetTileRef(EntityCoordinates coordinates, [NotNullWhen(true)] out TileRef? tile)
{
return (tile = GetTileRef(coordinates)) is not null;
}
/// <summary>
/// Returns true if a given tile is blocked by physics-enabled entities.
@@ -63,14 +101,14 @@ public sealed class TurfSystem : EntitySystem
rot -= gridRot;
pos = (-gridRot).RotateVec(pos - gridPos);
var xform = new Transform(pos, (float) rot.Theta);
var xform = new Transform(pos, (float)rot.Theta);
foreach (var fixture in fixtures.Fixtures.Values)
{
if (!fixture.Hard)
continue;
if ((fixture.CollisionLayer & (int) mask) == 0)
if ((fixture.CollisionLayer & (int)mask) == 0)
continue;
for (var i = 0; i < fixture.Shape.ChildCount; i++)
@@ -86,6 +124,26 @@ public sealed class TurfSystem : EntitySystem
return false;
}
/// <summary>
/// Returns whether a tile is considered to be space or directly exposed to space.
/// </summary>
/// <param name="tile">The tile in question.</param>
/// <returns>True if the tile is considered to be space, false otherwise.</returns>
public bool IsSpace(Tile tile)
{
return GetContentTileDefinition(tile).MapAtmosphere;
}
/// <summary>
/// Returns whether a tile is considered to be space or directly exposed to space.
/// </summary>
/// <param name="tile">The tile in question.</param>
/// <returns>True if the tile is considered to be space, false otherwise.</returns>
public bool IsSpace(TileRef tile)
{
return IsSpace(tile.Tile);
}
/// <summary>
/// Returns the location of the centre of the tile in grid coordinates.
/// </summary>
@@ -95,4 +153,78 @@ public sealed class TurfSystem : EntitySystem
var center = (turf.GridIndices + new Vector2(0.5f, 0.5f)) * grid.TileSize;
return new EntityCoordinates(turf.GridUid, center);
}
/// <summary>
/// Returns the content tile definition for a tile.
/// </summary>
public ContentTileDefinition GetContentTileDefinition(Tile tile)
{
return (ContentTileDefinition)_tileDefinitions[tile.TypeId];
}
/// <summary>
/// Returns the content tile definition for a tile ref.
/// </summary>
public ContentTileDefinition GetContentTileDefinition(TileRef tile)
{
return GetContentTileDefinition(tile.Tile);
}
/// <summary>
/// Collects all of the entities intersecting with the turf at a given position into a provided <see cref="HashSet{EntityUid}"/>
/// </summary>
/// <param name="coords">The position of the turf to search for entities.</param>
/// <param name="intersecting">The hashset used to collect the relevant entities.</param>
/// <param name="flags">A set of lookup categories to search for relevant entities.</param>
public void GetEntitiesInTile(EntityCoordinates coords, HashSet<EntityUid> intersecting, LookupFlags flags = LookupFlags.Static)
{
if (!TryGetTileRef(coords, out var tileRef))
return;
_entityLookup.GetEntitiesInTile(tileRef.Value, intersecting, flags);
}
/// <summary>
/// Returns a collection containing all of the entities overlapping with the turf at a given position.
/// </summary>
/// <inheritdoc cref="GetEntitiesInTile(EntityCoordinates, HashSet{EntityUid}, LookupFlags)"/>
/// <returns>A hashset containing all of the entities overlapping with the turf in question.</returns>
public HashSet<EntityUid> GetEntitiesInTile(EntityCoordinates coords, LookupFlags flags = LookupFlags.Static)
{
if (!TryGetTileRef(coords, out var tileRef))
return [];
return _entityLookup.GetEntitiesInTile(tileRef.Value, flags);
}
}
/// <summary>
/// Extension methods for looking up entities with respect to given turfs.
/// </summary>
public static partial class TurfLookupExtensions
{
/// <summary>
/// Collects all of the entities overlapping with a given turf into a provided <see cref="HashSet{EntityUid}"/>.
/// </summary>
/// <param name="turf">The turf in question.</param>
/// <param name="intersecting">The hashset used to collect the relevant entities.</param>
/// <param name="flags">A set of lookup categories to search for relevant entities.</param>
public static void GetEntitiesInTile(this EntityLookupSystem lookupSystem, TileRef turf, HashSet<EntityUid> intersecting, LookupFlags flags = LookupFlags.Static)
{
var bounds = lookupSystem.GetWorldBounds(turf);
bounds.Box = bounds.Box.Scale(0.9f); // Otherwise the box can clip into neighboring tiles.
lookupSystem.GetEntitiesIntersecting(turf.GridUid, bounds, intersecting, flags);
}
/// <summary>
/// Returns a collection containing all of the entities overlapping with a given turf.
/// </summary>
/// <inheritdoc cref="GetEntitiesInTile(EntityLookupSystem, TileRef, HashSet{EntityUid}, LookupFlags)"/>
/// <returns>A hashset containing all of the entities overlapping with the turf in question.</returns>
public static HashSet<EntityUid> GetEntitiesInTile(this EntityLookupSystem lookupSystem, TileRef turf, LookupFlags flags = LookupFlags.Static)
{
var intersecting = new HashSet<EntityUid>();
lookupSystem.GetEntitiesInTile(turf, intersecting, flags);
return intersecting;
}
}

View File

@@ -175,7 +175,7 @@ public sealed class RCDSystem : EntitySystem
else
{
var deconstructedTile = _mapSystem.GetTileRef(gridUid.Value, mapGrid, location);
var protoName = !deconstructedTile.IsSpace() ? _deconstructTileProto : _deconstructLatticeProto;
var protoName = !_turf.IsSpace(deconstructedTile) ? _deconstructTileProto : _deconstructLatticeProto;
if (_protoManager.TryIndex(protoName, out var deconProto))
{
@@ -383,7 +383,7 @@ public sealed class RCDSystem : EntitySystem
}
// Check rule: Must place on subfloor
if (prototype.ConstructionRules.Contains(RcdConstructionRule.MustBuildOnSubfloor) && !tile.Tile.GetContentTileDefinition().IsSubFloor)
if (prototype.ConstructionRules.Contains(RcdConstructionRule.MustBuildOnSubfloor) && !_turf.GetContentTileDefinition(tile).IsSubFloor)
{
if (popMsgs)
_popup.PopupClient(Loc.GetString("rcd-component-must-build-on-subfloor-message"), uid, user);
@@ -404,7 +404,7 @@ public sealed class RCDSystem : EntitySystem
}
// Check rule: Tiles can't be identical
if (tile.Tile.GetContentTileDefinition().ID == prototype.Prototype)
if (_turf.GetContentTileDefinition(tile).ID == prototype.Prototype)
{
if (popMsgs)
_popup.PopupClient(Loc.GetString("rcd-component-cannot-build-identical-tile"), uid, user);
@@ -487,7 +487,7 @@ public sealed class RCDSystem : EntitySystem
}
// The tile cannot be destroyed
var tileDef = (ContentTileDefinition) _tileDefMan[tile.Tile.TypeId];
var tileDef = _turf.GetContentTileDefinition(tile);
if (tileDef.Indestructible)
{
@@ -559,7 +559,7 @@ public sealed class RCDSystem : EntitySystem
if (target == null)
{
// Deconstruct tile (either converts the tile to lattice, or removes lattice)
var tileDef = (tile.Tile.GetContentTileDefinition().ID != "Lattice") ? new Tile(_tileDefMan["Lattice"].TileId) : Tile.Empty;
var tileDef = (_turf.GetContentTileDefinition(tile).ID != "Lattice") ? new Tile(_tileDefMan["Lattice"].TileId) : Tile.Empty;
_mapSystem.SetTile(gridUid, mapGrid, position, tileDef);
_adminLogger.Add(LogType.RCD, LogImpact.High, $"{ToPrettyString(user):user} used RCD to set grid: {gridUid} tile: {position} open to space");
}

View File

@@ -31,13 +31,13 @@ public abstract class SharedEmitSoundSystem : EntitySystem
{
[Dependency] protected readonly IGameTiming Timing = default!;
[Dependency] private readonly INetManager _netMan = default!;
[Dependency] private readonly ITileDefinitionManager _tileDefMan = default!;
[Dependency] protected readonly IRobustRandom Random = default!;
[Dependency] private readonly SharedAmbientSoundSystem _ambient = default!;
[Dependency] private readonly SharedAudioSystem _audioSystem = default!;
[Dependency] protected readonly SharedPopupSystem Popup = default!;
[Dependency] private readonly SharedMapSystem _map = default!;
[Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!;
[Dependency] private readonly TurfSystem _turf = default!;
public override void Initialize()
{
@@ -135,7 +135,7 @@ public abstract class SharedEmitSoundSystem : EntitySystem
var tile = _map.GetTileRef(xform.GridUid.Value, grid, xform.Coordinates);
// Handle maps being grids (we'll still emit the sound).
if (xform.GridUid != xform.MapUid && tile.IsSpace(_tileDefMan))
if (xform.GridUid != xform.MapUid && _turf.IsSpace(tile))
return;
// hand throwing not predicted sadly

View File

@@ -37,9 +37,15 @@ public sealed class FloorTileSystem : EntitySystem
[Dependency] private readonly TileSystem _tile = default!;
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
[Dependency] private readonly SharedMapSystem _map = default!;
[Dependency] private readonly TurfSystem _turf = default!;
private static readonly Vector2 CheckRange = new(1f, 1f);
/// <summary>
/// A recycled hashset used to check for walls when trying to place tiles on turfs.
/// </summary>
private readonly HashSet<EntityUid> _turfCheck = [];
public override void Initialize()
{
base.Initialize();
@@ -104,14 +110,16 @@ public sealed class FloorTileSystem : EntitySystem
// if user can access tile center then they can place floor
// otherwise check it isn't blocked by a wall
if (!canAccessCenter)
if (!canAccessCenter && _turf.TryGetTileRef(location, out var tileRef))
{
foreach (var ent in location.GetEntitiesInTile(lookupSystem: _lookup))
_turfCheck.Clear();
_lookup.GetEntitiesInTile(tileRef.Value, _turfCheck);
foreach (var ent in _turfCheck)
{
if (physicQuery.TryGetComponent(ent, out var phys) &&
phys.BodyType == BodyType.Static &&
phys.Hard &&
(phys.CollisionLayer & (int) CollisionGroup.Impassable) != 0)
(phys.CollisionLayer & (int)CollisionGroup.Impassable) != 0)
{
return;
}