TileSystem.cs 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. using System.Linq;
  2. using System.Numerics;
  3. using Content.Shared.Coordinates.Helpers;
  4. using Content.Shared.Decals;
  5. using Robust.Shared.Map;
  6. using Robust.Shared.Map.Components;
  7. using Robust.Shared.Random;
  8. using Robust.Shared.Utility;
  9. namespace Content.Shared.Maps;
  10. /// <summary>
  11. /// Handles server-side tile manipulation like prying/deconstructing tiles.
  12. /// </summary>
  13. public sealed class TileSystem : EntitySystem
  14. {
  15. [Dependency] private readonly IMapManager _mapManager = default!;
  16. [Dependency] private readonly IRobustRandom _robustRandom = default!;
  17. [Dependency] private readonly ITileDefinitionManager _tileDefinitionManager = default!;
  18. [Dependency] private readonly SharedDecalSystem _decal = default!;
  19. [Dependency] private readonly SharedMapSystem _maps = default!;
  20. [Dependency] private readonly TurfSystem _turf = default!;
  21. /// <summary>
  22. /// Returns a weighted pick of a tile variant.
  23. /// </summary>
  24. public byte PickVariant(ContentTileDefinition tile)
  25. {
  26. return PickVariant(tile, _robustRandom.GetRandom());
  27. }
  28. /// <summary>
  29. /// Returns a weighted pick of a tile variant.
  30. /// </summary>
  31. public byte PickVariant(ContentTileDefinition tile, int seed)
  32. {
  33. var rand = new System.Random(seed);
  34. return PickVariant(tile, rand);
  35. }
  36. /// <summary>
  37. /// Returns a weighted pick of a tile variant.
  38. /// </summary>
  39. public byte PickVariant(ContentTileDefinition tile, System.Random random)
  40. {
  41. var variants = tile.PlacementVariants;
  42. var sum = variants.Sum();
  43. var accumulated = 0f;
  44. var rand = random.NextFloat() * sum;
  45. for (byte i = 0; i < variants.Length; ++i)
  46. {
  47. accumulated += variants[i];
  48. if (accumulated >= rand)
  49. return i;
  50. }
  51. // Shouldn't happen
  52. throw new InvalidOperationException($"Invalid weighted variantize tile pick for {tile.ID}!");
  53. }
  54. /// <summary>
  55. /// Returns a tile with a weighted random variant.
  56. /// </summary>
  57. public Tile GetVariantTile(ContentTileDefinition tile, System.Random random)
  58. {
  59. return new Tile(tile.TileId, variant: PickVariant(tile, random));
  60. }
  61. /// <summary>
  62. /// Returns a tile with a weighted random variant.
  63. /// </summary>
  64. public Tile GetVariantTile(ContentTileDefinition tile, int seed)
  65. {
  66. var rand = new System.Random(seed);
  67. return new Tile(tile.TileId, variant: PickVariant(tile, rand));
  68. }
  69. public bool PryTile(Vector2i indices, EntityUid gridId)
  70. {
  71. var grid = Comp<MapGridComponent>(gridId);
  72. var tileRef = _maps.GetTileRef(gridId, grid, indices);
  73. return PryTile(tileRef);
  74. }
  75. public bool PryTile(TileRef tileRef)
  76. {
  77. return PryTile(tileRef, false);
  78. }
  79. public bool PryTile(TileRef tileRef, bool pryPlating)
  80. {
  81. var tile = tileRef.Tile;
  82. if (tile.IsEmpty)
  83. return false;
  84. var tileDef = (ContentTileDefinition) _tileDefinitionManager[tile.TypeId];
  85. if (!tileDef.CanCrowbar)
  86. return false;
  87. return DeconstructTile(tileRef);
  88. }
  89. public bool ReplaceTile(TileRef tileref, ContentTileDefinition replacementTile)
  90. {
  91. if (!TryComp<MapGridComponent>(tileref.GridUid, out var grid))
  92. return false;
  93. return ReplaceTile(tileref, replacementTile, tileref.GridUid, grid);
  94. }
  95. public bool ReplaceTile(TileRef tileref, ContentTileDefinition replacementTile, EntityUid grid, MapGridComponent? component = null)
  96. {
  97. DebugTools.Assert(tileref.GridUid == grid);
  98. if (!Resolve(grid, ref component))
  99. return false;
  100. var variant = PickVariant(replacementTile);
  101. var decals = _decal.GetDecalsInRange(tileref.GridUid, _turf.GetTileCenter(tileref).Position, 0.5f);
  102. foreach (var (id, _) in decals)
  103. {
  104. _decal.RemoveDecal(tileref.GridUid, id);
  105. }
  106. _maps.SetTile(grid, component, tileref.GridIndices, new Tile(replacementTile.TileId, 0, variant));
  107. return true;
  108. }
  109. public bool DeconstructTile(TileRef tileRef)
  110. {
  111. if (tileRef.Tile.IsEmpty)
  112. return false;
  113. var tileDef = (ContentTileDefinition) _tileDefinitionManager[tileRef.Tile.TypeId];
  114. if (string.IsNullOrEmpty(tileDef.BaseTurf))
  115. return false;
  116. var gridUid = tileRef.GridUid;
  117. var mapGrid = Comp<MapGridComponent>(gridUid);
  118. const float margin = 0.1f;
  119. var bounds = mapGrid.TileSize - margin * 2;
  120. var indices = tileRef.GridIndices;
  121. var coordinates = _maps.GridTileToLocal(gridUid, mapGrid, indices)
  122. .Offset(new Vector2(
  123. (_robustRandom.NextFloat() - 0.5f) * bounds,
  124. (_robustRandom.NextFloat() - 0.5f) * bounds));
  125. //Actually spawn the relevant tile item at the right position and give it some random offset.
  126. var tileItem = Spawn(tileDef.ItemDropPrototypeName, coordinates);
  127. Transform(tileItem).LocalRotation = _robustRandom.NextDouble() * Math.Tau;
  128. // Destroy any decals on the tile
  129. var decals = _decal.GetDecalsInRange(gridUid, coordinates.SnapToGrid(EntityManager, _mapManager).Position, 0.5f);
  130. foreach (var (id, _) in decals)
  131. {
  132. _decal.RemoveDecal(tileRef.GridUid, id);
  133. }
  134. var plating = _tileDefinitionManager[tileDef.BaseTurf];
  135. _maps.SetTile(gridUid, mapGrid, tileRef.GridIndices, new Tile(plating.TileId));
  136. return true;
  137. }
  138. }