diff --git a/NETWORKING.md b/NETWORKING.md index c4536aebc..4d2378008 100644 --- a/NETWORKING.md +++ b/NETWORKING.md @@ -253,6 +253,18 @@ Current players in server with ip in human readable format and time played of ea `*_player_stats` All players with online id and username with their time played stats in this server since creation of this database. +A empty table named `v(server database version)_countries` will also be created in your database if not exists: +```sql +CREATE TABLE IF NOT EXISTS (table name above) +( + country_code TEXT NOT NULL PRIMARY KEY UNIQUE, -- Unique 2-letter country code + country_flag TEXT NOT NULL, -- Unicode country flag representation of 2-letter country code + country_name TEXT NOT NULL -- Readable name of this country +) WITHOUT ROWID; +``` + +If you want to see flags and readable names of countries in `*_full_stats` and `*_current_players` views, you need to initialize `v(server database version)_countries` table, check [this script](tools/generate-countries-table.py). + For IP, online ID ban list or player reports, you need to create one yourself: ```sql CREATE TABLE ip_ban diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index c8b2ca2c0..28dc9b086 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -258,6 +258,18 @@ void ServerLobby::initServerStatsTable() if (m_server_stats_table.empty()) return; + // Extra default table _countries: + // Server owner need to initialise this table himself, check NETWORKING.md + std::string country_table_name = std::string("v") + StringUtils::toString( + ServerConfig::m_server_db_version) + "_countries"; + query = StringUtils::insertValues( + "CREATE TABLE IF NOT EXISTS %s (\n" + " country_code TEXT NOT NULL PRIMARY KEY UNIQUE, -- Unique 2-letter country code\n" + " country_flag TEXT NOT NULL, -- Unicode country flag representation of 2-letter country code\n" + " country_name TEXT NOT NULL -- Readable name of this country\n" + ") WITHOUT ROWID;", country_table_name.c_str()); + easySQLQuery(query); + // Default views: // _full_stats // Full stats with ip in human readable format and time played of each @@ -269,10 +281,13 @@ void ServerLobby::initServerStatsTable() oss << "CREATE VIEW IF NOT EXISTS " << view_name << " AS\n" << " SELECT host_id, ip,\n" << " ((ip >> 24) & 255) ||'.'|| ((ip >> 16) & 255) ||'.'|| ((ip >> 8) & 255) ||'.'|| ((ip ) & 255) AS ip_readable,\n" - << " port, online_id, username, player_num, country_code, version,\n" + << " port, online_id, username, player_num,\n" + << " " << m_server_stats_table << ".country_code AS country_code, country_flag, country_name, version,\n" << " ROUND((STRFTIME(\"%s\", disconnected_time) - STRFTIME(\"%s\", connected_time)) / 60.0, 2) AS time_played,\n" - << " connected_time, disconnected_time, ping\n" - << " FROM " << m_server_stats_table << " ORDER BY connected_time DESC;"; + << " connected_time, disconnected_time, ping FROM " << m_server_stats_table << "\n" + << " LEFT JOIN " << country_table_name << " ON " + << country_table_name << ".country_code = " << m_server_stats_table << ".country_code\n" + << " ORDER BY connected_time DESC;"; query = oss.str(); easySQLQuery(query); @@ -287,9 +302,12 @@ void ServerLobby::initServerStatsTable() oss << "CREATE VIEW IF NOT EXISTS " << view_name << " AS\n" << " SELECT host_id, ip,\n" << " ((ip >> 24) & 255) ||'.'|| ((ip >> 16) & 255) ||'.'|| ((ip >> 8) & 255) ||'.'|| ((ip ) & 255) AS ip_readable,\n" - << " port, online_id, username, player_num, country_code, version,\n" + << " port, online_id, username, player_num,\n" + << " " << m_server_stats_table << ".country_code AS country_code, country_flag, country_name, version,\n" << " ROUND((STRFTIME(\"%s\", 'now') - STRFTIME(\"%s\", connected_time)) / 60.0, 2) AS time_played,\n" << " connected_time, ping FROM " << m_server_stats_table << "\n" + << " LEFT JOIN " << country_table_name << " ON " + << country_table_name << ".country_code = " << m_server_stats_table << ".country_code\n" << " WHERE connected_time = disconnected_time;"; query = oss.str(); easySQLQuery(query); diff --git a/tools/generate-countries-table.py b/tools/generate-countries-table.py new file mode 100755 index 000000000..7b8c5e0b2 --- /dev/null +++ b/tools/generate-countries-table.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python3 + +# usage: generate-countries-table.py > countries.csv +# in sqlite3 terminal: +# +# .mode csv +# .headers off +# .separator ";" +# .import `full path to countries.csv` `v(database_version)_countries` +# + +import csv +import os +import sys + +CSV_FILE = '../data/country_names.csv' +# Use another name in the country_code header if you want countries names in different language +READABLE_NAME = 'en' +# ord("🇦") - ord("A") +FLAG_OFFSET = 127397 + +if not os.path.exists(CSV_FILE): + print("File = {} does not exist.".format(CSV_FILE)) + sys.exit(1) + +with open(CSV_FILE, 'r') as csvfile: + country = csv.DictReader(csvfile, delimiter=';', quotechar='"') + # Skip header + next(country) + for row in country: + country_code = row['country_code'] + codepoints = [ord(x) + FLAG_OFFSET for x in country_code] + print('%s;%s;%s' % (country_code, chr(codepoints[0]) + chr(codepoints[1]), row[READABLE_NAME]))