make wesnothd use savefile format for new games

This patch changes the mp wesnothd protocol.

multiplayer connect now works as following:
multiplayer_create/configure creates saved_game object which is then
loaded by mp_connect and sended to the server in the usual savefile
format, this especially implies that [side] are no longer at toplevel
but instead nested into [scenario] or [snapshot].

mp options are saved into state (the saved_game object)
(state_.mp_settings()) previously we had a separate mp_settings object
for that now we only have one mp_setting object.

This commit still not fixes mp modification/era events/options. The
reason is, that i want to move the expansion of those to saved_game.cpp
for better compatibility to Sp (Especially make era events work in mp games
reloaded in sp), but if that won't work i'll just enable them how they
were before.

There  are still some things to do. Especially the server generated
replay-saves will be completely broken. (will fix in another commit)

we don't use the [replay_start] as starting pos in mp anymore so i removed
2 lines in playcampaign that assumed that.

I also removed soem code in mo_game_utils that seemed redundant, bugged or useless

since we now send the [carryover_sides_start] over the network too there
is no reason to apply [carryover_sides_start] before getting into
mp_connect engine (when advanging the the next scenario), even more,
since the new code expects only ONE of [carryover_sides_start] or
[carryover_sides] to be present, we cannot expand carryover_sides_start
in playcampaign before going to mp_connect because we might wan to modify
[carryover_sides_start] in mp_connect

still TODO:
* rename mp::configure::get_parameters
* reimplement mp modification/era s events/options
* remove fields from the mp_game_settings object
* remove disabled/outcommented code
This commit is contained in:
gfgtdf 2014-06-12 17:13:43 +02:00
parent dd7dca975d
commit 728b29dc61
16 changed files with 260 additions and 229 deletions

View file

@ -45,63 +45,68 @@ static lg::log_domain log_network("network");
namespace mp {
config initial_level_config(game_display& disp, const mp_game_settings& params,
saved_game& state)
// To remove radundant informaion in the clientside internal programmflow
// I want to remove these values from mp_settings so i need to readd them here
static void add_multiplayer_classification(config& multiplayer, saved_game& state)
{
config level;
multiplayer["mp_scenario"] = state.get_scenario_id();
multiplayer["mp_scenario_name"] = state.get_starting_pos()["name"];
multiplayer["difficulty_define"] = state.classification().difficulty;
multiplayer["mp_campaign"] = state.classification().campaign;
}
if (params.saved_game) {
try {
savegame::loadgame load(disp,
resources::config_manager->game_config(), state);
load.load_multiplayer_game();
load.fill_mplevel_config(level);
resources::config_manager->
load_game_config_for_game(state.classification());
config initial_level_config(saved_game& state)
{
const mp_game_settings& params = state.mp_settings();
//Shall we do this here or in create_engine ? Idk so just call it twice.
state.expand_scenario();
config& scenario = state.get_starting_pos();
if(!state.mp_settings().saved_game)
{
if(state.carryover_sides_start["random_seed"].str() == "")
{
state.carryover_sides_start["random_seed"] = rand();
state.carryover_sides_start["random_calls"] = 0;
}
catch (load_game_cancelled_exception){
return config();
} catch(config::error&) {
return config();
}
} else {
level.merge_with(params.scenario_data);
level["turns"] = params.num_turns;
level["difficulty"] = params.difficulty_define;
level.add_child("multiplayer", params.to_config());
scenario["turns"] = params.num_turns;
// Convert options to events
level.add_child_at("event", options::to_event(params.options.find_child(
scenario.add_child_at("event", options::to_event(params.options.find_child(
"multiplayer", "id", params.mp_scenario)), 0);
if(!level.has_attribute("next_underlying_unit_id"))
{
level["next_underlying_unit_id"] = 0;
}
n_unit::id_manager::instance().clear();
if (params.random_start_time)
{
if (!tod_manager::is_start_ToD(level["random_start_time"]))
if (!tod_manager::is_start_ToD(scenario["random_start_time"]))
{
level["random_start_time"] = true;
scenario["random_start_time"] = true;
}
}
else
{
level["random_start_time"] = false;
scenario["random_start_time"] = false;
}
level["experience_modifier"] = params.xp_modifier;
level["random_seed"] = state.carryover_sides_start["random_seed"];
scenario["experience_modifier"] = params.xp_modifier;
}
if (scenario["objectives"].empty()) {
scenario["objectives"] = "<big>" + t_string(N_("Victory:"), "wesnoth") +
"</big>\n<span foreground=\"#00ff00\">&#8226; " +
t_string(N_("Defeat enemy leader(s)"), "wesnoth") + "</span>";
}
config level = state.to_config();
add_multiplayer_classification(level.child_or_add("multiplayer"), state);
std::string era = params.mp_era;
if (params.saved_game) {
if (const config &c = level.child("snapshot").child("era"))
//if (const config &c = level.child("snapshot").child("era"))
// era = c["id"].str();
if (const config &c = level.child("era"))
era = c["id"].str();
}
//[era] as a toplevel tag ? fine for me.
// Initialize the list of sides available for the current era.
const config &era_cfg =
resources::config_manager->game_config().find_child("era", "id", era);
@ -127,7 +132,8 @@ config initial_level_config(game_display& disp, const mp_game_settings& params,
cfg.add_child_at("event", options::to_event(
params.options.find_child("era", "id", era)), 0);
}
//TODO: move to saved_game.
// Add modifications
const std::vector<std::string>& mods = params.active_mods;
for (unsigned i = 0; i < mods.size(); i++) {
@ -140,9 +146,9 @@ config initial_level_config(game_display& disp, const mp_game_settings& params,
params.options.find_child("modification", "id", mods[i])), 0);
}
// This will force connecting clients to be using the same version number as us.
level["version"] = game_config::version;
#if 0
// we have this alredy in [multiplayer]. If removing this causes a bug than that's most likley bacause some is searchin for this information at the wrng place (not in [multiplayer])
// If game was reloaded, params won't contain all required information and so we
// need to take it from the actual level config.
if (params.saved_game) {
@ -152,24 +158,22 @@ config initial_level_config(game_display& disp, const mp_game_settings& params,
level["observer"] = params.allow_observers;
level["shuffle_sides"] = params.shuffle_sides;
}
if (level["objectives"].empty()) {
level["objectives"] = "<big>" + t_string(N_("Victory:"), "wesnoth") +
"</big>\n<span foreground=\"#00ff00\">&#8226; " +
t_string(N_("Defeat enemy leader(s)"), "wesnoth") + "</span>";
}
#endif
// This will force connecting clients to be using the same version number as us.
level["version"] = game_config::version;
return level;
}
void level_to_gamestate(config& level, saved_game& state)
void level_to_gamestate(const config& level, saved_game& state)
{
state = saved_game(level);
state.classification().campaign_type = game_classification::MULTIPLAYER;
// Any replay data is only temporary and should be removed from
// the level data in case we want to save the game later.
if (const config& replay_data = level.child("replay"))
{
LOG_NW << "setting replay\n";
state.replay_data = replay_data;
recorder = replay(replay_data);
if (!recorder.empty()) {
recorder.set_skip(false);
@ -177,66 +181,35 @@ void level_to_gamestate(config& level, saved_game& state)
}
}
carryover_info sides = carryover_info(state.carryover_sides_start);
n_unit::id_manager::instance().set_save_id(level["next_underlying_unit_id"]);
// Set random.
const config::attribute_value& seed = level["random_seed"];
if (!seed.empty()) {
const unsigned calls = level["random_calls"].to_unsigned();
sides.rng().seed_random(seed.to_int(42), calls);
} else {
ERR_NG << "No random seed found, random "
"events will probably be out of sync.\n";
}
//save id setting was moved to play_controller.
// Adds the starting pos to the level.
if (!level.child("replay_start")) {
level.add_child("replay_start", level);
level.child("replay_start").remove_child("multiplayer", 0);
}
// This is important, if it does not happen, the starting position is
// missing and will be drawn from the snapshot instead
// (which is not what we want since we have
// all needed information here already).
state.replay_start() = level.child("replay_start");
//state.replay_start() = level.child("replay_start");
level["campaign_type"] = lexical_cast<std::string> (game_classification::MULTIPLAYER);
state.classification().campaign_type = game_classification::MULTIPLAYER;
state.classification().completion = level["completion"].str();
state.classification().version = level["version"].str();
if (const config& vars = level.child("variables")) {
sides.set_variables(vars);
}
sides.get_wml_menu_items().set_menu_items(level);
state.mp_settings().set_from_config(level);
// Check whether it is a save-game by looking for snapshot data.
const config& snapshot = level.child("snapshot");
const bool saved_game = snapshot && snapshot.child("side");
//const config& snapshot = level.child("snapshot");
//const bool saved_game = state.mp_settings().saved_game;
// It might be a MP campaign start-of-scenario save.
// In this case, it's not entirely a new game, but not a save, either.
// Check whether it is no savegame and the starting_pos
// contains [player] information.
bool start_of_scenario =
!saved_game && state.replay_start().child("player");
// If we start a fresh game, there won't be any snapshot information.
// If however this is a savegame, we got a valid snapshot here.
if (saved_game) {
state.set_snapshot(snapshot);
if (const config& v = snapshot.child("variables")) {
sides.set_variables(v);
}
sides.get_wml_menu_items().set_menu_items(snapshot);
}
// Edit: idk what this code did before, but i most liley didn't work because [replay_start] never contains [player]
//bool start_of_scenario = !saved_game && state.replay_start().child("player");
// In any type of reload (normal save or start-of-scenario) the players
// could have changed and need to be replaced.
if (saved_game || start_of_scenario){
// EDIT: We directy use the starting_pos() sides now, so no need to so this anymore.
#if 0
if (saved_game)
{
config::child_itors saved_sides = saved_game ?
state.get_starting_pos().child_range("side") :
state.replay_start().child_range("side");
@ -257,14 +230,7 @@ void level_to_gamestate(config& level, saved_game& state)
}
}
}
if (sides.get_variables().empty()) {
LOG_NG << "No variables were found for the saved_game." << std::endl;
} else {
LOG_NG << "Variables found and loaded into saved_game:" << std::endl;
LOG_NG << sides.get_variables();
}
state.carryover_sides_start = sides.to_config();
#endif
}
void check_response(network::connection res, const config& data)

View file

@ -23,10 +23,9 @@ class saved_game;
namespace mp {
config initial_level_config(game_display& disp, const mp_game_settings& params,
saved_game& state);
config initial_level_config(saved_game& state);
void level_to_gamestate(config& level, saved_game& state);
void level_to_gamestate(const config& level, saved_game& state);
void check_response(network::connection res, const config& data);

View file

@ -474,7 +474,7 @@ static void enter_create_mode(game_display& disp, const config& game_config,
saved_game& state, bool local_players_only = false);
static bool enter_connect_mode(game_display& disp, const config& game_config,
saved_game& state, const mp_game_settings& params,
saved_game& state,
bool local_players_only = false)
{
DBG_MP << "entering connect mode" << std::endl;
@ -487,9 +487,8 @@ static bool enter_connect_mode(game_display& disp, const config& game_config,
statistics::fresh_stats();
{
mp::connect_engine_ptr connect_engine(new mp::connect_engine(disp,
state, params, local_players_only, true));
mp::connect ui(disp, params.name, game_config, gamechat, gamelist,
mp::connect_engine_ptr connect_engine(new mp::connect_engine(state, local_players_only, true));
mp::connect ui(disp, state.mp_settings().name, game_config, gamechat, gamelist,
*connect_engine);
run_lobby_loop(disp, ui);
@ -522,7 +521,7 @@ static bool enter_connect_mode(game_display& disp, const config& game_config,
}
static bool enter_configure_mode(game_display& disp, const config& game_config,
saved_game& state, const mp_game_settings& params,
saved_game& state,
bool local_players_only = false);
static void enter_create_mode(game_display& disp, const config& game_config,
@ -547,23 +546,22 @@ static void enter_create_mode(game_display& disp, const config& game_config,
} else {
mp::ui::result res;
mp_game_settings new_params;
{
mp::create ui(disp, game_config, state, gamechat, gamelist);
run_lobby_loop(disp, ui);
res = ui.get_result();
new_params = ui.get_parameters();
ui.get_parameters();
}
switch (res) {
case mp::ui::CREATE:
configure_canceled = !enter_configure_mode(disp, game_config,
state, new_params, local_players_only);
state, local_players_only);
break;
case mp::ui::LOAD_GAME:
connect_canceled = !enter_connect_mode(disp, game_config,
state, new_params, local_players_only);
state, local_players_only);
break;
case mp::ui::QUIT:
default:
@ -576,7 +574,7 @@ static void enter_create_mode(game_display& disp, const config& game_config,
}
static bool enter_configure_mode(game_display& disp, const config& game_config,
saved_game& state, const mp_game_settings& params, bool local_players_only)
saved_game& state, bool local_players_only)
{
DBG_MP << "entering configure mode" << std::endl;
@ -586,20 +584,19 @@ static bool enter_configure_mode(game_display& disp, const config& game_config,
connect_canceled = false;
mp::ui::result res;
mp_game_settings new_params;
{
mp::configure ui(disp, game_config, gamechat, gamelist, params,
mp::configure ui(disp, game_config, gamechat, gamelist, state,
local_players_only);
run_lobby_loop(disp, ui);
res = ui.get_result();
new_params = ui.get_parameters();
ui.get_parameters();
}
switch (res) {
case mp::ui::CREATE:
connect_canceled = !enter_connect_mode(disp, game_config,
state, new_params, local_players_only);
state, local_players_only);
break;
case mp::ui::QUIT:
default:
@ -856,8 +853,7 @@ void start_local_game_commandline(game_display& disp, const config& game_config,
statistics::fresh_stats();
{
mp::connect_engine_ptr connect_engine(new mp::connect_engine(disp,
state, parameters, true, true));
mp::connect_engine_ptr connect_engine(new mp::connect_engine(state, true, true));
mp::connect ui(disp, parameters.name, game_config, gamechat, gamelist,
*connect_engine);

View file

@ -29,6 +29,7 @@
#include "multiplayer_configure.hpp"
#include "filesystem.hpp"
#include "log.hpp"
#include "saved_game.hpp"
#include "wml_exception.hpp"
#include "wml_separators.hpp"
#include "formula_string_utils.hpp"
@ -43,7 +44,7 @@ static lg::log_domain log_mp_configure("mp/configure");
namespace mp {
configure::configure(game_display& disp, const config &cfg, chat& c, config& gamelist, const mp_game_settings& params, bool local_players_only) :
configure::configure(game_display& disp, const config &cfg, chat& c, config& gamelist, saved_game& game, bool local_players_only) :
ui(disp, _("Configure Game"), cfg, c, gamelist),
local_players_only_(local_players_only),
@ -90,7 +91,8 @@ configure::configure(game_display& disp, const config &cfg, chat& c, config& gam
entry_points_(),
show_entry_points_(false),
force_use_map_settings_check_(true),
parameters_(params),
state_(game),
parameters_(state_.mp_settings()),
options_manager_(cfg, disp, &options_pane_right_, preferences::options())
{
// Build the list of scenarios to play
@ -146,7 +148,7 @@ configure::configure(game_display& disp, const config &cfg, chat& c, config& gam
xp_modifier_slider_.set_increment(10);
xp_modifier_slider_.set_help_string(_("The amount of experience a unit needs to advance"));
if (parameters_.scenario_data["force_lock_settings"].to_bool()) {
if (state_.get_starting_pos()["force_lock_settings"].to_bool()) {
use_map_settings_.enable(false);
use_map_settings_.set_check(true);
} else {
@ -202,7 +204,7 @@ configure::configure(game_display& disp, const config &cfg, chat& c, config& gam
}
options_manager_.set_era(parameters_.mp_era);
options_manager_.set_scenario(parameters_.mp_scenario);
options_manager_.set_scenario(state_.get_scenario_id()/*parameters_.mp_scenario*/);
options_manager_.set_modifications(parameters_.active_mods);
options_manager_.init_widgets();
@ -325,9 +327,7 @@ void configure::process_event()
const config& scenario = *entry_points_[entry_points_combo_.selected()];
parameters_.hash = scenario.hash();
parameters_.scenario_data = scenario;
parameters_.mp_scenario = scenario["id"].str();
parameters_.mp_scenario_name = scenario["name"].str();
state_.set_scenario(scenario);
force_use_map_settings_check_ = true;
}
@ -412,15 +412,15 @@ void configure::process_event()
// If the map settings are wanted use them,
// if not properly defined fall back to the default settings
turns_slider_.set_value(map_settings ?
settings::get_turns(parameters_.scenario_data["turns"]) :
settings::get_turns(state_.get_starting_pos()["turns"]) :
preferences::turns());
xp_modifier_slider_.set_value(map_settings ?
settings::get_xp_modifier(parameters_.scenario_data["experience_modifier"]) :
settings::get_xp_modifier(state_.get_starting_pos()["experience_modifier"]) :
preferences::xp_modifier());
random_start_time_.set_check(map_settings ?
parameters_.scenario_data["random_start_time"].to_bool(true) :
state_.get_starting_pos()["random_start_time"].to_bool(true) :
preferences::random_start_time());
// These are per player, always show values of player 1.
@ -430,7 +430,7 @@ void configure::process_event()
* This might change in the future.
* NOTE when 'load game' is selected there are no sides.
*/
config::const_child_itors sides = parameters_.scenario_data.child_range("side");
config::const_child_itors sides = state_.get_starting_pos().child_range("side");
if (sides.first != sides.second)
{
const config &cfg = *sides.first;

View file

@ -25,12 +25,15 @@
#include "tooltips.hpp"
#include "mp_options.hpp"
class saved_game;
namespace mp {
class configure : public mp::ui
{
public:
configure(game_display& dist, const config& game_config, chat& c, config& gamelist, const mp_game_settings& params, bool local_players_only);
///gives the user the option to adjust the passed saved_game
///Call get_parameters to finalize;
configure(game_display& dist, const config& game_config, chat& c, config& gamelist, saved_game& game, bool local_players_only);
~configure();
const mp_game_settings& get_parameters();
@ -92,8 +95,8 @@ private:
bool show_entry_points_;
bool force_use_map_settings_check_;
mp_game_settings parameters_;
saved_game& state_;
mp_game_settings& parameters_;
options::manager options_manager_;
};

View file

@ -395,7 +395,7 @@ connect::connect(game_display& disp, const std::string& game_name,
if (get_result() == QUIT || get_result() == CREATE) {
return;
}
if (engine_.level()["id"].empty()) {
if (engine_.scenario()["id"].empty()) {
throw config::error(_("The scenario is invalid because it has no id."));
}
@ -426,7 +426,7 @@ connect::connect(game_display& disp, const std::string& game_name,
side_pos_y_offset += 60;
}
append_to_title("" + engine_.level()["name"].t_str());
append_to_title("" + engine_.scenario()["name"].t_str());
gold_title_label_.hide(params().saved_game);
income_title_label_.hide(params().saved_game);

View file

@ -69,12 +69,11 @@ const std::string attributes_to_trim[] = {
namespace mp {
connect_engine::connect_engine(game_display& disp, saved_game& state,
const mp_game_settings& params, const bool local_players_only,
const bool first_scenario) :
connect_engine::connect_engine(saved_game& state,
const bool local_players_only, const bool first_scenario) :
level_(),
state_(state),
params_(params),
params_(state.mp_settings()),
default_controller_(local_players_only ? CNTR_LOCAL: CNTR_NETWORK),
local_players_only_(local_players_only),
first_scenario_(first_scenario),
@ -87,12 +86,12 @@ connect_engine::connect_engine(game_display& disp, saved_game& state,
connected_users_()
{
// Initial level config from the mp_game_settings.
level_ = initial_level_config(disp, params_, state_);
level_ = initial_level_config(state_);
if (level_.empty()) {
return;
}
force_lock_settings_ = level_["force_lock_settings"].to_bool();
force_lock_settings_ = scenario()["force_lock_settings"].to_bool();
// Original level sides.
config::child_itors sides = current_config()->child_range("side");
@ -208,25 +207,10 @@ connect_engine::~connect_engine()
}
config* connect_engine::current_config() {
config* cfg_level = NULL;
// It might make sense to invent a mechanism of some sort to check
// whether a config node contains information
// that you can load from(side information, specifically).
config &snapshot = level_.child("snapshot");
if (snapshot && snapshot.child("side")) {
// Savegame.
cfg_level = &snapshot;
} else if (!level_.child("side")) {
// Start-of-scenario save,
// the info has to be taken from the starting_pos.
cfg_level = &state_.replay_start();
} else {
// Fresh game, no snapshot available.
cfg_level = &level_;
}
return cfg_level;
if(config& s = scenario())
return &s;
else
return NULL;
}
void connect_engine::import_user(const std::string& name, const bool observer,
@ -312,25 +296,18 @@ void connect_engine::update_level()
{
DBG_MP << "updating level" << std::endl;
level_.clear_children("side");
scenario().clear_children("side");
BOOST_FOREACH(side_engine_ptr side, side_engines_) {
level_.add_child("side", side->new_config());
scenario().add_child("side", side->new_config());
}
}
void connect_engine::update_and_send_diff(bool update_time_of_day)
void connect_engine::update_and_send_diff(bool /*update_time_of_day*/)
{
config old_level = level_;
update_level();
if (update_time_of_day) {
// Set random start ToD.
// This doesn't do anything since the "const" parameter is now really a const.
// We currently resolve the random tod on all clients seperately with the synced rng.
tod_manager tod_mng(level_);
}
config diff = level_.get_diff(old_level);
if (!diff.empty()) {
config scenario_diff;
@ -543,7 +520,7 @@ void connect_engine::start_game_commandline(
if (cmdline_opts.multiplayer_turns) {
DBG_MP << "\tsetting turns: " << cmdline_opts.multiplayer_turns <<
std::endl;
level_["turns"] = *cmdline_opts.multiplayer_turns;
scenario()["turns"] = *cmdline_opts.multiplayer_turns;
}
BOOST_FOREACH(config &side, level_.child_range("side"))

View file

@ -43,8 +43,8 @@ typedef std::pair<mp::controller, std::string> controller_option;
class connect_engine
{
public:
connect_engine(game_display& disp, saved_game& state,
const mp_game_settings& params, const bool local_players_only,
connect_engine(saved_game& state,
const bool local_players_only,
const bool first_scenario);
~connect_engine();
@ -84,6 +84,15 @@ public:
/* Setters & Getters */
const config& level() const { return level_; }
config& scenario()
{
if(config& scenario = level_.child("scenario"))
return scenario;
else if(config& snapshot = level_.child("snapshot"))
return snapshot;
else
throw "No scenariodata found";
}
const std::set<std::string>& connected_users() const
{ return connected_users_; }
const std::vector<std::string>& user_team_names()

View file

@ -36,6 +36,8 @@
#include "minimap.hpp"
#include "multiplayer_create.hpp"
#include "filesystem.hpp"
#include "resources.hpp"
#include "savegame.hpp"
#include "log.hpp"
#include "wml_exception.hpp"
#include "wml_separators.hpp"
@ -253,11 +255,25 @@ void create::process_event()
}
if (load_game_.pressed()) {
engine_.prepare_for_saved_game();
try
{
savegame::loadgame load(disp_,
resources::config_manager->game_config(), engine_.get_state());
load.load_multiplayer_game();
set_result(LOAD_GAME);
engine_.prepare_for_saved_game();
set_result(LOAD_GAME);
return;
}
catch (load_game_cancelled_exception)
{
}
catch(config::error&)
{
}
return;
}
bool update_mod_button_label = mod_selection_ != mods_menu_.selection();

View file

@ -344,7 +344,6 @@ create_engine::create_engine(game_display& disp, saved_game& state) :
eras_(),
mods_(),
state_(state),
parameters_(),
dependency_manager_(resources::config_manager->game_config(), disp.video()),
generator_(NULL)
{
@ -369,17 +368,17 @@ create_engine::create_engine(game_display& disp, saved_game& state) :
init_extras(ERA);
init_extras(MOD);
parameters_.saved_game = false;
state_.mp_settings().saved_game = false;
BOOST_FOREACH (const std::string& str, preferences::modifications()) {
if (resources::config_manager->
game_config().find_child("modification", "id", str))
parameters_.active_mods.push_back(str);
state_.mp_settings().active_mods.push_back(str);
}
if (current_level_type_ != level::CAMPAIGN &&
current_level_type_ != level::SP_CAMPAIGN) {
dependency_manager_.try_modifications(parameters_.active_mods, true);
dependency_manager_.try_modifications(state_.mp_settings().active_mods, true);
}
reset_level_filters();
@ -409,10 +408,8 @@ void create_engine::prepare_for_new_level()
{
DBG_MP << "preparing mp_game_settings for new level\n";
parameters_.scenario_data = current_level().data();
parameters_.hash = parameters_.scenario_data.hash();
parameters_.mp_scenario = parameters_.scenario_data["id"].str();
parameters_.mp_scenario_name = parameters_.scenario_data["name"].str();
state_.set_scenario(current_level().data());
state_.mp_settings().hash = current_level().data().hash();
}
void create_engine::prepare_for_campaign(const std::string& difficulty)
@ -421,7 +418,6 @@ void create_engine::prepare_for_campaign(const std::string& difficulty)
if (difficulty != "") {
state_.classification().difficulty = difficulty;
parameters_.difficulty_define = difficulty;
}
state_.classification().campaign = current_level().data()["id"].str();
@ -443,20 +439,20 @@ void create_engine::prepare_for_campaign(const std::string& difficulty)
resources::config_manager->game_config().find_child(
lexical_cast<std::string> (game_classification::MULTIPLAYER),
"id", current_level().data()["first_scenario"]));
parameters_.mp_campaign = current_level().id();
}
void create_engine::prepare_for_saved_game()
{
DBG_MP << "preparing mp_game_settings for saved game\n";
parameters_.saved_game = true;
parameters_.scenario_data.clear();
resources::config_manager->load_game_config_for_game(state_.classification());
//The save migh be a start-of-scenario save so make sure we have the scenario data loaded.
state_.expand_scenario();
state_.mp_settings().saved_game = true;
utils::string_map i18n_symbols;
i18n_symbols["login"] = preferences::login();
parameters_.name = vgettext("$login|s game", i18n_symbols);
state_.mp_settings().name = vgettext("$login|s game", i18n_symbols);
}
void create_engine::apply_level_filter(const std::string &name)
@ -642,7 +638,7 @@ bool create_engine::toggle_current_mod()
bool is_active = dependency_manager_.is_modification_active(current_mod_index_);
dependency_manager_.try_modification_by_index(current_mod_index_, !is_active);
parameters_.active_mods = dependency_manager_.get_modifications();
state_.mp_settings().active_mods = dependency_manager_.get_modifications();
return !is_active;
}
@ -762,12 +758,12 @@ const depcheck::manager& create_engine::dependency_manager() const
void create_engine::init_active_mods()
{
parameters_.active_mods = dependency_manager_.get_modifications();
state_.mp_settings().active_mods = dependency_manager_.get_modifications();
}
std::vector<std::string>& create_engine::active_mods()
{
return parameters_.active_mods;
return state_.mp_settings().active_mods;
}
const mp_game_settings& create_engine::get_parameters()
@ -775,9 +771,9 @@ const mp_game_settings& create_engine::get_parameters()
DBG_MP << "getting parameter values" << std::endl;
int era_index = current_level().allow_era_choice() ? current_era_index_ : 0;
parameters_.mp_era = eras_[era_index]->id;
state_.mp_settings().mp_era = eras_[era_index]->id;
return parameters_;
return state_.mp_settings();
}
void create_engine::init_all_levels()
@ -1061,4 +1057,9 @@ std::vector<create_engine::extras_metadata_ptr>&
return (extra_type == ERA) ? eras_ : mods_;
}
saved_game& create_engine::get_state()
{
return state_;
}
} // end namespace mp

View file

@ -223,6 +223,7 @@ public:
const mp_game_settings& get_parameters();
saved_game& get_state();
private:
create_engine(const create_engine&);
void operator=(const create_engine&);
@ -268,7 +269,6 @@ private:
std::vector<extras_metadata_ptr> mods_;
saved_game& state_;
mp_game_settings parameters_;
depcheck::manager dependency_manager_;

View file

@ -224,7 +224,7 @@ void wait::join_game(bool observe)
if (!download_res) {
set_result(QUIT);
return;
} else if (!level_["allow_new_game"].to_bool(true)) {
} else if (!get_scenario()["allow_new_game"].to_bool(true)) {
set_result(PLAY);
return;
}
@ -235,10 +235,10 @@ void wait::join_game(bool observe)
const config* campaign = &resources::config_manager->
game_config().find_child("campaign", "id",
level_.child(lexical_cast<std::string>(game_classification::MULTIPLAYER))["mp_campaign"]);
level_.child("multiplayer")["mp_campaign"]);
if (*campaign) {
state_.classification().difficulty =
level_.child(lexical_cast<std::string>(game_classification::MULTIPLAYER))["difficulty_define"].str();
level_.child("multiplayer")["difficulty_define"].str();
state_.classification().campaign_define =
(*campaign)["define"].str();
state_.classification().campaign_xtra_defines =
@ -251,7 +251,7 @@ void wait::join_game(bool observe)
}
// Add the map name to the title.
append_to_title(": " + level_["name"].t_str());
append_to_title(": " + get_scenario()["name"].t_str());
if (!observe) {
//search for an appropriate vacant slot. If a description is set
@ -260,7 +260,7 @@ void wait::join_game(bool observe)
//available side.
const config *side_choice = NULL;
int side_num = -1, nb_sides = 0;
BOOST_FOREACH(const config &sd, level_.child_range("side"))
BOOST_FOREACH(const config &sd, get_scenario().child_range("side"))
{
if (sd["controller"] == "reserved" && sd["current_player"] == preferences::login())
{
@ -315,7 +315,7 @@ void wait::join_game(bool observe)
}
const bool lock_settings =
level_["force_lock_settings"].to_bool();
get_scenario()["force_lock_settings"].to_bool();
const bool saved_game =
level_.child("multiplayer")["savegame"].to_bool();
@ -462,17 +462,17 @@ void wait::process_network_data(const config& data, const network::connection so
LOG_RG << data.debug() << std::endl;
//const int side = lexical_cast<int>(change["side"]);
if (config & sidetochange = level_.find_child("side", "side", change["side"])) {
if (config & sidetochange = get_scenario().find_child("side", "side", change["side"])) {
LOG_RG << "found side : " << sidetochange.debug() << std::endl;
sidetochange.merge_with(change);
LOG_RG << "changed to : " << sidetochange.debug() << std::endl;
} else {
LOG_RG << "change_controller didn't find any side!" << std::endl;
}
} else if(data.child("side") || data.child("next_scenario")) {
} else if(data.has_child("scenario") || data.has_child("snapshot") || data.child("next_scenario")) {
level_ = first_scenario_ ? data : data.child("next_scenario");
LOG_NW << "got some sides. Current number of sides = "
<< level_.child_count("side") << ','
<< get_scenario().child_count("side") << ','
<< data.child_count("side") << '\n';
generate_menu();
}
@ -486,7 +486,7 @@ void wait::generate_menu()
std::vector<std::string> details;
std::vector<std::string> playerlist;
BOOST_FOREACH(const config &sd, level_.child_range("side"))
BOOST_FOREACH(const config &sd, get_scenario().child_range("side"))
{
if (!sd["allow_player"].to_bool(true)) {
continue;
@ -600,7 +600,7 @@ void wait::generate_menu()
bool wait::has_level_data() const
{
if (first_scenario_) {
return level_.has_attribute("version") && level_.has_child("side");
return level_.has_attribute("version") && get_scenario().has_child("side");
} else {
return level_.has_child("next_scenario");
}
@ -634,5 +634,26 @@ bool wait::download_level_data()
return true;
}
config& wait::get_scenario()
{
if(config& scenario = level_.child("scenario"))
return scenario;
else if(config& snapshot = level_.child("snapshot"))
return snapshot;
else
return level_;
}
const config& wait::get_scenario() const
{
if(const config& scenario = level_.child("scenario"))
return scenario;
else if(const config& snapshot = level_.child("snapshot"))
return snapshot;
else
return level_;
}
} // namespace mp

View file

@ -68,6 +68,8 @@ private:
void generate_menu();
bool has_level_data() const;
bool download_level_data();
config& get_scenario();
const config& get_scenario() const;
gui::button cancel_button_;
gui::label start_label_;

View file

@ -435,8 +435,9 @@ LEVEL_RESULT play_game(game_display& disp, saved_game& gamestate,
return QUIT;
}
gamestate.set_scenario(gamestate.replay_start());
gamestate.replay_start() = config();
//The host shoudl send teh complete savegame now that also contains teh carryvoer seides start-
//gamestate.set_scenario(gamestate.replay_start());
//gamestate.replay_start() = config();
// Retain carryover_sides_start, as the config from the server
// doesn't contain it.
//TODO: enable this again or make mp_wait not change carryover sides start.
@ -446,44 +447,37 @@ LEVEL_RESULT play_game(game_display& disp, saved_game& gamestate,
gamestate.expand_scenario();
if (io_type == IO_SERVER && gamestate.valid()) {
config * scenario = &gamestate.get_starting_pos();
mp_game_settings& params = gamestate.mp_settings();
// A hash have to be generated using an unmodified
// scenario data.
params.hash = scenario->hash();
gamestate.mp_settings().hash = starting_pos.hash();
// Apply carryover before passing a scenario data to the
// mp::connect_engine.
gamestate.expand_carryover();
//WHY???
//gamestate.expand_carryover();
//We don't merge WML until start of next scenario, but if we want to allow user to disable MP ui in transition,
//then we have to move "allow_new_game" attribute over now.
bool allow_new_game_flag = (*scenario)["allow_new_game"].to_bool(true);
bool allow_new_game_flag = starting_pos["allow_new_game"].to_bool(true);
if (gamestate.carryover_sides_start.child_or_empty("end_level_data").child_or_empty("next_scenario_settings").has_attribute("allow_new_game")) {
allow_new_game_flag = gamestate.carryover_sides_start.child_or_empty("end_level_data").child("next_scenario_settings")["allow_new_game"].to_bool();
}
params.scenario_data = *scenario;
params.scenario_data["next_underlying_unit_id"] = n_unit::id_manager::instance().get_save_id();
params.mp_scenario = (*scenario)["id"].str();
params.mp_scenario_name = (*scenario)["name"].str();
params.num_turns = (*scenario)["turns"].to_int(-1);
params.saved_game = false;
params.use_map_settings =
(*scenario)["force_lock_settings"].to_bool();
gamestate.mp_settings().num_turns = starting_pos["turns"].to_int(-1);
gamestate.mp_settings().saved_game = false;
gamestate.mp_settings().use_map_settings = starting_pos["force_lock_settings"].to_bool();
mp::connect_engine_ptr
connect_engine(new mp::connect_engine(disp, gamestate,
params, !network_game, false));
connect_engine(new mp::connect_engine(gamestate,
!network_game, false));
if (allow_new_game_flag || (game_config::debug && network::nconnections() == 0)) {
// Opens mp::connect dialog to allow users to
// make an adjustments for scenario.
// TODO: Fix this so that it works when network::nconnections() > 0 as well.
mp::ui::result connect_res = mp::goto_mp_connect(disp,
*connect_engine, game_config, params.name);
*connect_engine, game_config, gamestate.mp_settings().name);
if (connect_res == mp::ui::QUIT) {
return QUIT;
}
@ -493,9 +487,6 @@ LEVEL_RESULT play_game(game_display& disp, saved_game& gamestate,
start_game(mp::connect_engine::FORCE_IMPORT_USERS);
}
starting_pos = gamestate.replay_start();
scenario = &starting_pos;
// TODO: move this code to mp::connect_engine
// in order to send generated data to the network
// before starting the game.

View file

@ -287,3 +287,51 @@ void saved_game::convert_to_start_save()
carryover_sides = config();
remove_snapshot();
}
config saved_game::to_config()
{
//TODO: remove this code dublication with write_... functions.
config r = classification_.to_config();
if(!this->replay_start_.empty())
{
r.add_child("replay_start", replay_start_);
}
if(!this->replay_data.empty())
{
r.add_child("replay", replay_data);
}
if(starting_pos_type_ == STARTINGPOS_SNAPSHOT)
{
r.add_child("snapshot", starting_pos_);
}
else if(starting_pos_type_ == STARTINGPOS_SCENARIO)
{
r.add_child("scenario", starting_pos_);
}
if(!this->carryover_sides.empty())
{
r.add_child("carryover_sides", carryover_sides);
}
if(!this->carryover_sides_start.empty())
{
r.add_child("carryover_sides_start", carryover_sides_start);
}
if (classification_.campaign_type == game_classification::MULTIPLAYER) {
r.add_child("multiplayer", mp_settings_.to_config());
}
return r;
}
std::string saved_game::get_scenario_id()
{
if(this->starting_pos_type_ == STARTINGPOS_SNAPSHOT
|| this->starting_pos_type_ == STARTINGPOS_SCENARIO)
{
return starting_pos_["id"];
}
else
{
return carryover_sides_start["next_scenario"];
}
}

View file

@ -29,6 +29,7 @@ public:
void write_general_info(config_writer& out) const;
void write_carryover(config_writer& out) const;
void write_starting_pos(config_writer& out) const;
config to_config();
void remove_old_scenario();
game_classification& classification() { return classification_; }
const game_classification& classification() const { return classification_; }
@ -53,6 +54,7 @@ public:
void convert_to_start_save();
const config& get_replay_starting_pos();
std::string get_scenario_id();
config& get_starting_pos();
config& replay_start() { return replay_start_; }
const config& replay_start() const { return replay_start_; }