Better Undo/Redo can merge two steps into one
numberlesstim opened this issue · 3 comments
Steps to reproduce:
- Place 2 tanks attached to each other.
- Move the second (not root tank) using the "Move" tool.
- Undo step 2.
- Observe the tank disappearing instead of getting moved to the original place.
Using Redo after this will add the tank back in at the position it was after moving it, so it appears that two steps have been merged.
This "merging" of steps also happens if you change anything in the paw. For example changing fuellevel, open/close a bay, extend panels, change part variant etc.
I did test this with no other mods installed and verified this does not happen without KSPCF.
Further, if in the above steps you instead move the root tank, it will both remove the second tank and move the root tank back to the original place. Maybe that is a better example.
So...
It's not really a "merging" of steps, but more an oversight of the consequences of inverting the undo/redo logic.
Basically, what the patch does is invert the core undo/redo logic from capturing state after events to capturing it before events.
However, I only moved at which point the state is captured for attach/detach events, not for offset/rotate events, which means you end up with twice the same state captured (in your reproduction steps, you will notice that you have to undo twice at step 3 for step 4 to happen), and the state before offsetting/rotating not being captured at all.
Now that I'm looking at it, there are actually more events that result in the same issue (same repro steps, just change step 2 with the following actions) :
- Switching between part variants
- Removing parts from symmetry
- Adding/removing part actions to action groups, and resetting part actions on the selected part
- Using the reset button of the stage manager
This will need quite a bit of work to fix them all. Basically, we need to move the call to EditorLogic.SetBackup()
before the actions take place (instead of after).
- Offset/Rotate gizmo
The backup is created from callbacks called from the gizmo componentsOnMoveEnd
/OnRotateEnd
methods, triggered when the gizmo is released. The gizmos do have aOn*Start
method, but unfortunately they aren't hooked to a callback, and those are generic components that can potentially be used elsewhere. We can still patch those methods, and compare the gizmo instance to theEditorLogic.gizmo*
fields. - Switching between part variants
Requires moving theSetBackup()
call at the beginning of theModulePartVariants.onVariantChanged
method
Doesn't work because the field is already set whenModulePartVariants.onVariantChanged
, so the changes will be saved to the backup anyway. Alternatively, we patchUIPartActionVariantSelector.SelectVariant()
- Removing parts from symmetry
Requires moving theSetBackup()
call at the beginning of thePart.RemoveFromSymmetry
method - Adding/removing part actions to action groups, and resetting part actions on the selected part
Requires moving theSetBackup()
call at the beginning of theEditorActionGroups
ResetPart
,AddActionToGroup
andRemoveActionFromGroup
methods - Using the reset button of the stage manager
Requires moving theSetBackup()
call at the beginning of theStageManager.Reset
method
Actually after further testing, it seems the backup is already created before the action, so nothing to fix here
Fix released in 1.35.0