Skip to content

Commit

Permalink
Editor actor move
Browse files Browse the repository at this point in the history
  • Loading branch information
CDVoidwalker authored and drogoganor committed Feb 12, 2024
1 parent 2fe13fe commit 88bd693
Show file tree
Hide file tree
Showing 7 changed files with 188 additions and 29 deletions.
92 changes: 89 additions & 3 deletions OpenRA.Mods.Common/EditorBrushes/EditorDefaultBrush.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,9 @@ public sealed class EditorDefaultBrush : IEditorBrush
readonly EditorActorLayer editorLayer;
readonly EditorActionManager editorActionManager;
readonly IResourceLayer resourceLayer;
readonly EditorCursorLayer cursorLayer;

public bool ActorFreeMove;
public CellRegion CurrentDragBounds => selectionBounds ?? Selection.Area;

public EditorSelection Selection { get; private set; } = new();
Expand All @@ -53,6 +55,8 @@ public sealed class EditorDefaultBrush : IEditorBrush
int2? selectionStartLocation;
CPos? selectionStartCell;
int2 worldPixel;
bool draggingActor;
MoveActorAction moveAction;

public EditorDefaultBrush(EditorViewportControllerWidget editorWidget, WorldRenderer wr)
{
Expand All @@ -63,6 +67,7 @@ public EditorDefaultBrush(EditorViewportControllerWidget editorWidget, WorldRend
editorLayer = world.WorldActor.Trait<EditorActorLayer>();
editorActionManager = world.WorldActor.Trait<EditorActionManager>();
resourceLayer = world.WorldActor.TraitOrDefault<IResourceLayer>();
cursorLayer = world.WorldActor.Trait<EditorCursorLayer>();
}

long CalculateActorSelectionPriority(EditorActorPreview actor)
Expand Down Expand Up @@ -126,16 +131,44 @@ public bool HandleMouseInput(MouseInput mi)
else
editorWidget.SetTooltip(null);

// Actor drag.
if (mi.Button == MouseButton.Left)
{
if (mi.Event == MouseInputEvent.Down && underCursor != null && (ActorFreeMove || underCursor == Selection.Actor))
{
editorWidget.SetTooltip(null);
var cellViewPx = worldRenderer.Viewport.WorldToViewPx(worldRenderer.ScreenPosition(world.Map.CenterOfCell(cell)));
var pixelOffset = cellViewPx - mi.Location;
var cellOffset = underCursor.Location - cell;
moveAction = new MoveActorAction(underCursor, cursorLayer, worldRenderer, pixelOffset, cellOffset);
draggingActor = true;
return false;
}
else if (mi.Event == MouseInputEvent.Up && draggingActor)
{
editorWidget.SetTooltip(null);
draggingActor = false;
editorActionManager.Add(moveAction);
moveAction = null;
return false;
}
else if (mi.Event == MouseInputEvent.Move && draggingActor)
{
editorWidget.SetTooltip(null);
moveAction.Move(mi.Location);
return false;
}
}

// Selection box drag.
if (selectionStartLocation != null &&
if (mi.Event == MouseInputEvent.Move &&
selectionStartLocation != null &&
(selectionBounds != null || (mi.Location - selectionStartLocation.Value).LengthSquared > MinMouseMoveBeforeDrag))
{
selectionStartCell ??= worldRenderer.Viewport.ViewToWorld(selectionStartLocation.Value);

var topLeft = new CPos(Math.Min(selectionStartCell.Value.X, cell.X), Math.Min(selectionStartCell.Value.Y, cell.Y));
var bottomRight = new CPos(Math.Max(selectionStartCell.Value.X, cell.X), Math.Max(selectionStartCell.Value.Y, cell.Y));
var width = bottomRight.X - topLeft.X;
var height = bottomRight.Y - topLeft.Y;
var gridType = worldRenderer.World.Map.Grid.Type;

// We've dragged enough to capture more than one cell, make a selection box.
Expand Down Expand Up @@ -368,6 +401,59 @@ public void Undo()
}
}

sealed class MoveActorAction : IEditorAction
{
[TranslationReference("id", "x1", "y1", "x2", "y2")]
const string MovedActor = "notification-moved-actor";

public string Text { get; private set; }

readonly EditorActorPreview actor;
readonly EditorCursorLayer layer;
readonly WorldRenderer worldRenderer;
readonly int2 pixelOffset;
readonly CVec cellOffset;
readonly CPos from;

CPos to;

public MoveActorAction(
EditorActorPreview actor,
EditorCursorLayer layer,
WorldRenderer worldRenderer,
int2 pixelOffset,
CVec cellOffset)
{
this.actor = actor;
this.layer = layer;
this.worldRenderer = worldRenderer;
this.pixelOffset = pixelOffset;
this.cellOffset = cellOffset;

from = actor.Location;
}

public void Execute() { }

public void Do()
{
layer.MoveActor(actor, to);
}

public void Undo()
{
layer.MoveActor(actor, from);
}

public void Move(int2 pixelTo)
{
to = worldRenderer.Viewport.ViewToWorld(pixelTo + pixelOffset) + cellOffset;
layer.MoveActor(actor, to);

Text = TranslationProvider.GetString(MovedActor, Translation.Arguments("id", actor.ID, "x1", from.X, "y1", from.Y, "x2", to.X, "y2", to.Y));
}
}

sealed class RemoveResourceAction : IEditorAction
{
[TranslationReference("type")]
Expand Down
62 changes: 38 additions & 24 deletions OpenRA.Mods.Common/Traits/World/EditorActorPreview.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,6 @@ public class EditorActorPreview : IEquatable<EditorActorPreview>
{
public readonly string DescriptiveName;
public readonly ActorInfo Info;
public readonly WPos CenterPosition;
public readonly IReadOnlyDictionary<CPos, SubCell> Footprint;
public readonly Rectangle Bounds;
public readonly SelectionBoxAnnotationRenderable SelectionBox;

public string Tooltip =>
(tooltip == null ? " < " + Info.Name + " >" : TranslationProvider.GetString(tooltip.Name)) + "\n" + Owner.Name + " (" + Owner.Faction + ")"
Expand All @@ -38,18 +34,23 @@ public class EditorActorPreview : IEquatable<EditorActorPreview>

public string ID { get; set; }
public PlayerReference Owner { get; set; }
public SubCell SubCell { get; }
public WPos CenterPosition { get; set; }
public IReadOnlyDictionary<CPos, SubCell> Footprint { get; private set; }
public Rectangle Bounds { get; private set; }
public bool Selected { get; set; }
public Color RadarColor { get; private set; }
readonly RadarColorFromTerrainInfo terrainRadarColorInfo;
public CPos Location { get; private set; }

readonly RadarColorFromTerrainInfo terrainRadarColorInfo;
readonly WorldRenderer worldRenderer;
readonly TooltipInfoBase tooltip;
IActorPreview[] previews;
readonly ActorReference reference;
readonly Action<CPos> onCellEntryChanged;
readonly Dictionary<INotifyEditorPlacementInfo, object> editorData = new();

SelectionBoxAnnotationRenderable selectionBox;
IActorPreview[] previews;
Action<CPos> onCellEntryChanged;

public EditorActorPreview(WorldRenderer worldRenderer, string id, ActorReference reference, PlayerReference owner)
{
ID = id;
Expand All @@ -68,18 +69,7 @@ public EditorActorPreview(WorldRenderer worldRenderer, string id, ActorReference
throw new InvalidDataException($"Actor {id} of unknown type {reference.Type.ToLowerInvariant()}");

CenterPosition = PreviewPosition(world, reference);

var location = reference.Get<LocationInit>().Value;
var ios = Info.TraitInfoOrDefault<IOccupySpaceInfo>();

var subCellInit = reference.GetOrDefault<SubCellInit>();
var subCell = subCellInit != null ? subCellInit.Value : SubCell.Any;

var occupiedCells = ios?.OccupiedCells(Info, location, subCell);
if (occupiedCells == null || occupiedCells.Count == 0)
Footprint = new Dictionary<CPos, SubCell>() { { location, SubCell.FullCell } };
else
Footprint = occupiedCells;
GenerateFootprint();

tooltip = Info.TraitInfos<EditorOnlyTooltipInfo>().FirstOrDefault(info => info.EnabledByDefault) as TooltipInfoBase
?? Info.TraitInfos<TooltipInfo>().FirstOrDefault(info => info.EnabledByDefault);
Expand All @@ -91,19 +81,36 @@ public EditorActorPreview(WorldRenderer worldRenderer, string id, ActorReference
terrainRadarColorInfo = Info.TraitInfoOrDefault<RadarColorFromTerrainInfo>();
UpdateRadarColor();

// Bounds are fixed from the initial render.
// If this is a problem, then we may need to fetch the area from somewhere else
GenerateBounds();
}

void GenerateBounds()
{
var r = previews.SelectMany(p => p.ScreenBounds(worldRenderer, CenterPosition));

Bounds = r.Union();

SelectionBox = new SelectionBoxAnnotationRenderable(new WPos(CenterPosition.X, CenterPosition.Y, 8192),
selectionBox = new SelectionBoxAnnotationRenderable(new WPos(CenterPosition.X, CenterPosition.Y, 8192),
new Rectangle(Bounds.X, Bounds.Y, Bounds.Width, Bounds.Height), Color.White);

// TODO: updating all actors on the map is not very efficient.
onCellEntryChanged = _ => GeneratePreviews();
}

void GenerateFootprint()
{
Location = reference.Get<LocationInit>().Value;
var ios = Info.TraitInfoOrDefault<IOccupySpaceInfo>();
var subCellInit = reference.GetOrDefault<SubCellInit>();
var subCell = subCellInit != null ? subCellInit.Value : SubCell.Any;

var occupiedCells = ios?.OccupiedCells(Info, Location, subCell);
if (occupiedCells == null || occupiedCells.Count == 0)
Footprint = new Dictionary<CPos, SubCell>() { { Location, SubCell.FullCell } };
else
Footprint = occupiedCells;
}

public void Tick()
{
foreach (var p in previews)
Expand Down Expand Up @@ -131,7 +138,7 @@ public IEnumerable<IRenderable> Render()
public IEnumerable<IRenderable> RenderAnnotations()
{
if (Selected)
yield return SelectionBox;
yield return selectionBox;
}

public void AddedToEditor()
Expand Down Expand Up @@ -214,6 +221,13 @@ public void RemovedFromEditor()
GeneratePreviews();
}

public void RebuildVisuals()
{
CenterPosition = PreviewPosition(worldRenderer.World, reference);
GenerateFootprint();
GenerateBounds();
}

public MiniYaml Save()
{
bool SaveInit(ActorInit init)
Expand Down
16 changes: 16 additions & 0 deletions OpenRA.Mods.Common/Traits/World/EditorCursorLayer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,22 @@ public int SetActor(WorldRenderer wr, ActorInfo actor, PlayerReference owner)
return ++CurrentToken;
}

public void MoveActor(EditorActorPreview preview, CPos location)
{
editorLayer.Remove(preview);
preview.ReplaceInit(new LocationInit(location));
var ios = preview.Info.TraitInfoOrDefault<IOccupySpaceInfo>();
if (ios != null && ios.SharesCell)
{
var actorSubCell = editorLayer.FreeSubCellAt(location);
if (actorSubCell != SubCell.Invalid)
preview.ReplaceInit(new SubCellInit(actorSubCell));
}

preview.RebuildVisuals();
editorLayer.Add(preview);
}

public int SetTerrainTemplate(WorldRenderer wr, TerrainTemplateInfo template)
{
terrainOrResourceCell = wr.Viewport.ViewToWorld(wr.Viewport.WorldToViewPx(Viewport.LastMousePos));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#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.Widgets;

namespace OpenRA.Mods.Common.Widgets.Logic.Ingame
{
public class EditorMoveActorHotkeyLogic : ChromeLogic
{
EditorViewportControllerWidget editor;

[ObjectCreator.UseCtor]
public EditorMoveActorHotkeyLogic(Widget widget, ModData modData, Dictionary<string, MiniYaml> logicArgs)
{
var keyhandler = widget.Get<LogicKeyListenerWidget>("GLOBAL_KEYHANDLER");
keyhandler.AddHandler(e =>
{
// Hotkeys do not support only a modifier key; actor move override key will have to be hardcoded for now
if (e.Key != Keycode.LSHIFT)
return false;
if (editor == null)
{
var worldRoot = Ui.Root.Get<ContainerWidget>("EDITOR_WORLD_ROOT");
editor = worldRoot.Get<EditorViewportControllerWidget>("MAP_EDITOR");
}
editor.DefaultBrush.ActorFreeMove = e.Event == KeyInputEvent.Down;
return false;
});
}
}
}
2 changes: 1 addition & 1 deletion mods/cnc/chrome/editor.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ Container@EDITOR_ROOT:
Logic: LoadMapEditorLogic
Children:
LogicKeyListener@GLOBAL_KEYHANDLER:
Logic: MusicHotkeyLogic, ScreenshotHotkeyLogic, MuteHotkeyLogic, EditorQuickSaveHotkeyLogic
Logic: MusicHotkeyLogic, ScreenshotHotkeyLogic, MuteHotkeyLogic, EditorQuickSaveHotkeyLogic, EditorMoveActorHotkeyLogic
StopMusicKey: StopMusic
PauseMusicKey: PauseMusic
PrevMusicKey: PrevMusic
Expand Down
2 changes: 1 addition & 1 deletion mods/common/chrome/editor.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ Container@EDITOR_ROOT:
Logic: LoadMapEditorLogic
Children:
LogicKeyListener@GLOBAL_KEYHANDLER:
Logic: MusicHotkeyLogic, ScreenshotHotkeyLogic, MuteHotkeyLogic, EditorQuickSaveHotkeyLogic
Logic: MusicHotkeyLogic, ScreenshotHotkeyLogic, MuteHotkeyLogic, EditorQuickSaveHotkeyLogic, EditorMoveActorHotkeyLogic
StopMusicKey: StopMusic
PauseMusicKey: PauseMusic
PrevMusicKey: PrevMusic
Expand Down
1 change: 1 addition & 0 deletions mods/common/languages/en.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -810,6 +810,7 @@ notification-selected-actor = Selected actor { $id }
notification-cleared-selection = Cleared selection
notification-removed-actor = Removed { $name } ({ $id })
notification-removed-resource = Removed { $type }
notification-moved-actor = Moved { $id } from { $x1 },{ $y1 } to { $x2 },{ $y2 }
## EditorResourceBrush
notification-added-resource =
Expand Down

0 comments on commit 88bd693

Please sign in to comment.