diff --git a/OpenRA.Game/Game.cs b/OpenRA.Game/Game.cs index e6d94e6cd3..a53073e2b8 100644 --- a/OpenRA.Game/Game.cs +++ b/OpenRA.Game/Game.cs @@ -201,6 +201,19 @@ namespace OpenRA using (new PerfTimer("NewWorld")) { ModData.PrepareMap(map); + + // The depth buffer needs to be initialized with enough range to cover: + // - the height of the screen + // - the z-offset of tiles from MaxTerrainHeight below the bottom of the screen (pushed into view) + // - additional z-offset from actors on top of MaxTerrainHeight terrain + // - a small margin so that tiles rendered partially above the top edge of the screen aren't pushed behind the clip plane + // We need an offset of mapGrid.MaximumTerrainHeight * mapGrid.TileSize.Height / 2 to cover the terrain height + // and choose to use mapGrid.MaximumTerrainHeight * mapGrid.TileSize.Height / 4 for each of the actor and top-edge cases + var margin = 0; + if (map.Grid.EnableDepthBuffer) + margin = map.Rules.TerrainInfo.TileSize.Height * map.Grid.MaximumTerrainHeight; + + Renderer.SetDepthMargin(margin); OrderManager.World = new World(map, ModData, OrderManager, type); } @@ -497,9 +510,6 @@ namespace OpenRA using (new PerfTimer("LoadMaps")) ModData.MapCache.LoadMaps(); - var grid = ModData.Manifest.Contains() ? ModData.Manifest.Get() : null; - Renderer.InitializeDepthBuffer(grid); - Cursor?.Dispose(); Cursor = new CursorManager(ModData.CursorProvider, ModData.Manifest.CursorSheetSize); diff --git a/OpenRA.Game/Graphics/Viewport.cs b/OpenRA.Game/Graphics/Viewport.cs index a916cf016d..d1ce3f2023 100644 --- a/OpenRA.Game/Graphics/Viewport.cs +++ b/OpenRA.Game/Graphics/Viewport.cs @@ -146,7 +146,7 @@ namespace OpenRA.Graphics public Viewport(WorldRenderer wr, Map map) { worldRenderer = wr; - var grid = Game.ModData.Manifest.Get(); + tileSize = map.Rules.TerrainInfo.TileSize; viewportSizes = Game.ModData.Manifest.Get(); graphicSettings = Game.Settings.Graphics; defaultScale = viewportSizes.DefaultScale; @@ -155,8 +155,8 @@ namespace OpenRA.Graphics if (wr.World.Type == WorldType.Editor) { // The full map is visible in the editor - var width = map.MapSize.X * grid.TileSize.Width; - var height = map.MapSize.Y * grid.TileSize.Height; + var width = map.MapSize.X * tileSize.Width; + var height = map.MapSize.Y * tileSize.Height; if (wr.World.Map.Grid.Type == MapGridType.RectangularIsometric) height /= 2; @@ -171,8 +171,6 @@ namespace OpenRA.Graphics CenterLocation = (tl + br) / 2; } - tileSize = grid.TileSize; - UpdateViewportZooms(); } diff --git a/OpenRA.Game/Graphics/WorldRenderer.cs b/OpenRA.Game/Graphics/WorldRenderer.cs index 523a08f2ea..aa1e69afff 100644 --- a/OpenRA.Game/Graphics/WorldRenderer.cs +++ b/OpenRA.Game/Graphics/WorldRenderer.cs @@ -50,7 +50,7 @@ namespace OpenRA.Graphics internal WorldRenderer(ModData modData, World world) { World = world; - TileSize = World.Map.Grid.TileSize; + TileSize = World.Map.Rules.TerrainInfo.TileSize; TileScale = World.Map.Grid.TileScale; Viewport = new Viewport(this, world.Map); diff --git a/OpenRA.Game/Map/MapGrid.cs b/OpenRA.Game/Map/MapGrid.cs index a44bbd8211..a8179863ea 100644 --- a/OpenRA.Game/Map/MapGrid.cs +++ b/OpenRA.Game/Map/MapGrid.cs @@ -12,7 +12,6 @@ using System.Collections.Generic; using System.IO; using System.Linq; -using OpenRA.Primitives; using OpenRA.Traits; namespace OpenRA @@ -106,7 +105,6 @@ namespace OpenRA public class MapGrid : IGlobalModData { public readonly MapGridType Type = MapGridType.Rectangular; - public readonly Size TileSize = new(24, 24); public readonly byte MaximumTerrainHeight = 0; public readonly SubCell DefaultSubCell = (SubCell)byte.MaxValue; diff --git a/OpenRA.Game/Map/TerrainInfo.cs b/OpenRA.Game/Map/TerrainInfo.cs index 090033e1eb..a72f61f38c 100644 --- a/OpenRA.Game/Map/TerrainInfo.cs +++ b/OpenRA.Game/Map/TerrainInfo.cs @@ -25,6 +25,7 @@ namespace OpenRA public interface ITerrainInfo { string Id { get; } + Size TileSize { get; } TerrainTypeInfo[] TerrainTypes { get; } TerrainTileInfo GetTerrainInfo(TerrainTile r); bool TryGetTerrainInfo(TerrainTile r, out TerrainTileInfo info); diff --git a/OpenRA.Game/Renderer.cs b/OpenRA.Game/Renderer.cs index 81d5602e9f..864fd912db 100644 --- a/OpenRA.Game/Renderer.cs +++ b/OpenRA.Game/Renderer.cs @@ -155,16 +155,9 @@ namespace OpenRA }; } - public void InitializeDepthBuffer(MapGrid mapGrid) + public void SetDepthMargin(float depthMargin) { - // The depth buffer needs to be initialized with enough range to cover: - // - the height of the screen - // - the z-offset of tiles from MaxTerrainHeight below the bottom of the screen (pushed into view) - // - additional z-offset from actors on top of MaxTerrainHeight terrain - // - a small margin so that tiles rendered partially above the top edge of the screen aren't pushed behind the clip plane - // We need an offset of mapGrid.MaximumTerrainHeight * mapGrid.TileSize.Height / 2 to cover the terrain height - // and choose to use mapGrid.MaximumTerrainHeight * mapGrid.TileSize.Height / 4 for each of the actor and top-edge cases - depthMargin = mapGrid == null || !mapGrid.EnableDepthBuffer ? 0 : mapGrid.TileSize.Height * mapGrid.MaximumTerrainHeight; + this.depthMargin = depthMargin; } void BeginFrame() diff --git a/OpenRA.Game/Traits/World/ScreenMap.cs b/OpenRA.Game/Traits/World/ScreenMap.cs index d2ec915c62..204e47c188 100644 --- a/OpenRA.Game/Traits/World/ScreenMap.cs +++ b/OpenRA.Game/Traits/World/ScreenMap.cs @@ -63,7 +63,7 @@ namespace OpenRA.Traits public ScreenMap(World world, ScreenMapInfo info) { - var size = world.Map.Grid.TileSize; + var size = world.Map.Rules.TerrainInfo.TileSize; var width = world.Map.MapSize.X * size.Width; var height = world.Map.MapSize.Y * size.Height; diff --git a/OpenRA.Mods.Cnc/Graphics/ModelRenderable.cs b/OpenRA.Mods.Cnc/Graphics/ModelRenderable.cs index 7eaec17942..aa6be48fc5 100644 --- a/OpenRA.Mods.Cnc/Graphics/ModelRenderable.cs +++ b/OpenRA.Mods.Cnc/Graphics/ModelRenderable.cs @@ -141,7 +141,7 @@ namespace OpenRA.Mods.Cnc.Graphics { var map = wr.World.Map; var groundPos = model.Pos - new WVec(0, 0, map.DistanceAboveTerrain(model.Pos).Length); - var groundZ = (float)map.Grid.TileSize.Height * (groundPos.Z - model.Pos.Z) / map.Grid.TileScale; + var groundZ = (float)map.Rules.TerrainInfo.TileSize.Height * (groundPos.Z - model.Pos.Z) / map.Grid.TileScale; var pxOrigin = wr.Screen3DPosition(model.Pos); // HACK: We don't have enough texture channels to pass the depth data to the shader @@ -152,7 +152,7 @@ namespace OpenRA.Mods.Cnc.Graphics // sloped towards the camera. Offset it by another half cell to avoid clipping. var cell = map.CellContaining(model.Pos); if (map.Ramp.Contains(cell) && map.Ramp[cell] == 7) - pxOrigin += new float3(0, 0, 0.5f * map.Grid.TileSize.Height); + pxOrigin += new float3(0, 0, 0.5f * map.Rules.TerrainInfo.TileSize.Height); var shadowOrigin = pxOrigin - groundZ * new float2(renderProxy.ShadowDirection, 1); @@ -179,7 +179,7 @@ namespace OpenRA.Mods.Cnc.Graphics public void RenderDebugGeometry(WorldRenderer wr) { var groundPos = model.Pos - new WVec(0, 0, wr.World.Map.DistanceAboveTerrain(model.Pos).Length); - var groundZ = wr.World.Map.Grid.TileSize.Height * (groundPos.Z - model.Pos.Z) / 1024f; + var groundZ = wr.World.Map.Rules.TerrainInfo.TileSize.Height * (groundPos.Z - model.Pos.Z) / 1024f; var pxOrigin = wr.Screen3DPosition(model.Pos); var shadowOrigin = pxOrigin - groundZ * new float2(renderProxy.ShadowDirection, 1); diff --git a/OpenRA.Mods.Cnc/UtilityCommands/LegacySequenceImporter.cs b/OpenRA.Mods.Cnc/UtilityCommands/LegacySequenceImporter.cs index b509f0ebcd..cda272b3f1 100644 --- a/OpenRA.Mods.Cnc/UtilityCommands/LegacySequenceImporter.cs +++ b/OpenRA.Mods.Cnc/UtilityCommands/LegacySequenceImporter.cs @@ -13,6 +13,7 @@ using System; using System.IO; using System.Linq; using OpenRA.Mods.Common.FileFormats; +using OpenRA.Primitives; namespace OpenRA.Mods.Cnc.UtilityCommands { @@ -26,16 +27,14 @@ namespace OpenRA.Mods.Cnc.UtilityCommands string IUtilityCommand.Name => "--sequence-import"; IniFile file; - MapGrid grid; + Size tileSize; [Desc("FILENAME", "Convert ART.INI to the OpenRA sequence definition format.")] void IUtilityCommand.Run(Utility utility, string[] args) { // HACK: The engine code assumes that Game.modData is set. Game.ModData = utility.ModData; - - grid = Game.ModData.Manifest.Get(); - + tileSize = Game.ModData.DefaultTerrainInfo.Values.First().TileSize; file = new IniFile(File.Open(args[1], FileMode.Open)); foreach (var section in file.Sections) @@ -65,8 +64,8 @@ namespace OpenRA.Mods.Cnc.UtilityCommands var x = Exts.ParseInt32Invariant(size[0]); var y = Exts.ParseInt32Invariant(size[1]); - var xOffset = (x - y) * grid.TileSize.Width / 4; - var yOffset = (x + y) * grid.TileSize.Height / 4; + var xOffset = (x - y) * tileSize.Width / 4; + var yOffset = (x + y) * tileSize.Height / 4; Console.WriteLine("\t\tOffset: {0},{1}", -xOffset, -yOffset); } } diff --git a/OpenRA.Mods.Cnc/UtilityCommands/LegacyTilesetImporter.cs b/OpenRA.Mods.Cnc/UtilityCommands/LegacyTilesetImporter.cs index 65a9c2b619..2fc5ddd9be 100644 --- a/OpenRA.Mods.Cnc/UtilityCommands/LegacyTilesetImporter.cs +++ b/OpenRA.Mods.Cnc/UtilityCommands/LegacyTilesetImporter.cs @@ -36,7 +36,7 @@ namespace OpenRA.Mods.Cnc.UtilityCommands var file = new IniFile(File.Open(args[1], FileMode.Open)); var extension = args[2]; - var tileSize = utility.ModData.Manifest.Get().TileSize; + var tileSize = utility.ModData.DefaultTerrainInfo.Values.First().TileSize; var templateIndex = 0; diff --git a/OpenRA.Mods.Common/Lint/CheckInteractable.cs b/OpenRA.Mods.Common/Lint/CheckInteractable.cs index 77aacb50ab..5cfa5ab67b 100644 --- a/OpenRA.Mods.Common/Lint/CheckInteractable.cs +++ b/OpenRA.Mods.Common/Lint/CheckInteractable.cs @@ -10,6 +10,7 @@ #endregion using System; +using System.Linq; using OpenRA.Mods.Common.Traits; using OpenRA.Primitives; using OpenRA.Server; @@ -31,7 +32,8 @@ namespace OpenRA.Mods.Common.Lint static void Run(Action emitError, Ruleset rules, ModData modData) { // As the map has not been created we need to get MapGrid info directly from manifest. - var grid = modData.Manifest.Get(); + var tileSize = modData.DefaultTerrainInfo.Values.First().TileSize; + var tileScale = modData.Manifest.Get().TileScale; foreach (var actorInfo in rules.Actors) { // Catch TypeDictionary errors. @@ -41,10 +43,10 @@ namespace OpenRA.Mods.Common.Lint if (interactable == null) continue; - if (HasInvalidBounds(interactable.Bounds, grid.TileSize, grid.TileScale)) + if (HasInvalidBounds(interactable.Bounds, tileSize, tileScale)) emitError($"{actorInfo.Key}.{interactable.GetType().Name}.{nameof(interactable.Bounds)} are empty or negative."); - if (HasInvalidBounds(interactable.DecorationBounds, grid.TileSize, grid.TileScale)) + if (HasInvalidBounds(interactable.DecorationBounds, tileSize, tileScale)) emitError($"{actorInfo.Key}.{interactable.GetType().Name}.{nameof(interactable.DecorationBounds)} are empty or negative."); } catch (InvalidOperationException e) diff --git a/OpenRA.Mods.Common/Terrain/DefaultTerrain.cs b/OpenRA.Mods.Common/Terrain/DefaultTerrain.cs index fb55922042..635915541a 100644 --- a/OpenRA.Mods.Common/Terrain/DefaultTerrain.cs +++ b/OpenRA.Mods.Common/Terrain/DefaultTerrain.cs @@ -70,6 +70,7 @@ namespace OpenRA.Mods.Common.Terrain { public readonly string Name; public readonly string Id; + public readonly Size TileSize = new(24, 24); public readonly int SheetSize = 512; public readonly Color[] HeightDebugColors = [Color.Red]; public readonly string[] EditorTemplateOrder; @@ -176,6 +177,7 @@ namespace OpenRA.Mods.Common.Terrain } string ITerrainInfo.Id => Id; + Size ITerrainInfo.TileSize => TileSize; TerrainTypeInfo[] ITerrainInfo.TerrainTypes => TerrainInfo; TerrainTileInfo ITerrainInfo.GetTerrainInfo(TerrainTile r) { return GetTileInfo(r); } bool ITerrainInfo.TryGetTerrainInfo(TerrainTile r, out TerrainTileInfo info) { return TryGetTileInfo(r, out info); } diff --git a/OpenRA.Mods.Common/Traits/World/EditorActorLayer.cs b/OpenRA.Mods.Common/Traits/World/EditorActorLayer.cs index 032a1649b5..5555fec721 100644 --- a/OpenRA.Mods.Common/Traits/World/EditorActorLayer.cs +++ b/OpenRA.Mods.Common/Traits/World/EditorActorLayer.cs @@ -81,10 +81,10 @@ namespace OpenRA.Mods.Common.Traits cellOffset = new int2(world.Map.AllCells.Min(c => c.X), world.Map.AllCells.Min((c) => c.Y)); var cellOffsetMax = new int2(world.Map.AllCells.Max(c => c.X), world.Map.AllCells.Max((c) => c.Y)); var mapCellSize = cellOffsetMax - cellOffset; + var ts = world.Map.Rules.TerrainInfo.TileSize; cellMap = new SpatiallyPartitioned( - mapCellSize.X, mapCellSize.Y, Exts.IntegerDivisionRoundingAwayFromZero(Info.BinSize, world.Map.Grid.TileSize.Width)); + mapCellSize.X, mapCellSize.Y, Exts.IntegerDivisionRoundingAwayFromZero(Info.BinSize, ts.Width)); - var ts = world.Map.Grid.TileSize; var width = world.Map.MapSize.X * ts.Width; var height = world.Map.MapSize.Y * ts.Height; screenMap = new SpatiallyPartitioned(width, height, Info.BinSize); diff --git a/OpenRA.Mods.Common/Traits/World/MapOptions.cs b/OpenRA.Mods.Common/Traits/World/MapOptions.cs index 4a7abed335..9cfaa2ec33 100644 --- a/OpenRA.Mods.Common/Traits/World/MapOptions.cs +++ b/OpenRA.Mods.Common/Traits/World/MapOptions.cs @@ -143,7 +143,7 @@ namespace OpenRA.Mods.Common.Traits if (info.ViewportHeight.HasValue) { // WPos to world pixels - var height = info.ViewportHeight.Value.Length * w.Map.Grid.TileSize.Height / w.Map.Grid.TileScale; + var height = info.ViewportHeight.Value.Length * w.Map.Rules.TerrainInfo.TileSize.Height / w.Map.Grid.TileScale; wr.Viewport.OverrideDefaultHeight(height); } } diff --git a/OpenRA.Mods.Common/Traits/World/TerrainRenderer.cs b/OpenRA.Mods.Common/Traits/World/TerrainRenderer.cs index aca1cbff19..036c8a7d02 100644 --- a/OpenRA.Mods.Common/Traits/World/TerrainRenderer.cs +++ b/OpenRA.Mods.Common/Traits/World/TerrainRenderer.cs @@ -133,7 +133,7 @@ namespace OpenRA.Mods.Common.Traits Rectangle ITiledTerrainRenderer.TemplateBounds(TerrainTemplateInfo template) { Rectangle? templateRect = null; - var tileSize = map.Grid.TileSize; + var tileSize = map.Rules.TerrainInfo.TileSize; var i = 0; for (var y = 0; y < template.Size.Y; y++) @@ -162,7 +162,7 @@ namespace OpenRA.Mods.Common.Traits if (t is not DefaultTerrainTemplateInfo template) yield break; - var ts = map.Grid.TileSize; + var ts = map.Rules.TerrainInfo.TileSize; var gridType = map.Grid.Type; var i = 0; diff --git a/OpenRA.Mods.Common/UpdateRules/Rules/20210321/ConvertBoundsToWDist.cs b/OpenRA.Mods.Common/UpdateRules/Rules/20210321/ConvertBoundsToWDist.cs index 9e9e9d4122..87a087fad2 100644 --- a/OpenRA.Mods.Common/UpdateRules/Rules/20210321/ConvertBoundsToWDist.cs +++ b/OpenRA.Mods.Common/UpdateRules/Rules/20210321/ConvertBoundsToWDist.cs @@ -10,6 +10,7 @@ #endregion using System.Collections.Generic; +using System.Linq; namespace OpenRA.Mods.Common.UpdateRules.Rules { @@ -27,7 +28,7 @@ namespace OpenRA.Mods.Common.UpdateRules.Rules public override IEnumerable UpdateActorNode(ModData modData, MiniYamlNodeBuilder actorNode) { var grid = modData.Manifest.Get(); - var tileSize = grid.TileSize; + var tileSize = modData.DefaultTerrainInfo.Values.First().TileSize; var tileScale = grid.TileScale; foreach (var trait in traits) diff --git a/OpenRA.Mods.Common/Widgets/ResourcePreviewWidget.cs b/OpenRA.Mods.Common/Widgets/ResourcePreviewWidget.cs index 7a0a56a4de..0d128c7ad0 100644 --- a/OpenRA.Mods.Common/Widgets/ResourcePreviewWidget.cs +++ b/OpenRA.Mods.Common/Widgets/ResourcePreviewWidget.cs @@ -52,7 +52,7 @@ namespace OpenRA.Mods.Common.Widgets this.worldRenderer = worldRenderer; viewportSizes = modData.Manifest.Get(); resourceRenderers = world.WorldActor.TraitsImplementing().ToArray(); - tileSize = world.Map.Grid.TileSize; + tileSize = world.Map.Rules.TerrainInfo.TileSize; IdealPreviewSize = new Size( (int)(viewportSizes.DefaultScale * tileSize.Width), (int)(viewportSizes.DefaultScale * tileSize.Height)); diff --git a/mods/cnc/mod.yaml b/mods/cnc/mod.yaml index 29697e0391..902a89a2d2 100644 --- a/mods/cnc/mod.yaml +++ b/mods/cnc/mod.yaml @@ -232,7 +232,6 @@ Missions: cnc|missions.yaml MapGrid: - TileSize: 24,24 Type: Rectangular DefaultOrderGenerator: UnitOrderGenerator diff --git a/mods/d2k/mod.yaml b/mods/d2k/mod.yaml index f04c811e0c..960ece2421 100644 --- a/mods/d2k/mod.yaml +++ b/mods/d2k/mod.yaml @@ -66,7 +66,6 @@ TileSets: d2k|tilesets/arrakis.yaml MapGrid: - TileSize: 32,32 Type: Rectangular Cursors: diff --git a/mods/d2k/tilesets/arrakis.yaml b/mods/d2k/tilesets/arrakis.yaml index 1138d2d6c7..b1161f9b3a 100644 --- a/mods/d2k/tilesets/arrakis.yaml +++ b/mods/d2k/tilesets/arrakis.yaml @@ -1,6 +1,7 @@ General: Name: Arrakis Id: ARRAKIS + TileSize: 32, 32 SheetSize: 1024 EditorTemplateOrder: Basic, Dune, Sand-Detail, Rock-Detail, Ice-Detail, Rock-Sand-Smooth, Sand-Sand-Cliff, Sand-Rock-Cliff, Sand-Ice-Cliff, Rock-Rock-Cliff, Rock-Sand-Cliff, Cliff-Type-Changer, Cliff-Ends, Sand-Platform, Bridge, Rotten-Base, Dead-Worm, Unidentified IgnoreTileSpriteOffsets: True diff --git a/mods/ra/mod.yaml b/mods/ra/mod.yaml index 709988a9ed..e4ed73c517 100644 --- a/mods/ra/mod.yaml +++ b/mods/ra/mod.yaml @@ -261,7 +261,6 @@ Missions: ra|missions.yaml MapGrid: - TileSize: 24,24 Type: Rectangular DefaultOrderGenerator: UnitOrderGenerator diff --git a/mods/ts/mod.yaml b/mods/ts/mod.yaml index 8ad1ac5327..a1f18b47bb 100644 --- a/mods/ts/mod.yaml +++ b/mods/ts/mod.yaml @@ -103,7 +103,6 @@ TileSets: ts|tilesets/snow.yaml MapGrid: - TileSize: 48,24 EnableDepthBuffer: True Type: RectangularIsometric MaximumTerrainHeight: 16 diff --git a/mods/ts/tilesets/snow.yaml b/mods/ts/tilesets/snow.yaml index 9306bb564c..2ca52434c3 100644 --- a/mods/ts/tilesets/snow.yaml +++ b/mods/ts/tilesets/snow.yaml @@ -1,6 +1,7 @@ General: Name: Snow Id: SNOW + TileSize: 48, 24 HeightDebugColors: 00000080, 00004480, 00008880, 0000CC80, 0000FF80, 4400CC80, 88008880, CC004480, FF110080, FF550080, FF990080, FFDD0080, DDFF0080, 99FF0080, 55FF0080, 11FF0080 EditorTemplateOrder: Bendy Dirt Roads, Blank, Bridges, Civilian Buildings, Clear, Clear/Rough LAT, Cliff Pieces, Cliff Set, Cliff/Water pieces, Dead Oil Tanker, Destroyable Cliffs, Dirt Road Junctions, Dirt Road Slopes, DirtTrackTunnel Floor, DirtTunnel Floor, Grey/Clear LAT, House, Ice 01, Ice 02, Ice 03, Ice Flow, Ice Ramps, Ice shore, Misc Buildings, Monorail Slopes, Paved Road Ends, Paved Road Slopes, Paved Roads, Pavement, Pavement (Use for LAT), Pavement/Clear LAT, Ramp edge fixup, Rough ground, Rough lat, Ruins, Shore Pieces, Slope Set Pieces, Straight Dirt Roads, TrackTunnel Floor, TrainBridges, Tunnel Side, Tunnels, Water, Water slopes, Waterfalls, Waterfalls-B, Waterfalls-C, Waterfalls-D SheetSize: 2048 diff --git a/mods/ts/tilesets/temperate.yaml b/mods/ts/tilesets/temperate.yaml index 7f4b3c02a2..75e9960322 100644 --- a/mods/ts/tilesets/temperate.yaml +++ b/mods/ts/tilesets/temperate.yaml @@ -1,6 +1,7 @@ General: Name: Temperate Id: TEMPERATE + TileSize: 48, 24 HeightDebugColors: 00000080, 00004480, 00008880, 0000CC80, 0000FF80, 4400CC80, 88008880, CC004480, FF110080, FF550080, FF990080, FFDD0080, DDFF0080, 99FF0080, 55FF0080, 11FF0080 EditorTemplateOrder: Misc Buildings, Clear, Cliff Pieces, Ice Flow, House, Blank, Ice Ramps, Cliff Set, Civilian Buildings, Shore Pieces, Rough LAT tile, Clear/Rough LAT, Cliff/Water pieces, Bendy Dirt Roads, Dirt Road Junctions, Straight Dirt Roads, Bridges, Paved Roads, Water, Dirt Road Slopes, Slope Set Pieces, Dead Oil Tanker, Ruins, Waterfalls, Ground 01, Ground 02, Sand, Sand/Clear LAT, Rough ground, Paved Road Ends, TrainBridges, Pavement, Pavement/Clear LAT, Paved road bits, Green, Green/Clear LAT, Ramp edge fixup, Water slopes, Pavement (Use for LAT), Paved Road Slopes, Monorail Slopes, Waterfalls-B, Waterfalls-C, Waterfalls-D, Tunnel Floor, Tunnel Side, TrackTunnel Floor, Destroyable Cliffs, Water Caves, Scrin Wreckage, DirtTrackTunnel Floor, DirtTunnel Floor, Crystal LAT tile, Clear Crystal LAT, Swampy, Swampy LAT, Blue Mold, Blue Mold LAT, Crystal Cliff, Kodiak Crash SheetSize: 2048