Country/Region location detection for High score postings

Hi,

I am creating a online highscore system with mysql/php and have gotten quite far with it.

Is there a way I can detect the users Country location from the iPad? I would like to register this when they create a profile name as it would add some add some colour to the high score table (which would otherwise simply be profile + score).

thanks for your help.

Good idea! Now I’m thinking of adding such a feature in my iPhone game’s online highscores too.

You can use iPhoneSettings.StartLocationService (specific to Unity iPhone 1.7, don’t know if the name’s been changed since 3.0) to use the GPS and get the longtitude and latitude, and from there you can find the country based on a reverse geo-coding lookup, like this one: http://tinygeocoder.com/create-api.php?g=33.790348,-117.226085

Alternatively, you can get the device’s IP address and get the country by using a whois lookup, like this one: APNIC - Query the APNIC Whois Database This requires the device to be connected to the Internet, but since your highscore system is online in the first place, that’s not much of a problem.

I’d go for the GPS method though, since country info on whois databases can get outdated (though not likely).

You can spice things up by using a flag icon from the set found here (public domain): http://www.phoca.cz/documents/35-gimp/127-flag-icons

Hey.
I just spent the last hour or so writing this script, thought in sharing in case it saves someone some time.
I just tested for a bit and it works, but I don’t guarantee it will work in all cases.

Cheers.

	public string playerPrefsKey = "Country";
	public void getGeographicalCoordinates()
	{
		if(Input.location.isEnabledByUser)
			StartCoroutine(getGeographicalCoordinates());
	}
	private IEnumerator getGeographicalCoordinatesCoroutine()
	{
		Input.location.Start();
		int maximumWait = 20;
		while(Input.location.status == LocationServiceStatus.Initializing  maximumWait > 0)
		{
			yield return new WaitForSeconds(1);
			maximumWait--;
		}
		if(maximumWait < 1 || Input.location.status == LocationServiceStatus.Failed)
		{
			Input.location.Stop();
			yield break;
		}
		float latitude = Input.location.lastData.latitude;
		float longitude = Input.location.lastData.longitude;
//		Asakusa.
//		float latitude = 35.71477f;
//		float longitude = 139.79256f;
		Input.location.Stop();
		WWW www = new WWW("https://maps.googleapis.com/maps/api/geocode/xml?latlng=" + latitude + "," + longitude + "&sensor=true");
		yield return www;
		if(www.error != null) yield break;
		XmlDocument reverseGeocodeResult = new XmlDocument();
		reverseGeocodeResult.LoadXml(www.text);
		if(reverseGeocodeResult.GetElementsByTagName("status").Item(0).ChildNodes.Item(0).Value != "OK") yield break;
		string countryCode = null;
		bool countryFound = false;
		foreach(XmlNode eachAdressComponent in reverseGeocodeResult.GetElementsByTagName("result").Item(0).ChildNodes)
		{
			if(eachAdressComponent.Name == "address_component")
			{
				foreach(XmlNode eachAddressAttribute in eachAdressComponent.ChildNodes)
				{
					if(eachAddressAttribute.Name == "short_name") countryCode = eachAddressAttribute.FirstChild.Value;
					if(eachAddressAttribute.Name == "type"  eachAddressAttribute.FirstChild.Value == "country")
						countryFound = true;
				}
				if(countryFound) break;
			}
		}
		if(countryFound  countryCode != null)
			PlayerPrefs.SetString(playerPrefsKey,countryCode);
	}
2 Likes

Thanks a lot pal. :slight_smile: But there’s a slight mistake in that code. Line 16 should be changed to this:

if(maximumWait < 1 && Input.location.status == LocationServiceStatus.Failed)

Thanks mate,

But you are missing a lot of &&'s, randomly. Maybe Unity forums prevent it?

Also

StartCoroutine(getGeographicalCoordinates());

is displaying error: Can’t convert void into IEnumerator

1 Like

Hi,

I made a solution which will give ability to get approximate Country Code. Maybe it will be helpful for you:

        private static readonly Dictionary<SystemLanguage,string> COUTRY_CODES = new Dictionary<SystemLanguage, string>()
        {
            { SystemLanguage.Afrikaans, "ZA" },
            { SystemLanguage.Arabic    , "SA" },
            { SystemLanguage.Basque    , "US" },
            { SystemLanguage.Belarusian    , "BY" },
            { SystemLanguage.Bulgarian    , "BJ" },
            { SystemLanguage.Catalan    , "ES" },
            { SystemLanguage.Chinese    , "CN" },
            { SystemLanguage.Czech    , "HK" },
            { SystemLanguage.Danish    , "DK" },
            { SystemLanguage.Dutch    , "BE" },
            { SystemLanguage.English    , "US" },
            { SystemLanguage.Estonian    , "EE" },
            { SystemLanguage.Faroese    , "FU" },
            { SystemLanguage.Finnish    , "FI" },
            { SystemLanguage.French    , "FR" },
            { SystemLanguage.German    , "DE" },
            { SystemLanguage.Greek    , "JR" },
            { SystemLanguage.Hebrew    , "IL" },
            { SystemLanguage.Icelandic    , "IS" },
            { SystemLanguage.Indonesian    , "ID" },
            { SystemLanguage.Italian    , "IT" },
            { SystemLanguage.Japanese    , "JP" },
            { SystemLanguage.Korean    , "KR" },
            { SystemLanguage.Latvian    , "LV" },
            { SystemLanguage.Lithuanian    , "LT" },
            { SystemLanguage.Norwegian    , "NO" },
            { SystemLanguage.Polish    , "PL" },
            { SystemLanguage.Portuguese    , "PT" },
            { SystemLanguage.Romanian    , "RO" },
            { SystemLanguage.Russian    , "RU" },
            { SystemLanguage.SerboCroatian    , "SP" },
            { SystemLanguage.Slovak    , "SK" },
            { SystemLanguage.Slovenian    , "SI" },
            { SystemLanguage.Spanish    , "ES" },
            { SystemLanguage.Swedish    , "SE" },
            { SystemLanguage.Thai    , "TH" },
            { SystemLanguage.Turkish    , "TR" },
            { SystemLanguage.Ukrainian    , "UA" },
            { SystemLanguage.Vietnamese    , "VN" },
            { SystemLanguage.ChineseSimplified    , "CN" },
            { SystemLanguage.ChineseTraditional    , "CN" },
            { SystemLanguage.Unknown    , "US" },
            { SystemLanguage.Hungarian    , "HU" },
        };

        /// <summary>
        /// Returns approximate country code of the language.
        /// </summary>
        /// <returns>Approximated country code.</returns>
        /// <param name="language">Language which should be converted to country code.</param>
        public static string ToCountryCode(this SystemLanguage language) {
            string result;
            if (COUTRY_CODES.TryGetValue (language, out result)) {
                return result;
            } else {
                return COUTRY_CODES[SystemLanguage.Unknown];
            }
        }

Usage is simple:

var countryCode = Application.systemLanguage.ToCountryCode();

With best regards,
Yulian

1 Like

There is a couple of incorrect country codes (corresponding to ISO 3166-1) in your dictionary. For example, for
Greek and SerboCroatian language.

Here is dictionary with correct country codes:
CountryCodes

        private static readonly Dictionary<SystemLanguage, string> CountryCodes = new Dictionary<SystemLanguage, string>
        {
            { SystemLanguage.Afrikaans, "af-ZA"},
            { SystemLanguage.Arabic, "ar-SA"},
            { SystemLanguage.Basque, "eu-ES"},
            { SystemLanguage.Belarusian, "be-BY"},
            { SystemLanguage.Bulgarian, "bg-BG"},
            { SystemLanguage.Catalan, "ca-ES"},
            { SystemLanguage.Chinese, "zh-CN"},
            { SystemLanguage.Czech, "cs-CZ"},
            { SystemLanguage.Danish, "da-DK"},
            { SystemLanguage.Dutch, "nl-NL"},
            { SystemLanguage.English, "en-US"},
            { SystemLanguage.Estonian, "et-EE"},
            { SystemLanguage.Faroese, "fo-FO"},
            { SystemLanguage.Finnish, "fi-FI"},
            { SystemLanguage.French, "fr-FR"},
            { SystemLanguage.German, "de-DE"},
            { SystemLanguage.Greek, "el-GR"},
            { SystemLanguage.Hebrew, "he-IL"},
            { SystemLanguage.Hungarian, "hu-HU"},
            { SystemLanguage.Icelandic, "is-IS"},
            { SystemLanguage.Indonesian, "id-ID"},
            { SystemLanguage.Italian, "it-IT"},
            { SystemLanguage.Japanese, "ja-JP"},
            { SystemLanguage.Korean, "ko-KR"},
            { SystemLanguage.Latvian, "lv-LV"},
            { SystemLanguage.Lithuanian, "lt-LT"},
            { SystemLanguage.Norwegian, "no-NO"},
            { SystemLanguage.Polish, "pl-PL"},
            { SystemLanguage.Portuguese, "pt-PT"},
            { SystemLanguage.Romanian, "ro-RO"},
            { SystemLanguage.Russian, "ru-RU"},
            { SystemLanguage.SerboCroatian, "sr-RS"}, //HR for Croatia
            { SystemLanguage.Slovak, "sk-SK"},
            { SystemLanguage.Slovenian, "sl-SI"},
            { SystemLanguage.Spanish, "es-ES"},
            { SystemLanguage.Swedish, "sv-SE"},
            { SystemLanguage.Thai, "th-TH"},
            { SystemLanguage.Turkish, "tr-TR"},
            { SystemLanguage.Ukrainian, "uk-UA"},
            { SystemLanguage.Vietnamese, "vi-VN"},
            { SystemLanguage.Unknown, "zz-US" }
        };

P.S. I have added language code (according to ISO 639) as prefix for each member my needs, you can remove it if you don’t need it.

1 Like

Is this the necromancer’s Wednesday guild meeting? I’m a member, but my card is in the other robe.

I think letting people self-identify their country of origin is best (use GeoIP to suggest a flag though). Don’t let them change this too often, and ensure they’re removed from/moved to the right table when they change it. Geolocation is often inaccurate for ISPs with international branches, like a couple of the ones we have in Norway.

One of the popular cable companies had IP addresses identifying as Dutch at times because of the parent company being Dutch. My current ISP at least identifies the country correctly (for now; Swedish owners took over), but the city is a few hundred kilometres off for many of the addresses I get (it changes monthly).

I could not get the postal_code form google response. except that, country, premise and other works !.