Server Browsing SDK
From GameSpy SDK
Server Browsing SDK
Overview
The GameSpy Server Browsing SDK is a portable LAN and Internet server browser engine. It allows developers to quickly and easily add a list-based matchmaking interface to the game, with powerful features such as server-side filtering, sorting, country-filtering, and ping (latency) measurement.
The concept of Server Browsing was popularized by our original GameSpy3D product, and is used as a matchmaking paradigm by GameSpy Arcade and many other online services today. The system functions as follows:
- A game server (or person hosting a game) starts, and reports its presence to our Master Server. This server reporting is done using the Query & Reporting SDK.
- Our Master Server aggregates a list of all available game servers, as well as all of the data known about the servers.
- Game Clients query the Master Server for a list of available game servers. This query can contain a filter to narrow down the list of servers returned.
- Once the list is obtained, the Game Client queries each server to obtain the latest information about the game (the name of the game, map being played, number of players, or any other relevant information). It also measures latency to the server at this time, since latency can be an important factor in the quality of the game play experience.
- This collection of servers is then displayed to the user, and they are able to browse the list and select a server to play on, at which point they connect directly to the server.
The Server Browsing SDK manages the entire client-side portion of this process - server list retrieval, server querying, etc. The SDK is a data engine only. You will be responsible for creating all the GUI elements that are required for a server browser in your game. These typically include buttons, long multi-column lists, scrollbars, and edit controls.
Server Browsing is typically used for matchmaking of "dedicated server" games. Dedicated server games are those in which a stand-alone server is run, and outside clients connect to the server. The server continues running even when no players are connected to it, and typically does not have a local client itself. For games that require a group of people to all join together at once, and that do not have persistent servers running (i.e. they use Peer to Peer networking, or require one of the players to "host" the game) the GameSpy Matchmaking Toolkit - which includes the Peer SDK - may be a better choice.
The Peer SDK extends the features of Server Browsing to include a dynamic list of available games, integrated chat lobbies and staging rooms, and more. The Peer SDK can be used for dedicated-server games as well, but using the Server Browsing SDK is quicker and easier to implement if you are simply looking to provide a list-based matchmaking experience.
Two examples are included for your review.
sbctest is a simple C based server list program that demonstrates how to easily receive and display a server list.
sbmfcsample is a C++ / MFC based server list with a full GUI. Your in-game server browser will most likely looking something like this (with the MFC code replaced by your custom GUI code).
This document provides a simple, pseudo-code based set of instructions for implementing an in-game server browser using the Server Browser. Your code will vary based on your specific GUI interfaces.
See the reference documentation for detailed descriptions of each function.
File Manifest
The following files should be included with this package. If any of the files are missing, please contact devsupport@gamespy.com.
- File
- Description
- sb_serverbrowsing.h
- Main header file for the Server Browsing SDK - includes all public functions
- sb_serverbrowsing.c
- Code for primary server browsing functionality
- sb_serverlist.c
- Server list / master server communication code
- sb_queryengine.c
- Server query engine code
- sb_server.c
- Functions for manipulating individual server objects
- sb_internal.h
- Header files for private functions
- sb_crypt.c,h
- Encryption code used for master server communication
- ../qr2/qr2regkeys.c,h
- Defines for pre-defined key names
In addition, to build the SDK and samples, you will need to separately download the GameSpy "common code" package, which includes the shared SDK code used by this SDK and others.
When extracting this package, make sure you preserve the directory tree in order to assure that the code builds correctly.
Implementation
Step 0: Implement the Query and Reporting 2 SDK
If you haven't already done so, you need to implement the Query and Reporting 2 SDK in your game. The Query and Reporting 2 SDK allows your game server to report to our master server and be listed for clients to query. Although you can test the Server Browsing SDK by querying other games, typically you'll want to do most of your testing with your own game.
Once you have implemented and tested the Query and Reporting 2 SDK, you can continue with the server list implementation.
Step 1: Create A Server Browser
Your first step should be to create a server browser object (not a true C++ object, just in the sense of an abstract type).
You can create the server browser when your game first starts, or right before you update the list. You can update a single server browser as many times as you want, so you probably won't need to create it more than once (although you can).
To create a server browser, call:
ServerBrowser ServerBrowserNew(const gsi_char *queryForGamename, const gsi_char *queryFromGamename, const gsi_char *queryFromKey, int queryFromVersion, int maxConcUpdates, int queryVersion, SBBool lanBrowse, ServerBrowserCallback callback, void *instance);
- queryForGamename
- The name of the game you want to browse for. gamenames are issued by our developer relations team. If you do not have one already, contact devsupport@gamespy.com to request a gamename for your game. For testing purposes, you may wish to query for a gamename other than your game - for example, to test how well your list works with several thousand servers listed. Contact devsupport@gamespy.com for a list of alternative gamenames you can use for testing.
- queryFromGamename
- Your gamename that you were issued with your secret key. If you don't have a gamename or secret key, please contact devsupport@gamespy.com. This will typically be the same as queryForGamename, unless you are querying for a different game list during testing.
- queryFromKey
- The secret key you were issued that corresponds to your queryFromGamename
- queryFromVersion
- A version identifier for your game - this is optional and should be set to 0 unless you are told otherwise by developer support
- maxConcUpdates
- The maximum number of concurrent updates (queries) that will be made. 10 is appropriate for modem users, broadband users can generally accommodate 20-30. You can either present this as an option to your users, or leave it at 10 for everyone. Higher numbers lead to faster refreshes of the server list, but if the refresh speed exceeds the user's capacity, ping times will be measured inaccurately and some servers will time out and not show up on the list.
- queryVersion
- Determines the protocol used for server queries. If your game implements the Query and Reporting 2 SDK (as most new games will), simply pass QVERSION_QR2. If you are updating a legacy game to support the Server Browsing SDK, but the game still uses the original Query and Reporting SDK, then you should pass QVERSION_GOA.
- lanBrowse
- The switch to turn on only LAN browsing - use SBTrue if you want only LAN browsing.
- callback
- The server browser callback function described in Step 3. For now you can just create a stub function with a prototype like:
void SBCallback(ServerBrowser sb, SBCallbackReason reason, SBServer server, void *instance) { } // todo - instance
- Any game-specific data you want passed to the callback function. For example, you can pass a structure pointer or object pointer for use within the CallBack. If you can access any needed data within the CallBack already, then you can just pass NULL for instance.
This step should look something like:
int CMyGame::OnMultiplayerButtonClicked(...)
{
m_ServerBrowser = ServerBrowserNew("mygame", "mygame", "123456", 0, 10, QVERSION_QR2, SBFalse, SBCallBack, this);
}
Step 2: Update The Server Browser
When you are ready to populate the Server Browser with data, you need to call one of the update functions. There are two update functions available:
- ServerBrowserUpdate
- Obtains a list of servers from the master server, and then queries the individual servers for information.
- ServerListLANUpdate
- Scans the local LAN for games and updates the list with them.
Note that if you've already updated the server list once, you need to call ServerBrowserClear to clear the list of servers (otherwise you will end up with duplicates). You can call ServerBrowserClear even if the list hasn't been updated yet (it won't break anything).
When calling either of the update functions, you need to decide whether you want to do updates Synchronously or Asynchronously.
With a Synchronous update, the Update function does not return until the entire list is finished updating. Your callback function will still be called during the update (so you can add servers to your list or repaint the window) but there is no guarantee as to how often the callback will be called. If you choose to use Synchronous updates, it is important that you display status messages to the user as the list state changes, otherwise they may think the game has locked up.
With Asynchronous updates, the Update function returns immediately, but you are responsible for calling the ServerBrowserThink function every 10-100 ms while the list is being updated. If you do not call the function, the update will not occur. If you do not call it often enough, the ping times for servers will be inaccurate.
The sbctest sample uses Synchronous updates, while the Sample1 sample uses Asynchronous updates (and a Windows timer to trigger the ServerBrowserThink function).
You may find it easier to implement the browser with Synchronous updates at first, then switch to Asynchronous updates once it has been fully tested.
The following additional parameters are used with the ServerBrowserUpdate function:
- disconnectOnComplete
- Determines whether the Server Browser disconnects from the master server after obtaining the server list, or stays connected. The only reason to stay connected is if you expect to be querying the master server for full details on individual servers (using ServerBrowserAuxUpdateServer) in a game that supports NAT Negotiation (and thus may have servers hosted behind firewalls). In most cases you should pass SBTrue here. Even if you need to contact the master server to obtain information with ServerBrowserAuxUpdateServer, that function will automatically reconnect as-needed.
- basicFields
- An array of information keys that you want to retrieve from each server in the list.
unsigned char basicFields[] = {HOSTNAME_KEY, GAMETYPE_KEY, MAPNAME_KEY, NUMPLAYERS_KEY, MAXPLAYERS_KEY}; int numFields = sizeof(basicFields) / sizeof(basicFields[0]); - This means that the hostname, gametype, mapname, numplayers, and maxplayers keys will be retrieved for each server in your list. The key indexes are the same as those used in the QR2 SDK. If you've defined custom key indexes for custom keys in your game, you can include those as well. Note that you MUST register all custom keys with qr2_register_key before using their indexes in this function. Once you have the basic keys for servers, you can go back and query for the "full" list of keys your game reports - including player and team keys. Details on re-querying servers for additional information is contained in Step 5.
- Note that when using the LAN Update function, you do not need to specify a list of keys - LAN updates automatically retrieve all keys and values from the server.
- numBasicFields
- The number of basic fields passed in your array.
- serverFilter
- A filter that will be applied on the master server, prior to sending the list of servers to the client. When applied correctly, filtering can dramatically increase the speed of server list updates by reducing the number of servers to query, and can make it easier for players to find the types of game they are looking for.
- All of your server keys are available for filtering, as well as two special keys that are added by the master server:
- country
- the two-letter ISO country code where a server is located - as-determined by the IP address of the server
- region
- a numeric bitmask that identifies the region a server is located in (based on the country). See the region list appendix at the end of this document for all available regions.
Note that filtering by "ping" is not possible, since ping is determined by the client - not the master server.
Filter strings are written using SQL-like syntax. Most standard SQL operators are available. Wildcard string comparisions can be made using the "like" operator, with % as the wildcard character.
Here are some examples of useful filter strings:
- gametype = 'ctf' Only returns games whose gametype key matches 'ctf'
-
numplayers > 0 and numplayers != maxplayers
Only returns servers who have players on them, but are not full -
password = 0
Only returns servers that are not passworded (assuming you use a "password" key to indicate password protected servers) -
hostname like '%[gsf]%'
Only returns servers that have the string '[gsf]' somewhere in their name. Could be used, for example, to allow a player to find just the servers their clan runs. -
(country = 'DE' or country = 'FR') and maxplayers >= 8
Only returns servers located in Germany or France that support 8 or more players.
Pass NULL or an empty string if no filtering is required.
For LAN Updates you will also need to specify the ports to check for servers on. The Server Browsing SDK will scan a range of ports by sending a query packet to the broadcast address for each one. startSearchport is usually your standard query port (e.g. the UDP port number you pass to qr2_init in the Query and Reporting SDK).
endSearchPort is the highest port to scan. When multiple servers are run on the same machine, the QR2 SDK allocates incrementally higher ports from the starting port for each server. In general, it is not recommended to use an end port more than 100 higher than the start port. A packet must be sent out to all ports between start and end, and higher numbers can lead to broadcast storms.
This step should look like:
int CMyGame::OnRefreshInternetButtonClicked(...)
{
ServerBrowserUpdate(m_ServerBrowser, SBFalse, SBTrue, basicFields,numBasicFields, NULL);
...
}
int CMyGame::OnRefreshLANButtonClicked(...)
{
ServerBrowserLANUpdate(m_ServerBrowser,SBFalse,START_PORT,START_PORT+100);
...
}
Step 3: Create The List Callback
As the Server Browser updates the server list, it calls back to the function you passed in ServerBrowserNew to give status and progress updates.
The sb parameter is the ServerBrowser object the callback is referring to.
The reason parameter is one of the following values:
- sbc_serveradded
- A server was added to the list. Note that you may just have an IP and port at this point - all servers are added before they are queried. You can choose to add the server to your UI at this point, or wait until you get a serverupdated callback for the server and have more information to display about it.
- sbc_serverupdated
- The information for a server has been updated. Either basic or full information is now available about this server.
- sbc_serverupdatefailed
- An attempt to retrieve information about this server, either directly or from the master server, failed. The server is down or unreachable.
- sbc_serverdeleted
- A server was removed from the list. This only occurs when using push updates, which are not generally used in the Server Browsing SDK (only the Peer SDK).
- sbc_updatecomplete
- All queued updates have been completed and the query engine is now idle.
- sbc_queryerror
- The master returned an error string for the provided query. Typically due to a filter string syntax error. You can obtain the text of the error message from ServerBrowserListQueryError
The server parameter indicates the server that is being referred to, if the message is server-specific.
instance is the instance pointer you passed in when initializing the Server Browser object.
This step should look something like:
void SBCallback(ServerBrowser sb, SBCallbackReason reason, SBServer server, void *instance)
{
CMyGame *g = (CMyGame *)instance;
switch (reason)
{
case sbc_serveradded :
g->ServerView->AddServerToList(server);
break;
case sbc_serverupdated :
g->ServerView->UpdateServerInList(server);
break;
case sbc_updatecomplete:
g->ServerView->SetStatus("Update Complete");
break;
case sbc_queryerror:
g->ServerView->SetStatus("Query Error Occurred:",
ServerBrowserListQueryError(sb));
break;
}
}
Step 4: Extracting and Displaying Server Information
Somewhere along the line (either in your Callback or a helper function) you will need to actually get the data out of the SBServer object to display it on your list.
The Server Browsing SDK provides 10 functions to help you get the data you need from the SBServer object:
const char *SBServerGetStringValue(SBServer server, char *keyname, char *def); int SBServerGetIntValue(SBServer server, char *key, int idefault); double SBServerGetFloatValue(SBServer server, char *key, double fdefault); SBBool SBServerGetBoolValue(SBServer server, char *key, SBBool bdefault);
The first four functions are used to access the values for server key information. Simply use the key name you registered to access the value for that key on a server. Note that only the basic keys you requested in ServerBrowserUpdate are available after the initial update. See the next step for information on getting the rest of the keys\values from the server.
const char *SBServerGetPlayerStringValue(SBServer server, int playernum, char *key, char *sdefault); int SBServerGetPlayerIntValue(SBServer server, int playernum, char *key, int idefault); double SBServerGetPlayerFloatValue(SBServer server, int playernum, char *key, double fdefault);
The second set of functions returns a specific player key. You can get the same result by asking for a server key in the form keyname_N where N is the player number you are interested in. The SBServerGetPlayer functions just provide a shortcut to this. To get the ping for player 0, you would ask for SBServerGetPlayerIntValue(server, 0, "ping", 0).
const char *SBServerGetTeamStringValue(SBServer server, int teamnum, char *key, char *sdefault); int SBServerGetTeamIntValue(SBServer server, int teamnum, char *key, int idefault); double SBServerGetTeamFloatValue(SBServer server, int teamnum, char *key, double fdefault);
The final set of functions is similar to the player key lookups, except for team keys. Team keys are reported in the form keyname_tN where N is the team index. To get the score for team 0 (score_t0, you would ask for: SBServerGetTeamIntValue(server, 0, "score", 0).
The sdefault, idefault and fdefault parameters will be used if the server doesn't include the specific key you requested.
Team and player keys are only available for servers with a full set of keys. You can determine whether a particular server in your list has basic or full keys with the SBServerHasBasicKeys / SBServerHasFullKeys functions.
This step should look something like:
//insert a server onto the list
CServerView::Insert(GServer server)
{
AddItem(SBServerGetStringValue(server, "hostname","(NONE)"),
SBServerGetPing(server),
SBServerGetIntValue(server,"numplayers",0),
SBServerGetIntValue(server,"maxplayers",0),
SBServerGetStringValue(server,"mapname","(NO MAP)")
SBServerGetStringValue(server,"gametype",""));
}
Step 5: Obtaining Additional Server Information
After your initial server browser update, the servers will only have the "basic" keys available for them. Most in-game server browsers are built so that when you click on a server, you can get additional information about it - such as the full rules for the game, the list players currently in the game, and the team information. To obtain this additional information when someone selects a server, you will need to perform what is known as an "Auxiliary" update of the server. To accomplish this, call:SBError ServerBrowserAuxUpdateServer(ServerBrowser sb, SBServer server, SBBool async, SBBool fullUpdate);
- server
- The server you want to get updated information for.
- async
- Determines whether the function returns immediately, or waits for the update to complete. Note that if you perform the AuxUpdate asynchronously, you must call the ServerBrowserThink function to perform processing.
- fullUpdate
- Determines whether basic or full keys are retrieved from the server. Generally you will want to pass SBTrue to retrieve all the available keys\values from the server.
You should check to see if the server already has full keys available with SBServerHasFullKeys to avoid updating the server if not needed. Multiple aux updates can be queued at a time if you want to get full keys for a range of servers.
If the server being updated is behind a NAT, and does not support direct-UDP queries (only for games that use the NAT Negotiation SDK), then the full server information is obtained from the master server, instead of the game server directly. This requires a connection to the master server. If you set the disconnectOnComplete option when updating, a connection will be re-established to the master to obtain the information.
You can also use the ServerBrowserAuxUpdateIP function to "add" a server to the list that was not already present. Instead of providing an SBServer object, you will provide the IP and query port of the server. You can use this to allow players to manually add servers to the list, or to store a list of favorites locally and add them to the list directly.
Step 6: Sorting and Other Features
You will probably want to give players the ability to sort the server list on a specific column (for example, the server name to find a specific server, by ping to find the best server, or by players to find the most crowded). If your list control supports sorting, you can do it that way, or, you can resort the actual ServerBrowser object and repopulate your display with the sorted data. Unlike the previous CEngine SDK, list storage is decoupled from updating, so you can use the sorting functions to resort the list while it is being updated (although resorting after every server update arrives may lead to poor performance on large lists).
To resort the internal list, use the ServerBrowserSort function:
void ServerBrowserSort(ServerBrowser sb, SBBool ascending, char *sortkey,SBCompareMode comparemode);
You should pass in whether you want the list to be sorted in ascending or descending order, what key it should be sorted on (e.g. "ping" or "hostname" or "numplayers") and the value type for that key (e.g. sbcm_int for integer comparison, sbcm_stricase for case-insensitive string comparison).
To sort the list ascending by ping you would call:
ServerBrowserSort(sb, SBTrue, "ping", sbcm_int);
Once you have resorted the list, you will need to clear your display and repopulate it with the sorted list. This is typically done with a FOR loop from 0 to ServerBrowserCount(...)-1 in which you call ServerBrowserGetServer to get each server in the list.
In order to display the progress of the server list update, you can use the ServerBrowserPendingQueryCount to determine the number of servers waiting to be queried. By comparing this to the number of servers on the list, you can determine a completion percentage.
The ServerBrowserHalt function can be used to stop an update in progress, if the user wants to abort the update.
The ServerBrowserState can be used to determine the current state of the Server Browser. Descriptions of the possible state values can be find in the main header file.
Step 7: Free the Server Browser When Done
When you are completely done with the server browser, call the ServerBrowserFree function to free the memory allocated by the list. The Server Browser object is invalid after this call, so do not use it again without calling ServerBrowserNew.
UNICODE Support
The GameSpy SDKs support an optional UNICODE interface for widestring applications. To use this interface, first define the symbol GSI_UNICODE. Then, use widestrings wherever ANSI strings were previously called for. When in doubt, please refer to the header files for specific function declarations.
Although the GameSpy SDK interfaces support UNICODE parameters, some items may be stripped of their extra UNICODE information. These items include: nickname, email address, and URL strings. You may pass in widestring values, but they will first be converted to their ANSI counterparts before transmission.
Appendix: Changes From The CEngine SDK
The Server Browsing SDK replaces the CEngine SDK, and provides a number of changes an enhancements. Migration from the CEngine SDK is fairly straight-forward and can provide a number of benefits.
The changes and improvements in the SDK are listed below to help you with migration:
- Defaults to a multi-step update process, where only basic keys are obtained from servers initially, and full keys are obtained on-request. This results in a significant bandwidth reduction for both clients and servers (on the order of 5-10X) and leads to faster refreshes with less overhead.
- Supports the new QR2 querying protocol, which allows for querying of individual keys and optimized encoding of key data (key names are no longer sent if not required).
- Allows server information to be obtained from the master server for games hosted behind a NAT/Firewall.
- Supports the new NAT Negotiation SDK for hosting and connecting-to games behind a NAT or Firewall
- Allows for filtering by any server key, instead of the fixed list of keys available for filtering in the CEngine SDK
- Allows for filtering of servers by country and region, without requiring server administrators to report that information.
- Allows for sorting of the server list while updates are still in progress.
- Faster socket code that uses a single UDP socket for all queries, instead of requiring 1 socket for each simultaneous query.
- Server lists from the master server use a new format that is compressed even more than before.
Appendix: Region Codes and Usage
The updated Master Server backend that supports the Server Browsing SDK has the ability to identify the country a server is located in based on its IP address, and based on that country, sort it into a specific region. Master regions are make up of smaller regions. You can use filtering to restrict the list of servers returned to a specific country or region, thus giving players a list that better represents their play-able servers.
Regions are identified by a region ID number, however a particular server can be listed in multiple regions since regions are "nested". Because of this, the region number for a server is actually the sum of all the regions the server is in. To filter on a specific region, you should use the bitwise-AND operator to identify servers that are listed in that region.
For example, to identify servers in North America, you would use the filter: (region & 2) = 2 , since 2 is the region code for North America. Normal bitwise math can be used to check for multiple regions. For example, to check for North America or Caribbean, you can add them together: (region & 6) != 0
regionid regionname ----------- ---------------- 1 Americas 2 North America 4 Caribbean 8 Central America 16 South America 32 Africa 64 Central Africa 128 East Africa 256 Northern Africa 512 Southern Africa 1024 West Africa 2048 Asia 4096 East Asia 8192 Pacific 16384 South Asia 32768 South-East Asia 65536 Europe 131072 Baltic States 262144 Commonwealth of Independent States 524288 Eastern Europe 1048576 Middle East 2097152 South-East Europe 4194304 Western Europe
ccode country regionname ----- ------------------------------ ------------ BI Burundi Central Africa CM Cameroon Central Africa CF Central African Republic Central Africa TD Chad Central Africa CG Congo Central Africa GQ Equatorial Guinea Central Africa RW Rwanda Central Africa DJ Djibouti East Africa ER Eritrea East Africa ET Ethiopia East Africa KE Kenya East Africa SC Seychelles East Africa SO Somalia East Africa SH St. Helena East Africa SD Sudan East Africa TZ Tanzania East Africa UG Uganda East Africa DZ Algeria Northern Africa EG Egypt Northern Africa LY Libya Northern Africa MA Morocco Northern Africa TN Tunisia Northern Africa AO Angola Southern Africa BW Botswana Southern Africa BV Bouvet Island Southern Africa KM Comoros Southern Africa HM Heard and McDonald Islands Southern Africa LS Lesotho Southern Africa MG Madagascar Southern Africa MW Malawi Southern Africa MU Mauritius Southern Africa YT Mayotte Southern Africa MZ Mozambique Southern Africa NA Namibia Southern Africa RE Reunion Southern Africa ZA South Africa Southern Africa SZ Swaziland Southern Africa ZM Zambia Southern Africa ZW Zimbabwe Southern Africa BJ Benin West Africa BF Burkina Faso West Africa CV Cape Verde West Africa CI Cote D`ivoire West Africa GA Gabon West Africa GM Gambia West Africa GH Ghana West Africa GN Guinea West Africa GW Guinea-Bissau West Africa LR Liberia West Africa ML Mali West Africa MR Mauritania West Africa NE Niger West Africa NG Nigeria West Africa ST Sao Tome and Principe West Africa SN Senegal West Africa SL Sierra Leone West Africa TG Togo West Africa AI Anguilla Caribbean AG Antigua and Barbuda Caribbean AW Aruba Caribbean BS Bahamas Caribbean BB Barbados Caribbean BM Bermuda Caribbean KY Cayman Islands Caribbean CU Cuba Caribbean DM Dominica Caribbean DO Dominican Republic Caribbean GD Grenada Caribbean GP Guadeloupe Caribbean HT Haiti Caribbean JM Jamaica Caribbean MQ Martinique Caribbean MS Montserrat Caribbean AN Netherlands Antilles Caribbean PR Puerto Rico Caribbean VC Saint Vincent and The Grenadin Caribbean KN St Kitts-Nevis Caribbean LC St Lucia Caribbean TT Trinidad & Tobago Caribbean TC Turks & Caicos Islands Caribbean VG Virgin Islands (British) Caribbean VI Virgin Islands (US) Caribbean BZ Belize Central America CR Costa Rica Central America SV El Salvador Central America GT Guatemala Central America HN Honduras Central America MX Mexico Central America NI Nicaragua Central America PA Panama Central America CA Canada North America GL Greenland North America PM St. Pierre and Miquelon North America US United States North America UM US Minor Outlying Islands North America AR Argentina South America BO Bolivia South America BR Brazil South America CL Chile South America CO Colombia South America EC Ecuador South America FK Falkland Islands (Malvinas) South America GF French Guiana South America GY Guyana South America PY Paraguay South America PE Peru South America GS S. Georgia and S. Sandwich Isl South America SR Suriname South America UY Uruguay South America VE Venezuela South America CN China East Asia HK Hong Kong East Asia JP Japan East Asia MO Macao East Asia MN Mongolia East Asia KP North Korea East Asia KR South Korea East Asia TW Taiwan East Asia AS American Samoa Pacific AU Australia Pacific CK Cook Islands Pacific FJ Fiji Pacific PF French Polynesia Pacific GU Guam Pacific KI Kiribati Pacific MH Marshall Islands Pacific FM Micronesia Pacific NR Nauru Pacific NC New Caledonia Pacific NZ New Zealand Pacific NU Niue Pacific NF Norfolk Island Pacific MP Northern Mariana Islands Pacific PG Papua New Guinea Pacific PN Pitcairn Islands Pacific EH Samoa Pacific SB Solomon Islands Pacific TO Tonga Pacific TK Tonga Pacific TV Tuvalu Pacific VU Vanuatu Pacific WF Wallis and Futuna Islands Pacific AF Afghanistan South Asia BD Bangladesh South Asia BT Bhutan South Asia IO British Indian Ocean Territory South Asia IN India South Asia MV Maldives South Asia NP Nepal South Asia PK Pakistan South Asia LK Sri Lanka South Asia BN Brunei Darussalam South-East Asia KH Cambodia South-East Asia CX Christmas Island South-East Asia CC Cocos (Keeling Islands) South-East Asia TP East Timor South-East Asia ID Indonesia South-East Asia LA Laos South-East Asia MY Malaysia South-East Asia MM Myanmar South-East Asia PW Palau South-East Asia PH Philippines South-East Asia SG Singapore South-East Asia TH Thailand South-East Asia VN Vietnam South-East Asia EE Estonia Baltic States LV Latvia Baltic States LT Lithuania Baltic States AM Armenia CIS AZ Azerbaijan CIS BY Belarus CIS GE Georgia CIS KZ Kazakstan CIS KG Kyrgyzstan CIS MD Moldova CIS RU Russian Federation CIS TJ Tajikistan CIS TM Turkmenistan CIS UA Ukraine CIS UZ Uzbekistan CIS CZ Czech Republic Eastern Europe HU Hungary Eastern Europe PL Poland Eastern Europe RO Romania Eastern Europe SK Slovak Republic Eastern Europe BH Bahrain Middle East IR Iran Middle East IQ Iraq Middle East IL Israel/Occupied Territories Middle East JO Jordan Middle East KW Kuwait Middle East LB Lebanon Middle East OM Oman Middle East QA Qatar Middle East SA Saudi Arabia Middle East SY Syria Middle East AE United Arab Emirates Middle East YE Yemen Middle East AL Albania South-East Europe BA Bosnia-Herzegovina South-East Europe BG Bulgaria South-East Europe HR Croatia South-East Europe CY Cyprus South-East Europe GR Greece South-East Europe MK Macedonia South-East Europe MT Malta South-East Europe SI Slovenia South-East Europe TR Turkey South-East Europe YU Yugoslavia South-East Europe AD Andorra Western Europe AT Austria Western Europe BE Belgium Western Europe DK Denmark Western Europe FO Faroe Islands Western Europe FI Finland Western Europe FR France Western Europe DE Germany Western Europe GI Gibraltar Western Europe IS Iceland Western Europe IE Ireland Western Europe IT Italy Western Europe LI Liechtenstein Western Europe LU Luxembourg Western Europe MC Monaco Western Europe NL Netherlands Western Europe NO Norway Western Europe PT Portugal Western Europe SM San Marino Western Europe ES Spain Western Europe SJ Svalbard and Jan Mayen Islands Western Europe SE Sweden Western Europe CH Switzerland Western Europe UK United Kingdom Western Europe VA Vatican Western Europe