Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Editor undo redo #16772

Merged
merged 2 commits into from Sep 27, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
96 changes: 69 additions & 27 deletions OpenRA.Mods.Common/EditorBrushes/EditorActorBrush.cs
Expand Up @@ -24,6 +24,7 @@ public sealed class EditorActorBrush : IEditorBrush
readonly WorldRenderer worldRenderer;
readonly World world;
readonly EditorActorLayer editorLayer;
readonly EditorActionManager editorActionManager;
readonly EditorViewportControllerWidget editorWidget;
readonly ActorPreviewWidget preview;
readonly WVec centerOffset;
Expand All @@ -38,6 +39,7 @@ public EditorActorBrush(EditorViewportControllerWidget editorWidget, ActorInfo a
worldRenderer = wr;
world = wr.World;
editorLayer = world.WorldActor.Trait<EditorActorLayer>();
editorActionManager = world.WorldActor.Trait<EditorActionManager>();

Actor = actor;
this.owner = owner;
Expand Down Expand Up @@ -101,33 +103,8 @@ public bool HandleMouseInput(MouseInput mi)
return true;

// Enforce first entry of ValidOwnerNames as owner if the actor has RequiresSpecificOwners
var ownerName = owner.Name;
var specificOwnerInfo = Actor.TraitInfoOrDefault<RequiresSpecificOwnersInfo>();
if (specificOwnerInfo != null && !specificOwnerInfo.ValidOwnerNames.Contains(ownerName))
ownerName = specificOwnerInfo.ValidOwnerNames.First();

var newActorReference = new ActorReference(Actor.Name);
newActorReference.Add(new OwnerInit(ownerName));

newActorReference.Add(new LocationInit(cell));

var ios = Actor.TraitInfoOrDefault<IOccupySpaceInfo>();
if (ios != null && ios.SharesCell)
{
var subcell = editorLayer.FreeSubCellAt(cell);
if (subcell != SubCell.Invalid)
newActorReference.Add(new SubCellInit(subcell));
}

var initDict = newActorReference.InitDict;

if (Actor.HasTraitInfo<IFacingInfo>())
initDict.Add(new FacingInit(facing));

if (Actor.HasTraitInfo<TurretedInfo>())
initDict.Add(new TurretFacingInit(facing));

editorLayer.Add(newActorReference);
var action = new AddActorAction(editorLayer, Actor, cell, owner, facing);
editorActionManager.Add(action);
}

return true;
Expand All @@ -151,4 +128,69 @@ public void Tick()

public void Dispose() { }
}

class AddActorAction : IEditorAction
{
public string Text { get; private set; }

readonly EditorActorLayer editorLayer;
readonly ActorInfo actor;
readonly CPos cell;
readonly PlayerReference owner;
readonly int facing;

EditorActorPreview editorActorPreview;

public AddActorAction(EditorActorLayer editorLayer, ActorInfo actor, CPos cell, PlayerReference owner, int facing)
{
this.editorLayer = editorLayer;
this.actor = actor;
this.cell = cell;
this.owner = owner;
this.facing = facing;
}

public void Execute()
{
Do();
}

public void Do()
{
var ownerName = owner.Name;
var specificOwnerInfo = actor.TraitInfoOrDefault<RequiresSpecificOwnersInfo>();
if (specificOwnerInfo != null && !specificOwnerInfo.ValidOwnerNames.Contains(ownerName))
ownerName = specificOwnerInfo.ValidOwnerNames.First();

var newActorReference = new ActorReference(actor.Name);
newActorReference.Add(new OwnerInit(ownerName));

newActorReference.Add(new LocationInit(cell));

var ios = actor.TraitInfoOrDefault<IOccupySpaceInfo>();
if (ios != null && ios.SharesCell)
{
var subcell = editorLayer.FreeSubCellAt(cell);
if (subcell != SubCell.Invalid)
newActorReference.Add(new SubCellInit(subcell));
}

var initDict = newActorReference.InitDict;

if (actor.HasTraitInfo<IFacingInfo>())
initDict.Add(new FacingInit(facing));

if (actor.HasTraitInfo<TurretedInfo>())
initDict.Add(new TurretFacingInit(facing));

editorActorPreview = editorLayer.Add(newActorReference);

Text = "Added {0} ({1})".F(editorActorPreview.Info.Name, editorActorPreview.ID);
}

public void Undo()
{
editorLayer.Remove(editorActorPreview);
}
}
}
121 changes: 108 additions & 13 deletions OpenRA.Mods.Common/EditorBrushes/EditorCopyPasteBrush.cs
Expand Up @@ -36,6 +36,7 @@ enum State { SelectFirst, SelectSecond, Paste }
readonly EditorSelectionLayer selectionLayer;
readonly EditorActorLayer editorLayer;
readonly Func<MapCopyFilters> getCopyFilters;
readonly EditorActionManager editorActionManager;

State state;
CPos start;
Expand All @@ -46,6 +47,8 @@ public EditorCopyPasteBrush(EditorViewportControllerWidget editorWidget, WorldRe
this.editorWidget = editorWidget;
worldRenderer = wr;

editorActionManager = wr.World.WorldActor.Trait<EditorActionManager>();

selectionLayer = wr.World.WorldActor.Trait<EditorSelectionLayer>();
editorLayer = wr.World.WorldActor.Trait<EditorActorLayer>();
this.getCopyFilters = getCopyFilters;
Expand Down Expand Up @@ -143,8 +146,78 @@ void Copy(CellRegion source, CVec offset)
}
}

var action = new CopyPasteEditorAction(copyFilters, worldRenderer.World.Map, tiles, previews, editorLayer, dest);
editorActionManager.Add(action);
}

public void Tick()
{
var cell = worldRenderer.Viewport.ViewToWorld(Viewport.LastMousePos);
if (state == State.Paste)
{
selectionLayer.SetPasteRegion(cell + (start - end), cell);
return;
}

if (state == State.SelectFirst)
start = end = cell;
else if (state == State.SelectSecond)
end = cell;

selectionLayer.SetCopyRegion(start, end);
}

public void Dispose()
{
selectionLayer.Clear();
}
}

class CopyPasteEditorAction : IEditorAction
{
public string Text { get; private set; }

readonly MapCopyFilters copyFilters;
readonly Dictionary<CPos, Tuple<TerrainTile, ResourceTile, byte>> tiles;
readonly Dictionary<string, ActorReference> previews;
readonly EditorActorLayer editorLayer;
readonly CellRegion dest;
readonly CellLayer<TerrainTile> mapTiles;
readonly CellLayer<byte> mapHeight;
readonly CellLayer<ResourceTile> mapResources;

readonly Queue<UndoCopyPaste> undoCopyPastes = new Queue<UndoCopyPaste>();
readonly Queue<EditorActorPreview> removedActors = new Queue<EditorActorPreview>();
readonly Queue<EditorActorPreview> addedActorPreviews = new Queue<EditorActorPreview>();

public CopyPasteEditorAction(MapCopyFilters copyFilters, Map map,
Dictionary<CPos, Tuple<TerrainTile, ResourceTile, byte>> tiles, Dictionary<string, ActorReference> previews,
EditorActorLayer editorLayer, CellRegion dest)
{
this.copyFilters = copyFilters;
this.tiles = tiles;
this.previews = previews;
this.editorLayer = editorLayer;
this.dest = dest;

mapTiles = map.Tiles;
mapHeight = map.Height;
mapResources = map.Resources;

Text = "Copied {0} tiles".F(tiles.Count);
}

public void Execute()
{
Do();
}

public void Do()
{
foreach (var kv in tiles)
{
undoCopyPastes.Enqueue(new UndoCopyPaste(kv.Key, mapTiles[kv.Key], mapResources[kv.Key], mapHeight[kv.Key]));

if (copyFilters.HasFlag(MapCopyFilters.Terrain))
mapTiles[kv.Key] = kv.Value.Item1;

Expand All @@ -158,33 +231,55 @@ void Copy(CellRegion source, CVec offset)
{
var removeActors = dest.SelectMany(editorLayer.PreviewsAt).Distinct().ToList();
foreach (var preview in removeActors)
{
removedActors.Enqueue(preview);
editorLayer.Remove(preview);
}
}

foreach (var kv in previews)
editorLayer.Add(kv.Value);
addedActorPreviews.Enqueue(editorLayer.Add(kv.Value));
}

public void Tick()
public void Undo()
{
var cell = worldRenderer.Viewport.ViewToWorld(Viewport.LastMousePos);
if (state == State.Paste)
while (undoCopyPastes.Count > 0)
{
selectionLayer.SetPasteRegion(cell + (start - end), cell);
return;
var undoCopyPaste = undoCopyPastes.Dequeue();

var cell = undoCopyPaste.Cell;

if (copyFilters.HasFlag(MapCopyFilters.Terrain))
mapTiles[cell] = undoCopyPaste.MapTile;

if (copyFilters.HasFlag(MapCopyFilters.Resources))
mapResources[cell] = undoCopyPaste.ResourceTile;

mapHeight[cell] = undoCopyPaste.Height;
}

if (state == State.SelectFirst)
start = end = cell;
else if (state == State.SelectSecond)
end = cell;
while (addedActorPreviews.Count > 0)
editorLayer.Remove(addedActorPreviews.Dequeue());
teinarss marked this conversation as resolved.
Show resolved Hide resolved

selectionLayer.SetCopyRegion(start, end);
if (copyFilters.HasFlag(MapCopyFilters.Actors))
while (removedActors.Count > 0)
editorLayer.Add(removedActors.Dequeue());
}
}

public void Dispose()
internal class UndoCopyPaste
{
public CPos Cell { get; private set; }
public TerrainTile MapTile { get; private set; }
public ResourceTile ResourceTile { get; private set; }
public byte Height { get; private set; }

public UndoCopyPaste(CPos cell, TerrainTile mapTile, ResourceTile resourceTile, byte height)
{
selectionLayer.Clear();
Cell = cell;
MapTile = mapTile;
ResourceTile = resourceTile;
Height = height;
}
}
}
75 changes: 72 additions & 3 deletions OpenRA.Mods.Common/EditorBrushes/EditorDefaultBrush.cs
Expand Up @@ -33,6 +33,8 @@ public sealed class EditorDefaultBrush : IEditorBrush
readonly EditorViewportControllerWidget editorWidget;
readonly EditorActorLayer editorLayer;
readonly Dictionary<int, ResourceType> resources;
readonly EditorActionManager editorActionManager;

public EditorActorPreview SelectedActor;
int2 worldPixel;

Expand All @@ -45,6 +47,8 @@ public EditorDefaultBrush(EditorViewportControllerWidget editorWidget, WorldRend
editorLayer = world.WorldActor.Trait<EditorActorLayer>();
resources = world.WorldActor.TraitsImplementing<ResourceType>()
.ToDictionary(r => r.Info.ResourceType, r => r);

editorActionManager = world.WorldActor.Trait<EditorActionManager>();
}

long CalculateActorSelectionPriority(EditorActorPreview actor)
Expand Down Expand Up @@ -74,7 +78,7 @@ public bool HandleMouseInput(MouseInput mi)
var underCursor = editorLayer.PreviewsAt(worldPixel).MinByOrDefault(CalculateActorSelectionPriority);

var mapResources = world.Map.Resources;
ResourceType type;
ResourceType type = null;
if (underCursor != null)
editorWidget.SetTooltip(underCursor.Tooltip);
else if (mapResources.Contains(cell) && resources.TryGetValue(mapResources[cell].Type, out type))
Expand All @@ -97,10 +101,10 @@ public bool HandleMouseInput(MouseInput mi)
editorWidget.SetTooltip(null);

if (underCursor != null && underCursor != SelectedActor)
editorLayer.Remove(underCursor);
editorActionManager.Add(new RemoveActorAction(editorLayer, underCursor));

if (mapResources.Contains(cell) && mapResources[cell].Type != 0)
mapResources[cell] = default(ResourceTile);
editorActionManager.Add(new RemoveResourceAction(mapResources, cell, type));
}

return true;
Expand All @@ -109,4 +113,69 @@ public bool HandleMouseInput(MouseInput mi)
public void Tick() { }
public void Dispose() { }
}

class RemoveActorAction : IEditorAction
{
public string Text { get; private set; }

readonly EditorActorLayer editorActorLayer;
readonly EditorActorPreview actor;

public RemoveActorAction(EditorActorLayer editorActorLayer, EditorActorPreview actor)
{
this.editorActorLayer = editorActorLayer;
this.actor = actor;

Text = "Removed {0} ({1})".F(actor.Info.Name, actor.ID);
}

public void Execute()
{
Do();
}

public void Do()
{
editorActorLayer.Remove(actor);
}

public void Undo()
{
editorActorLayer.Add(actor);
}
}

class RemoveResourceAction : IEditorAction
{
public string Text { get; private set; }

readonly CellLayer<ResourceTile> mapResources;
readonly CPos cell;

ResourceTile resourceTile;

public RemoveResourceAction(CellLayer<ResourceTile> mapResources, CPos cell, ResourceType type)
{
this.mapResources = mapResources;
this.cell = cell;

Text = "Removed {0}".F(type.Info.TerrainType);
}

public void Execute()
{
Do();
}

public void Do()
{
resourceTile = mapResources[cell];
mapResources[cell] = default(ResourceTile);
}

public void Undo()
{
mapResources[cell] = resourceTile;
}
}
}