From 102e251fda6bb675b1e13612ba84f081ef99e5d0 Mon Sep 17 00:00:00 2001 From: biwa <6475593+biwa@users.noreply.github.com> Date: Thu, 3 Jun 2021 12:02:51 +0200 Subject: [PATCH] Improved solution for issue #573 to not destroy the undo history when no player start is present --- Source/Core/Editing/ClassicMode.cs | 17 +++++++++++------ Source/Core/Map/MapSet.cs | 20 ++++++++++++++++++++ Source/Core/Map/Thing.cs | 10 +++++++--- 3 files changed, 38 insertions(+), 9 deletions(-) diff --git a/Source/Core/Editing/ClassicMode.cs b/Source/Core/Editing/ClassicMode.cs index e6b59318..97217c3e 100755 --- a/Source/Core/Editing/ClassicMode.cs +++ b/Source/Core/Editing/ClassicMode.cs @@ -704,6 +704,8 @@ namespace CodeImp.DoomBuilder.Editing { if(testFromCurrentPosition) { + bool oldignorepropchanges = General.Map.UndoRedo.IgnorePropChanges; + if (!mouseinside) { General.MainWindow.DisplayStatus(StatusType.Warning, "Can't test from current position: mouse is outside editing window!"); @@ -753,15 +755,16 @@ namespace CodeImp.DoomBuilder.Editing if(start == null) // biwa. If there's no existing valid player start create one { - // Create an undo snapshot that can will be revoked in OnMapTestEnd to remove the temporary player start - // This has to be done because just creating and deleting the thing will screw with the undo/redo. See https://github.com/jewalky/UltimateDoomBuilder/issues/573 - General.Map.UndoRedo.CreateUndo("Create temporary player thing"); - playerStartIsTempThing = true; - start = General.Map.Map.CreateThing(); + + // We have to circumvent the undo manager when creating the temporary player start, otherwise undoing + // stuff will crash: https://github.com/jewalky/UltimateDoomBuilder/issues/573 + start = General.Map.Map.CreateTempThing(); if (start != null) { + // We have to ignore property changes, otherwise the undo manager will try to record the changes + General.Map.UndoRedo.IgnorePropChanges = true; General.Settings.ApplyDefaultThingSettings(start); start.Type = 1; } @@ -782,6 +785,8 @@ namespace CodeImp.DoomBuilder.Editing //everything should be valid, let's move player start here start.Move(new Vector3D(mousemappos.x, mousemappos.y, s.FloorHeight)); + + General.Map.UndoRedo.IgnorePropChanges = oldignorepropchanges; } return true; @@ -793,7 +798,7 @@ namespace CodeImp.DoomBuilder.Editing { if (playerStartIsTempThing) // biwa { - General.Map.UndoRedo.WithdrawUndo(); + General.Map.Map.RemoveThing(playerStart.Index); } else { diff --git a/Source/Core/Map/MapSet.cs b/Source/Core/Map/MapSet.cs index 661a952d..1b37ec71 100755 --- a/Source/Core/Map/MapSet.cs +++ b/Source/Core/Map/MapSet.cs @@ -678,6 +678,26 @@ namespace CodeImp.DoomBuilder.Map return t; } + /// + /// This creates a temporary thing. The difference to normal thing creation is that the creation will not be recorded by the undo manager. + /// This should only be used in very specific cases, like creating a temporary player start for the "test from current position" action + /// + /// The new thing + internal Thing CreateTempThing() + { + if (numthings == General.Map.FormatInterface.MaxThings) + { + General.Interface.DisplayStatus(StatusType.Warning, "Failed to complete operation: maximum number of things reached."); + return null; + } + + // Make the thing + Thing t = new Thing(this, numthings, false); + AddItem(t, ref things, numthings, ref numthings); + return t; + + } + // This increases the size of the array to add an item private void AddItem(T item, ref T[] array, int index, ref int counter) where T: MapElement { diff --git a/Source/Core/Map/Thing.cs b/Source/Core/Map/Thing.cs index fd37bf52..ecd8c524 100755 --- a/Source/Core/Map/Thing.cs +++ b/Source/Core/Map/Thing.cs @@ -86,6 +86,9 @@ namespace CodeImp.DoomBuilder.Map private bool fixedsize; private bool directional; //mxd. If true, we need to render an arrow + // biwa. This should only ever be used for temporary player starts for the "test from current position" action + private bool recordundo; + // Rendering private int lastProcessed; @@ -126,7 +129,7 @@ namespace CodeImp.DoomBuilder.Map #region ================== Constructor / Disposer // Constructor - internal Thing(MapSet map, int listindex) + internal Thing(MapSet map, int listindex, bool recordundo = true) { // Initialize this.elementtype = MapElementType.THING; //mxd @@ -137,8 +140,9 @@ namespace CodeImp.DoomBuilder.Map this.scaleX = 1.0f; this.scaleY = 1.0f; this.spritescale = new SizeF(1.0f, 1.0f); + this.recordundo = recordundo; - if(map == General.Map.Map) + if(map == General.Map.Map && recordundo) General.Map.UndoRedo.RecAddThing(this); // We have no destructor @@ -151,7 +155,7 @@ namespace CodeImp.DoomBuilder.Map // Not already disposed? if(!isdisposed) { - if(map == General.Map.Map) + if(map == General.Map.Map && recordundo) General.Map.UndoRedo.RecRemThing(this); // Remove from main list