Don't spawn mobs on blocked dungeon tiles (#17910)

a
This commit is contained in:
metalgearsloth
2023-07-10 05:20:55 +10:00
committed by GitHub
parent 982e8f3865
commit 7a63238487
5 changed files with 58 additions and 41 deletions

View File

@@ -23,9 +23,6 @@ public sealed partial class DungeonJob
* Run after the main dungeon generation * Run after the main dungeon generation
*/ */
private const int CollisionMask = (int) CollisionGroup.Impassable;
private const int CollisionLayer = (int) CollisionGroup.Impassable;
private bool HasWall(MapGridComponent grid, Vector2i tile) private bool HasWall(MapGridComponent grid, Vector2i tile)
{ {
var anchored = grid.GetAnchoredEntitiesEnumerator(tile); var anchored = grid.GetAnchoredEntitiesEnumerator(tile);
@@ -194,7 +191,7 @@ public sealed partial class DungeonJob
if (dungeon.RoomTiles.Contains(neighbor)) if (dungeon.RoomTiles.Contains(neighbor))
continue; continue;
if (!_anchorable.TileFree(grid, neighbor, CollisionLayer, CollisionMask)) if (!_anchorable.TileFree(grid, neighbor, DungeonSystem.CollisionLayer, DungeonSystem.CollisionMask))
continue; continue;
tiles.Add((neighbor, _tileDefManager.GetVariantTile(tileDef, random))); tiles.Add((neighbor, _tileDefManager.GetVariantTile(tileDef, random)));
@@ -205,7 +202,7 @@ public sealed partial class DungeonJob
if (dungeon.RoomTiles.Contains(index)) if (dungeon.RoomTiles.Contains(index))
continue; continue;
if (!_anchorable.TileFree(grid, index, CollisionLayer, CollisionMask)) if (!_anchorable.TileFree(grid, index, DungeonSystem.CollisionLayer, DungeonSystem.CollisionMask))
continue; continue;
tiles.Add((index, _tileDefManager.GetVariantTile(tileDef, random))); tiles.Add((index, _tileDefManager.GetVariantTile(tileDef, random)));
@@ -217,7 +214,7 @@ public sealed partial class DungeonJob
for (var i = 0; i < tiles.Count; i++) for (var i = 0; i < tiles.Count; i++)
{ {
var index = tiles[i]; var index = tiles[i];
if (!_anchorable.TileFree(grid, index.Index, CollisionLayer, CollisionMask)) if (!_anchorable.TileFree(grid, index.Index, DungeonSystem.CollisionLayer, DungeonSystem.CollisionMask))
continue; continue;
// If no cardinal neighbors in dungeon then we're a corner. // If no cardinal neighbors in dungeon then we're a corner.
@@ -469,13 +466,13 @@ public sealed partial class DungeonJob
} }
// Check if exterior spot free. // Check if exterior spot free.
if (!_anchorable.TileFree(_grid, tile, CollisionLayer, CollisionMask)) if (!_anchorable.TileFree(_grid, tile, DungeonSystem.CollisionLayer, DungeonSystem.CollisionMask))
{ {
continue; continue;
} }
// Check if interior spot free (no guarantees on exterior but ClearDoor should handle it) // Check if interior spot free (no guarantees on exterior but ClearDoor should handle it)
if (!_anchorable.TileFree(_grid, dirVec, CollisionLayer, CollisionMask)) if (!_anchorable.TileFree(_grid, dirVec, DungeonSystem.CollisionLayer, DungeonSystem.CollisionMask))
{ {
continue; continue;
} }
@@ -542,7 +539,7 @@ public sealed partial class DungeonJob
break; break;
// Room tile / already used. // Room tile / already used.
if (!_anchorable.TileFree(_grid, tile, CollisionLayer, CollisionMask) || if (!_anchorable.TileFree(_grid, tile, DungeonSystem.CollisionLayer, DungeonSystem.CollisionMask) ||
takenTiles.Contains(tile)) takenTiles.Contains(tile))
{ {
continue; continue;
@@ -562,7 +559,7 @@ public sealed partial class DungeonJob
if (!allExterior.Contains(neighbor) || if (!allExterior.Contains(neighbor) ||
takenTiles.Contains(neighbor) || takenTiles.Contains(neighbor) ||
!_anchorable.TileFree(grid, neighbor, CollisionLayer, CollisionMask)) !_anchorable.TileFree(grid, neighbor, DungeonSystem.CollisionLayer, DungeonSystem.CollisionMask))
{ {
isValid = false; isValid = false;
break; break;
@@ -577,7 +574,7 @@ public sealed partial class DungeonJob
if (allExterior.Contains(perpTile) || if (allExterior.Contains(perpTile) ||
takenTiles.Contains(neighbor) || takenTiles.Contains(neighbor) ||
!_anchorable.TileFree(_grid, perpTile, CollisionLayer, CollisionMask)) !_anchorable.TileFree(_grid, perpTile, DungeonSystem.CollisionLayer, DungeonSystem.CollisionMask))
{ {
isValid = false; isValid = false;
break; break;
@@ -684,7 +681,7 @@ public sealed partial class DungeonJob
var windowTile = tile + dirVec; var windowTile = tile + dirVec;
if (!_anchorable.TileFree(grid, windowTile, CollisionLayer, CollisionMask)) if (!_anchorable.TileFree(grid, windowTile, DungeonSystem.CollisionLayer, DungeonSystem.CollisionMask))
continue; continue;
validTiles.Add(windowTile); validTiles.Add(windowTile);
@@ -930,7 +927,7 @@ public sealed partial class DungeonJob
// N-wide junctions // N-wide junctions
foreach (var tile in dungeon.CorridorTiles) foreach (var tile in dungeon.CorridorTiles)
{ {
if (!_anchorable.TileFree(_grid, tile, CollisionLayer, CollisionMask)) if (!_anchorable.TileFree(_grid, tile, DungeonSystem.CollisionLayer, DungeonSystem.CollisionMask))
continue; continue;
// Check each direction: // Check each direction:
@@ -967,7 +964,7 @@ public sealed partial class DungeonJob
} }
// If we're not at the end tile then check it + perpendicular are free. // If we're not at the end tile then check it + perpendicular are free.
if (!_anchorable.TileFree(_grid, neighbor, CollisionLayer, CollisionMask)) if (!_anchorable.TileFree(_grid, neighbor, DungeonSystem.CollisionLayer, DungeonSystem.CollisionMask))
{ {
isValid = false; isValid = false;
break; break;
@@ -976,13 +973,13 @@ public sealed partial class DungeonJob
var perp1 = tile + neighborVec * j + ((Direction) ((i * 2 + 2) % 8)).ToIntVec(); var perp1 = tile + neighborVec * j + ((Direction) ((i * 2 + 2) % 8)).ToIntVec();
var perp2 = tile + neighborVec * j + ((Direction) ((i * 2 + 6) % 8)).ToIntVec(); var perp2 = tile + neighborVec * j + ((Direction) ((i * 2 + 6) % 8)).ToIntVec();
if (!_anchorable.TileFree(_grid, perp1, CollisionLayer, CollisionMask)) if (!_anchorable.TileFree(_grid, perp1, DungeonSystem.CollisionLayer, DungeonSystem.CollisionMask))
{ {
isValid = false; isValid = false;
break; break;
} }
if (!_anchorable.TileFree(_grid, perp2, CollisionLayer, CollisionMask)) if (!_anchorable.TileFree(_grid, perp2, DungeonSystem.CollisionLayer, DungeonSystem.CollisionMask))
{ {
isValid = false; isValid = false;
break; break;
@@ -1004,7 +1001,7 @@ public sealed partial class DungeonJob
var cornerVec = cornerDir.ToIntVec(); var cornerVec = cornerDir.ToIntVec();
var cornerNeighbor = tile + neighborVec * j + cornerVec; var cornerNeighbor = tile + neighborVec * j + cornerVec;
if (_anchorable.TileFree(_grid, cornerNeighbor, CollisionLayer, CollisionMask)) if (_anchorable.TileFree(_grid, cornerNeighbor, DungeonSystem.CollisionLayer, DungeonSystem.CollisionMask))
{ {
freeCount++; freeCount++;
} }
@@ -1071,7 +1068,7 @@ public sealed partial class DungeonJob
if (dungeon.RoomTiles.Contains(neighbor)) if (dungeon.RoomTiles.Contains(neighbor))
continue; continue;
if (!_anchorable.TileFree(grid, neighbor, CollisionLayer, CollisionMask)) if (!_anchorable.TileFree(grid, neighbor, DungeonSystem.CollisionLayer, DungeonSystem.CollisionMask))
continue; continue;
roomEdges.Add(neighbor); roomEdges.Add(neighbor);
@@ -1133,7 +1130,7 @@ public sealed partial class DungeonJob
{ {
var node = nodeDistances[i].Node; var node = nodeDistances[i].Node;
var gridPos = grid.GridTileToLocal(node); var gridPos = grid.GridTileToLocal(node);
if (!_anchorable.TileFree(grid, node, CollisionLayer, CollisionMask)) if (!_anchorable.TileFree(grid, node, DungeonSystem.CollisionLayer, DungeonSystem.CollisionMask))
continue; continue;
width--; width--;
@@ -1193,8 +1190,8 @@ public sealed partial class DungeonJob
{ {
if (!physicsQuery.TryGetComponent(ent, out var physics) || if (!physicsQuery.TryGetComponent(ent, out var physics) ||
!physics.Hard || !physics.Hard ||
(CollisionMask & physics.CollisionLayer) == 0x0 && (DungeonSystem.CollisionMask & physics.CollisionLayer) == 0x0 &&
(CollisionLayer & physics.CollisionMask) == 0x0) (DungeonSystem.CollisionLayer & physics.CollisionMask) == 0x0)
{ {
continue; continue;
} }
@@ -1217,7 +1214,7 @@ public sealed partial class DungeonJob
foreach (var neighbor in allExterior) foreach (var neighbor in allExterior)
{ {
// Occupado // Occupado
if (dungeon.RoomTiles.Contains(neighbor) || checkedTiles.Contains(neighbor) || !_anchorable.TileFree(grid, neighbor, CollisionLayer, CollisionMask)) if (dungeon.RoomTiles.Contains(neighbor) || checkedTiles.Contains(neighbor) || !_anchorable.TileFree(grid, neighbor, DungeonSystem.CollisionLayer, DungeonSystem.CollisionMask))
continue; continue;
if (!random.Prob(gen.Prob) || !checkedTiles.Add(neighbor)) if (!random.Prob(gen.Prob) || !checkedTiles.Add(neighbor))

View File

@@ -6,6 +6,7 @@ using Content.Server.Decals;
using Content.Server.GameTicking.Events; using Content.Server.GameTicking.Events;
using Content.Shared.CCVar; using Content.Shared.CCVar;
using Content.Shared.Construction.EntitySystems; using Content.Shared.Construction.EntitySystems;
using Content.Shared.Physics;
using Content.Shared.Procedural; using Content.Shared.Procedural;
using Robust.Server.GameObjects; using Robust.Server.GameObjects;
using Robust.Shared.Configuration; using Robust.Shared.Configuration;
@@ -33,6 +34,9 @@ public sealed partial class DungeonSystem : SharedDungeonSystem
private const double DungeonJobTime = 0.005; private const double DungeonJobTime = 0.005;
public const int CollisionMask = (int) CollisionGroup.Impassable;
public const int CollisionLayer = (int) CollisionGroup.Impassable;
private readonly JobQueue _dungeonJobQueue = new(DungeonJobTime); private readonly JobQueue _dungeonJobQueue = new(DungeonJobTime);
private readonly Dictionary<DungeonJob, CancellationTokenSource> _dungeonJobs = new(); private readonly Dictionary<DungeonJob, CancellationTokenSource> _dungeonJobs = new();

View File

@@ -20,8 +20,6 @@ public sealed partial class SalvageSystem
* Handles setup / teardown of salvage expeditions. * Handles setup / teardown of salvage expeditions.
*/ */
[Dependency] private readonly CargoSystem _cargo = default!;
private const int MissionLimit = 5; private const int MissionLimit = 5;
private readonly JobQueue _salvageQueue = new(); private readonly JobQueue _salvageQueue = new();
@@ -269,7 +267,7 @@ public sealed partial class SalvageSystem
_timing, _timing,
_mapManager, _mapManager,
_prototypeManager, _prototypeManager,
_tileDefManager, _anchorable,
_biome, _biome,
_dungeon, _dungeon,
this, this,

View File

@@ -1,5 +1,6 @@
using System.Linq; using System.Linq;
using System.Numerics; using System.Numerics;
using Content.Server.Cargo.Systems;
using Content.Server.Construction; using Content.Server.Construction;
using Content.Server.GameTicking; using Content.Server.GameTicking;
using Content.Server.Radio.EntitySystems; using Content.Server.Radio.EntitySystems;
@@ -21,6 +22,7 @@ using Content.Server.Procedural;
using Content.Server.Shuttles.Systems; using Content.Server.Shuttles.Systems;
using Content.Server.Station.Systems; using Content.Server.Station.Systems;
using Content.Shared.CCVar; using Content.Shared.CCVar;
using Content.Shared.Construction.EntitySystems;
using Content.Shared.Random; using Content.Shared.Random;
using Content.Shared.Random.Helpers; using Content.Shared.Random.Helpers;
using Robust.Server.Maps; using Robust.Server.Maps;
@@ -37,8 +39,9 @@ namespace Content.Server.Salvage
[Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly IMapManager _mapManager = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly ITileDefinitionManager _tileDefManager = default!; [Dependency] private readonly AnchorableSystem _anchorable = default!;
[Dependency] private readonly BiomeSystem _biome = default!; [Dependency] private readonly BiomeSystem _biome = default!;
[Dependency] private readonly CargoSystem _cargo = default!;
[Dependency] private readonly DungeonSystem _dungeon = default!; [Dependency] private readonly DungeonSystem _dungeon = default!;
[Dependency] private readonly MapLoaderSystem _map = default!; [Dependency] private readonly MapLoaderSystem _map = default!;
[Dependency] private readonly SharedPopupSystem _popupSystem = default!; [Dependency] private readonly SharedPopupSystem _popupSystem = default!;

View File

@@ -12,25 +12,23 @@ using Content.Server.Procedural;
using Content.Server.Salvage.Expeditions; using Content.Server.Salvage.Expeditions;
using Content.Server.Salvage.Expeditions.Structure; using Content.Server.Salvage.Expeditions.Structure;
using Content.Shared.Atmos; using Content.Shared.Atmos;
using Content.Shared.Construction.EntitySystems;
using Content.Shared.Dataset; using Content.Shared.Dataset;
using Content.Shared.Gravity; using Content.Shared.Gravity;
using Content.Shared.Parallax.Biomes; using Content.Shared.Parallax.Biomes;
using Content.Shared.Parallax.Biomes.Markers; using Content.Shared.Physics;
using Content.Shared.Procedural; using Content.Shared.Procedural;
using Content.Shared.Procedural.Loot; using Content.Shared.Procedural.Loot;
using Content.Shared.Random;
using Content.Shared.Random.Helpers;
using Content.Shared.Salvage; using Content.Shared.Salvage;
using Content.Shared.Salvage.Expeditions; using Content.Shared.Salvage.Expeditions;
using Content.Shared.Salvage.Expeditions.Modifiers; using Content.Shared.Salvage.Expeditions.Modifiers;
using Content.Shared.Storage; using Content.Shared.Storage;
using Robust.Shared.Collections;
using Robust.Shared.Map; using Robust.Shared.Map;
using Robust.Shared.Map.Components; using Robust.Shared.Map.Components;
using Robust.Shared.Noise;
using Robust.Shared.Prototypes; using Robust.Shared.Prototypes;
using Robust.Shared.Random; using Robust.Shared.Random;
using Robust.Shared.Timing; using Robust.Shared.Timing;
using Robust.Shared.Utility;
namespace Content.Server.Salvage; namespace Content.Server.Salvage;
@@ -40,7 +38,7 @@ public sealed class SpawnSalvageMissionJob : Job<bool>
private readonly IGameTiming _timing; private readonly IGameTiming _timing;
private readonly IMapManager _mapManager; private readonly IMapManager _mapManager;
private readonly IPrototypeManager _prototypeManager; private readonly IPrototypeManager _prototypeManager;
private readonly ITileDefinitionManager _tileDefManager; private readonly AnchorableSystem _anchorable;
private readonly BiomeSystem _biome; private readonly BiomeSystem _biome;
private readonly DungeonSystem _dungeon; private readonly DungeonSystem _dungeon;
private readonly SalvageSystem _salvage; private readonly SalvageSystem _salvage;
@@ -54,7 +52,7 @@ public sealed class SpawnSalvageMissionJob : Job<bool>
IGameTiming timing, IGameTiming timing,
IMapManager mapManager, IMapManager mapManager,
IPrototypeManager protoManager, IPrototypeManager protoManager,
ITileDefinitionManager tileDefManager, AnchorableSystem anchorable,
BiomeSystem biome, BiomeSystem biome,
DungeonSystem dungeon, DungeonSystem dungeon,
SalvageSystem salvage, SalvageSystem salvage,
@@ -66,7 +64,7 @@ public sealed class SpawnSalvageMissionJob : Job<bool>
_timing = timing; _timing = timing;
_mapManager = mapManager; _mapManager = mapManager;
_prototypeManager = protoManager; _prototypeManager = protoManager;
_tileDefManager = tileDefManager; _anchorable = anchorable;
_biome = biome; _biome = biome;
_dungeon = dungeon; _dungeon = dungeon;
_salvage = salvage; _salvage = salvage;
@@ -314,6 +312,7 @@ public sealed class SpawnSalvageMissionJob : Job<bool>
// scale affects how many groups are spawned, not the size of the groups themselves // scale affects how many groups are spawned, not the size of the groups themselves
var groupSpawns = _salvage.GetSpawnCount(mission.Difficulty) * scale; var groupSpawns = _salvage.GetSpawnCount(mission.Difficulty) * scale;
var groupSum = faction.MobGroups.Sum(o => o.Prob); var groupSum = faction.MobGroups.Sum(o => o.Prob);
var validSpawns = new List<Vector2i>();
for (var i = 0; i < groupSpawns; i++) for (var i = 0; i < groupSpawns; i++)
{ {
@@ -332,15 +331,31 @@ public sealed class SpawnSalvageMissionJob : Job<bool>
var spawnRoomIndex = random.Next(dungeon.Rooms.Count); var spawnRoomIndex = random.Next(dungeon.Rooms.Count);
var spawnRoom = dungeon.Rooms[spawnRoomIndex]; var spawnRoom = dungeon.Rooms[spawnRoomIndex];
var spawnTile = spawnRoom.Tiles.ElementAt(random.Next(spawnRoom.Tiles.Count)); validSpawns.Clear();
var spawnPosition = grid.GridTileToLocal(spawnTile); validSpawns.AddRange(spawnRoom.Tiles);
random.Shuffle(validSpawns);
foreach (var entry in EntitySpawnCollection.GetSpawns(mobGroup.Entries, random)) while (validSpawns.Count > 0)
{ {
var uid = _entManager.CreateEntityUninitialized(entry, spawnPosition); var spawnTile = validSpawns[^1];
_entManager.RemoveComponent<GhostTakeoverAvailableComponent>(uid);
_entManager.RemoveComponent<GhostRoleComponent>(uid); if (!_anchorable.TileFree(grid, spawnTile, (int) CollisionGroup.MachineLayer, (int) CollisionGroup.MachineLayer))
_entManager.InitializeAndStartEntity(uid); {
validSpawns.RemoveAt(validSpawns.Count - 1);
continue;
}
var spawnPosition = grid.GridTileToLocal(spawnTile);
foreach (var entry in EntitySpawnCollection.GetSpawns(mobGroup.Entries, random))
{
var uid = _entManager.CreateEntityUninitialized(entry, spawnPosition);
_entManager.RemoveComponent<GhostTakeoverAvailableComponent>(uid);
_entManager.RemoveComponent<GhostRoleComponent>(uid);
_entManager.InitializeAndStartEntity(uid);
}
break;
} }
await SuspendIfOutOfTime(); await SuspendIfOutOfTime();