Improved solution for issue #573 to not destroy the undo history when no player start is present

This commit is contained in:
biwa 2021-06-03 12:02:51 +02:00
parent c35a409f54
commit 102e251fda
3 changed files with 38 additions and 9 deletions

View file

@ -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
{

View file

@ -678,6 +678,26 @@ namespace CodeImp.DoomBuilder.Map
return t;
}
/// <summary>
/// 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
/// </summary>
/// <returns>The new thing</returns>
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>(T item, ref T[] array, int index, ref int counter) where T: MapElement
{

View file

@ -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