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

The Everything Update (UI Overhaul + Bug Fixes) #30

Open
wants to merge 71 commits into
base: main
Choose a base branch
from

Conversation

speecil
Copy link
Contributor

@speecil speecil commented Oct 23, 2024

  • no longer uses the base game leaderboard
  • uses leaderboard core
  • fixed profile pictures
  • fixed cell clicking
  • added map info modal
  • added map link button to leaderboard
  • added ranking status header below panelview (coloured header that shows ranked status like stars)
  • added country rank to the panelview
  • fixed replay playback inconsistencies
  • removed old unity imgui replay ui
  • new screen space replay ui on desktop (with timebar scrubber)
  • fixed legacy replay method error
  • added setting to hide replay watermark if you are the user in the replay

image
image

I have probably forgotten something...

Copy link
Member

@Qwasyx Qwasyx left a comment

Choose a reason for hiding this comment

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

Finally got to review this. See the comments for details.

README.md Show resolved Hide resolved
ScoreSaber/Core/Data/Internal/Settings.cs Outdated Show resolved Hide resolved
ScoreSaber/Core/Data/Internal/Settings.cs Show resolved Hide resolved
ScoreSaber/Core/Data/Models/ScoreSaberTeam.cs Outdated Show resolved Hide resolved
ScoreSaber/Core/ReplaySystem/Accessors.cs Outdated Show resolved Hide resolved
ScoreSaber/UI/Main/ViewControllers/TeamViewController.cs Outdated Show resolved Hide resolved
ScoreSaber/UI/PromoBanner/PromoBannerView.cs Show resolved Hide resolved
ScoreSaber/Core/AffinityPatches/MenuPresencePatches.cs Outdated Show resolved Hide resolved
ScoreSaber/Core/Data/Models/LeaderboardUploadData.cs Outdated Show resolved Hide resolved
ScoreSaber/Core/Data/Models/ScoreSaberTeam.cs Show resolved Hide resolved
}

return currentNode;
_lastLocatedNode = _beatmapData.allBeatmapDataItems.Find(_beatmapDataItemsCache[Math.Max(0, high)]);
Copy link
Member

Choose a reason for hiding this comment

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

sorry to disappoint you, but this operation alone is O(n), completely making your binary search useless. You need to cache the actual LinkedList nodes, not just their content (please verify that those are actually consistent, i.e. can be cached).

Copy link
Member

Choose a reason for hiding this comment

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

Furthermore it is not consistent with your old code. Your old code returned null if you scrolled to the start of the map.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed

ScoreSaber/Core/Services/ScoreSaberRichPresenceService.cs Outdated Show resolved Hide resolved
ScoreSaber/UI/Elements/Profile/ProfileDetailView.cs Outdated Show resolved Hide resolved
ScoreSaber/UI/Elements/Profile/ProfileDetailView.cs Outdated Show resolved Hide resolved
@Umbranoxio Umbranoxio mentioned this pull request Dec 14, 2024
gameMode = Services.GameMode.practice;

// this is to privatise the practice mode song, as it would be exposed in the rich presence, still not shown in UI though.
var songeventPrivate = new SongRichPresenceInfo(_richPresenceService.TimeRightNow, gameMode,
Copy link
Member

Choose a reason for hiding this comment

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

Nitpick but, songEventPrivate

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed

startTime = (int)__instance._practiceViewController._practiceSettings.startSongTime;
}

var songevent = CreateSongStartEvent(__instance.selectedBeatmapLevel, __instance.selectedBeatmapKey, gameplayModifiers, startTime, gameMode);
Copy link
Member

Choose a reason for hiding this comment

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

Same as above

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed

@@ -16,20 +18,25 @@ public LeaderboardService() {
Plugin.Log.Debug("LeaderboardService Setup");
}

public async Task<LeaderboardMap> GetLeaderboardData(int maxMultipliedScore, BeatmapLevel beatmapLevel, BeatmapKey beatmapKey, PlatformLeaderboardsModel.ScoresScope scope, int page, PlayerSpecificSettings playerSpecificSettings, bool filterAroundCountry = false) {
public async Task<LeaderboardMap> GetLeaderboardData(int maxMultipliedScore, BeatmapLevel beatmapLevel, BeatmapKey beatmapKey, ScoreSaber.UI.Leaderboard.ScoreSaberLeaderboardViewController.ScoreSaberScoresScope scope, int page, PlayerSpecificSettings playerSpecificSettings) {
Copy link
Member

Choose a reason for hiding this comment

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

We've imported ScoreSaber.UI.Leaderboard above, why are we accessing it the long way here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed


try {
var socketOptions = new Socket.Options(new JsonMessageSerializer());
var socketAddress = "wss://ssrt.bzaz.au/socket"; // change to scoresaber subdomain once ready.
Copy link
Member

Choose a reason for hiding this comment

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

wss://realtime.scoresaber.com/socket

Should be a constant defined outside of the method, should build off of the baseUrl defined Plugin.cs however this was implemented

Copy link
Contributor Author

Choose a reason for hiding this comment

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

i made it a constant within the file, building off of the baseUrl would be difficult because its the api url, where this is the socket

Copy link
Member

Choose a reason for hiding this comment

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

The baseUrl should look like scoresaber.com, everything else should build off of this base.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

implemented

Copy link
Member

Choose a reason for hiding this comment

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

Wouldn't it make more sense to have not a single baseUrl, but instead multiple baseUrls for the different parts (still all stored at the same spot). That way it would be much easier to test individual component changes locally without having to deploy a full blown backend with all parts/components each time.

Copy link
Member

Choose a reason for hiding this comment

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

Create a new namespace and folder for this. Organize it properly e.g: models go in a Models folder, and classes should be in separate files and well-structured. The current setup isn’t scalable since our realtime functionality will expand beyond live presence in the future.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed

Copy link
Member

@Umbranoxio Umbranoxio Dec 14, 2024

Choose a reason for hiding this comment

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

Services usually refer to ScoreSaber communicating with an external source or larger functionality, while I'm not happy with our current structure and it does need refactoring, this is a UI utility.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Made it TweeningUtils

mapPresence.gameObject.SetActive(true);
mapPresenceTitle.gameObject.SetActive(true);
mapImagePresence.SetImageAsync($"https://cdn.scoresaber.com/covers/{_richPresence.state.currentMap.Hash}.png").RunTask();
}
Copy link
Member

Choose a reason for hiding this comment

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

Build this url from a constant baseUrl

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed

Plugin.Log.Error($"BeatmapDownloader is null, install a mod to [APP] that injects IScoreSaberBeatmapDownloader");
}
// load sprites
UnityMainThreadTaskScheduler.Factory.StartNew(() => BeatSaberMarkupLanguage.Utilities.LoadSpriteFromAssemblyAsync("ScoreSaber.Resources.Online.png")).ContinueWith(x => { _onlineSprite = x.Result.Result; });
Copy link
Member

Choose a reason for hiding this comment

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

We reference these strings quite frequently (later on in the file too). We should have one source of truth for them.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Made constants


[UIAction("OpenLeaderboardPage")]
internal void OpenLeaderboardPage() {
Application.OpenURL($"https://scoresaber.com/leaderboard/{_leaderboardService.currentLoadedLeaderboard.leaderboardInfoMap.leaderboardInfo.id}");
Copy link
Member

Choose a reason for hiding this comment

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

Build from BaseURL

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed

_panelView.statusWasSelected = delegate () {
if (_leaderboardService.currentLoadedLeaderboard == null) { return; }
_parserParams.EmitEvent("close-modals");
Application.OpenURL($"https://scoresaber.com/leaderboard/{_leaderboardService.currentLoadedLeaderboard.leaderboardInfoMap.leaderboardInfo.id}");
Copy link
Member

Choose a reason for hiding this comment

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

Build from BaseURL

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed


UnityMainThreadTaskScheduler.Factory.StartNew(async () => {
if (!Plugin.Settings.hasAcceptedRichPresenceDisclaimer) {
await Task.Delay(500);
Copy link
Member

Choose a reason for hiding this comment

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

Do we have a runtime issue if this delay doesn't exist or is it purely for UX? If it's for UX, this is fine. But if we're avoiding a runtime issue this isn't a stable fix and should be addressed correctly.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

without the delay, the modal doesnt have the foreground effect for some reason. Im not sure why

Copy link
Contributor Author

Choose a reason for hiding this comment

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

All it needs is a single millisecond after some testing

Copy link
Member

Choose a reason for hiding this comment

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

This implies that we're needing to wait a frame. Try await Task.Yield(); instead.

Or, use a coroutine which begins with yield return null; to wait until the next frame before ShowRichPresenceDisclaimer()

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants