AdamsLair / duality

a 2D Game Development Framework
https://adamslair.github.io/duality
MIT License
1.41k stars 289 forks source link

Use duality serializer for editoruserdata #865

Closed Barsonax closed 4 years ago

Barsonax commented 4 years ago

Changes:

Editorplugins will be updated in separate PR's

ilexp commented 4 years ago

Editorplugins will be updated in separate PR's

Related PRs for reference: #866, #867, #868, #869, #870, #871, #872

ilexp commented 4 years ago

I'll experiment with this locally to see if the result is a net improvement or not, will report back.

Okay, so I played around with this a bit and don't think this is a great way to go about this. Going forward, the SettingsContainer should theoretically be able to handle all the load / save code, without the need for additional calls:

Now that I've worked on this a bit, I think it might make sense to include the content of the plugin PRs (i.e. the whole port of the plugin settings serialization) in this one and merge it all in one big step. Could be less noise and intermediate states on the master branch in the end.

ilexp commented 4 years ago

Looked into some of the cases of per-plugin user settings we'd need to port and found a tricky one in the CamView plugin:

This would mean a really big number of various settings classes. Could mean a bit of boilerplate code - but then again, we get well-documented properties and a proper definition in return. Could be worth starting with the CamView port as a test case so we can be sure it won't get much worse after that.

ilexp commented 4 years ago

Going forward, the SettingsContainer should theoretically be able to handle all the load / save code, without the need for additional calls:

  • The EditorPluginManager.Load/Save call can probably be removed once all plugins use the new serializer API, since there wouldn't be anything left to do in there after that. All the plugins would access their settings object directly, no more field assignment needed. Any post-load code can still be executed by subscribing to the Changed event.
  • For Pre-save code, we could add a Saving event, but so far it's only the main form dock panel that would make use of this. And that specific case can still be done manually where needed, without much harm done. So we might not even need this event and could keep the SettingsContainer API a bit simpler that way.

More examples have come up where a Saving event or an actual Save call would be necessary, because their settings are stored in UI state.

It could make sense to refactor those parts as part of the port, which would mean that the call would no longer be necessary - but in that case, every UI change would directly edit the settings object, theoretically requiring to call its Changed event all the time. This would create a load of unnecessary work throughout the editor though and not be what this event was intended to do.

To fix this, I'd propose to rename Changed to Loaded and also add a Saving event for those cases that need it, as a mirror image. This would allow us to get rid of any additional call requirements beyond the container Load / Save to always serialize and apply the full thing, including the dock panel. It would also bring the API closer to what's actually happening, because Changed was never fired for every change anyway, or intended to do that. Loaded would match its behavior exactly.

We could get rid of the whole EditorPluginManager load / save calls entirely, and any plugin that really wants to go a different route for settings storage can just subscribe to Saving / Loaded and transform their data on-demand.

ilexp commented 4 years ago

One more thing to address: DualityApp user and app data make use of their Changed event to apply global settings internally, but there is no longer any way to invoke the Changed event at runtime without loading new settings from file, and I just proposed earlier to get rid of this event entirely / rename it to Loaded.

I'd honestly take a shortcut for this fix for now to keep workload low and wrap up this PR soon: Let's just add an Apply method to the SettingsContainer that calls Save and then Load immediately after internally. For runtime settings changes in a Duality game, like in an options menu, this should do exactly what people would expect.

Edit: Maybe a better naming for those events would be Saving and Applying, since the latter will be invoked both after load and when calling Apply?

ilexp commented 4 years ago

Progress

One more thing to address: DualityApp user and app data make use of their Changed event to apply global settings internally, but there is no longer any way to invoke the Changed event at runtime without loading new settings from file, and I just proposed earlier to get rid of this event entirely / rename it to Loaded.

I'd honestly take a shortcut for this fix for now to keep workload low and wrap up this PR soon: Let's just add an Apply method to the SettingsContainer that calls Save and then Load immediately after internally. For runtime settings changes in a Duality game, like in an options menu, this should do exactly what people would expect.

Edit: Maybe a better naming for those events would be Saving and Applying, since the latter will be invoked both after load and when calling Apply?

Done.

ToDo

Barsonax commented 4 years ago

I'm fine with a (squash-)merge based on the current state as long as the remaining ToDos are categorized in a new issue or PR when merging, I think the current state is solid enough to stand on its own, though individual merging would bump the priority of the followup PRs to not remain in this intermediate state for too long. Alternatively, we can do it all in this PR directly. Thoughts?

We could cherrypick/merge the commits for the other PR's into to this branch before merging this PR to master.

The main reason I splitted them up is for reviewing purposes.

ilexp commented 4 years ago

Added a few more commits where I removed the need for explicit "Update XY" calls by subscribing to the settings event handlers instead. It should now be a simple Load / Save call in all cases.

ilexp commented 4 years ago

Okay, so after letting this sink in a bit, I think it would be better to merge this as-is and continue with individual PRs for porting the existing user data: