restore last unit_id when undoing/redoing
otherwise the unit ids would be come out of sync when undoing,
This commit is contained in:
parent
0ce0e040f9
commit
7dc3969eec
4 changed files with 78 additions and 10 deletions
|
@ -37,6 +37,7 @@
|
|||
#include "../unit.hpp" // for unit
|
||||
#include "../unit_animation_component.hpp"
|
||||
#include "../unit_display.hpp" // for move_unit
|
||||
#include "../unit_id.hpp"
|
||||
#include "../unit_map.hpp" // for unit_map, etc
|
||||
#include "../unit_ptr.hpp" // for unit_const_ptr, unit_ptr
|
||||
#include "../unit_types.hpp" // for unit_type, unit_type_data, etc
|
||||
|
@ -82,7 +83,9 @@ struct undo_list::dismiss_action : undo_list::undo_action {
|
|||
|
||||
explicit dismiss_action(const unit_const_ptr dismissed) : undo_action(),
|
||||
dismissed_unit(new unit(*dismissed))
|
||||
{}
|
||||
{
|
||||
this->unit_id_diff = synced_context::get_unit_id_diff();
|
||||
}
|
||||
explicit dismiss_action(const config & unit_cfg) : undo_action(),
|
||||
dismissed_unit(new unit(unit_cfg))
|
||||
{}
|
||||
|
@ -117,7 +120,9 @@ struct undo_list::move_action : undo_list::undo_action {
|
|||
countdown_time_bonus(timebonus),
|
||||
starting_dir(dir == map_location::NDIRECTIONS ? moved->facing() : dir),
|
||||
goto_hex(moved->get_goto())
|
||||
{}
|
||||
{
|
||||
this->unit_id_diff = synced_context::get_unit_id_diff();
|
||||
}
|
||||
move_action(const config & unit_cfg, const config & route_cfg,
|
||||
int sm, int timebonus, int orig, const map_location::DIRECTION dir) :
|
||||
undo_action(unit_cfg),
|
||||
|
@ -153,7 +158,9 @@ struct undo_list::recall_action : undo_list::undo_action {
|
|||
undo_action(recalled, loc),
|
||||
id(recalled->id()),
|
||||
recall_from(from)
|
||||
{}
|
||||
{
|
||||
this->unit_id_diff = synced_context::get_unit_id_diff();
|
||||
}
|
||||
recall_action(const config & unit_cfg, const map_location & loc,
|
||||
const map_location & from) :
|
||||
undo_action(unit_cfg, loc),
|
||||
|
@ -183,7 +190,9 @@ struct undo_list::recruit_action : undo_list::undo_action {
|
|||
undo_action(recruited, loc),
|
||||
u_type(recruited->type()),
|
||||
recruit_from(from)
|
||||
{}
|
||||
{
|
||||
this->unit_id_diff = synced_context::get_unit_id_diff();
|
||||
}
|
||||
recruit_action(const config & unit_cfg, const unit_type & type,
|
||||
const map_location& loc, const map_location& from) :
|
||||
undo_action(unit_cfg, loc),
|
||||
|
@ -211,6 +220,12 @@ struct undo_list::auto_shroud_action : undo_list::undo_action {
|
|||
undo_action(),
|
||||
active(turned_on)
|
||||
{}
|
||||
explicit auto_shroud_action(bool turned_on, int unit_id_diff) :
|
||||
undo_action(),
|
||||
active(turned_on)
|
||||
{
|
||||
this->unit_id_diff = unit_id_diff;
|
||||
}
|
||||
virtual ~auto_shroud_action();
|
||||
|
||||
/// Writes this into the provided config.
|
||||
|
@ -228,6 +243,10 @@ struct undo_list::update_shroud_action : undo_list::undo_action {
|
|||
// No additional data.
|
||||
|
||||
update_shroud_action() : undo_action() {}
|
||||
update_shroud_action(int unit_id_diff) : undo_action()
|
||||
{
|
||||
this->unit_id_diff = unit_id_diff;
|
||||
}
|
||||
virtual ~update_shroud_action();
|
||||
|
||||
/// Writes this into the provided config.
|
||||
|
@ -299,6 +318,7 @@ undo_list::undo_action::create(const config & cfg)
|
|||
return NULL;
|
||||
}
|
||||
res->replay_data = cfg.child_or_empty("replay_data");
|
||||
res->unit_id_diff = cfg["unit_id_diff"];
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -309,6 +329,7 @@ undo_list::undo_action::create(const config & cfg)
|
|||
void undo_list::dismiss_action::write(config & cfg) const
|
||||
{
|
||||
cfg.add_child("replay_data", replay_data);
|
||||
cfg["unit_id_diff"] = unit_id_diff;
|
||||
cfg["type"] = "dismiss";
|
||||
dismissed_unit->write(cfg.add_child("unit"));
|
||||
}
|
||||
|
@ -319,6 +340,7 @@ void undo_list::dismiss_action::write(config & cfg) const
|
|||
void undo_list::recall_action::write(config & cfg) const
|
||||
{
|
||||
cfg.add_child("replay_data", replay_data);
|
||||
cfg["unit_id_diff"] = unit_id_diff;
|
||||
cfg["type"] = "recall";
|
||||
route.front().write(cfg);
|
||||
recall_from.write(cfg.add_child("leader"));
|
||||
|
@ -334,6 +356,7 @@ void undo_list::recall_action::write(config & cfg) const
|
|||
void undo_list::recruit_action::write(config & cfg) const
|
||||
{
|
||||
cfg.add_child("replay_data", replay_data);
|
||||
cfg["unit_id_diff"] = unit_id_diff;
|
||||
cfg["type"] = "recruit";
|
||||
route.front().write(cfg);
|
||||
recruit_from.write(cfg.add_child("leader"));
|
||||
|
@ -349,6 +372,7 @@ void undo_list::recruit_action::write(config & cfg) const
|
|||
void undo_list::move_action::write(config & cfg) const
|
||||
{
|
||||
cfg.add_child("replay_data", replay_data);
|
||||
cfg["unit_id_diff"] = unit_id_diff;
|
||||
cfg["type"] = "move";
|
||||
cfg["starting_direction"] = map_location::write_direction(starting_dir);
|
||||
cfg["starting_moves"] = starting_moves;
|
||||
|
@ -368,6 +392,7 @@ void undo_list::move_action::write(config & cfg) const
|
|||
void undo_list::auto_shroud_action::write(config & cfg) const
|
||||
{
|
||||
cfg.add_child("replay_data", replay_data);
|
||||
cfg["unit_id_diff"] = unit_id_diff;
|
||||
cfg["type"] = "auto_shroud";
|
||||
cfg["active"] = active;
|
||||
}
|
||||
|
@ -378,6 +403,7 @@ void undo_list::auto_shroud_action::write(config & cfg) const
|
|||
void undo_list::update_shroud_action::write(config & cfg) const
|
||||
{
|
||||
cfg.add_child("replay_data", replay_data);
|
||||
cfg["unit_id_diff"] = unit_id_diff;
|
||||
cfg["type"] = "update_shroud";
|
||||
}
|
||||
|
||||
|
@ -412,7 +438,7 @@ void undo_list::add_auto_shroud(bool turned_on)
|
|||
/// @todo: Consecutive shroud actions can be collapsed into one.
|
||||
|
||||
// Do not call add(), as this should not clear the redo stack.
|
||||
undos_.push_back(new auto_shroud_action(turned_on));
|
||||
undos_.push_back(new auto_shroud_action(turned_on, synced_context::get_unit_id_diff()));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -463,7 +489,7 @@ void undo_list::add_update_shroud()
|
|||
/// @todo: Consecutive shroud actions can be collapsed into one.
|
||||
|
||||
// Do not call add(), as this should not clear the redo stack.
|
||||
undos_.push_back(new update_shroud_action());
|
||||
undos_.push_back(new update_shroud_action(synced_context::get_unit_id_diff()));
|
||||
}
|
||||
|
||||
|
||||
|
@ -619,9 +645,14 @@ void undo_list::undo()
|
|||
// Get the action to undo. (This will be placed on the redo stack, but
|
||||
// only if the undo is successful.)
|
||||
action_list::auto_type action = undos_.pop_back();
|
||||
|
||||
if ( !action->undo(side_, *this) )
|
||||
int last_unit_id = n_unit::id_manager::instance().get_save_id();
|
||||
if ( !action->undo(side_, *this) ) {
|
||||
return;
|
||||
}
|
||||
if(last_unit_id - action->unit_id_diff < 0) {
|
||||
ERR_NG << "Next unit id is below 0 after undoing" << std::endl;
|
||||
}
|
||||
n_unit::id_manager::instance().set_save_id(last_unit_id - action->unit_id_diff);
|
||||
|
||||
// Bookkeeping.
|
||||
recorder.undo_cut(action->get_replay_data());
|
||||
|
@ -830,9 +861,14 @@ void undo_list::redo()
|
|||
// Get the action to redo. (This will be placed on the undo stack, but
|
||||
// only if the redo is successful.)
|
||||
action_list::auto_type action = redos_.pop_back();
|
||||
|
||||
if ( !action->redo(side_) )
|
||||
int last_unit_id = n_unit::id_manager::instance().get_save_id();
|
||||
if ( !action->redo(side_) ) {
|
||||
return;
|
||||
}
|
||||
if(last_unit_id + action->unit_id_diff < n_unit::id_manager::instance().get_save_id()) {
|
||||
ERR_NG << "Too much units were generated during redoing." << std::endl;
|
||||
}
|
||||
n_unit::id_manager::instance().set_save_id(last_unit_id + action->unit_id_diff);
|
||||
|
||||
// Bookkeeping.
|
||||
undos_.push_back(action.release());
|
||||
|
|
|
@ -41,6 +41,8 @@ class undo_list : boost::noncopyable {
|
|||
undo_action(const unit_const_ptr u,
|
||||
const std::vector<map_location>::const_iterator & begin,
|
||||
const std::vector<map_location>::const_iterator & end) :
|
||||
replay_data(),
|
||||
unit_id_diff(),
|
||||
route(begin, end),
|
||||
view_info(new clearer_info(*u))
|
||||
{
|
||||
|
@ -48,24 +50,32 @@ class undo_list : boost::noncopyable {
|
|||
/// Constructor for recruit and recall actions.
|
||||
/// These types of actions are guaranteed to have a non-empty route.
|
||||
undo_action(const unit_const_ptr u, const map_location& loc) :
|
||||
replay_data(),
|
||||
unit_id_diff(),
|
||||
route(1, loc),
|
||||
view_info(new clearer_info(*u))
|
||||
{}
|
||||
/// Constructor from a config storing the view info.
|
||||
/// Does not set @a route.
|
||||
explicit undo_action(const config & cfg) :
|
||||
replay_data(),
|
||||
unit_id_diff(),
|
||||
route(),
|
||||
view_info(new clearer_info(cfg))
|
||||
{}
|
||||
/// Constructor from a config storing the view info and a location.
|
||||
/// Guarantees a non-empty route.
|
||||
explicit undo_action(const config & cfg, const map_location & loc) :
|
||||
replay_data(),
|
||||
unit_id_diff(),
|
||||
route(1, loc),
|
||||
view_info(new clearer_info(cfg))
|
||||
{}
|
||||
/// Default constructor.
|
||||
/// This is the only way to get NULL view_info.
|
||||
undo_action() :
|
||||
replay_data(),
|
||||
unit_id_diff(),
|
||||
route(),
|
||||
view_info(NULL)
|
||||
{}
|
||||
|
@ -94,6 +104,7 @@ class undo_list : boost::noncopyable {
|
|||
/// but even undoable commands can have "dependent" (= user_input) commands, which we save here.
|
||||
config replay_data;
|
||||
|
||||
int unit_id_diff;
|
||||
/// 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.
|
||||
|
|
|
@ -51,6 +51,7 @@ static lg::log_domain log_replay("replay");
|
|||
|
||||
|
||||
synced_context::synced_state synced_context::state_ = synced_context::UNSYNCED;
|
||||
int synced_context::last_unit_id_ = 0;
|
||||
bool synced_context::is_simultaneously_ = false;
|
||||
|
||||
bool synced_context::run_in_synced_context(const std::string& commandname, const config& data, bool use_undo, bool show, bool store_in_replay, synced_command::error_handler_function error_handler)
|
||||
|
@ -187,6 +188,19 @@ bool synced_context::can_undo()
|
|||
//if we called the rng or if we sended data of this action over the network already, undoing is impossible.
|
||||
return (!is_simultaneously_) && (random_new::generator->get_random_calls() == 0);
|
||||
}
|
||||
|
||||
void synced_context::set_last_unit_id(int id)
|
||||
{
|
||||
last_unit_id_ = id;
|
||||
}
|
||||
|
||||
int synced_context::get_unit_id_diff()
|
||||
{
|
||||
//this method only works in a synced context.
|
||||
assert(get_synced_state() == SYNCED);
|
||||
return n_unit::id_manager::instance().get_save_id() - last_unit_id_;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
class lua_network_error : public network::error , public tlua_jailbreak_exception
|
||||
|
@ -374,6 +388,7 @@ void set_scontext_synced::init()
|
|||
synced_context::set_synced_state(synced_context::SYNCED);
|
||||
synced_context::reset_is_simultaneously();
|
||||
|
||||
synced_context::set_last_unit_id(n_unit::id_manager::instance().get_save_id());
|
||||
old_checkup_ = checkup_instance;
|
||||
checkup_instance = &*new_checkup_;
|
||||
old_rng_ = random_new::generator;
|
||||
|
|
|
@ -112,6 +112,8 @@ public:
|
|||
@return whether there were recently no methods called that prevent undoing.
|
||||
*/
|
||||
static bool can_undo();
|
||||
static void set_last_unit_id(int id);
|
||||
static int get_unit_id_diff();
|
||||
private:
|
||||
/*
|
||||
generates a random seed, if we are in a mp game, ask the server, otherwise generate the seed ourselves.
|
||||
|
@ -128,6 +130,10 @@ private:
|
|||
false = we are on a local turn and haven't sended anything yet.
|
||||
*/
|
||||
static bool is_simultaneously_;
|
||||
/**
|
||||
Used to restore the unit id manager when undoing.
|
||||
*/
|
||||
static int last_unit_id_;
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
Loading…
Add table
Reference in a new issue