Saved Game: formatting cleanup

This commit is contained in:
Charles Dang 2017-10-06 11:38:25 +11:00
parent 02907ebe75
commit 15d09dff07

View file

@ -12,53 +12,68 @@
*/
/**
Some information about savefiles:
A saveile can contain:
* General information (toplevel atributes, [multiplayer])
This is present in all savefiles
* [statistics]
This is present in all savefiles but it's not handled by playcampaign/play_controller/saved_game.
It's handled by savegame.cpp
* [snapshot]
If a savegame was saved during a scenario this contains a snapshot of the game at the point when it was saved.
* [carryover_sides_start]
At start-of-scenrio saves this contains data from the previous scenario that was preserved
* [carryover_sides]
In savefile made during the game, this tag contains data from [carryover_sides_start] that was not used in the current scenario but should be saved for a next scenario
* [replay_start]
A snapshot made very early to replay the game from.
* [replay]
A record of game actions that was made between the creation of [replay_start] and [snapshot].
The following types of savegames are known:
* Start of scenario savefiles
These files only contain general information, statistics, and [carryover_sides_start]
When these saves are loaded, the scenario data is loaded form the game config using the next_scenario attribute from [carryover_sides_start]
* Expanded Start of scenario savefiles
Similar to normal Start-of-scenario savefiles, but the also contain a [scenario] that contains the scenario data.
This type is only used internally and usually doesn't get written to the disk.
* Ingame savefile
These files contain general information, statistics, [snapshot], [replay], [replay_start], [snapshot], [carryover_sides]
These files don't contain a [carryover_sides_start] because both starting points ([replay_start] and [snapshot])
were made after [carryover_sides_start] was merged into the scenario.
* Replay savefiles
Like a Ingame save made during linger mode, but without the [snapshot]
*/
* Some information about savefiles:
*
* A savefile can contain:
*
* - General information (toplevel atributes, [multiplayer])
* This is present in all savefiles
*
* - [statistics]
* This is present in all savefiles but it's not handled by playcampaign/play_controller/saved_game.
* It's handled by savegame.cpp
*
* - [snapshot]
* If a savegame was saved during a scenario this contains a snapshot of the game at the point when
* it was saved.
*
* - [carryover_sides_start]
* At start-of-scenario saves this contains data from the previous scenario that was preserved.
*
* - [carryover_sides]
* In savefile made during the game, this tag contains data from [carryover_sides_start] that was not
* used in the current scenario but should be saved for a next scenario
*
* - [replay_start]
* A snapshot made very early to replay the game from.
*
* - [replay]
* A record of game actions that was made between the creation of [replay_start] and [snapshot].
*
*
* The following types of savegames are known:
*
* - Start of scenario savefiles
* These files only contain general information, statistics, and [carryover_sides_start]. When these
* saves are loaded, the scenario data is loaded form the game config using the next_scenario attribute
* from [carryover_sides_start].
*
* - Expanded Start of scenario savefiles
* Similar to normal Start-of-scenario savefiles, but the also contain a [scenario] that contains the
* scenario data. This type is only used internally and usually doesn't get written to the disk.
*
* - In-game savefile
* These files contain general information, statistics, [snapshot], [replay], [replay_start], [snapshot],
* and [carryover_sides]. These files don't contain a [carryover_sides_start] because both starting points
* ([replay_start] and [snapshot]) were made after [carryover_sides_start] was merged into the scenario.
*
* - Replay savefiles
* Like a in-game save made during linger mode, but without the [snapshot].
*/
#include "saved_game.hpp"
#include "carryover.hpp"
#include "config.hpp"
#include "cursor.hpp"
#include "log.hpp"
#include "formula/string_utils.hpp"
#include "game_config_manager.hpp"
#include "generators/map_create.hpp"
#include "statistics.hpp"
#include "log.hpp"
#include "serialization/binary_or_text.hpp"
#include "variable_info.hpp"
#include "formula/string_utils.hpp"
#include "config.hpp"
#include "statistics.hpp"
#include "variable.hpp" // for config_variable_set
#include "variable_info.hpp"
#include <boost/range/adaptors.hpp>
#include <boost/range/algorithm/copy.hpp>
@ -80,7 +95,6 @@ saved_game::saved_game()
, starting_pos_()
, replay_data_()
{
}
saved_game::saved_game(config cfg)
@ -117,10 +131,10 @@ void saved_game::set_carryover_sides_start(config carryover_sides_start)
void saved_game::set_random_seed()
{
if(has_carryover_expanded_ || !carryover_["random_seed"].empty())
{
if(has_carryover_expanded_ || !carryover_["random_seed"].empty()) {
return;
}
carryover_["random_seed"] = rand();
carryover_["random_calls"] = 0;
}
@ -129,34 +143,33 @@ void saved_game::write_config(config_writer& out) const
{
write_general_info(out);
write_starting_pos(out);
if(!this->replay_start_.empty())
{
if(!this->replay_start_.empty()) {
out.write_child("replay_start", replay_start_);
}
out.open_child("replay");
replay_data_.write(out);
out.close_child("replay");
write_carryover(out);
}
void saved_game::write_starting_pos(config_writer& out) const
{
if(starting_pos_type_ == STARTINGPOS_SNAPSHOT)
{
if(starting_pos_type_ == STARTINGPOS_SNAPSHOT) {
out.write_child("snapshot", starting_pos_);
}
else if(starting_pos_type_ == STARTINGPOS_SCENARIO)
{
} else if(starting_pos_type_ == STARTINGPOS_SCENARIO) {
out.write_child("scenario", starting_pos_);
}
}
void saved_game::write_carryover(config_writer& out) const
{
assert(not_corrupt());
out.write_child(has_carryover_expanded_ ? "carryover_sides" : "carryover_sides_start", carryover_);
}
void saved_game::write_general_info(config_writer& out) const
{
out.write(classification_.to_config());
@ -167,33 +180,36 @@ void saved_game::set_defaults()
{
const bool is_loaded_game = this->starting_pos_type_ != STARTINGPOS_SCENARIO;
const bool is_multiplayer_tag = classification().get_tagname() == "multiplayer";
static const std::vector<std::string> team_defaults {
"carryover_percentage",
"carryover_add",
};
for(config& side : starting_pos_.child_range("side"))
{
// Set save_id default value directly after loading to its default to prevent different default behaviour in mp_connect code and sp code.
if(side["save_id"].empty())
{
for(config& side : starting_pos_.child_range("side")) {
// Set save_id default value directly after loading to its default to prevent different default behaviour in
// mp_connect code and sp code.
if(side["save_id"].empty()) {
side["save_id"] = side["id"];
}
if(!is_multiplayer_tag && side["side_name"].blank())
{
if(!is_multiplayer_tag && side["side_name"].blank()) {
side["side_name"] = side["name"];
}
if(!is_loaded_game && !side["current_player"].empty())
{
ERR_NG << "Removed invalid 'current_player' attribute from [side] while loading a scenario. Consider using 'side_name' instead\n";
if(!is_loaded_game && !side["current_player"].empty()) {
ERR_NG << "Removed invalid 'current_player' attribute from [side] while loading a scenario. Consider using "
"'side_name' instead\n";
side["current_player"] = config::attribute_value();
}
// Set some team specific values to their defaults specified in scenario
for(const std::string& att_name : team_defaults)
{
for(const std::string& att_name : team_defaults) {
const config::attribute_value* scenario_value = starting_pos_.get(att_name);
config::attribute_value& team_value = side[att_name];
if(scenario_value && team_value.empty())
{
if(scenario_value && team_value.empty()) {
team_value = *scenario_value;
}
}
@ -202,28 +218,32 @@ void saved_game::set_defaults()
void saved_game::expand_scenario()
{
if(this->starting_pos_type_ == STARTINGPOS_NONE && !has_carryover_expanded_)
{
if(this->starting_pos_type_ == STARTINGPOS_NONE && !has_carryover_expanded_) {
game_config_manager::get()->load_game_config_for_game(this->classification());
const config& game_config = game_config_manager::get()->game_config();
const config& scenario = game_config.find_child(classification().get_tagname(), "id", carryover_["next_scenario"]);
if(scenario)
{
const config& scenario =
game_config.find_child(classification().get_tagname(), "id", carryover_["next_scenario"]);
if(scenario) {
this->starting_pos_type_ = STARTINGPOS_SCENARIO;
this->starting_pos_ = scenario;
// A hash has to be generated using an unmodified scenario data.
mp_settings_.hash = scenario.hash();
// Add addon_id information if it exists.
if (!scenario["addon_id"].empty() && scenario["require_scenario"].to_bool(false)) {
mp_settings_.update_addon_requirements(config {"id",scenario["addon_id"], "version", scenario["addon_version"], "min_version", scenario["addon_min_version"]});
if(!scenario["addon_id"].empty() && scenario["require_scenario"].to_bool(false)) {
mp_settings_.update_addon_requirements(config {
"id", scenario["addon_id"],
"version", scenario["addon_version"],
"min_version", scenario["addon_min_version"]
});
}
update_label();
set_defaults();
}
else
{
} else {
this->starting_pos_type_ = STARTINGPOS_INVALID;
this->starting_pos_ = config();
}
@ -232,135 +252,152 @@ void saved_game::expand_scenario()
namespace
{
bool variable_to_bool(const config& vars, const std::string& expression)
bool variable_to_bool(const config& vars, const std::string& expression)
{
std::string res = utils::interpolate_variables_into_string(expression, config_variable_set(vars));
return res == "true" || res == "yes" || res == "1";
}
// helper objects for saved_game::expand_mp_events()
struct modevents_entry
{
modevents_entry(const std::string& _type, const std::string& _id)
: type(_type)
, id(_id)
{
std::string res = utils::interpolate_variables_into_string(expression, config_variable_set(vars));
return res == "true" || res == "yes" || res == "1";
}
//helper objects for saved_game::expand_mp_events()
struct modevents_entry
std::string type;
std::string id;
};
struct modevents_entry_for
{
// This typedef is used by boost.
typedef modevents_entry result_type;
modevents_entry_for(const std::string& type)
: type_(type)
{
modevents_entry(const std::string& _type, const std::string& _id) : type(_type), id(_id) {}
std::string type;
std::string id;
};
struct modevents_entry_for
}
modevents_entry operator()(const std::string& id) const
{
//this typedef is used by boost.
typedef modevents_entry result_type;
modevents_entry_for(const std::string& type ) : type_(type) {}
modevents_entry operator()(const std::string& id) const
{
return modevents_entry(type_, id);
}
private:
std::string type_;
};
}
return modevents_entry(type_, id);
}
private:
std::string type_;
};
} // end anon namespace
void saved_game::load_mod(const std::string& type, const std::string& id)
{
if(const config& cfg = game_config_manager::get()->
game_config().find_child(type, "id", id))
{
// Note the addon_id if this mod is required to play the game in mp
if(const config& cfg = game_config_manager::get()->game_config().find_child(type, "id", id)) {
// Note the addon_id if this mod is required to play the game in mp.
std::string require_attr = "require_" + type;
bool require_default = (type == "era"); // By default, eras have "require_era = true", and mods have "require_modification = false"
if (!cfg["addon_id"].empty() && cfg[require_attr].to_bool(require_default)) {
mp_settings_.update_addon_requirements(config {"id",cfg["addon_id"], "version", cfg["addon_version"], "min_version", cfg["addon_min_version"]});
// By default, eras have "require_era = true", and mods have "require_modification = false".
bool require_default = (type == "era");
if(!cfg["addon_id"].empty() && cfg[require_attr].to_bool(require_default)) {
mp_settings_.update_addon_requirements(config{
"id", cfg["addon_id"], "version", cfg["addon_version"], "min_version", cfg["addon_min_version"]});
}
// Copy events
for(const config& modevent : cfg.child_range("event"))
{
if(modevent["enable_if"].empty() || variable_to_bool(carryover_.child_or_empty("variables"), modevent["enable_if"]))
{
for(const config& modevent : cfg.child_range("event")) {
if(modevent["enable_if"].empty()
|| variable_to_bool(carryover_.child_or_empty("variables"), modevent["enable_if"])
) {
this->starting_pos_.add_child("event", modevent);
}
}
// Copy lua
for(const config& modlua : cfg.child_range("lua"))
{
for(const config& modlua : cfg.child_range("lua")) {
this->starting_pos_.add_child("lua", modlua);
}
// Copy load_resource
for(const config& load_resource : cfg.child_range("load_resource"))
{
for(const config& load_resource : cfg.child_range("load_resource")) {
this->starting_pos_.add_child("load_resource", load_resource);
}
}
else
{
//TODO: A user message instead?
ERR_NG << "Couldn't find [" << type<< "] with id=" << id <<std::endl;
} else {
// TODO: A user message instead?
ERR_NG << "Couldn't find [" << type << "] with id=" << id << std::endl;
}
}
// Gets the ids of the mp_era and modifications which were set to be active, then fetches these configs from the game_config and copies their [event] and [lua] to the starting_pos_.
// At this time, also collect the addon_id attributes which appeared in them and put this list in the addon_ids attribute of the mp_settings.
// Gets the ids of the mp_era and modifications which were set to be active, then fetches these configs from the
// game_config and copies their [event] and [lua] to the starting_pos_.
// At this time, also collect the addon_id attributes which appeared in them and put this list in the addon_ids
// attribute of the mp_settings.
void saved_game::expand_mp_events()
{
expand_scenario();
if(this->starting_pos_type_ == STARTINGPOS_SCENARIO && !this->starting_pos_["has_mod_events"].to_bool(false))
{
if(this->starting_pos_type_ == STARTINGPOS_SCENARIO && !this->starting_pos_["has_mod_events"].to_bool(false)) {
std::vector<modevents_entry> mods;
std::set<std::string> loaded_resources;
boost::copy( mp_settings_.active_mods
| boost::adaptors::transformed(modevents_entry_for("modification"))
, std::back_inserter(mods) );
if(!mp_settings_.mp_era.empty()) //We don't want the error message below if there is no era (= if this is a sp game)
{ mods.emplace_back("era", mp_settings_.mp_era); }
if(!classification_.campaign.empty())
{ mods.emplace_back("campaign", classification_.campaign); }
// In the first iteration mod contains no [resource]s in all other iterations, mods contains only [resource]s
boost::copy(mp_settings_.active_mods | boost::adaptors::transformed(modevents_entry_for("modification")),
std::back_inserter(mods));
// We don't want the error message below if there is no era (= if this is a sp game).
if(!mp_settings_.mp_era .empty()) {
mods.emplace_back("era", mp_settings_.mp_era);
}
if(!classification_.campaign.empty()) {
mods.emplace_back("campaign", classification_.campaign);
}
// In the first iteration mod contains no [resource]s in all other iterations, mods contains only [resource]s.
do {
for(modevents_entry& mod : mods)
{
for(modevents_entry& mod : mods) {
load_mod(mod.type, mod.id);
}
mods.clear();
for(const config& cfg : starting_pos_.child_range("load_resource"))
{
for(const config& cfg : starting_pos_.child_range("load_resource")) {
if(loaded_resources.find(cfg["id"].str()) == loaded_resources.end()) {
mods.emplace_back("resource", cfg["id"].str());
loaded_resources.insert(cfg["id"].str());
}
}
starting_pos_.clear_children("load_resource");
} while(!mods.empty());
this->starting_pos_["has_mod_events"] = true;
}
}
void saved_game::expand_mp_options()
{
if(starting_pos_type_ == STARTINGPOS_SCENARIO && !has_carryover_expanded_)
{
if(starting_pos_type_ == STARTINGPOS_SCENARIO && !has_carryover_expanded_) {
std::vector<modevents_entry> mods;
boost::copy( mp_settings_.active_mods
| boost::adaptors::transformed(modevents_entry_for("modification"))
, std::back_inserter(mods) );
boost::copy(mp_settings_.active_mods | boost::adaptors::transformed(modevents_entry_for("modification")),
std::back_inserter(mods));
mods.emplace_back("era", mp_settings_.mp_era);
mods.emplace_back("multiplayer", get_scenario_id());
mods.emplace_back("campaign", classification().campaign);
config& variables = carryover_.child_or_add("variables");
for(modevents_entry& mod : mods)
{
if(const config& cfg = this->mp_settings().options.find_child(mod.type, "id", mod.id))
{
for(modevents_entry& mod : mods) {
if(const config& cfg = this->mp_settings().options.find_child(mod.type, "id", mod.id)) {
// Parse old [option] tag range syntax.
for(const config& option : cfg.child_range("option"))
{
try
{
for(const config& option : cfg.child_range("option")) {
try {
variable_access_create(option["id"], variables).as_scalar() = option["value"];
}
catch(const invalid_variablename_exception&)
{
} catch(const invalid_variablename_exception&) {
ERR_NG << "variable " << option["id"] << "cannot be set to " << option["value"] << std::endl;
}
}
@ -373,10 +410,8 @@ void saved_game::expand_mp_options()
ERR_NG << "variable " << option.first << "cannot be set to " << option.second << std::endl;
}
}
}
else
{
LOG_NG << "Couldn't find [" << mod.type<< "] with id=" << mod.id << " for [option]s" << std::endl;
} else {
LOG_NG << "Couldn't find [" << mod.type << "] with id=" << mod.id << " for [option]s" << std::endl;
}
}
}
@ -385,23 +420,24 @@ void saved_game::expand_mp_options()
void saved_game::expand_random_scenario()
{
expand_scenario();
if(this->starting_pos_type_ == STARTINGPOS_SCENARIO)
{
if(this->starting_pos_type_ == STARTINGPOS_SCENARIO) {
// If the entire scenario should be randomly generated
if(!starting_pos_["scenario_generation"].empty())
{
if(!starting_pos_["scenario_generation"].empty()) {
LOG_NG << "randomly generating scenario...\n";
const cursor::setter cursor_setter(cursor::WAIT);
config scenario_new = random_generate_scenario(starting_pos_["scenario_generation"],
starting_pos_.child("generator"));
//Preserve "story" form the scenario toplevel.
for(config& story : starting_pos_.child_range("story"))
{
config scenario_new =
random_generate_scenario(starting_pos_["scenario_generation"], starting_pos_.child("generator"));
// Preserve "story" form the scenario toplevel.
for(config& story : starting_pos_.child_range("story")) {
scenario_new.add_child("story", story);
}
scenario_new["id"] = starting_pos_["id"];
starting_pos_ = scenario_new;
update_label();
set_defaults();
}
@ -417,8 +453,8 @@ void saved_game::expand_random_scenario()
LOG_NG << "randomly generating map...\n";
const cursor::setter cursor_setter(cursor::WAIT);
starting_pos_["map_data"] = random_generate_map(
starting_pos_["map_generation"], starting_pos_.child("generator"));
starting_pos_["map_data"] =
random_generate_map(starting_pos_["map_generation"], starting_pos_.child("generator"));
}
}
}
@ -426,13 +462,11 @@ void saved_game::expand_random_scenario()
void saved_game::expand_carryover()
{
expand_scenario();
if(this->starting_pos_type_ == STARTINGPOS_SCENARIO && !has_carryover_expanded_)
{
if(this->starting_pos_type_ == STARTINGPOS_SCENARIO && !has_carryover_expanded_) {
carryover_info sides(carryover_);
sides.transfer_to(get_starting_pos());
for(config& side_cfg : get_starting_pos().child_range("side"))
{
for(config& side_cfg : get_starting_pos().child_range("side")) {
sides.transfer_all_to(side_cfg);
}
@ -450,6 +484,7 @@ config& saved_game::set_snapshot(config snapshot)
{
this->starting_pos_type_ = STARTINGPOS_SNAPSHOT;
this->starting_pos_.swap(snapshot);
return this->starting_pos_;
}
@ -457,7 +492,9 @@ void saved_game::set_scenario(config scenario)
{
this->starting_pos_type_ = STARTINGPOS_SCENARIO;
this->starting_pos_.swap(scenario);
has_carryover_expanded_ = false;
update_label();
}
@ -472,79 +509,80 @@ config& saved_game::get_starting_pos()
return starting_pos_;
}
const config& saved_game::get_replay_starting_pos()
{
if(!replay_start_.empty())
{
if(!replay_start_.empty()) {
return replay_start_;
}
if(!has_carryover_expanded_)
{
//Try to load the scenario form game config or from [scenario] if there is no [replay_start]
if(!has_carryover_expanded_) {
// Try to load the scenario form game config or from [scenario] if there is no [replay_start]
expand_scenario();
expand_carryover();
}
if(starting_pos_type_ == STARTINGPOS_SCENARIO)
{
if(starting_pos_type_ == STARTINGPOS_SCENARIO) {
return starting_pos_;
}
return this->replay_start_.child("some_non_existet_invalid");
}
void saved_game::convert_to_start_save()
{
assert(starting_pos_type_ == STARTINGPOS_SNAPSHOT);
carryover_info sides(starting_pos_, true);
sides.merge_old_carryover(carryover_info(carryover_));
sides.rng().rotate_random();
carryover_ = sides.to_config();
has_carryover_expanded_ = false;
replay_data_ = replay_recorder_base();
replay_start_ = config();
remove_snapshot();
}
config saved_game::to_config() const
{
//TODO: remove this code dublication with write_... functions.
// TODO: remove this code duplication with write_... functions.
config r = classification_.to_config();
if(!this->replay_start_.empty())
{
if(!this->replay_start_.empty()) {
r.add_child("replay_start", replay_start_);
}
replay_data_.write(r.add_child("replay"));
if(starting_pos_type_ == STARTINGPOS_SNAPSHOT)
{
if(starting_pos_type_ == STARTINGPOS_SNAPSHOT) {
r.add_child("snapshot", starting_pos_);
}
else if(starting_pos_type_ == STARTINGPOS_SCENARIO)
{
} else if(starting_pos_type_ == STARTINGPOS_SCENARIO) {
r.add_child("scenario", starting_pos_);
}
r.add_child(has_carryover_expanded_ ? "carryover_sides" : "carryover_sides_start" , carryover_);
r.add_child(has_carryover_expanded_ ? "carryover_sides" : "carryover_sides_start", carryover_);
r.add_child("multiplayer", mp_settings_.to_config());
return r;
}
std::string saved_game::get_scenario_id()
{
std::string scenario_id;
if(this->starting_pos_type_ == STARTINGPOS_SNAPSHOT
|| this->starting_pos_type_ == STARTINGPOS_SCENARIO)
{
if(this->starting_pos_type_ == STARTINGPOS_SNAPSHOT || this->starting_pos_type_ == STARTINGPOS_SCENARIO) {
scenario_id = starting_pos_["id"].str();
}
else if(!has_carryover_expanded_)
{
} else if(!has_carryover_expanded_) {
scenario_id = carryover_["next_scenario"].str();
}
else
{
} else {
assert(!"cannot figure out scenario_id");
throw "assertion ingnored";
}
return scenario_id == "null" ? "" : scenario_id;
}
@ -555,23 +593,24 @@ bool saved_game::not_corrupt() const
void saved_game::update_label()
{
if (classification().abbrev.empty())
if(classification().abbrev.empty()) {
classification().label = starting_pos_["name"].str();
else {
} else {
classification().label = classification().abbrev + "-" + starting_pos_["name"];
}
}
void saved_game::cancel_orders()
{
for(config &side : this->starting_pos_.child_range("side"))
{
for(config& side : this->starting_pos_.child_range("side")) {
// for humans "goto_x/y" is used for multi-turn-moves
// for the ai "goto_x/y" is a way for wml to order the ai to move a unit to a certain place.
// we want to cancel human order but not to break wml.
if (side["controller"] != "human" && side["controller"] != "network") continue;
for(config &unit : side.child_range("unit"))
{
if(side["controller"] != "human" && side["controller"] != "network") {
continue;
}
for(config& unit : side.child_range("unit")) {
unit["goto_x"] = -999;
unit["goto_y"] = -999;
}
@ -580,12 +619,14 @@ void saved_game::cancel_orders()
void saved_game::unify_controllers()
{
for(config &side : this->starting_pos_.child_range("side"))
{
if (side["controller"] == "network")
for(config& side : this->starting_pos_.child_range("side")) {
if(side["controller"] == "network") {
side["controller"] = "human";
if (side["controller"] == "network_ai")
}
if(side["controller"] == "network_ai") {
side["controller"] = "ai";
}
}
}
@ -598,12 +639,15 @@ saved_game& saved_game::operator=(saved_game&& other)
void saved_game::swap(saved_game& other)
{
carryover_.swap(other.carryover_);
std::swap(classification_, other.classification_);
std::swap(has_carryover_expanded_, other.has_carryover_expanded_);
std::swap(mp_settings_, other.mp_settings_);
replay_data_.swap(other.replay_data_);
replay_start_.swap(other.replay_start_);
starting_pos_.swap(other.starting_pos_);
std::swap(starting_pos_type_, other.starting_pos_type_);
}
@ -611,62 +655,53 @@ void saved_game::set_data(config& cfg)
{
log_scope("read_game");
if(config & caryover_sides = cfg.child("carryover_sides"))
{
if(config& caryover_sides = cfg.child("carryover_sides")) {
carryover_.swap(caryover_sides);
has_carryover_expanded_ = true;
}
else if(config & caryover_sides_start = cfg.child("carryover_sides_start"))
{
} else if(config& caryover_sides_start = cfg.child("carryover_sides_start")) {
carryover_.swap(caryover_sides_start);
has_carryover_expanded_ = false;
}
else
{
} else {
carryover_ = config();
has_carryover_expanded_ = false;
}
if(config & replay_start = cfg.child("replay_start"))
{
if(config& replay_start = cfg.child("replay_start")) {
replay_start_.swap(replay_start);
}
else
{
} else {
replay_start_ = config();
}
replay_data_ = replay_recorder_base();
//Serversided replays can contain multiple [replay]
for(config& replay : cfg.child_range("replay"))
{
// Serversided replays can contain multiple [replay]
for(config& replay : cfg.child_range("replay")) {
replay_data_.append_config(replay);
}
replay_data_.set_to_end();
if(config& snapshot = cfg.child("snapshot"))
{
if(config& snapshot = cfg.child("snapshot")) {
this->starting_pos_type_ = STARTINGPOS_SNAPSHOT;
this->starting_pos_.swap(snapshot);
}
else if(config& scenario = cfg.child("scenario"))
{
} else if(config& scenario = cfg.child("scenario")) {
this->starting_pos_type_ = STARTINGPOS_SCENARIO;
this->starting_pos_.swap(scenario);
}
else
{
} else {
this->starting_pos_type_ = STARTINGPOS_NONE;
this->starting_pos_ = config();
}
LOG_NG << "scenario: '" << carryover_["next_scenario"].str() << "'\n";
if (const config &stats = cfg.child("statistics")) {
if(const config& stats = cfg.child("statistics")) {
statistics::fresh_stats();
statistics::read_stats(stats);
}
classification_ = game_classification(cfg);
mp_settings_ = mp_game_settings(cfg.child_or_empty("multiplayer"));
cfg.clear();
}