recorder writes directly into saved_game object
Previously recorder had config memaber and saved_game had a config memeber. And when saving a game the config was copied from recorder to saved_game and the other way when loading a game. Now the recorder object directly writes into the saved_game object. This saves some copying when saving and loading data. I also moved the pos_ variable from the recorder object to the saved_game replay_recorder_base object, This fixes a bug where saving a game during a replay also caused to not yet played turns to be written into the savefile.
This commit is contained in:
parent
9aa6bb37fd
commit
bb0ecd14c0
30 changed files with 312 additions and 197 deletions
|
@ -956,6 +956,7 @@ set(wesnoth-main_SRC
|
|||
replay.cpp
|
||||
replay_helper.cpp
|
||||
replay_controller.cpp
|
||||
replay_recorder_base.cpp
|
||||
resources.cpp
|
||||
save_blocker.cpp
|
||||
save_index.cpp
|
||||
|
|
|
@ -529,6 +529,7 @@ wesnoth_sources = Split("""
|
|||
replay.cpp
|
||||
replay_helper.cpp
|
||||
replay_controller.cpp
|
||||
replay_recorder_base.cpp
|
||||
resources.cpp
|
||||
save_blocker.cpp
|
||||
save_index.cpp
|
||||
|
|
|
@ -1266,7 +1266,7 @@ size_t move_unit_and_record(const std::vector<map_location> &steps,
|
|||
/*
|
||||
enter the synced mode and do the actual movement.
|
||||
*/
|
||||
recorder.add_synced_command("move",replay_helper::get_movement(steps, continued_move, skip_ally_sighted));
|
||||
resources::recorder->add_synced_command("move",replay_helper::get_movement(steps, continued_move, skip_ally_sighted));
|
||||
set_scontext_synced sync;
|
||||
size_t r = move_unit_internal(undo_stack, show_move, interrupted, mover);
|
||||
resources::controller->check_victory();
|
||||
|
|
|
@ -659,7 +659,7 @@ void undo_list::undo()
|
|||
n_unit::id_manager::instance().set_save_id(last_unit_id - action->unit_id_diff);
|
||||
|
||||
// Bookkeeping.
|
||||
recorder.undo_cut(action->get_replay_data());
|
||||
resources::recorder->undo_cut(action->get_replay_data());
|
||||
redos_.push_back(action.release());
|
||||
resources::whiteboard->on_gamestate_change();
|
||||
|
||||
|
@ -822,10 +822,10 @@ bool undo_list::auto_shroud_action::undo(int /*side*/, undo_list & undos)
|
|||
{
|
||||
// This does not count as an undoable action, so undo the next
|
||||
// action instead.
|
||||
recorder.undo();
|
||||
resources::recorder->undo();
|
||||
undos.undo();
|
||||
// Now keep the auto-shroud toggle at the top of the undo stack.
|
||||
recorder.add_synced_command("auto_shroud", replay_helper::get_auto_shroud(active));
|
||||
resources::recorder->add_synced_command("auto_shroud", replay_helper::get_auto_shroud(active));
|
||||
undos.add_auto_shroud(active, this->unit_id_diff);
|
||||
// Shroud actions never get moved to the redo stack, so claim an error.
|
||||
return false;
|
||||
|
@ -839,10 +839,10 @@ bool undo_list::update_shroud_action::undo(int /*side*/, undo_list & undos)
|
|||
{
|
||||
// This does not count as an undoable action, so undo the next
|
||||
// action instead.
|
||||
recorder.undo();
|
||||
resources::recorder->undo();
|
||||
undos.undo();
|
||||
// Now keep the shroud update at the top of the undo stack.
|
||||
recorder.add_synced_command("update_shroud", replay_helper::get_update_shroud());
|
||||
resources::recorder->add_synced_command("update_shroud", replay_helper::get_update_shroud());
|
||||
|
||||
undos.add_update_shroud(this->unit_id_diff);
|
||||
// Shroud actions never get moved to the redo stack, so claim an error.
|
||||
|
@ -898,7 +898,7 @@ bool undo_list::dismiss_action::redo(int side)
|
|||
<< ", which has no recall list!\n";
|
||||
return false;
|
||||
}
|
||||
recorder.redo(replay_data);
|
||||
resources::recorder->redo(replay_data);
|
||||
replay_data.clear();
|
||||
current_team.recall_list().erase_if_matches_id(dismissed_unit->id());
|
||||
return true;
|
||||
|
@ -931,7 +931,7 @@ bool undo_list::recall_action::redo(int side)
|
|||
|
||||
const std::string &msg = find_recall_location(side, loc, from, *un);
|
||||
if ( msg.empty() ) {
|
||||
recorder.redo(replay_data);
|
||||
resources::recorder->redo(replay_data);
|
||||
replay_data.clear();
|
||||
set_scontext_synced sync;
|
||||
recall_unit(id, current_team, loc, from, true, false);
|
||||
|
@ -979,7 +979,7 @@ bool undo_list::recruit_action::redo(int side)
|
|||
if ( msg.empty() ) {
|
||||
//MP_COUNTDOWN: restore recruitment bonus
|
||||
current_team.set_action_bonus_count(1 + current_team.action_bonus_count());
|
||||
recorder.redo(replay_data);
|
||||
resources::recorder->redo(replay_data);
|
||||
replay_data.clear();
|
||||
set_scontext_synced sync;
|
||||
recruit_unit(u_type, side, loc, from, true, false);
|
||||
|
@ -1044,7 +1044,7 @@ bool undo_list::move_action::redo(int side)
|
|||
}
|
||||
|
||||
gui.invalidate_unit_after_move(route.front(), route.back());
|
||||
recorder.redo(replay_data);
|
||||
resources::recorder->redo(replay_data);
|
||||
replay_data.clear();
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -287,7 +287,7 @@ void attack_result::do_execute()
|
|||
if(synced_context::get_synced_state() != synced_context::SYNCED) //RAII block for set_scontext_synced
|
||||
{
|
||||
//we don't use synced_context::run_in_synced_context because that wouldn't allow us to pass advancements_
|
||||
recorder.add_synced_command("attack", replay_helper::get_attack(attacker_loc_, defender_loc_, attacker_weapon, defender_weapon, a_->type_id(),
|
||||
resources::recorder->add_synced_command("attack", replay_helper::get_attack(attacker_loc_, defender_loc_, attacker_weapon, defender_weapon, a_->type_id(),
|
||||
d_->type_id(), a_->level(), d_->level(), resources::tod_manager->turn(),
|
||||
resources::tod_manager->get_time_of_day()));
|
||||
set_scontext_synced sync;
|
||||
|
|
|
@ -1368,8 +1368,8 @@ private:
|
|||
|
||||
const terrain_label *res;
|
||||
res = gui->labels().set_label(location, text, team_name, color);
|
||||
if (res)
|
||||
recorder.add_label(res);
|
||||
if (res && resources::recorder)
|
||||
resources::recorder->add_label(res);
|
||||
}
|
||||
|
||||
const formula_ai& ai_;
|
||||
|
|
|
@ -69,21 +69,21 @@ void ai_testing::log_turn(const char* msg, unsigned int side)
|
|||
c["units_cost"] = _units_cost;
|
||||
c["gold"] = _gold;
|
||||
c["villages"] = _villages;
|
||||
recorder.add_log_data("ai_log","turn_info",c);
|
||||
resources::recorder->add_log_data("ai_log","turn_info",c);
|
||||
}
|
||||
|
||||
void ai_testing::log_draw()
|
||||
{
|
||||
LOG_AI_TESTING << "DRAW:" << std::endl;
|
||||
recorder.add_log_data("ai_log","result","draw");
|
||||
resources::recorder->add_log_data("ai_log","result","draw");
|
||||
}
|
||||
|
||||
void ai_testing::log_victory(std::set<unsigned int> winners)
|
||||
{
|
||||
recorder.add_log_data("ai_log","result","victory");
|
||||
resources::recorder->add_log_data("ai_log","result","victory");
|
||||
for(std::set<unsigned int>::const_iterator w = winners.begin(); w != winners.end(); ++w) {
|
||||
LOG_AI_TESTING << "WINNER: "<< *w <<std::endl;
|
||||
recorder.add_log_data("ai_log","winner",str_cast(*w));
|
||||
resources::recorder->add_log_data("ai_log","winner",str_cast(*w));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -93,22 +93,22 @@ void ai_testing::log_game_start()
|
|||
int side = tm-resources::teams->begin()+1;
|
||||
LOG_AI_TESTING << "AI_IDENTIFIER"<<side<<": " << ai::manager::get_active_ai_identifier_for_side(side) <<std::endl;
|
||||
LOG_AI_TESTING << "TEAM"<<side<<": " << tm->name() << std::endl;
|
||||
recorder.add_log_data("ai_log","ai_id"+str_cast(side),ai::manager::get_active_ai_identifier_for_side(side));
|
||||
recorder.add_log_data("ai_log","faction"+str_cast(side),tm->name());
|
||||
resources::recorder->add_log_data("ai_log","ai_id"+str_cast(side),ai::manager::get_active_ai_identifier_for_side(side));
|
||||
resources::recorder->add_log_data("ai_log","faction"+str_cast(side),tm->name());
|
||||
///@todo 1.9: add information about ai_config
|
||||
}
|
||||
LOG_AI_TESTING << "VERSION: " << game_config::revision << std::endl;
|
||||
recorder.add_log_data("ai_log","version",game_config::revision);
|
||||
resources::recorder->add_log_data("ai_log","version",game_config::revision);
|
||||
}
|
||||
|
||||
void ai_testing::log_game_end()
|
||||
{
|
||||
LOG_AI_TESTING << "GAME_END_TURN: "<< resources::tod_manager->turn() <<std::endl;
|
||||
recorder.add_log_data("ai_log","end_turn",
|
||||
resources::recorder->add_log_data("ai_log","end_turn",
|
||||
str_cast(resources::tod_manager->turn()));
|
||||
for (std::vector<team>::const_iterator tm = resources::teams->begin(); tm != resources::teams->end(); ++tm) {
|
||||
int side = tm-resources::teams->begin()+1;
|
||||
recorder.add_log_data("ai_log","end_gold"+str_cast(side),str_cast(tm->gold()));
|
||||
recorder.add_log_data("ai_log","end_units"+str_cast(side),str_cast(resources::gameboard->side_units(side)));
|
||||
resources::recorder->add_log_data("ai_log","end_gold"+str_cast(side),str_cast(tm->gold()));
|
||||
resources::recorder->add_log_data("ai_log","end_units"+str_cast(side),str_cast(resources::gameboard->side_units(side)));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,8 +58,8 @@ static void display_label(int /*side*/, const map_location& location, const std:
|
|||
|
||||
const terrain_label *res;
|
||||
res = gui->labels().set_label(location, text, team_name, color);
|
||||
if (res)
|
||||
recorder.add_label(res);
|
||||
if (res && resources::recorder)
|
||||
resources::recorder->add_label(res);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -163,8 +163,6 @@ gui::dialog_button_action::RESULT delete_recall_unit::button_pressed(int menu_se
|
|||
|
||||
// Record the dismissal, then delete the unit.
|
||||
synced_context::run_and_throw("disband", replay_helper::get_disband(dismissed_unit->id()));
|
||||
//recorder.add_disband(dismissed_unit->id());
|
||||
//recall_list.erase(dismissed_unit);
|
||||
|
||||
return gui::DELETE_ITEM;
|
||||
} else {
|
||||
|
|
|
@ -497,7 +497,7 @@ wml_action::wml_action(const std::string & tag, handler function)
|
|||
/// @todo Finish experimenting.
|
||||
WML_HANDLER_FUNCTION(clear_global_variable,/**/,pcfg)
|
||||
{
|
||||
if (get_replay_source().at_end() || (network::nconnections() != 0))
|
||||
if (!resources::controller->is_replay())
|
||||
verify_and_clear_global_variable(pcfg);
|
||||
}
|
||||
|
||||
|
|
|
@ -476,8 +476,6 @@ static void enter_wait_mode(game_display& disp, const config& game_config,
|
|||
case mp::ui::PLAY:
|
||||
play_game(disp, state, game_config, game_config_manager::get()->terrain_types(), IO_CLIENT,
|
||||
preferences::skip_mp_replay() && observe, true, preferences::blindfold_replay() && observe);
|
||||
recorder.clear();
|
||||
|
||||
break;
|
||||
case mp::ui::QUIT:
|
||||
default:
|
||||
|
@ -520,8 +518,6 @@ static bool enter_connect_mode(game_display& disp, const config& game_config,
|
|||
case mp::ui::PLAY:
|
||||
play_game(disp, state, game_config, game_config_manager::get()->terrain_types(), IO_SERVER, false,
|
||||
!local_players_only);
|
||||
recorder.clear();
|
||||
|
||||
break;
|
||||
case mp::ui::CREATE:
|
||||
enter_create_mode(disp, game_config, state, local_players_only);
|
||||
|
@ -895,14 +891,14 @@ void start_local_game_commandline(game_display& disp, const config& game_config,
|
|||
|
||||
std::string label = "";
|
||||
if (cmdline_opts.multiplayer_label) label = *cmdline_opts.multiplayer_label;
|
||||
recorder.add_log_data("ai_log","ai_label",label);
|
||||
|
||||
//resources::recorder->add_log_data("ai_log","ai_label",label);
|
||||
|
||||
unsigned int repeat = (cmdline_opts.multiplayer_repeat) ? *cmdline_opts.multiplayer_repeat : 1;
|
||||
for(unsigned int i = 0; i < repeat; i++){
|
||||
saved_game state_copy(state);
|
||||
play_game(disp, state_copy, game_config, game_config_manager::get()->terrain_types(), IO_SERVER, false, false);
|
||||
}
|
||||
recorder.clear();
|
||||
}
|
||||
|
||||
void start_client(game_display& disp, const config& game_config,
|
||||
|
|
|
@ -127,7 +127,7 @@ static void show_carryover_message(saved_game& gamestate, playsingle_controller&
|
|||
LEVEL_RESULT play_replay(display& disp, saved_game& gamestate, const config& game_config,
|
||||
const tdata_cache & tdata, bool is_unit_test)
|
||||
{
|
||||
recorder = replay(gamestate.replay_data);
|
||||
gamestate.get_replay().set_pos(0);
|
||||
// 'starting_pos' will contain the position we start the game from.
|
||||
// this call also might expand [scenario] in case thatt there is no replay_start
|
||||
const config& starting_pos = gamestate.get_replay_starting_pos();
|
||||
|
@ -141,9 +141,6 @@ LEVEL_RESULT play_replay(display& disp, saved_game& gamestate, const config& gam
|
|||
|
||||
LEVEL_RESULT res = play_replay_level(game_config, tdata, disp.video(), gamestate, is_unit_test);
|
||||
|
||||
recorder.clear();
|
||||
gamestate.replay_data.clear();
|
||||
|
||||
return res;
|
||||
} catch(game::load_game_failed& e) {
|
||||
ERR_NG << std::string(_("The game could not be loaded: ")) + " (game::load_game_failed) " + e.message << std::endl;
|
||||
|
@ -256,8 +253,7 @@ LEVEL_RESULT play_game(game_display& disp, saved_game& gamestate,
|
|||
io_type_t io_type, bool skip_replay,
|
||||
bool network_game, bool blindfold_replay, bool is_unit_test)
|
||||
{
|
||||
recorder = replay(gamestate.replay_data);
|
||||
recorder.set_to_end();
|
||||
gamestate.get_replay().set_to_end();
|
||||
|
||||
gamestate.expand_scenario();
|
||||
|
||||
|
@ -333,7 +329,6 @@ LEVEL_RESULT play_game(game_display& disp, saved_game& gamestate,
|
|||
}
|
||||
|
||||
gamestate.convert_to_start_save();
|
||||
recorder.clear();
|
||||
|
||||
//If there is no next scenario we're done now.
|
||||
if(gamestate.get_scenario_id().empty())
|
||||
|
|
|
@ -65,6 +65,7 @@
|
|||
#include "preferences_display.hpp"
|
||||
#include "replay.hpp"
|
||||
#include "replay_helper.hpp"
|
||||
#include "resources.hpp"
|
||||
#include "savegame.hpp"
|
||||
#include "save_index.hpp"
|
||||
#include "scripting/game_lua_kernel.hpp"
|
||||
|
@ -513,9 +514,9 @@ void menu_handler::show_chat_log()
|
|||
{
|
||||
config c;
|
||||
c["name"] = "prototype of chat log";
|
||||
gui2::tchat_log chat_log_dialog(vconfig(c),&recorder);
|
||||
gui2::tchat_log chat_log_dialog(vconfig(c), resources::recorder);
|
||||
chat_log_dialog.show(gui_->video());
|
||||
//std::string text = recorder.build_chat_log();
|
||||
//std::string text = resources::recorder->build_chat_log();
|
||||
//gui::show_dialog(*gui_,NULL,_("Chat Log"),"",gui::CLOSE_ONLY,NULL,NULL,"",&text);
|
||||
|
||||
}
|
||||
|
@ -935,7 +936,7 @@ void menu_handler::rename_unit()
|
|||
const std::string label(N_("Name:"));
|
||||
|
||||
if(gui2::tedit_text::execute(title, label, name, gui_->video())) {
|
||||
recorder.add_rename(name, un->get_location());
|
||||
resources::recorder->add_rename(name, un->get_location());
|
||||
un->rename(name);
|
||||
gui_->invalidate_unit();
|
||||
}
|
||||
|
@ -1205,7 +1206,7 @@ void menu_handler::label_terrain(mouse_handler& mousehandler, bool team_only)
|
|||
}
|
||||
const terrain_label* res = gui_->labels().set_label(loc, label, team_name, color);
|
||||
if (res)
|
||||
recorder.add_label(res);
|
||||
resources::recorder->add_label(res);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1215,7 +1216,7 @@ void menu_handler::clear_labels()
|
|||
&& !board().is_observer())
|
||||
{
|
||||
gui_->labels().clear(gui_->current_team_name(), false);
|
||||
recorder.clear_labels(gui_->current_team_name(), false);
|
||||
resources::recorder->clear_labels(gui_->current_team_name(), false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2581,7 +2582,7 @@ void menu_handler::send_chat_message(const std::string& message, bool allies_onl
|
|||
}
|
||||
}
|
||||
|
||||
recorder.speak(cfg);
|
||||
resources::recorder->speak(cfg);
|
||||
|
||||
add_chat_message(time, cfg["id"], side, message,
|
||||
private_message ? events::chat_handler::MESSAGE_PRIVATE : events::chat_handler::MESSAGE_PUBLIC);
|
||||
|
|
|
@ -99,6 +99,7 @@ static void clear_resources()
|
|||
resources::tod_manager = NULL;
|
||||
resources::tunnels = NULL;
|
||||
resources::undo_stack = NULL;
|
||||
resources::recorder = NULL;
|
||||
resources::units = NULL;
|
||||
resources::whiteboard.reset();
|
||||
|
||||
|
@ -132,6 +133,7 @@ play_controller::play_controller(const config& level, saved_game& state_of_game,
|
|||
, xp_mod_(new unit_experience_accelerator(level["experience_modifier"].to_int(100)))
|
||||
, statistics_context_(new statistics::scenario_context(level["name"]))
|
||||
, undo_stack_(new actions::undo_list(level.child("undo_stack")))
|
||||
, replay_(new replay(state_of_game.get_replay()))
|
||||
, loading_game_(level["playing_team"].empty() == false)
|
||||
, player_number_(1)
|
||||
, first_player_(level["playing_team"].to_int() + 1)
|
||||
|
@ -156,6 +158,7 @@ play_controller::play_controller(const config& level, saved_game& state_of_game,
|
|||
resources::teams = &gamestate_.board_.teams_;
|
||||
resources::tod_manager = &gamestate_.tod_manager_;
|
||||
resources::undo_stack = undo_stack_.get();
|
||||
resources::recorder = replay_.get();
|
||||
resources::units = &gamestate_.board_.units_;
|
||||
resources::filter_con = &gamestate_;
|
||||
|
||||
|
@ -364,7 +367,7 @@ void play_controller::maybe_do_init_side()
|
|||
return;
|
||||
}
|
||||
|
||||
recorder.init_side();
|
||||
resources::recorder->init_side();
|
||||
do_init_side();
|
||||
}
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@ class game_data;
|
|||
class team;
|
||||
class unit;
|
||||
class wmi_pager;
|
||||
|
||||
class replay;
|
||||
class saved_game;
|
||||
struct mp_game_settings;
|
||||
class game_classification;
|
||||
|
@ -273,6 +273,7 @@ protected:
|
|||
/// undo_list can be an incomplete type at this point (which reduces the
|
||||
/// number of files that depend on actions/undo.hpp).
|
||||
boost::scoped_ptr<actions::undo_list> undo_stack_;
|
||||
boost::scoped_ptr<replay> replay_;
|
||||
|
||||
//if a team is specified whose turn it is, it means we're loading a game
|
||||
//instead of starting a fresh one. Gets reset to false after init_side
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "mp_ui_alerts.hpp"
|
||||
#include "playturn.hpp"
|
||||
#include "preferences.hpp"
|
||||
#include "resources.hpp"
|
||||
#include "savegame.hpp"
|
||||
#include "sound.hpp"
|
||||
#include "formula_string_utils.hpp"
|
||||
|
@ -322,7 +323,7 @@ void playmp_controller::after_human_turn(){
|
|||
|
||||
current_team().set_action_bonus_count(0);
|
||||
current_team().set_countdown_time(new_time);
|
||||
recorder.add_countdown_update(new_time, player_number_);
|
||||
resources::recorder->add_countdown_update(new_time, player_number_);
|
||||
}
|
||||
LOG_NG << "playmp::after_human_turn...\n";
|
||||
|
||||
|
@ -454,7 +455,7 @@ void playmp_controller::process_network_data()
|
|||
}
|
||||
turn_info::PROCESS_DATA_RESULT res = turn_info::PROCESS_CONTINUE;
|
||||
config cfg;
|
||||
if(!recorder.at_end()) {
|
||||
if(!resources::recorder->at_end()) {
|
||||
res = turn_info::replay_to_process_data_result(do_replay());
|
||||
}
|
||||
else if(network_reader_.read(cfg)) {
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
#include "playturn.hpp"
|
||||
#include "random_new_deterministic.hpp"
|
||||
#include "replay_helper.hpp"
|
||||
#include "resources.hpp"
|
||||
#include "savegame.hpp"
|
||||
#include "sound.hpp"
|
||||
#include "synced_context.hpp"
|
||||
|
@ -76,7 +77,7 @@ playsingle_controller::playsingle_controller(const config& level,
|
|||
: play_controller(level, state_of_game, ticks, game_config, tdata, video, skip_replay)
|
||||
, cursor_setter(cursor::NORMAL)
|
||||
, textbox_info_()
|
||||
, replay_sender_(recorder)
|
||||
, replay_sender_(*resources::recorder)
|
||||
, network_reader_()
|
||||
, turn_data_(replay_sender_, network_reader_)
|
||||
, end_turn_(END_TURN_NONE)
|
||||
|
@ -207,13 +208,13 @@ void playsingle_controller::play_scenario_init() {
|
|||
|
||||
fire_preload();
|
||||
|
||||
assert(recorder.at_end());
|
||||
assert(resources::recorder->at_end());
|
||||
|
||||
if(!loading_game_ )
|
||||
{
|
||||
assert(recorder.empty());
|
||||
recorder.add_start();
|
||||
recorder.get_next_action();
|
||||
assert(resources::recorder->empty());
|
||||
resources::recorder->add_start();
|
||||
resources::recorder->get_next_action();
|
||||
//we can only use a set_scontext_synced with a non empty recorder.
|
||||
set_scontext_synced sync;
|
||||
|
||||
|
@ -839,7 +840,7 @@ void playsingle_controller::sync_end_turn()
|
|||
assert(synced_context::synced_state() == synced_context::UNSYNCED);
|
||||
if(end_turn_ == END_TURN_REQUIRED && current_team().is_local())
|
||||
{
|
||||
recorder.end_turn();
|
||||
resources::recorder->end_turn();
|
||||
end_turn_ = END_TURN_SYNCED;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -99,7 +99,7 @@ turn_info::PROCESS_DATA_RESULT turn_info::handle_turn(const config& t)
|
|||
/** @todo FIXME: Check what commands we execute when it's our turn! */
|
||||
|
||||
//note, that this function might call itself recursively: do_replay -> ... -> get_user_choice -> ... -> playmp_controller::pull_remote_choice -> sync_network -> handle_turn
|
||||
recorder.add_config(t, replay::MARK_AS_SENT);
|
||||
resources::recorder->add_config(t, replay::MARK_AS_SENT);
|
||||
PROCESS_DATA_RESULT retv = replay_to_process_data_result(do_replay());
|
||||
return retv;
|
||||
}
|
||||
|
@ -132,7 +132,7 @@ turn_info::PROCESS_DATA_RESULT turn_info::process_network_data(const config& cfg
|
|||
assert(network::nconnections() <= 1);
|
||||
assert(cfg.all_children_count() == 1);
|
||||
assert(cfg.attribute_range().first == cfg.attribute_range().second);
|
||||
if(!recorder.at_end())
|
||||
if(!resources::recorder->at_end())
|
||||
{
|
||||
ERR_NW << "processing network data while still having data on the replay." << std::endl;
|
||||
}
|
||||
|
|
134
src/replay.cpp
134
src/replay.cpp
|
@ -38,6 +38,7 @@
|
|||
#include "statistics.hpp"
|
||||
#include "unit.hpp"
|
||||
#include "whiteboard/manager.hpp"
|
||||
#include "replay_recorder_base.hpp"
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
@ -142,11 +143,6 @@ static time_t get_time(const config &speak)
|
|||
return time;
|
||||
}
|
||||
|
||||
// FIXME: this one now has to be assigned with set_random_generator
|
||||
// from play_level or similar. We should surely hunt direct
|
||||
// references to it from this very file and move it out of here.
|
||||
replay recorder;
|
||||
|
||||
chat_msg::chat_msg(const config &cfg)
|
||||
: color_()
|
||||
, nick_()
|
||||
|
@ -183,22 +179,10 @@ chat_msg::~chat_msg()
|
|||
{
|
||||
}
|
||||
|
||||
replay::replay() :
|
||||
cfg_(),
|
||||
pos_(0),
|
||||
message_locations()
|
||||
replay::replay(replay_recorder_base& base)
|
||||
: base_(&base)
|
||||
, message_locations()
|
||||
{}
|
||||
|
||||
replay::replay(const config& cfg) :
|
||||
cfg_(cfg),
|
||||
pos_(0),
|
||||
message_locations()
|
||||
{}
|
||||
|
||||
void replay::append(const config& cfg)
|
||||
{
|
||||
cfg_.append(cfg);
|
||||
}
|
||||
/*
|
||||
TODO: there should be different types of OOS messages:
|
||||
1)the normal OOS message
|
||||
|
@ -314,27 +298,27 @@ void replay::end_turn()
|
|||
|
||||
void replay::add_log_data(const std::string &key, const std::string &var)
|
||||
{
|
||||
config& ulog = cfg_.child_or_add("upload_log");
|
||||
config& ulog = base_->get_upload_log();
|
||||
ulog[key] = var;
|
||||
}
|
||||
|
||||
void replay::add_log_data(const std::string &category, const std::string &key, const std::string &var)
|
||||
{
|
||||
config& ulog = cfg_.child_or_add("upload_log");
|
||||
config& ulog = base_->get_upload_log();
|
||||
config& cat = ulog.child_or_add(category);
|
||||
cat[key] = var;
|
||||
}
|
||||
|
||||
void replay::add_log_data(const std::string &category, const std::string &key, const config &c)
|
||||
{
|
||||
config& ulog = cfg_.child_or_add("upload_log");
|
||||
config& ulog = base_->get_upload_log();
|
||||
config& cat = ulog.child_or_add(category);
|
||||
cat.add_child(key,c);
|
||||
}
|
||||
|
||||
void replay::add_chat_message_location()
|
||||
{
|
||||
message_locations.push_back(pos_-1);
|
||||
message_locations.push_back(base_->get_pos() - 1);
|
||||
}
|
||||
|
||||
void replay::speak(const config& cfg)
|
||||
|
@ -355,7 +339,7 @@ void replay::add_chat_log_entry(const config &cfg, std::back_insert_iterator<std
|
|||
|
||||
void replay::remove_command(int index)
|
||||
{
|
||||
cfg_.remove_child("command", index);
|
||||
base_->remove_command(index);
|
||||
std::vector<int>::reverse_iterator loc_it;
|
||||
for (loc_it = message_locations.rbegin(); loc_it != message_locations.rend() && index < *loc_it;++loc_it)
|
||||
{
|
||||
|
@ -412,13 +396,12 @@ struct async_cmd
|
|||
|
||||
void replay::redo(const config& cfg)
|
||||
{
|
||||
//we set pos_ = ncommands(), if we recorded something else in the meantime it doesn't make sense to redo an action.
|
||||
assert(pos_ == ncommands());
|
||||
assert(base_->get_pos() == ncommands());
|
||||
BOOST_FOREACH(const config &cmd, cfg.child_range("command"))
|
||||
{
|
||||
/*config &cfg = */cfg_.add_child("command", cmd);
|
||||
base_->add_child() = cmd;
|
||||
}
|
||||
pos_ = ncommands();
|
||||
base_->set_to_end();
|
||||
|
||||
}
|
||||
|
||||
|
@ -426,7 +409,7 @@ void replay::redo(const config& cfg)
|
|||
|
||||
config& replay::get_last_real_command()
|
||||
{
|
||||
for (int cmd_num = pos_ - 1; cmd_num >= 0; --cmd_num)
|
||||
for (int cmd_num = base_->get_pos() - 1; cmd_num >= 0; --cmd_num)
|
||||
{
|
||||
config &c = command(cmd_num);
|
||||
const config &cc = c;
|
||||
|
@ -445,8 +428,8 @@ config& replay::get_last_real_command()
|
|||
void replay::undo_cut(config& dst)
|
||||
{
|
||||
assert(dst.empty());
|
||||
//pos_ < ncommands() could mean that we try to undo commands that haven't been executed yet.
|
||||
assert(pos_ == ncommands());
|
||||
//assert that we are not undoing a command which we didn't execute yet.
|
||||
assert(at_end());
|
||||
std::vector<async_cmd> async_cmds;
|
||||
// Remember commands not yet synced and skip over them.
|
||||
// We assume that all already sent (sent=yes) data isn't undoable
|
||||
|
@ -478,13 +461,13 @@ void replay::undo_cut(config& dst)
|
|||
|
||||
if (cmd < 0) return;
|
||||
//we add the commands that we want to remove later to the passed cfg first.
|
||||
dst.add_child("command", cfg_.child("command", cmd));
|
||||
dst.add_child("command", base_->get_command_at(cmd));
|
||||
//we do this in a seperate loop because we don't want to loop forward in the loop while when we remove the elements to keepo the indexes simple.
|
||||
for(int cmd_2 = cmd + 1; cmd_2 < ncommands(); ++cmd_2)
|
||||
{
|
||||
if(command(cmd_2)["dependent"].to_bool(false))
|
||||
{
|
||||
dst.add_child("command", cfg_.child("command", cmd_2));
|
||||
dst.add_child("command", base_->get_command_at(cmd_2));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -543,13 +526,15 @@ void replay::undo_cut(config& dst)
|
|||
if (config &async_child = ac.cfg->child("rename"))
|
||||
{
|
||||
map_location aloc(async_child, resources::gamedata);
|
||||
if (src == aloc) remove_command(ac.num);
|
||||
if (src == aloc) {
|
||||
remove_command(ac.num);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
remove_command(cmd);
|
||||
pos_ = ncommands();
|
||||
set_to_end();
|
||||
}
|
||||
|
||||
void replay::undo()
|
||||
|
@ -560,72 +545,74 @@ void replay::undo()
|
|||
|
||||
config &replay::command(int n)
|
||||
{
|
||||
config & retv = cfg_.child("command", n);
|
||||
config & retv = base_->get_command_at(n);
|
||||
assert(retv);
|
||||
return retv;
|
||||
}
|
||||
|
||||
int replay::ncommands() const
|
||||
{
|
||||
return cfg_.child_count("command");
|
||||
return base_->size();
|
||||
}
|
||||
|
||||
config& replay::add_command()
|
||||
{
|
||||
//pos_ != ncommands() means that there is a command on the replay which would be skipped.
|
||||
assert(pos_ == ncommands());
|
||||
pos_ = ncommands()+1;
|
||||
return cfg_.add_child("command");
|
||||
//if we werent at teh end of teh replay we sould skip one or mutiple commands.
|
||||
assert(at_end());
|
||||
config& retv = base_->add_child();
|
||||
set_to_end();
|
||||
return retv;
|
||||
}
|
||||
|
||||
config& replay::add_nonundoable_command()
|
||||
{
|
||||
config& r = cfg_.add_child_at("command",config(), pos_);
|
||||
config& r = base_->insert_command(base_->get_pos());
|
||||
r["undo"] = false;
|
||||
++pos_;
|
||||
base_->set_pos(base_->get_pos() + 1);
|
||||
return r;
|
||||
}
|
||||
|
||||
void replay::start_replay()
|
||||
{
|
||||
pos_ = 0;
|
||||
base_->set_pos(0);
|
||||
}
|
||||
|
||||
void replay::revert_action()
|
||||
{
|
||||
if (pos_ > 0)
|
||||
--pos_;
|
||||
|
||||
if (base_->get_pos() > 0)
|
||||
base_->set_pos(base_->get_pos() - 1);
|
||||
}
|
||||
|
||||
config* replay::get_next_action()
|
||||
{
|
||||
if (pos_ >= ncommands())
|
||||
if (at_end())
|
||||
return NULL;
|
||||
|
||||
LOG_REPLAY << "up to replay action " << pos_ + 1 << '/' << ncommands() << '\n';
|
||||
LOG_REPLAY << "up to replay action " << base_->get_pos() + 1 << '/' << ncommands() << '\n';
|
||||
|
||||
config* retv = &command(pos_);
|
||||
++pos_;
|
||||
config* retv = &command(base_->get_pos());
|
||||
base_->set_pos(base_->get_pos() + 1);
|
||||
return retv;
|
||||
}
|
||||
|
||||
|
||||
bool replay::at_end() const
|
||||
{
|
||||
return pos_ >= ncommands();
|
||||
assert(base_->get_pos() <= ncommands());
|
||||
return base_->get_pos() == ncommands();
|
||||
}
|
||||
|
||||
void replay::set_to_end()
|
||||
{
|
||||
pos_ = ncommands();
|
||||
base_->set_to_end();
|
||||
}
|
||||
|
||||
void replay::clear()
|
||||
{
|
||||
message_locations.clear();
|
||||
message_log.clear();
|
||||
cfg_ = config();
|
||||
pos_ = 0;
|
||||
//FIXME
|
||||
}
|
||||
|
||||
bool replay::empty()
|
||||
|
@ -637,25 +624,20 @@ void replay::add_config(const config& cfg, MARK_SENT mark)
|
|||
{
|
||||
BOOST_FOREACH(const config &cmd, cfg.child_range("command"))
|
||||
{
|
||||
config &cfg = cfg_.add_child("command", cmd);
|
||||
config &cfg = base_->insert_command(base_->size());
|
||||
cfg = cmd;
|
||||
if(mark == MARK_AS_SENT) {
|
||||
cfg["sent"] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
replay& get_replay_source()
|
||||
{
|
||||
return recorder;
|
||||
}
|
||||
|
||||
bool replay::add_start_if_not_there_yet()
|
||||
{
|
||||
//this method would confuse the value of 'pos' otherwise
|
||||
assert(pos_ == 0);
|
||||
if(at_end() || !cfg_.child("command", pos_).has_child("start"))
|
||||
assert(base_->get_pos() == 0);
|
||||
if(at_end() || !base_->get_command_at(0).has_child("start"))
|
||||
{
|
||||
cfg_.add_child_at("command",config_of("start", config()),pos_);
|
||||
base_->insert_command(0) = config_of("start", config());
|
||||
return true;
|
||||
}
|
||||
else
|
||||
|
@ -695,7 +677,7 @@ REPLAY_RETURN do_replay_handle(bool one_move)
|
|||
const int side_num = resources::controller->current_side();
|
||||
while(true)
|
||||
{
|
||||
const config *cfg = get_replay_source().get_next_action();
|
||||
const config *cfg = resources::recorder->get_next_action();
|
||||
const bool is_synced = (synced_context::get_synced_state() == synced_context::SYNCED);
|
||||
|
||||
DBG_REPLAY << "in do replay with is_synced=" << is_synced << "\n";
|
||||
|
@ -727,7 +709,7 @@ REPLAY_RETURN do_replay_handle(bool one_move)
|
|||
const std::string &message = child["message"];
|
||||
//if (!preferences::parse_should_show_lobby_join(speaker_name, message)) return;
|
||||
bool is_whisper = (speaker_name.find("whisper: ") == 0);
|
||||
get_replay_source().add_chat_message_location();
|
||||
resources::recorder->add_chat_message_location();
|
||||
if (!resources::controller->is_skipping_replay() || is_whisper) {
|
||||
int side = child["side"];
|
||||
resources::screen->get_chat_manager().add_chat_message(get_time(child), speaker_name, side, message,
|
||||
|
@ -775,7 +757,7 @@ REPLAY_RETURN do_replay_handle(bool one_move)
|
|||
if(is_synced)
|
||||
{
|
||||
replay::process_error("found side initialization in replay expecting a user choice\n" );
|
||||
get_replay_source().revert_action();
|
||||
resources::recorder->revert_action();
|
||||
return REPLAY_FOUND_DEPENDENT;
|
||||
}
|
||||
else
|
||||
|
@ -790,7 +772,7 @@ REPLAY_RETURN do_replay_handle(bool one_move)
|
|||
if(is_synced)
|
||||
{
|
||||
replay::process_error("found turn end in replay while expecting a user choice\n" );
|
||||
get_replay_source().revert_action();
|
||||
resources::recorder->revert_action();
|
||||
return REPLAY_FOUND_DEPENDENT;
|
||||
}
|
||||
else
|
||||
|
@ -832,7 +814,7 @@ REPLAY_RETURN do_replay_handle(bool one_move)
|
|||
assert(cfg->all_children_count() == 1);
|
||||
std::string child_name = cfg->all_children_range().first->key;
|
||||
DBG_REPLAY << "got an dependent action name = " << child_name <<"\n";
|
||||
get_replay_source().revert_action();
|
||||
resources::recorder->revert_action();
|
||||
return REPLAY_FOUND_DEPENDENT;
|
||||
}
|
||||
else
|
||||
|
@ -844,7 +826,7 @@ REPLAY_RETURN do_replay_handle(bool one_move)
|
|||
if(is_synced)
|
||||
{
|
||||
replay::process_error("found [" + commandname + "] command in replay expecting a user choice\n" );
|
||||
get_replay_source().revert_action();
|
||||
resources::recorder->revert_action();
|
||||
return REPLAY_FOUND_DEPENDENT;
|
||||
}
|
||||
else
|
||||
|
@ -964,7 +946,7 @@ static std::map<int, config> get_user_choice_internal(const std::string &name, c
|
|||
}
|
||||
|
||||
bool has_local_side = local_side != 0;
|
||||
bool is_replay_end = get_replay_source().at_end();
|
||||
bool is_replay_end = resources::recorder->at_end();
|
||||
|
||||
if (is_replay_end && has_local_side)
|
||||
{
|
||||
|
@ -974,7 +956,7 @@ static std::map<int, config> get_user_choice_internal(const std::string &name, c
|
|||
DBG_REPLAY << "MP synchronization: local choice\n";
|
||||
config cfg = uch.query_user(local_side);
|
||||
|
||||
recorder.user_input(name, cfg, local_side);
|
||||
resources::recorder->user_input(name, cfg, local_side);
|
||||
retv[local_side]= cfg;
|
||||
|
||||
//send data to others.
|
||||
|
@ -1001,13 +983,13 @@ static std::map<int, config> get_user_choice_internal(const std::string &name, c
|
|||
{
|
||||
DBG_REPLAY << "MP synchronization: extracting choice from replay with has_local_side=" << has_local_side << "\n";
|
||||
|
||||
const config *action = get_replay_source().get_next_action();
|
||||
assert(action); //action cannot be null because get_replay_source().at_end() returned false.
|
||||
const config *action = resources::recorder->get_next_action();
|
||||
assert(action); //action cannot be null because resources::recorder->at_end() returned false.
|
||||
if( !action->has_child(name) || !(*action)["dependent"].to_bool())
|
||||
{
|
||||
replay::process_error("[" + name + "] expected but none found\n. found instead:\n" + action->debug());
|
||||
//We save this action for later
|
||||
get_replay_source().revert_action();
|
||||
resources::recorder->revert_action();
|
||||
//and let the user try to get the intended result.
|
||||
BOOST_FOREACH(int side, sides)
|
||||
{
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include <deque>
|
||||
#include <map>
|
||||
#include <set>
|
||||
class replay_recorder_base;
|
||||
class game_display;
|
||||
class terrain_label;
|
||||
class unit_map;
|
||||
|
@ -50,11 +51,9 @@ private:
|
|||
class replay
|
||||
{
|
||||
public:
|
||||
replay();
|
||||
explicit replay(const config& cfg);
|
||||
|
||||
void append(const config& cfg);
|
||||
explicit replay(replay_recorder_base& base);
|
||||
|
||||
|
||||
void add_start();
|
||||
void add_countdown_update(int value,int team);
|
||||
|
||||
|
@ -93,8 +92,6 @@ public:
|
|||
//ignored by the undo system.
|
||||
enum DATA_TYPE { ALL_DATA, NON_UNDO_DATA };
|
||||
config get_data_range(int cmd_start, int cmd_end, DATA_TYPE data_type=ALL_DATA);
|
||||
config get_last_turn(int num_turns=1);
|
||||
const config& get_replay_data() const { return cfg_; }
|
||||
|
||||
void undo();
|
||||
/*
|
||||
|
@ -145,16 +142,10 @@ private:
|
|||
* @return a reference to the added command
|
||||
*/
|
||||
config& add_nonundoable_command();
|
||||
config cfg_;
|
||||
int pos_;
|
||||
|
||||
replay_recorder_base* base_;
|
||||
std::vector<int> message_locations;
|
||||
};
|
||||
|
||||
replay& get_replay_source();
|
||||
|
||||
extern replay recorder;
|
||||
|
||||
enum REPLAY_RETURN
|
||||
{
|
||||
REPLAY_RETURN_AT_END,
|
||||
|
|
|
@ -97,7 +97,7 @@ void play_replay_level_main_loop(replay_controller & replaycontroller, bool & is
|
|||
void replay_controller::try_run_to_completion() {
|
||||
for (;;) {
|
||||
play_slice();
|
||||
if (recorder.at_end()) {
|
||||
if (resources::recorder->at_end()) {
|
||||
return;
|
||||
} else {
|
||||
if (!is_playing_) {
|
||||
|
@ -271,7 +271,7 @@ void replay_controller::replay_ui_playback_should_stop()
|
|||
if(!replay_ui_has_all_buttons())
|
||||
return;
|
||||
|
||||
if(!recorder.at_end()) {
|
||||
if(!resources::recorder->at_end()) {
|
||||
play_button()->enable(true);
|
||||
reset_button()->enable(true);
|
||||
play_turn_button()->enable(true);
|
||||
|
@ -317,7 +317,7 @@ void replay_controller::reset_replay()
|
|||
it_is_a_new_turn_ = true;
|
||||
skip_replay_ = false;
|
||||
gamestate_.tod_manager_= tod_manager_start_;
|
||||
recorder.start_replay();
|
||||
resources::recorder->start_replay();
|
||||
saved_game_ = saved_game_start_;
|
||||
gamestate_.board_ = gameboard_start_;
|
||||
gui_->change_display_context(&gamestate_.board_); //this doesn't change the pointer value, but it triggers the gui to update the internal terrain builder object,
|
||||
|
@ -359,14 +359,14 @@ void replay_controller::reset_replay()
|
|||
// Scenario initialization. (c.f. playsingle_controller::play_scenario())
|
||||
fire_preload();
|
||||
{ //block for set_scontext_synced
|
||||
if(recorder.add_start_if_not_there_yet())
|
||||
if(resources::recorder->add_start_if_not_there_yet())
|
||||
{
|
||||
ERR_REPLAY << "inserted missing [start]" << std::endl;
|
||||
}
|
||||
config* pstart = recorder.get_next_action();
|
||||
config* pstart = resources::recorder->get_next_action();
|
||||
assert(pstart->has_child("start"));
|
||||
/*
|
||||
use this after recorder.add_synced_command
|
||||
use this after resources::recorder->add_synced_command
|
||||
because set_scontext_synced sets the checkup to the last added command
|
||||
*/
|
||||
set_scontext_synced sync;
|
||||
|
@ -476,7 +476,7 @@ void replay_controller::replay_skip_animation(){
|
|||
void replay_controller::play_replay()
|
||||
{
|
||||
|
||||
if (recorder.at_end())
|
||||
if (resources::recorder->at_end())
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -495,7 +495,7 @@ void replay_controller::play_replay()
|
|||
void replay_controller::play_replay_main_loop()
|
||||
{
|
||||
DBG_REPLAY << "starting main loop\n" << (SDL_GetTicks() - ticks_) << "\n";
|
||||
for(; !recorder.at_end() && is_playing_; first_player_ = 1) {
|
||||
for(; !resources::recorder->at_end() && is_playing_; first_player_ = 1) {
|
||||
play_turn();
|
||||
}
|
||||
}
|
||||
|
@ -512,7 +512,7 @@ void replay_controller::play_turn()
|
|||
|
||||
bool last_team = false;
|
||||
|
||||
while ( (!last_team) && (!recorder.at_end()) && is_playing_ ){
|
||||
while ( (!last_team) && (!resources::recorder->at_end()) && is_playing_ ){
|
||||
last_team = static_cast<size_t>(player_number_) == gamestate_.board_.teams().size();
|
||||
play_side();
|
||||
play_slice();
|
||||
|
@ -624,5 +624,5 @@ void replay_controller::handle_generic_event(const std::string& name)
|
|||
}
|
||||
|
||||
bool replay_controller::recorder_at_end() {
|
||||
return recorder.at_end();
|
||||
return resources::recorder->at_end();
|
||||
}
|
||||
|
|
104
src/replay_recorder_base.cpp
Normal file
104
src/replay_recorder_base.cpp
Normal file
|
@ -0,0 +1,104 @@
|
|||
|
||||
#include "replay_recorder_base.hpp"
|
||||
#include "serialization\binary_or_text.hpp"
|
||||
|
||||
replay_recorder_base::replay_recorder_base(void)
|
||||
: upload_log_()
|
||||
, commands_()
|
||||
, pos_(0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
replay_recorder_base::~replay_recorder_base(void)
|
||||
{
|
||||
}
|
||||
|
||||
int replay_recorder_base::get_pos() const
|
||||
{
|
||||
return pos_;
|
||||
}
|
||||
|
||||
int replay_recorder_base::size() const
|
||||
{
|
||||
return commands_.size();
|
||||
}
|
||||
|
||||
config& replay_recorder_base::get_command_at(int pos)
|
||||
{
|
||||
assert(pos < size());
|
||||
return commands_[pos];
|
||||
}
|
||||
|
||||
config& replay_recorder_base::add_child()
|
||||
{
|
||||
assert(pos_ <= size());
|
||||
commands_.insert(commands_.begin() + pos_, new config());
|
||||
++pos_;
|
||||
return commands_[pos_ - 1];
|
||||
}
|
||||
void replay_recorder_base::set_pos(int pos)
|
||||
{
|
||||
assert(pos <= size());
|
||||
pos_ = pos;
|
||||
}
|
||||
void replay_recorder_base::set_to_end()
|
||||
{
|
||||
pos_ = size();
|
||||
}
|
||||
config& replay_recorder_base::get_upload_log()
|
||||
{
|
||||
return upload_log_;
|
||||
}
|
||||
|
||||
void replay_recorder_base::remove_command(int index)
|
||||
{
|
||||
assert(index < size());
|
||||
commands_.erase(commands_.begin() + index);
|
||||
if(index < pos_)
|
||||
{
|
||||
--pos_;
|
||||
}
|
||||
}
|
||||
|
||||
config& replay_recorder_base::insert_command(int index)
|
||||
{
|
||||
assert(index <= size());
|
||||
if(index < pos_)
|
||||
{
|
||||
++pos_;
|
||||
}
|
||||
return *commands_.insert(commands_.begin() + index, new config());
|
||||
}
|
||||
|
||||
|
||||
void replay_recorder_base::append_config(const config& data)
|
||||
{
|
||||
if(const config& upload_log = data.child("upload_log"))
|
||||
{
|
||||
upload_log_ = upload_log;
|
||||
}
|
||||
BOOST_FOREACH(const config& command, data.child_range("command"))
|
||||
{
|
||||
commands_.push_back(new config(command));
|
||||
}
|
||||
}
|
||||
|
||||
void replay_recorder_base::write(config_writer& out) const
|
||||
{
|
||||
out.write_child("upload_log", upload_log_);
|
||||
for(int i = 0; i < pos_; ++i)
|
||||
{
|
||||
out.write_child("command", commands_[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void replay_recorder_base::write(config& out) const
|
||||
{
|
||||
out.add_child("upload_log", upload_log_);
|
||||
for(int i = 0; i < pos_; ++i)
|
||||
{
|
||||
out.add_child("command", commands_[i]);
|
||||
}
|
||||
}
|
39
src/replay_recorder_base.hpp
Normal file
39
src/replay_recorder_base.hpp
Normal file
|
@ -0,0 +1,39 @@
|
|||
#pragma once
|
||||
#include <cassert>
|
||||
#include <boost/ptr_container/ptr_vector.hpp>
|
||||
|
||||
class config_writer;
|
||||
class replay_recorder_base
|
||||
{
|
||||
public:
|
||||
replay_recorder_base();
|
||||
~replay_recorder_base();
|
||||
|
||||
int get_pos() const;
|
||||
|
||||
int size() const;
|
||||
|
||||
config& get_command_at(int pos);
|
||||
|
||||
config& add_child();
|
||||
|
||||
config& get_upload_log();
|
||||
|
||||
void remove_command(int index);
|
||||
|
||||
config& insert_command(int index);
|
||||
|
||||
void set_to_end();
|
||||
|
||||
void set_pos(int pos);
|
||||
|
||||
void append_config(const config& data);
|
||||
|
||||
void write(config_writer& out) const;
|
||||
|
||||
void write(config& out) const;
|
||||
protected:
|
||||
config upload_log_;
|
||||
boost::ptr_vector<config> commands_;
|
||||
int pos_;
|
||||
};
|
|
@ -27,6 +27,7 @@ namespace resources
|
|||
game_display *screen = NULL;
|
||||
soundsource::manager *soundsources = NULL;
|
||||
std::vector<team> *teams = NULL;
|
||||
replay *recorder = NULL;
|
||||
::tod_manager *tod_manager = NULL;
|
||||
fake_unit_manager *fake_units = NULL;
|
||||
pathfind::manager *tunnels = NULL;
|
||||
|
|
|
@ -33,6 +33,7 @@ class unit_map;
|
|||
class persist_manager;
|
||||
class game_classification;
|
||||
struct mp_game_settings;
|
||||
class replay;
|
||||
namespace actions { class undo_list; }
|
||||
|
||||
namespace game_events { class manager; }
|
||||
|
@ -59,6 +60,7 @@ namespace resources
|
|||
extern const mp_game_settings *mp_settings;
|
||||
extern soundsource::manager *soundsources;
|
||||
extern std::vector<team> *teams;
|
||||
extern replay *recorder;
|
||||
extern fake_unit_manager *fake_units;
|
||||
extern ::tod_manager *tod_manager;
|
||||
extern pathfind::manager *tunnels;
|
||||
|
|
|
@ -56,27 +56,27 @@ static lg::log_domain log_engine("engine");
|
|||
#define DBG_NG LOG_STREAM(debug, log_engine)
|
||||
|
||||
saved_game::saved_game()
|
||||
: replay_data()
|
||||
, has_carryover_expanded_(false)
|
||||
: has_carryover_expanded_(false)
|
||||
, carryover_(carryover_info().to_config())
|
||||
, replay_start_()
|
||||
, classification_()
|
||||
, mp_settings_()
|
||||
, starting_pos_type_(STARTINGPOS_NONE)
|
||||
, starting_pos_()
|
||||
, replay_data_()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
saved_game::saved_game(const config& cfg)
|
||||
: replay_data()
|
||||
, has_carryover_expanded_(false)
|
||||
: has_carryover_expanded_(false)
|
||||
, carryover_()
|
||||
, replay_start_()
|
||||
, classification_(cfg)
|
||||
, mp_settings_(cfg)
|
||||
, starting_pos_type_(STARTINGPOS_NONE)
|
||||
, starting_pos_()
|
||||
, replay_data_()
|
||||
|
||||
{
|
||||
log_scope("read_game");
|
||||
|
@ -94,12 +94,11 @@ saved_game::saved_game(const config& cfg)
|
|||
|
||||
//Serversided replays can contain multiple [replay]
|
||||
replay_start_ = cfg.child_or_empty("replay_start");
|
||||
replay_data = config(); //cfg.child_or_empty("replay");
|
||||
BOOST_FOREACH(const config& replay, cfg.child_range("replay"))
|
||||
{
|
||||
replay_data.append_children(replay);
|
||||
replay_data_.append_config(replay);
|
||||
}
|
||||
|
||||
replay_data_.set_to_end();
|
||||
if(const config& snapshot = cfg.child("snapshot"))
|
||||
{
|
||||
this->starting_pos_type_ = STARTINGPOS_SNAPSHOT;
|
||||
|
@ -121,14 +120,14 @@ saved_game::saved_game(const config& cfg)
|
|||
}
|
||||
|
||||
saved_game::saved_game(const saved_game& state)
|
||||
: replay_data(state.replay_data)
|
||||
, has_carryover_expanded_(state.has_carryover_expanded_)
|
||||
: has_carryover_expanded_(state.has_carryover_expanded_)
|
||||
, carryover_(state.carryover_)
|
||||
, replay_start_(state.replay_start_)
|
||||
, classification_(state.classification_)
|
||||
, mp_settings_(state.mp_settings_)
|
||||
, starting_pos_type_(state.starting_pos_type_)
|
||||
, starting_pos_(state.starting_pos_)
|
||||
, replay_data_(state.replay_data_)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -156,10 +155,9 @@ void saved_game::write_config(config_writer& out) const
|
|||
{
|
||||
out.write_child("replay_start", replay_start_);
|
||||
}
|
||||
if(!this->replay_data.empty())
|
||||
{
|
||||
out.write_child("replay", replay_data);
|
||||
}
|
||||
out.open_child("replay");
|
||||
replay_data_.write(out);
|
||||
out.close_child("replay");
|
||||
write_carryover(out);
|
||||
}
|
||||
|
||||
|
@ -445,7 +443,7 @@ void saved_game::convert_to_start_save()
|
|||
sides.rng().rotate_random();
|
||||
carryover_ = sides.to_config();
|
||||
has_carryover_expanded_ = false;
|
||||
replay_data = config();
|
||||
replay_data_ = replay_recorder_base();
|
||||
replay_start_ = config();
|
||||
remove_snapshot();
|
||||
}
|
||||
|
@ -458,10 +456,8 @@ config saved_game::to_config() const
|
|||
{
|
||||
r.add_child("replay_start", replay_start_);
|
||||
}
|
||||
if(!this->replay_data.empty())
|
||||
{
|
||||
r.add_child("replay", replay_data);
|
||||
}
|
||||
replay_data_.write(r.add_child("replay"));
|
||||
|
||||
if(starting_pos_type_ == STARTINGPOS_SNAPSHOT)
|
||||
{
|
||||
r.add_child("snapshot", starting_pos_);
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
#include "config.hpp"
|
||||
#include "game_classification.hpp"
|
||||
#include "mp_game_settings.hpp"
|
||||
#include "replay_recorder_base.hpp"
|
||||
|
||||
class config_writer;
|
||||
|
||||
|
||||
|
@ -94,13 +96,9 @@ public:
|
|||
/* removes network_ai and network controller types*/
|
||||
void unify_controllers();
|
||||
|
||||
/**
|
||||
* If the game is saved mid-level, we have a series of replay steps
|
||||
* to take the game up to the position it was saved at.
|
||||
*/
|
||||
config replay_data;
|
||||
|
||||
void set_default_save_id();
|
||||
replay_recorder_base& get_replay() { return replay_data_; }
|
||||
const replay_recorder_base& get_replay() const { return replay_data_; }
|
||||
private:
|
||||
|
||||
bool has_carryover_expanded_;
|
||||
|
@ -122,6 +120,8 @@ private:
|
|||
This can eigher be a [scenario] for a fresh game or a [snapshot] if this is a reloaded game
|
||||
*/
|
||||
config starting_pos_;
|
||||
|
||||
replay_recorder_base replay_data_;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -481,7 +481,6 @@ void savegame::set_filename(std::string filename)
|
|||
|
||||
void savegame::before_save()
|
||||
{
|
||||
gamestate_.replay_data = recorder.get_replay_data();
|
||||
}
|
||||
|
||||
bool savegame::save_game(CVideo* video, const std::string& filename)
|
||||
|
@ -609,7 +608,10 @@ void replay_savegame::write_game(config_writer &out) {
|
|||
|
||||
gamestate().write_carryover(out);
|
||||
out.write_child("replay_start", gamestate().replay_start());
|
||||
out.write_child("replay", gamestate().replay_data);
|
||||
|
||||
out.open_child("replay");
|
||||
gamestate().get_replay().write(out);
|
||||
out.close_child("replay");
|
||||
|
||||
}
|
||||
|
||||
|
@ -693,7 +695,9 @@ void ingame_savegame::write_game(config_writer &out) {
|
|||
gamestate().write_carryover(out);
|
||||
out.write_child("snapshot",gamestate().get_starting_pos());
|
||||
out.write_child("replay_start", gamestate().replay_start());
|
||||
out.write_child("replay", gamestate().replay_data);
|
||||
out.open_child("replay");
|
||||
gamestate().get_replay().write(out);
|
||||
out.close_child("replay");
|
||||
}
|
||||
|
||||
//changes done during 1.11.0-dev
|
||||
|
|
|
@ -60,7 +60,7 @@ bool synced_context::run(const std::string& commandname, const config& data, boo
|
|||
|
||||
assert(use_undo || (!resources::undo_stack->can_redo() && !resources::undo_stack->can_undo()));
|
||||
/*
|
||||
use this after recorder.add_synced_command
|
||||
use this after resources::recorder->add_synced_command
|
||||
because set_scontext_synced sets the checkup to the last added command
|
||||
*/
|
||||
set_scontext_synced sync;
|
||||
|
@ -88,12 +88,12 @@ bool synced_context::run(const std::string& commandname, const config& data, boo
|
|||
|
||||
bool synced_context::run_and_store(const std::string& commandname, const config& data, bool use_undo, bool show, synced_command::error_handler_function error_handler)
|
||||
{
|
||||
assert(recorder.at_end());
|
||||
recorder.add_synced_command(commandname, data);
|
||||
assert(resources::recorder->at_end());
|
||||
resources::recorder->add_synced_command(commandname, data);
|
||||
bool success = run(commandname, data, use_undo, show, error_handler);
|
||||
if(!success)
|
||||
{
|
||||
recorder.undo();
|
||||
resources::recorder->undo();
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
@ -296,7 +296,7 @@ config synced_context::ask_server_for_seed()
|
|||
while(true) {
|
||||
|
||||
do_replay_handle();
|
||||
bool is_replay_end = get_replay_source().at_end();
|
||||
bool is_replay_end = resources::recorder->at_end();
|
||||
|
||||
if (is_replay_end && !is_mp_game)
|
||||
{
|
||||
|
@ -305,7 +305,7 @@ config synced_context::ask_server_for_seed()
|
|||
DBG_REPLAY << "MP synchronization: local server choice\n";
|
||||
config cfg = config_of("new_seed", seed_rng::next_seed_str());
|
||||
//-1 for "server" todo: change that.
|
||||
recorder.user_input(name, cfg, -1);
|
||||
resources::recorder->user_input(name, cfg, -1);
|
||||
return cfg;
|
||||
|
||||
}
|
||||
|
@ -335,18 +335,18 @@ config synced_context::ask_server_for_seed()
|
|||
be extracted from the replay. */
|
||||
DBG_REPLAY << "MP synchronization: replay server choice\n";
|
||||
do_replay_handle();
|
||||
const config *action = get_replay_source().get_next_action();
|
||||
const config *action = resources::recorder->get_next_action();
|
||||
if (!action)
|
||||
{
|
||||
replay::process_error("[" + name + "] expected but none found\n");
|
||||
get_replay_source().revert_action();
|
||||
resources::recorder->revert_action();
|
||||
return config_of("new_seed", seed_rng::next_seed_str());
|
||||
}
|
||||
if (!action->has_child(name))
|
||||
{
|
||||
replay::process_error("[" + name + "] expected but none found, found instead:\n " + action->debug() + "\n");
|
||||
|
||||
get_replay_source().revert_action();
|
||||
resources::recorder->revert_action();
|
||||
return config_of("new_seed", seed_rng::next_seed_str());
|
||||
}
|
||||
if((*action)["from_side"].str() != "server" || (*action)["side_invalid"].to_bool(false) )
|
||||
|
@ -401,7 +401,7 @@ checkup* set_scontext_synced::generate_checkup(const std::string& tagname)
|
|||
}
|
||||
else
|
||||
{
|
||||
return new synced_checkup(recorder.get_last_real_command().child_or_add(tagname));
|
||||
return new synced_checkup(resources::recorder->get_last_real_command().child_or_add(tagname));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -707,8 +707,6 @@ static int do_gameloop(const std::vector<std::string>& args)
|
|||
return 0;
|
||||
}
|
||||
|
||||
recorder.clear();
|
||||
|
||||
//Start directly a campaign
|
||||
if(game->goto_campaign() == false){
|
||||
if (game->jump_to_campaign_id().empty())
|
||||
|
|
Loading…
Add table
Reference in a new issue