Merge pull request #141 from gfgtdf/sync_fix
fixes bugs intrduced in pr 121 and more
This commit is contained in:
commit
f6fbfb6879
18 changed files with 431 additions and 193 deletions
|
@ -845,6 +845,7 @@ set(wesnoth-main_SRC
|
|||
playmp_controller.cpp
|
||||
playsingle_controller.cpp
|
||||
playturn.cpp
|
||||
playturn_network_adapter.cpp
|
||||
portrait.cpp
|
||||
random_new.cpp
|
||||
random_new_deterministic.cpp
|
||||
|
|
|
@ -478,6 +478,7 @@ wesnoth_sources = Split("""
|
|||
playmp_controller.cpp
|
||||
playsingle_controller.cpp
|
||||
playturn.cpp
|
||||
playturn_network_adapter.cpp
|
||||
portrait.cpp
|
||||
random_new.cpp
|
||||
random_new_deterministic.cpp
|
||||
|
|
|
@ -1377,8 +1377,9 @@ namespace
|
|||
{
|
||||
}
|
||||
|
||||
virtual config query_user() const
|
||||
virtual config query_user(int /*side*/) const
|
||||
{
|
||||
//the 'side' parameter might differ from side_num_-
|
||||
int res = 0;
|
||||
team t = (*resources::teams)[side_num_ - 1];
|
||||
//i wonder how this got included here ?
|
||||
|
@ -1423,7 +1424,7 @@ namespace
|
|||
return retv;
|
||||
|
||||
}
|
||||
virtual config random_choice() const
|
||||
virtual config random_choice(int /*side*/) const
|
||||
{
|
||||
config retv;
|
||||
retv["value"] = 0;
|
||||
|
|
|
@ -145,7 +145,7 @@ namespace { // Types
|
|||
, has_text_input(ht), options(o)
|
||||
{}
|
||||
|
||||
virtual config query_user() const
|
||||
virtual config query_user(int /*side*/) const
|
||||
{
|
||||
std::string image = get_image(cfg, speaker);
|
||||
std::string caption = get_caption(cfg, speaker);
|
||||
|
@ -190,7 +190,7 @@ namespace { // Types
|
|||
return cfg;
|
||||
}
|
||||
|
||||
virtual config random_choice() const
|
||||
virtual config random_choice(int /*side*/) const
|
||||
{
|
||||
return config();
|
||||
}
|
||||
|
@ -206,7 +206,7 @@ namespace { // Types
|
|||
: nb_options(o), loc(l), use_dialog(d)
|
||||
{}
|
||||
|
||||
virtual config query_user() const
|
||||
virtual config query_user(int /*side*/) const
|
||||
{
|
||||
int selected;
|
||||
if (use_dialog) {
|
||||
|
@ -221,7 +221,7 @@ namespace { // Types
|
|||
return cfg;
|
||||
}
|
||||
|
||||
virtual config random_choice() const
|
||||
virtual config random_choice(int /*side*/) const
|
||||
{
|
||||
config cfg;
|
||||
cfg["value"] = random_new::generator->next_random() % nb_options;
|
||||
|
@ -1111,7 +1111,7 @@ WML_HANDLER_FUNCTION(message, event_info, cfg)
|
|||
{
|
||||
/* Always show the dialog if it has no input, whether we are
|
||||
replaying or not. */
|
||||
msg.query_user();
|
||||
msg.query_user(resources::controller->current_side());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
#include "util.hpp"
|
||||
#include "variable.hpp"
|
||||
|
||||
|
||||
#include <cassert>
|
||||
|
||||
//TODO: remove LOG_PERSIST, ERR_PERSIST from persist_context.hpp to .cpp files.
|
||||
#define DBG_PERSIST LOG_STREAM(debug, log_persist)
|
||||
|
@ -41,15 +41,17 @@ struct persist_choice: mp_sync::user_choice {
|
|||
, var_name(name)
|
||||
, side(side_num) {
|
||||
}
|
||||
virtual config query_user() const {
|
||||
virtual config query_user(int side_for) const {
|
||||
assert(side == side_for);
|
||||
config ret;
|
||||
ret["side"] = side;
|
||||
ret.add_child("variables",ctx.get_var(var_name));
|
||||
return ret;
|
||||
}
|
||||
virtual config random_choice() const {
|
||||
virtual config random_choice(int /*side_for*/) const {
|
||||
return config();
|
||||
}
|
||||
virtual bool is_visible() const { return false; }
|
||||
};
|
||||
|
||||
static void get_global_variable(persist_context &ctx, const vconfig &pcfg)
|
||||
|
|
|
@ -190,11 +190,9 @@ void playmp_controller::play_human_turn(){
|
|||
|
||||
try {
|
||||
config cfg;
|
||||
const network::connection res = network::receive_data(cfg);
|
||||
std::deque<config> backlog;
|
||||
|
||||
if(res != network::null_connection) {
|
||||
if (turn_data_->process_network_data(cfg, res, backlog, skip_replay_) == turn_info::PROCESS_RESTART_TURN)
|
||||
if(network_reader_.read(cfg)) {
|
||||
if (turn_data_->process_network_data(cfg, skip_replay_) == turn_info::PROCESS_RESTART_TURN)
|
||||
{
|
||||
// Clean undo stack if turn has to be restarted (losing control)
|
||||
if ( undo_stack_->can_undo() )
|
||||
|
@ -274,11 +272,8 @@ void playmp_controller::play_idle_loop()
|
|||
{
|
||||
try {
|
||||
config cfg;
|
||||
const network::connection res = network::receive_data(cfg);
|
||||
std::deque<config> backlog;
|
||||
|
||||
if(res != network::null_connection) {
|
||||
if (turn_data_->process_network_data(cfg, res, backlog, skip_replay_) == turn_info::PROCESS_RESTART_TURN)
|
||||
if(network_reader_.read(cfg)) {
|
||||
if (turn_data_->process_network_data(cfg, skip_replay_) == turn_info::PROCESS_RESTART_TURN)
|
||||
{
|
||||
throw end_turn_exception(gui_->playing_side());
|
||||
}
|
||||
|
@ -400,26 +395,26 @@ void playmp_controller::wait_for_upload()
|
|||
init_turn_data();
|
||||
}
|
||||
|
||||
config cfg;
|
||||
network_reader_.set_source(playturn_network_adapter::get_source_from_config(cfg));
|
||||
while(true) {
|
||||
try {
|
||||
config cfg;
|
||||
const network::connection res = dialogs::network_receive_dialog(
|
||||
*gui_, _("Waiting for next scenario..."), cfg);
|
||||
|
||||
std::deque<config> backlog;
|
||||
if(res != network::null_connection) {
|
||||
if (turn_data_->process_network_data(cfg, res, backlog, skip_replay_)
|
||||
== turn_info::PROCESS_END_LINGER) {
|
||||
if (turn_data_->process_network_data_from_reader(skip_replay_) == turn_info::PROCESS_END_LINGER) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} catch(const end_level_exception&) {
|
||||
network_reader_.set_source(playturn_network_adapter::read_network);
|
||||
turn_data_->send_data();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
network_reader_.set_source(playturn_network_adapter::read_network);
|
||||
if(set_turn_data) {
|
||||
delete turn_data_;
|
||||
turn_data_ = NULL;
|
||||
|
@ -469,33 +464,25 @@ void playmp_controller::play_network_turn(){
|
|||
LOG_NG << "is networked...\n";
|
||||
|
||||
end_turn_enable(false);
|
||||
turn_info turn_data(player_number_, replay_sender_);
|
||||
turn_info turn_data(player_number_, replay_sender_, network_reader_);
|
||||
turn_data.host_transfer().attach_handler(this);
|
||||
|
||||
for(;;) {
|
||||
|
||||
if (!network_processing_stopped_){
|
||||
bool have_data = false;
|
||||
config cfg;
|
||||
|
||||
network::connection from = network::null_connection;
|
||||
|
||||
if(data_backlog_.empty() == false) {
|
||||
have_data = true;
|
||||
cfg = data_backlog_.front();
|
||||
data_backlog_.pop_front();
|
||||
} else {
|
||||
from = network::receive_data(cfg);
|
||||
have_data = from != network::null_connection;
|
||||
}
|
||||
|
||||
if(have_data) {
|
||||
if(network_reader_.read(cfg)) {
|
||||
if (replay_last_turn_ <= turn()){
|
||||
if (skip_replay_) {
|
||||
skip_replay_ = false;
|
||||
}
|
||||
}
|
||||
const turn_info::PROCESS_DATA_RESULT result = turn_data.process_network_data(cfg, from, data_backlog_, skip_replay_);
|
||||
const turn_info::PROCESS_DATA_RESULT result = turn_data.process_network_data(cfg, skip_replay_);
|
||||
if(player_type_changed_ == true)
|
||||
{
|
||||
//we received a player change/quit during waiting in get_user_choice/synced_context::pull_remote_user_input
|
||||
return;
|
||||
}
|
||||
if (result == turn_info::PROCESS_RESTART_TURN) {
|
||||
player_type_changed_ = true;
|
||||
return;
|
||||
|
@ -510,7 +497,7 @@ void playmp_controller::play_network_turn(){
|
|||
{
|
||||
bool was_skipping = recorder.is_skipping();
|
||||
recorder.set_skip(skip_replay_);
|
||||
if(do_replay(current_side()))
|
||||
if(do_replay(current_side()) == REPLAY_FOUND_END_TURN)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
@ -534,7 +521,7 @@ void playmp_controller::play_network_turn(){
|
|||
}
|
||||
|
||||
void playmp_controller::init_turn_data() {
|
||||
turn_data_ = new turn_info(player_number_, replay_sender_);
|
||||
turn_data_ = new turn_info(player_number_, replay_sender_,network_reader_);
|
||||
turn_data_->host_transfer().attach_handler(this);
|
||||
}
|
||||
|
||||
|
@ -563,14 +550,19 @@ void playmp_controller::process_oos(const std::string& err_msg) const {
|
|||
}
|
||||
|
||||
void playmp_controller::handle_generic_event(const std::string& name){
|
||||
turn_info turn_data(player_number_, replay_sender_);
|
||||
turn_info turn_data(player_number_, replay_sender_, network_reader_);
|
||||
|
||||
if (name == "ai_user_interact"){
|
||||
playsingle_controller::handle_generic_event(name);
|
||||
turn_data.send_data();
|
||||
}
|
||||
else if ((name == "ai_gamestate_changed") || (name == "ai_sync_network")){
|
||||
turn_data.sync_network();
|
||||
turn_info::PROCESS_DATA_RESULT res = turn_data.sync_network();
|
||||
assert(res == turn_info::PROCESS_CONTINUE || res == turn_info::PROCESS_RESTART_TURN || res == turn_info::PROCESS_FOUND_DEPENDENT);
|
||||
if(res == turn_info::PROCESS_RESTART_TURN)
|
||||
{
|
||||
player_type_changed_ = true;
|
||||
}
|
||||
}
|
||||
else if (name == "host_transfer"){
|
||||
is_host_ = true;
|
||||
|
|
|
@ -63,9 +63,9 @@ playsingle_controller::playsingle_controller(const config& level,
|
|||
const config& game_config, CVideo& video, bool skip_replay) :
|
||||
play_controller(level, state_of_game, ticks, num_turns, game_config, video, skip_replay),
|
||||
cursor_setter(cursor::NORMAL),
|
||||
data_backlog_(),
|
||||
textbox_info_(),
|
||||
replay_sender_(recorder),
|
||||
network_reader_(),
|
||||
end_turn_(false),
|
||||
player_type_changed_(false),
|
||||
replaying_(false),
|
||||
|
@ -609,7 +609,7 @@ void playsingle_controller::play_turn(bool save)
|
|||
init_side(player_number_ - 1);
|
||||
} catch (end_turn_exception) {
|
||||
if (current_team().is_network() == false) {
|
||||
turn_info turn_data(player_number_, replay_sender_);
|
||||
turn_info turn_data(player_number_, replay_sender_,network_reader_);
|
||||
recorder.end_turn();
|
||||
turn_data.sync_network();
|
||||
}
|
||||
|
@ -618,7 +618,7 @@ void playsingle_controller::play_turn(bool save)
|
|||
|
||||
if (replaying_) {
|
||||
LOG_NG << "doing replay " << player_number_ << "\n";
|
||||
replaying_ = ::do_replay(player_number_);
|
||||
replaying_ = ::do_replay(player_number_) == REPLAY_FOUND_END_TURN;
|
||||
LOG_NG << "result of replay: " << (replaying_?"true":"false") << "\n";
|
||||
} else {
|
||||
// If a side is dead end the turn, but play at least side=1's
|
||||
|
@ -626,7 +626,7 @@ void playsingle_controller::play_turn(bool save)
|
|||
if (current_team().is_human() && side_units(player_number_) == 0
|
||||
&& (resources::units->size() != 0 || player_number_ != 1))
|
||||
{
|
||||
turn_info turn_data(player_number_, replay_sender_);
|
||||
turn_info turn_data(player_number_, replay_sender_, network_reader_);
|
||||
recorder.end_turn();
|
||||
turn_data.sync_network();
|
||||
continue;
|
||||
|
@ -926,7 +926,7 @@ void playsingle_controller::play_ai_turn(){
|
|||
synced_context::run_in_synced_context("auto_shroud", replay_helper::get_auto_shroud(true));
|
||||
}
|
||||
|
||||
turn_info turn_data(player_number_, replay_sender_);
|
||||
turn_info turn_data(player_number_, replay_sender_, network_reader_);
|
||||
|
||||
try {
|
||||
ai::manager::play_turn(player_number_);
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#define PLAYSINGLE_CONTROLLER_H_INCLUDED
|
||||
|
||||
#include "play_controller.hpp"
|
||||
#include "playturn_network_adapter.hpp"
|
||||
#include "replay.hpp"
|
||||
|
||||
class playsingle_controller : public play_controller
|
||||
|
@ -92,10 +93,10 @@ protected:
|
|||
void store_gold(bool obs = false);
|
||||
|
||||
const cursor::setter cursor_setter;
|
||||
std::deque<config> data_backlog_;
|
||||
gui::floating_textbox textbox_info_;
|
||||
|
||||
replay_network_sender replay_sender_;
|
||||
playturn_network_adapter network_reader_;
|
||||
|
||||
bool end_turn_;
|
||||
bool player_type_changed_;
|
||||
|
|
158
src/playturn.cpp
158
src/playturn.cpp
|
@ -38,38 +38,43 @@
|
|||
static lg::log_domain log_network("network");
|
||||
#define ERR_NW LOG_STREAM(err, log_network)
|
||||
|
||||
turn_info::turn_info(unsigned team_num, replay_network_sender &replay_sender) :
|
||||
turn_info::turn_info(unsigned team_num, replay_network_sender &replay_sender,playturn_network_adapter &network_reader) :
|
||||
team_num_(team_num),
|
||||
replay_sender_(replay_sender),
|
||||
host_transfer_("host_transfer"),
|
||||
replay_()
|
||||
network_reader_(network_reader)
|
||||
{
|
||||
/**
|
||||
* We do network sync so [init_side] is transferred to network hosts
|
||||
* TODO: i think it is unintiutive that creating this object automatictly sends data over the network.
|
||||
* For example it means that playmp_controller::handle_generic_event("ai_user_interact") casues send_data,
|
||||
* Idk whether that is intended, but an explicit call would be better.
|
||||
*/
|
||||
if(network::nconnections() > 0)
|
||||
send_data();
|
||||
}
|
||||
|
||||
turn_info::~turn_info(){
|
||||
turn_info::~turn_info()
|
||||
{
|
||||
}
|
||||
|
||||
void turn_info::sync_network()
|
||||
turn_info::PROCESS_DATA_RESULT turn_info::sync_network()
|
||||
{
|
||||
//there should be nothing left on the replay and we should get turn_info::PROCESS_CONTINUE back.
|
||||
turn_info::PROCESS_DATA_RESULT retv = replay_to_process_data_result(do_replay(team_num_));
|
||||
if(network::nconnections() > 0) {
|
||||
|
||||
//receive data first, and then send data. When we sent the end of
|
||||
//the AI's turn, we don't want there to be any chance where we
|
||||
//could get data back pertaining to the next turn.
|
||||
config cfg;
|
||||
while(network::connection res = network::receive_data(cfg)) {
|
||||
std::deque<config> backlog;
|
||||
process_network_data(cfg,res,backlog,false);
|
||||
while( (retv == turn_info::PROCESS_CONTINUE) && network_reader_.read(cfg)) {
|
||||
retv = process_network_data(cfg,false);
|
||||
cfg.clear();
|
||||
}
|
||||
|
||||
send_data();
|
||||
}
|
||||
return retv;
|
||||
}
|
||||
|
||||
void turn_info::send_data()
|
||||
|
@ -81,33 +86,21 @@ void turn_info::send_data()
|
|||
}
|
||||
}
|
||||
|
||||
void turn_info::handle_turn(
|
||||
bool& turn_end,
|
||||
turn_info::PROCESS_DATA_RESULT turn_info::handle_turn(
|
||||
const config& t,
|
||||
const bool skip_replay,
|
||||
std::deque<config>& backlog)
|
||||
const bool skip_replay)
|
||||
{
|
||||
if(turn_end == false) {
|
||||
/** @todo FIXME: Check what commands we execute when it's our turn! */
|
||||
//TODO: can we remove replay_ ? i think yes.
|
||||
replay_.append(t);
|
||||
replay_.set_skip(skip_replay);
|
||||
//t can contain a [command] or a [upload_log]
|
||||
assert(t.all_children_count() == 1);
|
||||
/** @todo FIXME: Check what commands we execute when it's our turn! */
|
||||
|
||||
bool was_skipping = recorder.is_skipping();
|
||||
recorder.set_skip(skip_replay);
|
||||
//turn_end = do_replay(team_num_, &replay_);
|
||||
//note, that this cunfion might call itself recursively: do_replay -> ... -> persist_var -> ... -> handle_generic_event -> sync_network -> handle_turn
|
||||
recorder.add_config(t, replay::MARK_AS_SENT);
|
||||
turn_end = do_replay(team_num_);
|
||||
recorder.set_skip(was_skipping);
|
||||
|
||||
} else {
|
||||
|
||||
//this turn has finished, so push the remaining moves
|
||||
//into the backlog
|
||||
backlog.push_back(config());
|
||||
backlog.back().add_child("turn", t);
|
||||
}
|
||||
bool was_skipping = recorder.is_skipping();
|
||||
recorder.set_skip(skip_replay);
|
||||
//note, that this function might call itself recursively: do_replay -> ... -> persist_var -> ... -> handle_generic_event -> sync_network -> handle_turn
|
||||
recorder.add_config(t, replay::MARK_AS_SENT);
|
||||
PROCESS_DATA_RESULT retv = replay_to_process_data_result(do_replay(team_num_));
|
||||
recorder.set_skip(was_skipping);
|
||||
return retv;
|
||||
}
|
||||
|
||||
void turn_info::do_save()
|
||||
|
@ -118,56 +111,69 @@ void turn_info::do_save()
|
|||
}
|
||||
}
|
||||
|
||||
turn_info::PROCESS_DATA_RESULT turn_info::process_network_data(const config& cfg,
|
||||
network::connection /*from*/, std::deque<config>& backlog, bool skip_replay)
|
||||
turn_info::PROCESS_DATA_RESULT turn_info::process_network_data_from_reader(bool skip_replay)
|
||||
{
|
||||
config cfg;
|
||||
while(this->network_reader_.read(cfg))
|
||||
{
|
||||
PROCESS_DATA_RESULT res = process_network_data(cfg, skip_replay);
|
||||
if(res != PROCESS_CONTINUE)
|
||||
{
|
||||
return res;
|
||||
}
|
||||
}
|
||||
return PROCESS_CONTINUE;
|
||||
}
|
||||
|
||||
turn_info::PROCESS_DATA_RESULT turn_info::process_network_data(const config& cfg, bool skip_replay)
|
||||
{
|
||||
// we cannot be connected to multiple peers anymore because
|
||||
// the simple wesnothserver implementation in wesnoth was removed years ago.
|
||||
assert(network::nconnections() <= 1);
|
||||
|
||||
assert(cfg.all_children_count() == 1);
|
||||
assert(cfg.attribute_range().first == cfg.attribute_range().second);
|
||||
if(!recorder.at_end())
|
||||
{
|
||||
ERR_NW << "processing network data while still having data on the replay.\n";
|
||||
}
|
||||
|
||||
if (const config &msg = cfg.child("message"))
|
||||
{
|
||||
resources::screen->add_chat_message(time(NULL), msg["sender"], msg["side"],
|
||||
msg["message"], events::chat_handler::MESSAGE_PUBLIC,
|
||||
preferences::message_bell());
|
||||
}
|
||||
|
||||
if (const config &msg = cfg.child("whisper") /*&& is_observer()*/)
|
||||
else if (const config &msg = cfg.child("whisper") /*&& is_observer()*/)
|
||||
{
|
||||
resources::screen->add_chat_message(time(NULL), "whisper: " + msg["sender"].str(), 0,
|
||||
msg["message"], events::chat_handler::MESSAGE_PRIVATE,
|
||||
preferences::message_bell());
|
||||
}
|
||||
|
||||
BOOST_FOREACH(const config &ob, cfg.child_range("observer")) {
|
||||
else if (const config &ob = cfg.child("observer") )
|
||||
{
|
||||
resources::screen->add_observer(ob["name"]);
|
||||
}
|
||||
|
||||
BOOST_FOREACH(const config &ob, cfg.child_range("observer_quit")) {
|
||||
else if (const config &ob = cfg.child("observer_quit"))
|
||||
{
|
||||
resources::screen->remove_observer(ob["name"]);
|
||||
}
|
||||
|
||||
if (cfg.child("leave_game")) {
|
||||
else if (cfg.child("leave_game")) {
|
||||
throw network::error("");
|
||||
}
|
||||
|
||||
bool turn_end = false;
|
||||
|
||||
config::const_child_itors turns = cfg.child_range("turn");
|
||||
|
||||
const config& change = cfg.child_or_empty("change_controller");
|
||||
const std::string& side_drop = cfg["side_drop"].str();
|
||||
|
||||
BOOST_FOREACH(const config &t, turns)
|
||||
else if (const config &turn = cfg.child("turn"))
|
||||
{
|
||||
recorder.add_config(t, replay::MARK_AS_SENT);
|
||||
return handle_turn(turn, skip_replay);
|
||||
}
|
||||
handle_turn(turn_end, config(), skip_replay, backlog);
|
||||
|
||||
resources::whiteboard->process_network_data(cfg);
|
||||
|
||||
if (!change.empty())
|
||||
else if (cfg.has_child("whiteboard"))
|
||||
{
|
||||
resources::whiteboard->process_network_data(cfg);
|
||||
}
|
||||
else if (const config &change = cfg.child("change_controller"))
|
||||
{
|
||||
if(change.empty())
|
||||
{
|
||||
return PROCESS_CONTINUE;
|
||||
}
|
||||
//don't use lexical_cast_default it's "safer" to end on error
|
||||
const int side = lexical_cast<int>(change["side"]);
|
||||
const size_t index = static_cast<size_t>(side-1);
|
||||
|
@ -221,10 +227,12 @@ turn_info::PROCESS_DATA_RESULT turn_info::process_network_data(const config& cfg
|
|||
return restart ? PROCESS_RESTART_TURN : PROCESS_CONTINUE;
|
||||
}
|
||||
}
|
||||
|
||||
//if a side has dropped out of the game.
|
||||
if(!side_drop.empty()) {
|
||||
const std::string controller = cfg["controller"];
|
||||
|
||||
else if (const config &side_drop_c = cfg.child("side_drop"))
|
||||
{
|
||||
const std::string& side_drop = side_drop_c["side_num"].str();
|
||||
const std::string controller = side_drop_c["controller"];
|
||||
//if a side has dropped out of the game.
|
||||
int side = atoi(side_drop.c_str());
|
||||
const size_t side_index = side-1;
|
||||
|
||||
|
@ -364,7 +372,7 @@ turn_info::PROCESS_DATA_RESULT turn_info::process_network_data(const config& cfg
|
|||
|
||||
// The host has ended linger mode in a campaign -> enable the "End scenario" button
|
||||
// and tell we did get the notification.
|
||||
if (cfg.child("notify_next_scenario")) {
|
||||
else if (cfg.child("notify_next_scenario")) {
|
||||
gui::button* btn_end = resources::screen->find_action_button("button-endturn");
|
||||
if(btn_end) {
|
||||
btn_end->enable(true);
|
||||
|
@ -373,13 +381,17 @@ turn_info::PROCESS_DATA_RESULT turn_info::process_network_data(const config& cfg
|
|||
}
|
||||
|
||||
//If this client becomes the new host, notify the play_controller object about it
|
||||
if (const config &cfg_host_transfer = cfg.child("host_transfer")){
|
||||
else if (const config &cfg_host_transfer = cfg.child("host_transfer")){
|
||||
if (cfg_host_transfer["value"] == "1") {
|
||||
host_transfer_.notify_observers();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ERR_NW << "found unknown command:\n" << cfg.debug() << "\n";
|
||||
}
|
||||
|
||||
return turn_end ? PROCESS_END_TURN : PROCESS_CONTINUE;
|
||||
return PROCESS_CONTINUE;
|
||||
}
|
||||
|
||||
void turn_info::change_controller(const std::string& side, const std::string& controller)
|
||||
|
@ -402,6 +414,22 @@ void turn_info::change_side_controller(const std::string& side, const std::strin
|
|||
network::send_data(cfg, 0);
|
||||
}
|
||||
|
||||
turn_info::PROCESS_DATA_RESULT turn_info::replay_to_process_data_result(REPLAY_RETURN replayreturn)
|
||||
{
|
||||
switch(replayreturn)
|
||||
{
|
||||
case REPLAY_RETURN_AT_END:
|
||||
return PROCESS_CONTINUE;
|
||||
case REPLAY_FOUND_DEPENDENT:
|
||||
return PROCESS_FOUND_DEPENDENT;
|
||||
case REPLAY_FOUND_END_TURN:
|
||||
return PROCESS_END_TURN;
|
||||
default:
|
||||
assert(false);
|
||||
throw "found invalid REPLAY_RETURN";
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
void turn_info::take_side(const std::string& side, const std::string& controller)
|
||||
{
|
||||
|
|
|
@ -20,46 +20,47 @@ class replay_network_sender;
|
|||
|
||||
#include "generic_event.hpp"
|
||||
#include "network.hpp"
|
||||
#include "playturn_network_adapter.hpp"
|
||||
#include "replay.hpp"
|
||||
|
||||
class turn_info
|
||||
{
|
||||
public:
|
||||
turn_info(unsigned team_num, replay_network_sender &network_sender);
|
||||
turn_info(unsigned team_num, replay_network_sender &network_sender, playturn_network_adapter &network_reader);
|
||||
|
||||
~turn_info();
|
||||
|
||||
void sync_network();
|
||||
|
||||
void send_data();
|
||||
|
||||
enum PROCESS_DATA_RESULT {
|
||||
enum PROCESS_DATA_RESULT
|
||||
{
|
||||
PROCESS_CONTINUE,
|
||||
PROCESS_RESTART_TURN,
|
||||
PROCESS_END_TURN,
|
||||
/** When the host uploaded the next scenario this is returned. */
|
||||
PROCESS_END_LINGER
|
||||
};
|
||||
PROCESS_END_LINGER,
|
||||
/** When we couldn't process the network data because we found a dependent command, this should only happen if we were called playmp_controller::from handle_generic_event -> sync_network*/
|
||||
PROCESS_FOUND_DEPENDENT
|
||||
};
|
||||
|
||||
//function which will process incoming network data, and act on it. If there is
|
||||
//more data than a single turn's worth, excess data will be placed into 'backlog'.
|
||||
//No more than one turn's worth of data will be placed into a single backlog item,
|
||||
//so it is safe to assume that backlog won't be touched if cfg is a member of a previous
|
||||
//backlog.
|
||||
//data will be forwarded to all peers other than 'from', unless 'from' is null, in
|
||||
//which case data will not be forwarded
|
||||
PROCESS_DATA_RESULT process_network_data(const config& cfg,network::connection from,std::deque<config>& backlog, bool skip_replay);
|
||||
PROCESS_DATA_RESULT sync_network();
|
||||
|
||||
void send_data();
|
||||
|
||||
//function which will process incoming network data received with playturn_network_adapter, and act on it.
|
||||
PROCESS_DATA_RESULT process_network_data(const config& cfg, bool skip_replay);
|
||||
|
||||
//reads as much data from network_reader_ as possible and processed it.
|
||||
PROCESS_DATA_RESULT process_network_data_from_reader(bool skip_replay);
|
||||
|
||||
events::generic_event& host_transfer() { return host_transfer_; }
|
||||
private:
|
||||
static void change_controller(const std::string& side, const std::string& controller);
|
||||
static void change_side_controller(const std::string& side, const std::string& player);
|
||||
|
||||
void handle_turn(
|
||||
bool& turn_end,
|
||||
static PROCESS_DATA_RESULT replay_to_process_data_result(REPLAY_RETURN replayreturn);
|
||||
PROCESS_DATA_RESULT handle_turn(
|
||||
const config& t,
|
||||
const bool skip_replay,
|
||||
std::deque<config>& backlog);
|
||||
const bool skip_replay);
|
||||
|
||||
void do_save();
|
||||
|
||||
|
@ -69,7 +70,7 @@ private:
|
|||
|
||||
events::generic_event host_transfer_;
|
||||
|
||||
replay replay_;
|
||||
playturn_network_adapter& network_reader_;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
149
src/playturn_network_adapter.cpp
Normal file
149
src/playturn_network_adapter.cpp
Normal file
|
@ -0,0 +1,149 @@
|
|||
#include "playturn_network_adapter.hpp"
|
||||
#include "network.hpp"
|
||||
#include "config_assign.hpp"
|
||||
#include "log.hpp"
|
||||
|
||||
#include <boost/assign.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
#include <iostream>
|
||||
#include <cassert>
|
||||
|
||||
|
||||
static lg::log_domain log_network("network");
|
||||
#define ERR_NW LOG_STREAM(err, log_network)
|
||||
|
||||
void playturn_network_adapter::read_from_network()
|
||||
{
|
||||
assert(data_.size() > 0);
|
||||
|
||||
this->data_.push_back(config());
|
||||
config& back = data_.back();
|
||||
bool has_data = this->network_reader_(back);
|
||||
//ping is handeled by network.cpp and we can ignore it.
|
||||
back.remove_attribute("ping");
|
||||
if((!has_data) || back.empty())
|
||||
{
|
||||
this->data_.pop_back();
|
||||
return;
|
||||
}
|
||||
assert(!data_.back().empty());
|
||||
|
||||
if(back.has_attribute("side_drop"))
|
||||
{
|
||||
config child;
|
||||
child["side_num"] = back["side_drop"];
|
||||
child["controller"] = back["controller"];
|
||||
this->data_.push_back(config_of("side_drop", child));
|
||||
back.remove_attribute("side_drop");
|
||||
back.remove_attribute("controller");
|
||||
}
|
||||
assert(!data_.back().empty());
|
||||
//there should be no attributes left.
|
||||
|
||||
if(back.attribute_range().first != back.attribute_range().second )
|
||||
{
|
||||
ERR_NW << "found unexpected attribute:" <<back.debug() << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
bool playturn_network_adapter::is_at_end()
|
||||
{
|
||||
assert(data_.size() > 0);
|
||||
return this->next_ == data_.back().ordered_end();
|
||||
}
|
||||
|
||||
bool playturn_network_adapter::read(config& dst)
|
||||
{
|
||||
assert(dst.empty());
|
||||
if(is_at_end())
|
||||
{
|
||||
read_from_network();
|
||||
}
|
||||
if(is_at_end())
|
||||
{
|
||||
//that means we couldn't read anything from the network.
|
||||
return false;
|
||||
}
|
||||
//skip empty data.
|
||||
while(next_ == data_.begin()->ordered_end())
|
||||
{
|
||||
data_.pop_front();
|
||||
next_ = data_.front().ordered_begin();
|
||||
assert(!is_at_end());
|
||||
}
|
||||
config& child = dst.add_child(next_->key);
|
||||
//TODO: implement a non const version of ordered children
|
||||
config& child_old = const_cast<config&>(next_->cfg);
|
||||
if(next_->key == "turn")
|
||||
{
|
||||
//split [turn] indo different [turn] for each child.
|
||||
assert(next_->cfg.all_children_count() > next_command_num_);
|
||||
config::all_children_iterator itor = child_old.ordered_begin();
|
||||
//TODO: implement operator + (all_children_iterator, int ) properly
|
||||
for(unsigned int i = 0; i < next_command_num_; i++) {itor++;}
|
||||
//TODO: implement a non const version of ordered children
|
||||
config& childchild_old = const_cast<config&>(itor->cfg);
|
||||
config& childchild = child.add_child(itor->key);
|
||||
childchild.swap(childchild_old);
|
||||
|
||||
next_command_num_++;
|
||||
if(next_->cfg.all_children_count() == next_command_num_)
|
||||
{
|
||||
next_command_num_ = 0;
|
||||
next_++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
child.swap(child_old);
|
||||
next_++;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
playturn_network_adapter::playturn_network_adapter(source_type source)
|
||||
: data_(boost::assign::list_of(config()).convert_to_container<std::list<config> >()),
|
||||
next_(data_.front().ordered_end()),
|
||||
next_command_num_(0),
|
||||
network_reader_(source)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
playturn_network_adapter::~playturn_network_adapter()
|
||||
{
|
||||
if(!is_at_end())
|
||||
{
|
||||
ERR_NW << "Destroing playturn_network_adapter with an non empty buffer, this means loss of network data\n";
|
||||
}
|
||||
}
|
||||
|
||||
void playturn_network_adapter::set_source(source_type source)
|
||||
{
|
||||
network_reader_ = source;
|
||||
}
|
||||
|
||||
static bool read_config(config& src, config& dst)
|
||||
{
|
||||
assert(dst.empty());
|
||||
if(!src.empty())
|
||||
{
|
||||
src.swap(dst);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
playturn_network_adapter::source_type playturn_network_adapter::get_source_from_config(config& cfg)
|
||||
{
|
||||
return boost::bind(read_config, cfg, _1);
|
||||
}
|
||||
|
||||
bool playturn_network_adapter::read_network(config& cfg)
|
||||
{
|
||||
return network::receive_data(cfg) != network::null_connection;
|
||||
}
|
46
src/playturn_network_adapter.hpp
Normal file
46
src/playturn_network_adapter.hpp
Normal file
|
@ -0,0 +1,46 @@
|
|||
|
||||
|
||||
#ifndef PLAYTURN_NETWORK_ADAPTER_HPP_INCLUDED
|
||||
#define PLAYTURN_NETWORK_ADAPTER_HPP_INCLUDED
|
||||
|
||||
#include "config.hpp"
|
||||
#include <list>
|
||||
#include <boost/function.hpp>
|
||||
|
||||
/*
|
||||
The purpose if this class is to preprocess incoming network data, and provide a steam that always returns just one command/action at a time.
|
||||
Especialy we want each replay command in his own [turn].
|
||||
*/
|
||||
class playturn_network_adapter
|
||||
{
|
||||
public:
|
||||
typedef boost::function1<bool, config&> source_type;
|
||||
|
||||
playturn_network_adapter(source_type source = read_network);
|
||||
~playturn_network_adapter();
|
||||
|
||||
//returns true on success.
|
||||
//dst has to be empty befor the call.
|
||||
//after the call dst contains one child chen returned true otherise it's empty.
|
||||
bool read(config& dst);
|
||||
//returns false if there is still data in the internal buffer.
|
||||
bool is_at_end();
|
||||
void set_source(source_type source);
|
||||
//returns a function to be passed to set_source.
|
||||
static source_type get_source_from_config(config& src);
|
||||
//a function to be passed to set_source.
|
||||
static bool read_network(config& dst);
|
||||
private:
|
||||
//reads data from the network stream.
|
||||
void read_from_network();
|
||||
//this always contains one empty config becasue we want a vaid value for next_.
|
||||
std::list<config> data_;
|
||||
//the position of the next to be received element in data_->front().
|
||||
config::all_children_iterator next_;
|
||||
//if we are processing a [turn] with mutiple [command] we want to split them.
|
||||
//In this case next_command_num_ is the next to be processed turn into a command otherwise it's 0;
|
||||
unsigned int next_command_num_;
|
||||
//a function to receive data from the network.
|
||||
source_type network_reader_;
|
||||
};
|
||||
#endif
|
|
@ -692,7 +692,7 @@ static void show_oos_error_error_function(const std::string& message, bool /*hea
|
|||
replay::process_error(message);
|
||||
}
|
||||
|
||||
bool do_replay(int side_num)
|
||||
REPLAY_RETURN do_replay(int side_num)
|
||||
{
|
||||
log_scope("do replay");
|
||||
|
||||
|
@ -701,10 +701,10 @@ bool do_replay(int side_num)
|
|||
}
|
||||
|
||||
update_locker lock_update(resources::screen->video(),get_replay_source().is_skipping());
|
||||
return do_replay_handle(side_num, "");
|
||||
return do_replay_handle(side_num);
|
||||
}
|
||||
|
||||
bool do_replay_handle(int side_num, const std::string &do_untill)
|
||||
REPLAY_RETURN do_replay_handle(int side_num)
|
||||
{
|
||||
|
||||
//team ¤t_team = (*resources::teams)[side_num - 1];
|
||||
|
@ -728,14 +728,7 @@ bool do_replay_handle(int side_num, const std::string &do_untill)
|
|||
//if there is nothing more in the records
|
||||
if(cfg == NULL) {
|
||||
//replayer.set_skip(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
// We return if caller wants it for this tag
|
||||
if (!do_untill.empty() && cfg->child(do_untill))
|
||||
{
|
||||
get_replay_source().revert_action();
|
||||
return false;
|
||||
return REPLAY_RETURN_AT_END;
|
||||
}
|
||||
|
||||
config::all_children_itors ch_itors = cfg->all_children_range();
|
||||
|
@ -822,7 +815,7 @@ bool do_replay_handle(int side_num, const std::string &do_untill)
|
|||
verify(*resources::units, child);
|
||||
}
|
||||
|
||||
return true;
|
||||
return REPLAY_FOUND_END_TURN;
|
||||
}
|
||||
else if (const config &change = cfg->child("record_change_controller"))
|
||||
{
|
||||
|
@ -888,7 +881,7 @@ bool do_replay_handle(int side_num, const std::string &do_untill)
|
|||
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();
|
||||
return false;
|
||||
return REPLAY_FOUND_DEPENDENT;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -973,7 +966,7 @@ static std::map<int, config> get_user_choice_internal(const std::string &name, c
|
|||
/*
|
||||
there might be speak or similar commands in the replay before the user input.
|
||||
*/
|
||||
do_replay_handle(current_side, name);
|
||||
do_replay_handle(current_side);
|
||||
|
||||
/*
|
||||
these value might change due to player left/reassign during pull_remote_user_input
|
||||
|
@ -1005,7 +998,7 @@ static std::map<int, config> get_user_choice_internal(const std::string &name, c
|
|||
/* At least one of the decisions is ours, and it will be inserted
|
||||
into the replay. */
|
||||
DBG_REPLAY << "MP synchronization: local choice\n";
|
||||
config cfg = uch.query_user();
|
||||
config cfg = uch.query_user(local_side);
|
||||
|
||||
recorder.user_input(name, cfg, local_side);
|
||||
retv[local_side]= cfg;
|
||||
|
@ -1071,10 +1064,11 @@ static std::map<int, config> get_user_choice_internal(const std::string &name, c
|
|||
std::map<int,config> mp_sync::get_user_choice_multiple_sides(const std::string &name, const mp_sync::user_choice &uch,
|
||||
std::set<int> sides)
|
||||
{
|
||||
//pass sides by copy becasue we need a copy.
|
||||
bool is_synced = synced_context::get_syced_state() == synced_context::SYNCED;
|
||||
//pass sides by copy because we need a copy.
|
||||
const bool is_synced = synced_context::get_syced_state() == synced_context::SYNCED;
|
||||
const int max_side = static_cast<int>(resources::teams->size());
|
||||
|
||||
//we currently don't check for too early because luas sync choice doesn't necessarily show screen dialogs.
|
||||
//It (currently) in the responsibility of the user of sync choice to not use dialogs during prestart events..
|
||||
if(!is_synced)
|
||||
{
|
||||
//we got called from inside luas wesnoth.synchronize_choice or from a select event.
|
||||
|
@ -1083,7 +1077,7 @@ std::map<int,config> mp_sync::get_user_choice_multiple_sides(const std::string &
|
|||
}
|
||||
|
||||
/*
|
||||
for empty sides we want to use reandom choice instead.
|
||||
for empty sides we want to use random choice instead.
|
||||
*/
|
||||
std::set<int> empty_sides;
|
||||
BOOST_FOREACH(int side, sides)
|
||||
|
@ -1104,7 +1098,7 @@ std::map<int,config> mp_sync::get_user_choice_multiple_sides(const std::string &
|
|||
|
||||
BOOST_FOREACH(int side, empty_sides)
|
||||
{
|
||||
retv[side] = uch.random_choice();
|
||||
retv[side] = uch.random_choice(side);
|
||||
}
|
||||
return retv;
|
||||
|
||||
|
@ -1116,25 +1110,34 @@ std::map<int,config> mp_sync::get_user_choice_multiple_sides(const std::string &
|
|||
config mp_sync::get_user_choice(const std::string &name, const mp_sync::user_choice &uch,
|
||||
int side)
|
||||
{
|
||||
bool is_synced = synced_context::get_syced_state() == synced_context::SYNCED;
|
||||
bool is_mp_game = network::nconnections() != 0;
|
||||
bool is_side_null_controlled;
|
||||
const bool is_too_early = resources::gamedata->phase() != game_data::START && resources::gamedata->phase() != game_data::PLAY;
|
||||
const bool is_synced = synced_context::get_syced_state() == synced_context::SYNCED;
|
||||
const bool is_mp_game = network::nconnections() != 0;//Only used in debugging output below
|
||||
const int max_side = static_cast<int>(resources::teams->size());
|
||||
int current_side = resources::controller->current_side();
|
||||
|
||||
const int current_side = resources::controller->current_side();
|
||||
bool is_side_null_controlled;
|
||||
|
||||
if(!is_synced)
|
||||
{
|
||||
//we got called from inside luas wesnoth.synchronize_choice or from a select event.
|
||||
//This doesn't cause problems but someone could use it for example to use a [message][option] inside a wesnoth.synchronize_choice wich could be useful,
|
||||
//we got called from inside luas wesnoth.synchronize_choice or from a select event (or maybe a preload event?).
|
||||
//This doesn't cause problems and someone could use it for example to use a [message][option] inside a wesnoth.synchronize_choice which could be useful,
|
||||
//so just give a warning.
|
||||
WRN_REPLAY << "MP synchronization called during an unsynced context.";;
|
||||
return uch.query_user();
|
||||
return uch.query_user(side);
|
||||
}
|
||||
//technicly we can use mp_sync in start/prestarte events, but the question is wether that makes sense
|
||||
//because it's unclear to decide on which side the function should be executed.
|
||||
//However, for advancements we can just decide on the side that owns the unit and that's in the responsibility of advance_unit_at.
|
||||
if(is_too_early && uch.is_visible())
|
||||
{
|
||||
//We are in a prestart event or even earlier.
|
||||
//Although we are able to sync them, we cannot use query_user,
|
||||
//because we cannot (or shouldn't) put things on the screen inside a prestart event, this is true for SP and MP games.
|
||||
//Quotation form event wiki: "For things displayed on-screen such as character dialog, use start instead"
|
||||
return uch.random_choice(side);
|
||||
}
|
||||
//in start events it's unclear to decide on which side the function should be executed (default= side1 still).
|
||||
//But for advancements we can just decide on the side that owns the unit and that's in the responsibility of advance_unit_at.
|
||||
//For [message][option] and luas sync_choice the scenario designer is responsible for that.
|
||||
//For [get_global_variable] side is never null.
|
||||
|
||||
/*
|
||||
side = 0 should default to the currently active side per definition.
|
||||
*/
|
||||
|
@ -1158,7 +1161,7 @@ config mp_sync::get_user_choice(const std::string &name, const mp_sync::user_cho
|
|||
if (is_side_null_controlled)
|
||||
{
|
||||
DBG_REPLAY << "MP synchronization: side 1 being null-controlled in get_user_choice.\n";
|
||||
//most likeley we are in a start event with an empty side 1
|
||||
//most likely we are in a start event with an empty side 1
|
||||
//but calling [set_global_variable] to an empty side might also cause this.
|
||||
//i think in that case we should better use uch.random_choice(),
|
||||
//which could return something like config_of("invalid", true);
|
||||
|
|
|
@ -154,11 +154,17 @@ replay& get_replay_source();
|
|||
|
||||
extern replay recorder;
|
||||
|
||||
enum REPLAY_RETURN
|
||||
{
|
||||
REPLAY_RETURN_AT_END,
|
||||
REPLAY_FOUND_DEPENDENT,
|
||||
REPLAY_FOUND_END_TURN
|
||||
};
|
||||
//replays up to one turn from the recorder object
|
||||
//returns true if it got to the end of the turn without data running out
|
||||
bool do_replay(int side_num);
|
||||
REPLAY_RETURN do_replay(int side_num);
|
||||
|
||||
bool do_replay_handle(int side_num, const std::string &do_untill);
|
||||
REPLAY_RETURN do_replay_handle(int side_num);
|
||||
|
||||
class replay_network_sender
|
||||
{
|
||||
|
@ -182,8 +188,11 @@ namespace mp_sync {
|
|||
struct user_choice
|
||||
{
|
||||
virtual ~user_choice() {}
|
||||
virtual config query_user() const = 0;
|
||||
virtual config random_choice() const = 0;
|
||||
virtual config query_user(int side) const = 0;
|
||||
virtual config random_choice(int side) const = 0;
|
||||
///whether the choice is visible for the user like an advacement choice
|
||||
///a non-visible choice is for example get_global_variable
|
||||
virtual bool is_visible() const { return true; }
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "gettext.hpp"
|
||||
#include "log.hpp"
|
||||
#include "map_label.hpp"
|
||||
#include "mouse_handler_base.hpp"
|
||||
#include "replay.hpp"
|
||||
#include "random_new_deterministic.hpp"
|
||||
#include "replay_controller.hpp"
|
||||
|
@ -444,7 +445,7 @@ void replay_controller::play_side(const unsigned int /*team_index*/, bool){
|
|||
// if have reached the end we don't want to execute finish_side_turn and finish_turn
|
||||
// becasue we might not have enough data to execute them (like advancements during turn_end for example)
|
||||
// !has_end_turn == we reached the end of teh replay without finding and end turn tag.
|
||||
has_end_turn = do_replay(player_number_);
|
||||
has_end_turn = do_replay(player_number_) == REPLAY_FOUND_END_TURN;
|
||||
if(!has_end_turn)
|
||||
{
|
||||
return;
|
||||
|
@ -548,16 +549,13 @@ bool replay_controller::can_execute_command(const hotkey::hotkey_command& cmd, i
|
|||
return true;
|
||||
|
||||
//commands we only can do before the end of the replay
|
||||
case hotkey::HOTKEY_REPLAY_PLAY:
|
||||
case hotkey::HOTKEY_REPLAY_STOP:
|
||||
return !recorder.at_end();
|
||||
case hotkey::HOTKEY_REPLAY_PLAY:
|
||||
case hotkey::HOTKEY_REPLAY_NEXT_TURN:
|
||||
case hotkey::HOTKEY_REPLAY_NEXT_SIDE:
|
||||
if(recorder.at_end()) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
|
||||
//we have one events_disabler when starting the replay_controller and a second when entering the synced context.
|
||||
return (events::commands_disabled <= 1 ) && !recorder.at_end();
|
||||
default:
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -2655,17 +2655,17 @@ namespace {
|
|||
lua_State *L;
|
||||
lua_synchronize(lua_State *l): L(l) {}
|
||||
|
||||
virtual config query_user() const
|
||||
virtual config query_user(int side) const
|
||||
{
|
||||
config cfg;
|
||||
int index = 1;
|
||||
if (!lua_isnoneornil(L, 2)) {
|
||||
int side = resources::controller->current_side();
|
||||
if ((*resources::teams)[side - 1].is_ai())
|
||||
index = 2;
|
||||
}
|
||||
lua_pushvalue(L, index);
|
||||
if (luaW_pcall(L, 0, 1, false)) {
|
||||
lua_pushnumber(L, side);
|
||||
if (luaW_pcall(L, 1, 1, false)) {
|
||||
if(!luaW_toconfig(L, -1, cfg) && game_config::debug) {
|
||||
chat_message("Lua warning", "function returned to wesnoth.synchronize_choice a table which was partially invalid");
|
||||
}
|
||||
|
@ -2673,10 +2673,14 @@ namespace {
|
|||
return cfg;
|
||||
}
|
||||
|
||||
virtual config random_choice() const
|
||||
virtual config random_choice(int /*side*/) const
|
||||
{
|
||||
return config();
|
||||
}
|
||||
//Although luas sync_choice can show a dialog, (and will in most cases)
|
||||
//we return false to enable other possible things that do not contain UI things.
|
||||
//it's in the responsbility of the umc dev to not show dialogs durign prestart events.
|
||||
virtual bool is_visible() const { return false; }
|
||||
};
|
||||
}//unnamed namespace for lua_synchronize
|
||||
|
||||
|
|
|
@ -221,7 +221,7 @@ config synced_context::ask_server(const std::string &name, const mp_sync::user_c
|
|||
*/
|
||||
while(true){
|
||||
|
||||
do_replay_handle(current_side, name);
|
||||
do_replay_handle(current_side);
|
||||
// the current_side on the server is a lie because it can happen on one client we are already executing side 2
|
||||
bool is_local_side = (*resources::teams)[side-1].is_local();
|
||||
bool is_replay_end = get_replay_source().at_end();
|
||||
|
@ -231,7 +231,7 @@ config synced_context::ask_server(const std::string &name, const mp_sync::user_c
|
|||
/* The decision is ours, and it will be inserted
|
||||
into the replay. */
|
||||
DBG_REPLAY << "MP synchronization: local server choice\n";
|
||||
config cfg = uch.query_user();
|
||||
config cfg = uch.query_user(-1);
|
||||
//-1 for "server" todo: change that.
|
||||
recorder.user_input(name, cfg, -1);
|
||||
return cfg;
|
||||
|
@ -264,7 +264,7 @@ config synced_context::ask_server(const std::string &name, const mp_sync::user_c
|
|||
/* The decision has already been made, and must
|
||||
be extracted from the replay. */
|
||||
DBG_REPLAY << "MP synchronization: replay server choice\n";
|
||||
do_replay_handle(resources::controller->current_side(), name);
|
||||
do_replay_handle(resources::controller->current_side());
|
||||
const config *action = get_replay_source().get_next_action();
|
||||
if (!action)
|
||||
{
|
||||
|
@ -287,19 +287,19 @@ config synced_context::ask_server(const std::string &name, const mp_sync::user_c
|
|||
}
|
||||
|
||||
set_scontext_synced::set_scontext_synced(const std::string& commandname)
|
||||
: new_rng_(synced_context::get_rng_for(commandname)), new_checkup_(recorder.get_last_real_command().child_or_add("checkup"))
|
||||
: new_rng_(synced_context::get_rng_for(commandname)), new_checkup_(recorder.get_last_real_command().child_or_add("checkup")), disabler_()
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
set_scontext_synced::set_scontext_synced()
|
||||
: new_rng_(synced_context::get_rng_for("")), new_checkup_(recorder.get_last_real_command().child_or_add("checkup"))
|
||||
: new_rng_(synced_context::get_rng_for("")), new_checkup_(recorder.get_last_real_command().child_or_add("checkup")), disabler_()
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
set_scontext_synced::set_scontext_synced(int number)
|
||||
: new_rng_(synced_context::get_rng_for("")), new_checkup_(recorder.get_last_real_command().child_or_add("checkup" + boost::lexical_cast<std::string>(number)))
|
||||
: new_rng_(synced_context::get_rng_for("")), new_checkup_(recorder.get_last_real_command().child_or_add("checkup" + boost::lexical_cast<std::string>(number))), disabler_()
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
@ -378,7 +378,7 @@ random_seed_choice::~random_seed_choice()
|
|||
|
||||
}
|
||||
|
||||
config random_seed_choice::query_user() const
|
||||
config random_seed_choice::query_user(int /*side*/) const
|
||||
{
|
||||
//getting here means we are in a sp game
|
||||
|
||||
|
@ -387,7 +387,7 @@ config random_seed_choice::query_user() const
|
|||
retv["new_seed"] = rand();
|
||||
return retv;
|
||||
}
|
||||
config random_seed_choice::random_choice() const
|
||||
config random_seed_choice::random_choice(int /*side*/) const
|
||||
{
|
||||
//it obviously doesn't make sense to call the uninitialized random generator to generatoe a seed ofr the same random generator;
|
||||
//this shoud never happen
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "random_new.hpp"
|
||||
#include "random_new_synced.hpp"
|
||||
#include "generic_event.hpp"
|
||||
#include "mouse_handler_base.hpp"
|
||||
#include <boost/shared_ptr.hpp>
|
||||
class config;
|
||||
|
||||
|
@ -150,6 +151,7 @@ private:
|
|||
boost::shared_ptr<random_new::rng> new_rng_;
|
||||
checkup* old_checkup_;
|
||||
synced_checkup new_checkup_;
|
||||
events::command_disabler disabler_;
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -173,8 +175,8 @@ class random_seed_choice : public mp_sync::user_choice
|
|||
public:
|
||||
random_seed_choice();
|
||||
virtual ~random_seed_choice();
|
||||
virtual config query_user() const;
|
||||
virtual config random_choice() const;
|
||||
virtual config query_user(int /*side*/) const;
|
||||
virtual config random_choice(int /*side*/) const;
|
||||
};
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue