Beginning of finite state machine for network manager.

git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/trunk/supertuxkart@2232 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
hikerstk 2008-09-07 13:58:37 +00:00
parent 94a1882435
commit fd93bfef1a
15 changed files with 315 additions and 60 deletions

View File

@ -107,6 +107,9 @@ void GameManager::run()
network_manager->update(dt);
if (race_manager->raceIsActive())
{
// Busy wait if race_manager is active (i.e. creating of world is done)
// till all clients have reached this state.
if(network_manager->getState()==NetworkManager::NS_READY_SET_GO_BARRIER) continue;
music_on = false;
if(user_config->m_profile) dt=1.0f/60.0f;
// In the first call dt might be large (includes loading time),

View File

@ -66,10 +66,10 @@ CharSel::CharSel(int whichPlayer)
// the user is moving back through the menus and the last value in the vector
// needs to be made available again.
if (m_player_index == 0)
kart_properties_manager->m_selected_karts.clear();
kart_properties_manager->clearAllSelectedKarts();
if (m_player_index < (int)kart_properties_manager->m_selected_karts.size())
kart_properties_manager->m_selected_karts.pop_back();
if (m_player_index < (int)kart_properties_manager->getNumSelectedKarts())
kart_properties_manager->removeLastSelectedKart();
char heading[MAX_MESSAGE_LENGTH];
snprintf(heading, sizeof(heading), _("Player %d, choose a driver"),
@ -111,7 +111,7 @@ CharSel::CharSel(int whichPlayer)
m_current_kart = -1;
const int LAST_KART = user_config->m_player[m_player_index].getLastKartId();
if( LAST_KART != -1 && kartAvailable(LAST_KART))// is LAST_KART not in vector of selected karts
if( LAST_KART != -1 && kart_properties_manager->kartAvailable(LAST_KART))// is LAST_KART not in vector of selected karts
{
int local_index = 0;
for(unsigned int i=0; i<m_index_avail_karts.size(); i++)
@ -214,7 +214,7 @@ void CharSel::switchGroup()
kart_properties_manager->getKartsInGroup(user_config->m_kart_group);
for(unsigned int i=0; i<karts.size(); i++)
{
if(kartAvailable(karts[i]))
if(kart_properties_manager->kartAvailable(karts[i]))
{
m_index_avail_karts.push_back(karts[i]);
}
@ -361,7 +361,7 @@ void CharSel::select()
user_config->m_player[m_player_index].setLastKartId(kart_id);
// Add selected kart (token) to selected karts vector so it cannot be
// selected again
kart_properties_manager->m_selected_karts.push_back(kart_id);
kart_properties_manager->testAndSetKart(kart_id);
}
if (race_manager->getNumLocalPlayers() > 1)
@ -393,6 +393,7 @@ void CharSel::select()
if(network_manager->getMode()==NetworkManager::NW_CLIENT)
{
network_manager->sendKartsInformationToServer();
menu_manager->pushMenu(MENUID_START_RACE_FEEDBACK);
}
else
@ -426,24 +427,4 @@ void CharSel::handle(GameAction action, int value)
return;
} // if cursor down
BaseGUI::handle(action, value);
} // handle
//----------------------------------------------------------------------------
// Function checks the vector of previously selected karts and returns true if
// kart i is in the vector and false if it is not.
bool CharSel::kartAvailable(int kartid)
{
if (!kart_properties_manager->m_selected_karts.empty())
{
std::vector<int>::iterator it;
for (it = kart_properties_manager->m_selected_karts.begin();
it < kart_properties_manager->m_selected_karts.end(); it++)
{
if ( kartid == *it)
return false;
}
}
const KartProperties *kartprop=kart_properties_manager->getKartById(kartid);
return !unlock_manager->isLocked(kartprop->getIdent());
} // kartAvailable
} // handle

View File

@ -38,7 +38,6 @@ private:
unsigned int m_num_entries; // number of entries to display
std::vector<int> m_index_avail_karts;
static const unsigned int m_max_entries=7;
bool kartAvailable(int kart);
void updateScrollPosition();
int computeIndent(int n) {return 40+abs((int)(m_max_entries-1)/2 - n)*3;}
void switchGroup();

View File

@ -54,6 +54,7 @@
#include "challenges_menu.hpp"
#include "feature_unlocked.hpp"
#include "start_race_feedback.hpp"
#include "network_info.hpp"
using namespace std;
@ -238,6 +239,10 @@ void MenuManager::update()
break;
case MENUID_START_RACE_FEEDBACK:
m_current_menu = new StartRaceFeedback();
break;
case MENUID_NETWORK_INFO:
m_current_menu = new NetworkInfo();
break;
default:
break;
} // switch

View File

@ -44,7 +44,8 @@ enum MenuManagerIDs
MENUID_EXITGAME,
MENUID_GRANDPRIXSELECT,
MENUID_UNLOCKED_FEATURE,
MENUID_START_RACE_FEEDBACK,
MENUID_START_RACE_FEEDBACK, // 'loading'
MENUID_NETWORK_INFO, // wait for clients to connect
// menu configuration
MENUID_CONFIG_DISPLAY,

88
src/gui/network_info.cpp Normal file
View File

@ -0,0 +1,88 @@
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2006 SuperTuxKart-Team
//
// 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 <SDL/SDL.h>
#include "network_info.hpp"
#include "widget_manager.hpp"
#include "translation.hpp"
#include "network/network_manager.hpp"
#include "stk_config.hpp"
#include "gui/menu_manager.hpp"
enum WidgetTokens
{
WTOK_MSG,
WTOK_CLIENT,
WTOK_OK
};
NetworkInfo::NetworkInfo()
{
//Add some feedback so people know they are going to start the race
widget_manager->reset();
Widget *w_prev=widget_manager->addTitleWgt( WTOK_MSG, 60, 7, _("Waiting for clients ...") );
w_prev->setPosition(WGT_DIR_CENTER, 0.0, NULL,
WGT_DIR_FROM_TOP, 0.1f, NULL);
// Display a single space to avoid warnings from the widget_manager
Widget *w=widget_manager->addTextWgt(WTOK_CLIENT, 60, 10, " ");
w->setPosition(WGT_DIR_CENTER, 0.0, NULL,
WGT_DIR_UNDER_WIDGET, 0.0, w_prev);
w_prev = w;
w=widget_manager->addTextButtonWgt(WTOK_OK, 60, 7, _("OK"));
w->setPosition(WGT_DIR_CENTER, 0.0, NULL,
WGT_DIR_UNDER_WIDGET, 0.1f, w_prev);
widget_manager->layout(WGT_AREA_TOP);
m_num_clients = 0;
} // NetworkInfo
//-----------------------------------------------------------------------------
NetworkInfo::~NetworkInfo()
{
widget_manager->reset();
}
//-----------------------------------------------------------------------------
void NetworkInfo::update(float DELTA)
{
widget_manager->update(0.0f);
if(m_num_clients==network_manager->getNumClients()) return;
// At least one new client has connected:
std::string s="";
m_num_clients = network_manager->getNumClients();
for(unsigned int i=1; i<=m_num_clients; i++)
{
s+=network_manager->getClientName(i)+"\n";
}
widget_manager->setWgtText(WTOK_CLIENT, s);
} // update
//-----------------------------------------------------------------------------
void NetworkInfo::select()
{
switch( widget_manager->getSelectedWgt() )
{
case WTOK_OK:
network_manager->switchToCharacterSelection();
menu_manager->popMenu();
break;
}
} // select

34
src/gui/network_info.hpp Normal file
View File

@ -0,0 +1,34 @@
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2008 Joerg Henrichs
//
// 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_NETWORK_INFO_H
#define HEADER_NETWORK_INFO_H
#include "base_gui.hpp"
class NetworkInfo : public BaseGUI
{
private:
unsigned int m_num_clients;
public:
NetworkInfo();
~NetworkInfo();
void update(float DELTA);
void select();
};
#endif

View File

@ -30,6 +30,8 @@ enum WidgetTokens
StartRaceFeedback::StartRaceFeedback()
{
network_manager->switchToRaceDataSynchronisation();
m_state = network_manager->getMode()==NetworkManager::NW_NONE ? SRF_LOADING : SRF_NETWORK;
//Add some feedback so people know they are going to start the race
@ -65,10 +67,17 @@ void StartRaceFeedback::update(float DELTA)
m_state = SRF_NETWORK;
break;
case SRF_NETWORK:
// The server only waits for one frame:
if(network_manager->getMode()==NetworkManager::NW_SERVER)
{
network_manager->sendRaceInformationToClients();
else
network_manager->waitForRaceInformation();
m_state = SRF_LOADING_DISPLAY;
widget_manager->setWgtText(WTOK_MSG, _("Loading race...") );
return;
}
// The client have to be busy waiting till the race data has arrived:
if(network_manager->getState()==NetworkManager::NS_WAITING_FOR_RACE_DATA)
return;
m_state = SRF_LOADING_DISPLAY;
widget_manager->setWgtText(WTOK_MSG, _("Loading race...") );
break;

View File

@ -1006,6 +1006,10 @@
RelativePath="../../../src\gui\menu_manager.cpp"
>
</File>
<File
RelativePath="..\..\gui\network_info.cpp"
>
</File>
<File
RelativePath="../../../src\gui\num_players.cpp"
>
@ -1480,6 +1484,10 @@
RelativePath="../../../src\gui\menu_manager.hpp"
>
</File>
<File
RelativePath="..\..\gui\network_info.hpp"
>
</File>
<File
RelativePath="../../../src\gui\num_players.hpp"
>

View File

@ -26,6 +26,8 @@
#include "kart_properties.hpp"
#include "translation.hpp"
#include "user_config.hpp"
#include "unlock_manager.hpp"
#if defined(WIN32) && !defined(__CYGWIN__)
# define snprintf _snprintf
#endif
@ -159,6 +161,27 @@ int KartPropertiesManager::getKartByGroup(const std::string& group, int n) const
return -1;
} // getKartByGroup
//-----------------------------------------------------------------------------
bool KartPropertiesManager::testAndSetKart(int kartid)
{
if(!kartAvailable(kartid)) return false;
m_selected_karts.push_back(kartid);
return true;
} // testAndSetKart
//-----------------------------------------------------------------------------
bool KartPropertiesManager::kartAvailable(int kartid)
{
std::vector<int>::iterator it;
for (it = m_selected_karts.begin(); it < m_selected_karts.end(); it++)
{
if ( kartid == *it) return false;
}
const KartProperties *kartprop=getKartById(kartid);
if(unlock_manager->isLocked(kartprop->getIdent())) return false;
return true;
} // testAndSetKart
//-----------------------------------------------------------------------------
void KartPropertiesManager::fillWithRandomKarts(std::vector<RemoteKartInfo>& vec)
{

View File

@ -31,6 +31,10 @@ class KartPropertiesManager
private:
std::vector<std::string> m_all_groups;
std::map<std::string, std::vector<int> > m_groups;
// vector containing kart numbers that have been selected in multiplayer
// games. This it used to ensure the same kart can not be selected more
// than once.
std::vector<int> m_selected_karts;
protected:
float m_max_steer_angle;
@ -41,12 +45,7 @@ protected:
public:
KartPropertiesManager();
~KartPropertiesManager();
// vector containing kart numbers that have been selected in multiplayer
// games. This it used to ensure the same kart can not be selected more
// than once.
std::vector<int> m_selected_karts;
const KartProperties* getKartById (int i) const;
const KartProperties* getKart (const std::string IDENT) const;
const int getKartId (const std::string IDENT) const;
@ -58,7 +57,11 @@ public:
getAllGroups () const {return m_all_groups; }
const std::vector<int>& getKartsInGroup (const std::string& g)
{return m_groups[g]; }
void clearAllSelectedKarts() {m_selected_karts.clear();}
void removeLastSelectedKart() {m_selected_karts.pop_back();}
int getNumSelectedKarts() const {return m_selected_karts.size();}
bool kartAvailable(int kartid);
bool testAndSetKart(int kartid);
/** Fill the empty positions in the given vector with random karts */
void fillWithRandomKarts (std::vector<RemoteKartInfo>& vec);
void removeTextures ();

View File

@ -536,7 +536,11 @@ int main(int argc, char *argv[] )
fprintf(stderr, "Problems initialising network connections,\n"
"Running in non-network mode.\n");
}
// On the server start with the network information page
if(network_manager->getMode()==NetworkManager::NW_SERVER)
{
menu_manager->pushMenu(MENUID_NETWORK_INFO);
}
// Not replaying
// =============
if(!user_config->m_profile)

View File

@ -21,13 +21,14 @@
#include "stk_config.hpp"
#include "user_config.hpp"
#include "race_manager.hpp"
#include "kart_properties_manager.hpp"
NetworkManager* network_manager = 0;
NetworkManager::NetworkManager()
{
m_mode = NW_NONE;
m_state = NS_SYNCHRONISING;
m_state = NS_ACCEPT_CONNECTIONS;
m_port = 12345;
m_server_address = "172.31.41.53";
m_num_clients = 0;
@ -86,6 +87,7 @@ bool NetworkManager::initServer()
}
fprintf(stderr, "Server initialised, waiting for connections ...\n");
m_client_names.push_back("server");
return true;
#endif
} // initServer
@ -145,12 +147,12 @@ bool NetworkManager::initClient()
return true;
#endif
} // initServer
} // initClient
// ----------------------------------------------------------------------------
void NetworkManager::handleNewConnection(ENetEvent *event)
{
if(m_state!=NS_SYNCHRONISING)
if(m_state!=NS_ACCEPT_CONNECTIONS)
{
// We don't accept connections atm
return;
@ -161,13 +163,14 @@ void NetworkManager::handleNewConnection(ENetEvent *event)
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");
} // handleNewConnection
// ----------------------------------------------------------------------------
void NetworkManager::handleDisconnection(ENetEvent *event)
{
if(m_state!=NS_SYNCHRONISING)
if(m_state!=NS_ACCEPT_CONNECTIONS)
{
fprintf(stderr, "Disconnect while in race - close your eyes and hope for the best.\n");
return;
@ -178,14 +181,86 @@ void NetworkManager::handleDisconnection(ENetEvent *event)
} // handleDisconnection
// ----------------------------------------------------------------------------
void NetworkManager::handleNewMessage(ENetEvent *event)
void NetworkManager::handleServerMessage(ENetEvent *event)
{
if(m_state==NS_SYNCHRONISING)
switch(m_state)
{
case NS_ACCEPT_CONNECTIONS:
fprintf(stderr, "Received a receive event while waiting for client - ignored.\n");
return;
}
} // handleNewMessage
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))
{
// send 'ok' message to client and all other clients
m_kart_info.push_back(RemoteKartInfo(playerid, name, user, hostid));
}
else
{
// send 'not avail' to sender
}
break;
}
case NS_READY_SET_GO_BARRIER:
m_barrier_count++;
if(m_barrier_count==m_num_clients)
{
// broadcast start message
m_state = NS_RACING;
}
break;
case NS_KART_INFO_BARRIER:
m_barrier_count++;
if(m_barrier_count==m_num_clients)
{
// broadcast start message
m_state = NS_RACING;
}
break;
} // switch m_state
} // handleServerMessage
// ----------------------------------------------------------------------------
void NetworkManager::switchToReadySetGoBarrier()
{
assert(m_state == NS_CHARACTER_SELECT);
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::switchToRaceDataSynchronisation()
{
assert(m_state == NS_CHARACTER_SELECT);
m_state = NS_KART_INFO_BARRIER;
m_barrier_count = 0;
} // switchToRaceDataSynchronisation
// ----------------------------------------------------------------------------
void NetworkManager::handleClientMessage(ENetEvent *event)
{
switch(m_state)
{
case NS_ACCEPT_CONNECTIONS:
fprintf(stderr, "Received a receive event while waiting for client - ignored.\n");
return;
} // switch m_state
} // handleClientMessage
// ----------------------------------------------------------------------------
void NetworkManager::update(float dt)
@ -202,7 +277,12 @@ void NetworkManager::update(float dt)
switch (event.type)
{
case ENET_EVENT_TYPE_CONNECT: handleNewConnection(&event); break;
case ENET_EVENT_TYPE_RECEIVE: handleNewMessage(&event); break;
case ENET_EVENT_TYPE_RECEIVE:
if(m_mode==NW_SERVER)
handleServerMessage(&event);
else
handleClientMessage(&event);
break;
case ENET_EVENT_TYPE_DISCONNECT: handleDisconnection(&event); break;
case ENET_EVENT_TYPE_NONE: break;
}

View File

@ -35,8 +35,14 @@ public:
// The mode the network manager is operating in
enum NetworkMode {NW_SERVER, NW_CLIENT, NW_NONE};
// The current state.
enum NetworkState {NS_SYNCHRONISING, NS_RACING};
// States for the finite state machine. First for server:
enum NetworkState {NS_ACCEPT_CONNECTIONS, NS_KART_INFO_BARRIER,
// Then client only states:
NS_CHARACTER_CONFIRMED,
NS_CHARACTER_REJECTED,
NS_WAITING_FOR_RACE_DATA,
// Shared states
NS_CHARACTER_SELECT, NS_READY_SET_GO_BARRIER, NS_RACING};
private:
NetworkMode m_mode;
@ -46,6 +52,8 @@ private:
int m_num_clients;
std::vector<RemoteKartInfo> m_kart_info;
int m_host_id;
std::vector<std::string> m_client_names;
int m_barrier_count;
#ifdef HAVE_ENET
ENetHost *m_host;
#endif
@ -53,20 +61,24 @@ private:
bool initServer();
bool initClient();
void handleNewConnection(ENetEvent *event);
void handleNewMessage (ENetEvent *event);
void handleServerMessage(ENetEvent *event);
void handleClientMessage(ENetEvent *event);
void handleDisconnection(ENetEvent *event);
void testSetCharacter (ENetEvent *event);
public:
NetworkManager();
~NetworkManager();
void setMode(NetworkMode m) {m_mode = m; }
NetworkMode getMode() const {return m_mode; }
void setState(NetworkState s) {m_state = s; }
NetworkState getState() const {return m_state; }
int getHostId() const {return m_host_id; }
int getNumClients() const {return m_num_clients; }
void setPort(int p) {m_port=p; }
void setServerIP(const std::string &s) {m_server_address=s; }
void setMode(NetworkMode m) {m_mode = m; }
NetworkMode getMode() const {return m_mode; }
void setState(NetworkState s) {m_state = s; }
NetworkState getState() const {return m_state; }
int getHostId() const {return m_host_id; }
unsigned int getNumClients() const {return m_num_clients; }
const std::string&
getClientName(int i) const {return m_client_names[i];}
void setPort(int p) {m_port=p; }
void setServerIP(const std::string &s) {m_server_address=s; }
void setKartInfo(int player_id, const std::string& kart,
const std::string& user="", int hostid=-1);
bool initialiseConnections();
@ -75,6 +87,10 @@ public:
void waitForKartsInformation();
void sendRaceInformationToClients();
void waitForRaceInformation();
void switchToReadySetGoBarrier();
void switchToCharacterSelection();
void switchToRaceDataSynchronisation();
};
extern NetworkManager *network_manager;

View File

@ -189,6 +189,7 @@ World::World()
}
if( m_p_replay_player ) m_p_replay_player->showReplayAt( 0.0 );
#endif
network_manager->switchToReadySetGoBarrier();
} // World
//-----------------------------------------------------------------------------