Skip to content

Commit

Permalink
use synced_context in undo and rest
Browse files Browse the repository at this point in the history
in undos we have to do it differently in different actions becasue in moves we just show the move (ro save performance i guess) but in other actions (recall/recruit) we also fire the events again.

"Rest" means: lua_ai, disband, fire_event (right click menus), update_shroud manualy.

this commit is part of pr 121.
  • Loading branch information
gfgtdf committed Apr 2, 2014
1 parent 2b56c85 commit 59a78ca
Show file tree
Hide file tree
Showing 8 changed files with 110 additions and 92 deletions.
30 changes: 18 additions & 12 deletions src/actions/undo.cpp
Expand Up @@ -26,14 +26,17 @@
#include "../log.hpp"
#include "../play_controller.hpp"
#include "../replay.hpp"
#include "../replay_helper.hpp"
#include "../resources.hpp"
#include "../team.hpp"
#include "../unit.hpp"
#include "../unit_display.hpp"
#include "../unit_map.hpp"
#include "../whiteboard/manager.hpp"
#include "../synced_context.hpp"

#include <boost/foreach.hpp>
#include <cassert>

static lg::log_domain log_engine("engine");
#define ERR_NG LOG_STREAM(err, log_engine)
Expand Down Expand Up @@ -464,12 +467,8 @@ void undo_list::clear()
* This may fire events and change the game state.
* @param[in] is_replay Set to true when this is called during a replay.
*/
void undo_list::commit_vision(bool is_replay)
void undo_list::commit_vision(bool /*is_replay*/)
{
if ( !is_replay )
// Record this.
recorder.update_shroud();

// Update fog/shroud.
size_t erase_to = apply_shroud_changes();

Expand Down Expand Up @@ -573,7 +572,7 @@ void undo_list::undo()
return;

// Bookkeeping.
recorder.undo();
recorder.undo_cut(action->get_replay_data());
redos_.push_back(action.release());
resources::whiteboard->on_gamestate_change();

Expand Down Expand Up @@ -735,7 +734,7 @@ bool undo_list::auto_shroud_action::undo(int /*side*/, undo_list & undos)
recorder.undo();
undos.undo();
// Now keep the auto-shroud toggle at the top of the undo stack.
recorder.add_auto_shroud(active);
recorder.add_synced_command("auto_shroud", replay_helper::get_auto_shroud(active));
undos.add_auto_shroud(active);
// Shroud actions never get moved to the redo stack, so claim an error.
return false;
Expand All @@ -752,7 +751,8 @@ bool undo_list::update_shroud_action::undo(int /*side*/, undo_list & undos)
recorder.undo();
undos.undo();
// Now keep the shroud update at the top of the undo stack.
recorder.update_shroud();
recorder.add_synced_command("update_shroud", replay_helper::get_update_shroud());

undos.add_update_shroud();
// Shroud actions never get moved to the redo stack, so claim an error.
return false;
Expand Down Expand Up @@ -802,8 +802,8 @@ bool undo_list::dismiss_action::redo(int side)
<< ", which has no recall list!\n";
return false;
}

recorder.add_disband(dismissed_unit.id());
recorder.redo(replay_data);
replay_data.clear();
std::vector<unit>::iterator unit_it =
find_if_matches_id(current_team.recall_list(), dismissed_unit.id());
current_team.recall_list().erase(unit_it);
Expand Down Expand Up @@ -838,6 +838,9 @@ bool undo_list::recall_action::redo(int side)

const std::string &msg = find_recall_location(side, loc, from, *unit_it);
if ( msg.empty() ) {
recorder.redo(replay_data);
replay_data.clear();
set_scontext_synced sco;
recall_unit(id, current_team, loc, from, true, false);

// Quick error check. (Abuse of [allow_undo]?)
Expand Down Expand Up @@ -882,7 +885,9 @@ 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);
replay_data.clear();
set_scontext_synced sco;
recruit_unit(u_type, side, loc, from, true, false);

// Quick error check. (Abuse of [allow_undo]?)
Expand Down Expand Up @@ -944,7 +949,8 @@ bool undo_list::move_action::redo(int side)
}

gui.invalidate_unit_after_move(route.front(), route.back());
recorder.add_movement(route);
recorder.redo(replay_data);
replay_data.clear();
return true;
}

Expand Down
7 changes: 7 additions & 0 deletions src/actions/undo.hpp
Expand Up @@ -86,7 +86,14 @@ class undo_list : boost::noncopyable {
/// @return true on success; false on an error.
virtual bool redo(int side) = 0;

config& get_replay_data() { return replay_data; }

// Data:
/// the replay data to do this action, this is only !empty() when this action is on the redo stack
/// we need this because we dont recalculate the redos like they would be in real game,
/// but even undoable comands can have "dependent" (= user_input) commands, which we save here.
config replay_data;

/// The hexes occupied by the affected unit during this action.
std::vector<map_location> route;
/// A record of the affected unit's ability to see.
Expand Down
6 changes: 3 additions & 3 deletions src/ai/actions.cpp
Expand Up @@ -897,10 +897,10 @@ void synced_command_result::do_execute()
s << "local x1 = " << location_.x << " local y1 = " << location_.y << " ";
}
s << lua_code_;

resources::lua_kernel->run(s.str().c_str());

synced_context::run_in_synced_context("lua_ai", replay_helper::get_lua_ai(s.str()));

try {
recorder.add_lua_ai(s.str());
set_gamestate_changed();
manager::raise_gamestate_changed();
} catch (...) {
Expand Down
5 changes: 3 additions & 2 deletions src/dialogs.cpp
Expand Up @@ -136,8 +136,9 @@ gui::dialog_button_action::RESULT delete_recall_unit::button_pressed(int menu_se
assert(dismissed_unit != recall_list.end());

// Record the dismissal, then delete the unit.
recorder.add_disband(dismissed_unit->id());
recall_list.erase(dismissed_unit);
synced_context::run_in_synced_context("disband", replay_helper::get_disband(dismissed_unit->id()));
//recorder.add_disband(dismissed_unit->id());
//recall_list.erase(dismissed_unit);

return gui::DELETE_ITEM;
} else {
Expand Down
19 changes: 11 additions & 8 deletions src/game_events/menu_item.cpp
Expand Up @@ -31,7 +31,9 @@
#include "../play_controller.hpp"
#include "../preferences.hpp"
#include "../replay.hpp"
#include "../replay_helper.hpp"
#include "../resources.hpp"
#include "../synced_context.hpp"
#include "../terrain_filter.hpp"

static lg::log_domain log_engine("engine");
Expand Down Expand Up @@ -196,15 +198,16 @@ void wml_menu_item::fire_event(const map_location & event_hex) const
// No new player-issued commands allowed while this is firing.
const events::command_disabler disable_commands;

// Should we record the preceding select event?
// instead of adding a second "select" event like it sdone before, we just fire the select event again, and this time in a synced context.
// note that there coudnt be and user choiced durign teh last "select" event because it didn't run in a synced context.
if ( needs_select_ && last_select.valid() )
recorder.add_event("select", last_select);

// Record and fire this item's event.
recorder.add_event(event_name_, event_hex);
if ( fire(event_name_, event_hex) )
// The event has mutated the gamestate
resources::undo_stack->clear();
{
synced_context::run_in_synced_context("fire_event", replay_helper::get_event(event_name_, event_hex, &last_select));
}
else
{
synced_context::run_in_synced_context("fire_event", replay_helper::get_event(event_name_, event_hex, NULL));
}
}

/**
Expand Down
5 changes: 2 additions & 3 deletions src/menu_events.cpp
Expand Up @@ -777,14 +777,13 @@ void menu_handler::toggle_shroud_updates(int side_num)
if (!auto_shroud) update_shroud_now(side_num);

// Toggle the setting and record this.
recorder.add_auto_shroud(!auto_shroud);
current_team.set_auto_shroud_updates(!auto_shroud);
synced_context::run_in_synced_context("auto_shroud", replay_helper::get_auto_shroud(!auto_shroud));
resources::undo_stack->add_auto_shroud(!auto_shroud);
}

void menu_handler::update_shroud_now(int /* side_num */)
{
resources::undo_stack->commit_vision();
synced_context::run_in_synced_context("update_shroud", replay_helper::get_update_shroud());
}


Expand Down
111 changes: 55 additions & 56 deletions src/replay.cpp
Expand Up @@ -236,22 +236,27 @@ void replay::add_unit_checksum(const map_location& loc,config* const cfg)
cc["value"] = get_checksum(*u);
}

void replay::add_start()
{
config* const cmd = add_command(true);
cmd->add_child("start");
}


void replay::add_disband(const std::string& unit_id)
void replay::init_side()
{
config* const cmd = add_command();
config init_side;
init_side["side_number"] = resources::controller->current_side();
cmd->add_child("init_side", init_side);
}

config val;

val["value"] = unit_id;

cmd->add_child("disband",val);
void replay::add_start()
{
config* const cmd = add_command(true);
/*
before, the "start" command was called from play_controller::init which is called from play_controller contructor which is called bepfre the contrucotr of replay_sender_
and thats was why the "start" command wanst't sended over network.
i wanto to add the stat event direct before the "prestart" is fired. which happends after playsingle_controller::replay_sender_ is initialised.
in order to allow ger_user_inut in prestart events.
*/
(*cmd)["sent"] = true;
cmd->add_child("start");
}

void replay::add_countdown_update(int value, int team)
Expand All @@ -270,24 +275,6 @@ void replay::add_synced_command(const std::string& name, const config& command)
}


/**
* Records that the player has toggled automatic shroud updates.
*/
void replay::add_auto_shroud(bool turned_on)
{
config* cmd = add_command(false);
config& child = cmd->add_child("auto_shroud");
child["active"] = turned_on;
}

/**
* Records that the player has manually updated fog/shroud.
*/
void replay::update_shroud()
{
config* cmd = add_command(false);
cmd->add_child("update_shroud");
}

void replay::add_seed(const char* child_name, int seed)
{
Expand Down Expand Up @@ -345,38 +332,13 @@ void replay::add_rename(const std::string& name, const map_location& loc)
cmd->add_child("rename", val);
}

void replay::init_side()
{
config* const cmd = add_command();
config init_side;
if(!lg::debug.dont_log("network")) init_side["side_number"] = resources::controller->current_side();
cmd->add_child("init_side", init_side);
}

void replay::end_turn()
{
config* const cmd = add_command();
cmd->add_child("end_turn");
}

void replay::add_event(const std::string& name, const map_location& loc)
{
config* const cmd = add_command();
config& ev = cmd->add_child("fire_event");
ev["raise"] = name;
if(loc.valid()) {
config& source = ev.add_child("source");
loc.write(source);
}
(*cmd)["undo"] = false;
}

void replay::add_lua_ai(const std::string& lua_code)
{
config* const cmd = add_command();
config& child = cmd->add_child("lua_ai");
child["code"] = lua_code;
}

void replay::add_log_data(const std::string &key, const std::string &var)
{
Expand Down Expand Up @@ -485,6 +447,16 @@ struct async_cmd
int num;
};

void replay::redo(const config& cfg)
{
BOOST_FOREACH(const config &cmd, cfg.child_range("command"))
{
/*config &cfg = */cfg_.add_child("command", cmd);
}
}



config& replay::get_last_real_command()
{
for (int cmd_num = pos_ - 1; cmd_num >= 0; --cmd_num)
Expand All @@ -502,8 +474,11 @@ config& replay::get_last_real_command()
throw "assert didnt work :o";
}

void replay::undo()

void replay::undo_cut(config& dst)
{
assert(dst.empty());

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
Expand All @@ -530,7 +505,25 @@ void replay::undo()
}

if (cmd < 0) return;
dst.add_child("command", cfg_.child("command", cmd));

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

/*
cfg_.remove_child("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)
{
--(*loc_it);
}
*/
//we remove dependent commands after the actual removed command that don't make sense if they stand alone especialy user choices and checksum data.
for(int cmd_2 = ncommands() - 1; cmd_2 > cmd; --cmd_2)
{
Expand Down Expand Up @@ -592,6 +585,12 @@ void replay::undo()
set_random(NULL);
}

void replay::undo()
{
config dummy;
undo_cut(dummy);
}

config &replay::command(int n)
{
return cfg_.child("command", n);
Expand Down

0 comments on commit 59a78ca

Please sign in to comment.