use synced_context::run for move actions
With this, finally all actions run though synced context::run, so that we not only have a central place that happens before/after synced actions, we also guarantee that there is no difference between the original and the replay codepath for all actions. This should also make upcoming changed to the undo code easier.
This commit is contained in:
parent
d0050dac8e
commit
3d589f8d0d
5 changed files with 147 additions and 110 deletions
|
@ -50,6 +50,7 @@
|
|||
#include <set>
|
||||
|
||||
static lg::log_domain log_engine("engine");
|
||||
#define ERR_NG LOG_STREAM(err, log_engine)
|
||||
#define DBG_NG LOG_STREAM(debug, log_engine)
|
||||
|
||||
|
||||
|
@ -98,8 +99,25 @@ const unit_map::const_iterator& move_unit_spectator::get_unit() const
|
|||
}
|
||||
|
||||
|
||||
move_unit_spectator::move_unit_spectator(const unit_map &units)
|
||||
: ambusher_(units.end()),failed_teleport_(units.end()),seen_enemies_(),seen_friends_(),unit_(units.end())
|
||||
move_unit_spectator::move_unit_spectator(const unit_map& units)
|
||||
: ambusher_(units.end())
|
||||
, failed_teleport_(units.end())
|
||||
, seen_enemies_()
|
||||
, seen_friends_()
|
||||
, unit_(units.end())
|
||||
, tiles_entered_(0)
|
||||
, interrupted_(false)
|
||||
{
|
||||
}
|
||||
|
||||
move_unit_spectator::move_unit_spectator()
|
||||
: ambusher_()
|
||||
, failed_teleport_()
|
||||
, seen_enemies_()
|
||||
, seen_friends_()
|
||||
, unit_()
|
||||
, tiles_entered_(0)
|
||||
, interrupted_(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -115,8 +133,14 @@ void move_unit_spectator::reset(const unit_map &units)
|
|||
seen_enemies_.clear();
|
||||
seen_friends_.clear();
|
||||
unit_ = units.end();
|
||||
tiles_entered_ = 0;
|
||||
interrupted_ = false;
|
||||
}
|
||||
|
||||
void move_unit_spectator::error(const std::string& message)
|
||||
{
|
||||
ERR_NG << message;
|
||||
}
|
||||
|
||||
void move_unit_spectator::set_ambusher(const unit_map::const_iterator &u)
|
||||
{
|
||||
|
@ -243,7 +267,10 @@ namespace { // Private helpers for move_unit()
|
|||
const route_iterator & current,
|
||||
const route_iterator & other);
|
||||
/** AI moves are supposed to not change the "goto" order. */
|
||||
bool is_ai_move() const { return spectator_ != nullptr; }
|
||||
bool is_ai_move() const
|
||||
{
|
||||
return spectator_ && spectator_->is_ai_move();
|
||||
}
|
||||
/** Checks how far it appears we can move this turn. */
|
||||
route_iterator plot_turn(const route_iterator & start,
|
||||
const route_iterator & stop);
|
||||
|
@ -1146,6 +1173,8 @@ namespace { // Private helpers for move_unit()
|
|||
// Record keeping.
|
||||
if (spectator_) {
|
||||
spectator_->set_unit(move_it_);
|
||||
spectator_->set_interrupted(interrupted());
|
||||
spectator_->set_tiles_entered(steps_travelled());
|
||||
}
|
||||
if ( undo_stack ) {
|
||||
const bool mover_valid = move_it_.valid();
|
||||
|
@ -1248,15 +1277,11 @@ namespace { // Private helpers for move_unit()
|
|||
}//end anonymous namespace
|
||||
|
||||
|
||||
static std::size_t move_unit_internal(
|
||||
bool show_move, bool* interrupted, unit_mover& mover)
|
||||
static void move_unit_internal(
|
||||
bool show_move, unit_mover& mover)
|
||||
{
|
||||
show_move = show_move && !resources::controller->is_skipping_actions();
|
||||
const events::command_disabler disable_commands;
|
||||
// Default return value.
|
||||
if (interrupted) {
|
||||
*interrupted = false;
|
||||
}
|
||||
|
||||
// Attempt moving.
|
||||
mover.try_actual_movement(show_move);
|
||||
|
@ -1282,48 +1307,6 @@ static std::size_t move_unit_internal(
|
|||
if (show_move) {
|
||||
mover.feedback();
|
||||
}
|
||||
|
||||
// Set return value.
|
||||
if (interrupted) {
|
||||
*interrupted = mover.interrupted();
|
||||
}
|
||||
|
||||
return mover.steps_travelled();
|
||||
}
|
||||
|
||||
void teleport_unit_and_record(const map_location& teleport_from,
|
||||
const map_location& teleport_to,
|
||||
bool show_move,
|
||||
move_unit_spectator* move_spectator)
|
||||
{
|
||||
const bool skip_ally_sighted = true;
|
||||
const bool continued_move = false;
|
||||
|
||||
const std::vector<map_location>& route{teleport_from, teleport_to};
|
||||
|
||||
unit_mover mover(route, move_spectator, continued_move, skip_ally_sighted);
|
||||
|
||||
if(synced_context::get_synced_state() != synced_context::SYNCED) {
|
||||
/*
|
||||
enter the synced mode and do the actual movement.
|
||||
*/
|
||||
resources::recorder->add_synced_command("debug_teleport",
|
||||
config{"teleport_from_x", teleport_from.wml_x(), "teleport_from_y", teleport_from.wml_y(), "teleport_to_x",
|
||||
teleport_to.wml_x(), "teleport_to_y", teleport_to.wml_y()});
|
||||
set_scontext_synced sync;
|
||||
mover.try_teleport(show_move);
|
||||
sync.do_final_checkup();
|
||||
} else {
|
||||
// we are already in synced mode and don't need to reenter it again.
|
||||
mover.try_teleport(show_move);
|
||||
}
|
||||
}
|
||||
|
||||
void teleport_unit_from_replay(const std::vector<map_location> &steps,
|
||||
bool continued_move, bool skip_ally_sighted, bool show_move)
|
||||
{
|
||||
unit_mover mover(steps, nullptr, continued_move, skip_ally_sighted);
|
||||
mover.try_teleport(show_move);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1336,27 +1319,94 @@ void teleport_unit_from_replay(const std::vector<map_location> &steps,
|
|||
* supplied path.)
|
||||
*
|
||||
* @param[in] steps The route to be traveled. The unit to be moved is at the beginning of this route.
|
||||
* @param undo_stack If supplied, then either this movement will be added to the stack or the stack will be cleared.
|
||||
* @param[in] continued_move If set to true, this is a continuation of an earlier move (movement is not interrupted should units be spotted).
|
||||
* @param[in] continued_move If set to true, this is a continuation of an earlier move (movement is not
|
||||
* interrupted should units be spotted).
|
||||
* @param[in] skip_ally_sighted If set to true, movement is not interrupted should allied units be spotted.
|
||||
* @param[in] show_move Controls whether or not the movement is animated for the player.
|
||||
* @param[out] interrupted If supplied, then this is set to true if information was uncovered that warrants interrupting a chain of actions (and set to false otherwise).
|
||||
* @param[out] move_spectator If supplied, this will be given the information uncovered by the move (and the unit's "goto" instruction will be preserved).
|
||||
* @param[out] move_spectator If supplied, this will be given the information uncovered by the move and about the
|
||||
* move
|
||||
*/
|
||||
void execute_move_unit(const std::vector<map_location>& steps,
|
||||
bool continued_move,
|
||||
bool skip_ally_sighted,
|
||||
bool show_move,
|
||||
move_unit_spectator* move_spectator)
|
||||
{
|
||||
// Evaluate this move.
|
||||
unit_mover mover(steps, move_spectator, continued_move, skip_ally_sighted);
|
||||
if(!mover.check_expected_movement()) {
|
||||
DBG_NG << "found expected empty move, aborting";
|
||||
return;
|
||||
}
|
||||
|
||||
move_unit_internal(show_move, mover);
|
||||
}
|
||||
|
||||
void teleport_unit_and_record(const map_location& teleport_from,
|
||||
const map_location& teleport_to,
|
||||
move_unit_spectator* /* move_spectator */)
|
||||
{
|
||||
synced_context::run_and_throw("debug_teleport",
|
||||
config{"teleport_from_x", teleport_from.wml_x(), "teleport_from_y", teleport_from.wml_y(), "teleport_to_x",
|
||||
teleport_to.wml_x(), "teleport_to_y", teleport_to.wml_y()});
|
||||
}
|
||||
|
||||
void teleport_unit_from_replay(const std::vector<map_location> &steps,
|
||||
bool continued_move, bool skip_ally_sighted, bool show_move)
|
||||
{
|
||||
unit_mover mover(steps, nullptr, continued_move, skip_ally_sighted);
|
||||
mover.try_teleport(show_move);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Wrapper around the other overload.
|
||||
*
|
||||
* @param[in] steps The route to be traveled. The unit to be moved is at the beginning of this route.
|
||||
* @param[in] continued_move If set to true, this is a continuation of an earlier move (movement is not
|
||||
* interrupted should units be spotted).
|
||||
* @param[out] interrupted If supplied, then this is set to true if information was uncovered that warrants
|
||||
* interrupting a chain of actions (and set to false otherwise).
|
||||
*
|
||||
* @returns The number of hexes entered. This can safely be used as an index
|
||||
* into @a steps to get the location where movement ended, provided
|
||||
* @a steps is not empty (the return value is guaranteed to be less
|
||||
* than steps.size() ).
|
||||
*/
|
||||
std::size_t move_unit_and_record(const std::vector<map_location> &steps,
|
||||
bool continued_move, bool show_move,
|
||||
bool* interrupted, move_unit_spectator* move_spectator)
|
||||
std::size_t move_unit_and_record(
|
||||
const std::vector<map_location>& steps, bool continued_move, bool* interrupted)
|
||||
{
|
||||
auto move_spectator = move_unit_spectator();
|
||||
move_unit_and_record(steps, continued_move, move_spectator);
|
||||
if(interrupted) {
|
||||
*interrupted = move_spectator.get_interrupted();
|
||||
}
|
||||
return move_spectator.get_tiles_entered();
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves a unit across the board.
|
||||
*
|
||||
* This function handles actual movement, checking terrain costs as well as
|
||||
* things that might interrupt movement (e.g. ambushes). If the full path
|
||||
* cannot be reached this turn, the remainder is stored as the unit's "goto"
|
||||
* instruction. (The unit itself is whatever unit is at the beginning of the
|
||||
* supplied path.)
|
||||
*
|
||||
* @param[in] steps The route to be traveled. The unit to be moved is at the beginning of this route.
|
||||
* @param[in] continued_move If set to true, this is a continuation of an earlier move (movement is not interrupted should units be spotted).
|
||||
* @param[out] move_spectator If supplied, this will be given the information uncovered by the move and about the move
|
||||
*/
|
||||
void move_unit_and_record(
|
||||
const std::vector<map_location>& steps, bool continued_move, move_unit_spectator& move_spectator)
|
||||
{
|
||||
|
||||
// Avoid some silliness.
|
||||
if ( steps.size() < 2 || (steps.size() == 2 && steps.front() == steps.back()) ) {
|
||||
DBG_NG << "Ignoring a unit trying to jump on its hex at " <<
|
||||
( steps.empty() ? map_location::null_location() : steps.front() ) << ".";
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
//if we have no fog activated then we always skip sighted
|
||||
if(resources::gameboard->units().find(steps.front()) != resources::gameboard->units().end())
|
||||
|
@ -1367,42 +1417,9 @@ std::size_t move_unit_and_record(const std::vector<map_location> &steps,
|
|||
}
|
||||
const bool skip_ally_sighted = !prefs::get().ally_sighted_interrupts();
|
||||
|
||||
// Evaluate this move.
|
||||
unit_mover mover(steps, move_spectator, continued_move, skip_ally_sighted);
|
||||
if ( !mover.check_expected_movement() )
|
||||
return 0;
|
||||
if(synced_context::get_synced_state() != synced_context::SYNCED)
|
||||
{
|
||||
/*
|
||||
enter the synced mode and do the actual movement.
|
||||
*/
|
||||
resources::recorder->add_synced_command("move",replay_helper::get_movement(steps, continued_move, skip_ally_sighted));
|
||||
set_scontext_synced sync;
|
||||
std::size_t r = move_unit_internal(show_move, interrupted, mover);
|
||||
resources::controller->check_victory();
|
||||
resources::controller->maybe_throw_return_to_play_side();
|
||||
sync.do_final_checkup();
|
||||
return r;
|
||||
}
|
||||
else
|
||||
{
|
||||
//we are already in synced mode and don't need to reenter it again.
|
||||
return move_unit_internal(show_move, interrupted, mover);
|
||||
}
|
||||
}
|
||||
synced_context::run_and_throw(
|
||||
"move", replay_helper::get_movement(steps, continued_move, skip_ally_sighted), move_spectator);
|
||||
|
||||
std::size_t move_unit_from_replay(const std::vector<map_location> &steps,
|
||||
bool continued_move, bool skip_ally_sighted, bool show_move)
|
||||
{
|
||||
// Evaluate this move.
|
||||
unit_mover mover(steps, nullptr, continued_move,skip_ally_sighted);
|
||||
if ( !mover.check_expected_movement() )
|
||||
{
|
||||
replay::process_error("found corrupt movement in replay.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return move_unit_internal(show_move, nullptr, mover);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ struct map_location;
|
|||
|
||||
#include "units/map.hpp"
|
||||
#include "game_events/fwd.hpp"
|
||||
#include "synced_commands.hpp"
|
||||
|
||||
#include <vector>
|
||||
|
||||
|
@ -32,8 +33,11 @@ namespace actions {
|
|||
class undo_list;
|
||||
|
||||
|
||||
class move_unit_spectator {
|
||||
class move_unit_spectator : public action_spectator {
|
||||
public:
|
||||
|
||||
/** ingerited from action_spectator */
|
||||
void error(const std::string& message) override;
|
||||
/** add a location of a seen friend */
|
||||
void add_seen_friend(const unit_map::const_iterator &u);
|
||||
|
||||
|
@ -63,7 +67,9 @@ public:
|
|||
|
||||
|
||||
/** constructor */
|
||||
move_unit_spectator(const unit_map &units);
|
||||
move_unit_spectator(const unit_map& units);
|
||||
|
||||
move_unit_spectator();
|
||||
|
||||
|
||||
/** destructor */
|
||||
|
@ -83,12 +89,25 @@ public:
|
|||
|
||||
/** set the iterator to moved unit*/
|
||||
void set_unit(const unit_map::const_iterator &u);
|
||||
|
||||
void set_ai_move(bool ai_move = true) { is_ai_move_ = ai_move; }
|
||||
bool is_ai_move() const { return is_ai_move_; }
|
||||
|
||||
void set_interrupted(bool interrupted) { interrupted_ = interrupted; }
|
||||
bool get_interrupted() const { return interrupted_; }
|
||||
|
||||
void set_tiles_entered(std::size_t tiles_entered) { tiles_entered_ = tiles_entered; }
|
||||
std::size_t get_tiles_entered() const { return tiles_entered_; }
|
||||
|
||||
private:
|
||||
unit_map::const_iterator ambusher_;
|
||||
unit_map::const_iterator failed_teleport_;
|
||||
std::vector<unit_map::const_iterator> seen_enemies_;
|
||||
std::vector<unit_map::const_iterator> seen_friends_;
|
||||
unit_map::const_iterator unit_;
|
||||
std::size_t tiles_entered_;
|
||||
bool interrupted_;
|
||||
bool is_ai_move_ = false;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -103,7 +122,6 @@ game_events::pump_result_t get_village(const map_location& loc, int side, bool *
|
|||
*/
|
||||
void teleport_unit_and_record(const map_location& teleport_from,
|
||||
const map_location& teleport_to,
|
||||
bool show_move = false,
|
||||
move_unit_spectator* move_spectator = nullptr);
|
||||
|
||||
/**
|
||||
|
@ -120,21 +138,24 @@ void teleport_unit_from_replay(
|
|||
* Moves a unit across the board.
|
||||
* And enters the synced context.
|
||||
*/
|
||||
std::size_t move_unit_and_record(
|
||||
void move_unit_and_record(
|
||||
const std::vector<map_location> &steps,
|
||||
bool continued_move,
|
||||
move_unit_spectator& move_spectator);
|
||||
|
||||
std::size_t move_unit_and_record(const std::vector<map_location>& steps,
|
||||
bool continued_move = false,
|
||||
bool show_move = true,
|
||||
bool* interrupted = nullptr,
|
||||
move_unit_spectator* move_spectator = nullptr);
|
||||
bool* interrupted = nullptr);
|
||||
|
||||
/**
|
||||
* Moves a unit across the board.
|
||||
* to be called from replay when we are already in the synced context.
|
||||
*/
|
||||
std::size_t move_unit_from_replay(
|
||||
void execute_move_unit(
|
||||
const std::vector<map_location> &steps,
|
||||
bool continued_move,
|
||||
bool skip_ally_sighted,
|
||||
bool show_move = true);
|
||||
bool show_move = true,
|
||||
move_unit_spectator* move_spectator);
|
||||
|
||||
}//namespace actions
|
||||
|
|
|
@ -463,16 +463,15 @@ void move_result::do_execute()
|
|||
|
||||
::actions::move_unit_spectator move_spectator(resources::gameboard->units());
|
||||
move_spectator.set_unit(resources::gameboard->units().find(from_));
|
||||
move_spectator.set_ai_move(true);
|
||||
|
||||
if (from_ != to_) {
|
||||
std::size_t num_steps = ::actions::move_unit_and_record(
|
||||
::actions::move_unit_and_record(
|
||||
/*std::vector<map_location> steps*/ route_->steps,
|
||||
/*bool continue_move*/ true,
|
||||
/*bool show_move*/ true,
|
||||
/*bool* interrupted*/ nullptr,
|
||||
/*::actions::move_unit_spectator* move_spectator*/ &move_spectator);
|
||||
/*::actions::move_unit_spectator* move_spectator*/ move_spectator);
|
||||
|
||||
if ( num_steps > 0 ) {
|
||||
if( move_spectator.get_tiles_entered() > 0) {
|
||||
set_gamestate_changed();
|
||||
} else if ( move_spectator.get_ambusher().valid() ) {
|
||||
// Unlikely, but some types of strange WML (or bad pathfinding)
|
||||
|
|
|
@ -1264,7 +1264,7 @@ std::size_t mouse_handler::move_unit_along_route(const std::vector<map_location>
|
|||
}
|
||||
|
||||
LOG_NG << "move unit along route from " << steps.front() << " to " << steps.back();
|
||||
std::size_t moves = actions::move_unit_and_record(steps, false, true, &interrupted);
|
||||
std::size_t moves = actions::move_unit_and_record(steps, false, &interrupted);
|
||||
|
||||
cursor::set(cursor::NORMAL);
|
||||
gui().invalidate_game_status();
|
||||
|
|
|
@ -312,7 +312,7 @@ SYNCED_COMMAND_HANDLER_FUNCTION(move, child, spectator)
|
|||
{
|
||||
show_move = show_move && !prefs::get().skip_ai_moves();
|
||||
}
|
||||
actions::move_unit_from_replay(steps, skip_sighted, skip_ally_sighted, show_move);
|
||||
actions::execute_move_unit(steps, skip_sighted, skip_ally_sighted, show_move, dynamic_cast<actions::move_unit_spectator*>(&spectator));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue