Tile variants content (#6956)
@@ -40,13 +40,13 @@ namespace Content.IntegrationTests.Tests
|
||||
var mapGrid = mapManager.CreateGrid(mapId);
|
||||
var mapGridEnt = mapGrid.GridEntityId;
|
||||
sEntities.GetComponent<TransformComponent>(mapGridEnt).WorldPosition = new Vector2(10, 10);
|
||||
mapGrid.SetTile(new Vector2i(0,0), new Tile(1, 512));
|
||||
mapGrid.SetTile(new Vector2i(0,0), new Tile(1, (TileRenderFlag)1, 255));
|
||||
}
|
||||
{
|
||||
var mapGrid = mapManager.CreateGrid(mapId);
|
||||
var mapGridEnt = mapGrid.GridEntityId;
|
||||
sEntities.GetComponent<TransformComponent>(mapGridEnt).WorldPosition = new Vector2(-8, -8);
|
||||
mapGrid.SetTile(new Vector2i(0, 0), new Tile(2, 511));
|
||||
mapGrid.SetTile(new Vector2i(0, 0), new Tile(2, (TileRenderFlag)1, 254));
|
||||
}
|
||||
|
||||
mapLoader.SaveMap(mapId, mapPath);
|
||||
@@ -68,14 +68,14 @@ namespace Content.IntegrationTests.Tests
|
||||
|
||||
Assert.That(mapGrid.WorldPosition, Is.EqualTo(new Vector2(10, 10)));
|
||||
|
||||
Assert.That(mapGrid.GetTileRef(new Vector2i(0, 0)).Tile, Is.EqualTo(new Tile(1, 512)));
|
||||
Assert.That(mapGrid.GetTileRef(new Vector2i(0, 0)).Tile, Is.EqualTo(new Tile(1, (TileRenderFlag)1, 255)));
|
||||
}
|
||||
{
|
||||
if (!mapManager.TryFindGridAt(new MapId(10), new Vector2(-8, -8), out var mapGrid))
|
||||
Assert.Fail();
|
||||
|
||||
Assert.That(mapGrid.WorldPosition, Is.EqualTo(new Vector2(-8, -8)));
|
||||
Assert.That(mapGrid.GetTileRef(new Vector2i(0, 0)).Tile, Is.EqualTo(new Tile(2, 511)));
|
||||
Assert.That(mapGrid.GetTileRef(new Vector2i(0, 0)).Tile, Is.EqualTo(new Tile(2, (TileRenderFlag)1, 254)));
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ namespace Content.MapRenderer.Painters
|
||||
var x = (int) (tile.X + xOffset);
|
||||
var y = (int) (tile.Y + yOffset);
|
||||
var sprite = _sTileDefinitionManager[tile.Tile.TypeId].SpriteName;
|
||||
var image = images[sprite];
|
||||
var image = images[sprite][tile.Tile.Variant];
|
||||
|
||||
gridCanvas.Mutate(o => o.DrawImage(image, new Point(x * tileSize, y * tileSize), 1));
|
||||
|
||||
@@ -54,7 +54,7 @@ namespace Content.MapRenderer.Painters
|
||||
Console.WriteLine($"{nameof(TilePainter)} painted {i} tiles on grid {grid.Index} in {(int) stopwatch.Elapsed.TotalMilliseconds} ms");
|
||||
}
|
||||
|
||||
private Dictionary<string, Image> GetTileImages(
|
||||
private Dictionary<string, List<Image>> GetTileImages(
|
||||
ITileDefinitionManager tileDefinitionManager,
|
||||
IResourceCache resourceCache,
|
||||
int tileSize)
|
||||
@@ -62,11 +62,12 @@ namespace Content.MapRenderer.Painters
|
||||
var stopwatch = new Stopwatch();
|
||||
stopwatch.Start();
|
||||
|
||||
var images = new Dictionary<string, Image>();
|
||||
var images = new Dictionary<string, List<Image>>();
|
||||
|
||||
foreach (var definition in tileDefinitionManager)
|
||||
{
|
||||
var sprite = definition.SpriteName;
|
||||
images[sprite] = new List<Image>(definition.Variants);
|
||||
|
||||
if (string.IsNullOrEmpty(sprite))
|
||||
{
|
||||
@@ -74,14 +75,18 @@ namespace Content.MapRenderer.Painters
|
||||
}
|
||||
|
||||
using var stream = resourceCache.ContentFileRead($"{TilesPath}{sprite}.png");
|
||||
Image tileImage = Image.Load<Rgba32>(stream);
|
||||
Image tileSheet = Image.Load<Rgba32>(stream);
|
||||
|
||||
if (tileImage.Width != tileSize || tileImage.Height != tileSize)
|
||||
if (tileSheet.Width != tileSize * definition.Variants || tileSheet.Height != tileSize)
|
||||
{
|
||||
throw new NotSupportedException($"Unable to use tiles with a dimension other than {tileSize}x{tileSize}.");
|
||||
}
|
||||
|
||||
images[sprite] = tileImage;
|
||||
for (var i = 0; i < definition.Variants; i++)
|
||||
{
|
||||
var tileImage = tileSheet.Clone(o => o.Crop(new Rectangle(tileSize * i, 0, 32, 32)));
|
||||
images[sprite].Add(tileImage);
|
||||
}
|
||||
}
|
||||
|
||||
Console.WriteLine($"Indexed all tile images in {(int) stopwatch.Elapsed.TotalMilliseconds} ms");
|
||||
|
||||
49
Content.Server/Administration/Commands/VariantizeCommand.cs
Normal file
@@ -0,0 +1,49 @@
|
||||
using Content.Shared.Administration;
|
||||
using Content.Shared.Maps;
|
||||
using Robust.Shared.Console;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Random;
|
||||
|
||||
namespace Content.Server.Administration.Commands;
|
||||
|
||||
[AdminCommand(AdminFlags.Mapping)]
|
||||
public sealed class VariantizeCommand : IConsoleCommand
|
||||
{
|
||||
|
||||
public string Command => "variantize";
|
||||
|
||||
public string Description => Loc.GetString("variantize-command-description");
|
||||
|
||||
public string Help => Loc.GetString("variantize-command-help-text");
|
||||
|
||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
if (args.Length != 1)
|
||||
{
|
||||
shell.WriteError(Loc.GetString("shell-wrong-arguments-number"));
|
||||
return;
|
||||
}
|
||||
|
||||
var mapManager = IoCManager.Resolve<IMapManager>();
|
||||
var random = IoCManager.Resolve<IRobustRandom>();
|
||||
|
||||
if (!int.TryParse(args[0], out var targetId))
|
||||
{
|
||||
shell.WriteError(Loc.GetString("shell-argument-must-be-number"));
|
||||
return;
|
||||
}
|
||||
|
||||
var gridId = new GridId(targetId);
|
||||
if (!mapManager.TryGetGrid(gridId, out var grid))
|
||||
{
|
||||
shell.WriteError(Loc.GetString("shell-invalid-grid-id"));
|
||||
return;
|
||||
}
|
||||
foreach (var tile in grid.GetAllTiles())
|
||||
{
|
||||
var def = tile.GetContentTileDefinition();
|
||||
var newTile = new Tile(tile.Tile.TypeId, tile.Tile.Flags, random.Pick(def.PlacementVariants));
|
||||
grid.SetTile(tile.GridIndices, newTile);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,7 @@ using Robust.Shared.IoC;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Random;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List;
|
||||
|
||||
@@ -23,6 +24,7 @@ namespace Content.Server.Tiles
|
||||
{
|
||||
[Dependency] private readonly IEntityManager _entMan = default!;
|
||||
[Dependency] private readonly ITileDefinitionManager _tileDefinitionManager = default!;
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
|
||||
[DataField("outputs", customTypeSerializer: typeof(PrototypeIdListSerializer<ContentTileDefinition>))]
|
||||
private List<string>? _outputTiles;
|
||||
@@ -50,7 +52,8 @@ namespace Content.Server.Tiles
|
||||
|
||||
private void PlaceAt(IMapGrid mapGrid, EntityCoordinates location, ushort tileId, float offset = 0)
|
||||
{
|
||||
mapGrid.SetTile(location.Offset(new Vector2(offset, offset)), new Tile(tileId));
|
||||
var variant = _random.Pick(((ContentTileDefinition) _tileDefinitionManager[tileId]).PlacementVariants);
|
||||
mapGrid.SetTile(location.Offset(new Vector2(offset, offset)), new Tile(tileId, 0, variant));
|
||||
SoundSystem.Play(Filter.Pvs(location), _placeTileSound.GetSound(), location, AudioHelpers.WithVariation(0.125f));
|
||||
}
|
||||
|
||||
|
||||
@@ -40,6 +40,13 @@ namespace Content.Shared.Maps
|
||||
|
||||
[DataField("friction")] public float Friction { get; set; }
|
||||
|
||||
[DataField("variants")] public byte Variants { get; set; } = 1;
|
||||
|
||||
/// <summary>
|
||||
/// This controls what variants the `variantize` command is allowed to use.
|
||||
/// </summary>
|
||||
[DataField("placementVariants")] public byte[] PlacementVariants { get; set; } = new byte[1] { 0 };
|
||||
|
||||
[DataField("thermalConductivity")] public float ThermalConductivity { get; set; } = 0.05f;
|
||||
|
||||
// Heat capacity is opt-in, not opt-out.
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
variantize-command-description = Randomizes all tile variants on a given grid.
|
||||
variantize-command-help-text = variantize <grid id>
|
||||
@@ -21,6 +21,7 @@ shell-need-between-arguments = Need {$lower} to {$upper} arguments!
|
||||
|
||||
shell-entity-is-not-mob = Target entity is not a mob!
|
||||
shell-invalid-entity-id = Invalid entity ID.
|
||||
shell-invalid-grid-id = Invalid grid ID.
|
||||
shell-invalid-entity-uid = {$uid} is not a valid entity uid
|
||||
shell-entity-uid-must-be-number = EntityUid must be a number.
|
||||
shell-could-not-find-entity = Could not find entity {$entity}
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
id: floor_steel
|
||||
name: steel floor
|
||||
texture: "steel"
|
||||
variants: 4
|
||||
placementVariants: [0, 1, 2, 3]
|
||||
base_turfs:
|
||||
- plating
|
||||
is_subfloor: false
|
||||
@@ -17,6 +19,8 @@
|
||||
id: floor_wood
|
||||
name: wood
|
||||
texture: "wood"
|
||||
variants: 4
|
||||
placementVariants: [0, 1, 2, 3]
|
||||
base_turfs:
|
||||
- plating
|
||||
is_subfloor: false
|
||||
@@ -32,6 +36,8 @@
|
||||
id: floor_white
|
||||
name: white floor
|
||||
texture: "white"
|
||||
variants: 4
|
||||
placementVariants: [0, 1, 2, 3]
|
||||
base_turfs:
|
||||
- plating
|
||||
is_subfloor: false
|
||||
@@ -47,6 +53,8 @@
|
||||
id: floor_dark
|
||||
name: dark floor
|
||||
texture: "dark"
|
||||
variants: 4
|
||||
placementVariants: [ 0, 1, 2, 3 ]
|
||||
base_turfs:
|
||||
- plating
|
||||
is_subfloor: false
|
||||
@@ -228,6 +236,8 @@
|
||||
id: floor_bar
|
||||
name: bar floor
|
||||
texture: "bar"
|
||||
variants: 4
|
||||
placementVariants: [ 0, 1, 2, 3 ]
|
||||
base_turfs:
|
||||
- plating
|
||||
is_subfloor: false
|
||||
@@ -591,8 +601,10 @@
|
||||
|
||||
- type: tile
|
||||
id: floor_asteroid_coarse_sand0
|
||||
name: asteroid coarse sand 0
|
||||
texture: Asteroid/asteroid_coarse_sand0
|
||||
name: asteroid coarse sand
|
||||
texture: Asteroid/asteroid_coarse_sand
|
||||
variants: 3
|
||||
placementVariants: [ 0, 1, 2 ]
|
||||
base_turfs:
|
||||
- space
|
||||
is_subfloor: false
|
||||
@@ -605,8 +617,10 @@
|
||||
|
||||
- type: tile
|
||||
id: floor_asteroid_coarse_sand1
|
||||
name: asteroid coarse sand 1
|
||||
texture: Asteroid/asteroid_coarse_sand1
|
||||
name: asteroid coarse sand [DO NOT USE]
|
||||
texture: Asteroid/asteroid_coarse_sand
|
||||
variants: 3
|
||||
placementVariants: [ 0, 1, 2 ]
|
||||
base_turfs:
|
||||
- space
|
||||
is_subfloor: false
|
||||
@@ -619,8 +633,10 @@
|
||||
|
||||
- type: tile
|
||||
id: floor_asteroid_coarse_sand2
|
||||
name: asteroid coarse sand 2
|
||||
texture: Asteroid/asteroid_coarse_sand2
|
||||
name: asteroid coarse sand [DO NOT USE]
|
||||
texture: Asteroid/asteroid_coarse_sand
|
||||
variants: 3
|
||||
placementVariants: [ 0, 1, 2 ]
|
||||
base_turfs:
|
||||
- space
|
||||
is_subfloor: false
|
||||
|
||||
BIN
Resources/Textures/Tiles/Asteroid/asteroid_coarse_sand.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 221 B |
|
Before Width: | Height: | Size: 229 B |
|
Before Width: | Height: | Size: 228 B |
|
Before Width: | Height: | Size: 4.6 KiB After Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 615 B After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 824 B After Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 495 B After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 573 B After Width: | Height: | Size: 1.4 KiB |