Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add very basic skin editor undo / redo support #22506

Merged
merged 18 commits into from
Feb 8, 2023

Conversation

peppy
Copy link
Member

@peppy peppy commented Feb 3, 2023

I made this work and it seems like it might be okay to get it in in this state? I'm hesitant to write tests or spend more time on this due to the fact that #22388 will likely require deep modifications in how change handling is done (assuming we move every target container to a single json structure or similar).

Put another way, I wasn't sure if I should work on undo/redo support before considering the aforementioned restructure, but getting it working to a MVP level was quick enough that I propose we get this out to users so they can benefit from it while the larger restructuring tasks happen in the background.

Of note: if any new elements are added or removed, all elements will be recycled. This is the simplest way of handling this, especially since we don't have any ID for tracking movement of elements around. There may be room to use SkinnableTargetContainer's bindable Components list to better handle this in the future.

osu.2023-02-03.at.10.02.43.mp4

PRing this to get some initial feedback on direction.

Issues of note:

  • Changes to SettingsSourceAttributes do not trigger state saves.

Copy link
Collaborator

@bdach bdach left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generally code seems inoffensive on a read-through, some structure issues from me though

Comment on lines 11 to +16
namespace osu.Game.Screens.Edit
{
/// <summary>
/// Tracks changes to the <see cref="Editor"/>.
/// </summary>
public partial class EditorChangeHandler : TransactionalCommitComponent, IEditorChangeHandler
public abstract partial class EditorChangeHandler : TransactionalCommitComponent, IEditorChangeHandler
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With the way this is being abstracted away further, I'm not sure that the namespace or the xmldoc here make much sense.

Namespace comment also applies to IEditorChangeHandler and TransactionalCommitComponent.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Honestly wasn't sure if we should still keep the underlying TransactionalCommitComponent, but left it there to reduce changes for the time being. I'd be okay with moving this to another namespace, but I'm honestly not sure where they should exist. Open to suggestion.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's leave this where it is until the dust settles and we see the final shape of the skin editor better for now I guess.

osu.Game/Screens/Edit/EditorChangeHandler.cs Outdated Show resolved Hide resolved
osu.Game/Skinning/ISkinnableTarget.cs Outdated Show resolved Hide resolved
@peppy peppy added the next release Pull requests which are almost there. We'll aim to get them in the next release, but no guarantees! label Feb 6, 2023
@bdach bdach self-requested a review February 6, 2023 17:17
@bdach
Copy link
Collaborator

bdach commented Feb 6, 2023

I can break this pretty hard using the "scene library" toolbar.

  1. Start at main menu
  2. Click the "Gameplay" scene from the library
  3. Wait for it to load
  4. Make any change
  5. Notice that you can undo twice, and the second undo erases every component from the skin
2023-02-06.19-08-59.mp4

It appears that the initial save in the skin editor change handler fails when doing this (resulting json is {}), because the firstTarget is null.

Careful not to trip over #22263 and #17391 when reproducing.

I also got this to crash once on a mismatched EndChange() without StartChange() call, but I'm not completely sure what I did to make it happen, so I'm not sure I'll be able to make it happen again.

@bdach
Copy link
Collaborator

bdach commented Feb 6, 2023

Never mind, I repro'd the second thing immediately.

  1. Go to gameplay
  2. Seek track to be close to end
  3. Open skin editor
  4. Select a component and start dragging it with left mouse
  5. Wait for map to end, progressing to results screen
  6. Release mouse to 💥
2023-02-06.19-17-28.mp4

Crash trace is, unsurprisingly:

Unhandled exception. System.InvalidOperationException: Cannot call EndChange without a previous call to BeginChange.
   at osu.Game.Screens.Edit.TransactionalCommitComponent.EndChange() in /home/dachb/Documents/opensource/osu/osu.Game/Screens/Edit/TransactionalCommitComponent.cs:line 49
   at osu.Game.Overlays.SkinEditor.SkinEditor.EndChange() in /home/dachb/Documents/opensource/osu/osu.Game/Overlays/SkinEditor/SkinEditor.cs:line 485
   at osu.Game.Screens.Edit.Compose.Components.BlueprintContainer`1.OnDragEnd(DragEndEvent e) in /home/dachb/Documents/opensource/osu/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs:line 212
   at osu.Framework.Graphics.Drawable.TriggerEvent(UIEvent e)
   at System.Linq.Enumerable.TryGetFirst[TSource](IEnumerable`1 source, Func`2 predicate, Boolean& found)

Copy link
Collaborator

@bdach bdach left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see above

@peppy
Copy link
Member Author

peppy commented Feb 7, 2023

It appears that the initial save in the skin editor change handler fails when doing this (resulting json is {}), because the firstTarget is null.

This actually goes a bit deeper. firstTarget is non-null but the components haven't finished loading at the point the state is saved. SkinBlueprintContainer gets around this by watching for changes in components, but it has an easier task because it doesn't need to know which change is the initial one.. so if we used that method it would be best-effort..

foreach (var targetContainer in targetContainers)
{
var bindableList = new BindableList<ISkinnableDrawable> { BindTarget = targetContainer.Components };
bindableList.BindCollectionChanged(componentsChanged, true);
targetComponents.Add(bindableList);
}

Edit: And of course, the Components list is populated after async load of the components.

@peppy
Copy link
Member Author

peppy commented Feb 7, 2023

I've fixed both the issues you found. See what you think of the solutions.

@bdach
Copy link
Collaborator

bdach commented Feb 7, 2023

Changes look okay (the ensureStateSaved() thing feels a little wonky but looks correct), issues look fixed, but e162fd5 broke tests and 0320ba7 broke code quality.

On a quick look the first one may not be very easy to fix, may just need to update assertions? Second issue should be trivial to resolve (not sure where that conditional access in the ctor there even comes from).

@bdach bdach self-requested a review February 8, 2023 17:33
@bdach
Copy link
Collaborator

bdach commented Feb 8, 2023

Seems solid enough for an initial implementation as far as I'm concerned.

I did find one issue with the "Revert to default" option and how it interacts with undo, but I think it's relatively minor and don't really want to be blocking this PR too much longer, so I'll open a follow-up issue for it.

@bdach bdach enabled auto-merge February 8, 2023 17:45
@bdach bdach merged commit 2873905 into ppy:master Feb 8, 2023
@bdach
Copy link
Collaborator

bdach commented Feb 8, 2023

Tracking aforementioned issue as #22562

@peppy peppy deleted the skin-editor-undo-support branch February 9, 2023 05:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area:skin-editor next release Pull requests which are almost there. We'll aim to get them in the next release, but no guarantees! size/L
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add ability to undo in skin editor
2 participants