Skip to content

Commit

Permalink
make wesnothd use savefile format for new games
Browse files Browse the repository at this point in the history
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
  • Loading branch information
gfgtdf committed Jun 15, 2014
1 parent dd7dca9 commit 728b29d
Show file tree
Hide file tree
Showing 16 changed files with 260 additions and 229 deletions.
166 changes: 66 additions & 100 deletions src/mp_game_utils.cpp
Expand Up @@ -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;

if (params.saved_game) {
try {
savegame::loadgame load(disp,
resources::config_manager->game_config(), state);
load.load_multiplayer_game();
load.fill_mplevel_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;
}

resources::config_manager->
load_game_config_for_game(state.classification());
}
catch (load_game_cancelled_exception){
return config();
} catch(config::error&) {
return config();
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;
}
} 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);
Expand All @@ -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++) {
Expand All @@ -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) {
Expand All @@ -152,91 +158,58 @@ 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);
recorder.set_to_end();
}
}

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");

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();
//state.replay_start() = level.child("replay_start");

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");
Expand All @@ -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)
Expand Down
5 changes: 2 additions & 3 deletions src/mp_game_utils.hpp
Expand Up @@ -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);

Expand Down
28 changes: 12 additions & 16 deletions src/multiplayer.cpp
Expand Up @@ -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;
Expand All @@ -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);

Expand Down Expand Up @@ -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,
Expand All @@ -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:
Expand All @@ -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;

Expand All @@ -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:
Expand Down Expand Up @@ -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);

Expand Down

0 comments on commit 728b29d

Please sign in to comment.