diff --git a/OpenRA.Editor/BrushTool.cs b/OpenRA.Editor/BrushTool.cs index 8ed2f609c3..e33b60cc76 100644 --- a/OpenRA.Editor/BrushTool.cs +++ b/OpenRA.Editor/BrushTool.cs @@ -37,16 +37,15 @@ namespace OpenRA.Editor for (var u = 0; u < template.Size.X; u++) for (var v = 0; v < template.Size.Y; v++) { - if (surface.Map.IsInMap(new CVec(u, v) + pos)) + var cell = pos + new CVec(u, v); + if (surface.Map.IsInMap(cell)) { var z = u + v * template.Size.X; if (tile[z].Length > 0) - surface.Map.MapTiles.Value[u + pos.X, v + pos.Y] = - new TileReference - { - Type = brushTemplate.N, - Index = template.PickAny ? (byte)((u + pos.X) % 4 + ((v + pos.Y) % 4) * 4) : (byte)z, - }; + { + var index = template.PickAny ? (byte)((u + pos.X) % 4 + ((v + pos.Y) % 4) * 4) : (byte)z; + surface.Map.MapTiles.Value[cell] = new TerrainTile(brushTemplate.N, index); + } var ch = new int2((pos.X + u) / Surface.ChunkSize, (pos.Y + v) / Surface.ChunkSize); if (surface.Chunks.ContainsKey(ch)) @@ -70,7 +69,7 @@ namespace OpenRA.Editor void FloodFillWithBrush(Surface s, CPos pos) { var queue = new Queue(); - var replace = s.Map.MapTiles.Value[pos.X, pos.Y]; + var replace = s.Map.MapTiles.Value[pos]; var touched = new bool[s.Map.MapSize.X, s.Map.MapSize.Y]; Action maybeEnqueue = (x, y) => @@ -87,7 +86,7 @@ namespace OpenRA.Editor while (queue.Count > 0) { var p = queue.Dequeue(); - if (s.Map.MapTiles.Value[p.X, p.Y].Type != replace.Type) + if (s.Map.MapTiles.Value[p].Type != replace.Type) continue; var a = FindEdge(s, p, new CVec(-1, 0), replace); @@ -95,10 +94,10 @@ namespace OpenRA.Editor for (var x = a.X; x <= b.X; x++) { - s.Map.MapTiles.Value[x, p.Y] = new TileReference { Type = brushTemplate.N, Index = (byte)0 }; - if (s.Map.MapTiles.Value[x, p.Y - 1].Type == replace.Type) + s.Map.MapTiles.Value[new CPos(x, p.Y)] = new TerrainTile(brushTemplate.N, (byte)0); + if (s.Map.MapTiles.Value[new CPos(x, p.Y - 1)].Type == replace.Type) maybeEnqueue(x, p.Y - 1); - if (s.Map.MapTiles.Value[x, p.Y + 1].Type == replace.Type) + if (s.Map.MapTiles.Value[new CPos(x, p.Y + 1)].Type == replace.Type) maybeEnqueue(x, p.Y + 1); } } @@ -108,13 +107,13 @@ namespace OpenRA.Editor s.Chunks.Clear(); } - static CPos FindEdge(Surface s, CPos p, CVec d, TileReference replace) + static CPos FindEdge(Surface s, CPos p, CVec d, TerrainTile replace) { for (;;) { var q = p + d; if (!s.Map.IsInMap(q)) return p; - if (s.Map.MapTiles.Value[q.X, q.Y].Type != replace.Type) return p; + if (s.Map.MapTiles.Value[q].Type != replace.Type) return p; p = q; } } diff --git a/OpenRA.Editor/Surface.cs b/OpenRA.Editor/Surface.cs index 6bcb4c6844..16fcb1f678 100644 --- a/OpenRA.Editor/Surface.cs +++ b/OpenRA.Editor/Surface.cs @@ -62,7 +62,7 @@ namespace OpenRA.Editor public bool ShowRuler; public bool IsPaste { get { return TileSelection != null && ResourceSelection != null; } } - public TileReference[,] TileSelection; + public TerrainTile[,] TileSelection; public ResourceTile[,] ResourceSelection; public CPos SelectionStart; public CPos SelectionEnd; @@ -272,7 +272,7 @@ namespace OpenRA.Editor for (var j = 0; j < ChunkSize; j++) { var cell = new CPos(u * ChunkSize + i, v * ChunkSize + j); - var tr = Map.MapTiles.Value[u * ChunkSize + i, v * ChunkSize + j]; + var tr = Map.MapTiles.Value[cell]; var tile = TileSetRenderer.Data(tr.Type); var index = (tr.Index < tile.Count) ? tr.Index : (byte)0; var rawImage = tile[index]; @@ -509,7 +509,7 @@ namespace OpenRA.Editor var width = Math.Abs((start - end).X); var height = Math.Abs((start - end).Y); - TileSelection = new TileReference[width, height]; + TileSelection = new TerrainTile[width, height]; ResourceSelection = new ResourceTile[width, height]; for (var x = 0; x < width; x++) @@ -518,7 +518,7 @@ namespace OpenRA.Editor { // TODO: crash prevention var cell = new CPos(start.X + x, start.Y + y); - TileSelection[x, y] = Map.MapTiles.Value[start.X + x, start.Y + y]; + TileSelection[x, y] = Map.MapTiles.Value[cell]; ResourceSelection[x, y] = Map.MapResources.Value[cell]; } } @@ -539,7 +539,7 @@ namespace OpenRA.Editor var cell = new CPos(mapX, mapY); // TODO: crash prevention for outside of bounds - Map.MapTiles.Value[mapX, mapY] = TileSelection[x, y]; + Map.MapTiles.Value[cell] = TileSelection[x, y]; Map.MapResources.Value[cell] = ResourceSelection[x, y]; var ch = new int2(mapX / ChunkSize, mapY / ChunkSize); diff --git a/OpenRA.Game/Graphics/TerrainRenderer.cs b/OpenRA.Game/Graphics/TerrainRenderer.cs index f8562ed359..7d55487720 100644 --- a/OpenRA.Game/Graphics/TerrainRenderer.cs +++ b/OpenRA.Game/Graphics/TerrainRenderer.cs @@ -28,15 +28,12 @@ namespace OpenRA.Graphics var vertices = new Vertex[4 * map.Bounds.Height * map.Bounds.Width]; var nv = 0; - for (var j = map.Bounds.Top; j < map.Bounds.Bottom; j++) + foreach (var cell in map.Cells) { - for (var i = map.Bounds.Left; i < map.Bounds.Right; i++) - { - var tile = wr.Theater.TileSprite(map.MapTiles.Value[i, j]); - var pos = wr.ScreenPosition(new CPos(i, j).CenterPosition) - 0.5f * tile.size; - Util.FastCreateQuad(vertices, pos, tile, terrainPalette, nv, tile.size); - nv += 4; - } + var tile = wr.Theater.TileSprite(map.MapTiles.Value[cell]); + var pos = wr.ScreenPosition(cell.CenterPosition) - 0.5f * tile.size; + Util.FastCreateQuad(vertices, pos, tile, terrainPalette, nv, tile.size); + nv += 4; } vertexBuffer = Game.Renderer.Device.CreateVertexBuffer(vertices.Length); diff --git a/OpenRA.Game/Graphics/Theater.cs b/OpenRA.Game/Graphics/Theater.cs index c7b136b5ed..141e3ddd02 100644 --- a/OpenRA.Game/Graphics/Theater.cs +++ b/OpenRA.Game/Graphics/Theater.cs @@ -71,7 +71,7 @@ namespace OpenRA.Graphics missingTile = sheetBuilder.Add(new byte[1], new Size(1, 1)); } - public Sprite TileSprite(TileReference r) + public Sprite TileSprite(TerrainTile r) { Sprite[] template; if (!templates.TryGetValue(r.Type, out template)) diff --git a/OpenRA.Game/Map/Map.cs b/OpenRA.Game/Map/Map.cs index 489f42ecbf..c49b4c3733 100644 --- a/OpenRA.Game/Map/Map.cs +++ b/OpenRA.Game/Map/Map.cs @@ -111,7 +111,7 @@ namespace OpenRA [FieldLoader.Ignore] public byte TileFormat = 1; public int2 MapSize; - [FieldLoader.Ignore] public Lazy[,]> MapTiles; + [FieldLoader.Ignore] public Lazy> MapTiles; [FieldLoader.Ignore] public Lazy> MapResources; [FieldLoader.Ignore] public CellLayer CustomTerrain; @@ -123,10 +123,16 @@ namespace OpenRA public static Map FromTileset(TileSet tileset) { - var tile = tileset.Templates.First(); - var tileRef = new TileReference { Type = tile.Key, Index = (byte)0 }; - var size = new Size(1, 1); + var tileRef = new TerrainTile(tileset.Templates.First().Key, (byte)0); + + var makeMapTiles = Exts.Lazy(() => + { + var ret = new CellLayer(size); + ret.Clear(tileRef); + return ret; + }); + var map = new Map() { Title = "Name your map here", @@ -136,7 +142,7 @@ namespace OpenRA Tileset = tileset.Id, Options = new MapOptions(), MapResources = Exts.Lazy(() => new CellLayer(size)), - MapTiles = Exts.Lazy(() => new TileReference[1, 1] { { tileRef } }), + MapTiles = makeMapTiles, Actors = Exts.Lazy(() => new Dictionary()), Smudges = Exts.Lazy(() => new List()) }; @@ -353,9 +359,9 @@ namespace OpenRA Container.Write(entries); } - public TileReference[,] LoadMapTiles() + public CellLayer LoadMapTiles() { - var tiles = new TileReference[MapSize.X, MapSize.Y]; + var tiles = new CellLayer(this); using (var dataStream = Container.GetContent("map.bin")) { if (dataStream.ReadUInt8() != 1) @@ -372,15 +378,19 @@ namespace OpenRA var data = dataStream.ReadBytes(MapSize.X * MapSize.Y * 3); var d = 0; for (var i = 0; i < MapSize.X; i++) + { for (var j = 0; j < MapSize.Y; j++) { var tile = BitConverter.ToUInt16(data, d); d += 2; + var index = data[d++]; if (index == byte.MaxValue) index = (byte)(i % 4 + (j % 4) * 4); - tiles[i, j] = new TileReference(tile, index); + + tiles[i, j] = new TerrainTile(tile, index); } + } } return tiles; @@ -431,8 +441,9 @@ namespace OpenRA for (var i = 0; i < MapSize.X; i++) for (var j = 0; j < MapSize.Y; j++) { - writer.Write(MapTiles.Value[i, j].Type); - writer.Write(MapTiles.Value[i, j].Index); + var tile = MapTiles.Value[new CPos(i, j)]; + writer.Write(tile.Type); + writer.Write(tile.Index); } // Resource data @@ -459,7 +470,7 @@ namespace OpenRA var oldMapResources = MapResources.Value; var newSize = new Size(width, height); - MapTiles = Exts.Lazy(() => Exts.ResizeArray(oldMapTiles, oldMapTiles[0, 0], width, height)); + MapTiles = Exts.Lazy(() => CellLayer.Resize(oldMapTiles, newSize, oldMapTiles[0, 0])); MapResources = Exts.Lazy(() => CellLayer.Resize(oldMapResources, newSize, oldMapResources[0, 0])); MapSize = new int2(newSize); } @@ -537,17 +548,21 @@ namespace OpenRA { for (var i = Bounds.Left; i < Bounds.Right; i++) { - var tr = MapTiles.Value[i, j]; - if (!tileset.Templates.ContainsKey(tr.Type)) + var cell = new CPos(i, j); + var type = MapTiles.Value[cell].Type; + var index = MapTiles.Value[cell].Index; + if (!tileset.Templates.ContainsKey(type)) { - Console.WriteLine("Unknown Tile ID {0}".F(tr.Type)); + Console.WriteLine("Unknown Tile ID {0}".F(type)); continue; } - var template = tileset.Templates[tr.Type]; + + var template = tileset.Templates[type]; if (!template.PickAny) continue; - tr.Index = (byte)r.Next(0, template.TilesCount); - MapTiles.Value[i, j] = tr; + + index = (byte)r.Next(0, template.TilesCount); + MapTiles.Value[cell] = new TerrainTile(type, index); } } } @@ -556,7 +571,7 @@ namespace OpenRA { var custom = CustomTerrain[cell]; var tileSet = Rules.TileSets[Tileset]; - return custom != -1 ? custom : tileSet.GetTerrainIndex(MapTiles.Value[cell.X, cell.Y]); + return custom != -1 ? custom : tileSet.GetTerrainIndex(MapTiles.Value[cell]); } public TerrainTypeInfo GetTerrainInfo(CPos cell) diff --git a/OpenRA.Game/Map/TileReference.cs b/OpenRA.Game/Map/TileReference.cs index 187a80c3b9..1d835888a5 100644 --- a/OpenRA.Game/Map/TileReference.cs +++ b/OpenRA.Game/Map/TileReference.cs @@ -10,15 +10,15 @@ namespace OpenRA { - public struct TileReference + public struct TerrainTile { - public T Type; - public U Index; + public readonly ushort Type; + public readonly byte Index; - public TileReference(T t, U i) + public TerrainTile(ushort type, byte index) { - Type = t; - Index = i; + Type = type; + Index = index; } public override int GetHashCode() { return Type.GetHashCode() ^ Index.GetHashCode(); } diff --git a/OpenRA.Game/Map/TileSet.cs b/OpenRA.Game/Map/TileSet.cs index 1397cd5eea..1afa545d16 100644 --- a/OpenRA.Game/Map/TileSet.cs +++ b/OpenRA.Game/Map/TileSet.cs @@ -223,7 +223,7 @@ namespace OpenRA throw new InvalidDataException("Tileset '{0}' lacks terrain type '{1}'".F(Id, type)); } - public int GetTerrainIndex(TileReference r) + public int GetTerrainIndex(TerrainTile r) { var tpl = Templates[r.Type]; @@ -261,7 +261,7 @@ namespace OpenRA root.WriteToFile(filepath); } - public TerrainTypeInfo GetTerrainInfo(TileReference r) + public TerrainTypeInfo GetTerrainInfo(TerrainTile r) { return terrainInfo[GetTerrainIndex(r)]; } diff --git a/OpenRA.Mods.RA/Bridge.cs b/OpenRA.Mods.RA/Bridge.cs index fc87dc4927..6fa095944c 100644 --- a/OpenRA.Mods.RA/Bridge.cs +++ b/OpenRA.Mods.RA/Bridge.cs @@ -98,7 +98,7 @@ namespace OpenRA.Mods.RA { var dx = cell - self.Location; var index = dx.X + self.World.TileSet.Templates[template].Size.X * dx.Y; - return self.World.TileSet.GetTerrainIndex(new TileReference(template, (byte)index)); + return self.World.TileSet.GetTerrainIndex(new TerrainTile(template, (byte)index)); } public void LinkNeighbouringBridges(World world, BridgeLayer bridges) @@ -121,7 +121,7 @@ namespace OpenRA.Mods.RA IRenderable[] TemplateRenderables(WorldRenderer wr, PaletteReference palette, ushort template) { return footprint.Select(c => (IRenderable)(new SpriteRenderable( - wr.Theater.TileSprite(new TileReference(template, c.Value)), + wr.Theater.TileSprite(new TerrainTile(template, c.Value)), c.Key.CenterPosition, WVec.Zero, -512, palette, 1f, true))).ToArray(); } diff --git a/OpenRA.Mods.RA/BridgeLayer.cs b/OpenRA.Mods.RA/BridgeLayer.cs index 1b85304c82..f816ecb51e 100644 --- a/OpenRA.Mods.RA/BridgeLayer.cs +++ b/OpenRA.Mods.RA/BridgeLayer.cs @@ -51,9 +51,14 @@ namespace OpenRA.Mods.RA // Loop through the map looking for templates to overlay for (var i = w.Map.Bounds.Left; i < w.Map.Bounds.Right; i++) + { for (var j = w.Map.Bounds.Top; j < w.Map.Bounds.Bottom; j++) - if (bridgeTypes.Keys.Contains(w.Map.MapTiles.Value[i, j].Type)) - ConvertBridgeToActor(w, new CPos(i, j)); + { + var cell = new CPos(i, j); + if (bridgeTypes.Keys.Contains(w.Map.MapTiles.Value[cell].Type)) + ConvertBridgeToActor(w, cell); + } + } // Link adjacent (long)-bridges so that artwork is updated correctly foreach (var b in w.Actors.SelectMany(a => a.TraitsImplementing())) @@ -67,8 +72,8 @@ namespace OpenRA.Mods.RA return; // Correlate the tile "image" aka subtile with its position to find the template origin - var tile = w.Map.MapTiles.Value[cell.X, cell.Y].Type; - var index = w.Map.MapTiles.Value[cell.X, cell.Y].Index; + var tile = w.Map.MapTiles.Value[cell].Type; + var index = w.Map.MapTiles.Value[cell].Index; var template = w.TileSet.Templates[tile]; var ni = cell.X - index % template.Size.X; var nj = cell.Y - index / template.Size.X; @@ -90,8 +95,8 @@ namespace OpenRA.Mods.RA var subtile = new CPos(ni + ind % template.Size.X, nj + ind / template.Size.X); // This isn't the bridge you're looking for - if (!w.Map.IsInMap(subtile) || w.Map.MapTiles.Value[subtile.X, subtile.Y].Type != tile || - w.Map.MapTiles.Value[subtile.X, subtile.Y].Index != ind) + if (!w.Map.IsInMap(subtile) || w.Map.MapTiles.Value[subtile].Type != tile || + w.Map.MapTiles.Value[subtile].Index != ind) continue; subTiles.Add(subtile, ind); diff --git a/OpenRA.Mods.RA/Buildings/LaysTerrain.cs b/OpenRA.Mods.RA/Buildings/LaysTerrain.cs index f079df6807..d375de521a 100755 --- a/OpenRA.Mods.RA/Buildings/LaysTerrain.cs +++ b/OpenRA.Mods.RA/Buildings/LaysTerrain.cs @@ -61,7 +61,7 @@ namespace OpenRA.Mods.RA.Buildings continue; var index = Game.CosmeticRandom.Next(template.TilesCount); - layer.AddTile(c, new TileReference(template.Id, (byte)index)); + layer.AddTile(c, new TerrainTile(template.Id, (byte)index)); } return; @@ -80,7 +80,7 @@ namespace OpenRA.Mods.RA.Buildings if (bi.GetBuildingAt(c) != self || map.CustomTerrain[c] != -1) continue; - layer.AddTile(c, new TileReference(template.Id, (byte)i)); + layer.AddTile(c, new TerrainTile(template.Id, (byte)i)); } } } diff --git a/OpenRA.Mods.RA/World/BuildableTerrainLayer.cs b/OpenRA.Mods.RA/World/BuildableTerrainLayer.cs index fdca2da8cc..36ecb72e1b 100644 --- a/OpenRA.Mods.RA/World/BuildableTerrainLayer.cs +++ b/OpenRA.Mods.RA/World/BuildableTerrainLayer.cs @@ -32,7 +32,7 @@ namespace OpenRA.Mods.RA dirty = new Dictionary(); } - public void AddTile(CPos cell, TileReference tile) + public void AddTile(CPos cell, TerrainTile tile) { map.CustomTerrain[cell] = tileset.GetTerrainIndex(tile); diff --git a/OpenRA.Utility/LegacyMapImporter.cs b/OpenRA.Utility/LegacyMapImporter.cs index 6e40e4ec63..ded0b9d2ab 100644 --- a/OpenRA.Utility/LegacyMapImporter.cs +++ b/OpenRA.Utility/LegacyMapImporter.cs @@ -137,6 +137,7 @@ namespace OpenRA.Utility var width = Exts.ParseIntegerInvariant(mapSection.GetValue("Width", "0")); var height = Exts.ParseIntegerInvariant(mapSection.GetValue("Height", "0")); mapSize = (legacyMapFormat == IniMapFormat.RedAlert) ? 128 : 64; + var size = new Size(mapSize, mapSize); map.Title = basic.GetValue("Name", Path.GetFileNameWithoutExtension(iniFile)); map.Author = "Westwood Studios"; @@ -148,8 +149,8 @@ namespace OpenRA.Utility map.Smudges = Exts.Lazy(() => new List()); map.Actors = Exts.Lazy(() => new Dictionary()); - map.MapResources = Exts.Lazy(() => new CellLayer(new Size(mapSize, mapSize))); - map.MapTiles = Exts.Lazy(() => new TileReference[mapSize, mapSize]); + map.MapResources = Exts.Lazy(() => new CellLayer(size)); + map.MapTiles = Exts.Lazy(() => new CellLayer(size)); map.Options = new MapOptions(); @@ -250,20 +251,20 @@ namespace OpenRA.Utility void UnpackRATileData(MemoryStream ms) { - for (var i = 0; i < mapSize; i++) - for (var j = 0; j < mapSize; j++) - map.MapTiles.Value[i, j] = new TileReference(); - + var types = new ushort[mapSize, mapSize]; for (var j = 0; j < mapSize; j++) + { for (var i = 0; i < mapSize; i++) { var tileID = ms.ReadUInt16(); - map.MapTiles.Value[i, j].Type = tileID == (ushort)0 ? (ushort)255 : tileID; // RAED weirdness + types[i, j] = tileID == (ushort)0 ? (ushort)255 : tileID; // RAED weirdness } + } for (var j = 0; j < mapSize; j++) for (var i = 0; i < mapSize; i++) - map.MapTiles.Value[i, j].Index = ms.ReadUInt8(); + map.MapTiles.Value[new CPos(i, j)] = new TerrainTile(types[i, j], ms.ReadUInt8()); + } void UnpackRAOverlayData(MemoryStream ms) @@ -314,16 +315,13 @@ namespace OpenRA.Utility void UnpackCncTileData(Stream ms) { - for (var i = 0; i < mapSize; i++) - for (var j = 0; j < mapSize; j++) - map.MapTiles.Value[i, j] = new TileReference(); - for (var j = 0; j < mapSize; j++) { for (var i = 0; i < mapSize; i++) { - map.MapTiles.Value[i, j].Type = ms.ReadUInt8(); - map.MapTiles.Value[i, j].Index = ms.ReadUInt8(); + var type = ms.ReadUInt8(); + var index = ms.ReadUInt8(); + map.MapTiles.Value[new CPos(i, j)] = new TerrainTile(type, index); } } }