1) Added kart_packet files to Makefile.am
2) Improvements to network managers (finite state machine) and to the network GUI. git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/trunk/supertuxkart@2235 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
parent
ed1d4b0192
commit
3ccd8500de
@ -30,9 +30,14 @@ supertuxkart_SOURCES = main.cpp \
|
||||
coord.hpp \
|
||||
actionmap.cpp actionmap.hpp \
|
||||
material.cpp material.hpp \
|
||||
network/network_manager.cpp network/network_manager.hpp \
|
||||
network/network_kart.cpp network/network_kart.hpp \
|
||||
network/remote_kart_info.hpp \
|
||||
network/network_manager.cpp network/network_manager.hpp \
|
||||
network/network_kart.cpp network/network_kart.hpp \
|
||||
network/race_info_message.hpp network/race_info_message.cpp \
|
||||
network/remote_kart_info.hpp network/character_selected_message.hpp \
|
||||
network/race_start_message.hpp network/connect_message.hpp \
|
||||
network.num_players_message.hpp network/world_loaded_message.hpp \
|
||||
network/connect_message.hpp network/character_info_message.hpp \
|
||||
network/message.cpp network/message.hpp \
|
||||
material_manager.cpp material_manager.hpp \
|
||||
grand_prix_manager.cpp grand_prix_manager.hpp \
|
||||
attachment.cpp attachment.hpp \
|
||||
@ -112,20 +117,19 @@ supertuxkart_SOURCES = main.cpp \
|
||||
gui/track_sel.cpp gui/track_sel.hpp \
|
||||
gui/player_controls.cpp gui/player_controls.hpp \
|
||||
gui/config_display.cpp gui/config_display.hpp \
|
||||
gui/display_res_confirm.cpp gui/display_res_confirm.hpp \
|
||||
gui/display_res_confirm.cpp gui/display_res_confirm.hpp \
|
||||
gui/config_sound.cpp gui/config_sound.hpp \
|
||||
gui/config_controls.cpp gui/config_controls.hpp \
|
||||
gui/options.cpp gui/options.hpp \
|
||||
gui/game_mode.cpp gui/game_mode.hpp \
|
||||
gui/race_options.cpp gui/race_options.hpp \
|
||||
gui/race_options.cpp gui/race_options.hpp \
|
||||
gui/char_sel.cpp gui/char_sel.hpp \
|
||||
gui/start_race_feedback.cpp gui/start_race_feedback.hpp \
|
||||
gui/network_info.cpp gui/network_info.hpp \
|
||||
gui/start_race_feedback.cpp gui/start_race_feedback.hpp \
|
||||
gui/network_gui.cpp gui/network_gui.hpp \
|
||||
gui/main_menu.cpp gui/main_menu.hpp \
|
||||
gui/help_page_one.cpp gui/help_page_one.hpp \
|
||||
gui/help_page_two.cpp gui/help_page_two.hpp \
|
||||
gui/help_page_three.cpp gui/help_page_three.hpp \
|
||||
gui/help_page_one.cpp gui/help_page_one.hpp \
|
||||
gui/help_page_two.cpp gui/help_page_two.hpp \
|
||||
gui/help_page_three.cpp gui/help_page_three.hpp \
|
||||
gui/credits_menu.cpp gui/credits_menu.hpp \
|
||||
gui/grand_prix_select.cpp gui/grand_prix_select.hpp \
|
||||
gui/challenges_menu.cpp gui/challenges_menu.hpp \
|
||||
|
@ -162,6 +162,7 @@ void GameManager::run()
|
||||
#if !defined(WIN32) && !defined(__CYGWIN__)
|
||||
// usleep(2000);
|
||||
#endif
|
||||
|
||||
//Draw the splash screen
|
||||
glBindTexture(GL_TEXTURE_2D,TITLE_SCREEN_TEXTURE);
|
||||
|
||||
|
@ -39,13 +39,13 @@
|
||||
|
||||
enum WidgetTokens
|
||||
{
|
||||
WTOK_TITLE,
|
||||
|
||||
WTOK_QUIT,
|
||||
WTOK_EMPTY_UP,
|
||||
WTOK_UP,
|
||||
WTOK_EMPTY_DOWN,
|
||||
WTOK_EMPTY_UP,
|
||||
WTOK_TITLE,
|
||||
WTOK_UP,
|
||||
WTOK_DOWN,
|
||||
WTOK_MESSAGE,
|
||||
WTOK_QUIT,
|
||||
WTOK_EMPTY0 = 10,
|
||||
WTOK_NAME0 = 2000,
|
||||
WTOK_RACER0 = 3000
|
||||
@ -54,6 +54,11 @@ enum WidgetTokens
|
||||
CharSel::CharSel(int whichPlayer)
|
||||
: m_kart(0), m_player_index(whichPlayer)
|
||||
{
|
||||
// First time this is called --> switch client and server
|
||||
// to character barrier mode
|
||||
if(network_manager->getState()==NetworkManager::NS_NONE)
|
||||
network_manager->switchToCharacterSelection();
|
||||
|
||||
// For some strange reasons plib calls makeCurrent() in ssgContext
|
||||
// constructor, so we have to save the old one here and restore it
|
||||
ssgContext* oldContext = ssgGetCurrentContext();
|
||||
@ -106,6 +111,13 @@ CharSel::CharSel(int whichPlayer)
|
||||
|
||||
switchGroup(); // select all karts from the currently selected group
|
||||
|
||||
Widget *w=widget_manager->addTextWgt(WTOK_MESSAGE, 30, 7, "");
|
||||
w->setPosition(WGT_DIR_CENTER, 0, WGT_DIR_CENTER, 0);
|
||||
if(network_manager->getMode()==NetworkManager::NW_CLIENT)
|
||||
widget_manager->setWgtText(WTOK_MESSAGE, _("Waiting for server"));
|
||||
else
|
||||
widget_manager->setWgtText(WTOK_MESSAGE, _("Waiting for clients"));
|
||||
|
||||
widget_manager->layout(WGT_AREA_RGT);
|
||||
|
||||
m_current_kart = -1;
|
||||
@ -132,10 +144,20 @@ CharSel::CharSel(int whichPlayer)
|
||||
m_offset = 0;
|
||||
switchCharacter(0);
|
||||
}
|
||||
updateScrollPosition();
|
||||
if(network_manager->getState()==NetworkManager::NS_WAIT_FOR_AVAILABLE_CHARACTERS)
|
||||
{
|
||||
widget_manager->hideWgt(WTOK_TITLE, WTOK_DOWN);
|
||||
// Hide all widgets except the message widget
|
||||
for (unsigned int i = 0; i < m_max_entries; i++)
|
||||
{
|
||||
widget_manager->hideWgt(WTOK_NAME0+i);
|
||||
widget_manager->hideWgt(WTOK_RACER0+i);
|
||||
}
|
||||
}
|
||||
else
|
||||
updateScrollPosition();
|
||||
|
||||
m_clock = 0;
|
||||
//test
|
||||
|
||||
} // CharSel
|
||||
|
||||
@ -164,17 +186,15 @@ void CharSel::updateScrollPosition()
|
||||
{
|
||||
if(i<start || i>end)
|
||||
{
|
||||
widget_manager->hideWgtRect (WTOK_NAME0 +i);
|
||||
widget_manager->hideWgt (WTOK_NAME0 +i);
|
||||
widget_manager->hideWgtRect (WTOK_RACER0+i);
|
||||
widget_manager->hideWgtText (WTOK_NAME0 +i);
|
||||
widget_manager->hideWgtTexture(WTOK_RACER0+i);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Otherwise enable the widgets again (just in case that they
|
||||
// had been disabled before)
|
||||
widget_manager->showWgtRect (WTOK_NAME0 +i);
|
||||
widget_manager->showWgtText (WTOK_NAME0 +i);
|
||||
widget_manager->showWgt(WTOK_NAME0 +i);
|
||||
|
||||
int indx = (i+m_offset)%m_index_avail_karts.size();
|
||||
indx = m_index_avail_karts[indx];
|
||||
@ -272,6 +292,29 @@ void CharSel::switchCharacter(int n)
|
||||
//-----------------------------------------------------------------------------
|
||||
void CharSel::update(float dt)
|
||||
{
|
||||
// If we are still waiting in the barrier, don't do anything
|
||||
if(network_manager->getState()==NetworkManager::NS_WAIT_FOR_AVAILABLE_CHARACTERS)
|
||||
{
|
||||
widget_manager->update(dt);
|
||||
return;
|
||||
}
|
||||
static bool first=true;
|
||||
if(first)
|
||||
{
|
||||
// Now hide the message window and display the widgets:
|
||||
widget_manager->hideWgt(WTOK_MESSAGE);
|
||||
widget_manager->showWgt(WTOK_TITLE, WTOK_EMPTY_DOWN);
|
||||
// Hide all widgets except the message widget
|
||||
for (unsigned int i = 0; i < m_max_entries; i++)
|
||||
{
|
||||
widget_manager->showWgt(WTOK_NAME0+i);
|
||||
widget_manager->showWgt(WTOK_RACER0+i);
|
||||
}
|
||||
first=false;
|
||||
updateScrollPosition();
|
||||
return;
|
||||
}
|
||||
|
||||
m_clock += dt * 40.0f;
|
||||
|
||||
if( widget_manager->selectionChanged() )
|
||||
@ -362,6 +405,8 @@ void CharSel::select()
|
||||
// Add selected kart (token) to selected karts vector so it cannot be
|
||||
// selected again
|
||||
kart_properties_manager->testAndSetKart(kart_id);
|
||||
if(network_manager->getMode()==NetworkManager::NW_CLIENT)
|
||||
network_manager->sendCharacterSelected(m_player_index);
|
||||
}
|
||||
|
||||
if (race_manager->getNumLocalPlayers() > 1)
|
||||
@ -391,13 +436,19 @@ void CharSel::select()
|
||||
}
|
||||
}
|
||||
|
||||
// Last character selected"
|
||||
if(network_manager->getMode()==NetworkManager::NW_CLIENT)
|
||||
{
|
||||
network_manager->sendKartsInformationToServer();
|
||||
// Switch state to wait for race information
|
||||
network_manager->waitForRaceInformation();
|
||||
menu_manager->pushMenu(MENUID_START_RACE_FEEDBACK);
|
||||
}
|
||||
else
|
||||
{
|
||||
// The state of the server does not change now (so that it can keep
|
||||
// on handling client selections). Waiting for all client infos
|
||||
// happens in the start_race_feedback menu (which then triggers
|
||||
// sending the race info).
|
||||
if (race_manager->getMajorMode() == RaceManager::RM_GRAND_PRIX)
|
||||
menu_manager->pushMenu(MENUID_GRANDPRIXSELECT);
|
||||
else
|
||||
|
@ -43,6 +43,10 @@ enum WidgetTokens
|
||||
|
||||
MainMenu::MainMenu()
|
||||
{
|
||||
// Reset the state of the network manager to none (which is correct
|
||||
// independent if it is a client, server, or no networking
|
||||
network_manager->setState(NetworkManager::NS_NONE);
|
||||
|
||||
widget_manager->switchOrder();
|
||||
|
||||
const int WIDTH=30;
|
||||
@ -79,6 +83,7 @@ MainMenu::MainMenu()
|
||||
widget_manager->hideWgtRect(WTOK_WARNING);
|
||||
}
|
||||
|
||||
widget_manager->activateWgt(WTOK_SINGLE);
|
||||
widget_manager->layout(WGT_AREA_ALL);
|
||||
}
|
||||
|
||||
|
@ -22,6 +22,9 @@
|
||||
//This is needed in various platforms, but not all
|
||||
# include <algorithm>
|
||||
|
||||
#define _WINSOCKAPI_
|
||||
#include "network/network_manager.hpp"
|
||||
|
||||
#include "menu_manager.hpp"
|
||||
|
||||
#include "main_menu.hpp"
|
||||
@ -54,7 +57,6 @@
|
||||
#include "challenges_menu.hpp"
|
||||
#include "feature_unlocked.hpp"
|
||||
#include "start_race_feedback.hpp"
|
||||
#include "network_info.hpp"
|
||||
#include "network_gui.hpp"
|
||||
|
||||
using namespace std;
|
||||
@ -149,6 +151,11 @@ void MenuManager::update()
|
||||
{
|
||||
case MENUID_MAINMENU:
|
||||
m_current_menu= new MainMenu();
|
||||
// in this case the network entry can be removed, resulting
|
||||
// in warnings etc. if the widget manager then tries to select
|
||||
// the widget again. To avoid this, set the saved widget to NONE.
|
||||
if(network_manager->getMode()!=NetworkManager::NW_NONE)
|
||||
saved_widget=WidgetManager::WGT_NONE;
|
||||
break;
|
||||
case MENUID_CHALLENGES:
|
||||
m_current_menu= new ChallengesMenu();
|
||||
@ -244,9 +251,6 @@ void MenuManager::update()
|
||||
case MENUID_NETWORK_GUI:
|
||||
m_current_menu = new NetworkGUI();
|
||||
break;
|
||||
case MENUID_NETWORK_INFO:
|
||||
m_current_menu = new NetworkInfo();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
} // switch
|
||||
|
@ -37,6 +37,7 @@ enum WidgetTokens
|
||||
WTOK_SERVER,
|
||||
WTOK_SERVER_ADDRESS,
|
||||
WTOK_CONNECTED,
|
||||
WTOK_MESSAGE,
|
||||
WTOK_QUIT
|
||||
};
|
||||
|
||||
@ -46,14 +47,17 @@ const int NetworkGUI::SERVER_NAME_MAX = 50;
|
||||
|
||||
NetworkGUI::NetworkGUI()
|
||||
{
|
||||
|
||||
m_num_clients = 0;
|
||||
Widget *w=widget_manager->addTitleWgt( WTOK_TITLE, 60, 7, _("Select network mode"));
|
||||
w->setPosition(WGT_DIR_CENTER, 0.0, WGT_DIR_FROM_TOP, 0.1f);
|
||||
widget_manager->hideWgtRect(WTOK_TITLE);
|
||||
w->setPosition(WGT_DIR_CENTER, 0.0, WGT_DIR_FROM_TOP, 0.15f);
|
||||
|
||||
Widget *w_prev=widget_manager->addTextButtonWgt( WTOK_CONNECT, 30, 7, _("Connect to server:") );
|
||||
w_prev->setPosition(WGT_DIR_FROM_LEFT, 0.05f, WGT_DIR_FROM_TOP, 0.2f);
|
||||
widget_manager->resizeWgtToText(WTOK_CONNECT);
|
||||
w_prev->setPosition(WGT_DIR_FROM_LEFT, 0.05f, WGT_DIR_FROM_TOP, 0.25f);
|
||||
|
||||
w=widget_manager->addTextButtonWgt( WTOK_SERVER, 30, 7, _("Become server") );
|
||||
widget_manager->resizeWgtToText(WTOK_SERVER);
|
||||
w->setPosition(WGT_DIR_FROM_LEFT, 0.05f, NULL,
|
||||
WGT_DIR_UNDER_WIDGET, 0, w_prev);
|
||||
widget_manager->sameWidth(WTOK_CONNECT, WTOK_SERVER);
|
||||
@ -63,22 +67,28 @@ NetworkGUI::NetworkGUI()
|
||||
m_server_address=s.str();
|
||||
w=widget_manager->addTextButtonWgt(WTOK_SERVER_ADDRESS, 50, 7, m_server_address);
|
||||
w->setPosition(WGT_DIR_RIGHT_WIDGET, 0.05f, w_prev,
|
||||
WGT_DIR_FROM_TOP, 0.2f, NULL);
|
||||
WGT_DIR_FROM_TOP, 0.25f, NULL);
|
||||
|
||||
w=widget_manager->addTextButtonWgt(WTOK_CONNECTED, 50, 20, " ");
|
||||
w->setPosition(WGT_DIR_RIGHT_WIDGET, 0.05f, w_prev,
|
||||
WGT_DIR_FROM_TOP, 0.2f, NULL);
|
||||
WGT_DIR_FROM_TOP, 0.25f, NULL);
|
||||
widget_manager->hideWgt(WTOK_CONNECTED);
|
||||
widget_manager->deactivateWgt(WTOK_CONNECTED);
|
||||
|
||||
w=widget_manager->addTextButtonWgt( WTOK_QUIT, 60, 7, _("Press <ESC> to go back") );
|
||||
w->setPosition(WGT_DIR_CENTER, 0, WGT_DIR_FROM_BOTTOM, 0);
|
||||
|
||||
w=widget_manager->addTextWgt(WTOK_MESSAGE, 30, 7, "");
|
||||
w->setPosition(WGT_DIR_CENTER, 0, WGT_DIR_CENTER, 0);
|
||||
widget_manager->hideWgt(WTOK_MESSAGE);
|
||||
|
||||
// This can happen either when going back here, or when a command line
|
||||
// option was specified causing the connection to already have happened
|
||||
if(network_manager->getMode()==NetworkManager::NW_SERVER)
|
||||
switchToWaitForConnectionMode();
|
||||
widget_manager->layout(WGT_AREA_ALL);
|
||||
m_state=NGS_NONE;
|
||||
|
||||
} // NetworkGUI
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -96,20 +106,27 @@ void NetworkGUI::select()
|
||||
case WTOK_SERVER_ADDRESS:
|
||||
// Switch to typing in the address of the server
|
||||
widget_manager->setWgtText(WTOK_SERVER_ADDRESS, (m_server_address + "<").c_str());
|
||||
|
||||
inputDriver->setMode(LOWLEVEL);
|
||||
|
||||
break;
|
||||
case WTOK_CONNECT:
|
||||
network_manager->setMode(NetworkManager::NW_CLIENT);
|
||||
if(!network_manager->initialiseConnections())
|
||||
{
|
||||
fprintf(stderr, "Problems initialising network connections,\n"
|
||||
"Running in non-network mode.\n");
|
||||
}
|
||||
// If we could connect here, no message could be displayed since
|
||||
// glflush isn't called. So we only set a message for the network
|
||||
// manager to display, and set the state so that the actual
|
||||
// connection is done later when updating.
|
||||
m_state=NGS_CONNECT_DISPLAY;
|
||||
widget_manager->setWgtText(WTOK_MESSAGE, _("Waiting for server"));
|
||||
widget_manager->resizeWgtToText(WTOK_MESSAGE);
|
||||
widget_manager->showWgt(WTOK_MESSAGE);
|
||||
widget_manager->hideWgt(WTOK_CONNECT, WTOK_SERVER_ADDRESS);
|
||||
break;
|
||||
case WTOK_SERVER:
|
||||
network_manager->setMode(NetworkManager::NW_SERVER);
|
||||
network_manager->setState(NetworkManager::NS_ACCEPT_CONNECTIONS);
|
||||
widget_manager->hideWgt(WTOK_MESSAGE);
|
||||
widget_manager->resizeWgtToText(WTOK_MESSAGE);
|
||||
widget_manager->showWgt(WTOK_MESSAGE);
|
||||
// Initialising the server does not block, so we don't have to
|
||||
// do this in the update loop (to enable updates of the display).
|
||||
if(!network_manager->initialiseConnections())
|
||||
{
|
||||
fprintf(stderr, "Problems initialising network connections,\n"
|
||||
@ -118,8 +135,14 @@ void NetworkGUI::select()
|
||||
switchToWaitForConnectionMode();
|
||||
break;
|
||||
case WTOK_QUIT:
|
||||
// Don't do networking if no clients are connected
|
||||
if(network_manager->getNumClients()==0)
|
||||
network_manager->setMode(NetworkManager::NW_NONE);
|
||||
// Disable accepting of clients
|
||||
if(network_manager->getMode()==NetworkManager::NW_SERVER)
|
||||
network_manager->setState(NetworkManager::NS_NONE);
|
||||
// Leave menu.
|
||||
menu_manager->popMenu();
|
||||
menu_manager->popMenu();
|
||||
|
||||
break;
|
||||
}
|
||||
@ -129,18 +152,42 @@ void NetworkGUI::select()
|
||||
void NetworkGUI::switchToWaitForConnectionMode()
|
||||
{
|
||||
widget_manager->setWgtText(WTOK_CONNECT, _("Connected:"));
|
||||
widget_manager->hideWgtRect(WTOK_CONNECT);
|
||||
widget_manager->deactivateWgt(WTOK_CONNECT); //make it non-selectable
|
||||
widget_manager->setWgtText(WTOK_QUIT, _("OK"));
|
||||
widget_manager->hideWgt(WTOK_SERVER_ADDRESS);
|
||||
widget_manager->showWgt(WTOK_CONNECTED);
|
||||
widget_manager->hideWgt(WTOK_SERVER);
|
||||
widget_manager->setWgtText(WTOK_TITLE,_("Waiting for clients"));
|
||||
widget_manager->hideWgt(WTOK_MESSAGE);
|
||||
m_num_clients = 0;
|
||||
} // switchToWaitForConnectionMode
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void NetworkGUI::update(float dt)
|
||||
{
|
||||
// We need one 'in between' frame (finite state machine goes from
|
||||
// NGS_CONNECT_DISPLAY to NGS_CONNECT_DOIT) since otherwise the text
|
||||
// set for the message widget is not displayed (since glFlush isn't
|
||||
// called before the blocking initialiseConnection call).
|
||||
if(m_state==NGS_CONNECT_DOIT)
|
||||
{
|
||||
network_manager->setMode(NetworkManager::NW_CLIENT);
|
||||
if(!network_manager->initialiseConnections())
|
||||
{
|
||||
widget_manager->setWgtText(WTOK_MESSAGE, _("Can't connect to server"));
|
||||
widget_manager->resizeWgtToText(WTOK_MESSAGE);
|
||||
network_manager->disableNetworking();
|
||||
}
|
||||
else
|
||||
{
|
||||
menu_manager->popMenu();
|
||||
}
|
||||
m_state=NGS_NONE;
|
||||
}
|
||||
else if(m_state==NGS_CONNECT_DISPLAY)
|
||||
m_state=NGS_CONNECT_DOIT;
|
||||
|
||||
widget_manager->update(0.0f);
|
||||
if(m_num_clients==network_manager->getNumClients()) return;
|
||||
|
||||
|
@ -28,10 +28,12 @@
|
||||
class NetworkGUI: public BaseGUI
|
||||
{
|
||||
private:
|
||||
unsigned int m_num_clients;
|
||||
std::string m_server_address;
|
||||
unsigned int m_num_clients;
|
||||
std::string m_server_address;
|
||||
enum {NGS_NONE, NGS_CONNECT_DISPLAY, NGS_CONNECT_DOIT}
|
||||
m_state;
|
||||
|
||||
static const int SERVER_NAME_MAX;
|
||||
static const int SERVER_NAME_MAX;
|
||||
|
||||
void switchToWaitForConnectionMode();
|
||||
public:
|
||||
|
168
src/network/kart_packet.cpp
Normal file
168
src/network/kart_packet.cpp
Normal file
@ -0,0 +1,168 @@
|
||||
// $Id: network_manager.hpp 2128 2008-06-13 00:53:52Z cosmosninja $
|
||||
//
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2008 Joerg Henrichs, Stephen Leak
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 3
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
#include "kart_packet.hpp"
|
||||
#include <string>
|
||||
#include <math.h>
|
||||
#include <stdexcept>
|
||||
|
||||
|
||||
// need a more elegant way of setting the data_size, esp when strings are being used
|
||||
|
||||
// also, looking at how the packets are actually used, we can probably serialise as
|
||||
// part of the constructor, it seems packets to be sent are always created in a
|
||||
// single line
|
||||
|
||||
KartPacket::KartPacket(int data_size)
|
||||
{
|
||||
m_data_size = data_size;
|
||||
m_pkt = enet_packet_create (NULL, data_size*sizeof(int), ENET_PACKET_FLAG_RELIABLE);
|
||||
m_pos = 0;
|
||||
m_data = (int*) m_pkt->data;
|
||||
}
|
||||
|
||||
KartPacket::KartPacket(ENetPacket* pkt)
|
||||
{
|
||||
m_pkt = pkt;
|
||||
m_data = (int*) pkt->data;
|
||||
m_data_size = pkt->dataLength/sizeof(int);
|
||||
m_pos = 0;
|
||||
}
|
||||
|
||||
KartPacket::~KartPacket()
|
||||
{
|
||||
enet_packet_destroy(m_pkt);
|
||||
}
|
||||
|
||||
bool KartPacket::pushInt(int &data)
|
||||
{
|
||||
if (m_pos > m_data_size)
|
||||
return false;
|
||||
m_data[m_pos] = htonl(data);
|
||||
++m_pos;
|
||||
return true;
|
||||
}
|
||||
|
||||
int KartPacket::pullInt()
|
||||
{
|
||||
m_pos++;
|
||||
return ntohl(m_data[m_pos-1]);
|
||||
}
|
||||
|
||||
bool KartPacket::pushFloat(float &data)
|
||||
{
|
||||
int *dcast = (int*) &data;
|
||||
return pushInt(*dcast);
|
||||
}
|
||||
|
||||
float KartPacket::pullFloat()
|
||||
{ // ugly...
|
||||
int i = pullInt();
|
||||
float *f = (float*) &i;
|
||||
return *f;
|
||||
}
|
||||
|
||||
bool KartPacket::pushString(std::string &data)
|
||||
{ // urk, this is a little ugly. want to put the string on a 4-byte boundary
|
||||
int len = (int)ceil((float)data.length() / 4.0f) * 4; // round length up to next 4-char boundary
|
||||
if (m_pos+len > m_data_size)
|
||||
return false; // FIXME: resize the packet so it fits
|
||||
memcpy (&(m_data[m_pos]), data.c_str(), data.length()+1);
|
||||
m_pos += len;
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string KartPacket::pullString()
|
||||
{
|
||||
char *str = (char*) &(m_data[m_pos]);
|
||||
int len = strlen(str)+1;
|
||||
int len4 = len/sizeof(int) + 1;
|
||||
m_pos += len4; // I think this is correct ..
|
||||
return std::string(str);
|
||||
}
|
||||
|
||||
bool KartPacket::send(ENetPeer& peer)
|
||||
{
|
||||
this->serialise();
|
||||
enet_peer_send(&peer, 0, m_pkt);
|
||||
return true;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
ClientHostIdPacket::ClientHostIdPacket(int id)
|
||||
: KartPacket(2)
|
||||
{ // create a ClientHostIdPacket with id as data
|
||||
m_type = CLIENT_HOST_ID_PACKET;
|
||||
m_id = id;
|
||||
}
|
||||
|
||||
ClientHostIdPacket::ClientHostIdPacket(ENetPacket* pkt)
|
||||
: KartPacket(pkt)
|
||||
{ // create a ClientHostIdPacket based on a received packet
|
||||
m_type = static_cast<PacketType> (pullInt()); // (ntohl(m_data[0]));
|
||||
if (m_type != CLIENT_HOST_ID_PACKET)
|
||||
// FIXME: do something more elegant here
|
||||
throw std::runtime_error("Received packet mismatch!");
|
||||
m_id = pullInt(); // ntohl(m_data[1]);
|
||||
}
|
||||
|
||||
void ClientHostIdPacket::serialise()
|
||||
{
|
||||
int type = m_type;
|
||||
pushInt(type);
|
||||
pushInt(m_id);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
LocalKartInfoPacket::LocalKartInfoPacket(const std::string& player_name,
|
||||
const std::string& kart_name)
|
||||
: KartPacket(128) // a bit arbitrary, just to check it works
|
||||
{
|
||||
m_type = LOCAL_KART_INFO_PACKET;
|
||||
m_player_name = std::string(player_name);
|
||||
m_kart_name = std::string(kart_name);
|
||||
}
|
||||
|
||||
LocalKartInfoPacket::LocalKartInfoPacket(ENetPacket* pkt)
|
||||
: KartPacket(pkt)
|
||||
{ // create a LocalKartInfoPacket based on a received packet
|
||||
m_type = static_cast<PacketType> (pullInt()); // (ntohl(m_data[0]));
|
||||
if (m_type != LOCAL_KART_INFO_PACKET)
|
||||
// FIXME: do something more elegant here
|
||||
throw std::runtime_error("Received packet mismatch!");
|
||||
m_player_name = pullString(); // new string((char*) &(m_data[1]));
|
||||
m_kart_name = pullString(); // new string(&(m_data[1]));
|
||||
}
|
||||
|
||||
//LocalKartInfoPacket::~LocalKartInfoPacket()
|
||||
//{
|
||||
// delete m_player_name;
|
||||
// delete m_kart_name;
|
||||
// // FIXME: poss mem leak here, need to call ~KartPacket
|
||||
//}
|
||||
|
||||
void LocalKartInfoPacket::serialise()
|
||||
{
|
||||
int type = m_type;
|
||||
pushInt(type);
|
||||
pushString(m_player_name);
|
||||
pushString(m_kart_name);
|
||||
}
|
102
src/network/kart_packet.hpp
Normal file
102
src/network/kart_packet.hpp
Normal file
@ -0,0 +1,102 @@
|
||||
// $Id: network_manager.hpp 2128 2008-06-13 00:53:52Z cosmosninja $
|
||||
//
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2008 Joerg Henrichs, Stephen Leak
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 3
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
#ifndef HEADER_KART_PACKET_H
|
||||
#define HEADER_KART_PACKET_H
|
||||
|
||||
#include <string>
|
||||
|
||||
#ifdef HAVE_ENET
|
||||
# include "enet/enet.h"
|
||||
#else
|
||||
# error "need enet for this implementation!"
|
||||
#endif
|
||||
|
||||
// sjl: when a message is received, need to work out what kind of message it
|
||||
// is and therefore what to do with it
|
||||
|
||||
class KartPacket
|
||||
{ // collects and serialises/deserialises kart info to send
|
||||
public:
|
||||
KartPacket(int data_size); // create from scratch (to send)
|
||||
KartPacket(ENetPacket* pkt); // create from (received) ENetacket
|
||||
~KartPacket();
|
||||
|
||||
enum PacketType { LOCAL_KART_INFO_PACKET, CLIENT_HOST_ID_PACKET };
|
||||
PacketType getType();
|
||||
bool send(ENetPeer& peer);
|
||||
|
||||
protected:
|
||||
bool pushInt(int &data);
|
||||
bool pushFloat(float &data);
|
||||
bool pushString(std::string &data);
|
||||
int pullInt();
|
||||
float pullFloat();
|
||||
std::string pullString();
|
||||
|
||||
PacketType m_type;
|
||||
int *m_data;
|
||||
|
||||
//virtual ENetPacket* serialise(); // convert KartPacket into ENetPacket
|
||||
virtual void serialise() =0; // convert KartPacket into ENetPacket
|
||||
|
||||
private:
|
||||
ENetPacket *m_pkt;
|
||||
int m_data_size;
|
||||
int m_pos; // simple stack counter for constructing packet data
|
||||
};
|
||||
|
||||
class ClientHostIdPacket : public KartPacket
|
||||
{ // during init phase, server sends this to client
|
||||
public:
|
||||
ClientHostIdPacket(int id); // create one to send
|
||||
ClientHostIdPacket(ENetPacket* pkt); // wait for one from server
|
||||
|
||||
int getId() { return m_id; };
|
||||
|
||||
protected:
|
||||
void serialise(); // convert KartPacket into ENetPacket
|
||||
|
||||
private:
|
||||
int m_id;
|
||||
|
||||
};
|
||||
|
||||
class LocalKartInfoPacket : public KartPacket
|
||||
{ // before a race, each client sends server one of these for each player on that client
|
||||
public:
|
||||
LocalKartInfoPacket(const std::string& player_name,
|
||||
const std::string& kart_name);
|
||||
LocalKartInfoPacket(ENetPacket* pkt);
|
||||
// ~LocalKartInfoPacket();
|
||||
|
||||
std::string getPlayerName();
|
||||
std::string getKartName();
|
||||
|
||||
protected:
|
||||
void serialise(); // convert KartPacket into ENetPacket
|
||||
|
||||
private:
|
||||
std::string m_player_name;
|
||||
std::string m_kart_name;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
@ -18,10 +18,18 @@
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
#include "network_manager.hpp"
|
||||
#include "connect_message.hpp"
|
||||
#include "character_info_message.hpp"
|
||||
#include "character_selected_message.hpp"
|
||||
#include "race_info_message.hpp"
|
||||
#include "race_start_message.hpp"
|
||||
#include "world_loaded_message.hpp"
|
||||
#include "stk_config.hpp"
|
||||
#include "user_config.hpp"
|
||||
#include "race_manager.hpp"
|
||||
#include "kart_properties_manager.hpp"
|
||||
#include "translation.hpp"
|
||||
#include "gui/font.hpp"
|
||||
|
||||
NetworkManager* network_manager = 0;
|
||||
|
||||
@ -32,6 +40,7 @@ NetworkManager::NetworkManager()
|
||||
|
||||
m_num_clients = 0;
|
||||
m_host_id = 0;
|
||||
|
||||
#ifdef HAVE_ENET
|
||||
if (enet_initialize () != 0)
|
||||
{
|
||||
@ -66,8 +75,6 @@ NetworkManager::~NetworkManager()
|
||||
bool NetworkManager::initServer()
|
||||
{
|
||||
#ifdef HAVE_ENET
|
||||
fprintf(stderr, "Initialising server, listening on %d\n", user_config->m_server_port);
|
||||
|
||||
ENetAddress address;
|
||||
address.host = ENET_HOST_ANY;
|
||||
address.port = user_config->m_server_port;
|
||||
@ -88,7 +95,6 @@ bool NetworkManager::initServer()
|
||||
m_server = NULL;
|
||||
m_clients.push_back(NULL); // server has host_id=0, so put a dummy entry at 0 in client array
|
||||
|
||||
fprintf(stderr, "Server initialised, waiting for connections ...\n");
|
||||
m_client_names.push_back("server");
|
||||
return true;
|
||||
#endif
|
||||
@ -97,7 +103,6 @@ bool NetworkManager::initServer()
|
||||
// -----------------------------------------------------------------------------
|
||||
bool NetworkManager::initClient()
|
||||
{
|
||||
fprintf(stderr, "Initialising client\n");
|
||||
#ifdef HAVE_ENET
|
||||
m_host = enet_host_create (NULL /* create a client host */,
|
||||
1 /* only allow 1 outgoing connection */,
|
||||
@ -123,9 +128,9 @@ bool NetworkManager::initClient()
|
||||
|
||||
if (peer == NULL)
|
||||
{
|
||||
fprintf (stderr,
|
||||
"No available peers for initiating an ENet connection.\n");
|
||||
return false;
|
||||
fprintf(stderr,
|
||||
"No available peers for initiating an ENet connection.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Wait up to 5 seconds for the connection attempt to succeed. */
|
||||
@ -141,50 +146,34 @@ bool NetworkManager::initClient()
|
||||
user_config->m_server_address.c_str(), user_config->m_server_port);
|
||||
return false;
|
||||
}
|
||||
fprintf(stderr, "Connection to %s:%d succeeded.\n",
|
||||
user_config->m_server_address.c_str(), user_config->m_server_port);
|
||||
|
||||
m_server = peer;
|
||||
if (enet_host_service(m_host, &event, 5000) > 0)
|
||||
if (event.type == ENET_EVENT_TYPE_RECEIVE)
|
||||
{
|
||||
m_host_id = ClientHostIdPacket(event.packet).getId();
|
||||
fprintf(stderr, "got host id %d from server\n", m_host_id);
|
||||
return true;
|
||||
}
|
||||
fprintf(stderr, "didn't receive a host_id!\n");
|
||||
return false;
|
||||
return true;
|
||||
#endif
|
||||
} // initClient
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Called in case of an error, to switch back to non-networking mode.
|
||||
*/
|
||||
void NetworkManager::disableNetworking()
|
||||
{
|
||||
m_mode=NW_NONE;
|
||||
// FIXME: what enet data structures do we have to free/reset???
|
||||
|
||||
} // disableNetworking
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void NetworkManager::handleNewConnection(ENetEvent *event)
|
||||
{
|
||||
ClientHostIdPacket *msg;
|
||||
int new_host_id;
|
||||
// Only accept while waiting for connections
|
||||
if(m_state!=NS_ACCEPT_CONNECTIONS) return;
|
||||
|
||||
if(m_state!=NS_ACCEPT_CONNECTIONS)
|
||||
{
|
||||
// We don't accept connections atm
|
||||
return;
|
||||
}
|
||||
m_num_clients++;
|
||||
fprintf (stderr, "A new client connected from %x:%u. Connected: %d.\n",
|
||||
event->peer -> address.host,
|
||||
event->peer -> address.port, m_num_clients);
|
||||
|
||||
// FIXME: send m_num_clients as hostid back to new client.
|
||||
// FIXME: client should send an id as well to be displayed
|
||||
m_client_names.push_back("client");
|
||||
|
||||
// send a hostid back
|
||||
new_host_id = m_clients.size();
|
||||
// fprintf (stderr, "allocated client host_id as %d\n", new_host_id);
|
||||
// The logical connection (from STK point of view) happens when
|
||||
// the connection message is received. But for now reserve the
|
||||
// space in the data structures (e.g. in case that two connects
|
||||
// happen before a connect message is received
|
||||
m_client_names.push_back("NOT SET YET");
|
||||
m_clients.push_back(event->peer);
|
||||
msg = new ClientHostIdPacket(new_host_id);
|
||||
msg->send(*(m_clients[new_host_id]));
|
||||
enet_host_flush(m_host);
|
||||
delete msg;
|
||||
event->peer->data = (void*)int(m_clients.size()-1); // save hostid in peer data
|
||||
|
||||
} // handleNewConnection
|
||||
|
||||
@ -196,113 +185,98 @@ void NetworkManager::handleDisconnection(ENetEvent *event)
|
||||
fprintf(stderr, "Disconnect while in race - close your eyes and hope for the best.\n");
|
||||
return;
|
||||
}
|
||||
fprintf(stderr, "%x:%d disconected.\n", event->peer->address.host,
|
||||
event->peer->address.port );
|
||||
fprintf(stderr, "%x:%d disconnected (host id %d).\n", event->peer->address.host,
|
||||
event->peer->address.port, (int)event->peer->data );
|
||||
m_num_clients--;
|
||||
} // handleDisconnection
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void NetworkManager::handleServerMessage(ENetEvent *event)
|
||||
void NetworkManager::handleMessageAtServer(ENetEvent *event)
|
||||
{ // handle message at server (from client)
|
||||
|
||||
switch(m_state)
|
||||
{
|
||||
case NS_ACCEPT_CONNECTIONS:
|
||||
fprintf(stderr, "Received a receive event while waiting for client - ignored.\n");
|
||||
return;
|
||||
{
|
||||
ConnectMessage m(event->packet);
|
||||
m_client_names[(int)event->peer->data] = m.getId();
|
||||
m_num_clients++;
|
||||
return;
|
||||
}
|
||||
case NS_CHARACTER_SELECT:
|
||||
{
|
||||
// only accept testAndSet and 'character selected' messages here.
|
||||
// Get character from message, check if it's still available
|
||||
int kartid=0, playerid=0, hostid=0;
|
||||
std::string name="tuxkart", user="guest";
|
||||
if(kart_properties_manager->testAndSetKart(kartid))
|
||||
{
|
||||
CharacterSelectedMessage m(event->packet);
|
||||
int hostid=(int)event->peer->data;
|
||||
assert(hostid>=1 && hostid<=m_num_clients);
|
||||
if(m_num_local_players[hostid]==-1) // first package from that host
|
||||
{
|
||||
// send 'ok' message to client and all other clients
|
||||
m_kart_info.push_back(RemoteKartInfo(playerid, name, user, hostid));
|
||||
m_num_local_players[hostid] = m.getNumPlayers();
|
||||
m_num_all_players += m.getNumPlayers();
|
||||
// count how many hosts have sent (at least) one message
|
||||
m_barrier_count ++;
|
||||
}
|
||||
else
|
||||
RemoteKartInfo ki=m.getKartInfo();
|
||||
ki.setHostId(hostid);
|
||||
m_kart_info.push_back(ki);
|
||||
// See if this was the last message, i.e. we have received at least
|
||||
// one message from each client, and the size of the kart_info
|
||||
// array is the same as the number of all players (which does not
|
||||
// yet include the number of players on the host).
|
||||
if(m_barrier_count = m_num_clients &&
|
||||
m_num_all_players==m_kart_info.size())
|
||||
{
|
||||
// send 'not avail' to sender
|
||||
// we can't send the race info yet, since the server might
|
||||
// not yet have selected all characters!
|
||||
m_state = NS_ALL_REMOTE_CHARACTERS_DONE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NS_READY_SET_GO_BARRIER:
|
||||
m_barrier_count++;
|
||||
if(m_barrier_count==m_num_clients)
|
||||
{
|
||||
// broadcast start message
|
||||
m_state = NS_RACING;
|
||||
m_barrier_count ++;
|
||||
if(m_barrier_count==m_num_clients)
|
||||
{
|
||||
m_state = NS_RACING;
|
||||
RaceStartMessage m;
|
||||
broadcastToClients(m);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case NS_WAIT_FOR_KART_INFO:
|
||||
m_barrier_count++;
|
||||
// handle message, i.e. append to m_kart_info
|
||||
if(m_barrier_count==m_num_clients)
|
||||
{
|
||||
// broadcast start message
|
||||
m_state = NS_READY_SET_GO_BARRIER;
|
||||
}
|
||||
break;
|
||||
|
||||
} // switch m_state
|
||||
} // handleServerMessage
|
||||
} // handleMessageAtServer
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void NetworkManager::switchToReadySetGoBarrier()
|
||||
{
|
||||
if(m_num_clients==0)
|
||||
{
|
||||
m_state = NS_RACING;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_state = NS_READY_SET_GO_BARRIER;
|
||||
m_barrier_count = 0;
|
||||
}
|
||||
} // switchToReadySetGoBarrier
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void NetworkManager::switchToCharacterSelection()
|
||||
{
|
||||
// This must be called from the network info menu,
|
||||
// so make sure the state is correct
|
||||
assert(m_state == NS_ACCEPT_CONNECTIONS);
|
||||
m_state = NS_CHARACTER_SELECT;
|
||||
} // switchTocharacterSelection
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void NetworkManager::switchToReceiveKartInfo()
|
||||
{
|
||||
assert(m_state == NS_CHARACTER_SELECT);
|
||||
m_state = NS_WAIT_FOR_KART_INFO;
|
||||
} // switchToReceiveKartInfo
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void NetworkManager::switchToRaceDataSynchronisation()
|
||||
{
|
||||
m_state = NS_WAIT_FOR_RACE_DATA;
|
||||
m_barrier_count = 0;
|
||||
} // switchToRaceDataSynchronisation
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void NetworkManager::handleClientMessage(ENetEvent *event)
|
||||
void NetworkManager::handleMessageAtClient(ENetEvent *event)
|
||||
{ // handle message at client (from server)
|
||||
switch(m_state)
|
||||
{
|
||||
case NS_WAIT_FOR_AVAILABLE_CHARACTERS:
|
||||
{
|
||||
CharacterInfoMessage m(event->packet);
|
||||
// FIXME: handle list of available characters
|
||||
m_state = NS_CHARACTER_SELECT;
|
||||
break;
|
||||
}
|
||||
case NS_WAIT_FOR_RACE_DATA:
|
||||
// check if message is really race data
|
||||
fprintf(stderr, "Client received race data\n");
|
||||
break;
|
||||
{
|
||||
RaceInfoMessage m(event->packet);
|
||||
// The constructor actually sets the information in the race manager
|
||||
m_state = NS_LOADING_WORLD;
|
||||
break;
|
||||
}
|
||||
case NS_READY_SET_GO_BARRIER:
|
||||
{
|
||||
m_state = NS_RACING;
|
||||
break;
|
||||
}
|
||||
} // switch m_state
|
||||
} // handleClientMessage
|
||||
} // handleMessageAtClient
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void NetworkManager::update(float dt)
|
||||
{
|
||||
if(m_mode==NW_NONE) return;
|
||||
ENetEvent event;
|
||||
int result = enet_host_service (m_host, &event, 1);
|
||||
int result = enet_host_service (m_host, &event, 0);
|
||||
if(result==0) return;
|
||||
if(result<0)
|
||||
{
|
||||
@ -314,60 +288,97 @@ void NetworkManager::update(float dt)
|
||||
case ENET_EVENT_TYPE_CONNECT: handleNewConnection(&event); break;
|
||||
case ENET_EVENT_TYPE_RECEIVE:
|
||||
if(m_mode==NW_SERVER)
|
||||
handleServerMessage(&event);
|
||||
handleMessageAtServer(&event);
|
||||
else
|
||||
handleClientMessage(&event);
|
||||
handleMessageAtClient(&event);
|
||||
break;
|
||||
case ENET_EVENT_TYPE_DISCONNECT: handleDisconnection(&event); break;
|
||||
case ENET_EVENT_TYPE_NONE: break;
|
||||
}
|
||||
} // update
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void NetworkManager::broadcastToClients(Message &m)
|
||||
{
|
||||
enet_host_broadcast(m_host, 0, m.getPacket());
|
||||
enet_host_flush(m_host);
|
||||
} // broadcastToClients
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Send race_manager->getNumPlayers(), the kart and the name of each
|
||||
player to the server.
|
||||
*/
|
||||
void NetworkManager::sendKartsInformationToServer()
|
||||
void NetworkManager::sendToServer(Message* m)
|
||||
{
|
||||
LocalKartInfoPacket *msg;
|
||||
for(int i=0; i<(int)race_manager->getNumLocalPlayers(); i++)
|
||||
enet_peer_send(m_server, 0, m->getPacket());
|
||||
enet_host_flush(m_host);
|
||||
} // sendToServer
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void NetworkManager::switchToCharacterSelection()
|
||||
{
|
||||
// This is called the first time the character selection menu is displayed
|
||||
assert(m_state == NS_NONE);
|
||||
if(m_mode==NW_CLIENT)
|
||||
{
|
||||
fprintf(stderr, "Sending name '%s', ",user_config->m_player[i].getName().c_str());
|
||||
fprintf(stderr, "kart name '%s'\n", race_manager->getLocalKartInfo(i).getKartName().c_str());
|
||||
msg = new LocalKartInfoPacket(user_config->m_player[i].getName(), /* player name */
|
||||
race_manager->getLocalKartInfo(i).getKartName()); /* kart name */
|
||||
msg->send(*m_server);
|
||||
enet_host_flush(m_host);
|
||||
delete msg;
|
||||
// Change state to wait for list of characters from server
|
||||
m_state = NS_WAIT_FOR_AVAILABLE_CHARACTERS;
|
||||
}
|
||||
else
|
||||
{ // server: create message with all valid characters
|
||||
// ================================================
|
||||
CharacterInfoMessage m;
|
||||
broadcastToClients(m);
|
||||
|
||||
} // for i<getNumLocalPlayers
|
||||
fprintf(stderr, "Client sending kart information to server\n");
|
||||
// Prepare the data structures to receive and
|
||||
// store information from all clients.
|
||||
m_num_local_players.clear();
|
||||
// Server (hostid 0) is not included in the num_clients count. So to
|
||||
// be able to use the hostid as index, we have to allocate one
|
||||
// additional element.
|
||||
m_num_local_players.resize(m_num_clients+1, -1);
|
||||
m_kart_info.clear();
|
||||
m_num_all_players = 0;
|
||||
// use barrier count to see if we had at least one message from each host
|
||||
m_barrier_count = 0;
|
||||
m_state = NS_CHARACTER_SELECT;
|
||||
}
|
||||
|
||||
} // switchTocharacterSelection
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void NetworkManager::sendCharacterSelected(int player_id)
|
||||
{
|
||||
CharacterSelectedMessage m(player_id);
|
||||
sendToServer(&m);
|
||||
} // sendCharacterSelected
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void NetworkManager::waitForRaceInformation()
|
||||
{
|
||||
m_state = NS_WAIT_FOR_RACE_DATA;
|
||||
} // sendKartsInformationToServer
|
||||
} // waitForRaceInformation
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void NetworkManager::worldLoaded()
|
||||
{
|
||||
if(m_mode==NW_CLIENT)
|
||||
{
|
||||
WorldLoadedMessage m;
|
||||
sendToServer(&m);
|
||||
}
|
||||
else if(m_mode==NW_SERVER)
|
||||
{
|
||||
assert(m_state=NS_READY_SET_GO_BARRIER);
|
||||
RaceStartMessage m;
|
||||
broadcastToClients(m);
|
||||
}
|
||||
|
||||
} // worldLoaded
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Receive and store the information from sendKartsInformation()
|
||||
*/
|
||||
void NetworkManager::setupPlayerKartInfo()
|
||||
{
|
||||
LocalKartInfoPacket *msg;
|
||||
m_kart_info.clear();
|
||||
|
||||
// FIXME: debugging
|
||||
//m_kart_info.push_back(RemoteKartInfo(0, "tuxkart","xx", 1));
|
||||
//m_kart_info.push_back(RemoteKartInfo(1, "yetikart", "yy", 1));
|
||||
|
||||
// FIXME: put this into state machine
|
||||
//if (enet_host_service(m_host, &event, 15000) > 0)
|
||||
// if (event.type == ENET_EVENT_TYPE_RECEIVE)
|
||||
// {
|
||||
// msg = new LocalKartDetails(event.packet)
|
||||
// m_kart_info.push_back(RemoteKartInfo(0, "tuxkart","xx", 1));
|
||||
// m_kart_info.push_back(RemoteKartInfo(1, "yetikart", "yy", 1));
|
||||
// }
|
||||
//fprintf(stderr, "didn't receive kart info!\n");
|
||||
|
||||
// Get the local kart info
|
||||
for(unsigned int i=0; i<race_manager->getNumLocalPlayers(); i++)
|
||||
m_kart_info.push_back(race_manager->getLocalKartInfo(i));
|
||||
@ -379,8 +390,6 @@ void NetworkManager::setupPlayerKartInfo()
|
||||
for(unsigned int i=0; i<m_kart_info.size(); i++)
|
||||
m_kart_info[i].setGlobalPlayerId(i);
|
||||
|
||||
// FIXME: distribute m_kart_info to all clients
|
||||
|
||||
// Set the player kart information
|
||||
race_manager->setNumPlayers(m_kart_info.size());
|
||||
for(unsigned int i=0; i<m_kart_info.size(); i++)
|
||||
@ -394,23 +403,18 @@ void NetworkManager::setupPlayerKartInfo()
|
||||
*/
|
||||
void NetworkManager::sendRaceInformationToClients()
|
||||
{
|
||||
fprintf(stderr, "server sending race_manager information to all clients\n");
|
||||
for(unsigned i=0; i<race_manager->getNumLocalPlayers(); i++)
|
||||
{
|
||||
const RemoteKartInfo& ki=race_manager->getLocalKartInfo(i);
|
||||
fprintf(stderr, "Sending kart '%s' playerid %d host %d\n",
|
||||
ki.getKartName().c_str(), ki.getLocalPlayerId(), ki.getHostId());
|
||||
} // for i
|
||||
|
||||
// Go
|
||||
m_state=NS_READY_SET_GO_BARRIER;
|
||||
setupPlayerKartInfo();
|
||||
RaceInfoMessage m(m_kart_info);
|
||||
broadcastToClients(m);
|
||||
m_state = NS_READY_SET_GO_BARRIER;
|
||||
m_barrier_count = 0;
|
||||
if(m_num_clients==0) m_state = NS_RACING;
|
||||
} // sendRaceInformationToClients
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Receives and sets the race_manager information.
|
||||
*/
|
||||
void NetworkManager::waitForRaceInformation()
|
||||
void NetworkManager::sendConnectMessage()
|
||||
{
|
||||
fprintf(stderr, "Client waiting for race information\n");
|
||||
} // waitForRaceInformation
|
||||
ConnectMessage msg;
|
||||
sendToServer(&msg);
|
||||
} // sendConnectMessage
|
||||
// ----------------------------------------------------------------------------
|
||||
|
@ -30,6 +30,8 @@
|
||||
# include "enet/enet.h"
|
||||
#endif
|
||||
|
||||
class Message;
|
||||
|
||||
class NetworkManager
|
||||
{
|
||||
public:
|
||||
@ -37,13 +39,15 @@ public:
|
||||
enum NetworkMode {NW_SERVER, NW_CLIENT, NW_NONE};
|
||||
|
||||
// States for the finite state machine. First for server:
|
||||
enum NetworkState {NS_ACCEPT_CONNECTIONS, NS_WAIT_FOR_KART_INFO,
|
||||
// Then client only states:
|
||||
NS_CHARACTER_CONFIRMED,
|
||||
NS_CHARACTER_REJECTED,
|
||||
NS_WAIT_FOR_RACE_DATA,
|
||||
// Shared states
|
||||
NS_CHARACTER_SELECT, NS_READY_SET_GO_BARRIER, NS_RACING};
|
||||
enum NetworkState {NS_NONE,
|
||||
NS_ACCEPT_CONNECTIONS, // server: accept connections
|
||||
NS_WAIT_FOR_AVAILABLE_CHARACTERS, // client: wait for list
|
||||
NS_ALL_REMOTE_CHARACTERS_DONE, // server: all client data received
|
||||
NS_WAIT_FOR_RACE_DATA, // client: wait for race info
|
||||
NS_READY_SET_GO_BARRIER, // c&s: barrier before r.s.g.
|
||||
NS_CHARACTER_SELECT, // c&s: character select in progress
|
||||
NS_LOADING_WORLD, // client: loading world
|
||||
NS_RACING};
|
||||
private:
|
||||
|
||||
NetworkMode m_mode;
|
||||
@ -52,7 +56,10 @@ private:
|
||||
std::vector<RemoteKartInfo> m_kart_info;
|
||||
int m_host_id;
|
||||
std::vector<std::string> m_client_names;
|
||||
std::vector<int> m_num_local_players;
|
||||
int m_num_all_players;
|
||||
int m_barrier_count;
|
||||
|
||||
#ifdef HAVE_ENET
|
||||
ENetHost *m_host; // me
|
||||
ENetPeer *m_server; // (clients only)
|
||||
@ -62,11 +69,14 @@ private:
|
||||
bool initServer();
|
||||
bool initClient();
|
||||
void handleNewConnection(ENetEvent *event);
|
||||
void handleServerMessage(ENetEvent *event);
|
||||
void handleClientMessage(ENetEvent *event);
|
||||
void handleMessageAtServer(ENetEvent *event);
|
||||
void handleMessageAtClient(ENetEvent *event);
|
||||
void handleDisconnection(ENetEvent *event);
|
||||
void testSetCharacter (ENetEvent *event);
|
||||
unsigned int getHostId(ENetPeer *p) const {return (int)p->data; }
|
||||
|
||||
void sendToServer(Message *m);
|
||||
void broadcastToClients(Message &m);
|
||||
void sendToClient(int id, const Message *m);
|
||||
public:
|
||||
NetworkManager();
|
||||
~NetworkManager();
|
||||
@ -82,16 +92,20 @@ public:
|
||||
const std::string& user="", int hostid=-1);
|
||||
bool initialiseConnections();
|
||||
void update(float dt);
|
||||
void sendKartsInformationToServer();
|
||||
|
||||
void disableNetworking();
|
||||
void sendConnectMessage(); // client send initial info to server
|
||||
void switchToCharacterSelection();
|
||||
void sendCharacterSelected(int player_id);
|
||||
void waitForRaceInformation();
|
||||
void worldLoaded();
|
||||
|
||||
// which one is actually necessary:
|
||||
void setupPlayerKartInfo();
|
||||
void sendRaceInformationToClients();
|
||||
void waitForRaceInformation();
|
||||
|
||||
void switchToCharacterSelection();
|
||||
void switchToReceiveKartInfo();
|
||||
void switchToRaceDataSynchronisation();
|
||||
void switchToReadySetGoBarrier();
|
||||
|
||||
};
|
||||
|
||||
extern NetworkManager *network_manager;
|
||||
|
@ -128,8 +128,9 @@ class WidgetManager
|
||||
|
||||
int m_default_show_track;
|
||||
int m_default_track_num;
|
||||
|
||||
public:
|
||||
int findId(const int TOKEN) const;
|
||||
private:
|
||||
|
||||
int calcLineWidth( const int POS );
|
||||
int calcLineHeight( const int POS );
|
||||
@ -300,7 +301,9 @@ public:
|
||||
void showWgtRect(const int TOKEN);
|
||||
// Completely hide and show a widget
|
||||
void hideWgt(const int t) {hideWgtRect(t); hideWgtText(t);}
|
||||
void hideWgt(int t0, int t2) {for(int i=t0; i<=t2; hideWgt(i++));}
|
||||
void showWgt(const int t) {showWgtRect(t); showWgtText(t);}
|
||||
void showWgt(int t0, int t2) {for(int i=t0; i<=t2; showWgt(i++));}
|
||||
void hideWgtRect(const int TOKEN);
|
||||
|
||||
void setWgtBorderColor(const int TOKEN, const GLfloat* const COLOR);
|
||||
|
Loading…
x
Reference in New Issue
Block a user