add oos debug mode and mp_debug_checkup class

The game sometimes does some checkup to test whether the calculated results in a replay match the ones calculated during the original game.
This data was stored in the replay inside the [command] for that action. The problem is that this doesn't work in networked mp because we often send the [command] before calculating the results.
I added an alternative mode that used get_user_choice to compare the results, this also works in networked mp but it causes a little more network traffic.
This commit is contained in:
gfgtdf 2015-01-07 23:33:52 +01:00
parent 5067ecf932
commit dbb75bdd47
6 changed files with 83 additions and 44 deletions

View file

@ -44,7 +44,8 @@ game_classification::game_classification():
end_text(),
end_text_duration(),
difficulty(DEFAULT_DIFFICULTY),
random_mode("")
random_mode(""),
oos_debug(false)
{}
game_classification::game_classification(const config& cfg):
@ -64,7 +65,8 @@ game_classification::game_classification(const config& cfg):
end_text(cfg["end_text"]),
end_text_duration(cfg["end_text_duration"]),
difficulty(cfg["difficulty"].empty() ? DEFAULT_DIFFICULTY : cfg["difficulty"].str()),
random_mode(cfg["random_mode"])
random_mode(cfg["random_mode"]),
oos_debug(cfg["oos_debug"].to_bool(false))
{}
game_classification::game_classification(const game_classification& gc):
@ -84,7 +86,8 @@ game_classification::game_classification(const game_classification& gc):
end_text(gc.end_text),
end_text_duration(gc.end_text_duration),
difficulty(gc.difficulty),
random_mode(gc.random_mode)
random_mode(gc.random_mode),
oos_debug(gc.oos_debug)
{
}
@ -108,6 +111,6 @@ config game_classification::to_config() const
cfg["end_text_duration"] = str_cast<unsigned int>(end_text_duration);
cfg["difficulty"] = difficulty;
cfg["random_mode"] = random_mode;
cfg["oos_debug"] = oos_debug;
return cfg;
}

View file

@ -57,6 +57,7 @@ public:
unsigned int end_text_duration; /**< for how long the end-of-campaign text is shown */
std::string difficulty; /**< The difficulty level the game is being played on. */
std::string random_mode;
bool oos_debug;
};
MAKE_ENUM_STREAM_OPS2(game_classification, CAMPAIGN_TYPE)

View file

@ -11,11 +11,13 @@
See the COPYING file for more details.
*/
#include "global.hpp"
#include "synced_checkup.hpp"
#include "log.hpp"
#include "map_location.hpp"
#include "unit_map.hpp"
#include "unit.hpp"
#include "replay.hpp"
#include "resources.hpp"
#include "game_display.hpp"
static lg::log_domain log_replay("replay");
@ -52,15 +54,6 @@ bool ignored_checkup::local_checkup(const config& /*expected_data*/, config& rea
return true;
}
bool ignored_checkup::networked_checkup(const config& /*expected_data*/, config& real_data)
{
assert(real_data.empty());
LOG_REPLAY << "ignored_checkup::networked_checkup called\n";
return true;
}
synced_checkup::synced_checkup(config& buffer)
: buffer_(buffer), pos_(0)
{
@ -89,9 +82,44 @@ bool synced_checkup::local_checkup(const config& expected_data, config& real_dat
}
}
bool synced_checkup::networked_checkup(const config& /*expected_data*/, config& real_data)
namespace
{
struct checkup_choice : public mp_sync::user_choice
{
checkup_choice(const config& cfg) : cfg_(cfg)
{
}
virtual ~checkup_choice()
{
}
virtual config random_choice(int /*side*/) const OVERRIDE
{
throw "not implemented";
}
virtual bool is_visible() const OVERRIDE
{
return false;
}
virtual config query_user(int /*side*/) const OVERRIDE
{
return cfg_;
}
const config& cfg_;
};
}
mp_debug_checkup::mp_debug_checkup()
{
}
mp_debug_checkup::~mp_debug_checkup()
{
}
bool mp_debug_checkup::local_checkup(const config& expected_data, config& real_data)
{
assert(real_data.empty());
throw "not implemented";
//TODO: something with get_user_choice :).
real_data = get_user_choice("mp_checkup", checkup_choice(expected_data));
return real_data == expected_data;
}

View file

@ -34,37 +34,24 @@ public:
returns whether the two config objects are equal.
*/
virtual bool local_checkup(const config& expected_data, config& real_data) = 0;
/**
compares data on all clients in a networked game, the disadvantage is,
that the clients have to communicate more which might be not wanted if some persons have laggy inet.
returns whether the two config objects are equal.
This is currently not used.
This is currently not implemented.
TODO: we might want to change the design to have a 'local_checkup' subclass (the normal case)
and a 'networked_checkup' subclass (for network OOS debugging) of the checkup class that then replace
the synced_checkup class. Instead of having 2 different methods local_checkup,networked_checkup.
*/
virtual bool networked_checkup(const config& expected_data, config& real_data) = 0;
};
/**
This checkup compares whether the results calculated during the original game match the ones calculated during replay.
Whether this checkup also compares the calculated results of different clients in a a mp game depends on whether
there was already data sended about the current synced command.
*/
class synced_checkup : public checkup
{
public:
synced_checkup(config& buffer);
virtual ~synced_checkup();
virtual bool local_checkup(const config& expected_data, config& real_data);
virtual bool networked_checkup(const config& expected_data, config& real_data);
private:
config& buffer_;
unsigned int pos_;
};
/*
the only purpose of these function isto thro OOS erros, because they should never be called.
*/
class ignored_checkup : public checkup
{
public:
@ -74,10 +61,16 @@ public:
always returns true
*/
virtual bool local_checkup(const config& expected_data, config& real_data);
/**
always returns true
*/
virtual bool networked_checkup(const config& expected_data, config& real_data);
};
/**
This checkup always compares the results in from different clients in a mp game but it also causes more network overhead.
*/
class mp_debug_checkup : public checkup
{
public:
mp_debug_checkup();
virtual ~mp_debug_checkup();
virtual bool local_checkup(const config& expected_data, config& real_data);
};
/*

View file

@ -339,17 +339,29 @@ config synced_context::ask_server_for_seed()
}
set_scontext_synced::set_scontext_synced()
: new_rng_(synced_context::get_rng_for_action()), new_checkup_(recorder.get_last_real_command().child_or_add("checkup")), disabler_()
: new_rng_(synced_context::get_rng_for_action()), new_checkup_(generate_checkup("checkup")), disabler_()
{
init();
}
set_scontext_synced::set_scontext_synced(int number)
: new_rng_(synced_context::get_rng_for_action()), new_checkup_(recorder.get_last_real_command().child_or_add("checkup" + boost::lexical_cast<std::string>(number))), disabler_()
: new_rng_(synced_context::get_rng_for_action()), new_checkup_(generate_checkup("checkup" + boost::lexical_cast<std::string>(number))), disabler_()
{
init();
}
checkup* set_scontext_synced::generate_checkup(const std::string& tagname)
{
if(resources::classification->oos_debug)
{
return new mp_debug_checkup();
}
else
{
return new synced_checkup(recorder.get_last_real_command().child_or_add(tagname));
}
}
/*
so we dont have to write the same code 3 times.
*/
@ -362,7 +374,7 @@ void set_scontext_synced::init()
synced_context::reset_is_simultaneously();
old_checkup_ = checkup_instance;
checkup_instance = & new_checkup_;
checkup_instance = &*new_checkup_;
old_rng_ = random_new::generator;
random_new::generator = new_rng_.get();
}
@ -370,7 +382,7 @@ set_scontext_synced::~set_scontext_synced()
{
LOG_REPLAY << "set_scontext_synced:: destructor\n";
assert(synced_context::get_synced_state() == synced_context::SYNCED);
assert(checkup_instance == &new_checkup_);
assert(checkup_instance == &*new_checkup_);
config co;
if(!checkup_instance->local_checkup(config_of("random_calls", new_rng_->get_random_calls()), co))
{
@ -393,7 +405,7 @@ int set_scontext_synced::get_random_calls()
set_scontext_local_choice::set_scontext_local_choice()
{
//TODO: should we also reset the synced checkup?
assert(synced_context::get_synced_state() == synced_context::SYNCED);
synced_context::set_synced_state(synced_context::LOCAL_CHOICE);

View file

@ -23,6 +23,7 @@
#include "generic_event.hpp"
#include "mouse_handler_base.hpp"
#include <boost/shared_ptr.hpp>
#include <boost/scoped_ptr.hpp>
class config;
//only static methods.
@ -145,10 +146,11 @@ public:
private:
//only called by contructors.
void init();
static checkup* generate_checkup(const std::string& tagname);
random_new::rng* old_rng_;
boost::shared_ptr<random_new::rng> new_rng_;
checkup* old_checkup_;
synced_checkup new_checkup_;
boost::scoped_ptr<checkup> new_checkup_;
events::command_disabler disabler_;
};