diff --git a/OpenRA.Editor/BrushTool.cs b/OpenRA.Editor/BrushTool.cs index 9a20c1db6c..f5b0dcc3b1 100644 --- a/OpenRA.Editor/BrushTool.cs +++ b/OpenRA.Editor/BrushTool.cs @@ -43,7 +43,7 @@ namespace OpenRA.Editor { var z = u + v * template.Size.X; if (tile.TileBitmapBytes[z] != null) - surface.Map.MapTiles[u + pos.X, v + pos.Y] = + surface.Map.MapTiles.Value[u + pos.X, v + pos.Y] = new TileReference { type = Brush.N, @@ -72,7 +72,7 @@ namespace OpenRA.Editor void FloodFillWithBrush(Surface s, int2 pos) { var queue = new Queue(); - var replace = s.Map.MapTiles[pos.X, pos.Y]; + var replace = s.Map.MapTiles.Value[pos.X, pos.Y]; var touched = new bool[s.Map.MapSize.X, s.Map.MapSize.Y]; Action MaybeEnqueue = (x, y) => @@ -88,7 +88,7 @@ namespace OpenRA.Editor while (queue.Count > 0) { var p = queue.Dequeue(); - if (!s.Map.MapTiles[p.X, p.Y].Equals(replace)) + if (!s.Map.MapTiles.Value[p.X, p.Y].Equals(replace)) continue; var a = FindEdge(s, p, new int2(-1, 0), replace); @@ -96,10 +96,10 @@ namespace OpenRA.Editor for (var x = a.X; x <= b.X; x++) { - s.Map.MapTiles[x, p.Y] = new TileReference { type = Brush.N, index = (byte)0 }; - if (s.Map.MapTiles[x, p.Y - 1].Equals(replace)) + s.Map.MapTiles.Value[x, p.Y] = new TileReference { type = Brush.N, index = (byte)0 }; + if (s.Map.MapTiles.Value[x, p.Y - 1].Equals(replace)) MaybeEnqueue(x, p.Y - 1); - if (s.Map.MapTiles[x, p.Y + 1].Equals(replace)) + if (s.Map.MapTiles.Value[x, p.Y + 1].Equals(replace)) MaybeEnqueue(x, p.Y + 1); } } @@ -115,7 +115,7 @@ namespace OpenRA.Editor { var q = p + d; if (!s.Map.IsInMap(q)) return p; - if (!s.Map.MapTiles[q.X, q.Y].Equals(replace)) return p; + if (!s.Map.MapTiles.Value[q.X, q.Y].Equals(replace)) return p; p = q; } } diff --git a/OpenRA.Editor/LegacyMapImporter.cs b/OpenRA.Editor/LegacyMapImporter.cs index 88e3433f6e..fc1ab8c7c8 100644 --- a/OpenRA.Editor/LegacyMapImporter.cs +++ b/OpenRA.Editor/LegacyMapImporter.cs @@ -117,6 +117,7 @@ namespace OpenRA.Editor public void ConvertIniMap(string iniFile) { + var file = new IniFile(FileSystem.Open(iniFile)); var basic = file.GetSection("Basic"); var map = file.GetSection("Map"); @@ -134,7 +135,7 @@ namespace OpenRA.Editor Map.MapSize.Y = MapSize; Map.Bounds = Rectangle.FromLTRB(XOffset, YOffset, XOffset + Width, YOffset + Height); Map.Selectable = true; - + /* if (legacyMapFormat == IniMapFormat.RedAlert) { UnpackRATileData(ReadPackedSection(file.GetSection("MapPack"))); @@ -147,7 +148,7 @@ namespace OpenRA.Editor ReadCncOverlay(file); ReadCncTrees(file); } - + */ LoadActors(file, "STRUCTURES"); LoadActors(file, "UNITS"); LoadActors(file, "INFANTRY"); @@ -232,7 +233,7 @@ namespace OpenRA.Editor return ret; } - + /* void UnpackRATileData(MemoryStream ms) { Map.MapTiles = new TileReference[MapSize, MapSize]; @@ -312,7 +313,7 @@ namespace OpenRA.Editor Map.MapTiles[i, j].index = byte.MaxValue; } } - + void ReadCncOverlay(IniFile file) { IniSection overlay = file.GetSection("OVERLAY", true); @@ -340,7 +341,7 @@ namespace OpenRA.Editor }); } } - + */ void ReadCncTrees(IniFile file) { IniSection terrain = file.GetSection("TERRAIN", true); diff --git a/OpenRA.Editor/ResourceTool.cs b/OpenRA.Editor/ResourceTool.cs index 8bc1786d64..a1c87f86dd 100644 --- a/OpenRA.Editor/ResourceTool.cs +++ b/OpenRA.Editor/ResourceTool.cs @@ -23,7 +23,7 @@ namespace OpenRA.Editor public void Apply(Surface surface) { - surface.Map.MapResources[surface.GetBrushLocation().X, surface.GetBrushLocation().Y] + surface.Map.MapResources.Value[surface.GetBrushLocation().X, surface.GetBrushLocation().Y] = new TileReference { type = (byte)Resource.Info.ResourceType, diff --git a/OpenRA.Editor/Surface.cs b/OpenRA.Editor/Surface.cs index e9d6caf4c7..4ba29f8263 100755 --- a/OpenRA.Editor/Surface.cs +++ b/OpenRA.Editor/Surface.cs @@ -155,9 +155,9 @@ namespace OpenRA.Editor var key = Map.Actors.FirstOrDefault(a => a.Value.Location() == BrushLocation); if (key.Key != null) Map.Actors.Remove(key.Key); - if (Map.MapResources[BrushLocation.X, BrushLocation.Y].type != 0) + if (Map.MapResources.Value[BrushLocation.X, BrushLocation.Y].type != 0) { - Map.MapResources[BrushLocation.X, BrushLocation.Y] = new TileReference(); + Map.MapResources.Value[BrushLocation.X, BrushLocation.Y] = new TileReference(); var ch = new int2((BrushLocation.X) / ChunkSize, (BrushLocation.Y) / ChunkSize); if (Chunks.ContainsKey(ch)) { @@ -209,7 +209,7 @@ namespace OpenRA.Editor for (var i = 0; i < ChunkSize; i++) for (var j = 0; j < ChunkSize; j++) { - var tr = Map.MapTiles[u * ChunkSize + i, v * ChunkSize + j]; + var tr = Map.MapTiles.Value[u * ChunkSize + i, v * ChunkSize + j]; var tile = TileSet.Tiles[tr.type]; var index = (tr.index < tile.TileBitmapBytes.Count) ? tr.index : (byte)0; var rawImage = tile.TileBitmapBytes[index]; @@ -217,9 +217,9 @@ namespace OpenRA.Editor for (var y = 0; y < TileSet.TileSize; y++) p[(j * TileSet.TileSize + y) * stride + i * TileSet.TileSize + x] = Palette.GetColor(rawImage[x + TileSet.TileSize * y]).ToArgb(); - if (Map.MapResources[u * ChunkSize + i, v * ChunkSize + j].type != 0) + if (Map.MapResources.Value[u * ChunkSize + i, v * ChunkSize + j].type != 0) { - var resourceImage = ResourceTemplates[Map.MapResources[u * ChunkSize + i, v * ChunkSize + j].type].Bitmap; + var resourceImage = ResourceTemplates[Map.MapResources.Value[u * ChunkSize + i, v * ChunkSize + j].type].Bitmap; var srcdata = resourceImage.LockBits(new Rectangle(0, 0, resourceImage.Width, resourceImage.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); diff --git a/OpenRA.Game/Graphics/Minimap.cs b/OpenRA.Game/Graphics/Minimap.cs index 4f30725202..08cad4472f 100644 --- a/OpenRA.Game/Graphics/Minimap.cs +++ b/OpenRA.Game/Graphics/Minimap.cs @@ -50,7 +50,7 @@ namespace OpenRA.Graphics { var mapX = x + map.Bounds.Left; var mapY = y + map.Bounds.Top; - var type = tileset.GetTerrainType(map.MapTiles[mapX, mapY]); + var type = tileset.GetTerrainType(map.MapTiles.Value[mapX, mapY]); if (!tileset.Terrain.ContainsKey(type)) throw new InvalidDataException("Tileset {0} lacks terraintype {1}".F(tileset.Id, type)); @@ -80,11 +80,11 @@ namespace OpenRA.Graphics { var mapX = x + map.Bounds.Left; var mapY = y + map.Bounds.Top; - if (map.MapResources[mapX, mapY].type == 0) + if (map.MapResources.Value[mapX, mapY].type == 0) continue; var res = Rules.Info["world"].Traits.WithInterface() - .Where(t => t.ResourceType == map.MapResources[mapX, mapY].type) + .Where(t => t.ResourceType == map.MapResources.Value[mapX, mapY].type) .Select(t => t.TerrainType).FirstOrDefault(); if (res == null) continue; diff --git a/OpenRA.Game/Graphics/TerrainRenderer.cs b/OpenRA.Game/Graphics/TerrainRenderer.cs index 9d6e0f89b8..cb91ff3e9b 100644 --- a/OpenRA.Game/Graphics/TerrainRenderer.cs +++ b/OpenRA.Game/Graphics/TerrainRenderer.cs @@ -37,7 +37,7 @@ namespace OpenRA.Graphics Vertex[] vertices = new Vertex[4 * map.Bounds.Height * map.Bounds.Width]; ushort[] indices = new ushort[6 * map.Bounds.Height * map.Bounds.Width]; - terrainSheet = tileMapping[map.MapTiles[map.Bounds.Left, map.Bounds.Top]].sheet; + terrainSheet = tileMapping[map.MapTiles.Value[map.Bounds.Left, map.Bounds.Top]].sheet; int nv = 0; int ni = 0; @@ -45,14 +45,14 @@ namespace OpenRA.Graphics for( int j = map.Bounds.Top; j < map.Bounds.Bottom; j++ ) for( int i = map.Bounds.Left; i < map.Bounds.Right; i++ ) { - Sprite tile = tileMapping[map.MapTiles[i, j]]; + Sprite tile = tileMapping[map.MapTiles.Value[i, j]]; // TODO: The zero below should explicitly refer to the terrain palette, but this code is called // before the palettes are created. Therefore assumes that "terrain" is the first palette to be defined Util.FastCreateQuad(vertices, indices, Game.CellSize * new float2(i, j), tile, Game.modData.Palette.GetPaletteIndex("terrain"), nv, ni, tile.size); nv += 4; ni += 6; - if (tileMapping[map.MapTiles[i, j]].sheet != terrainSheet) + if (tileMapping[map.MapTiles.Value[i, j]].sheet != terrainSheet) throw new InvalidOperationException("Terrain sprites span multiple sheets"); } diff --git a/OpenRA.Game/Map.cs b/OpenRA.Game/Map.cs index 8249daed8f..5166422999 100644 --- a/OpenRA.Game/Map.cs +++ b/OpenRA.Game/Map.cs @@ -42,8 +42,8 @@ namespace OpenRA public byte TileFormat = 1; [FieldLoader.Load] public int2 MapSize; - public TileReference[,] MapTiles; - public TileReference[,] MapResources; + public Lazy[,]> MapTiles; + public Lazy[,]> MapResources; public string [,] CustomTerrain; public Map() @@ -61,12 +61,12 @@ namespace OpenRA Author = "Your name here", MapSize = new int2(1, 1), Tileset = tileset, - MapResources = new TileReference[1, 1], - MapTiles = new TileReference[1, 1] + MapResources = Lazy.New(() => new TileReference[1, 1]), + MapTiles = Lazy.New(() => new TileReference[1, 1] { { new TileReference { type = tile.Key, index = (byte)0 } - } }, + } }) }; return map; @@ -152,8 +152,10 @@ namespace OpenRA // Voices Voices = (yaml.NodesDict.ContainsKey("Voices")) ? yaml.NodesDict["Voices"].Nodes : new List(); - CustomTerrain = new string[MapSize.X, MapSize.Y]; - LoadBinaryData(); + CustomTerrain = new string[MapSize.X, MapSize.Y]; + + MapTiles = Lazy.New(() => LoadMapTiles()); + MapResources = Lazy.New(() => LoadResourceTiles()); } public void Save(string toPath) @@ -234,9 +236,42 @@ namespace OpenRA return ret; } - - public void LoadBinaryData() + + public TileReference[,] LoadMapTiles() { + var tiles = new TileReference[MapSize.X, MapSize.Y]; + using (var dataStream = Container.GetContent("map.bin")) + { + if (ReadByte(dataStream) != 1) + throw new InvalidDataException("Unknown binary map format"); + + // Load header info + var width = ReadWord(dataStream); + var height = ReadWord(dataStream); + + if (width != MapSize.X || height != MapSize.Y) + throw new InvalidDataException("Invalid tile data"); + + + // Load tile data + for (int i = 0; i < MapSize.X; i++) + for (int j = 0; j < MapSize.Y; j++) + { + ushort tile = ReadWord(dataStream); + byte index = ReadByte(dataStream); + if (index == byte.MaxValue) + index = (byte)(i % 4 + (j % 4) * 4); + + tiles[i, j] = new TileReference(tile, index); + } + } + return tiles; + } + + public TileReference[,] LoadResourceTiles() + { + var resources = new TileReference[MapSize.X, MapSize.Y]; + using (var dataStream = Container.GetContent("map.bin")) { if (ReadByte(dataStream) != 1) @@ -248,21 +283,10 @@ namespace OpenRA if (width != MapSize.X || height != MapSize.Y) throw new InvalidDataException("Invalid tile data"); - - MapTiles = new TileReference[MapSize.X, MapSize.Y]; - MapResources = new TileReference[MapSize.X, MapSize.Y]; - - // Load tile data - for (int i = 0; i < MapSize.X; i++) - for (int j = 0; j < MapSize.Y; j++) - { - ushort tile = ReadWord(dataStream); - byte index = ReadByte(dataStream); - if (index == byte.MaxValue) - index = (byte)(i % 4 + (j % 4) * 4); - - MapTiles[i, j] = new TileReference(tile, index); - } + + // Skip past tile data + for (var i = 0; i < 3*MapSize.X*MapSize.Y; i++) + ReadByte(dataStream); // Load resource data for (int i = 0; i < MapSize.X; i++) @@ -270,9 +294,10 @@ namespace OpenRA { byte type = ReadByte(dataStream); byte index = ReadByte(dataStream); - MapResources[i, j] = new TileReference(type, index); + resources[i, j] = new TileReference(type, index); } } + return resources; } public byte[] SaveBinaryData() @@ -289,17 +314,17 @@ namespace OpenRA for (int i = 0; i < MapSize.X; i++) for (int j = 0; j < MapSize.Y; j++) { - writer.Write(MapTiles[i, j].type); - var PickAny = OpenRA.Rules.TileSets[Tileset].Templates[MapTiles[i, j].type].PickAny; - writer.Write(PickAny ? (byte)(i % 4 + (j % 4) * 4) : MapTiles[i, j].index); + writer.Write(MapTiles.Value[i, j].type); + var PickAny = OpenRA.Rules.TileSets[Tileset].Templates[MapTiles.Value[i, j].type].PickAny; + writer.Write(PickAny ? (byte)(i % 4 + (j % 4) * 4) : MapTiles.Value[i, j].index); } // Resource data for (int i = 0; i < MapSize.X; i++) for (int j = 0; j < MapSize.Y; j++) { - writer.Write(MapResources[i, j].type); - writer.Write(MapResources[i, j].index); + writer.Write(MapResources.Value[i, j].type); + writer.Write(MapResources.Value[i, j].index); } } return dataStream.ToArray(); @@ -327,8 +352,8 @@ namespace OpenRA public void Resize(int width, int height) // editor magic. { - MapTiles = ResizeArray(MapTiles, MapTiles[0, 0], width, height); - MapResources = ResizeArray(MapResources, MapResources[0, 0], width, height); + MapTiles = Lazy.New(() => ResizeArray(MapTiles.Value, MapTiles.Value[0, 0], width, height)); + MapResources = Lazy.New(() => ResizeArray(MapResources.Value, MapResources.Value[0, 0], width, height)); MapSize = new int2(width, height); } diff --git a/OpenRA.Game/Traits/World/ResourceLayer.cs b/OpenRA.Game/Traits/World/ResourceLayer.cs index 4649b62689..8686bfb559 100644 --- a/OpenRA.Game/Traits/World/ResourceLayer.cs +++ b/OpenRA.Game/Traits/World/ResourceLayer.cs @@ -59,7 +59,7 @@ namespace OpenRA.Traits for (int y = map.Bounds.Top; y < map.Bounds.Bottom; y++) { var type = resourceTypes.FirstOrDefault( - r => r.info.ResourceType == w.Map.MapResources[x, y].type); + r => r.info.ResourceType == w.Map.MapResources.Value[x, y].type); if (type == null) continue; diff --git a/OpenRA.Game/WorldUtils.cs b/OpenRA.Game/WorldUtils.cs index 244ab3dc00..afee12b3ca 100755 --- a/OpenRA.Game/WorldUtils.cs +++ b/OpenRA.Game/WorldUtils.cs @@ -64,7 +64,7 @@ namespace OpenRA public static string GetTerrainType(this World world, int2 cell) { var custom = world.Map.CustomTerrain[cell.X, cell.Y]; - return custom != null ? custom : world.TileSet.GetTerrainType(world.Map.MapTiles[cell.X, cell.Y]); + return custom != null ? custom : world.TileSet.GetTerrainType(world.Map.MapTiles.Value[cell.X, cell.Y]); } public static TerrainTypeInfo GetTerrainInfo(this World world, int2 cell) diff --git a/OpenRA.Mods.RA/BridgeLayer.cs b/OpenRA.Mods.RA/BridgeLayer.cs index 74ddd1eb70..14211c6992 100644 --- a/OpenRA.Mods.RA/BridgeLayer.cs +++ b/OpenRA.Mods.RA/BridgeLayer.cs @@ -51,7 +51,7 @@ namespace OpenRA.Mods.RA // Loop through the map looking for templates to overlay for (int i = w.Map.Bounds.Left; i < w.Map.Bounds.Right; i++) for (int j = w.Map.Bounds.Top; j < w.Map.Bounds.Bottom; j++) - if (BridgeTypes.Keys.Contains(w.Map.MapTiles[i, j].type)) + if (BridgeTypes.Keys.Contains(w.Map.MapTiles.Value[i, j].type)) ConvertBridgeToActor(w, i, j); // Link adjacent (long)-bridges so that artwork is updated correctly @@ -66,8 +66,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[i, j].type; - var index = w.Map.MapTiles[i, j].index; + var tile = w.Map.MapTiles.Value[i, j].type; + var index = w.Map.MapTiles.Value[i, j].index; var template = w.TileSet.Templates[tile]; var ni = i - index % template.Size.X; var nj = j - index / template.Size.X; @@ -94,7 +94,7 @@ namespace OpenRA.Mods.RA var y = nj + ind / template.Size.X; // This isn't the bridge you're looking for - if (!w.Map.IsInMap(x, y) || w.Map.MapTiles[x, y].index != ind) + if (!w.Map.IsInMap(x, y) || w.Map.MapTiles.Value[x, y].index != ind) continue; subTiles.Add(new int2(x,y),ind);