Skip to content

Commit

Permalink
Use an independent ID for the database's GAME_ID column.
Browse files Browse the repository at this point in the history
Currently, wesnothd uses the game instance's `id_` value when inserting into the game_info, game_player_info, and game_modification_info tables.  However, this value is unique only per game instance, not per scenario.  This then results in problems when handling MP campaigns, which re-use the same game instance for multiple scenarios.  Incrementing the game instance's `id_` was determined to not be suitable since it's used in a boost multi-index, and instead creating a brand new game instance for each scenario in an MP campaign is complex without being especially useful beyond this case.

This commit instead adds a separate `db_id_` value to each game instance, which can be incremented without causing any issues since it's used nowhere else, and is what will be inserted into the database.  This means the `db_id_` is unique per scenario, and therefore resolves the below two issues.

Fixes #4281
Fixes #4341
  • Loading branch information
Pentarctagon committed Feb 26, 2020
1 parent 5842f48 commit 1a46bea
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 6 deletions.
4 changes: 3 additions & 1 deletion src/server/game.cpp
Expand Up @@ -84,6 +84,7 @@ void send_to_players(simple_wml::document& data, const Container& players, socke
}

int game::id_num = 1;
int game::db_id_num = 1;

void game::missing_user(socket_ptr /*socket*/, const std::string& func) const
{
Expand All @@ -98,6 +99,7 @@ game::game(player_connections& player_connections,
const std::string& replay_save_path)
: player_connections_(player_connections)
, id_(id_num++)
, db_id_(db_id_num++)
, name_(name)
, password_()
, owner_(host)
Expand Down Expand Up @@ -1836,7 +1838,7 @@ static bool is_invalid_filename_char(char c)
std::string game::get_replay_filename()
{
std::stringstream name;
name << (*starting_pos(level_.root()))["name"] << " Turn " << current_turn() << " (" << id_ << ").bz2";
name << (*starting_pos(level_.root()))["name"] << " Turn " << current_turn() << " (" << db_id_ << ").bz2";
std::string filename(name.str());
std::replace(filename.begin(), filename.end(), ' ', '_');
filename.erase(std::remove_if(filename.begin(), filename.end(), is_invalid_filename_char), filename.end());
Expand Down
17 changes: 17 additions & 0 deletions src/server/game.hpp
Expand Up @@ -54,6 +54,16 @@ class game
return id_;
}

int db_id() const
{
return db_id_;
}

void next_db_id()
{
db_id_ = db_id_num++;
}

const std::string& name() const
{
return name_;
Expand Down Expand Up @@ -460,9 +470,16 @@ class game

player_connections& player_connections_;

// used for unique identification of game instances within wesnothd
static int id_num;
int id_;

// used for unique identification of games played in the database
// necessary since for MP campaigns multiple scenarios can be played within the same game instance
// and we need a unique ID per scenario played, not per game instance
static int db_id_num;
int db_id_;

/** The name of the game. */
std::string name_;
std::string password_;
Expand Down
14 changes: 9 additions & 5 deletions src/server/server.cpp
Expand Up @@ -1305,7 +1305,7 @@ void server::cleanup_game(game* game_ptr)
metrics_.game_terminated(game_ptr->termination_reason());

if(user_handler_){
user_handler_->db_update_game_end(uuid_, game_ptr->id(), game_ptr->get_replay_filename());
user_handler_->db_update_game_end(uuid_, game_ptr->db_id(), game_ptr->get_replay_filename());
}

simple_wml::node* const gamelist = games_and_users_list_.child("gamelist");
Expand Down Expand Up @@ -1547,13 +1547,17 @@ void server::handle_player_in_game(socket_ptr socket, std::shared_ptr<simple_wml
}

g.save_replay();
if(user_handler_){
user_handler_->db_update_game_end(uuid_, g.db_id(), g.get_replay_filename());
}

g.new_scenario(socket);
g.reset_last_synced_context_id();

// Record the full scenario in g.level()
g.level().clear();
scenario->copy_into(g.level().root());
g.next_db_id();

if(g.description() == nullptr) {
ERR_SERVER << client_address(socket) << "\tERROR: \"" << g.name() << "\" (" << g.id()
Expand Down Expand Up @@ -1621,7 +1625,7 @@ void server::handle_player_in_game(socket_ptr socket, std::shared_ptr<simple_wml

if(user_handler_) {
const simple_wml::node& m = *g.level().root().child("multiplayer");
user_handler_->db_insert_game_info(uuid_, g.id(), game_config::wesnoth_version.str(), g.name(), m["mp_scenario"].to_string(), m["mp_era"].to_string(), g.is_reload(), m["observer"].to_bool(), !m["private_replay"].to_bool(), g.has_password());
user_handler_->db_insert_game_info(uuid_, g.db_id(), game_config::wesnoth_version.str(), g.name(), m["mp_scenario"].to_string(), m["mp_era"].to_string(), g.is_reload(), m["observer"].to_bool(), !m["private_replay"].to_bool(), g.has_password());

const simple_wml::node::child_list& sides = g.get_sides_list();
for(unsigned side_index = 0; side_index < sides.size(); ++side_index) {
Expand All @@ -1642,13 +1646,13 @@ void server::handle_player_in_game(socket_ptr socket, std::shared_ptr<simple_wml
source = "Default";
}
}
user_handler_->db_insert_game_player_info(uuid_, g.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());
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());
}

const std::string mods = m["active_mods"].to_string();
if(mods != "") {
for(const std::string mod : utils::split(mods, ',')){
user_handler_->db_insert_modification_info(uuid_, g.id(), mod);
user_handler_->db_insert_modification_info(uuid_, g.db_id(), mod);
}
}
}
Expand Down Expand Up @@ -1770,7 +1774,7 @@ void server::handle_player_in_game(socket_ptr socket, std::shared_ptr<simple_wml
if((*info)["condition"].to_string() == "out of sync") {
g.send_and_record_server_message(player.name() + " reports out of sync errors.");
if(user_handler_){
user_handler_->db_set_oos_flag(uuid_, g.id());
user_handler_->db_set_oos_flag(uuid_, g.db_id());
}
}
}
Expand Down

0 comments on commit 1a46bea

Please sign in to comment.