Added a more user friendly messagebox when network errors are encountered.
This commit is contained in:
parent
c925665d31
commit
89d3c66471
|
@ -0,0 +1,205 @@
|
|||
// ==============================================================
|
||||
// This file is part of Glest (www.glest.org)
|
||||
//
|
||||
// Copyright (C) 2001-2008 Martiño Figueroa
|
||||
//
|
||||
// You can redistribute this code and/or modify it under
|
||||
// the terms of the GNU General Public License as published
|
||||
// by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version
|
||||
// ==============================================================
|
||||
|
||||
#include "main.h"
|
||||
|
||||
#include <string>
|
||||
#include <cstdlib>
|
||||
|
||||
#include "game.h"
|
||||
#include "main_menu.h"
|
||||
#include "program.h"
|
||||
#include "config.h"
|
||||
#include "metrics.h"
|
||||
#include "game_util.h"
|
||||
#include "platform_util.h"
|
||||
#include "platform_main.h"
|
||||
#include "leak_dumper.h"
|
||||
#include "network_interface.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace Shared::Platform;
|
||||
using namespace Shared::Util;
|
||||
|
||||
namespace Glest{ namespace Game{
|
||||
|
||||
// =====================================================
|
||||
// class ExceptionHandler
|
||||
// =====================================================
|
||||
|
||||
class ExceptionHandler: public PlatformExceptionHandler{
|
||||
public:
|
||||
virtual void handle(){
|
||||
|
||||
string msg = "An error ocurred and Glest will close.\nPlease report this bug to "+mailString+", attaching the generated "+getCrashDumpFileName()+" file.";
|
||||
Program *program = Program::getInstance();
|
||||
if(program) {
|
||||
program->showMessage(msg.c_str());
|
||||
}
|
||||
|
||||
message(msg.c_str());
|
||||
}
|
||||
|
||||
static void handleRuntimeError(const char *msg) {
|
||||
Program *program = Program::getInstance();
|
||||
if(program) {
|
||||
program->showMessage(msg);
|
||||
}
|
||||
else {
|
||||
message("An error ocurred and Glest will close.\nPlease report this bug to "+mailString+", attaching the generated "+getCrashDumpFileName()+" file.");
|
||||
}
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
static int DisplayMessage(const char *msg, bool exitApp) {
|
||||
|
||||
Program *program = Program::getInstance();
|
||||
if(program) {
|
||||
program->showMessage(msg);
|
||||
}
|
||||
else {
|
||||
message(msg);
|
||||
}
|
||||
|
||||
if(exitApp == true) {
|
||||
exit(0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
// =====================================================
|
||||
// class MainWindow
|
||||
// =====================================================
|
||||
|
||||
MainWindow::MainWindow(Program *program){
|
||||
this->program= program;
|
||||
}
|
||||
|
||||
MainWindow::~MainWindow(){
|
||||
delete program;
|
||||
}
|
||||
|
||||
void MainWindow::eventMouseDown(int x, int y, MouseButton mouseButton){
|
||||
switch(mouseButton){
|
||||
case mbLeft:
|
||||
program->mouseDownLeft(x, getH() - y);
|
||||
break;
|
||||
case mbRight:
|
||||
program->mouseDownRight(x, getH() - y);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::eventMouseUp(int x, int y, MouseButton mouseButton){
|
||||
if(mouseButton==mbLeft){
|
||||
program->mouseUpLeft(x, getH() - y);
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::eventMouseDoubleClick(int x, int y, MouseButton mouseButton){
|
||||
if(mouseButton == mbLeft){
|
||||
program->mouseDoubleClickLeft(x, getH() - y);
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::eventMouseMove(int x, int y, const MouseState *ms){
|
||||
program->mouseMove(x, getH() - y, ms);
|
||||
}
|
||||
|
||||
void MainWindow::eventKeyDown(char key){
|
||||
program->keyDown(key);
|
||||
}
|
||||
|
||||
void MainWindow::eventKeyUp(char key){
|
||||
program->keyUp(key);
|
||||
}
|
||||
|
||||
void MainWindow::eventKeyPress(char c){
|
||||
program->keyPress(c);
|
||||
}
|
||||
|
||||
void MainWindow::eventActivate(bool active){
|
||||
if(!active){
|
||||
//minimize();
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::eventResize(SizeState sizeState){
|
||||
program->resize(sizeState);
|
||||
}
|
||||
|
||||
void MainWindow::eventClose(){
|
||||
delete program;
|
||||
program= NULL;
|
||||
}
|
||||
|
||||
// =====================================================
|
||||
// Main
|
||||
// =====================================================
|
||||
|
||||
int glestMain(int argc, char** argv){
|
||||
|
||||
MainWindow *mainWindow= NULL;
|
||||
Program *program= NULL;
|
||||
ExceptionHandler exceptionHandler;
|
||||
exceptionHandler.install( getCrashDumpFileName() );
|
||||
|
||||
try{
|
||||
Config &config = Config::getInstance();
|
||||
|
||||
Socket::enableNetworkDebugInfo = (config.getBool("DebugMode","0") || config.getBool("DebugNetwork","0"));
|
||||
NetworkInterface::setDisplayMessageFunction(ExceptionHandler::DisplayMessage);
|
||||
|
||||
showCursor(config.getBool("Windowed"));
|
||||
|
||||
program= new Program();
|
||||
mainWindow= new MainWindow(program);
|
||||
|
||||
//parse command line
|
||||
if(argc==2 && string(argv[1])=="-server"){
|
||||
program->initServer(mainWindow);
|
||||
}
|
||||
else if(argc==3 && string(argv[1])=="-client"){
|
||||
program->initClient(mainWindow, Ip(argv[2]));
|
||||
}
|
||||
else{
|
||||
program->initNormal(mainWindow);
|
||||
}
|
||||
|
||||
// test
|
||||
//Shared::Platform::MessageBox(NULL,"Mark's test.","Test",0);
|
||||
//throw runtime_error("test!");
|
||||
//ExceptionHandler::DisplayMessage("test!", false);
|
||||
|
||||
//main loop
|
||||
while(Window::handleEvent()){
|
||||
program->loop();
|
||||
}
|
||||
}
|
||||
catch(const exception &e){
|
||||
restoreVideoMode();
|
||||
//exceptionMessage(e);
|
||||
ExceptionHandler::handleRuntimeError(e.what());
|
||||
}
|
||||
|
||||
delete mainWindow;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
}}//end namespace
|
||||
|
||||
MAIN_FUNCTION(Glest::Game::glestMain)
|
|
@ -40,11 +40,71 @@ using namespace Shared::Graphics::Gl;
|
|||
namespace Glest{ namespace Game{
|
||||
|
||||
const int Program::maxTimes= 10;
|
||||
Program *Program::singleton = NULL;
|
||||
|
||||
// =====================================================
|
||||
// class Program::CrashProgramState
|
||||
// =====================================================
|
||||
|
||||
Program::ShowMessageProgramState::ShowMessageProgramState(Program *program, const char *msg) :
|
||||
ProgramState(program) {
|
||||
|
||||
//if(Socket::enableDebugText) printf("In [%s::%s %d]\n",__FILE__,__FUNCTION__,__LINE__);
|
||||
|
||||
msgBox.init("Ok");
|
||||
|
||||
//if(Socket::enableDebugText) printf("In [%s::%s %d]\n",__FILE__,__FUNCTION__,__LINE__);
|
||||
|
||||
if(msg) {
|
||||
fprintf(stderr, "%s\n", msg);
|
||||
msgBox.setText(msg);
|
||||
} else {
|
||||
msgBox.setText("Mega-Glest has crashed.");
|
||||
}
|
||||
//if(Socket::enableDebugText) printf("In [%s::%s %d]\n",__FILE__,__FUNCTION__,__LINE__);
|
||||
|
||||
mouse2dAnim = mouseY = mouseX = 0;
|
||||
this->msg = (msg ? msg : "");
|
||||
|
||||
//if(Socket::enableDebugText) printf("In [%s::%s %d]\n",__FILE__,__FUNCTION__,__LINE__);
|
||||
}
|
||||
|
||||
void Program::ShowMessageProgramState::render() {
|
||||
Renderer &renderer= Renderer::getInstance();
|
||||
renderer.clearBuffers();
|
||||
renderer.reset2d();
|
||||
renderer.renderMessageBox(&msgBox);
|
||||
renderer.renderMouse2d(mouseX, mouseY, mouse2dAnim);
|
||||
renderer.swapBuffers();
|
||||
}
|
||||
|
||||
void Program::ShowMessageProgramState::mouseDownLeft(int x, int y) {
|
||||
//if(Socket::enableDebugText) printf("In [%s::%s %d]\n",__FILE__,__FUNCTION__,__LINE__);
|
||||
|
||||
if(msgBox.mouseClick(x,y)) {
|
||||
|
||||
//if(Socket::enableDebugText) printf("In [%s::%s %d]\n",__FILE__,__FUNCTION__,__LINE__);
|
||||
program->exit();
|
||||
}
|
||||
|
||||
//if(Socket::enableDebugText) printf("In [%s::%s %d]\n",__FILE__,__FUNCTION__,__LINE__);
|
||||
}
|
||||
|
||||
void Program::ShowMessageProgramState::mouseMove(int x, int y, const MouseState &mouseState) {
|
||||
mouseX = x;
|
||||
mouseY = y;
|
||||
msgBox.mouseMove(x, y);
|
||||
}
|
||||
|
||||
void Program::ShowMessageProgramState::update() {
|
||||
mouse2dAnim = (mouse2dAnim +1) % Renderer::maxMouse2dAnim;
|
||||
}
|
||||
|
||||
// ===================== PUBLIC ========================
|
||||
|
||||
Program::Program(){
|
||||
Program::Program() {
|
||||
programState= NULL;
|
||||
singleton = this;
|
||||
}
|
||||
|
||||
void Program::initNormal(WindowGl *window){
|
||||
|
@ -72,11 +132,13 @@ void Program::initClient(WindowGl *window, const Ip &serverIp){
|
|||
|
||||
Program::~Program(){
|
||||
delete programState;
|
||||
programState = NULL;
|
||||
|
||||
Renderer::getInstance().end();
|
||||
|
||||
//restore video mode
|
||||
restoreDisplaySettings();
|
||||
singleton = NULL;
|
||||
}
|
||||
|
||||
void Program::mouseDownLeft(int x, int y){
|
||||
|
@ -160,30 +222,35 @@ void Program::resize(SizeState sizeState){
|
|||
void Program::setState(ProgramState *programState)
|
||||
{
|
||||
|
||||
if(Socket::enableDebugText) printf("In [%s::%s] START\n",__FILE__,__FUNCTION__);
|
||||
//if(Socket::enableDebugText) printf("In [%s::%s] START\n",__FILE__,__FUNCTION__);
|
||||
|
||||
delete this->programState;
|
||||
|
||||
if(Socket::enableDebugText) printf("In [%s::%s] %d\n",__FILE__,__FUNCTION__,__LINE__);
|
||||
//if(Socket::enableDebugText) printf("In [%s::%s] %d\n",__FILE__,__FUNCTION__,__LINE__);
|
||||
|
||||
this->programState= programState;
|
||||
programState->load();
|
||||
|
||||
if(Socket::enableDebugText) printf("In [%s::%s] %d\n",__FILE__,__FUNCTION__,__LINE__);
|
||||
//if(Socket::enableDebugText) printf("In [%s::%s] %d\n",__FILE__,__FUNCTION__,__LINE__);
|
||||
|
||||
programState->init();
|
||||
|
||||
if(Socket::enableDebugText) printf("In [%s::%s] %d\n",__FILE__,__FUNCTION__,__LINE__);
|
||||
//if(Socket::enableDebugText) printf("In [%s::%s] %d\n",__FILE__,__FUNCTION__,__LINE__);
|
||||
|
||||
updateTimer.reset();
|
||||
updateCameraTimer.reset();
|
||||
fpsTimer.reset();
|
||||
|
||||
if(Socket::enableDebugText) printf("In [%s::%s] END\n",__FILE__,__FUNCTION__);
|
||||
//if(Socket::enableDebugText) printf("In [%s::%s] END\n",__FILE__,__FUNCTION__);
|
||||
}
|
||||
|
||||
void Program::exit(){
|
||||
|
||||
//if(Socket::enableDebugText) printf("In [%s::%s %d]\n",__FILE__,__FUNCTION__,__LINE__);
|
||||
|
||||
window->destroy();
|
||||
|
||||
//if(Socket::enableDebugText) printf("In [%s::%s %d]\n",__FILE__,__FUNCTION__,__LINE__);
|
||||
}
|
||||
|
||||
// ==================== PRIVATE ====================
|
||||
|
@ -267,4 +334,35 @@ void Program::restoreDisplaySettings(){
|
|||
}
|
||||
}
|
||||
|
||||
void Program::showMessage(const char *msg) {
|
||||
//if(Socket::enableDebugText) printf("In [%s::%s %d]\n",__FILE__,__FUNCTION__,__LINE__);
|
||||
|
||||
ProgramState *originalState = NULL;
|
||||
if(programState) {
|
||||
//delete programState;
|
||||
originalState = programState;
|
||||
}
|
||||
|
||||
//if(Socket::enableDebugText) printf("In [%s::%s %d]\n",__FILE__,__FUNCTION__,__LINE__);
|
||||
|
||||
programState = new ShowMessageProgramState(this, msg);
|
||||
|
||||
//if(Socket::enableDebugText) printf("In [%s::%s %d]\n",__FILE__,__FUNCTION__,__LINE__);
|
||||
|
||||
while(Window::handleEvent()) {
|
||||
loop();
|
||||
}
|
||||
|
||||
//if(Socket::enableDebugText) printf("In [%s::%s %d]\n",__FILE__,__FUNCTION__,__LINE__);
|
||||
|
||||
delete programState;
|
||||
|
||||
//if(Socket::enableDebugText) printf("In [%s::%s %d]\n",__FILE__,__FUNCTION__,__LINE__);
|
||||
|
||||
programState = originalState;
|
||||
|
||||
//if(Socket::enableDebugText) printf("In [%s::%s %d]\n",__FILE__,__FUNCTION__,__LINE__);
|
||||
}
|
||||
|
||||
|
||||
}}//end namespace
|
||||
|
|
|
@ -0,0 +1,135 @@
|
|||
// ==============================================================
|
||||
// This file is part of Glest (www.glest.org)
|
||||
//
|
||||
// Copyright (C) 2001-2008 Martiño Figueroa
|
||||
//
|
||||
// You can redistribute this code and/or modify it under
|
||||
// the terms of the GNU General Public License as published
|
||||
// by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version
|
||||
// ==============================================================
|
||||
|
||||
#ifndef _GLEST_GAME_PROGRAM_H_
|
||||
#define _GLEST_GAME_PROGRAM_H_
|
||||
|
||||
#include "context.h"
|
||||
#include "platform_util.h"
|
||||
#include "window_gl.h"
|
||||
#include "socket.h"
|
||||
#include "components.h"
|
||||
|
||||
using Shared::Graphics::Context;
|
||||
using Shared::Platform::WindowGl;
|
||||
using Shared::Platform::SizeState;
|
||||
using Shared::Platform::MouseState;
|
||||
using Shared::Platform::PerformanceTimer;
|
||||
using Shared::Platform::Ip;
|
||||
|
||||
namespace Glest{ namespace Game{
|
||||
|
||||
class Program;
|
||||
class MainWindow;
|
||||
|
||||
// =====================================================
|
||||
// class ProgramState
|
||||
//
|
||||
/// Base class for all program states:
|
||||
/// Intro, MainMenu, Game, BattleEnd (State Design pattern)
|
||||
// =====================================================
|
||||
|
||||
class ProgramState{
|
||||
protected:
|
||||
Program *program;
|
||||
|
||||
public:
|
||||
ProgramState(Program *program) {this->program= program;}
|
||||
virtual ~ProgramState(){};
|
||||
|
||||
virtual void render()=0;
|
||||
virtual void update(){};
|
||||
virtual void updateCamera(){};
|
||||
virtual void tick(){};
|
||||
virtual void init(){};
|
||||
virtual void load(){};
|
||||
virtual void end(){};
|
||||
virtual void mouseDownLeft(int x, int y){};
|
||||
virtual void mouseUpLeft(int x, int y){};
|
||||
virtual void mouseDownRight(int x, int y){};
|
||||
virtual void mouseDoubleClickLeft(int x, int y){};
|
||||
virtual void mouseMove(int x, int y, const MouseState *mouseState){};
|
||||
virtual void keyDown(char key){};
|
||||
virtual void keyUp(char key){};
|
||||
virtual void keyPress(char c){};
|
||||
};
|
||||
|
||||
// ===============================
|
||||
// class Program
|
||||
// ===============================
|
||||
|
||||
class Program{
|
||||
private:
|
||||
static const int maxTimes;
|
||||
|
||||
class ShowMessageProgramState : public ProgramState {
|
||||
GraphicMessageBox msgBox;
|
||||
int mouseX;
|
||||
int mouseY;
|
||||
int mouse2dAnim;
|
||||
string msg;
|
||||
|
||||
public:
|
||||
ShowMessageProgramState(Program *program, const char *msg);
|
||||
|
||||
virtual void render();
|
||||
virtual void mouseDownLeft(int x, int y);
|
||||
virtual void mouseMove(int x, int y, const MouseState &mouseState);
|
||||
virtual void update();
|
||||
};
|
||||
|
||||
|
||||
private:
|
||||
ProgramState *programState;
|
||||
|
||||
PerformanceTimer fpsTimer;
|
||||
PerformanceTimer updateTimer;
|
||||
PerformanceTimer updateCameraTimer;
|
||||
|
||||
WindowGl *window;
|
||||
static Program *singleton;
|
||||
|
||||
public:
|
||||
Program();
|
||||
~Program();
|
||||
|
||||
static Program *getInstance() {return singleton;}
|
||||
|
||||
void initNormal(WindowGl *window);
|
||||
void initServer(WindowGl *window);
|
||||
void initClient(WindowGl *window, const Ip &serverIp);
|
||||
|
||||
//main
|
||||
void mouseDownLeft(int x, int y);
|
||||
void mouseUpLeft(int x, int y);
|
||||
void mouseDownRight(int x, int y);
|
||||
void mouseDoubleClickLeft(int x, int y);
|
||||
void mouseMove(int x, int y, const MouseState *mouseState);
|
||||
void keyDown(char key);
|
||||
void keyUp(char key);
|
||||
void keyPress(char c);
|
||||
void loop();
|
||||
void resize(SizeState sizeState);
|
||||
void showMessage(const char *msg);
|
||||
|
||||
//misc
|
||||
void setState(ProgramState *programState);
|
||||
void exit();
|
||||
|
||||
private:
|
||||
void init(WindowGl *window);
|
||||
void setDisplaySettings();
|
||||
void restoreDisplaySettings();
|
||||
};
|
||||
|
||||
}} //end namespace
|
||||
|
||||
#endif
|
|
@ -139,11 +139,14 @@ void ClientInterface::updateLobby()
|
|||
//check consistency
|
||||
if(Config::getInstance().getBool("NetworkConsistencyChecks"))
|
||||
{
|
||||
if(networkMessageIntro.getVersionString()!=getNetworkVersionString())
|
||||
if(networkMessageIntro.getVersionString() != getNetworkVersionString())
|
||||
{
|
||||
string sErr = "Server and client versions do not match (" + networkMessageIntro.getVersionString() + "). You have to use the same binaries.";
|
||||
string sErr = "Server and client binary versions do not match [" + networkMessageIntro.getVersionString() + "]. You have to use the same binaries.";
|
||||
printf("%s\n",sErr.c_str());
|
||||
throw runtime_error(sErr);
|
||||
|
||||
sendTextMessage("Server and client binary mismatch [" + networkMessageIntro.getVersionString() + "]",-1);
|
||||
DisplayErrorMessage(sErr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -319,7 +322,12 @@ void ClientInterface::updateLobby()
|
|||
break;
|
||||
|
||||
default:
|
||||
throw runtime_error(string(__FILE__) + "::" + string(__FUNCTION__) + " Unexpected network message: " + intToStr(networkMessageType));
|
||||
{
|
||||
string sErr = string(__FILE__) + "::" + string(__FUNCTION__) + " Unexpected network message: " + intToStr(networkMessageType);
|
||||
//throw runtime_error(string(__FILE__) + "::" + string(__FUNCTION__) + " Unexpected network message: " + intToStr(networkMessageType));
|
||||
sendTextMessage("Unexpected network message: " + intToStr(networkMessageType),-1);
|
||||
DisplayErrorMessage(sErr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -349,7 +357,11 @@ void ClientInterface::updateKeyframe(int frameCount)
|
|||
//check that we are in the right frame
|
||||
if(networkMessageCommandList.getFrameCount()!=frameCount)
|
||||
{
|
||||
throw runtime_error("Network synchronization error, frame counts do not match");
|
||||
string sErr = "Network synchronization error, frame counts do not match";
|
||||
//throw runtime_error("Network synchronization error, frame counts do not match");
|
||||
sendTextMessage(sErr,-1);
|
||||
DisplayErrorMessage(sErr);
|
||||
return;
|
||||
}
|
||||
|
||||
// give all commands
|
||||
|
@ -388,7 +400,12 @@ void ClientInterface::updateKeyframe(int frameCount)
|
|||
break;
|
||||
|
||||
default:
|
||||
throw runtime_error(string(__FILE__) + "::" + string(__FUNCTION__) + " Unexpected message in client interface: " + intToStr(networkMessageType));
|
||||
{
|
||||
//throw runtime_error(string(__FILE__) + "::" + string(__FUNCTION__) + " Unexpected message in client interface: " + intToStr(networkMessageType));
|
||||
|
||||
sendTextMessage("Unexpected message in client interface: " + intToStr(networkMessageType),-1);
|
||||
DisplayErrorMessage(string(__FILE__) + "::" + string(__FUNCTION__) + " Unexpected message in client interface: " + intToStr(networkMessageType));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -426,7 +443,11 @@ void ClientInterface::waitUntilReady(Checksum* checksum)
|
|||
{
|
||||
if(chrono.getMillis() > readyWaitTimeout)
|
||||
{
|
||||
throw runtime_error("Timeout waiting for server");
|
||||
//throw runtime_error("Timeout waiting for server");
|
||||
string sErr = "Timeout waiting for server";
|
||||
sendTextMessage(sErr,-1);
|
||||
DisplayErrorMessage(sErr);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -442,7 +463,10 @@ void ClientInterface::waitUntilReady(Checksum* checksum)
|
|||
}
|
||||
else
|
||||
{
|
||||
throw runtime_error(string(__FILE__) + "::" + string(__FUNCTION__) + " Unexpected network message: " + intToStr(networkMessageType) );
|
||||
//throw runtime_error(string(__FILE__) + "::" + string(__FUNCTION__) + " Unexpected network message: " + intToStr(networkMessageType) );
|
||||
sendTextMessage("Unexpected network message: " + intToStr(networkMessageType),-1);
|
||||
DisplayErrorMessage(string(__FILE__) + "::" + string(__FUNCTION__) + " Unexpected network message: " + intToStr(networkMessageType));
|
||||
return;
|
||||
}
|
||||
|
||||
// sleep a bit
|
||||
|
@ -456,8 +480,9 @@ void ClientInterface::waitUntilReady(Checksum* checksum)
|
|||
{
|
||||
string sErr = "Checksum error, you don't have the same data as the server";
|
||||
//throw runtime_error("Checksum error, you don't have the same data as the server");
|
||||
printf("%s\n",sErr.c_str());
|
||||
throw runtime_error(sErr);
|
||||
sendTextMessage(sErr,-1);
|
||||
DisplayErrorMessage(sErr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -485,12 +510,18 @@ void ClientInterface::waitForMessage()
|
|||
{
|
||||
if(!isConnected())
|
||||
{
|
||||
throw runtime_error("Disconnected");
|
||||
//throw runtime_error("Disconnected");
|
||||
sendTextMessage("Disconnected",-1);
|
||||
DisplayErrorMessage("Disconnected");
|
||||
return;
|
||||
}
|
||||
|
||||
if(chrono.getMillis()>messageWaitTimeout)
|
||||
{
|
||||
throw runtime_error("Timeout waiting for message");
|
||||
//throw runtime_error("Timeout waiting for message");
|
||||
sendTextMessage("Timeout waiting for message",-1);
|
||||
DisplayErrorMessage("Timeout waiting for message");
|
||||
return;
|
||||
}
|
||||
|
||||
sleep(waitSleepTime);
|
||||
|
|
|
@ -0,0 +1,330 @@
|
|||
// ==============================================================
|
||||
// This file is part of Glest (www.glest.org)
|
||||
//
|
||||
// Copyright (C) 2001-2008 Martiño Figueroa
|
||||
//
|
||||
// You can redistribute this code and/or modify it under
|
||||
// the terms of the GNU General Public License as published
|
||||
// by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version
|
||||
// ==============================================================
|
||||
|
||||
#include "connection_slot.h"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include "conversion.h"
|
||||
#include "game_util.h"
|
||||
#include "config.h"
|
||||
#include "server_interface.h"
|
||||
#include "network_message.h"
|
||||
#include "leak_dumper.h"
|
||||
|
||||
#include "platform_util.h"
|
||||
#include "map.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace Shared::Util;
|
||||
//using namespace Shared::Platform;
|
||||
|
||||
namespace Glest{ namespace Game{
|
||||
|
||||
// =====================================================
|
||||
// class ClientConnection
|
||||
// =====================================================
|
||||
|
||||
ConnectionSlot::ConnectionSlot(ServerInterface* serverInterface, int playerIndex)
|
||||
{
|
||||
this->serverInterface= serverInterface;
|
||||
this->playerIndex= playerIndex;
|
||||
socket= NULL;
|
||||
ready= false;
|
||||
|
||||
networkGameDataSynchCheckOkMap = false;
|
||||
networkGameDataSynchCheckOkTile = false;
|
||||
networkGameDataSynchCheckOkTech = false;
|
||||
networkGameDataSynchCheckOkFogOfWar = false;
|
||||
|
||||
chatText.clear();
|
||||
chatSender.clear();
|
||||
chatTeamIndex= -1;
|
||||
}
|
||||
|
||||
ConnectionSlot::~ConnectionSlot()
|
||||
{
|
||||
if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] START\n",__FILE__,__FUNCTION__);
|
||||
|
||||
close();
|
||||
|
||||
if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] END\n",__FILE__,__FUNCTION__);
|
||||
}
|
||||
|
||||
void ConnectionSlot::update()
|
||||
{
|
||||
update(true);
|
||||
}
|
||||
|
||||
void ConnectionSlot::update(bool checkForNewClients)
|
||||
{
|
||||
if(socket == NULL)
|
||||
{
|
||||
if(networkGameDataSynchCheckOkMap) networkGameDataSynchCheckOkMap = false;
|
||||
if(networkGameDataSynchCheckOkTile) networkGameDataSynchCheckOkTile = false;
|
||||
if(networkGameDataSynchCheckOkTech) networkGameDataSynchCheckOkTech = false;
|
||||
if(networkGameDataSynchCheckOkFogOfWar) networkGameDataSynchCheckOkFogOfWar = false;
|
||||
|
||||
// Is the listener socket ready to be read?
|
||||
//if(serverInterface->getServerSocket()->isReadable() == true)
|
||||
if(checkForNewClients == true)
|
||||
{
|
||||
socket = serverInterface->getServerSocket()->accept();
|
||||
|
||||
//send intro message when connected
|
||||
if(socket != NULL)
|
||||
{
|
||||
if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] accepted new client connection\n",__FILE__,__FUNCTION__);
|
||||
|
||||
chatText.clear();
|
||||
chatSender.clear();
|
||||
chatTeamIndex= -1;
|
||||
|
||||
NetworkMessageIntro networkMessageIntro(getNetworkVersionString(), socket->getHostName(), playerIndex);
|
||||
sendMessage(&networkMessageIntro);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(socket->isConnected())
|
||||
{
|
||||
chatText.clear();
|
||||
chatSender.clear();
|
||||
chatTeamIndex= -1;
|
||||
|
||||
NetworkMessageType networkMessageType= getNextMessageType();
|
||||
|
||||
//process incoming commands
|
||||
switch(networkMessageType){
|
||||
|
||||
case nmtInvalid:
|
||||
break;
|
||||
|
||||
case nmtText:
|
||||
{
|
||||
if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] got nmtText\n",__FILE__,__FUNCTION__);
|
||||
|
||||
NetworkMessageText networkMessageText;
|
||||
if(receiveMessage(&networkMessageText))
|
||||
{
|
||||
chatText = networkMessageText.getText();
|
||||
chatSender = networkMessageText.getSender();
|
||||
chatTeamIndex = networkMessageText.getTeamIndex();
|
||||
|
||||
if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] chatText [%s] chatSender [%s] chatTeamIndex = %d\n",__FILE__,__FUNCTION__,chatText.c_str(),chatSender.c_str(),chatTeamIndex);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
//command list
|
||||
case nmtCommandList: {
|
||||
|
||||
if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] got nmtCommandList\n",__FILE__,__FUNCTION__);
|
||||
|
||||
NetworkMessageCommandList networkMessageCommandList;
|
||||
if(receiveMessage(&networkMessageCommandList))
|
||||
{
|
||||
for(int i= 0; i<networkMessageCommandList.getCommandCount(); ++i)
|
||||
{
|
||||
serverInterface->requestCommand(networkMessageCommandList.getCommand(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
//process intro messages
|
||||
case nmtIntro:
|
||||
{
|
||||
|
||||
if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] got nmtIntro\n",__FILE__,__FUNCTION__);
|
||||
|
||||
NetworkMessageIntro networkMessageIntro;
|
||||
if(receiveMessage(&networkMessageIntro))
|
||||
{
|
||||
name= networkMessageIntro.getName();
|
||||
|
||||
if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] got name [%s]\n",__FILE__,__FUNCTION__,name.c_str());
|
||||
|
||||
if(getAllowGameDataSynchCheck() == true && serverInterface->getGameSettings() != NULL)
|
||||
{
|
||||
if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] sending NetworkMessageSynchNetworkGameData\n",__FILE__,__FUNCTION__);
|
||||
|
||||
NetworkMessageSynchNetworkGameData networkMessageSynchNetworkGameData(serverInterface->getGameSettings());
|
||||
sendMessage(&networkMessageSynchNetworkGameData);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
//process datasynch messages
|
||||
case nmtSynchNetworkGameDataStatus:
|
||||
{
|
||||
|
||||
if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] got nmtSynchNetworkGameDataStatus\n",__FILE__,__FUNCTION__);
|
||||
|
||||
NetworkMessageSynchNetworkGameDataStatus networkMessageSynchNetworkGameDataStatus;
|
||||
if(receiveMessage(&networkMessageSynchNetworkGameDataStatus))
|
||||
{
|
||||
receivedNetworkGameStatus = true;
|
||||
|
||||
int32 tilesetCRC = getFolderTreeContentsCheckSumRecursively(string(GameConstants::folder_path_tilesets) + "/" + serverInterface->getGameSettings()->getTileset() + "/*", ".xml", NULL);
|
||||
int32 techCRC = getFolderTreeContentsCheckSumRecursively(string(GameConstants::folder_path_techs) + "/" + serverInterface->getGameSettings()->getTech() + "/*", ".xml", NULL);
|
||||
Checksum checksum;
|
||||
string file = Map::getMapPath(serverInterface->getGameSettings()->getMap());
|
||||
checksum.addFile(file);
|
||||
int32 mapCRC = checksum.getSum();
|
||||
|
||||
networkGameDataSynchCheckOkMap = (networkMessageSynchNetworkGameDataStatus.getMapCRC() == mapCRC);
|
||||
networkGameDataSynchCheckOkTile = (networkMessageSynchNetworkGameDataStatus.getTilesetCRC() == tilesetCRC);
|
||||
networkGameDataSynchCheckOkTech = (networkMessageSynchNetworkGameDataStatus.getTechCRC() == techCRC);
|
||||
networkGameDataSynchCheckOkFogOfWar = (networkMessageSynchNetworkGameDataStatus.getFogOfWar() == serverInterface->getFogOfWar() == true);
|
||||
|
||||
// For testing
|
||||
//techCRC++;
|
||||
|
||||
if( networkGameDataSynchCheckOkMap == true &&
|
||||
networkGameDataSynchCheckOkTile == true &&
|
||||
networkGameDataSynchCheckOkTech == true &&
|
||||
networkGameDataSynchCheckOkFogOfWar == true)
|
||||
{
|
||||
if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] client data synch ok\n",__FILE__,__FUNCTION__);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] mapCRC = %d, remote = %d\n",__FILE__,__FUNCTION__,mapCRC,networkMessageSynchNetworkGameDataStatus.getMapCRC());
|
||||
if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] tilesetCRC = %d, remote = %d\n",__FILE__,__FUNCTION__,tilesetCRC,networkMessageSynchNetworkGameDataStatus.getTilesetCRC());
|
||||
if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] techCRC = %d, remote = %d\n",__FILE__,__FUNCTION__,techCRC,networkMessageSynchNetworkGameDataStatus.getTechCRC());
|
||||
if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] serverInterface->getFogOfWar() = %d, remote = %d\n",__FILE__,__FUNCTION__,serverInterface->getFogOfWar(),networkMessageSynchNetworkGameDataStatus.getFogOfWar());
|
||||
|
||||
if(allowDownloadDataSynch == true)
|
||||
{
|
||||
// Now get all filenames with their CRC values and send to the client
|
||||
vctFileList.clear();
|
||||
|
||||
if(networkGameDataSynchCheckOkTile == false)
|
||||
{
|
||||
if(tilesetCRC == 0)
|
||||
{
|
||||
vctFileList = getFolderTreeContentsCheckSumListRecursively(string(GameConstants::folder_path_tilesets) + "/" + serverInterface->getGameSettings()->getTileset() + "/*", "", &vctFileList);
|
||||
}
|
||||
else
|
||||
{
|
||||
vctFileList = getFolderTreeContentsCheckSumListRecursively(string(GameConstants::folder_path_tilesets) + "/" + serverInterface->getGameSettings()->getTileset() + "/*", ".xml", &vctFileList);
|
||||
}
|
||||
}
|
||||
if(networkGameDataSynchCheckOkTech == false)
|
||||
{
|
||||
if(techCRC == 0)
|
||||
{
|
||||
vctFileList = getFolderTreeContentsCheckSumListRecursively(string(GameConstants::folder_path_techs) + "/" + serverInterface->getGameSettings()->getTech() + "/*", "", &vctFileList);
|
||||
}
|
||||
else
|
||||
{
|
||||
vctFileList = getFolderTreeContentsCheckSumListRecursively(string(GameConstants::folder_path_techs) + "/" + serverInterface->getGameSettings()->getTech() + "/*", ".xml", &vctFileList);
|
||||
}
|
||||
}
|
||||
if(networkGameDataSynchCheckOkMap == false)
|
||||
{
|
||||
vctFileList.push_back(std::pair<string,int32>(Map::getMapPath(serverInterface->getGameSettings()->getMap()),mapCRC));
|
||||
}
|
||||
|
||||
//for(int i = 0; i < vctFileList.size(); i++)
|
||||
//{
|
||||
NetworkMessageSynchNetworkGameDataFileCRCCheck networkMessageSynchNetworkGameDataFileCRCCheck(vctFileList.size(), 1, vctFileList[0].second, vctFileList[0].first);
|
||||
sendMessage(&networkMessageSynchNetworkGameDataFileCRCCheck);
|
||||
//}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case nmtSynchNetworkGameDataFileCRCCheck:
|
||||
{
|
||||
|
||||
if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] got nmtSynchNetworkGameDataFileCRCCheck\n",__FILE__,__FUNCTION__);
|
||||
|
||||
NetworkMessageSynchNetworkGameDataFileCRCCheck networkMessageSynchNetworkGameDataFileCRCCheck;
|
||||
if(receiveMessage(&networkMessageSynchNetworkGameDataFileCRCCheck))
|
||||
{
|
||||
int fileIndex = networkMessageSynchNetworkGameDataFileCRCCheck.getFileIndex();
|
||||
NetworkMessageSynchNetworkGameDataFileCRCCheck networkMessageSynchNetworkGameDataFileCRCCheck(vctFileList.size(), fileIndex, vctFileList[fileIndex-1].second, vctFileList[fileIndex-1].first);
|
||||
sendMessage(&networkMessageSynchNetworkGameDataFileCRCCheck);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case nmtSynchNetworkGameDataFileGet:
|
||||
{
|
||||
|
||||
if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] got nmtSynchNetworkGameDataFileGet\n",__FILE__,__FUNCTION__);
|
||||
|
||||
NetworkMessageSynchNetworkGameDataFileGet networkMessageSynchNetworkGameDataFileGet;
|
||||
if(receiveMessage(&networkMessageSynchNetworkGameDataFileGet))
|
||||
{
|
||||
FileTransferInfo fileInfo;
|
||||
fileInfo.hostType = eServer;
|
||||
//fileInfo.serverIP = this->ip.getString();
|
||||
fileInfo.serverPort = GameConstants::serverPort;
|
||||
fileInfo.fileName = networkMessageSynchNetworkGameDataFileGet.getFileName();
|
||||
|
||||
FileTransferSocketThread *fileXferThread = new FileTransferSocketThread(fileInfo);
|
||||
fileXferThread->start();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
//throw runtime_error("Unexpected message in connection slot: " + intToStr(networkMessageType));
|
||||
string sErr = "Unexpected message in connection slot: " + intToStr(networkMessageType);
|
||||
//sendTextMessage(sErr,-1);
|
||||
DisplayErrorMessage(sErr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] calling close...\n",__FILE__,__FUNCTION__);
|
||||
|
||||
close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ConnectionSlot::close()
|
||||
{
|
||||
if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] START\n",__FILE__,__FUNCTION__);
|
||||
|
||||
delete socket;
|
||||
socket= NULL;
|
||||
|
||||
chatText.clear();
|
||||
chatSender.clear();
|
||||
chatTeamIndex= -1;
|
||||
|
||||
if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] END\n",__FILE__,__FUNCTION__);
|
||||
}
|
||||
|
||||
bool ConnectionSlot::getFogOfWar()
|
||||
{
|
||||
return networkGameDataSynchCheckOkFogOfWar;
|
||||
}
|
||||
|
||||
bool ConnectionSlot::hasValidSocketId()
|
||||
{
|
||||
bool result = (socket != NULL && socket->getSocketId() > 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
}}//end namespace
|
|
@ -0,0 +1,294 @@
|
|||
// ==============================================================
|
||||
// This file is part of Glest (www.glest.org)
|
||||
//
|
||||
// Copyright (C) 2001-2008 Martiño Figueroa
|
||||
//
|
||||
// You can redistribute this code and/or modify it under
|
||||
// the terms of the GNU General Public License as published
|
||||
// by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version
|
||||
// ==============================================================
|
||||
|
||||
#include "network_interface.h"
|
||||
|
||||
#include <exception>
|
||||
#include <cassert>
|
||||
|
||||
#include "types.h"
|
||||
#include "conversion.h"
|
||||
#include "platform_util.h"
|
||||
|
||||
#include "leak_dumper.h"
|
||||
#include <fstream>
|
||||
|
||||
using namespace Shared::Platform;
|
||||
using namespace Shared::Util;
|
||||
using namespace std;
|
||||
|
||||
namespace Glest{ namespace Game{
|
||||
|
||||
// =====================================================
|
||||
// class NetworkInterface
|
||||
// =====================================================
|
||||
|
||||
const int NetworkInterface::readyWaitTimeout= 60000; //1 minute
|
||||
|
||||
bool NetworkInterface::allowGameDataSynchCheck = false;
|
||||
bool NetworkInterface::allowDownloadDataSynch = false;
|
||||
DisplayMessageFunction NetworkInterface::pCB_DisplayMessage = NULL;
|
||||
|
||||
void NetworkInterface::sendMessage(const NetworkMessage* networkMessage){
|
||||
Socket* socket= getSocket();
|
||||
|
||||
networkMessage->send(socket);
|
||||
}
|
||||
|
||||
NetworkMessageType NetworkInterface::getNextMessageType(bool checkHasDataFirst)
|
||||
{
|
||||
Socket* socket= getSocket();
|
||||
int8 messageType= nmtInvalid;
|
||||
|
||||
if(checkHasDataFirst == false ||
|
||||
(checkHasDataFirst == true &&
|
||||
socket != NULL &&
|
||||
socket->hasDataToRead() == true))
|
||||
{
|
||||
//peek message type
|
||||
int dataSize = socket->getDataToRead();
|
||||
if(dataSize >= sizeof(messageType)){
|
||||
if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] socket->getDataToRead() dataSize = %d\n",__FILE__,__FUNCTION__,dataSize);
|
||||
|
||||
int iPeek = socket->peek(&messageType, sizeof(messageType));
|
||||
|
||||
if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] socket->getDataToRead() iPeek = %d, messageType = %d\n",__FILE__,__FUNCTION__,iPeek,messageType);
|
||||
}
|
||||
|
||||
//sanity check new message type
|
||||
if(messageType<0 || messageType>=nmtCount){
|
||||
throw runtime_error("Invalid message type: " + intToStr(messageType));
|
||||
}
|
||||
}
|
||||
|
||||
return static_cast<NetworkMessageType>(messageType);
|
||||
}
|
||||
|
||||
bool NetworkInterface::receiveMessage(NetworkMessage* networkMessage){
|
||||
|
||||
if(Socket::enableNetworkDebugInfo) printf("In [%s::%s]\n",__FILE__,__FUNCTION__);
|
||||
|
||||
Socket* socket= getSocket();
|
||||
|
||||
return networkMessage->receive(socket);
|
||||
}
|
||||
|
||||
bool NetworkInterface::isConnected(){
|
||||
//if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] START\n",__FILE__,__FUNCTION__);
|
||||
|
||||
bool result = (getSocket()!=NULL && getSocket()->isConnected());
|
||||
|
||||
//if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] END\n",__FILE__,__FUNCTION__);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void NetworkInterface::DisplayErrorMessage(string sErr, bool closeSocket) {
|
||||
if(pCB_DisplayMessage != NULL) {
|
||||
pCB_DisplayMessage(sErr.c_str(), false);
|
||||
}
|
||||
else {
|
||||
throw runtime_error(sErr);
|
||||
}
|
||||
|
||||
if(closeSocket == true && getSocket() != NULL)
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// =====================================================
|
||||
// class GameNetworkInterface
|
||||
// =====================================================
|
||||
|
||||
GameNetworkInterface::GameNetworkInterface(){
|
||||
quit= false;
|
||||
}
|
||||
|
||||
// =====================================================
|
||||
// class FileTransferSocketThread
|
||||
// =====================================================
|
||||
|
||||
const int32 SEND_FILE = 0x20;
|
||||
const int32 ACK = 0x47;
|
||||
|
||||
FileTransferSocketThread::FileTransferSocketThread(FileTransferInfo fileInfo)
|
||||
{
|
||||
this->info = fileInfo;
|
||||
this->info.serverPort += 100;
|
||||
}
|
||||
|
||||
void FileTransferSocketThread::execute()
|
||||
{
|
||||
if(info.hostType == eServer)
|
||||
{
|
||||
ServerSocket serverSocket;
|
||||
//serverSocket.setBlock(false);
|
||||
serverSocket.bind(this->info.serverPort);
|
||||
serverSocket.listen(1);
|
||||
Socket *clientSocket = serverSocket.accept();
|
||||
|
||||
char data[513]="";
|
||||
memset(data, 0, 256);
|
||||
|
||||
clientSocket->receive(data,256);
|
||||
if(*data == SEND_FILE)
|
||||
{
|
||||
FileInfo file;
|
||||
|
||||
memcpy(&file, data+1, sizeof(file));
|
||||
|
||||
*data=ACK;
|
||||
clientSocket->send(data,256);
|
||||
|
||||
Checksum checksum;
|
||||
checksum.addFile(file.fileName);
|
||||
file.filecrc = checksum.getSum();
|
||||
|
||||
ifstream infile(file.fileName.c_str(), ios::in | ios::binary | ios::ate);
|
||||
if(infile.is_open() == true)
|
||||
{
|
||||
file.filesize = infile.tellg();
|
||||
infile.seekg (0, ios::beg);
|
||||
|
||||
memset(data, 0, 256);
|
||||
*data=SEND_FILE;
|
||||
memcpy(data+1,&file,sizeof(file));
|
||||
|
||||
clientSocket->send(data,256);
|
||||
clientSocket->receive(data,256);
|
||||
if(*data != ACK)
|
||||
;//transfer error
|
||||
|
||||
int remain=file.filesize % 512 ;
|
||||
int packs=(file.filesize-remain)/512;
|
||||
|
||||
while(packs--)
|
||||
{
|
||||
infile.read(data,512);
|
||||
//if(!ReadFile(file,data,512,&read,NULL))
|
||||
// ; //read error
|
||||
//if(written!=pack)
|
||||
// ; //read error
|
||||
clientSocket->send(data,512);
|
||||
clientSocket->receive(data,256);
|
||||
if(*data!=ACK)
|
||||
;//transfer error
|
||||
}
|
||||
|
||||
infile.read(data,remain);
|
||||
//if(!ReadFile(file,data,remain,&read,NULL))
|
||||
// ; //read error
|
||||
//if(written!=pack)
|
||||
// ; //read error
|
||||
|
||||
clientSocket->send(data,remain);
|
||||
clientSocket->receive(data,256);
|
||||
if(*data!=ACK)
|
||||
;//transfer error
|
||||
|
||||
infile.close();
|
||||
}
|
||||
}
|
||||
|
||||
delete clientSocket;
|
||||
}
|
||||
else
|
||||
{
|
||||
Ip ip(this->info.serverIP);
|
||||
ClientSocket clientSocket;
|
||||
//clientSocket.setBlock(false);
|
||||
clientSocket.connect(this->info.serverIP, this->info.serverPort);
|
||||
|
||||
if(clientSocket.isConnected() == true)
|
||||
{
|
||||
FileInfo file;
|
||||
file.fileName = this->info.fileName;
|
||||
//file.filesize =
|
||||
//file.filecrc = this->info.
|
||||
|
||||
string path = extractDirectoryPathFromFile(file.fileName);
|
||||
createDirectoryPaths(path);
|
||||
ofstream outFile(file.fileName.c_str(), ios_base::binary | ios_base::out);
|
||||
if(outFile.is_open() == true)
|
||||
{
|
||||
char data[513]="";
|
||||
memset(data, 0, 256);
|
||||
*data=SEND_FILE;
|
||||
memcpy(data+1,&file,sizeof(file));
|
||||
|
||||
clientSocket.send(data,256);
|
||||
clientSocket.receive(data,256);
|
||||
if(*data!=ACK)
|
||||
;//transfer error
|
||||
|
||||
clientSocket.receive(data,256);
|
||||
if(*data == SEND_FILE)
|
||||
{
|
||||
memcpy(&file, data+1, sizeof(file));
|
||||
*data=ACK;
|
||||
clientSocket.send(data,256);
|
||||
|
||||
int remain = file.filesize % 512 ;
|
||||
int packs = (file.filesize-remain) / 512;
|
||||
|
||||
while(packs--)
|
||||
{
|
||||
clientSocket.receive(data,512);
|
||||
|
||||
outFile.write(data, 512);
|
||||
if(outFile.bad())
|
||||
{
|
||||
int ii = 0;
|
||||
}
|
||||
//if(!WriteFile(file,data,512,&written,NULL))
|
||||
// ; //write error
|
||||
//if(written != pack)
|
||||
// ; //write error
|
||||
*data=ACK;
|
||||
clientSocket.send(data,256);
|
||||
}
|
||||
clientSocket.receive(data,remain);
|
||||
|
||||
outFile.write(data, remain);
|
||||
if(outFile.bad())
|
||||
{
|
||||
int ii = 0;
|
||||
}
|
||||
|
||||
//if(!WriteFile(file,data,remain,&written,NULL))
|
||||
// ; //write error
|
||||
//if(written!=pack)
|
||||
// ; //write error
|
||||
*data=ACK;
|
||||
clientSocket.send(data,256);
|
||||
|
||||
Checksum checksum;
|
||||
checksum.addFile(file.fileName);
|
||||
int32 crc = checksum.getSum();
|
||||
if(file.filecrc != crc)
|
||||
{
|
||||
int ii = 0;
|
||||
}
|
||||
|
||||
//if(calc_crc(file)!=info.crc)
|
||||
// ; //transfeer error
|
||||
}
|
||||
|
||||
outFile.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}}//end namespace
|
|
@ -38,6 +38,8 @@ namespace Glest{ namespace Game{
|
|||
// class NetworkInterface
|
||||
// =====================================================
|
||||
|
||||
typedef int (*DisplayMessageFunction)(const char *msg, bool exit);
|
||||
|
||||
class NetworkInterface {
|
||||
|
||||
protected:
|
||||
|
@ -51,6 +53,8 @@ protected:
|
|||
string chatText;
|
||||
string chatSender;
|
||||
int chatTeamIndex;
|
||||
static DisplayMessageFunction pCB_DisplayMessage;
|
||||
void DisplayErrorMessage(string sErr, bool closeSocket=true);
|
||||
|
||||
public:
|
||||
static const int readyWaitTimeout;
|
||||
|
@ -63,6 +67,7 @@ public:
|
|||
virtual const Socket* getSocket() const= 0;
|
||||
virtual void close()= 0;
|
||||
|
||||
static void setDisplayMessageFunction(DisplayMessageFunction pDisplayMessage) { pCB_DisplayMessage = pDisplayMessage; }
|
||||
string getIp() const {return getSocket()->getIp();}
|
||||
string getHostName() const {return getSocket()->getHostName();}
|
||||
|
||||
|
|
|
@ -0,0 +1,409 @@
|
|||
// ==============================================================
|
||||
// This file is part of Glest (www.glest.org)
|
||||
//
|
||||
// Copyright (C) 2001-2008 Martiño Figueroa
|
||||
//
|
||||
// You can redistribute this code and/or modify it under
|
||||
// the terms of the GNU General Public License as published
|
||||
// by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version
|
||||
// ==============================================================
|
||||
|
||||
#include "network_message.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "types.h"
|
||||
#include "util.h"
|
||||
#include "game_settings.h"
|
||||
|
||||
#include "leak_dumper.h"
|
||||
|
||||
#include "checksum.h"
|
||||
#include "map.h"
|
||||
#include "platform_util.h"
|
||||
#include "config.h"
|
||||
|
||||
using namespace Shared::Platform;
|
||||
using namespace Shared::Util;
|
||||
using namespace std;
|
||||
|
||||
namespace Glest{ namespace Game{
|
||||
|
||||
// =====================================================
|
||||
// class NetworkMessage
|
||||
// =====================================================
|
||||
|
||||
bool NetworkMessage::receive(Socket* socket, void* data, int dataSize)
|
||||
{
|
||||
int ipeekdatalen = socket->getDataToRead();
|
||||
|
||||
if(ipeekdatalen >= dataSize)
|
||||
{
|
||||
if(socket->receive(data, dataSize)!=dataSize)
|
||||
{
|
||||
if(socket != NULL && socket->getSocketId() > 0)
|
||||
{
|
||||
throw runtime_error("Error receiving NetworkMessage");
|
||||
}
|
||||
else
|
||||
{
|
||||
if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] socket has been disconnected\n",__FILE__,__FUNCTION__);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] dataSize = %d\n",__FILE__,__FUNCTION__,dataSize);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] socket->getDataToRead() returned %d\n",__FILE__,__FUNCTION__,ipeekdatalen);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void NetworkMessage::send(Socket* socket, const void* data, int dataSize) const
|
||||
{
|
||||
if(socket->send(data, dataSize)!=dataSize)
|
||||
{
|
||||
if(socket != NULL && socket->getSocketId() > 0)
|
||||
{
|
||||
throw runtime_error("Error sending NetworkMessage");
|
||||
}
|
||||
else
|
||||
{
|
||||
if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] socket has been disconnected\n",__FILE__,__FUNCTION__);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// =====================================================
|
||||
// class NetworkMessageIntro
|
||||
// =====================================================
|
||||
|
||||
NetworkMessageIntro::NetworkMessageIntro(){
|
||||
data.messageType= -1;
|
||||
data.playerIndex= -1;
|
||||
}
|
||||
|
||||
NetworkMessageIntro::NetworkMessageIntro(const string &versionString, const string &name, int playerIndex){
|
||||
data.messageType=nmtIntro;
|
||||
data.versionString= versionString;
|
||||
data.name= name;
|
||||
data.playerIndex= static_cast<int16>(playerIndex);
|
||||
}
|
||||
|
||||
bool NetworkMessageIntro::receive(Socket* socket){
|
||||
return NetworkMessage::receive(socket, &data, sizeof(data));
|
||||
}
|
||||
|
||||
void NetworkMessageIntro::send(Socket* socket) const{
|
||||
assert(data.messageType==nmtIntro);
|
||||
NetworkMessage::send(socket, &data, sizeof(data));
|
||||
}
|
||||
|
||||
// =====================================================
|
||||
// class NetworkMessageReady
|
||||
// =====================================================
|
||||
|
||||
NetworkMessageReady::NetworkMessageReady(){
|
||||
data.messageType= nmtReady;
|
||||
}
|
||||
|
||||
NetworkMessageReady::NetworkMessageReady(int32 checksum){
|
||||
data.messageType= nmtReady;
|
||||
data.checksum= checksum;
|
||||
}
|
||||
|
||||
bool NetworkMessageReady::receive(Socket* socket){
|
||||
return NetworkMessage::receive(socket, &data, sizeof(data));
|
||||
}
|
||||
|
||||
void NetworkMessageReady::send(Socket* socket) const{
|
||||
assert(data.messageType==nmtReady);
|
||||
NetworkMessage::send(socket, &data, sizeof(data));
|
||||
}
|
||||
|
||||
// =====================================================
|
||||
// class NetworkMessageLaunch
|
||||
// =====================================================
|
||||
|
||||
NetworkMessageLaunch::NetworkMessageLaunch(){
|
||||
data.messageType=-1;
|
||||
}
|
||||
|
||||
NetworkMessageLaunch::NetworkMessageLaunch(const GameSettings *gameSettings){
|
||||
data.messageType=nmtLaunch;
|
||||
|
||||
data.description= gameSettings->getDescription();
|
||||
data.map= gameSettings->getMap();
|
||||
data.tileset= gameSettings->getTileset();
|
||||
data.tech= gameSettings->getTech();
|
||||
data.factionCount= gameSettings->getFactionCount();
|
||||
data.thisFactionIndex= gameSettings->getThisFactionIndex();
|
||||
data.defaultResources= gameSettings->getDefaultResources();
|
||||
data.defaultUnits= gameSettings->getDefaultUnits();
|
||||
data.defaultVictoryConditions= gameSettings->getDefaultVictoryConditions();
|
||||
|
||||
for(int i= 0; i<data.factionCount; ++i){
|
||||
data.factionTypeNames[i]= gameSettings->getFactionTypeName(i);
|
||||
data.factionControls[i]= gameSettings->getFactionControl(i);
|
||||
data.teams[i]= gameSettings->getTeam(i);
|
||||
data.startLocationIndex[i]= gameSettings->getStartLocationIndex(i);
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkMessageLaunch::buildGameSettings(GameSettings *gameSettings) const{
|
||||
gameSettings->setDescription(data.description.getString());
|
||||
gameSettings->setMap(data.map.getString());
|
||||
gameSettings->setTileset(data.tileset.getString());
|
||||
gameSettings->setTech(data.tech.getString());
|
||||
gameSettings->setFactionCount(data.factionCount);
|
||||
gameSettings->setThisFactionIndex(data.thisFactionIndex);
|
||||
gameSettings->setDefaultResources(data.defaultResources);
|
||||
gameSettings->setDefaultUnits(data.defaultUnits);
|
||||
gameSettings->setDefaultVictoryConditions(data.defaultVictoryConditions);
|
||||
|
||||
for(int i= 0; i<data.factionCount; ++i){
|
||||
gameSettings->setFactionTypeName(i, data.factionTypeNames[i].getString());
|
||||
gameSettings->setFactionControl(i, static_cast<ControlType>(data.factionControls[i]));
|
||||
gameSettings->setTeam(i, data.teams[i]);
|
||||
gameSettings->setStartLocationIndex(i, data.startLocationIndex[i]);
|
||||
}
|
||||
}
|
||||
|
||||
bool NetworkMessageLaunch::receive(Socket* socket){
|
||||
return NetworkMessage::receive(socket, &data, sizeof(data));
|
||||
}
|
||||
|
||||
void NetworkMessageLaunch::send(Socket* socket) const{
|
||||
assert(data.messageType==nmtLaunch);
|
||||
NetworkMessage::send(socket, &data, sizeof(data));
|
||||
}
|
||||
|
||||
// =====================================================
|
||||
// class NetworkMessageLaunch
|
||||
// =====================================================
|
||||
|
||||
NetworkMessageCommandList::NetworkMessageCommandList(int32 frameCount){
|
||||
data.messageType= nmtCommandList;
|
||||
data.frameCount= frameCount;
|
||||
data.commandCount= 0;
|
||||
}
|
||||
|
||||
bool NetworkMessageCommandList::addCommand(const NetworkCommand* networkCommand){
|
||||
if(data.commandCount<maxCommandCount){
|
||||
data.commands[static_cast<int>(data.commandCount)]= *networkCommand;
|
||||
data.commandCount++;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NetworkMessageCommandList::receive(Socket* socket){
|
||||
//return NetworkMessage::receive(socket, &data, sizeof(data));
|
||||
|
||||
// read type, commandCount & frame num first.
|
||||
if (!NetworkMessage::receive(socket, &data, networkPacketMsgTypeSize)) {
|
||||
if(Socket::enableNetworkDebugInfo) printf("In [%s::%s %d] NetworkMessage::receive failed!\n",__FILE__,__FUNCTION__,__LINE__);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(Socket::enableNetworkDebugInfo) printf("In [%s::%s %d] messageType = %d, frameCount = %d, data.commandCount = %d\n",
|
||||
__FILE__,__FUNCTION__,__LINE__,data.messageType,data.frameCount,data.commandCount);
|
||||
|
||||
// read data.commandCount commands.
|
||||
if (data.commandCount) {
|
||||
bool result = NetworkMessage::receive(socket, &data.commands, sizeof(NetworkCommand) * data.commandCount);
|
||||
|
||||
if(Socket::enableNetworkDebugInfo) {
|
||||
for(int idx = 0 ; idx < data.commandCount; ++idx) {
|
||||
const NetworkCommand &cmd = data.commands[idx];
|
||||
|
||||
printf("In [%s::%s %d] index = %d, networkCommandType = %d, unitId = %d, commandTypeId = %d, positionX = %d, positionY = %d, unitTypeId = %d, targetId = %d\n",
|
||||
__FILE__,__FUNCTION__,__LINE__,idx, cmd.getNetworkCommandType(),cmd.getUnitId(), cmd.getCommandTypeId(),
|
||||
cmd.getPosition().x,cmd.getPosition().y, cmd.getUnitTypeId(), cmd.getTargetId());
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void NetworkMessageCommandList::send(Socket* socket) const{
|
||||
assert(data.messageType==nmtCommandList);
|
||||
//NetworkMessage::send(socket, &data, sizeof(data));
|
||||
NetworkMessage::send(socket, &data, networkPacketMsgTypeSize + sizeof(NetworkCommand) * data.commandCount);
|
||||
|
||||
if(Socket::enableNetworkDebugInfo) {
|
||||
printf("In [%s::%s %d] messageType = %d, frameCount = %d, data.commandCount = %d\n",
|
||||
__FILE__,__FUNCTION__,__LINE__,data.messageType,data.frameCount,data.commandCount);
|
||||
|
||||
if (data.commandCount) {
|
||||
for(int idx = 0 ; idx < data.commandCount; ++idx) {
|
||||
const NetworkCommand &cmd = data.commands[idx];
|
||||
|
||||
printf("In [%s::%s %d] index = %d, networkCommandType = %d, unitId = %d, commandTypeId = %d, positionX = %d, positionY = %d, unitTypeId = %d, targetId = %d\n",
|
||||
__FILE__,__FUNCTION__,__LINE__,idx, cmd.getNetworkCommandType(),cmd.getUnitId(), cmd.getCommandTypeId(),
|
||||
cmd.getPosition().x,cmd.getPosition().y, cmd.getUnitTypeId(), cmd.getTargetId());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// =====================================================
|
||||
// class NetworkMessageText
|
||||
// =====================================================
|
||||
|
||||
NetworkMessageText::NetworkMessageText(const string &text, const string &sender, int teamIndex){
|
||||
data.messageType= nmtText;
|
||||
data.text= text;
|
||||
data.sender= sender;
|
||||
data.teamIndex= teamIndex;
|
||||
}
|
||||
|
||||
bool NetworkMessageText::receive(Socket* socket){
|
||||
return NetworkMessage::receive(socket, &data, sizeof(data));
|
||||
}
|
||||
|
||||
void NetworkMessageText::send(Socket* socket) const{
|
||||
assert(data.messageType==nmtText);
|
||||
NetworkMessage::send(socket, &data, sizeof(data));
|
||||
}
|
||||
|
||||
// =====================================================
|
||||
// class NetworkMessageQuit
|
||||
// =====================================================
|
||||
|
||||
NetworkMessageQuit::NetworkMessageQuit(){
|
||||
data.messageType= nmtQuit;
|
||||
}
|
||||
|
||||
bool NetworkMessageQuit::receive(Socket* socket){
|
||||
return NetworkMessage::receive(socket, &data, sizeof(data));
|
||||
}
|
||||
|
||||
void NetworkMessageQuit::send(Socket* socket) const{
|
||||
assert(data.messageType==nmtQuit);
|
||||
NetworkMessage::send(socket, &data, sizeof(data));
|
||||
}
|
||||
|
||||
// =====================================================
|
||||
// class NetworkMessageSynchNetworkGameData
|
||||
// =====================================================
|
||||
|
||||
NetworkMessageSynchNetworkGameData::NetworkMessageSynchNetworkGameData(const GameSettings *gameSettings)
|
||||
{
|
||||
data.messageType= nmtSynchNetworkGameData;
|
||||
|
||||
data.map = gameSettings->getMap();
|
||||
data.tileset = gameSettings->getTileset();
|
||||
data.tech = gameSettings->getTech();
|
||||
|
||||
//Checksum checksum;
|
||||
data.tilesetCRC = getFolderTreeContentsCheckSumRecursively(string(GameConstants::folder_path_tilesets) + "/" + gameSettings->getTileset() + "/*", "xml", NULL);
|
||||
|
||||
//tech, load before map because of resources
|
||||
data.techCRC = getFolderTreeContentsCheckSumRecursively(string(GameConstants::folder_path_techs) + "/" + gameSettings->getTech() + "/*", "xml", NULL);
|
||||
|
||||
//map
|
||||
Checksum checksum;
|
||||
string file = Map::getMapPath(gameSettings->getMap());
|
||||
checksum.addFile(file);
|
||||
data.mapCRC = checksum.getSum();
|
||||
//if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] file = [%s] checksum = %d\n",__FILE__,__FUNCTION__,file.c_str(),data.mapCRC);
|
||||
|
||||
data.hasFogOfWar = Config::getInstance().getBool("FogOfWar");;
|
||||
}
|
||||
|
||||
bool NetworkMessageSynchNetworkGameData::receive(Socket* socket)
|
||||
{
|
||||
return NetworkMessage::receive(socket, &data, sizeof(data));
|
||||
}
|
||||
|
||||
void NetworkMessageSynchNetworkGameData::send(Socket* socket) const
|
||||
{
|
||||
assert(data.messageType==nmtSynchNetworkGameData);
|
||||
NetworkMessage::send(socket, &data, sizeof(data));
|
||||
}
|
||||
|
||||
|
||||
// =====================================================
|
||||
// class NetworkMessageSynchNetworkGameDataStatus
|
||||
// =====================================================
|
||||
|
||||
NetworkMessageSynchNetworkGameDataStatus::NetworkMessageSynchNetworkGameDataStatus(int32 mapCRC, int32 tilesetCRC, int32 techCRC, int8 hasFogOfWar)
|
||||
{
|
||||
data.messageType= nmtSynchNetworkGameDataStatus;
|
||||
|
||||
data.tilesetCRC = tilesetCRC;
|
||||
data.techCRC = techCRC;
|
||||
data.mapCRC = mapCRC;
|
||||
|
||||
data.hasFogOfWar = hasFogOfWar;
|
||||
}
|
||||
|
||||
bool NetworkMessageSynchNetworkGameDataStatus::receive(Socket* socket)
|
||||
{
|
||||
return NetworkMessage::receive(socket, &data, sizeof(data));
|
||||
}
|
||||
|
||||
void NetworkMessageSynchNetworkGameDataStatus::send(Socket* socket) const
|
||||
{
|
||||
assert(data.messageType==nmtSynchNetworkGameDataStatus);
|
||||
NetworkMessage::send(socket, &data, sizeof(data));
|
||||
}
|
||||
|
||||
// =====================================================
|
||||
// class NetworkMessageSynchNetworkGameDataFileCRCCheck
|
||||
// =====================================================
|
||||
|
||||
NetworkMessageSynchNetworkGameDataFileCRCCheck::NetworkMessageSynchNetworkGameDataFileCRCCheck(int32 totalFileCount, int32 fileIndex, int32 fileCRC, const string fileName)
|
||||
{
|
||||
data.messageType= nmtSynchNetworkGameDataFileCRCCheck;
|
||||
|
||||
data.totalFileCount = totalFileCount;
|
||||
data.fileIndex = fileIndex;
|
||||
data.fileCRC = fileCRC;
|
||||
data.fileName = fileName;
|
||||
}
|
||||
|
||||
bool NetworkMessageSynchNetworkGameDataFileCRCCheck::receive(Socket* socket)
|
||||
{
|
||||
return NetworkMessage::receive(socket, &data, sizeof(data));
|
||||
}
|
||||
|
||||
void NetworkMessageSynchNetworkGameDataFileCRCCheck::send(Socket* socket) const
|
||||
{
|
||||
assert(data.messageType==nmtSynchNetworkGameDataFileCRCCheck);
|
||||
NetworkMessage::send(socket, &data, sizeof(data));
|
||||
}
|
||||
|
||||
// =====================================================
|
||||
// class NetworkMessageSynchNetworkGameDataFileGet
|
||||
// =====================================================
|
||||
|
||||
NetworkMessageSynchNetworkGameDataFileGet::NetworkMessageSynchNetworkGameDataFileGet(const string fileName)
|
||||
{
|
||||
data.messageType= nmtSynchNetworkGameDataFileGet;
|
||||
|
||||
data.fileName = fileName;
|
||||
}
|
||||
|
||||
bool NetworkMessageSynchNetworkGameDataFileGet::receive(Socket* socket)
|
||||
{
|
||||
return NetworkMessage::receive(socket, &data, sizeof(data));
|
||||
}
|
||||
|
||||
void NetworkMessageSynchNetworkGameDataFileGet::send(Socket* socket) const
|
||||
{
|
||||
assert(data.messageType==nmtSynchNetworkGameDataFileGet);
|
||||
NetworkMessage::send(socket, &data, sizeof(data));
|
||||
}
|
||||
|
||||
|
||||
}}//end namespace
|
|
@ -0,0 +1,578 @@
|
|||
// ==============================================================
|
||||
// This file is part of Glest (www.glest.org)
|
||||
//
|
||||
// Copyright (C) 2001-2008 Martiño Figueroa
|
||||
//
|
||||
// You can redistribute this code and/or modify it under
|
||||
// the terms of the GNU General Public License as published
|
||||
// by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version
|
||||
// ==============================================================
|
||||
|
||||
#include "server_interface.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "platform_util.h"
|
||||
#include "conversion.h"
|
||||
#include "config.h"
|
||||
#include "lang.h"
|
||||
|
||||
#include "leak_dumper.h"
|
||||
#include "logger.h"
|
||||
#include <time.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace Shared::Platform;
|
||||
using namespace Shared::Util;
|
||||
|
||||
namespace Glest{ namespace Game{
|
||||
|
||||
// =====================================================
|
||||
// class ServerInterface
|
||||
// =====================================================
|
||||
|
||||
ServerInterface::ServerInterface(){
|
||||
gameHasBeenInitiated = false;
|
||||
gameSettingsUpdateCount = 0;
|
||||
|
||||
for(int i= 0; i<GameConstants::maxPlayers; ++i){
|
||||
slots[i]= NULL;
|
||||
}
|
||||
serverSocket.setBlock(false);
|
||||
serverSocket.bind(GameConstants::serverPort);
|
||||
}
|
||||
|
||||
ServerInterface::~ServerInterface(){
|
||||
if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] START\n",__FILE__,__FUNCTION__);
|
||||
|
||||
for(int i= 0; i<GameConstants::maxPlayers; ++i){
|
||||
delete slots[i];
|
||||
}
|
||||
|
||||
close();
|
||||
|
||||
if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] END\n",__FILE__,__FUNCTION__);
|
||||
}
|
||||
|
||||
void ServerInterface::addSlot(int playerIndex){
|
||||
|
||||
if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] START\n",__FILE__,__FUNCTION__);
|
||||
|
||||
assert(playerIndex>=0 && playerIndex<GameConstants::maxPlayers);
|
||||
|
||||
delete slots[playerIndex];
|
||||
slots[playerIndex]= new ConnectionSlot(this, playerIndex);
|
||||
updateListen();
|
||||
|
||||
if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] END\n",__FILE__,__FUNCTION__);
|
||||
}
|
||||
|
||||
void ServerInterface::removeSlot(int playerIndex){
|
||||
|
||||
if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] START\n",__FILE__,__FUNCTION__);
|
||||
|
||||
delete slots[playerIndex];
|
||||
slots[playerIndex]= NULL;
|
||||
updateListen();
|
||||
|
||||
if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] END\n",__FILE__,__FUNCTION__);
|
||||
}
|
||||
|
||||
ConnectionSlot* ServerInterface::getSlot(int playerIndex){
|
||||
return slots[playerIndex];
|
||||
}
|
||||
|
||||
int ServerInterface::getConnectedSlotCount(){
|
||||
int connectedSlotCount= 0;
|
||||
|
||||
for(int i= 0; i<GameConstants::maxPlayers; ++i){
|
||||
if(slots[i]!= NULL){
|
||||
++connectedSlotCount;
|
||||
}
|
||||
}
|
||||
return connectedSlotCount;
|
||||
}
|
||||
|
||||
void ServerInterface::update()
|
||||
{
|
||||
std::map<int,bool> socketTriggeredList;
|
||||
//update all slots
|
||||
for(int i= 0; i < GameConstants::maxPlayers; ++i)
|
||||
{
|
||||
ConnectionSlot* connectionSlot= slots[i];
|
||||
if(connectionSlot != NULL && connectionSlot->getSocket() != NULL &&
|
||||
slots[i]->getSocket()->getSocketId() > 0)
|
||||
{
|
||||
socketTriggeredList[connectionSlot->getSocket()->getSocketId()] = false;
|
||||
}
|
||||
}
|
||||
|
||||
chatText.clear();
|
||||
chatSender.clear();
|
||||
chatTeamIndex= -1;
|
||||
|
||||
if(gameHasBeenInitiated == false || socketTriggeredList.size() > 0)
|
||||
{
|
||||
if(gameHasBeenInitiated && Socket::enableNetworkDebugInfo) printf("In [%s::%s] socketTriggeredList.size() = %d\n",__FILE__,__FUNCTION__,socketTriggeredList.size());
|
||||
|
||||
bool hasData = Socket::hasDataToRead(socketTriggeredList);
|
||||
|
||||
if(hasData && Socket::enableNetworkDebugInfo) printf("In [%s::%s] hasData == true\n",__FILE__,__FUNCTION__);
|
||||
|
||||
if(gameHasBeenInitiated == false || hasData == true)
|
||||
{
|
||||
//if(gameHasBeenInitiated && Socket::enableNetworkDebugInfo) printf("In [%s::%s] hasData == true\n",__FILE__,__FUNCTION__);
|
||||
|
||||
//std::vector<TeamMessageData> vctTeamMessages;
|
||||
|
||||
//update all slots
|
||||
bool checkForNewClients = true;
|
||||
for(int i= 0; i<GameConstants::maxPlayers; ++i)
|
||||
{
|
||||
ConnectionSlot* connectionSlot= slots[i];
|
||||
if(connectionSlot != NULL &&
|
||||
(gameHasBeenInitiated == false || (connectionSlot->getSocket() != NULL && socketTriggeredList[connectionSlot->getSocket()->getSocketId()] == true)))
|
||||
{
|
||||
if(connectionSlot->isConnected() == false ||
|
||||
(socketTriggeredList[connectionSlot->getSocket()->getSocketId()] == true))
|
||||
{
|
||||
if(gameHasBeenInitiated && Socket::enableNetworkDebugInfo) printf("In [%s::%s] socketTriggeredList[i] = %i\n",__FILE__,__FUNCTION__,(socketTriggeredList[connectionSlot->getSocket()->getSocketId()] ? 1 : 0));
|
||||
|
||||
if(connectionSlot->isConnected())
|
||||
{
|
||||
if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] calling slots[i]->update() for slot = %d socketId = %d\n",
|
||||
__FILE__,__FUNCTION__,i,connectionSlot->getSocket()->getSocketId());
|
||||
}
|
||||
else
|
||||
{
|
||||
if(gameHasBeenInitiated && Socket::enableNetworkDebugInfo) printf("In [%s::%s] slot = %d getSocket() == NULL\n",__FILE__,__FUNCTION__,i);
|
||||
}
|
||||
connectionSlot->update(checkForNewClients);
|
||||
|
||||
// This means no clients are trying to connect at the moment
|
||||
if(connectionSlot != NULL && connectionSlot->getSocket() == NULL)
|
||||
{
|
||||
checkForNewClients = false;
|
||||
}
|
||||
|
||||
if(connectionSlot != NULL &&
|
||||
//connectionSlot->isConnected() == true &&
|
||||
connectionSlot->getChatText().empty() == false)
|
||||
{
|
||||
chatText = connectionSlot->getChatText();
|
||||
chatSender = connectionSlot->getChatSender();
|
||||
chatTeamIndex = connectionSlot->getChatTeamIndex();
|
||||
|
||||
//TeamMessageData teamMessageData;
|
||||
//teamMessageData.chatSender = connectionSlot->getChatSender();
|
||||
//teamMessageData.chatText = connectionSlot->getChatText();
|
||||
//teamMessageData.chatTeamIndex = connectionSlot->getChatTeamIndex();
|
||||
//teamMessageData.sourceTeamIndex = i;
|
||||
//vctTeamMessages.push_back(teamMessageData);
|
||||
|
||||
if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] #1 about to broadcast nmtText chatText [%s] chatSender [%s] chatTeamIndex = %d for SlotIndex# %d\n",__FILE__,__FUNCTION__,chatText.c_str(),chatSender.c_str(),chatTeamIndex,i);
|
||||
|
||||
NetworkMessageText networkMessageText(chatText,chatSender,chatTeamIndex);
|
||||
broadcastMessage(&networkMessageText, i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//process text messages
|
||||
if(chatText.empty() == true)
|
||||
{
|
||||
chatText.clear();
|
||||
chatSender.clear();
|
||||
chatTeamIndex= -1;
|
||||
|
||||
for(int i= 0; i< GameConstants::maxPlayers; ++i)
|
||||
{
|
||||
ConnectionSlot* connectionSlot= slots[i];
|
||||
|
||||
if(connectionSlot!= NULL &&
|
||||
(gameHasBeenInitiated == false || (connectionSlot->getSocket() != NULL && socketTriggeredList[connectionSlot->getSocket()->getSocketId()] == true)))
|
||||
{
|
||||
if(connectionSlot->isConnected() && socketTriggeredList[connectionSlot->getSocket()->getSocketId()] == true)
|
||||
{
|
||||
if(connectionSlot->getSocket() != NULL && Socket::enableNetworkDebugInfo) printf("In [%s::%s] calling connectionSlot->getNextMessageType() for slots[i]->getSocket()->getSocketId() = %d\n",
|
||||
__FILE__,__FUNCTION__,connectionSlot->getSocket()->getSocketId());
|
||||
|
||||
if(connectionSlot->getNextMessageType() == nmtText)
|
||||
{
|
||||
NetworkMessageText networkMessageText;
|
||||
if(connectionSlot->receiveMessage(&networkMessageText))
|
||||
{
|
||||
if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] #2 about to broadcast nmtText msg for SlotIndex# %d\n",__FILE__,__FUNCTION__,i);
|
||||
|
||||
broadcastMessage(&networkMessageText, i);
|
||||
chatText= networkMessageText.getText();
|
||||
chatSender= networkMessageText.getSender();
|
||||
chatTeamIndex= networkMessageText.getTeamIndex();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ServerInterface::updateKeyframe(int frameCount){
|
||||
|
||||
NetworkMessageCommandList networkMessageCommandList(frameCount);
|
||||
|
||||
//build command list, remove commands from requested and add to pending
|
||||
while(!requestedCommands.empty()){
|
||||
if(networkMessageCommandList.addCommand(&requestedCommands.back())){
|
||||
pendingCommands.push_back(requestedCommands.back());
|
||||
requestedCommands.pop_back();
|
||||
}
|
||||
else{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//broadcast commands
|
||||
broadcastMessage(&networkMessageCommandList);
|
||||
}
|
||||
|
||||
void ServerInterface::waitUntilReady(Checksum* checksum){
|
||||
|
||||
if(Socket::enableNetworkDebugInfo) printf("In [%s] START\n",__FUNCTION__);
|
||||
|
||||
Logger &logger= Logger::getInstance();
|
||||
gameHasBeenInitiated = true;
|
||||
|
||||
Chrono chrono;
|
||||
bool allReady= false;
|
||||
|
||||
chrono.start();
|
||||
|
||||
//wait until we get a ready message from all clients
|
||||
while(allReady == false)
|
||||
{
|
||||
vector<string> waitingForHosts;
|
||||
allReady= true;
|
||||
for(int i= 0; i<GameConstants::maxPlayers; ++i)
|
||||
{
|
||||
ConnectionSlot* connectionSlot= slots[i];
|
||||
|
||||
if(connectionSlot != NULL && connectionSlot->isConnected() == true)
|
||||
{
|
||||
if(connectionSlot->isReady() == false)
|
||||
{
|
||||
NetworkMessageType networkMessageType= connectionSlot->getNextMessageType(true);
|
||||
NetworkMessageReady networkMessageReady;
|
||||
|
||||
if(networkMessageType == nmtReady &&
|
||||
connectionSlot->receiveMessage(&networkMessageReady))
|
||||
{
|
||||
if(Socket::enableNetworkDebugInfo) printf("In [%s] networkMessageType==nmtReady\n",__FUNCTION__);
|
||||
|
||||
connectionSlot->setReady();
|
||||
}
|
||||
else if(networkMessageType != nmtInvalid)
|
||||
{
|
||||
//throw runtime_error("Unexpected network message: " + intToStr(networkMessageType));
|
||||
string sErr = "Unexpected network message: " + intToStr(networkMessageType);
|
||||
sendTextMessage(sErr,-1);
|
||||
DisplayErrorMessage(sErr);
|
||||
return;
|
||||
}
|
||||
|
||||
waitingForHosts.push_back(connectionSlot->getHostName());
|
||||
|
||||
allReady= false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//check for timeout
|
||||
if(allReady == false)
|
||||
{
|
||||
if(chrono.getMillis() > readyWaitTimeout)
|
||||
{
|
||||
//throw runtime_error("Timeout waiting for clients");
|
||||
string sErr = "Timeout waiting for clients.";
|
||||
sendTextMessage(sErr,-1);
|
||||
DisplayErrorMessage(sErr);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(chrono.getMillis() % 1000 == 0)
|
||||
{
|
||||
string waitForHosts = "";
|
||||
for(int i = 0; i < waitingForHosts.size(); i++)
|
||||
{
|
||||
if(waitForHosts != "")
|
||||
{
|
||||
waitForHosts += ", ";
|
||||
}
|
||||
waitForHosts += waitingForHosts[i];
|
||||
}
|
||||
|
||||
char szBuf[1024]="";
|
||||
sprintf(szBuf,"Waiting for network: %d of %d max seconds (waiting for: %s)",int(chrono.getMillis() / 1000),int(readyWaitTimeout / 1000),waitForHosts.c_str());
|
||||
logger.add(szBuf, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// FOR TESTING ONLY - delay to see the client count up while waiting
|
||||
//sleep(5000);
|
||||
|
||||
if(Socket::enableNetworkDebugInfo) printf("In [%s] PART B (telling client we are ready!\n",__FUNCTION__);
|
||||
|
||||
//send ready message after, so clients start delayed
|
||||
for(int i= 0; i < GameConstants::maxPlayers; ++i)
|
||||
{
|
||||
NetworkMessageReady networkMessageReady(checksum->getSum());
|
||||
|
||||
ConnectionSlot* connectionSlot= slots[i];
|
||||
if(connectionSlot!=NULL)
|
||||
{
|
||||
connectionSlot->sendMessage(&networkMessageReady);
|
||||
}
|
||||
}
|
||||
|
||||
if(Socket::enableNetworkDebugInfo) printf("In [%s] END\n",__FUNCTION__);
|
||||
}
|
||||
|
||||
void ServerInterface::sendTextMessage(const string &text, int teamIndex){
|
||||
NetworkMessageText networkMessageText(text, getHostName(), teamIndex);
|
||||
broadcastMessage(&networkMessageText);
|
||||
}
|
||||
|
||||
void ServerInterface::quitGame(bool userManuallyQuit)
|
||||
{
|
||||
if(userManuallyQuit == true)
|
||||
{
|
||||
string sQuitText = getHostName() + " has chosen to leave the game!";
|
||||
NetworkMessageText networkMessageText(sQuitText,getHostName(),-1);
|
||||
broadcastMessage(&networkMessageText, -1);
|
||||
}
|
||||
|
||||
NetworkMessageQuit networkMessageQuit;
|
||||
broadcastMessage(&networkMessageQuit);
|
||||
}
|
||||
|
||||
string ServerInterface::getNetworkStatus() const{
|
||||
Lang &lang= Lang::getInstance();
|
||||
string str;
|
||||
|
||||
for(int i= 0; i<GameConstants::maxPlayers; ++i){
|
||||
ConnectionSlot* connectionSlot= slots[i];
|
||||
|
||||
str+= intToStr(i)+ ": ";
|
||||
|
||||
if(connectionSlot!= NULL){
|
||||
if(connectionSlot->isConnected()){
|
||||
|
||||
str+= connectionSlot->getName();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
str+= lang.get("NotConnected");
|
||||
}
|
||||
|
||||
str+= '\n';
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
bool ServerInterface::launchGame(const GameSettings* gameSettings){
|
||||
|
||||
bool bOkToStart = true;
|
||||
|
||||
for(int i= 0; i<GameConstants::maxPlayers; ++i)
|
||||
{
|
||||
ConnectionSlot *connectionSlot= slots[i];
|
||||
if(connectionSlot != NULL &&
|
||||
connectionSlot->getAllowDownloadDataSynch() == true &&
|
||||
connectionSlot->isConnected())
|
||||
{
|
||||
if(connectionSlot->getNetworkGameDataSynchCheckOk() == false)
|
||||
{
|
||||
bOkToStart = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(bOkToStart == true)
|
||||
{
|
||||
NetworkMessageLaunch networkMessageLaunch(gameSettings);
|
||||
broadcastMessage(&networkMessageLaunch);
|
||||
}
|
||||
|
||||
return bOkToStart;
|
||||
}
|
||||
|
||||
void ServerInterface::broadcastMessage(const NetworkMessage* networkMessage, int excludeSlot){
|
||||
|
||||
//if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] START\n",__FILE__,__FUNCTION__);
|
||||
|
||||
for(int i= 0; i<GameConstants::maxPlayers; ++i)
|
||||
{
|
||||
ConnectionSlot* connectionSlot= slots[i];
|
||||
|
||||
if(i != excludeSlot && connectionSlot != NULL)
|
||||
{
|
||||
if(connectionSlot->isConnected())
|
||||
{
|
||||
|
||||
if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] before sendMessage\n",__FILE__,__FUNCTION__);
|
||||
connectionSlot->sendMessage(networkMessage);
|
||||
}
|
||||
else if(gameHasBeenInitiated == true)
|
||||
{
|
||||
|
||||
if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] #1 before removeSlot for slot# %d\n",__FILE__,__FUNCTION__,i);
|
||||
removeSlot(i);
|
||||
}
|
||||
}
|
||||
else if(i == excludeSlot && gameHasBeenInitiated == true &&
|
||||
connectionSlot != NULL && connectionSlot->isConnected() == false)
|
||||
{
|
||||
if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] #2 before removeSlot for slot# %d\n",__FILE__,__FUNCTION__,i);
|
||||
removeSlot(i);
|
||||
}
|
||||
}
|
||||
|
||||
//if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] END\n",__FILE__,__FUNCTION__);
|
||||
}
|
||||
|
||||
void ServerInterface::broadcastMessageToConnectedClients(const NetworkMessage* networkMessage, int excludeSlot){
|
||||
|
||||
//if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] START\n",__FILE__,__FUNCTION__);
|
||||
|
||||
for(int i= 0; i<GameConstants::maxPlayers; ++i){
|
||||
ConnectionSlot* connectionSlot= slots[i];
|
||||
|
||||
if(i!= excludeSlot && connectionSlot!= NULL){
|
||||
if(connectionSlot->isConnected()){
|
||||
|
||||
if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] before sendMessage\n",__FILE__,__FUNCTION__);
|
||||
|
||||
connectionSlot->sendMessage(networkMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] END\n",__FILE__,__FUNCTION__);
|
||||
}
|
||||
|
||||
void ServerInterface::updateListen()
|
||||
{
|
||||
int openSlotCount= 0;
|
||||
|
||||
for(int i= 0; i<GameConstants::maxPlayers; ++i)
|
||||
{
|
||||
if(slots[i] != NULL && slots[i]->isConnected() == false)
|
||||
{
|
||||
++openSlotCount;
|
||||
}
|
||||
}
|
||||
|
||||
serverSocket.listen(openSlotCount);
|
||||
}
|
||||
|
||||
void ServerInterface::setGameSettings(GameSettings *serverGameSettings, bool waitForClientAck)
|
||||
{
|
||||
if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] START gameSettingsUpdateCount = %d\n",__FILE__,__FUNCTION__,gameSettingsUpdateCount);
|
||||
|
||||
if(getAllowGameDataSynchCheck() == true)
|
||||
{
|
||||
if(waitForClientAck == true && gameSettingsUpdateCount > 0)
|
||||
{
|
||||
if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] Waiting for client acks #1\n",__FILE__,__FUNCTION__);
|
||||
|
||||
time_t tStart = time(NULL);
|
||||
bool gotAckFromAllClients = false;
|
||||
while(gotAckFromAllClients == false && difftime(time(NULL),tStart) <= 5)
|
||||
{
|
||||
gotAckFromAllClients = true;
|
||||
for(int i= 0; i<GameConstants::maxPlayers; ++i)
|
||||
{
|
||||
ConnectionSlot *connectionSlot = slots[i];
|
||||
if(connectionSlot != NULL && connectionSlot->isConnected())
|
||||
{
|
||||
if(connectionSlot->getReceivedNetworkGameStatus() == false)
|
||||
{
|
||||
gotAckFromAllClients = false;
|
||||
}
|
||||
|
||||
connectionSlot->update();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(int i= 0; i<GameConstants::maxPlayers; ++i)
|
||||
{
|
||||
ConnectionSlot *connectionSlot = slots[i];
|
||||
if(connectionSlot != NULL && connectionSlot->isConnected())
|
||||
{
|
||||
connectionSlot->setReceivedNetworkGameStatus(false);
|
||||
}
|
||||
}
|
||||
|
||||
gameSettings = *serverGameSettings;
|
||||
|
||||
NetworkMessageSynchNetworkGameData networkMessageSynchNetworkGameData(getGameSettings());
|
||||
broadcastMessageToConnectedClients(&networkMessageSynchNetworkGameData);
|
||||
|
||||
if(waitForClientAck == true)
|
||||
{
|
||||
if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] Waiting for client acks #2\n",__FILE__,__FUNCTION__);
|
||||
|
||||
time_t tStart = time(NULL);
|
||||
bool gotAckFromAllClients = false;
|
||||
while(gotAckFromAllClients == false && difftime(time(NULL),tStart) <= 5)
|
||||
{
|
||||
gotAckFromAllClients = true;
|
||||
for(int i= 0; i<GameConstants::maxPlayers; ++i)
|
||||
{
|
||||
ConnectionSlot *connectionSlot = slots[i];
|
||||
if(connectionSlot != NULL && connectionSlot->isConnected())
|
||||
{
|
||||
if(connectionSlot->getReceivedNetworkGameStatus() == false)
|
||||
{
|
||||
gotAckFromAllClients = false;
|
||||
}
|
||||
|
||||
connectionSlot->update();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gameSettingsUpdateCount++;
|
||||
}
|
||||
|
||||
if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] END\n",__FILE__,__FUNCTION__);
|
||||
}
|
||||
|
||||
void ServerInterface::close()
|
||||
{
|
||||
if(Socket::enableNetworkDebugInfo) printf("In [%s::%s] START\n",__FILE__,__FUNCTION__);
|
||||
|
||||
//serverSocket = ServerSocket();
|
||||
}
|
||||
|
||||
bool ServerInterface::getFogOfWar()
|
||||
{
|
||||
return Config::getInstance().getBool("FogOfWar");
|
||||
}
|
||||
|
||||
}}//end namespace
|
Loading…
Reference in New Issue