add endpoint for requesting map data

This commit is contained in:
Vinzenz Schroeter 2024-05-05 13:51:28 +02:00
parent 079b096c16
commit 5f5e9fb716
8 changed files with 97 additions and 32 deletions

View file

@ -0,0 +1,8 @@
namespace TanksServer.GameLogic;
internal abstract class MapPrototype
{
public abstract string Name { get; }
public abstract Map CreateInstance();
}

View file

@ -1,14 +1,10 @@
using System.Diagnostics.CodeAnalysis;
using System.IO;
using DisplayCommands;
using TanksServer.Graphics;
namespace TanksServer.GameLogic;
internal abstract class MapPrototype
{
public abstract Map CreateInstance();
}
internal sealed class MapService
{
public const ushort TilesPerRow = 44;
@ -17,9 +13,10 @@ internal sealed class MapService
public const ushort PixelsPerRow = TilesPerRow * TileSize;
public const ushort PixelsPerColumn = TilesPerColumn * TileSize;
private readonly Dictionary<string, MapPrototype> _maps = new();
private readonly Dictionary<string, MapPrototype> _mapPrototypes = new();
private readonly Dictionary<string, PixelGrid> _mapPreviews = new();
public IEnumerable<string> MapNames => _maps.Keys;
public IEnumerable<string> MapNames => _mapPrototypes.Keys;
public Map Current { get; private set; }
@ -29,29 +26,49 @@ internal sealed class MapService
LoadMapString(file);
foreach (var file in Directory.EnumerateFiles("./assets/maps/", "*.png"))
LoadMapPng(file);
var chosenMapIndex = Random.Shared.Next(_maps.Count);
var chosenMapName = _maps.Keys.Skip(chosenMapIndex).First();
Current = _maps[chosenMapName].CreateInstance();
Current = GetRandomMap();
}
public bool TryGetMapByName(string name, [MaybeNullWhen(false)] out MapPrototype map)
=> _maps.TryGetValue(name, out map);
public bool TryGetPrototype(string name, [MaybeNullWhen(false)] out MapPrototype map)
=> _mapPrototypes.TryGetValue(name, out map);
public void SwitchTo(MapPrototype prototype) => Current = prototype.CreateInstance();
public bool TryGetPreview(string name, [MaybeNullWhen(false)] out PixelGrid pixelGrid)
{
if (_mapPreviews.TryGetValue(name, out pixelGrid))
return true; // already generated
if (!_mapPrototypes.TryGetValue(name, out var prototype))
return false; // name not found
pixelGrid = new PixelGrid(PixelsPerRow, PixelsPerColumn);
DrawMapStep.Draw(pixelGrid, prototype.CreateInstance());
_mapPreviews.TryAdd(name, pixelGrid); // another thread may have added the map already
return true; // new preview
}
private void LoadMapPng(string file)
{
var name = Path.GetFileName(file);
var name = MapNameFromFilePath(file);
var prototype = new SpriteMapPrototype(name, Sprite.FromImageFile(file));
_maps.Add(Path.GetFileName(file), prototype);
_mapPrototypes.Add(name, prototype);
}
private void LoadMapString(string file)
{
var name = MapNameFromFilePath(file);
var map = File.ReadAllText(file).ReplaceLineEndings(string.Empty).Trim();
var name = Path.GetFileName(file);
var prototype = new TextMapPrototype(name, map);
_maps.Add(name, prototype);
_mapPrototypes.Add(name, prototype);
}
private static string MapNameFromFilePath(string filePath) => Path.GetFileName(filePath).ToUpperInvariant();
private Map GetRandomMap()
{
var chosenMapIndex = Random.Shared.Next(_mapPrototypes.Count);
var chosenMapName = _mapPrototypes.Keys.Skip(chosenMapIndex).First();
return _mapPrototypes[chosenMapName].CreateInstance();
}
}

View file

@ -5,17 +5,18 @@ namespace TanksServer.GameLogic;
internal sealed class SpriteMapPrototype : MapPrototype
{
private readonly string _name;
private readonly Sprite _sprite;
public override string Name { get; }
public Sprite Sprite { get; }
public SpriteMapPrototype(string name, Sprite sprite)
{
if (sprite.Width != MapService.PixelsPerRow || sprite.Height != MapService.PixelsPerColumn)
throw new FileLoadException($"invalid image size in file {_name}");
throw new FileLoadException($"invalid image size in file {Name}");
_name = name;
_sprite = sprite;
Name = name;
Sprite = sprite;
}
public override Map CreateInstance() => new(_name, _sprite.ToBoolArray());
public override Map CreateInstance() => new(Name, Sprite.ToBoolArray());
}

View file

@ -2,17 +2,19 @@ namespace TanksServer.GameLogic;
internal sealed class TextMapPrototype : MapPrototype
{
private readonly string _name;
private readonly string _text;
public override string Name { get; }
public string Text { get; }
public TextMapPrototype(string name, string text)
{
if (text.Length != MapService.TilesPerColumn * MapService.TilesPerRow)
throw new ArgumentException($"cannot load map {name}: invalid length");
_name = name;
_text = text;
Name = name;
Text = text;
}
public override Map CreateInstance()
{
var walls = new bool[MapService.PixelsPerRow, MapService.PixelsPerColumn];
@ -21,7 +23,7 @@ internal sealed class TextMapPrototype : MapPrototype
for (ushort tileY = 0; tileY < MapService.TilesPerColumn; tileY++)
{
var tile = new TilePosition(tileX, tileY);
if (_text[tileX + tileY * MapService.TilesPerRow] != '#')
if (Text[tileX + tileY * MapService.TilesPerRow] != '#')
continue;
for (byte pixelInTileX = 0; pixelInTileX < MapService.TileSize; pixelInTileX++)
@ -32,6 +34,6 @@ internal sealed class TextMapPrototype : MapPrototype
}
}
return new Map(_name, walls);
return new Map(Name, walls);
}
}