Files
OpenRA/OpenRA.Mods.Common/EditorBrushes/EditorResourceBrush.cs
2024-11-03 16:52:47 +02:00

175 lines
5.1 KiB
C#

#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 System.Linq;
using OpenRA.Graphics;
using OpenRA.Mods.Common.Traits;
namespace OpenRA.Mods.Common.Widgets
{
public sealed class EditorResourceBrush : IEditorBrush
{
public readonly string ResourceType;
readonly WorldRenderer worldRenderer;
readonly World world;
readonly EditorViewportControllerWidget editorWidget;
readonly EditorActionManager editorActionManager;
readonly IResourceLayer resourceLayer;
AddResourcesEditorAction action;
bool resourceAdded;
CPos cell;
readonly List<IRenderable> preview = new();
readonly IResourceRenderer[] resourceRenderers;
public EditorResourceBrush(EditorViewportControllerWidget editorWidget, string resourceType, WorldRenderer wr)
{
this.editorWidget = editorWidget;
ResourceType = resourceType;
worldRenderer = wr;
world = wr.World;
editorActionManager = world.WorldActor.Trait<EditorActionManager>();
resourceLayer = world.WorldActor.Trait<IResourceLayer>();
resourceRenderers = world.WorldActor.TraitsImplementing<IResourceRenderer>().ToArray();
cell = wr.Viewport.ViewToWorld(wr.Viewport.WorldToViewPx(Viewport.LastMousePos));
UpdatePreview();
action = new AddResourcesEditorAction(resourceType, resourceLayer);
}
public bool HandleMouseInput(MouseInput mi)
{
// Exclusively uses left and right mouse buttons, but nothing else
if (mi.Button != MouseButton.Left && mi.Button != MouseButton.Right)
return false;
if (mi.Button == MouseButton.Right)
{
if (mi.Event == MouseInputEvent.Up)
{
editorWidget.ClearBrush();
return true;
}
return false;
}
var cell = worldRenderer.Viewport.ViewToWorld(mi.Location);
if (mi.Button == MouseButton.Left && mi.Event != MouseInputEvent.Up && resourceLayer.CanAddResource(ResourceType, cell))
{
action.Add(new CellResource(cell, resourceLayer.GetResource(cell), ResourceType));
resourceAdded = true;
}
else if (resourceAdded && mi.Button == MouseButton.Left && mi.Event == MouseInputEvent.Up)
{
editorActionManager.Add(action);
action = new AddResourcesEditorAction(ResourceType, resourceLayer);
resourceAdded = false;
}
return true;
}
void UpdatePreview()
{
var pos = world.Map.CenterOfCell(cell);
preview.Clear();
preview.AddRange(resourceRenderers.SelectMany(r => r.RenderPreview(worldRenderer, ResourceType, pos)));
}
void IEditorBrush.TickRender(WorldRenderer wr, Actor self)
{
var currentCell = wr.Viewport.ViewToWorld(Viewport.LastMousePos);
if (cell != currentCell)
{
cell = currentCell;
UpdatePreview();
}
}
IEnumerable<IRenderable> IEditorBrush.RenderAboveShroud(Actor self, WorldRenderer wr) { return preview; }
IEnumerable<IRenderable> IEditorBrush.RenderAnnotations(Actor self, WorldRenderer wr) { yield break; }
public void Tick() { }
public void Dispose() { }
}
readonly struct CellResource
{
public readonly CPos Cell;
public readonly ResourceLayerContents OldResourceTile;
public readonly string NewResourceType;
public CellResource(CPos cell, ResourceLayerContents oldResourceTile, string newResourceType)
{
Cell = cell;
OldResourceTile = oldResourceTile;
NewResourceType = newResourceType;
}
}
sealed class AddResourcesEditorAction : IEditorAction
{
[FluentReference("amount", "type")]
const string AddedResource = "notification-added-resource";
public string Text { get; private set; }
readonly IResourceLayer resourceLayer;
readonly string resourceType;
readonly List<CellResource> cellResources = new();
public AddResourcesEditorAction(string resourceType, IResourceLayer resourceLayer)
{
this.resourceType = resourceType;
this.resourceLayer = resourceLayer;
}
public void Execute()
{
}
public void Do()
{
foreach (var resourceCell in cellResources)
{
resourceLayer.ClearResources(resourceCell.Cell);
resourceLayer.AddResource(resourceCell.NewResourceType, resourceCell.Cell, resourceLayer.GetMaxDensity(resourceCell.NewResourceType));
}
}
public void Undo()
{
foreach (var resourceCell in cellResources)
{
resourceLayer.ClearResources(resourceCell.Cell);
if (resourceCell.OldResourceTile.Type != null)
resourceLayer.AddResource(resourceCell.OldResourceTile.Type, resourceCell.Cell, resourceCell.OldResourceTile.Density);
}
}
public void Add(CellResource resourceCell)
{
resourceLayer.ClearResources(resourceCell.Cell);
resourceLayer.AddResource(resourceCell.NewResourceType, resourceCell.Cell, resourceLayer.GetMaxDensity(resourceCell.NewResourceType));
cellResources.Add(resourceCell);
Text = FluentProvider.GetMessage(AddedResource, "amount", cellResources.Count, "type", resourceType);
}
}
}