Add dynamic computation of beatmap difficulty#9637
Conversation
| starCounter.ReplayAnimation(); | ||
|
|
||
| if (Item.State.Value == CarouselItemState.Collapsed) | ||
| starDifficultyCancellationSource?.Cancel(); |
|
Just to confirm, this is only showing in the expanded panels' star displays? So the tooltips are using previous databased values for the time being intentionally, correct? |
|
Difficulty icons/tooltips are interesting since they:
I have a WIP branch for it, but I'd like to do that in a separate PR. |
|
Rather than tracked/untracked, how about making it a bit more explicit? Get or Fetch can be used in place of Create if you prefer. |
|
Are you saying to use the current beatmap rather than to pass in a beatmap? That's kind-of what it implies to me... Maybe if it were named: Instead? Though I do like that "tracked" implies it changes along with something (the ruleset and mods), whereas even this still can imply it's a one-time thing. |
|
by "current" i meant current ruleset/mods, so yeah as you said above. or maybe even combine the methods, and mention that if ruleset / mods is null, the game-wide settings are used and tracked? |
|
I haven't gone through this PR completely but "why would i want even want a bindable if it's untracked?" is a question I still have to figure out. Would be good if the naming can convey the meaning a bit better. Also since there's |
I think I'd be fine with having to specify the ruleset and mods every time.
Three reasons off the top of my head:
I think a better question is when someone would use the async version. Perhaps that could be an internal usage - for example maybe the async version should be invoked on import. And yeah,
I like that. |
bdach
left a comment
There was a problem hiding this comment.
Some notes from reading source. (Mostly nits.)
Not sure whether I have something to say right now when it comes to the discussion on whether tracked/untracked/async makes sense. I am of the opinion that both untracked and async have potential for being used but I'm bad at future-proofing.
| { | ||
| // If not, fall back to the existing star difficulty (e.g. from an online source). | ||
| existingDifficulty = new StarDifficulty(beatmapInfo.StarDifficulty); | ||
| key = default; |
There was a problem hiding this comment.
I don't think I can fabricate a scenario to confirm my suspicions for sure right now, but this seems unsafe. If I'm compiling in my head correctly, default is {BeatmapId = 0, RulesetId = 0, Mods = null}; callers of this method use the value of key without checks for default, so there's a potential for garbage stores to the cache - which in itself wouldn't be a problem, but the garbage reads that would be possible later on (if I'm not misreading) due to reusing that same default key is.
The returned key should be probably nullable or something.
There was a problem hiding this comment.
This method is private, so I'm not concerned about callers potentially doing something like:
tryGetExisting(... out key)
// Assume the key hasn't existed (ignore return value)
cache[key] = ...
There was a problem hiding this comment.
Hmm, I suppose. I still would have probably restructured this so that this mistake is impossible to make type-wise but I guess as long is it private...
|
@peppy I've changed to |
| if (Beatmap == null) | ||
| return; | ||
|
|
||
| var ourSource = starDifficultyCancellationSource = new CancellationTokenSource(); |
There was a problem hiding this comment.
Reason for ourSource local? Doesn't seem like it could be thread-unsafe to just use the field.
There was a problem hiding this comment.
Old code, whoops.
This introduces the new
BeatmapDifficultyManagerclass. I imagine this to take on the responsibility of databased background calculation in the future.You can retrieve the beatmap difficulty in four ways via
BeatmapDifficultyManager:Tracking of the bindable versions stops either when the given
CancellationTokenis cancelled, or when references are lost. I've chosen to explicitly cancel the token inSongSelectandAdvancedStatseven though it's not required, just so that calculation doesn't continue after exiting to main menu with references still alive.The async version can also be cancelled.
All of these will, in some way, give a
StarDifficultyobject. I imagine this object to contain more than just the star rating in the future - for example the currentBeatmapInfo.DifficultyRatingcould maybe be moved in there, along with the attributes provided by the difficulty calculator (to display graphs in advanced stats, etc).As for quirky implementation details, I've chosen to permanently keep the difficulties in the cache. I originally had it clear after 60s (although that didn't do much since it's a dictionary), however upon profiling I've found that 230 difficulty values take up ~13KB space anyway, which I'd say is insignificant for the time being.
