Implement a new class, save_blocker,
...analogous to input_blocker and update_locker, which effectively masks requests to save the game and processes them after the save_blocker has been destructed. Wrap one around playsingle_controller::init_side(), fixing bug #9496. See also bug #13298.
This commit is contained in:
parent
14d928b2cd
commit
3e874fdb86
4 changed files with 94 additions and 11 deletions
|
@ -27,7 +27,7 @@
|
|||
#include "sound.hpp"
|
||||
#include "unit_id.hpp"
|
||||
#include "terrain_filter.hpp"
|
||||
|
||||
#include "savegame.hpp"
|
||||
|
||||
#define LOG_NG LOG_STREAM(info, engine)
|
||||
|
||||
|
@ -286,15 +286,30 @@ void play_controller::status_table(){
|
|||
}
|
||||
|
||||
void play_controller::save_game(){
|
||||
menu_handler_.save_game("",gui::OK_CANCEL);
|
||||
if(save_blocker::try_block()) {
|
||||
save_blocker::save_unblocker unblocker;
|
||||
menu_handler_.save_game("",gui::OK_CANCEL);
|
||||
} else {
|
||||
save_blocker::on_unblock(this,&play_controller::save_game);
|
||||
}
|
||||
}
|
||||
|
||||
void play_controller::save_replay(){
|
||||
menu_handler_.save_replay("", gui::OK_CANCEL, false);
|
||||
if(save_blocker::try_block()) {
|
||||
save_blocker::save_unblocker unblocker;
|
||||
menu_handler_.save_game("", gui::OK_CANCEL, false);
|
||||
} else {
|
||||
save_blocker::on_unblock(this,&play_controller::save_replay);
|
||||
}
|
||||
}
|
||||
|
||||
void play_controller::save_map(){
|
||||
menu_handler_.save_map();
|
||||
if(save_blocker::try_block()) {
|
||||
save_blocker::save_unblocker unblocker;
|
||||
menu_handler_.save_map();
|
||||
} else {
|
||||
save_blocker::on_unblock(this,&play_controller::save_map);
|
||||
}
|
||||
}
|
||||
|
||||
void play_controller::load_game(){
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include "upload_log.hpp"
|
||||
#include "formula_string_utils.hpp"
|
||||
#include "events.hpp"
|
||||
#include "savegame.hpp"
|
||||
|
||||
#define ERR_NG LOG_STREAM(err, engine)
|
||||
#define LOG_NG LOG_STREAM(info, engine)
|
||||
|
@ -529,13 +530,7 @@ void playsingle_controller::play_turn(bool save)
|
|||
skip_next_turn_ = false;
|
||||
throw end_turn_exception();
|
||||
}
|
||||
/*
|
||||
* Commented this out at dfranke's request,
|
||||
* effectively reverting his commit 34278,
|
||||
* because it introduced blocker bug #13298:
|
||||
* reproducible hang in dialog code
|
||||
*/
|
||||
//input_blocker blocker;
|
||||
save_blocker blocker;
|
||||
init_side(player_number_ - 1);
|
||||
} catch (end_turn_exception) {
|
||||
if (current_team().is_network() == false) {
|
||||
|
|
|
@ -22,6 +22,51 @@
|
|||
|
||||
#define LOG_SAVE LOG_STREAM(info, engine)
|
||||
|
||||
|
||||
play_controller* save_blocker::controller_ = NULL;
|
||||
void (play_controller::*save_blocker::callback_)() = NULL;
|
||||
SDL_sem* save_blocker::sem_ = SDL_CreateSemaphore(1);
|
||||
|
||||
save_blocker::save_blocker() {
|
||||
block();
|
||||
}
|
||||
|
||||
save_blocker::~save_blocker() {
|
||||
unblock();
|
||||
if(controller_ && callback_) {
|
||||
(controller_->*callback_)();
|
||||
controller_ = NULL;
|
||||
callback_ = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void save_blocker::on_unblock(play_controller* controller, void (play_controller::*callback)()) {
|
||||
if(try_block()) {
|
||||
unblock();
|
||||
(controller->*callback)();
|
||||
} else {
|
||||
controller_ = controller;
|
||||
callback_ = callback;
|
||||
}
|
||||
}
|
||||
|
||||
bool save_blocker::saves_are_blocked() {
|
||||
return SDL_SemValue(sem_) == 0;
|
||||
}
|
||||
|
||||
void save_blocker::block() {
|
||||
SDL_SemWait(sem_);
|
||||
}
|
||||
|
||||
bool save_blocker::try_block() {
|
||||
return SDL_SemTryWait(sem_) == 0;
|
||||
}
|
||||
|
||||
void save_blocker::unblock() {
|
||||
assert(SDL_SemValue(sem_) == 0);
|
||||
SDL_SemPost(sem_);
|
||||
}
|
||||
|
||||
// Prototypes
|
||||
|
||||
// Interactive replay save
|
||||
|
|
|
@ -18,9 +18,37 @@
|
|||
|
||||
#include "global.hpp"
|
||||
#include "gamestatus.hpp"
|
||||
#include "play_controller.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "SDL_mutex.h"
|
||||
|
||||
class save_blocker {
|
||||
public:
|
||||
save_blocker();
|
||||
~save_blocker();
|
||||
static bool saves_are_blocked();
|
||||
static void on_unblock(play_controller* controller, void (play_controller::*callback)());
|
||||
|
||||
protected:
|
||||
friend class play_controller;
|
||||
static void block();
|
||||
static bool try_block();
|
||||
static void unblock();
|
||||
|
||||
class save_unblocker {
|
||||
public:
|
||||
save_unblocker() {}
|
||||
~save_unblocker() { save_blocker::unblock(); }
|
||||
};
|
||||
|
||||
private:
|
||||
static play_controller *controller_;
|
||||
static void (play_controller::*callback_)();
|
||||
static SDL_sem* sem_;
|
||||
};
|
||||
|
||||
/** Autosave */
|
||||
std::string save_autosave(unsigned turn, const config& snapshot, game_state& gamestate);
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue