-
-
Notifications
You must be signed in to change notification settings - Fork 2.3k
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
Replace Country
class with enumeration
#19137
Conversation
Also applied to `Language` while at it.
osu.Game/Users/Country.cs
Outdated
[Description("Alien")] | ||
XX = 0, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I initially went towards using null
as a default/unknown country value, but wasn't sure if that's a good direction code-wise.
I was also not sure between using Country.XX
and default
, but decided to use the latter as it reads somewhat better. Open for argument.
string textureName = country == default ? "__" : country.ToString(); | ||
Texture = ts.Get($@"Flags/{textureName}") ?? ts.Get(@"Flags/__"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could alternatively rename __.png
in resources project to XX.png
rather than doing this, but didn't want to initiate another game resources release just for this.
private Country? country; | ||
|
||
public Country Country | ||
{ | ||
get => country ??= (Enum.TryParse(userCountry.Code, out Country result) ? result : default); | ||
set => country = value; | ||
} | ||
|
||
#pragma warning disable 649 | ||
[JsonProperty(@"country")] | ||
public Country Country; | ||
private UserCountry userCountry; | ||
|
||
private class UserCountry | ||
{ | ||
[JsonProperty(@"code")] | ||
public string Code; | ||
} | ||
#pragma warning restore 649 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would hope to get rid of this eventually and have osu-web provide the country code in a country_code
property on the user object directly.
We need NRT sooner than later...
Not super sure I agree with this direction, conceptually speaking? The list of countries in this world isn't exactly that immutable. With this enumeration existing, now we're on the hook for tracking geopolitical changes and keeping the set of countries up-to-date in the enum, which was basically a non-issue in the previous structure. At least #19139 has enough sense to persist the enum as a string to DB, but at the point that that workaround has to exist, I am sort of questioning what exactly the enum is giving us here. I don't disagree with only persisting the ISO country code and having a mapping function to unmap that to a country name - that is complexity we will likely not avoid - but I am against countries being an enum. |
It's one way out of many to be able to take ISO country code and map it to a country name, without having to include the full name itself inside DB, which is the goal of this PR.
Alternative directions could be to change it to a dictionary, or an extensions method which takes a code and returns the full name for it. But I can't see any difference from an enum (if not just being more complex) since we're still bound to update it whenever the list of countries change? I don't see why you are against having it as an enum? |
Enum gives us "type safety" for tests etc. I'm neutral on enum vs acronym strings though. Whatever works really. |
If the country is in an enum as you have it, you have to both track new countries appearing and disappearing (by adding them to the enum), you have to track countries changing name (which happens - see Czech Republic -> Czechia, FYR Macedonia -> North Macedonia, Turkey -> Türkiye), and you have to unmap ISO codes to the enum in all cases the data is being retrieved/persisted as a string (API responses, DB storage). If the country is represented by a string of its ISO code, you only have to worry country changing names. New countries appearing and old disappearing are mostly handled automatically, and there is no unmapping step required. How would this be more complex? |
End of the day, we want to use the acronyms. That's standard across infrastructure. Not sure if that matches ISO code, but just going to add that. |
You will still have to update the mapping method to handle those new countries. But the point about not having to unmap is fair, okay. So we're all agreeing on a
If that matches with what the enum members are currently named, then yeah. |
Way I see it, the chance of us missing the fact that some new country has been added is 99.9%. At that point I don't much care how wrong the end result is going to be, because we won't see it until someone has actually reported it already. It probably shouldn't crash the game, but falling back to "Unknown" as the country name is probably okay enough (and not much different to what your current code would do).
As I stated above, this will unfortunately have to exist any way we cut it, so yes. |
After spending some time on moving away from enum, I've came across two ways:
I started with making it On the realm side of things, with the first approach only a public Country? Country
{
get => Country.FromCode(CountryCode);
set => CountryCode = value.Code;
}
[MapTo(nameof(Country))]
public string CountryCode { get; set; } |
If this implies storing the acronym, it should be called I have no issue with any of the provided solutions, including the enum. Choose whichever allows this to be merged. |
I meant the country acronym/code, yeah. |
Upon seeing the branches linked above I withdraw my objections. Between the three variants I see no clear best option, they all have varying degrees on wonkiness, so may as well go with what's PRed already to avoid bikeshedding further. |
Inclined to go with the enum then, since that's what we already have here. Still not happy with the enum-string mapping in realm, but also hoping that realm will eventually support enum types properly and we can drop that everywhere. |
if (!string.IsNullOrEmpty(country.FullName)) | ||
AddLink(country.FullName, () => rankings?.ShowCountry(country)); | ||
if (countryCode != CountryCode.Unknown) | ||
AddLink(countryCode.GetDescription(), () => rankings?.ShowCountry(countryCode)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not 100% on the use of GetDescription
to get the country name. It feels a bit too generic of a method call? Guess it works for now though. If it ever comes up as an issue we could make an extension method to use instead. Or maybe reconsider whether enum
is the best fit.
One step towards supporting inclusion of user country in local scores. Countries have been copied from the
countries.json
map with help from VIM keybindings, which will be removed in a follow-up PR given the current size of this PR and the usage behind that file.Reason for changing it to enum is to make it easier to store the user's country in local scores, by only specifying the acronym rather than passing the full
Country
structure and making a Realm version of it which inheritsEmbeddedObject
. It is also a good code-quality change overall seeing how it reflects on the test scenes.