Store side leader information in the database.

Backport of #7530
This commit is contained in:
Pentarctagon 2023-04-21 12:25:30 -05:00
parent eef9a072a5
commit 7149a3830c
26 changed files with 86 additions and 24 deletions

View file

@ -313,12 +313,12 @@ void dbconn::update_game_end(const std::string& uuid, int game_id, const std::st
log_sql_exception("Failed to update the game end for game info row for UUID `"+uuid+"` and game ID `"+std::to_string(game_id)+"`", e);
}
}
void dbconn::insert_game_player_info(const std::string& uuid, int game_id, const std::string& username, int side_number, int is_host, const std::string& faction, const std::string& version, const std::string& source, const std::string& current_user)
void dbconn::insert_game_player_info(const std::string& uuid, int game_id, const std::string& username, int side_number, int is_host, const std::string& faction, const std::string& version, const std::string& source, const std::string& current_user, const std::string& leaders)
{
try
{
modify(connection_, "INSERT INTO `"+db_game_player_info_table_+"`(INSTANCE_UUID, GAME_ID, USER_ID, SIDE_NUMBER, IS_HOST, FACTION, CLIENT_VERSION, CLIENT_SOURCE, USER_NAME) VALUES(?, ?, IFNULL((SELECT user_id FROM `"+db_users_table_+"` WHERE username = ?), -1), ?, ?, ?, ?, ?, ?)",
uuid, game_id, username, side_number, is_host, faction, version, source, current_user);
modify(connection_, "INSERT INTO `"+db_game_player_info_table_+"`(INSTANCE_UUID, GAME_ID, USER_ID, SIDE_NUMBER, IS_HOST, FACTION, CLIENT_VERSION, CLIENT_SOURCE, USER_NAME, LEADERS) VALUES(?, ?, IFNULL((SELECT user_id FROM `"+db_users_table_+"` WHERE username = ?), -1), ?, ?, ?, ?, ?, ?, ?)",
uuid, game_id, username, side_number, is_host, faction, version, source, current_user, leaders);
}
catch(const mariadb::exception::base& e)
{

View file

@ -132,7 +132,7 @@ class dbconn
/**
* @see forum_user_handler::db_insert_game_player_info().
*/
void insert_game_player_info(const std::string& uuid, int game_id, const std::string& username, int side_number, int is_host, const std::string& faction, const std::string& version, const std::string& source, const std::string& current_user);
void insert_game_player_info(const std::string& uuid, int game_id, const std::string& username, int side_number, int is_host, const std::string& faction, const std::string& version, const std::string& source, const std::string& current_user, const std::string& leaders);
/**
* @see forum_user_handler::db_insert_game_content_info().

View file

@ -215,8 +215,8 @@ void fuh::db_update_game_end(const std::string& uuid, int game_id, const std::st
conn_.update_game_end(uuid, game_id, replay_location);
}
void fuh::db_insert_game_player_info(const std::string& uuid, int game_id, const std::string& username, int side_number, int is_host, const std::string& faction, const std::string& version, const std::string& source, const std::string& current_user){
conn_.insert_game_player_info(uuid, game_id, username, side_number, is_host, faction, version, source, current_user);
void fuh::db_insert_game_player_info(const std::string& uuid, int game_id, const std::string& username, int side_number, int is_host, const std::string& faction, const std::string& version, const std::string& source, const std::string& current_user, const std::string& leaders){
conn_.insert_game_player_info(uuid, game_id, username, side_number, is_host, faction, version, source, current_user, leaders);
}
unsigned long long fuh::db_insert_game_content_info(const std::string& uuid, int game_id, const std::string& type, const std::string& name, const std::string& id, const std::string& addon_id, const std::string& addon_version){

View file

@ -167,8 +167,9 @@ public:
* @param version The version of Wesnoth this player is using.
* @param source The source where this player downloaded Wesnoth (ie: Steam, SourceForge, etc).
* @param current_user The player currently in control of this side.
* @param leaders The comma-delimited list of leader unit types for that side.
*/
void db_insert_game_player_info(const std::string& uuid, int game_id, const std::string& username, int side_number, int is_host, const std::string& faction, const std::string& version, const std::string& source, const std::string& current_user);
void db_insert_game_player_info(const std::string& uuid, int game_id, const std::string& username, int side_number, int is_host, const std::string& faction, const std::string& version, const std::string& source, const std::string& current_user, const std::string& leaders);
/**
* Inserts information about the content being played.

View file

@ -139,7 +139,7 @@ public:
virtual void async_get_and_send_game_history(boost::asio::io_service& io_service, wesnothd::server& s, wesnothd::player_iterator player, int player_id, int offset) =0;
virtual void db_insert_game_info(const std::string& uuid, int game_id, const std::string& version, const std::string& name, int reload, int observers, int is_public, int has_password) = 0;
virtual void db_update_game_end(const std::string& uuid, int game_id, const std::string& replay_location) = 0;
virtual void db_insert_game_player_info(const std::string& uuid, int game_id, const std::string& username, int side_number, int is_host, const std::string& faction, const std::string& version, const std::string& source, const std::string& current_user) = 0;
virtual void db_insert_game_player_info(const std::string& uuid, int game_id, const std::string& username, int side_number, int is_host, const std::string& faction, const std::string& version, const std::string& source, const std::string& current_user, const std::string& leaders) = 0;
virtual unsigned long long db_insert_game_content_info(const std::string& uuid, int game_id, const std::string& type, const std::string& name, const std::string& id, const std::string& addon_id, const std::string& addon_version) = 0;
virtual void db_set_oos_flag(const std::string& uuid, int game_id) = 0;
virtual void async_test_query(boost::asio::io_service& io_service, int limit) = 0;

View file

@ -1719,7 +1719,27 @@ void server::handle_player_in_game(player_iterator p, simple_wml::document& data
source = "Default";
}
}
user_handler_->db_insert_game_player_info(uuid_, g.db_id(), side["player_id"].to_string(), side["side"].to_int(), side["is_host"].to_bool(), side["faction"].to_string(), version, source, side["current_player"].to_string());
// approximately determine leader(s) for the side like the client does
// useful generally to know how often leaders are used vs other leaders
// also as an indication for which faction was chosen if a custom recruit list is provided since that results in "Custom" in the faction field
std::vector<std::string> leaders;
// if a type= attribute is specified for the side, add it
if(side.attr("type") != "") {
leaders.emplace_back(side.attr("type").to_string());
}
// add each [unit] in the side that has canrecruit=yes
for(const auto unit : side.children("unit")) {
if(unit->attr("canrecruit") == "yes") {
leaders.emplace_back(unit->attr("type").to_string());
}
}
// add any [leader] specified for the side
for(const auto leader : side.children("leader")) {
leaders.emplace_back(leader->attr("type").to_string());
}
user_handler_->db_insert_game_player_info(uuid_, g.db_id(), side["player_id"].to_string(), side["side"].to_int(), side["is_host"].to_bool(), side["faction"].to_string(), version, source, side["current_player"].to_string(), utils::join(leaders));
}
}

View file

@ -5,6 +5,7 @@ from
from wesnothd_game_info game, wesnothd_game_player_info player
where game.INSTANCE_UUID = player.INSTANCE_UUID
and game.GAME_ID = player.GAME_ID
and player.CLIENT_SOURCE != ''
group by player.USER_ID
) as temp
where YEAR(FIRST_GAME_START) = YEAR(CURRENT_DATE - INTERVAL 1 MONTH)

View file

@ -1,13 +1,14 @@
select count(*) as NEW_USERS_FIRST_GAME, CLIENT_SOURCE
select count(*) as NEW_USERS_FIRST_GAME, (select p2.CLIENT_SOURCE from wesnothd_game_player_info p2 where p2.USER_ID = temp.USER_ID limit 1) as CLIENT_SOURCE
from
(
select player.USER_ID, min(game.START_TIME) as FIRST_GAME_START, CLIENT_SOURCE
select player.USER_ID, min(game.START_TIME) as FIRST_GAME_START
from wesnothd_game_info game, wesnothd_game_player_info player
where game.INSTANCE_UUID = player.INSTANCE_UUID
and game.GAME_ID = player.GAME_ID
and player.CLIENT_SOURCE != ''
group by player.USER_ID, CLIENT_SOURCE
group by player.USER_ID
) as temp
where YEAR(FIRST_GAME_START) = YEAR(CURRENT_DATE - INTERVAL 2 MONTH)
and MONTH(FIRST_GAME_START) = MONTH(CURRENT_DATE - INTERVAL 2 MONTH)
where YEAR(FIRST_GAME_START) = YEAR(CURRENT_DATE - INTERVAL 1 MONTH)
and MONTH(FIRST_GAME_START) = MONTH(CURRENT_DATE - INTERVAL 1 MONTH)
group by CLIENT_SOURCE

View file

@ -1,13 +1,17 @@
select player.FACTION, count(*) as SIDE_COUNT
select content.ID, player.FACTION, count(*) as SIDE_COUNT
from wesnothd_game_info game
inner join wesnothd_game_player_info player
on game.INSTANCE_UUID = player.INSTANCE_UUID
and game.GAME_ID = player.GAME_ID
and player.USER_ID != -1
and player.FACTION != ''
inner join wesnothd_game_content_info content
on game.INSTANCE_UUID = content.INSTANCE_UUID
and game.GAME_ID = content.GAME_ID
and content.TYPE = 'era'
where YEAR(game.START_TIME) = YEAR(CURRENT_DATE - INTERVAL 1 MONTH)
and MONTH(game.START_TIME) = MONTH(CURRENT_DATE - INTERVAL 1 MONTH)
and game.END_TIME is not NULL
and TIMESTAMPDIFF(MINUTE, game.START_TIME, game.END_TIME) > 5
group by player.FACTION
group by content.ID, player.FACTION
order by count(*) desc

View file

@ -0,0 +1,18 @@
select content.ID, player.LEADERS, count(*) as LEADER_COUNT
from wesnothd_game_info game
inner join wesnothd_game_player_info player
on game.INSTANCE_UUID = player.INSTANCE_UUID
and game.GAME_ID = player.GAME_ID
and player.USER_ID != -1
and player.FACTION != ''
inner join wesnothd_game_content_info content
on game.INSTANCE_UUID = content.INSTANCE_UUID
and game.GAME_ID = content.GAME_ID
and content.TYPE = 'era'
where YEAR(game.START_TIME) = YEAR(CURRENT_DATE - INTERVAL 1 MONTH)
and MONTH(game.START_TIME) = MONTH(CURRENT_DATE - INTERVAL 1 MONTH)
and game.END_TIME is not NULL
and TIMESTAMPDIFF(MINUTE, game.START_TIME, game.END_TIME) > 5
group by content.ID, player.LEADERS
order by count(*) desc

View file

@ -57,14 +57,11 @@ create table extra
-- GAME_NAME: the game's displayed title in the lobby
-- START_TIME: when the players enter the game and begin playing
-- END_TIME: when the game ends, for any particular reason
-- MAP_NAME: the mp_scenario attribute value
-- MAP_SOURCE_ADDON: the add-on the map comes from
-- MAP_VERSION: the version of the add-on the map comes from
-- ERA_NAME: the mp_era attribute value
-- ERA_SOURCE_ADDON: the add-on the era comes from
-- ERA_VERSION: the version of the add-on the era comes from
-- REPLAY_NAME: the file name of the replay create when the game is ended
-- OOS: Y/N flag of whether the game encountered an OOS error
-- RELOAD: Y/N flag for whether the game allows observers
-- PASSWORD: Y/N flag for whether the game had a password set
-- PUBLIC: Y/N flag for whether the game will have a publicly accesible replay created for it
create table game_info
(
INSTANCE_UUID CHAR(36) NOT NULL,
@ -92,6 +89,7 @@ CREATE INDEX START_TIME_IDX ON game_info(START_TIME);
-- CLIENT_VERSION: the version of the wesnoth client used to connect
-- CLIENT_SOURCE: where the wesnoth client was downloaded from - SourceForge, Steam, etc
-- USER_NAME: the username logged in with
-- LEADERS: the leader(s) for the side. if multiple leaders are found, then they are comma delimited.
create table game_player_info
(
INSTANCE_UUID CHAR(36) NOT NULL,
@ -103,6 +101,7 @@ create table game_player_info
CLIENT_VERSION VARCHAR(255) NOT NULL DEFAULT '',
CLIENT_SOURCE VARCHAR(255) NOT NULL DEFAULT '',
USER_NAME VARCHAR(255) NOT NULL DEFAULT '',
LEADERS VARCHAR(255) NOT NULL DEFAULT '',
PRIMARY KEY (INSTANCE_UUID, GAME_ID, SIDE_NUMBER)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE INDEX USER_ID_IDX ON game_player_info(USER_ID);
@ -112,7 +111,7 @@ CREATE INDEX USER_ID_IDX ON game_player_info(USER_ID);
-- ID: the id of the content
-- NAME: the content's user-visible name
-- ADDON_ID: the id of the add-on that the particular content came from
-- ADDON_VERSION: the version of the source add-on
-- ADDON_VERSION: the version of the add-on
create table game_content_info
(
INSTANCE_UUID CHAR(36) NOT NULL,
@ -122,7 +121,7 @@ create table game_content_info
NAME VARCHAR(255),
ADDON_ID VARCHAR(100) NOT NULL,
ADDON_VERSION VARCHAR(255) NOT NULL,
PRIMARY KEY (INSTANCE_UUID, GAME_ID, TYPE, ID, SOURCE)
PRIMARY KEY (INSTANCE_UUID, GAME_ID, TYPE, ID, ADDON_ID)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- information about an uploaded addon
@ -134,6 +133,8 @@ create table game_content_info
-- FORUM_AUTH: whether forum authentication is to be used when uploading
-- UPLOADED_ON: when the addon was uploaded
-- FEEDBACK_TOPIC: the forum topic ID where feedback for the addon can be posted, 0 if not set
-- DOWNLOAD_COUNT: the number of times the add-on has been downloaded by players (does not count downloads from https://addons.wesnoth.org)
-- UPLOADER: the author attribute or the chosen secondary_author from the _server.pbl
create table addon_info
(
INSTANCE_VERSION VARCHAR(255) NOT NULL,
@ -144,9 +145,25 @@ create table addon_info
FORUM_AUTH BIT(1) NOT NULL,
UPLOADED_ON TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
FEEDBACK_TOPIC INT UNSIGNED NOT NULL,
DOWNLOAD_COUNT INT UNSIGNED NOT NULL DEFAULT 0,
UPLOADER VARCHAR(255),
PRIMARY KEY (INSTANCE_VERSION, ADDON_ID, VERSION)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- listing of the primary author and any secondary authors when forum_auth is used
-- INSTANCE_VERSION: the version of the addons server instance
-- ADDON_ID: the ID of the addon (folder name)
-- AUTHOR: the author attribute or the chosen secondary_author from the _server.pbl
-- IS_PRIMARY: whether this is the primary author or not
create table addon_authors
(
INSTANCE_VERSION VARCHAR(255) NOT NULL,
ADDON_ID VARCHAR(255) NOT NULL,
AUTHOR VARCHAR(255) NOT NULL,
IS_PRIMARY BIT(1) NOT NULL,
PRIMARY KEY (INSTANCE_VERSION, ADDON_ID, AUTHOR)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- history of user sessions
-- LOGIN_ID: auto generated ID to use as a primary key
-- USER_NAME: the username logged in with