made it so that multiplayer games loaded will start properly

This commit is contained in:
uid68803 2004-01-02 06:05:01 +00:00
parent d43270e6eb
commit 8c4711b6cb
17 changed files with 155 additions and 24 deletions

View file

@ -225,6 +225,10 @@ client_choose_side="Choose your side:"
start_game="Start Game!"
game_cancelled="The game has been cancelled"
waiting_start="Waiting for game to start..."
getting_game_data="Getting game data..."
receive_game_list="Receiving game list..."
connecting_remote="Connecting to remote host..."
kilobytes="KB"
human_controlled="Local Player"
ai_controlled="Computer Player"

View file

@ -111,6 +111,7 @@ std::string read_file(const std::string& fname)
void write_file(const std::string& fname, const std::string& data)
{
log_scope("write_file");
std::ofstream file(fname.c_str());
if(file.bad()) {
std::cerr << "error writing to file: '" << fname << "'\n";
@ -541,13 +542,12 @@ void config::read(const std::string& data,
}
}
std::string config::write() const
void config::write_internal(std::stringstream& res) const
{
std::string res;
for(std::map<std::string,std::string>::const_iterator i = values.begin();
i != values.end(); ++i) {
if(i->second.empty() == false) {
res += i->first + "=\"" + i->second + "\"\n";
res << i->first << "=\"" << i->second << "\"\n";
}
}
@ -556,15 +556,23 @@ std::string config::write() const
const std::vector<config*>& v = j->second;
for(std::vector<config*>::const_iterator it = v.begin();
it != v.end(); ++it) {
res += "[" + j->first + "]\n";
res += (*it)->write();
res += "[/" + j->first + "]\n";
res << "[" << j->first << "]\n";
(*it)->write_internal(res);
res << "[/" << j->first << "]\n";
}
}
res += "\n";
res << "\n";
}
return res;
std::string config::write() const
{
log_scope("config::write");
std::stringstream res;
write_internal(res);
return res.str();
}
config::child_itors config::child_range(const std::string& key)

View file

@ -20,6 +20,7 @@
#include <cassert>
#include <map>
#include <sstream>
#include <string>
#include <vector>
@ -166,6 +167,8 @@ struct config
string_map values;
private:
void write_internal(std::stringstream& str) const;
//a list of all children of this node.
child_map children;

View file

@ -385,7 +385,7 @@ int play_game(int argc, char** argv)
//only play replay data if the user has selected to view the replay,
//or if there is no starting position data to use.
if(!show_replay && state.starting_pos.child("side") == NULL) {
if(!show_replay && state.starting_pos.child("side") != NULL) {
recorder.set_to_end();
}
@ -400,6 +400,13 @@ int play_game(int argc, char** argv)
}
if(state.campaign_type == "multiplayer") {
//make all network players local
for(config::child_itors sides = state.starting_pos.child_range("side");
sides.first != sides.second; ++sides.first) {
if((**sides.first)["controller"] == "network")
(**sides.first)["controller"] = "human";
}
recorder.set_save_info(state);
std::vector<config*> story;

View file

@ -173,6 +173,7 @@ game_state read_game(game_data& data, const config* cfg)
void write_game(const game_state& game, config& cfg)
{
log_scope("write_game");
cfg["label"] = game.label;
cfg["version"] = game_config::version;
@ -267,6 +268,7 @@ void load_game(game_data& data, const std::string& name, game_state& state)
void save_game(const game_state& state)
{
log_scope("save_game");
std::string name = state.label;
std::replace(name.begin(),name.end(),' ','_');

View file

@ -99,10 +99,11 @@ void check_response(network::connection res, const config& data)
}
}
void receive_gamelist(config& data)
void receive_gamelist(display& disp, config& data)
{
for(;;) {
const network::connection res = network::receive_data(data,0,3000);
const network::connection res = gui::network_data_dialog(disp,string_table["receive_game_list"],data);
check_response(res,data);
if(data.child("gamelist")) {
@ -169,7 +170,8 @@ void play_multiplayer_client(display& disp, game_data& units_data, config& cfg,
sock = network::connect(host);
config sides, data;
network::connection data_res = network::receive_data(data,0,10000);
network::connection data_res = gui::network_data_dialog(disp,string_table["connecting_remote"],data);
check_response(data_res,data);
preferences::set_network_host(host);
@ -223,7 +225,7 @@ void play_multiplayer_client(display& disp, game_data& units_data, config& cfg,
first_time = false) {
if(!first_time) {
receive_gamelist(data);
receive_gamelist(disp,data);
}
//if we got a gamelist back - otherwise we have
@ -251,7 +253,7 @@ void play_multiplayer_client(display& disp, game_data& units_data, config& cfg,
}
for(;;) {
data_res = network::receive_data(sides,0,10000);
data_res = gui::network_data_dialog(disp,string_table["getting_game_data"],data);
check_response(data_res,data);
//if we have got valid side data

View file

@ -21,7 +21,9 @@ struct partial_buffer {
size_t upto;
};
std::map<network::connection,partial_buffer> received_data;
typedef std::map<network::connection,partial_buffer> partial_map;
partial_map received_data;
partial_map::const_iterator current_connection = received_data.end();
TCPsocket server_socket;
@ -148,6 +150,7 @@ void disconnect(connection s)
}
received_data.erase(s);
current_connection = received_data.end();
const sockets_list::iterator i = std::find(sockets.begin(),sockets.end(),s);
if(i != sockets.end()) {
@ -212,6 +215,7 @@ connection receive_data(config& cfg, connection connection_num, int timeout)
part_received->second.buf.resize(len);
}
current_connection = part_received;
partial_buffer& buf = part_received->second;
const size_t expected = buf.buf.size() - buf.upto;
@ -225,6 +229,7 @@ connection receive_data(config& cfg, connection connection_num, int timeout)
std::cerr << "received " << nbytes << "=" << buf.upto << "/" << buf.buf.size() << "\n";
if(buf.upto == buf.buf.size()) {
current_connection = received_data.end();
const std::string buffer(buf.buf.begin(),buf.buf.end());
received_data.erase(part_received); //invalidates buf. don't use again
if(buffer == "") {
@ -296,4 +301,12 @@ void send_data_all_except(const config& cfg, connection connection_num)
}
}
std::pair<int,int> current_transfer_stats()
{
if(current_connection == received_data.end())
return std::pair<int,int>(-1,-1);
else
return std::pair<int,int>(current_connection->second.upto,current_connection->second.buf.size());
}
} //end namespace network

View file

@ -77,6 +77,9 @@ void send_data(const config& cfg, connection connection_num=0);
//function to send data to all peers except 'connection_num'
void send_data_all_except(const config& cfg, connection connection_num);
//function to see the number of bytes being processed on the current socket
std::pair<int,int> current_transfer_stats();
struct error
{
error(const std::string& msg, connection sock=0)

View file

@ -16,6 +16,7 @@
#include "hotkeys.hpp"
#include "intro.hpp"
#include "language.hpp"
#include "log.hpp"
#include "mapgen.hpp"
#include "network.hpp"
#include "playlevel.hpp"
@ -200,6 +201,7 @@ LEVEL_RESULT play_level(game_data& gameinfo, config& game_config,
for(std::vector<team>::iterator team_it = teams.begin()+first_player;
team_it != teams.end(); ++team_it) {
log_scope("player turn");
const int player_number = (team_it - teams.begin()) + 1;
//if a side is dead, don't do their turn
@ -279,7 +281,10 @@ LEVEL_RESULT play_level(game_data& gameinfo, config& game_config,
if(game_config::debug)
display::clear_debug_highlights();
std::cerr << "human finished turn...\n";
} else if(!replaying && team_it->is_ai()) {
std::cerr << "is ai...\n";
const hotkey::basic_handler key_events_handler(gui);
const int start_command = recorder.ncommands();

View file

@ -745,13 +745,20 @@ void turn_info::cycle_units()
void turn_info::end_turn()
{
std::cerr << "ending turn...\n";
if(browse_)
return;
end_turn_ = true;
std::cerr << "saving game...\n";
//auto-save
config start_pos;
std::cerr << "writing snapshot...\n";
write_game_snapshot(start_pos);
std::cerr << "doing save...\n";
recorder.save_game(gameinfo_,string_table["auto_save"],start_pos);
std::cerr << "end turn...\n";
recorder.end_turn();
}

View file

@ -107,6 +107,7 @@ bool replay::skipping() const
void replay::save_game(game_data& data, const std::string& label, const config& start_pos)
{
log_scope("replay::save_game");
saveInfo_.starting_pos = start_pos;
saveInfo_.replay_data = cfg_;
saveInfo_.label = label;

View file

@ -31,12 +31,18 @@ report generate_report(TYPE type, const gamemap& map, const unit_map& units,
{
unit_map::const_iterator u = units.end();
if(int(type) >= int(UNIT_REPORTS_BEGIN) && int(type) < int(UNIT_REPORTS_END)
|| type == POSITION) {
u = units.find(mouseover);
if(int(type) >= int(UNIT_REPORTS_BEGIN) && int(type) < int(UNIT_REPORTS_END) || type == POSITION) {
if(!current_team.fogged(mouseover.x,mouseover.y)) {
u = units.find(mouseover);
}
if(u == units.end()) {
u = units.find(loc);
if(u == units.end()) {
if(!current_team.fogged(loc.x,loc.y)) {
u = units.find(loc);
}
if(u == units.end() && type != POSITION) {
return report();
}
}
@ -213,8 +219,9 @@ report generate_report(TYPE type, const gamemap& map, const unit_map& units,
break;
}
case POSITION: {
if(!map.on_board(mouseover))
if(!map.on_board(mouseover)) {
break;
}
str << (mouseover.x+1) << ", " << (mouseover.y+1);

View file

@ -620,6 +620,68 @@ int show_dialog(display& disp, SDL_Surface* image,
return -1;
}
}
namespace {
class dialog_action_receive_network : public gui::dialog_action
{
public:
dialog_action_receive_network(network::connection connection, config& cfg, const std::pair<int,int>& connection_stats);
int do_action();
network::connection result() const;
enum { CONNECTION_COMPLETE = 1, CONNECTION_CONTINUING = 2 };
private:
config& cfg_;
network::connection connection_, res_;
std::pair<int,int> stats_;
};
dialog_action_receive_network::dialog_action_receive_network(network::connection connection, config& cfg,
const std::pair<int,int>& stats)
: cfg_(cfg), connection_(connection), res_(0), stats_(stats)
{
}
int dialog_action_receive_network::do_action()
{
res_ = network::receive_data(cfg_,connection_,100);
if(res_ != 0)
return CONNECTION_COMPLETE;
else if(network::current_transfer_stats().first != stats_.first) {
std::cerr << "continuing connection...\n";
return CONNECTION_CONTINUING;
} else
return CONTINUE_DIALOG;
};
network::connection dialog_action_receive_network::result() const
{
return res_;
}
}
namespace gui {
network::connection network_data_dialog(display& disp, const std::string& msg, config& cfg, network::connection connection_num)
{
for(;;) {
const std::pair<int,int> stats = network::current_transfer_stats();
std::stringstream str;
str << msg;
if(stats.first != -1) {
str << ": " << (stats.first/1024) << "/" << (stats.second/1024) << string_table["kilobytes"];
}
dialog_action_receive_network receiver(connection_num,cfg,stats);
const int res = gui::show_dialog(disp,NULL,"",str.str(),CANCEL_ONLY,NULL,NULL,"",NULL,&receiver);
if(res != int(dialog_action_receive_network::CONNECTION_CONTINUING)) {
return receiver.result();
}
}
}
TITLE_RESULT show_title(display& screen)
{
const events::resize_lock prevent_resizing;

View file

@ -14,11 +14,14 @@
#ifndef SHOW_DIALOG_HPP_INCLUDED
#define SHOW_DIALOG_HPP_INCLUDED
#include "config.hpp"
#include "display.hpp"
#include "SDL.h"
#include "network.hpp"
#include "unit.hpp"
#include "video.hpp"
#include "SDL.h"
#include <string>
#include <vector>
@ -80,6 +83,8 @@ int show_dialog(display& screen, SDL_Surface* image,
std::vector<check_item>* options=NULL
);
network::connection network_data_dialog(display& disp, const std::string& msg, config& cfg, network::connection connection_num=0);
enum TITLE_RESULT { TUTORIAL, NEW_CAMPAIGN, MULTIPLAYER, LOAD_GAME, QUIT_GAME,
CHANGE_LANGUAGE, EDIT_PREFERENCES, SHOW_ABOUT };

View file

@ -33,7 +33,6 @@ button::button(display& disp, const std::string& label, button::TYPE type,
x_(0), y_(0), button_(true),
state_(UNINIT), type_(type)
{
log_scope("button constructor");
if(button_image_name.empty() && type == TYPE_PRESS) {
button_image_name = "button";
} else if(button_image_name.empty() && type == TYPE_CHECK) {

View file

@ -96,6 +96,8 @@ void textbox::draw() const
//if we can't fit the next character on screen
if(pos + area.w > location().w) {
if(cursor_ > i)
++firstOnScreen_;
break;
}

View file

@ -44,7 +44,8 @@ public:
private:
display& disp_;
std::string text_;
unsigned int firstOnScreen_, cursor_;
mutable unsigned int firstOnScreen_;
unsigned int cursor_;
scoped_sdl_surface buffer_;