mirror of
https://github.com/wesnoth/wesnoth
synced 2025-04-09 20:17:09 +00:00
Add queue-like functionality to the multiplayer lobby (#9819)
This allows defining an [game_presets] tag which contains [game] tags describing how to show the game in the lobby and what settings the game should use. Functionally this adds an entry per [game] into the Matchmaking section of the MP lobby: * If a player clicks Join and there are no previously created games from this "queue" that are open, then the server instead responds telling the client to create the game. The game is created directly using the settings defined in its [game] tag, so for the player it looks like they clicked join and then go straight to the MP staging screen. * If a player clicks Join and there is an open game created from this "queue", then the server instead responds telling the client the actual ID of the game to join and the client then joins that game just as if they had clicked Join on a normal game. Currently only implemented for mainline.
This commit is contained in:
parent
45b3f682c0
commit
a900508835
|
@ -112,6 +112,8 @@
|
|||
|
||||
{game_config.cfg}
|
||||
|
||||
{game_presets.cfg}
|
||||
|
||||
[textdomain]
|
||||
name="wesnoth-lib"
|
||||
[/textdomain]
|
||||
|
|
38
data/game_presets.cfg
Normal file
38
data/game_presets.cfg
Normal file
|
@ -0,0 +1,38 @@
|
|||
[game_presets]
|
||||
[game]
|
||||
scenario = "multiplayer_The_Freelands"
|
||||
era = "era_default"
|
||||
fog = yes
|
||||
shroud = no
|
||||
village_gold = 2
|
||||
village_support = 1
|
||||
experience_modifier = 70
|
||||
countdown = false
|
||||
random_start_time = no
|
||||
shuffle_sides = no
|
||||
[/game]
|
||||
[game]
|
||||
scenario = "multiplayer_The_Wilderlands"
|
||||
era = "era_default"
|
||||
fog = yes
|
||||
shroud = no
|
||||
village_gold = 2
|
||||
village_support = 1
|
||||
experience_modifier = 70
|
||||
countdown = false
|
||||
random_start_time = no
|
||||
shuffle_sides = no
|
||||
[/game]
|
||||
[game]
|
||||
scenario = "multiplayer_2p_Dark_Forecast"
|
||||
era = "era_default"
|
||||
fog = yes
|
||||
shroud = no
|
||||
village_gold = 2
|
||||
village_support = 1
|
||||
experience_modifier = 100
|
||||
countdown = false
|
||||
random_start_time = no
|
||||
shuffle_sides = no
|
||||
[/game]
|
||||
[/game_presets]
|
|
@ -524,5 +524,28 @@
|
|||
{SIMPLE_KEY code string}
|
||||
{DATA_TAG args 0 1 any}
|
||||
[/tag]
|
||||
[tag]
|
||||
name="game_presets"
|
||||
max=infinite
|
||||
[tag]
|
||||
name="game"
|
||||
max=infinite
|
||||
{SIMPLE_KEY scenario string}
|
||||
{SIMPLE_KEY era string}
|
||||
{SIMPLE_KEY fog bool}
|
||||
{SIMPLE_KEY shroud bool}
|
||||
{SIMPLE_KEY village_gold int}
|
||||
{SIMPLE_KEY village_support int}
|
||||
{SIMPLE_KEY experience_modifier int}
|
||||
{SIMPLE_KEY countdown bool}
|
||||
{SIMPLE_KEY countdown_init_time int}
|
||||
{SIMPLE_KEY countdown_turn_bonus int}
|
||||
{SIMPLE_KEY countdown_reservoir_time int}
|
||||
{SIMPLE_KEY countdown_action_bonus int}
|
||||
{SIMPLE_KEY random_start_time bool}
|
||||
{SIMPLE_KEY shuffle_sides bool}
|
||||
{SIMPLE_KEY turn_count int}
|
||||
[/tag]
|
||||
[/tag]
|
||||
[/tag]
|
||||
[/wml_schema]
|
||||
|
|
|
@ -741,7 +741,9 @@ void connect_engine::send_level_data() const
|
|||
"name", params_.name,
|
||||
"password", params_.password,
|
||||
"ignored", prefs::get().get_ignored_delim(),
|
||||
"auto_hosted", false,
|
||||
// all queue games count as auto hosted, but not all auto hosted games are queue games
|
||||
"auto_hosted", mp_metadata_ ? mp_metadata_->is_queue_game : false,
|
||||
"queue_game", mp_metadata_ ? mp_metadata_->is_queue_game : false,
|
||||
},
|
||||
});
|
||||
mp::send_to_server(level_);
|
||||
|
|
|
@ -545,6 +545,15 @@ void create_engine::set_current_era_index(const std::size_t index, bool force)
|
|||
dependency_manager_->try_era_by_index(index, force);
|
||||
}
|
||||
|
||||
void create_engine::set_current_era_id(const std::string& id, bool force)
|
||||
{
|
||||
std::size_t index = dependency_manager_->get_era_index(id);
|
||||
|
||||
current_era_index_ = index;
|
||||
|
||||
dependency_manager_->try_era_by_index(index, force);
|
||||
}
|
||||
|
||||
bool create_engine::toggle_mod(const std::string& id, bool force)
|
||||
{
|
||||
force |= state_.classification().type != campaign_type::type::multiplayer;
|
||||
|
|
|
@ -356,6 +356,7 @@ public:
|
|||
void set_current_level(const std::size_t index);
|
||||
|
||||
void set_current_era_index(const std::size_t index, bool force = false);
|
||||
void set_current_era_id(const std::string& id, bool force = false);
|
||||
|
||||
std::size_t current_era_index() const
|
||||
{
|
||||
|
@ -401,8 +402,6 @@ private:
|
|||
void init_extras(const MP_EXTRA extra_type);
|
||||
void apply_level_filters();
|
||||
|
||||
std::size_t map_level_index(std::size_t index) const;
|
||||
|
||||
level_type::type current_level_type_;
|
||||
std::size_t current_level_index_;
|
||||
|
||||
|
|
|
@ -409,6 +409,20 @@ int manager::get_era_index() const
|
|||
return -1;
|
||||
}
|
||||
|
||||
int manager::get_era_index(const std::string& id) const
|
||||
{
|
||||
int result = 0;
|
||||
for(const config& i : depinfo_.child_range("era")) {
|
||||
if(i["id"] == id) {
|
||||
return result;
|
||||
}
|
||||
|
||||
result++;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int manager::get_scenario_index() const
|
||||
{
|
||||
int result = 0;
|
||||
|
|
|
@ -146,6 +146,7 @@ public:
|
|||
* @return the index of the era
|
||||
*/
|
||||
int get_era_index() const;
|
||||
int get_era_index(const std::string& id) const;
|
||||
|
||||
/**
|
||||
* Returns the selected scenario
|
||||
|
|
|
@ -114,6 +114,7 @@ game_info::game_info(const config& game, const std::vector<std::string>& install
|
|||
, map_data(game["map_data"])
|
||||
, name(font::escape_text(game["name"].str()))
|
||||
, scenario()
|
||||
, scenario_id()
|
||||
, type_marker()
|
||||
, remote_scenario(false)
|
||||
, map_info()
|
||||
|
@ -261,6 +262,7 @@ game_info::game_info(const config& game, const std::vector<std::string>& install
|
|||
if(level_cfg) {
|
||||
type_marker = make_game_type_marker(_("scenario_abbreviation^S"), false);
|
||||
scenario = (*level_cfg)["name"].str();
|
||||
scenario_id = (*level_cfg)["id"].str();
|
||||
info_stream << scenario;
|
||||
|
||||
// Reloaded games do not match the original scenario hash, so it makes no sense
|
||||
|
|
|
@ -70,6 +70,7 @@ struct game_info
|
|||
std::string map_data;
|
||||
std::string name;
|
||||
std::string scenario;
|
||||
std::string scenario_id;
|
||||
std::string type_marker;
|
||||
bool remote_scenario;
|
||||
std::string map_info;
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "game_initialization/lobby_info.hpp"
|
||||
|
||||
#include "addon/manager.hpp" // for installed_addons
|
||||
#include "game_config_manager.hpp"
|
||||
#include "log.hpp"
|
||||
#include "mp_ui_alerts.hpp"
|
||||
|
||||
|
@ -120,6 +121,61 @@ void lobby_info::process_gamelist(const config& data)
|
|||
|
||||
games_by_id_.clear();
|
||||
|
||||
int queued_id = 0;
|
||||
for(const config& game : game_config_manager::get()->game_config().mandatory_child("game_presets").child_range("game")) {
|
||||
config qgame;
|
||||
const config& scenario = game_config_manager::get()->game_config().find_mandatory_child("multiplayer", "id", game["scenario"].str());
|
||||
int human_sides = 0;
|
||||
for(const auto& side : scenario.child_range("side")) {
|
||||
if(side["controller"].str() == "human") {
|
||||
human_sides++;
|
||||
}
|
||||
}
|
||||
if(human_sides == 0) {
|
||||
ERR_LB << "No human sides for scenario " << game["scenario"];
|
||||
continue;
|
||||
}
|
||||
// negative id means a queue-defined game
|
||||
queued_id--;
|
||||
qgame["id"] = queued_id;
|
||||
// all are set as auto_hosted so they show up in that tab of the MP lobby
|
||||
qgame["auto_hosted"] = true;
|
||||
|
||||
qgame["name"] = scenario["name"];
|
||||
qgame["mp_scenario"] = game["scenario"];
|
||||
qgame["mp_era"] = game["era"];
|
||||
qgame["mp_use_map_settings"] = game["use_map_settings"];
|
||||
qgame["mp_fog"] = game["fog"];
|
||||
qgame["mp_shroud"] = game["shroud"];
|
||||
qgame["mp_village_gold"] = game["village_gold"];
|
||||
qgame["experience_modifier"] = game["experience_modifier"];
|
||||
|
||||
qgame["mp_countdown"] = game["countdown"];
|
||||
if(qgame["countdown"].to_bool()) {
|
||||
qgame["mp_countdown_reservoir_time"] = game["countdown_reservoir_time"];
|
||||
qgame["mp_countdown_init_time"] = game["countdown_init_time"];
|
||||
qgame["mp_countdown_action_bonus"] = game["countdown_action_bonus"];
|
||||
qgame["mp_countdown_turn_bonus"] = game["countdown_turn_bonus"];
|
||||
}
|
||||
|
||||
qgame["observer"] = game["observer"];
|
||||
qgame["human_sides"] = human_sides;
|
||||
|
||||
if(scenario.has_attribute("map_data")) {
|
||||
qgame["map_data"] = scenario["map_data"];
|
||||
} else {
|
||||
qgame["map_data"] = filesystem::read_map(scenario["map_file"]);
|
||||
}
|
||||
qgame["hash"] = game_config_manager::get()->game_config().mandatory_child("multiplayer_hashes")[game["scenario"].str()];
|
||||
|
||||
config& qchild = qgame.add_child("slot_data");
|
||||
qchild["vacant"] = human_sides;
|
||||
qchild["max"] = human_sides;
|
||||
|
||||
game_info g(qgame, installed_addons_);
|
||||
games_by_id_.emplace(g.id, std::move(g));
|
||||
}
|
||||
|
||||
for(const auto& c : gamelist_.mandatory_child("gamelist").child_range("game")) {
|
||||
game_info game(c, installed_addons_);
|
||||
games_by_id_.emplace(game.id, std::move(game));
|
||||
|
|
|
@ -118,11 +118,14 @@ private:
|
|||
/** Opens the MP lobby. */
|
||||
bool enter_lobby_mode();
|
||||
|
||||
/** Opens the MP Create screen for hosts to configure a new game. */
|
||||
void enter_create_mode();
|
||||
/**
|
||||
* Opens the MP Create screen for hosts to configure a new game.
|
||||
* @param preset_scenario contains a scenario id if present
|
||||
*/
|
||||
void enter_create_mode(utils::optional<std::string> preset_scenario = utils::nullopt);
|
||||
|
||||
/** Opens the MP Staging screen for hosts to wait for players. */
|
||||
void enter_staging_mode();
|
||||
void enter_staging_mode(bool preset);
|
||||
|
||||
/** Opens the MP Join Game screen for non-host players and observers. */
|
||||
void enter_wait_mode(int game_id, bool observe);
|
||||
|
@ -536,14 +539,19 @@ bool mp_manager::enter_lobby_mode()
|
|||
|
||||
int dlg_retval = 0;
|
||||
int dlg_joined_game_id = 0;
|
||||
std::string preset_scenario = "";
|
||||
{
|
||||
gui2::dialogs::mp_lobby dlg(lobby_info, *connection, dlg_joined_game_id);
|
||||
dlg.show();
|
||||
dlg_retval = dlg.get_retval();
|
||||
preset_scenario = dlg.queue_game_scenario_id();
|
||||
}
|
||||
|
||||
try {
|
||||
switch(dlg_retval) {
|
||||
case gui2::dialogs::mp_lobby::CREATE_PRESET:
|
||||
enter_create_mode(utils::make_optional(preset_scenario));
|
||||
break;
|
||||
case gui2::dialogs::mp_lobby::CREATE:
|
||||
enter_create_mode();
|
||||
break;
|
||||
|
@ -572,18 +580,26 @@ bool mp_manager::enter_lobby_mode()
|
|||
return true;
|
||||
}
|
||||
|
||||
void mp_manager::enter_create_mode()
|
||||
void mp_manager::enter_create_mode(utils::optional<std::string> preset_scenario)
|
||||
{
|
||||
DBG_MP << "entering create mode";
|
||||
|
||||
if(gui2::dialogs::mp_create_game::execute(state, connection == nullptr)) {
|
||||
enter_staging_mode();
|
||||
if(preset_scenario) {
|
||||
for(const config& game : game_config_manager::get()->game_config().mandatory_child("game_presets").child_range("game")) {
|
||||
if(game["scenario"].str() == preset_scenario.value()) {
|
||||
gui2::dialogs::mp_create_game::quick_mp_setup(state, game);
|
||||
enter_staging_mode(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if(gui2::dialogs::mp_create_game::execute(state, connection == nullptr)) {
|
||||
enter_staging_mode(false);
|
||||
} else if(connection) {
|
||||
connection->send_data(config("refresh_lobby"));
|
||||
}
|
||||
}
|
||||
|
||||
void mp_manager::enter_staging_mode()
|
||||
void mp_manager::enter_staging_mode(bool preset)
|
||||
{
|
||||
DBG_MP << "entering connect mode";
|
||||
|
||||
|
@ -594,6 +610,7 @@ void mp_manager::enter_staging_mode()
|
|||
metadata = std::make_unique<mp_game_metadata>(*connection);
|
||||
metadata->connected_players.insert(prefs::get().login());
|
||||
metadata->is_host = true;
|
||||
metadata->is_queue_game = preset;
|
||||
}
|
||||
|
||||
bool dlg_ok = false;
|
||||
|
|
|
@ -33,6 +33,7 @@ struct mp_game_metadata
|
|||
, skip_replay(false)
|
||||
, skip_replay_blindfolded(false)
|
||||
, connection(wdc)
|
||||
, is_queue_game(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -43,6 +44,7 @@ struct mp_game_metadata
|
|||
bool skip_replay;
|
||||
bool skip_replay_blindfolded;
|
||||
wesnothd_connection& connection;
|
||||
bool is_queue_game;
|
||||
};
|
||||
|
||||
class campaign_controller
|
||||
|
|
|
@ -756,6 +756,13 @@ void mp_lobby::process_network_data(const config& data)
|
|||
announcements_ = info["message"].str();
|
||||
return;
|
||||
}
|
||||
} else if(auto create = data.optional_child("create_game")) {
|
||||
queue_game_scenario_id_ = create["mp_scenario"];
|
||||
set_retval(CREATE_PRESET);
|
||||
return;
|
||||
} else if(auto join_game = data.optional_child("join_game")) {
|
||||
enter_game_by_id(join_game["id"].to_int(), JOIN_MODE::DO_JOIN);
|
||||
return;
|
||||
}
|
||||
|
||||
chatbox_->process_network_data(data);
|
||||
|
@ -870,11 +877,15 @@ void mp_lobby::enter_game(const mp::game_info& game, JOIN_MODE mode)
|
|||
join_data["password"] = password;
|
||||
}
|
||||
|
||||
join_data["mp_scenario"] = game.scenario_id;
|
||||
mp::send_to_server(response);
|
||||
joined_game_id_ = game.id;
|
||||
|
||||
// We're all good. Close lobby and proceed to game!
|
||||
set_retval(try_join ? JOIN : OBSERVE);
|
||||
if(game.id >= 0) {
|
||||
joined_game_id_ = game.id;
|
||||
|
||||
// We're all good. Close lobby and proceed to game!
|
||||
set_retval(try_join ? JOIN : OBSERVE);
|
||||
}
|
||||
}
|
||||
|
||||
void mp_lobby::enter_game_by_index(const int index, JOIN_MODE mode)
|
||||
|
|
|
@ -61,10 +61,13 @@ public:
|
|||
QUIT,
|
||||
JOIN,
|
||||
OBSERVE,
|
||||
CREATE,
|
||||
RELOAD_CONFIG
|
||||
CREATE, /** player clicked the Create button */
|
||||
RELOAD_CONFIG,
|
||||
CREATE_PRESET /** player clicked Join button on an [mp_queue] game, but there was no existing game to join */
|
||||
};
|
||||
|
||||
const std::string queue_game_scenario_id() const { return queue_game_scenario_id_; };
|
||||
|
||||
private:
|
||||
void update_selected_game();
|
||||
|
||||
|
@ -174,6 +177,8 @@ private:
|
|||
|
||||
int& joined_game_id_;
|
||||
|
||||
std::string queue_game_scenario_id_;
|
||||
|
||||
friend struct lobby_delay_gamelist_update_guard;
|
||||
|
||||
static inline std::string server_information_ = "";
|
||||
|
|
|
@ -142,6 +142,85 @@ mp_create_game::mp_create_game(saved_game& state, bool local_mode)
|
|||
set_allow_plugin_skip(false);
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(performance-unnecessary-value-param)
|
||||
void mp_create_game::quick_mp_setup(saved_game& state, const config presets)
|
||||
{
|
||||
// from constructor
|
||||
ng::create_engine create(state);
|
||||
create.init_active_mods();
|
||||
create.get_state().clear();
|
||||
create.get_state().classification().type = campaign_type::type::multiplayer;
|
||||
|
||||
// from pre_show
|
||||
create.set_current_level_type(level_type::type::scenario);
|
||||
const auto& levels = create.get_levels_by_type(level_type::type::scenario);
|
||||
for(std::size_t i = 0; i < levels.size(); i++) {
|
||||
if(levels[i]->id() == presets["scenario"].str()) {
|
||||
create.set_current_level(i);
|
||||
}
|
||||
}
|
||||
|
||||
create.set_current_era_id(presets["era"]);
|
||||
|
||||
// from post_show
|
||||
create.prepare_for_era_and_mods();
|
||||
create.prepare_for_scenario();
|
||||
create.get_parameters();
|
||||
create.prepare_for_new_level();
|
||||
|
||||
mp_game_settings& params = create.get_state().mp_settings();
|
||||
params.use_map_settings = true;
|
||||
params.num_turns = presets["turn_count"].to_int(-1);
|
||||
params.village_gold = presets["village_gold"].to_int();
|
||||
params.village_support = presets["village_support"].to_int();
|
||||
params.xp_modifier = presets["experience_modifier"].to_int();
|
||||
params.random_start_time = presets["random_start_time"].to_bool();
|
||||
params.fog_game = presets["fog"].to_bool();
|
||||
params.shroud_game = presets["shroud"].to_bool();
|
||||
|
||||
// write to scenario
|
||||
// queue games are supposed to all use the same settings, not be modified by the user
|
||||
// can be removed later if we jump straight from the lobby into a game instead of going to the staging screen to wait for other players to join
|
||||
config& scenario = create.get_state().get_starting_point();
|
||||
|
||||
if(params.random_start_time) {
|
||||
if(!tod_manager::is_start_ToD(scenario["random_start_time"])) {
|
||||
scenario["random_start_time"] = true;
|
||||
}
|
||||
} else {
|
||||
scenario["random_start_time"] = false;
|
||||
}
|
||||
|
||||
scenario["experience_modifier"] = params.xp_modifier;
|
||||
scenario["turns"] = params.num_turns;
|
||||
|
||||
for(config& side : scenario.child_range("side")) {
|
||||
side["controller_lock"] = true;
|
||||
side["team_lock"] = true;
|
||||
side["gold_lock"] = true;
|
||||
side["income_lock"] = true;
|
||||
|
||||
side["fog"] = params.fog_game;
|
||||
side["shroud"] = params.shroud_game;
|
||||
side["village_gold"] = params.village_gold;
|
||||
side["village_support"] = params.village_support;
|
||||
}
|
||||
|
||||
params.mp_countdown = presets["countdown"].to_bool();
|
||||
params.mp_countdown_init_time = std::chrono::seconds{presets["countdown_init_time"].to_int()};
|
||||
params.mp_countdown_turn_bonus = std::chrono::seconds{presets["countdown_turn_bonus"].to_int()};
|
||||
params.mp_countdown_reservoir_time = std::chrono::seconds{presets["countdown_reservoir_time"].to_int()};
|
||||
params.mp_countdown_action_bonus = std::chrono::seconds{presets["countdown_action_bonus"].to_int()};
|
||||
|
||||
params.allow_observers = true;
|
||||
params.private_replay = false;
|
||||
create.get_state().classification().oos_debug = false;
|
||||
params.shuffle_sides = presets["shuffle_sides"].to_bool();
|
||||
|
||||
params.mode = random_faction_mode::type::no_mirror;
|
||||
params.name = settings::game_name_default();
|
||||
}
|
||||
|
||||
void mp_create_game::pre_show()
|
||||
{
|
||||
find_widget<text_box>("game_name").set_value(local_mode_ ? "" : settings::game_name_default());
|
||||
|
|
|
@ -41,6 +41,12 @@ public:
|
|||
/** The execute function. See @ref modal_dialog for more information. */
|
||||
DEFINE_SIMPLE_EXECUTE_WRAPPER(mp_create_game);
|
||||
|
||||
/**
|
||||
* @a presets needs to be a copy!
|
||||
* Otherwise you'll get segfaults when clicking the Join button since it results in the configs getting reloaded.
|
||||
*/
|
||||
static void quick_mp_setup(saved_game& state, const config presets);
|
||||
|
||||
private:
|
||||
virtual const std::string& window_id() const override;
|
||||
|
||||
|
|
|
@ -77,6 +77,7 @@ int game::db_id_num = 1;
|
|||
|
||||
game::game(wesnothd::server& server, player_connections& player_connections,
|
||||
player_iterator host,
|
||||
bool is_queue_game,
|
||||
const std::string& name,
|
||||
bool save_replays,
|
||||
const std::string& replay_save_path)
|
||||
|
@ -112,6 +113,7 @@ game::game(wesnothd::server& server, player_connections& player_connections,
|
|||
, replay_save_path_(replay_save_path)
|
||||
, rng_()
|
||||
, last_choice_request_id_(-1) /* or maybe 0 ? it shouldn't matter*/
|
||||
, is_queue_game_(is_queue_game)
|
||||
{
|
||||
players_.push_back(owner_);
|
||||
|
||||
|
@ -148,6 +150,11 @@ static const simple_wml::node& get_multiplayer(const simple_wml::node& root)
|
|||
}
|
||||
}
|
||||
|
||||
const std::string game::get_scenario_id() const
|
||||
{
|
||||
return get_multiplayer(level_.root())["mp_scenario"].to_string();
|
||||
}
|
||||
|
||||
bool game::allow_observers() const
|
||||
{
|
||||
return get_multiplayer(level_.root())["observer"].to_bool(true);
|
||||
|
|
|
@ -37,6 +37,7 @@ class game
|
|||
public:
|
||||
game(wesnothd::server& server, player_connections& player_connections,
|
||||
player_iterator host,
|
||||
bool is_queue_game,
|
||||
const std::string& name = "",
|
||||
bool save_replays = false,
|
||||
const std::string& replay_save_path = "");
|
||||
|
@ -139,6 +140,8 @@ public:
|
|||
return level_.child("snapshot") || level_.child("scenario");
|
||||
}
|
||||
|
||||
const std::string get_scenario_id() const;
|
||||
|
||||
/**
|
||||
* The non-const version.
|
||||
*
|
||||
|
@ -611,6 +614,15 @@ public:
|
|||
observers_.clear();
|
||||
}
|
||||
|
||||
bool is_queue_game() const
|
||||
{
|
||||
return is_queue_game_;
|
||||
}
|
||||
void is_queue_game(bool is_queue_game)
|
||||
{
|
||||
is_queue_game_ = is_queue_game;
|
||||
}
|
||||
|
||||
private:
|
||||
// forbidden operations
|
||||
game(const game&) = delete;
|
||||
|
@ -956,6 +968,9 @@ private:
|
|||
* New requests should never have a lower value than this.
|
||||
*/
|
||||
int last_choice_request_id_;
|
||||
|
||||
/** Whether this game was created by joining a game defined client-side in an [mp_queue] */
|
||||
bool is_queue_game_;
|
||||
};
|
||||
|
||||
} // namespace wesnothd
|
||||
|
|
|
@ -1376,15 +1376,16 @@ void server::handle_create_game(player_iterator player, simple_wml::node& create
|
|||
const std::string game_name = create_game["name"].to_string();
|
||||
const std::string game_password = create_game["password"].to_string();
|
||||
const std::string initial_bans = create_game["ignored"].to_string();
|
||||
const bool is_queue_game = create_game["queue_game"].to_bool();
|
||||
|
||||
DBG_SERVER << player->client_ip() << "\t" << player->info().name()
|
||||
<< "\tcreates a new game: \"" << game_name << "\".";
|
||||
|
||||
// Create the new game, remove the player from the lobby
|
||||
// and set the player as the host/owner.
|
||||
player_connections_.modify(player, [this, player, &game_name](player_record& host_record) {
|
||||
player_connections_.modify(player, [this, player, &game_name, is_queue_game](player_record& host_record) {
|
||||
host_record.get_game().reset(
|
||||
new wesnothd::game(*this, player_connections_, player, game_name, save_replays_, replay_save_path_),
|
||||
new wesnothd::game(*this, player_connections_, player, is_queue_game, game_name, save_replays_, replay_save_path_),
|
||||
std::bind(&server::cleanup_game, this, std::placeholders::_1)
|
||||
);
|
||||
});
|
||||
|
@ -1439,9 +1440,43 @@ void server::cleanup_game(game* game_ptr)
|
|||
|
||||
void server::handle_join_game(player_iterator player, simple_wml::node& join)
|
||||
{
|
||||
int game_id = join["id"].to_int();
|
||||
|
||||
// this is a game defined in an [mp_queue] in the client
|
||||
// if there is no mp_queue defined game already existing with empty slots, tell the client to create one
|
||||
// else update game_id to the game that already exists and have the client join that game
|
||||
if(game_id < 0) {
|
||||
for(const auto& game : games()) {
|
||||
if(game->is_queue_game() &&
|
||||
!game->started() &&
|
||||
join["mp_scenario"].to_string() == game->get_scenario_id() &&
|
||||
game->description()->child("slot_data")->attr("vacant").to_int() != 0) {
|
||||
game_id = game->id();
|
||||
}
|
||||
}
|
||||
|
||||
// if it's still negative, then there's no existing game to join
|
||||
if(game_id < 0) {
|
||||
simple_wml::document create_game_doc;
|
||||
simple_wml::node& create_game_node = create_game_doc.root().add_child("create_game");
|
||||
create_game_node.set_attr_dup("mp_scenario", join["mp_scenario"].to_string().c_str());
|
||||
|
||||
// tell the client to create a game since there is no suitable existing game to join
|
||||
send_to_player(player, create_game_doc);
|
||||
return;
|
||||
} else {
|
||||
simple_wml::document join_game_doc;
|
||||
simple_wml::node& join_game_node = join_game_doc.root().add_child("join_game");
|
||||
join_game_node.set_attr_int("id", game_id);
|
||||
|
||||
// tell the client to create a game since there is no suitable existing game to join
|
||||
send_to_player(player, join_game_doc);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const bool observer = join.attr("observe").to_bool();
|
||||
const std::string& password = join["password"].to_string();
|
||||
int game_id = join["id"].to_int();
|
||||
|
||||
auto g_iter = player_connections_.get<game_t>().find(game_id);
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user