Open Archytas79 opened 3 months ago
This is not really a bug. Any component can have very complex effects and changes on the data model - the undo system generally doesn't capture those complex effects, because they... well they can be very complex.
Making Undo system generically undo all implicit changes is unfortunately not feasible and would likely incur a significant performance impact as well.
Is there a solution to needing to reload the world in case these implicit changes need to be undone?
I don't think it's as simple as being impossible considering Unity, Godot, Unreal, Blender, etc etc have properly scoped transactions. I've programmed editor utilities in them for professional settings it's definitely possible to do this performant. The current scope for what counts as undo/redo seems pretty adequate. I don't know the internals of the resonite project, but it really seems like it should be possible
Everything is possible with significant enough effort, but question is - is it worth it?
One particular challenge unique to Resonite compared to editors is that there's lots of things happening all the time in parallel, not just the changes you're performing - the data model is being mutated by lots of other things - e.g. your avatar, other changes, the inspector tools themselves that are part of the data model.
The undo system would have to separate those changes out from the ones caused directly by the component or whatever action you did - but some can have complex cascading effects on things, compared to a more traditional editor when there isn't much other changing other than whatever action you invoke.
That is fair but if the alternative is closing and reopening the last save of the world it sounds pretty useful to implement regardless of the complexity. It doesn't seem reasonable to try to build things with others in a shared world if accidentally tweaking a component wrong irreversibly changes things, requiring people to notify the host, have them close and reload the world, and have everyone join, and hope the last save wasn't to far back and didn't include any errors. It doesn't foster an experimentive atmosphere for a mistake to be a hassle to undo.
I understand that it's a unique problem set for a living editor world like Resonite but this problem is also really bad without a clean solution besides scoping transactions like other editors do.
How do you separate things out though? You would similarly have a problem if you try to undo and it undoes a bunch of other changes that you haven't meant to.
I think having to close and reload the world can be a bit extreme, especially if it's just a single value that changed. We could look for a more narrowly scoped version of this where the changes and their consequences are known and expand it that way.
It wouldn't work generically, but would help make things a bit better.
Just gonna through my two cents in: Small changes can have a big impact, take one small change, setting a value to true... which also happens to be connected to a while loop- BAM! Infinite loop and a restart is needed. I know the scenario I presented is also extreme (and there are a least 2 issues on here that would solve that as the primary solution), but small things like that could matter too, and undoing something similar to that may help.
In my mind I feel like there could be some sort of system where you can temporarily (important cause you probably don't want 50 people with undoable avatars in a world, or accidentally leaving it on) mark components/values as "undoable" and they will be tracked as much as necessary?
Not sure if that'd be a bad solution for this problem or too complex but that was just kinda what I thought of reading through this
I'm imagining it'd scope changes from specific actions from specific contexts if needed. For example it could be constrained to only deltaing via manual actions while using tools that have deep undo as an enabled property.
On Thu, Jul 25, 2024, 5:29 PM Dusty-Sprinkles @.***> wrote:
In my mind I feel like there could be some sort of system where you can temporarily (important cause you probably don't want 50 people with undoable avatars in a world, or accidentally leaving it on) mark components/values as "undoable" and they will be tracked as much as necessary?
Not sure if that'd be a bad solution for this problem or too complex but that was just kinda what I thought of reading through this
— Reply to this email directly, view it on GitHub https://github.com/Yellow-Dog-Man/Resonite-Issues/issues/2667#issuecomment-2251655390, or unsubscribe https://github.com/notifications/unsubscribe-auth/ANJFYUZ6QUKON6CU77GJ4CDZOGJ47AVCNFSM6AAAAABLO3B2WCVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDENJRGY2TKMZZGA . You are receiving this because you authored the thread.Message ID: @.***>
None of this really helps here though. The main question is - how to actually track the changes? How do you determine what is a tracked change and what is not?
E.g. say you add a component that drives a value. There's a number of other things that then react to this driven value and result in a number of cascading changes as well.
Those things are non-trivial to track and to even determine they might be result of that particular change, which is the main challenge here.
We could more conceivably track more "direct changes" within a limited scope and stop it there. It means there would still be things that won't be tracked via the undo system, but there will be more of them. But it's also tricky to do that in some generic manner, we don't have a framework to do that right now.
Generally with engines they use a system of registering variable deltas in a stack and using something as a flag to know the checkpoints to go back to. This is usually done by assuming a distinct user action is a flag that saves the previous state of variables effected until the action is completed, aka the end of initialization and before any tick effects kick in.
There's a few key optimizations that deal with recursive concerns - mainly limiting the entry to once per variable, just keeping track from before the user action and the latest result. Unreal limits this logging to variables that are exposed to the engine.
It should go a step further and allow the component to be able to tel the undo manager what additional variables should be saved because this component will edit them.
I'm not concerned about implementation being possible because every engine scopes transactions in some manner similar to this, and because it's only invoked in editor contexts it doesn't hamper runtime. AFAIK Resonite already tracks Undo/Redo to acceptable actions for this kind of thing.
On Sat, Jul 27, 2024, 9:40 AM Trevor Morgan @.***> wrote:
I'm imagining it'd scope changes from specific actions from specific contexts if needed. For example it could be constrained to only deltaing via manual actions while using tools that have deep undo as an enabled property.
On Thu, Jul 25, 2024, 5:29 PM Dusty-Sprinkles @.***> wrote:
In my mind I feel like there could be some sort of system where you can temporarily (important cause you probably don't want 50 people with undoable avatars in a world, or accidentally leaving it on) mark components/values as "undoable" and they will be tracked as much as necessary?
Not sure if that'd be a bad solution for this problem or too complex but that was just kinda what I thought of reading through this
— Reply to this email directly, view it on GitHub https://github.com/Yellow-Dog-Man/Resonite-Issues/issues/2667#issuecomment-2251655390, or unsubscribe https://github.com/notifications/unsubscribe-auth/ANJFYUZ6QUKON6CU77GJ4CDZOGJ47AVCNFSM6AAAAABLO3B2WCVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDENJRGY2TKMZZGA . You are receiving this because you authored the thread.Message ID: @.***>
The other method is more similar to snapshotting where it solely uses a list of variables it will change and the engine snapshots their values into the undo, then snapshots them again once a tick is initialized. This one kinda sucks because it's a lot of points of failiure even though it's more optimized lol
On Sat, Jul 27, 2024, 10:01 AM Trevor Morgan @.***> wrote:
Generally with engines they use a system of registering variable deltas in a stack and using something as a flag to know the checkpoints to go back to. This is usually done by assuming a distinct user action is a flag that saves the previous state of variables effected until the action is completed, aka the end of initialization and before any tick effects kick in.
There's a few key optimizations that deal with recursive concerns - mainly limiting the entry to once per variable, just keeping track from before the user action and the latest result. Unreal limits this logging to variables that are exposed to the engine.
It should go a step further and allow the component to be able to tel the undo manager what additional variables should be saved because this component will edit them.
I'm not concerned about implementation being possible because every engine scopes transactions in some manner similar to this, and because it's only invoked in editor contexts it doesn't hamper runtime. AFAIK Resonite already tracks Undo/Redo to acceptable actions for this kind of thing.
On Sat, Jul 27, 2024, 9:40 AM Trevor Morgan @.***> wrote:
I'm imagining it'd scope changes from specific actions from specific contexts if needed. For example it could be constrained to only deltaing via manual actions while using tools that have deep undo as an enabled property.
On Thu, Jul 25, 2024, 5:29 PM Dusty-Sprinkles @.***> wrote:
In my mind I feel like there could be some sort of system where you can temporarily (important cause you probably don't want 50 people with undoable avatars in a world, or accidentally leaving it on) mark components/values as "undoable" and they will be tracked as much as necessary?
Not sure if that'd be a bad solution for this problem or too complex but that was just kinda what I thought of reading through this
— Reply to this email directly, view it on GitHub https://github.com/Yellow-Dog-Man/Resonite-Issues/issues/2667#issuecomment-2251655390, or unsubscribe https://github.com/notifications/unsubscribe-auth/ANJFYUZ6QUKON6CU77GJ4CDZOGJ47AVCNFSM6AAAAABLO3B2WCVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDENJRGY2TKMZZGA . You are receiving this because you authored the thread.Message ID: @.***>
This doesn't help here though, it's too broad/vague to apply to how Resonite works. Notably this part:
I'm not concerned about implementation being possible because every engine scopes transactions in some manner similar to this, and because it's only invoked in editor contexts it doesn't hamper runtime. AFAIK Resonite already tracks Undo/Redo to acceptable actions for this kind of thing.
Like I mentioned above, the unique challenge with Resonite is there's no distinct editor/runtime context - it's all the same. It's something you just can't do with Resonite.
FrooxEngine (which Resonite runs on) is very unique/novel as far as engines go, so this requires a bit different approach. It's clear that the values need to be snapshotted - this already happens when you make direct changes.
The problem we're dealing here with is figuring out which variables to snapshot. Components can vary wildly in behavior and implementation, so it's hard to do a completely generic way.
The other alternative is to add manual instrumentation - but there are thousands of components, if not more, so this would present significant burden.
What would most likely work is a system that would listen to some of the events (like when something becomes driven) within a certain call (e.g. when OnAttach is being executed). It would work for some things. But not everything in the engine has events like this, or at least not immediate ones for performance reasons, which is why a generic approach is complicated.
Describe the bug?
Undo isn't properly scoped. If a component is added that drives another field, undoing doesn't set the driven value to the previous one.
To Reproduce
Add any component that drives a value, then try undoing it. It will keep the driven value instead of the previous set value.
Expected behavior
Undo/Redo should include undoing the implicit changes instead of just the immediate ones. This is how it works in all other engines and would aid greatly in creating content. At the moment, to properly reset after messing up such a change, you need to reload the world to a previous save.
Screenshots
No response
Resonite Version Number
2024.7.24.1106
What Platforms does this occur on?
Windows, Linux, Android / Quest
What headset if any do you use?
Desktop
Log Files
N/A
Additional Context
I provided a specific context where it acts strangely, but ideally the undo system gets a good look through for stuff similar to this.
Reporters
No response