Implemented automatic saving of game replays.
This commit is contained in:
parent
27c5f6eb4f
commit
3c776a28cf
5 changed files with 67 additions and 5 deletions
|
@ -35,6 +35,8 @@ Version 1.7.0-svn:
|
|||
Czech, German, Finnish, Hebrew, Italian, Russian, Slovak, Turkish
|
||||
* Updated CJK character range
|
||||
* Fixed word wrapping in CJK languages (patch #1140 from sylecn)
|
||||
* Multiplayer server:
|
||||
* Implemented automatic saving of game replays.
|
||||
* User interface:
|
||||
* Fixed bug #13257: Attack dialog always uses the active name of a weapon
|
||||
special
|
||||
|
|
|
@ -138,9 +138,15 @@ The message of the day.
|
|||
.B passwd
|
||||
The password used to gain admin privileges. Usually it starts with `admin '.
|
||||
.TP
|
||||
.B replay_save_path
|
||||
The directory where the server stores game replays. (Don't forget the trailing /!) Defaults to `' which means the directory wesnothd was started in.
|
||||
.TP
|
||||
.B restart_command
|
||||
The command that the server uses to start a new server process via the `restart' command. (Can only be issued via the fifo.)
|
||||
.TP
|
||||
.B save_replays
|
||||
Defines whether the server will automatically save replays of games. (default: \fBfalse\fR)
|
||||
.TP
|
||||
.B versions_accepted
|
||||
A comma separated list of version strings to be accepted by the server. `*' and `?' from wildcard patterns are supported.
|
||||
(defaults to the corresponding wesnoth version)
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
#include "../global.hpp"
|
||||
|
||||
#include "../filesystem.hpp"
|
||||
#include "../game_config.hpp" // game_config::observer_team_name
|
||||
#include "../log.hpp"
|
||||
#include "../map.hpp" // gamemap::MAX_PLAYERS
|
||||
|
@ -53,7 +54,8 @@ namespace wesnothd {
|
|||
int game::id_num = 1;
|
||||
|
||||
game::game(player_map& players, const network::connection host,
|
||||
const std::string name) :
|
||||
const std::string name, bool save_replays,
|
||||
const std::string replay_save_path) :
|
||||
player_info_(&players),
|
||||
id_(id_num++),
|
||||
name_(name),
|
||||
|
@ -72,7 +74,9 @@ game::game(player_map& players, const network::connection host,
|
|||
end_turn_(0),
|
||||
all_observers_muted_(false),
|
||||
bans_(),
|
||||
termination_()
|
||||
termination_(),
|
||||
save_replays_(save_replays),
|
||||
replay_save_path_(replay_save_path)
|
||||
{
|
||||
// Hack to handle the pseudo games lobby_ and not_logged_in_.
|
||||
if (owner_ == 0) return;
|
||||
|
@ -89,6 +93,8 @@ game::game(player_map& players, const network::connection host,
|
|||
|
||||
game::~game()
|
||||
{
|
||||
save_replay();
|
||||
|
||||
user_vector users = all_game_users();
|
||||
for (user_vector::const_iterator u = users.begin(); u != users.end(); ++u) {
|
||||
remove_player(*u, false, true);
|
||||
|
@ -1193,6 +1199,43 @@ void game::send_history(const network::connection sock) const
|
|||
history_.push_back(doc);
|
||||
}
|
||||
|
||||
void game::save_replay() {
|
||||
if (!save_replays_) return;
|
||||
|
||||
std::string replay_commands;
|
||||
for(std::vector<simple_wml::document*>::iterator i = history_.begin();
|
||||
i != history_.end(); ++i) {
|
||||
const simple_wml::node::child_list& turn_list = (*i)->root().children("turn");
|
||||
for (simple_wml::node::child_list::const_iterator turn = turn_list.begin();
|
||||
turn != turn_list.end(); ++turn) {
|
||||
replay_commands += (*turn)->output();
|
||||
}
|
||||
}
|
||||
|
||||
std::stringstream name;
|
||||
name << level_["name"] << " Turn " << current_turn() << " (" << id_ << ").gz";
|
||||
|
||||
std::stringstream replay_data;
|
||||
replay_data << "campaign_type=\"multiplayer\"\n"
|
||||
<< "difficulty=\"NORMAL\"\n"
|
||||
<< "label=\"" << name.str() << "\"\n"
|
||||
<< "version=\"" << level_["version"] << "\"\n"
|
||||
<< "[replay]\n" << replay_commands << "[/replay]\n"
|
||||
<< "[replay_start]\n" << level_.output() << "[/replay_start]\n";
|
||||
|
||||
simple_wml::document replay(replay_data.str().c_str(), simple_wml::INIT_STATIC);
|
||||
|
||||
std::string filename(name.str());
|
||||
std::replace(filename.begin(), filename.end(), ' ', '_');
|
||||
//filename.erase(std::remove(filename.begin(), filename.end(), '\''), filename.end());
|
||||
DBG_GAME << "saving replay: " << filename << std::endl;
|
||||
scoped_ostream os(ostream_file(replay_save_path_ + filename));
|
||||
(*os) << replay.output_compressed();
|
||||
if (!os->good()) {
|
||||
LOG_GAME << "Could not save replay! (" << filename << ")\n";
|
||||
}
|
||||
}
|
||||
|
||||
void game::record_data(simple_wml::document* data) {
|
||||
data->compress();
|
||||
history_.push_back(data);
|
||||
|
|
|
@ -34,7 +34,9 @@ typedef std::vector<network::connection> side_vector;
|
|||
class game
|
||||
{
|
||||
public:
|
||||
game(player_map& players, const network::connection host=0, const std::string name="");
|
||||
game(player_map& players, const network::connection host=0,
|
||||
const std::string name="", bool save_replays=false,
|
||||
const std::string replay_save_path="");
|
||||
~game();
|
||||
|
||||
int id() const { return id_; }
|
||||
|
@ -218,6 +220,7 @@ private:
|
|||
void send_observerjoins(const network::connection sock=0) const;
|
||||
void send_observerquit(const player_map::const_iterator observer) const;
|
||||
void send_history(const network::connection sock) const;
|
||||
void save_replay();
|
||||
|
||||
/** In case of a host transfer, notify the new host about its status. */
|
||||
void notify_new_host();
|
||||
|
@ -306,6 +309,9 @@ private:
|
|||
std::vector<std::string> bans_;
|
||||
|
||||
std::string termination_;
|
||||
|
||||
bool save_replays_;
|
||||
std::string replay_save_path_;
|
||||
};
|
||||
|
||||
struct game_is_member {
|
||||
|
|
|
@ -340,6 +340,8 @@ private:
|
|||
size_t max_ip_log_size_;
|
||||
std::string uh_name_;
|
||||
bool deny_unregistered_login_;
|
||||
bool save_replays_;
|
||||
std::string replay_save_path_;
|
||||
|
||||
/** Parse the server config into local variables. */
|
||||
void load_config();
|
||||
|
@ -521,6 +523,9 @@ void server::load_config() {
|
|||
input_.reset();
|
||||
input_.reset(new input_stream(fifo_path));
|
||||
|
||||
save_replays_ = utils::string_bool(cfg_["save_replays"], false);
|
||||
replay_save_path_ = cfg_["replay_save_path"];
|
||||
|
||||
admin_passwd_ = cfg_["passwd"];
|
||||
motd_ = cfg_["motd"];
|
||||
lan_server_ = lexical_cast_default<time_t>(cfg_["lan_server"], 0);
|
||||
|
@ -1803,7 +1808,7 @@ void server::process_data_lobby(const network::connection sock,
|
|||
<< "\tcreates a new game: \"" << game_name << "\".\n";
|
||||
// Create the new game, remove the player from the lobby
|
||||
// and set the player as the host/owner.
|
||||
games_.push_back(new wesnothd::game(players_, sock, game_name));
|
||||
games_.push_back(new wesnothd::game(players_, sock, game_name, save_replays_, replay_save_path_));
|
||||
wesnothd::game& g = *games_.back();
|
||||
if(game_password.empty() == false) {
|
||||
g.set_password(game_password);
|
||||
|
@ -2026,7 +2031,7 @@ void server::process_data_game(const network::connection sock,
|
|||
//desc[""] = data["objectives"];
|
||||
//desc[""] = data["random_start_time"];
|
||||
//desc[""] = data["turns"];
|
||||
//desc["client_version"] = data["version"];
|
||||
//desc.set_attr_dup("client_version", data["version"]);
|
||||
|
||||
// Record the full scenario in g->level()
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue