Refactor editor clipboard logic as blitting logic
- Refactors internal editor clipboard logic into reusable map contents "Blitting" functionality. - Fix actor processing being unnecessarily (cell) looped within CopySelectionContents (now CopyRegionContents). - Deduplicates largely repeated code. - Minor code simplifications and renames.
This commit is contained in:
215
OpenRA.Mods.Common/EditorBrushes/EditorBlit.cs
Normal file
215
OpenRA.Mods.Common/EditorBrushes/EditorBlit.cs
Normal file
@@ -0,0 +1,215 @@
|
|||||||
|
#region Copyright & License Information
|
||||||
|
/*
|
||||||
|
* Copyright (c) The OpenRA Developers and Contributors
|
||||||
|
* This file is part of OpenRA, which is free software. It is made
|
||||||
|
* available to you under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation, either version 3 of
|
||||||
|
* the License, or (at your option) any later version. For more
|
||||||
|
* information, see COPYING.
|
||||||
|
*/
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using OpenRA.Mods.Common.Traits;
|
||||||
|
|
||||||
|
namespace OpenRA.Mods.Common.EditorBrushes
|
||||||
|
{
|
||||||
|
public readonly struct BlitTile
|
||||||
|
{
|
||||||
|
public readonly TerrainTile TerrainTile;
|
||||||
|
public readonly ResourceTile ResourceTile;
|
||||||
|
public readonly ResourceLayerContents? ResourceLayerContents;
|
||||||
|
public readonly byte Height;
|
||||||
|
|
||||||
|
public BlitTile(TerrainTile terrainTile, ResourceTile resourceTile, ResourceLayerContents? resourceLayerContents, byte height)
|
||||||
|
{
|
||||||
|
TerrainTile = terrainTile;
|
||||||
|
ResourceTile = resourceTile;
|
||||||
|
ResourceLayerContents = resourceLayerContents;
|
||||||
|
Height = height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public readonly struct EditorBlitSource
|
||||||
|
{
|
||||||
|
public readonly CellRegion CellRegion;
|
||||||
|
public readonly Dictionary<string, EditorActorPreview> Actors;
|
||||||
|
public readonly Dictionary<CPos, BlitTile> Tiles;
|
||||||
|
|
||||||
|
public EditorBlitSource(CellRegion cellRegion, Dictionary<string, EditorActorPreview> actors, Dictionary<CPos, BlitTile> tiles)
|
||||||
|
{
|
||||||
|
CellRegion = cellRegion;
|
||||||
|
Actors = actors;
|
||||||
|
Tiles = tiles;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
public enum MapBlitFilters
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
Terrain = 1,
|
||||||
|
Resources = 2,
|
||||||
|
Actors = 4,
|
||||||
|
All = Terrain | Resources | Actors
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Core implementation for EditorActions which overwrite a region of the map (such as
|
||||||
|
/// copy-paste).
|
||||||
|
/// </summary>
|
||||||
|
public sealed class EditorBlit
|
||||||
|
{
|
||||||
|
readonly MapBlitFilters blitFilters;
|
||||||
|
readonly IResourceLayer resourceLayer;
|
||||||
|
readonly EditorActorLayer editorActorLayer;
|
||||||
|
readonly EditorBlitSource blitSource;
|
||||||
|
readonly EditorBlitSource revertBlitSource;
|
||||||
|
readonly CPos blitPosition;
|
||||||
|
readonly Map map;
|
||||||
|
readonly bool respectBounds;
|
||||||
|
|
||||||
|
public EditorBlit(
|
||||||
|
MapBlitFilters blitFilters,
|
||||||
|
IResourceLayer resourceLayer,
|
||||||
|
CPos blitPosition,
|
||||||
|
Map map,
|
||||||
|
EditorBlitSource blitSource,
|
||||||
|
EditorActorLayer editorActorLayer,
|
||||||
|
bool respectBounds)
|
||||||
|
{
|
||||||
|
this.blitFilters = blitFilters;
|
||||||
|
this.resourceLayer = resourceLayer;
|
||||||
|
this.blitSource = blitSource;
|
||||||
|
this.blitPosition = blitPosition;
|
||||||
|
this.editorActorLayer = editorActorLayer;
|
||||||
|
this.map = map;
|
||||||
|
this.respectBounds = respectBounds;
|
||||||
|
|
||||||
|
var blitSize = blitSource.CellRegion.BottomRight - blitSource.CellRegion.TopLeft;
|
||||||
|
revertBlitSource = CopyRegionContents(
|
||||||
|
map,
|
||||||
|
editorActorLayer,
|
||||||
|
resourceLayer,
|
||||||
|
new CellRegion(map.Grid.Type, blitPosition, blitPosition + blitSize),
|
||||||
|
blitFilters);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns an EditorBlitSource containing the map contents for a given region.
|
||||||
|
/// </summary>
|
||||||
|
public static EditorBlitSource CopyRegionContents(
|
||||||
|
Map map,
|
||||||
|
EditorActorLayer editorActorLayer,
|
||||||
|
IResourceLayer resourceLayer,
|
||||||
|
CellRegion region,
|
||||||
|
MapBlitFilters blitFilters)
|
||||||
|
{
|
||||||
|
var mapTiles = map.Tiles;
|
||||||
|
var mapHeight = map.Height;
|
||||||
|
var mapResources = map.Resources;
|
||||||
|
|
||||||
|
var previews = new Dictionary<string, EditorActorPreview>();
|
||||||
|
var tiles = new Dictionary<CPos, BlitTile>();
|
||||||
|
|
||||||
|
foreach (var cell in region.CellCoords)
|
||||||
|
{
|
||||||
|
if (!mapTiles.Contains(cell))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
tiles.Add(
|
||||||
|
cell,
|
||||||
|
new BlitTile(mapTiles[cell],
|
||||||
|
mapResources[cell],
|
||||||
|
resourceLayer?.GetResource(cell),
|
||||||
|
mapHeight[cell]));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (blitFilters.HasFlag(MapBlitFilters.Actors))
|
||||||
|
foreach (var preview in editorActorLayer.PreviewsInCellRegion(region.CellCoords))
|
||||||
|
previews.TryAdd(preview.ID, preview);
|
||||||
|
|
||||||
|
return new EditorBlitSource(region, previews, tiles);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Blit(EditorBlitSource source, bool isRevert)
|
||||||
|
{
|
||||||
|
var blitPos = isRevert ? source.CellRegion.TopLeft : blitPosition;
|
||||||
|
var blitVec = blitPos - source.CellRegion.TopLeft;
|
||||||
|
var blitSize = source.CellRegion.BottomRight - source.CellRegion.TopLeft;
|
||||||
|
var blitRegion = new CellRegion(map.Grid.Type, blitPos, blitPos + blitSize);
|
||||||
|
|
||||||
|
if (blitFilters.HasFlag(MapBlitFilters.Actors))
|
||||||
|
{
|
||||||
|
// Clear any existing actors in the paste cells.
|
||||||
|
foreach (var regionActor in editorActorLayer.PreviewsInCellRegion(blitRegion.CellCoords).ToList())
|
||||||
|
editorActorLayer.Remove(regionActor);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var tileKeyValuePair in source.Tiles)
|
||||||
|
{
|
||||||
|
var position = tileKeyValuePair.Key + blitVec;
|
||||||
|
if (!map.Tiles.Contains(position) || (respectBounds && !map.Contains(position)))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Clear any existing resources.
|
||||||
|
if (resourceLayer != null && blitFilters.HasFlag(MapBlitFilters.Resources))
|
||||||
|
resourceLayer.ClearResources(position);
|
||||||
|
|
||||||
|
var tile = tileKeyValuePair.Value;
|
||||||
|
var resourceLayerContents = tile.ResourceLayerContents;
|
||||||
|
|
||||||
|
if (blitFilters.HasFlag(MapBlitFilters.Terrain))
|
||||||
|
{
|
||||||
|
map.Tiles[position] = tile.TerrainTile;
|
||||||
|
map.Height[position] = tile.Height;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (blitFilters.HasFlag(MapBlitFilters.Resources) &&
|
||||||
|
resourceLayerContents.HasValue &&
|
||||||
|
!string.IsNullOrWhiteSpace(resourceLayerContents.Value.Type))
|
||||||
|
resourceLayer.AddResource(resourceLayerContents.Value.Type, position, resourceLayerContents.Value.Density);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (blitFilters.HasFlag(MapBlitFilters.Actors))
|
||||||
|
{
|
||||||
|
if (isRevert)
|
||||||
|
{
|
||||||
|
// For reverts, just place the original actors back exactly how they were.
|
||||||
|
foreach (var actor in source.Actors.Values)
|
||||||
|
editorActorLayer.Add(actor);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Create copies of the original actors, update their locations, and place.
|
||||||
|
foreach (var actorKeyValuePair in source.Actors)
|
||||||
|
{
|
||||||
|
var copy = actorKeyValuePair.Value.Export();
|
||||||
|
var locationInit = copy.GetOrDefault<LocationInit>();
|
||||||
|
if (locationInit != null)
|
||||||
|
{
|
||||||
|
var actorPosition = locationInit.Value + blitVec;
|
||||||
|
if (respectBounds && !map.Contains(actorPosition))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
copy.RemoveAll<LocationInit>();
|
||||||
|
copy.Add(new LocationInit(actorPosition));
|
||||||
|
}
|
||||||
|
|
||||||
|
editorActorLayer.Add(copy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Commit() => Blit(blitSource, false);
|
||||||
|
public void Revert() => Blit(revertBlitSource, true);
|
||||||
|
|
||||||
|
public int TileCount()
|
||||||
|
{
|
||||||
|
return blitSource.Tiles.Count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
#region Copyright & License Information
|
|
||||||
/*
|
|
||||||
* Copyright (c) The OpenRA Developers and Contributors
|
|
||||||
* This file is part of OpenRA, which is free software. It is made
|
|
||||||
* available to you under the terms of the GNU General Public License
|
|
||||||
* as published by the Free Software Foundation, either version 3 of
|
|
||||||
* the License, or (at your option) any later version. For more
|
|
||||||
* information, see COPYING.
|
|
||||||
*/
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using OpenRA.Mods.Common.Traits;
|
|
||||||
|
|
||||||
namespace OpenRA.Mods.Common.EditorBrushes
|
|
||||||
{
|
|
||||||
public readonly struct ClipboardTile
|
|
||||||
{
|
|
||||||
public readonly TerrainTile TerrainTile;
|
|
||||||
public readonly ResourceTile ResourceTile;
|
|
||||||
public readonly ResourceLayerContents? ResourceLayerContents;
|
|
||||||
public readonly byte Height;
|
|
||||||
|
|
||||||
public ClipboardTile(TerrainTile terrainTile, ResourceTile resourceTile, ResourceLayerContents? resourceLayerContents, byte height)
|
|
||||||
{
|
|
||||||
TerrainTile = terrainTile;
|
|
||||||
ResourceTile = resourceTile;
|
|
||||||
ResourceLayerContents = resourceLayerContents;
|
|
||||||
Height = height;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public readonly struct EditorClipboard
|
|
||||||
{
|
|
||||||
public readonly CellRegion CellRegion;
|
|
||||||
public readonly Dictionary<string, EditorActorPreview> Actors;
|
|
||||||
public readonly Dictionary<CPos, ClipboardTile> Tiles;
|
|
||||||
|
|
||||||
public EditorClipboard(CellRegion cellRegion, Dictionary<string, EditorActorPreview> actors, Dictionary<CPos, ClipboardTile> tiles)
|
|
||||||
{
|
|
||||||
CellRegion = cellRegion;
|
|
||||||
Actors = actors;
|
|
||||||
Tiles = tiles;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -11,7 +11,6 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using OpenRA.Graphics;
|
using OpenRA.Graphics;
|
||||||
using OpenRA.Mods.Common.EditorBrushes;
|
using OpenRA.Mods.Common.EditorBrushes;
|
||||||
using OpenRA.Mods.Common.Graphics;
|
using OpenRA.Mods.Common.Graphics;
|
||||||
@@ -19,25 +18,15 @@ using OpenRA.Mods.Common.Traits;
|
|||||||
|
|
||||||
namespace OpenRA.Mods.Common.Widgets
|
namespace OpenRA.Mods.Common.Widgets
|
||||||
{
|
{
|
||||||
[Flags]
|
|
||||||
public enum MapCopyFilters
|
|
||||||
{
|
|
||||||
None = 0,
|
|
||||||
Terrain = 1,
|
|
||||||
Resources = 2,
|
|
||||||
Actors = 4,
|
|
||||||
All = Terrain | Resources | Actors
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class EditorCopyPasteBrush : IEditorBrush
|
public sealed class EditorCopyPasteBrush : IEditorBrush
|
||||||
{
|
{
|
||||||
readonly WorldRenderer worldRenderer;
|
readonly WorldRenderer worldRenderer;
|
||||||
readonly EditorViewportControllerWidget editorWidget;
|
readonly EditorViewportControllerWidget editorWidget;
|
||||||
readonly EditorActorLayer editorActorLayer;
|
readonly EditorActorLayer editorActorLayer;
|
||||||
readonly EditorActionManager editorActionManager;
|
readonly EditorActionManager editorActionManager;
|
||||||
readonly EditorClipboard clipboard;
|
readonly EditorBlitSource clipboard;
|
||||||
readonly IResourceLayer resourceLayer;
|
readonly IResourceLayer resourceLayer;
|
||||||
readonly Func<MapCopyFilters> getCopyFilters;
|
readonly Func<MapBlitFilters> getCopyFilters;
|
||||||
|
|
||||||
public CPos? PastePreviewPosition { get; private set; }
|
public CPos? PastePreviewPosition { get; private set; }
|
||||||
|
|
||||||
@@ -46,9 +35,9 @@ namespace OpenRA.Mods.Common.Widgets
|
|||||||
public EditorCopyPasteBrush(
|
public EditorCopyPasteBrush(
|
||||||
EditorViewportControllerWidget editorWidget,
|
EditorViewportControllerWidget editorWidget,
|
||||||
WorldRenderer wr,
|
WorldRenderer wr,
|
||||||
EditorClipboard clipboard,
|
EditorBlitSource clipboard,
|
||||||
IResourceLayer resourceLayer,
|
IResourceLayer resourceLayer,
|
||||||
Func<MapCopyFilters> getCopyFilters)
|
Func<MapBlitFilters> getCopyFilters)
|
||||||
{
|
{
|
||||||
this.getCopyFilters = getCopyFilters;
|
this.getCopyFilters = getCopyFilters;
|
||||||
this.editorWidget = editorWidget;
|
this.editorWidget = editorWidget;
|
||||||
@@ -80,13 +69,15 @@ namespace OpenRA.Mods.Common.Widgets
|
|||||||
if (mi.Button == MouseButton.Left && mi.Event == MouseInputEvent.Down)
|
if (mi.Button == MouseButton.Left && mi.Event == MouseInputEvent.Down)
|
||||||
{
|
{
|
||||||
var pastePosition = worldRenderer.Viewport.ViewToWorld(Viewport.LastMousePos);
|
var pastePosition = worldRenderer.Viewport.ViewToWorld(Viewport.LastMousePos);
|
||||||
var action = new CopyPasteEditorAction(
|
var editorBlit = new EditorBlit(
|
||||||
getCopyFilters(),
|
getCopyFilters(),
|
||||||
resourceLayer,
|
resourceLayer,
|
||||||
pastePosition,
|
pastePosition,
|
||||||
worldRenderer.World.Map,
|
worldRenderer.World.Map,
|
||||||
clipboard,
|
clipboard,
|
||||||
editorActorLayer);
|
editorActorLayer,
|
||||||
|
true);
|
||||||
|
var action = new CopyPasteEditorAction(editorBlit);
|
||||||
|
|
||||||
editorActionManager.Add(action);
|
editorActionManager.Add(action);
|
||||||
return true;
|
return true;
|
||||||
@@ -121,65 +112,13 @@ namespace OpenRA.Mods.Common.Widgets
|
|||||||
|
|
||||||
public string Text { get; }
|
public string Text { get; }
|
||||||
|
|
||||||
readonly MapCopyFilters copyFilters;
|
readonly EditorBlit editorBlit;
|
||||||
readonly IResourceLayer resourceLayer;
|
|
||||||
readonly EditorActorLayer editorActorLayer;
|
|
||||||
readonly EditorClipboard clipboard;
|
|
||||||
readonly EditorClipboard undoClipboard;
|
|
||||||
readonly CPos pastePosition;
|
|
||||||
readonly Map map;
|
|
||||||
|
|
||||||
public CopyPasteEditorAction(
|
public CopyPasteEditorAction(EditorBlit editorBlit)
|
||||||
MapCopyFilters copyFilters,
|
|
||||||
IResourceLayer resourceLayer,
|
|
||||||
CPos pastePosition,
|
|
||||||
Map map,
|
|
||||||
EditorClipboard clipboard,
|
|
||||||
EditorActorLayer editorActorLayer)
|
|
||||||
{
|
{
|
||||||
this.copyFilters = copyFilters;
|
this.editorBlit = editorBlit;
|
||||||
this.resourceLayer = resourceLayer;
|
|
||||||
this.clipboard = clipboard;
|
|
||||||
this.pastePosition = pastePosition;
|
|
||||||
this.editorActorLayer = editorActorLayer;
|
|
||||||
this.map = map;
|
|
||||||
|
|
||||||
undoClipboard = CopySelectionContents();
|
Text = FluentProvider.GetMessage(CopiedTiles, "amount", editorBlit.TileCount());
|
||||||
|
|
||||||
Text = FluentProvider.GetMessage(CopiedTiles, "amount", clipboard.Tiles.Count);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// TODO: This is pretty much repeated in MapEditorSelectionLogic.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>Clipboard containing map contents for this region.</returns>
|
|
||||||
EditorClipboard CopySelectionContents()
|
|
||||||
{
|
|
||||||
var selectionSize = clipboard.CellRegion.BottomRight - clipboard.CellRegion.TopLeft;
|
|
||||||
var source = new CellCoordsRegion(pastePosition, pastePosition + selectionSize);
|
|
||||||
var selection = new CellRegion(map.Grid.Type, pastePosition, pastePosition + selectionSize);
|
|
||||||
|
|
||||||
var mapTiles = map.Tiles;
|
|
||||||
var mapHeight = map.Height;
|
|
||||||
var mapResources = map.Resources;
|
|
||||||
|
|
||||||
var previews = new Dictionary<string, EditorActorPreview>();
|
|
||||||
var tiles = new Dictionary<CPos, ClipboardTile>();
|
|
||||||
|
|
||||||
foreach (var cell in source)
|
|
||||||
{
|
|
||||||
if (!mapTiles.Contains(cell))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var resourceLayerContents = resourceLayer?.GetResource(cell);
|
|
||||||
tiles.Add(cell, new ClipboardTile(mapTiles[cell], mapResources[cell], resourceLayerContents, mapHeight[cell]));
|
|
||||||
|
|
||||||
if (copyFilters.HasFlag(MapCopyFilters.Actors))
|
|
||||||
foreach (var preview in editorActorLayer.PreviewsInCellRegion(selection.CellCoords))
|
|
||||||
previews.TryAdd(preview.ID, preview);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new EditorClipboard(selection, previews, tiles);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Execute()
|
public void Execute()
|
||||||
@@ -189,103 +128,12 @@ namespace OpenRA.Mods.Common.Widgets
|
|||||||
|
|
||||||
public void Do()
|
public void Do()
|
||||||
{
|
{
|
||||||
var sourcePos = clipboard.CellRegion.TopLeft;
|
editorBlit.Commit();
|
||||||
var pasteVec = new CVec(pastePosition.X - sourcePos.X, pastePosition.Y - sourcePos.Y);
|
|
||||||
|
|
||||||
if (copyFilters.HasFlag(MapCopyFilters.Actors))
|
|
||||||
{
|
|
||||||
// Clear any existing actors in the paste cells.
|
|
||||||
var selectionSize = clipboard.CellRegion.BottomRight - clipboard.CellRegion.TopLeft;
|
|
||||||
var pasteRegion = new CellRegion(map.Grid.Type, pastePosition, pastePosition + selectionSize);
|
|
||||||
foreach (var regionActor in editorActorLayer.PreviewsInCellRegion(pasteRegion.CellCoords).ToList())
|
|
||||||
editorActorLayer.Remove(regionActor);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var tileKeyValuePair in clipboard.Tiles)
|
|
||||||
{
|
|
||||||
var position = tileKeyValuePair.Key + pasteVec;
|
|
||||||
if (!map.Contains(position))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// Clear any existing resources.
|
|
||||||
if (resourceLayer != null && copyFilters.HasFlag(MapCopyFilters.Resources))
|
|
||||||
resourceLayer.ClearResources(position);
|
|
||||||
|
|
||||||
var tile = tileKeyValuePair.Value;
|
|
||||||
var resourceLayerContents = tile.ResourceLayerContents;
|
|
||||||
|
|
||||||
if (copyFilters.HasFlag(MapCopyFilters.Terrain))
|
|
||||||
{
|
|
||||||
map.Tiles[position] = tile.TerrainTile;
|
|
||||||
map.Height[position] = tile.Height;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (copyFilters.HasFlag(MapCopyFilters.Resources) &&
|
|
||||||
resourceLayerContents.HasValue &&
|
|
||||||
!string.IsNullOrWhiteSpace(resourceLayerContents.Value.Type))
|
|
||||||
resourceLayer.AddResource(resourceLayerContents.Value.Type, position, resourceLayerContents.Value.Density);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (copyFilters.HasFlag(MapCopyFilters.Actors))
|
|
||||||
{
|
|
||||||
// Now place actors.
|
|
||||||
foreach (var actorKeyValuePair in clipboard.Actors)
|
|
||||||
{
|
|
||||||
var selection = clipboard.CellRegion;
|
|
||||||
var copy = actorKeyValuePair.Value.Export();
|
|
||||||
var locationInit = copy.GetOrDefault<LocationInit>();
|
|
||||||
if (locationInit != null)
|
|
||||||
{
|
|
||||||
var actorPosition = locationInit.Value + new CVec(pastePosition.X - selection.TopLeft.X, pastePosition.Y - selection.TopLeft.Y);
|
|
||||||
if (!map.Contains(actorPosition))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
copy.RemoveAll<LocationInit>();
|
|
||||||
copy.Add(new LocationInit(actorPosition));
|
|
||||||
}
|
|
||||||
|
|
||||||
editorActorLayer.Add(copy);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Undo()
|
public void Undo()
|
||||||
{
|
{
|
||||||
if (copyFilters.HasFlag(MapCopyFilters.Actors))
|
editorBlit.Revert();
|
||||||
{
|
|
||||||
// Clear existing actors.
|
|
||||||
foreach (var regionActor in editorActorLayer.PreviewsInCellRegion(undoClipboard.CellRegion.CellCoords).ToList())
|
|
||||||
editorActorLayer.Remove(regionActor);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var tileKeyValuePair in undoClipboard.Tiles)
|
|
||||||
{
|
|
||||||
var position = tileKeyValuePair.Key;
|
|
||||||
var tile = tileKeyValuePair.Value;
|
|
||||||
var resourceLayerContents = tile.ResourceLayerContents;
|
|
||||||
|
|
||||||
// Clear any existing resources.
|
|
||||||
if (resourceLayer != null && copyFilters.HasFlag(MapCopyFilters.Resources))
|
|
||||||
resourceLayer.ClearResources(position);
|
|
||||||
|
|
||||||
if (copyFilters.HasFlag(MapCopyFilters.Terrain))
|
|
||||||
{
|
|
||||||
map.Tiles[position] = tile.TerrainTile;
|
|
||||||
map.Height[position] = tile.Height;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (copyFilters.HasFlag(MapCopyFilters.Resources) &&
|
|
||||||
resourceLayerContents.HasValue &&
|
|
||||||
!string.IsNullOrWhiteSpace(resourceLayerContents.Value.Type))
|
|
||||||
resourceLayer.AddResource(resourceLayerContents.Value.Type, position, resourceLayerContents.Value.Density);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (copyFilters.HasFlag(MapCopyFilters.Actors))
|
|
||||||
{
|
|
||||||
// Place actors back again.
|
|
||||||
foreach (var actor in undoClipboard.Actors.Values)
|
|
||||||
editorActorLayer.Add(actor);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,6 @@
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using OpenRA.Graphics;
|
using OpenRA.Graphics;
|
||||||
using OpenRA.Mods.Common.EditorBrushes;
|
using OpenRA.Mods.Common.EditorBrushes;
|
||||||
using OpenRA.Mods.Common.Traits;
|
using OpenRA.Mods.Common.Traits;
|
||||||
@@ -34,8 +33,8 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
public LabelWidget DiagonalLabel;
|
public LabelWidget DiagonalLabel;
|
||||||
public LabelWidget ResourceCounterLabel;
|
public LabelWidget ResourceCounterLabel;
|
||||||
|
|
||||||
MapCopyFilters copyFilters = MapCopyFilters.All;
|
MapBlitFilters copyFilters = MapBlitFilters.All;
|
||||||
EditorClipboard? clipboard;
|
EditorBlitSource? clipboard;
|
||||||
|
|
||||||
[ObjectCreator.UseCtor]
|
[ObjectCreator.UseCtor]
|
||||||
public MapEditorSelectionLogic(Widget widget, World world, WorldRenderer worldRenderer)
|
public MapEditorSelectionLogic(Widget widget, World world, WorldRenderer worldRenderer)
|
||||||
@@ -91,39 +90,22 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
var closeAreaSelectionButton = areaEditPanel.Get<ButtonWidget>("SELECTION_CANCEL_BUTTON");
|
var closeAreaSelectionButton = areaEditPanel.Get<ButtonWidget>("SELECTION_CANCEL_BUTTON");
|
||||||
closeAreaSelectionButton.OnClick = () => editor.DefaultBrush.ClearSelection(updateSelectedTab: true);
|
closeAreaSelectionButton.OnClick = () => editor.DefaultBrush.ClearSelection(updateSelectedTab: true);
|
||||||
|
|
||||||
CreateCategoryPanel(MapCopyFilters.Terrain, copyTerrainCheckbox);
|
CreateCategoryPanel(MapBlitFilters.Terrain, copyTerrainCheckbox);
|
||||||
CreateCategoryPanel(MapCopyFilters.Resources, copyResourcesCheckbox);
|
CreateCategoryPanel(MapBlitFilters.Resources, copyResourcesCheckbox);
|
||||||
CreateCategoryPanel(MapCopyFilters.Actors, copyActorsCheckbox);
|
CreateCategoryPanel(MapBlitFilters.Actors, copyActorsCheckbox);
|
||||||
}
|
}
|
||||||
|
|
||||||
EditorClipboard CopySelectionContents()
|
EditorBlitSource CopySelectionContents()
|
||||||
{
|
{
|
||||||
var selection = editor.DefaultBrush.Selection.Area;
|
return EditorBlit.CopyRegionContents(
|
||||||
var source = new CellCoordsRegion(selection.TopLeft, selection.BottomRight);
|
map,
|
||||||
|
editorActorLayer,
|
||||||
var mapTiles = map.Tiles;
|
resourceLayer,
|
||||||
var mapHeight = map.Height;
|
editor.DefaultBrush.Selection.Area,
|
||||||
var mapResources = map.Resources;
|
copyFilters);
|
||||||
|
|
||||||
var previews = new Dictionary<string, EditorActorPreview>();
|
|
||||||
var tiles = new Dictionary<CPos, ClipboardTile>();
|
|
||||||
|
|
||||||
foreach (var cell in source)
|
|
||||||
{
|
|
||||||
if (!mapTiles.Contains(cell))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
tiles.Add(cell, new ClipboardTile(mapTiles[cell], mapResources[cell], resourceLayer?.GetResource(cell), mapHeight[cell]));
|
|
||||||
|
|
||||||
if (copyFilters.HasFlag(MapCopyFilters.Actors))
|
|
||||||
foreach (var preview in editorActorLayer.PreviewsInCellRegion(selection.CellCoords))
|
|
||||||
previews.TryAdd(preview.ID, preview);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new EditorClipboard(selection, previews, tiles);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CreateCategoryPanel(MapCopyFilters copyFilter, CheckboxWidget checkbox)
|
void CreateCategoryPanel(MapBlitFilters copyFilter, CheckboxWidget checkbox)
|
||||||
{
|
{
|
||||||
checkbox.GetText = () => copyFilter.ToString();
|
checkbox.GetText = () => copyFilter.ToString();
|
||||||
checkbox.IsChecked = () => copyFilters.HasFlag(copyFilter);
|
checkbox.IsChecked = () => copyFilters.HasFlag(copyFilter);
|
||||||
|
|||||||
Reference in New Issue
Block a user