wesnoth/src/server/game.hpp
Gunter Labes dbe1a5f46d wrapped most of the output_compressed() calls in a try-catch block...
...with trivial error handling and refactored some code along the way
2009-09-02 16:40:40 +00:00

338 lines
11 KiB
C++

/* $Id$ */
/*
Copyright (C) 2003 - 2009 by David White <dave@whitevine.net>
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
or at your option any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
#ifndef GAME_HPP_INCLUDED
#define GAME_HPP_INCLUDED
#include "../network.hpp"
#include "player.hpp"
#include "simple_wml.hpp"
#include <map>
#include <vector>
//class player;
namespace wesnothd {
typedef std::map<network::connection,player> player_map;
typedef std::vector<network::connection> user_vector;
typedef std::vector<network::connection> side_vector;
class game
{
public:
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_; }
const std::string& name() const { return name_; }
bool is_owner(const network::connection player) const { return (player == owner_); }
bool is_member(const network::connection player) const
{ return is_player(player) || is_observer(player); }
bool allow_observers() const;
bool is_observer(const network::connection player) const;
bool is_player(const network::connection player) const;
/** Checks whether the connection's ip address is banned. */
bool player_is_banned(const network::connection player) const;
bool level_init() const { return level_.child("side") != NULL; }
bool started() const { return started_; }
size_t nplayers() const { return players_.size(); }
size_t nobservers() const { return observers_.size(); }
size_t current_turn() const { return (nsides_ ? end_turn_ / nsides_ + 1 : 0); }
void mute_all_observers();
/**
* Mute an observer or give a message of all currently muted observers if no
* name is given.
*/
void mute_observer(const simple_wml::node& mute, const player_map::const_iterator muter);
void unmute_observer(const simple_wml::node& unmute, const player_map::const_iterator unmuter);
/**
* Kick a member by name.
*
* @return The network handle of the removed member if
* successful, '0' otherwise.
*/
network::connection kick_member(const simple_wml::node& kick, const player_map::const_iterator kicker);
/**
* Ban and kick a user by name.
*
* The user does not need to be in this game but logged in.
*
* @return The network handle of the banned player if he
* was in this game, '0' otherwise.
*/
network::connection ban_user(const simple_wml::node& ban, const player_map::const_iterator banner);
void unban_user(const simple_wml::node& unban, const player_map::const_iterator unbanner);
/**
* Add a user to the game.
*
* @return True iff the user successfully joined the game.
*/
bool add_player(const network::connection player, bool observer = false);
/**
* Removes a user from the game.
*
* @return True iff the game ends. That is, if there are
* no more players or the host left on a not yet
* started game.
*/
bool remove_player(const network::connection player, const bool disconnect=false, const bool destruct=false);
/** Adds players and observers into one vector and returns that. */
const user_vector all_game_users() const;
void start_game(const player_map::const_iterator starter);
/** A user (player only?) asks for the next scenario to advance to. */
void load_next_scenario(const player_map::const_iterator user) const;
/** Resets the side configuration according to the scenario data. */
void update_side_data();
/** Let's a player owning a side give it to another player or observer. */
void transfer_side_control(const network::connection sock, const simple_wml::node& cfg);
void process_message(simple_wml::document& data, const player_map::iterator user);
/**
* Handles [end_turn], repackages [commands] with private [speak]s in them
* and sends the data.
* Also filters commands from all but the current player.
* Currently removes all commands but [speak] for observers and all but
* [speak], [label] and [rename] for players.
*
* @returns True if the turn ended.
*/
bool process_turn(simple_wml::document& data, const player_map::const_iterator user);
/**
* Set the description to the number of available slots.
*
* @returns True iff the number of slots has changed.
*/
bool describe_slots();
void send_server_message_to_all(const char* message, network::connection exclude=0) const;
void send_server_message(const char* message, network::connection sock=0, simple_wml::document* doc=NULL) const;
/** Send data to all players in this game except 'exclude'. */
void send_and_record_server_message(const char* message,
const network::connection exclude=0);
void send_data(simple_wml::document& data, const network::connection exclude=0, std::string packet_type = "") const;
void clear_history();
void record_data(simple_wml::document* data);
void save_replay();
/** The full scenario data. */
simple_wml::document& level() { return level_; }
/**
* Functions to set/get the address of the game's summary description as
* sent to players in the lobby.
*/
void set_description(simple_wml::node* desc);
simple_wml::node* description() const { return description_; }
void set_password(const std::string& passwd) { password_ = passwd; }
bool password_matches(const std::string& passwd) const {
return password_.empty() || passwd == password_;
}
const std::string& termination_reason() const {
static const std::string aborted = "aborted";
static const std::string not_started = "not started";
return started_ ? (termination_.empty() ? aborted : termination_) : not_started;
}
void set_termination_reason(const std::string& reason);
private:
//forbidden operations
game(const game&);
void operator=(const game&);
size_t current_side() const { return (nsides_ ? end_turn_ % nsides_ : 0); }
network::connection current_player() const
{ return (nsides_ ? sides_[current_side()] : 0); }
bool is_current_player(const network::connection player) const
{ return (current_player() == player); }
bool is_muted_observer(const network::connection player) const;
bool all_observers_muted() const { return all_observers_muted_; }
void send_muted_observers(const player_map::const_iterator user) const;
bool send_taken_side(simple_wml::document& cfg, const simple_wml::node::child_list::const_iterator side) const;
/**
* Figures out which side to take and tells that side to the game owner.
*
* The owner then should send a [scenario_diff] that implements the side
* change and a subsequent update_side_data() call makes it actually
* happen.
* First we look for a side where save_id= or current_player= matches the
* new user's name then we search for the first controller="network" side.
*/
bool take_side(const player_map::const_iterator user);
/**
* Send [change_controller] message to tell all clients the new controller's name
* or controller type (human or ai).
*/
void change_controller(const size_t side_num,
const network::connection sock,
const std::string& player_name,
const bool player_left = true,
const std::string& controller = "");
void transfer_ai_sides(const network::connection player);
void send_leave_game(network::connection user) const;
void send_data_team(simple_wml::document& data, const simple_wml::string_span& team,
const network::connection exclude=0, std::string packet_type = "") const;
void send_data_observers(simple_wml::document& data, const network::connection exclude=0, std::string packet_type = "") const;
/**
* Send [observer] tags of all the observers in the game to the user or
* everyone if none given.
*/
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;
/** In case of a host transfer, notify the new host about its status. */
void notify_new_host();
/** Shortcut to a convenience function for finding a user by name. */
player_map::const_iterator find_user(const simple_wml::string_span& name) const;
bool observers_can_label() const { return false; }
bool observers_can_chat() const { return true; }
bool is_legal_command(const simple_wml::node& command, bool is_player);
/**
* Function which returns true iff 'player' is on 'team'.
* AI controlled sides are not considered on a team.
*/
bool is_on_team(const simple_wml::string_span& team, const network::connection player) const;
/**
* Checks whether a user has the same IP as members of this game.
* If observer is true it only checks against players.
* @return A comma separated string of members with matching IPs.
*/
std::string has_same_ip(const network::connection& user, bool observer) const;
/**
* Function which should be called every time a player ends their turn
* (i.e. [end_turn] received). This will update the 'turn' attribute for
* the game's description when appropriate. Will return true iff there has
* been a change.
*/
bool end_turn();
/**
* Function to send a list of users to all clients.
*
* Only sends data if the game is initialized but not yet started.
*/
void send_user_list(const network::connection exclude=0) const;
/** Helps debugging player and observer lists. */
std::string debug_player_info() const;
player_map* player_info_;
static int id_num;
int id_;
/** The name of the game. */
std::string name_;
std::string password_;
/** The game host or later owner (if the host left). */
network::connection owner_;
/** A vector of players (members owning a side). */
user_vector players_;
/** A vector of observers (members not owning a side). */
user_vector observers_;
user_vector muted_observers_;
/** A vector of side owners. */
side_vector sides_;
/**
* A vector of controller strings indicating the type.
* "human" - a side controlled by a human
* "ai" - a side controlled by an AI
* "null" - an empty side
*/
std::vector<std::string> side_controllers_;
/** Number of sides in the current scenario. */
int nsides_;
bool started_;
/** The current scenario data. */
simple_wml::document level_;
/** Replay data. */
mutable std::vector<simple_wml::document*> history_;
/** Pointer to the game's description in the games_and_users_list_. */
simple_wml::node* description_;
int end_turn_;
bool all_observers_muted_;
std::vector<std::string> bans_;
std::string termination_;
bool save_replays_;
std::string replay_save_path_;
};
struct game_is_member {
game_is_member(network::connection sock) : sock_(sock) {};
bool operator()(const game* g) const { return g->is_owner(sock_) || g->is_member(sock_); }
private:
network::connection sock_;
};
struct game_id_matches {
game_id_matches(int id) : id_(id) {};
bool operator()(const game* g) const { return g->id() == id_; }
private:
int id_;
};
}
#endif