BlobFloorPlanBuilderSystem.cs 3.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. using System.Linq;
  2. using Content.Server.Worldgen.Components.Debris;
  3. using Content.Shared.Maps;
  4. using Robust.Shared.Map;
  5. using Robust.Shared.Map.Components;
  6. using Robust.Shared.Random;
  7. namespace Content.Server.Worldgen.Systems.Debris;
  8. /// <summary>
  9. /// This handles building the floor plans for "blobby" debris.
  10. /// </summary>
  11. public sealed class BlobFloorPlanBuilderSystem : BaseWorldSystem
  12. {
  13. [Dependency] private readonly IRobustRandom _random = default!;
  14. [Dependency] private readonly ITileDefinitionManager _tileDefinition = default!;
  15. [Dependency] private readonly TileSystem _tiles = default!;
  16. [Dependency] private readonly SharedMapSystem _map = default!;
  17. /// <inheritdoc />
  18. public override void Initialize()
  19. {
  20. SubscribeLocalEvent<BlobFloorPlanBuilderComponent, ComponentStartup>(OnBlobFloorPlanBuilderStartup);
  21. }
  22. private void OnBlobFloorPlanBuilderStartup(EntityUid uid, BlobFloorPlanBuilderComponent component,
  23. ComponentStartup args)
  24. {
  25. PlaceFloorplanTiles(uid, component, Comp<MapGridComponent>(uid));
  26. }
  27. private void PlaceFloorplanTiles(EntityUid gridUid, BlobFloorPlanBuilderComponent comp, MapGridComponent grid)
  28. {
  29. // NO MORE THAN TWO ALLOCATIONS THANK YOU VERY MUCH.
  30. // TODO: Just put these on a field instead then?
  31. // Also the end of the method has a big LINQ which is gonna blow this out the water.
  32. var spawnPoints = new HashSet<Vector2i>(comp.FloorPlacements * 6);
  33. var taken = new Dictionary<Vector2i, Tile>(comp.FloorPlacements * 5);
  34. void PlaceTile(Vector2i point)
  35. {
  36. // Assume we already know that the spawn point is safe.
  37. spawnPoints.Remove(point);
  38. var north = point.Offset(Direction.North);
  39. var south = point.Offset(Direction.South);
  40. var east = point.Offset(Direction.East);
  41. var west = point.Offset(Direction.West);
  42. var radsq = Math.Pow(comp.Radius,
  43. 2); // I'd put this outside but i'm not 100% certain caching it between calls is a gain.
  44. // The math done is essentially a fancy way of comparing the distance from 0,0 to the radius,
  45. // and skipping the sqrt normally needed for dist.
  46. if (!taken.ContainsKey(north) && Math.Pow(north.X, 2) + Math.Pow(north.Y, 2) <= radsq)
  47. spawnPoints.Add(north);
  48. if (!taken.ContainsKey(south) && Math.Pow(south.X, 2) + Math.Pow(south.Y, 2) <= radsq)
  49. spawnPoints.Add(south);
  50. if (!taken.ContainsKey(east) && Math.Pow(east.X, 2) + Math.Pow(east.Y, 2) <= radsq)
  51. spawnPoints.Add(east);
  52. if (!taken.ContainsKey(west) && Math.Pow(west.X, 2) + Math.Pow(west.Y, 2) <= radsq)
  53. spawnPoints.Add(west);
  54. var tileDef = _tileDefinition[_random.Pick(comp.FloorTileset)];
  55. taken.Add(point, new Tile(tileDef.TileId, 0, _tiles.PickVariant((ContentTileDefinition) tileDef)));
  56. }
  57. PlaceTile(Vector2i.Zero);
  58. for (var i = 0; i < comp.FloorPlacements; i++)
  59. {
  60. var point = _random.Pick(spawnPoints);
  61. PlaceTile(point);
  62. if (comp.BlobDrawProb > 0.0f)
  63. {
  64. if (!taken.ContainsKey(point.Offset(Direction.North)) && _random.Prob(comp.BlobDrawProb))
  65. PlaceTile(point.Offset(Direction.North));
  66. if (!taken.ContainsKey(point.Offset(Direction.South)) && _random.Prob(comp.BlobDrawProb))
  67. PlaceTile(point.Offset(Direction.South));
  68. if (!taken.ContainsKey(point.Offset(Direction.East)) && _random.Prob(comp.BlobDrawProb))
  69. PlaceTile(point.Offset(Direction.East));
  70. if (!taken.ContainsKey(point.Offset(Direction.West)) && _random.Prob(comp.BlobDrawProb))
  71. PlaceTile(point.Offset(Direction.West));
  72. }
  73. }
  74. _map.SetTiles(gridUid, grid, taken.Select(x => (x.Key, x.Value)).ToList());
  75. }
  76. }