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

Abstract out osu specific stuff from UpdateManager #24484

Closed
wants to merge 4 commits into from

Conversation

LumpBloom7
Copy link
Contributor

@LumpBloom7 LumpBloom7 commented Aug 8, 2023

Opening this PR mainly for discussion on direction and implementation.

This serves as an initial step to allow rulesets to use the GitHub release notification code to announce that they have updates. (As an interim solution while waiting for ruleset listing to be available)

UpdateManager is the abstract base class for all implementations, and doesn't provide any functionality whatsoever. The post-update notification is now implemented within GameVersionUpdater (not a fan of the name), which is used by (*)GameUpdateManager.

I also took the liberty of simplifying NoActionUpdateManager, as that shared a lot of code with SimpleUpdateManager.

Rudimentary manual testing of SimpleGameUpdateManager seems to show that everything seems to be behaving as expected.

The first step in allowing rulesets to use the same GitHub update mechanism as an interim remedy to providing timely updates to players.
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.

Sorry but not buying this at all. These changes make understanding the updaters actively more difficult and bring yet another muddled class hierarchy into being.

Comment on lines 18 to 20
/// <remarks>
/// Implementers are expected to set <see cref="Version"/> to something that matches their release versioning/tagging system.
/// </remarks>
Copy link
Collaborator

Choose a reason for hiding this comment

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

This is a sign of bad design and needs to be handled better. Constructor, abstract property, whatever, but consumers should be forced to set this - you shouldn't need to rely on a loose setter only mentioned in passing in the remarks section.

Comment on lines 27 to 28
// For lack of a better term
protected abstract string UpdatedComponentName { get; }
Copy link
Collaborator

Choose a reason for hiding this comment

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

The lack of a better term implies overengineering. It means that it's no longer really clear what's being abstracted over.


return bestAsset?.BrowserDownloadUrl ?? release.HtmlUrl;
}
protected virtual string GetBestURL(GitHubRelease release) => release.HtmlUrl;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why virtual? Why is both this and UpdateActionOnClick() virtual? Means that overriding the latter potentially makes this completely useless.

/// <summary>
/// An update manager which only shows notifications after a game update completes.
/// </summary>
public partial class GameUpdateManager : UpdateManager
Copy link
Collaborator

@bdach bdach Aug 8, 2023

Choose a reason for hiding this comment

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

These classes just keep on coming...

  • Why does this exist at all?
  • Why is SquirrelUpdateManager not a GameUpdateManager, given it updates the game and shows the notification afterwards?

This class needs to not exist, ideally.

/// </summary>
public partial class NoActionGameUpdateManager : SimpleGameUpdateManager
{
protected override string DownloadMessage => "Check with your package manager / provider to bring osu! up-to-date!";
Copy link
Collaborator

Choose a reason for hiding this comment

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

These types of overrides are horrible for localisation purposes later on. It would be better to allow derived classes to specify the full message they are supposed to show (at the cost of copy duplication) rather than try and splice localisable strings together.

@bdach
Copy link
Collaborator

bdach commented Aug 8, 2023

As for more constructive feedback after pointing out the issues: What seems to be desired here is to reuse "fetch releases for arbitrary repo from github and show a notification" logic, and also have a way to hook that into the game.

If that goal is what is desired here, then I'd strongly urge considering composition over inheritance. Have something like a UpdateChecker or whatever which has the github logic inside it; have each UpdateManager receive an UpdateChecker to query and to delegate (or maybe multiple, even).

I'm not even really sure we need to rope any ruleset updaters - if we're even doing that, since this entire series is completely unprompted and has been preceded by no discussion - into the game update flow. Maybe it can be a separate thing without introducing a common giga-abstraction.

@LumpBloom7
Copy link
Contributor Author

Your suggestions do indeed sound like a better fit, and I'll look into that direction.

As for the discussion before implementation part, I'll keep that in mind the next time I make a big change like this. 🙇

@bdach
Copy link
Collaborator

bdach commented Aug 8, 2023

Loose thought, bu it isn't really obvious to me that we want to have ruleset updates potentially restart or close the game the same way an actual game update does. It would be very neat to get ruleset update-and-hot-reload to work. I'm not sure if it's feasible, but if it is, it may end up being a completely different API to the game updater. I'd probably explore the options there and see what ends up happening with that.

@LumpBloom7
Copy link
Contributor Author

LumpBloom7 commented Aug 10, 2023

So I redone this with composition in mind, and indeed it does seems much cleaner than my initial attempt.

A few things of note:

  • I moved the osu post-update notification out of UpdateManager into it's own component, since only osu has a changelog overlay

    • This makes UpdateManager no-op, and could be made abstract. OsuGame.CreateUpdateManager() can be made nullable to indicate the lack of update mechanism.
    • Perhaps other update managers can show a post-update notification, which doesn't show a changelog?
  • (Simple|NoAction)UpdateManagers now take in a single IUpdateChecker for now, which would contain implementation to check an arbitrary source for updates.

    • An abstract GitHubUpdateChecker is made, but other sources can be created as needed
    • The return type UpdateInfo is very basic, holding the bare essentials that is needed by SimpleUpdateManager.

I read into the possibility of having hot reload. To be able to unload an ruleset, we would need to not have any active references to any type/code from the ruleset.

I think a simple way to allow for seamless updates of rulesets would be to run the update process as part of the loading process, since at that point we can be sure that we are not using any types from the ruleset assembly such as icons or settings subsections.

Example flow for the above:
Load -> UpdateCheck -> Unload -> Replace -> Fully load

For light and relaxing read: https://learn.microsoft.com/en-us/dotnet/standard/assembly/unloadability

@caesay caesay mentioned this pull request Sep 2, 2024
5 tasks
@peppy peppy closed this in #28743 Sep 4, 2024
@LumpBloom7 LumpBloom7 deleted the update-manager-for-others branch October 9, 2024 20:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants