diff --git a/src/Makefile.am b/src/Makefile.am index 61bbe7020..667c17c64 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -35,7 +35,7 @@ supertuxkart_SOURCES = main.cpp \ network/message.cpp network/message.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/race_start_message.hpp network/character_confirm_message.hpp \ network/connect_message.hpp network/connect_message.cpp \ network/num_players_message.hpp network/world_loaded_message.hpp \ network/connect_message.hpp network/character_info_message.hpp \ @@ -86,8 +86,6 @@ supertuxkart_SOURCES = main.cpp \ shadow.cpp shadow.hpp \ particle_system.cpp particle_system.hpp \ game_manager.cpp game_manager.hpp \ - widget_manager.cpp widget_manager.hpp \ - widget.cpp widget.hpp \ camera.cpp camera.hpp \ sdldrv.cpp sdldrv.hpp \ moveable.cpp moveable.hpp \ @@ -113,6 +111,8 @@ supertuxkart_SOURCES = main.cpp \ lisp/lexer.cpp lisp/lexer.hpp \ lisp/parser.cpp lisp/parser.hpp \ lisp/writer.cpp lisp/writer.hpp \ + gui/widget_manager.cpp gui/widget_manager.hpp \ + gui/widget.cpp gui/widget.hpp \ gui/menu_manager.cpp gui/menu_manager.hpp \ gui/base_gui.cpp gui/base_gui.hpp \ gui/race_gui.cpp gui/race_gui.hpp \ diff --git a/src/gui/char_sel.cpp b/src/gui/char_sel.cpp index 1c0a2ef89..e1744b32a 100644 --- a/src/gui/char_sel.cpp +++ b/src/gui/char_sel.cpp @@ -227,17 +227,13 @@ void CharSel::updateScrollPosition() // set the 'selection changed' flag in the widget_manager, since update // scroll position (when called on action up/down) will change the kart // to display, even though it's the same widget - int current_widget = widget_manager->getSelectedWgt(); - widget_manager->setSelectedWgt(current_widget+1); - widget_manager->setSelectedWgt(current_widget); + widget_manager->setSelectionChanged(); } // updateScrollPosition //----------------------------------------------------------------------------- void CharSel::switchGroup() { m_index_avail_karts.clear(); - // This loop is too long (since getNumberOfKarts returns all karts in all groups), - // but the loop is left if no more kart is found. const std::vector &karts = kart_properties_manager->getKartsInGroup(user_config->m_kart_group); for(unsigned int i=0; iupdate(dt); return; } + + // Are we still waiting for a confirmation? + if(network_manager->getState()==NetworkManager::NS_WAIT_FOR_KART_CONFIRMATION) + { + widget_manager->update(dt); + return; + } + + // The selection was confirmed, proceed: + if(network_manager->getState()==NetworkManager::NS_KART_CONFIRMED) + { + nextMenu(); + return; + } + static bool first=true; if(first) { @@ -372,6 +400,56 @@ void CharSel::update(float dt) } // update //---------------------------------------------------------------------------- +/** Pushes the next menu onto the stack. In case of split screen that might + * be another instance of the character selection menu. + */ +void CharSel::nextMenu() +{ + if(race_manager->getNumLocalPlayers() > 1 && + menu_manager->isCurrentMenu(MENUID_CHARSEL_P1)) + { + menu_manager->pushMenu(MENUID_CHARSEL_P2); + return; + } + + if(race_manager->getNumLocalPlayers() > 2 && + menu_manager->isCurrentMenu(MENUID_CHARSEL_P2)) + { + menu_manager->pushMenu(MENUID_CHARSEL_P3); + return; + } + + if (race_manager->getNumLocalPlayers() > 3 && + menu_manager->isCurrentMenu(MENUID_CHARSEL_P3)) + { + menu_manager->pushMenu(MENUID_CHARSEL_P4); + return; + } + + // Last character selected + if(network_manager->getMode()==NetworkManager::NW_CLIENT) + { + // 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 + menu_manager->pushMenu(MENUID_TRACKSEL); + } +} // nextMenu + +// ---------------------------------------------------------------------------- +/** Handles widget selection. + */ void CharSel::select() { int wgt = widget_manager->getSelectedWgt(); @@ -389,6 +467,9 @@ void CharSel::select() updateScrollPosition(); return; } + + // Now it must be a character selection: + // ------------------------------------- int token = widget_manager->getSelectedWgt() - WTOK_RACER0; if(token<0 || token>(int)m_index_avail_karts.size()) { @@ -409,61 +490,19 @@ void CharSel::select() return; } const KartProperties* KP = kart_properties_manager->getKartById(kart_id); - if (KP != NULL) - { - race_manager->setLocalKartInfo(m_player_index, KP->getIdent()); - 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->testAndSetKart(kart_id); - if(network_manager->getMode()==NetworkManager::NW_CLIENT) - network_manager->sendCharacterSelected(m_player_index); - } + if (!KP) return; - if (race_manager->getNumLocalPlayers() > 1) + race_manager->setLocalKartInfo(m_player_index, KP->getIdent()); + user_config->m_player[m_player_index].setLastKartId(kart_id); + // Send the confirmation message to all clients. + network_manager->sendCharacterSelected(m_player_index, + KP->getIdent()); + // In non-network more or on the server add selected kart (token) to + // selected karts vector so it cannot be selected again + if(network_manager->getMode()!=NetworkManager::NW_CLIENT) { - if (menu_manager->isCurrentMenu(MENUID_CHARSEL_P1)) - { - menu_manager->pushMenu(MENUID_CHARSEL_P2); - return; - } - } - - if (race_manager->getNumLocalPlayers() > 2) - { - if (menu_manager->isCurrentMenu(MENUID_CHARSEL_P2)) - { - menu_manager->pushMenu(MENUID_CHARSEL_P3); - return; - } - } - - if (race_manager->getNumLocalPlayers() > 3) - { - if (menu_manager->isCurrentMenu(MENUID_CHARSEL_P3)) - { - menu_manager->pushMenu(MENUID_CHARSEL_P4); - return; - } - } - - // Last character selected" - if(network_manager->getMode()==NetworkManager::NW_CLIENT) - { - // 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 - menu_manager->pushMenu(MENUID_TRACKSEL); + kart_properties_manager->selectKart(kart_id); + nextMenu(); } } // select diff --git a/src/gui/char_sel.hpp b/src/gui/char_sel.hpp index 6ad05c400..25a1b7b2d 100644 --- a/src/gui/char_sel.hpp +++ b/src/gui/char_sel.hpp @@ -41,13 +41,15 @@ private: void updateScrollPosition(); int computeIndent(int n) {return 40+abs((int)(m_max_entries-1)/2 - n)*3;} void switchGroup(); + void nextMenu(); + void switchCharacter(int n); public: - CharSel(int which_player); - ~CharSel(); + CharSel(int which_player); + ~CharSel(); - void switchCharacter(int n); - void update(float dt); - void select(); + void update(float dt); + void select(); + void updateAvailableCharacters(); virtual void handle(GameAction, int); }; diff --git a/src/gui/start_race_feedback.cpp b/src/gui/start_race_feedback.cpp index 27bf0cbd5..cee3cb3bf 100644 --- a/src/gui/start_race_feedback.cpp +++ b/src/gui/start_race_feedback.cpp @@ -28,6 +28,7 @@ enum WidgetTokens WTOK_MSG }; +/** Constructor for feedback screen. */ StartRaceFeedback::StartRaceFeedback() { m_is_first_frame = true; @@ -45,16 +46,21 @@ StartRaceFeedback::StartRaceFeedback() } widget_manager->layout(WGT_AREA_ALL); -} +} // StartRaceFeedback //----------------------------------------------------------------------------- +/** Destructor for feedback screen. + */ StartRaceFeedback::~StartRaceFeedback() { widget_manager->reset(); -} - +} // ~StartRaceFeedback //----------------------------------------------------------------------------- +/** Updates the feedback screen. Depending on the state of the network manager + * it will change the displayed text. + * \param delta Time step size. + */ void StartRaceFeedback::update(float delta) { // First test if we are still waiting diff --git a/src/gui/start_race_feedback.hpp b/src/gui/start_race_feedback.hpp index 274ef7c96..96f201241 100644 --- a/src/gui/start_race_feedback.hpp +++ b/src/gui/start_race_feedback.hpp @@ -20,9 +20,18 @@ #include "base_gui.hpp" +/** This class is used to give feedback to the user while loading the track. + * It either displays a 'Loading track' or a 'Wait for synchronisation' + * message (dependent on the stage of the race manager). + */ class StartRaceFeedback: public BaseGUI { protected: + /** Flag used to make sure that the text is actually displayed (i.e + * update was called once) before loading the track - otherwise the + * text is set in the widget, but not on the screen since the screen + * wasn't updated. + */ bool m_is_first_frame; public: StartRaceFeedback(); diff --git a/src/widget.cpp b/src/gui/widget.cpp similarity index 100% rename from src/widget.cpp rename to src/gui/widget.cpp diff --git a/src/widget.hpp b/src/gui/widget.hpp similarity index 100% rename from src/widget.hpp rename to src/gui/widget.hpp diff --git a/src/widget_manager.cpp b/src/gui/widget_manager.cpp similarity index 100% rename from src/widget_manager.cpp rename to src/gui/widget_manager.cpp diff --git a/src/widget_manager.hpp b/src/gui/widget_manager.hpp similarity index 98% rename from src/widget_manager.hpp rename to src/gui/widget_manager.hpp index b11cba797..c97c9d54a 100644 --- a/src/widget_manager.hpp +++ b/src/gui/widget_manager.hpp @@ -200,9 +200,12 @@ public: int getSelectedWgt() const { return m_selected_wgt_token; } void setSelectedWgt(const int TOKEN); - //Checks if the selected widget changed since the last call to update() + /** Checks if the selected widget changed since the last call to update() */ bool selectionChanged() const { return m_selection_change; } + /** Forces the changed selection mode. */ + void setSelectionChanged() { m_selection_change = true; } + /* Macro functions. They are widgets with special predefined values. */ //FIXME: Temporal, till I rename addWgt() to addEmptyWgt() diff --git a/src/ide/vc9/enet.vcproj b/src/ide/vc9/enet.vcproj index 40ce5c128..d88efa45f 100644 --- a/src/ide/vc9/enet.vcproj +++ b/src/ide/vc9/enet.vcproj @@ -106,7 +106,7 @@ Optimization="2" EnableIntrinsicFunctions="true" WholeProgramOptimization="false" - AdditionalIncludeDirectories="C:\cygwin\home\joerg\nw\src\enet\include" + AdditionalIncludeDirectories="../../enet/include" PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS" RuntimeLibrary="2" EnableFunctionLevelLinking="true" diff --git a/src/ide/vc9/supertuxkart.vcproj b/src/ide/vc9/supertuxkart.vcproj index 9fd304177..d9cb7bdd0 100644 --- a/src/ide/vc9/supertuxkart.vcproj +++ b/src/ide/vc9/supertuxkart.vcproj @@ -915,14 +915,6 @@ RelativePath="..\..\vec3.cpp" > - - - - @@ -1042,6 +1034,14 @@ RelativePath="../../../src\gui\track_sel.cpp" > + + + + - - - - @@ -1564,6 +1556,14 @@ RelativePath="../../../src\gui\track_sel.hpp" > + + + + + + diff --git a/src/kart_properties_manager.cpp b/src/kart_properties_manager.cpp index f5a091f07..850ffc425 100644 --- a/src/kart_properties_manager.cpp +++ b/src/kart_properties_manager.cpp @@ -224,6 +224,16 @@ bool KartPropertiesManager::kartAvailable(int kartid) return true; } // testAndSetKart +//----------------------------------------------------------------------------- +/** Sets a kart to be selected by specifying the identifier (name) of the kart. + * \param kart_name Name of the kart. + */ +void KartPropertiesManager::selectKartName(const std::string &kart_name) +{ + int kart_id = getKartId(kart_name); + selectKart(kart_id); +} // selectKartName + //----------------------------------------------------------------------------- /** Returns a list of randomly selected karts. This list firstly contains * karts in the currently selected group, but which are not in the list diff --git a/src/kart_properties_manager.hpp b/src/kart_properties_manager.hpp index 9c7e3f572..c83dbe5c7 100644 --- a/src/kart_properties_manager.hpp +++ b/src/kart_properties_manager.hpp @@ -66,6 +66,9 @@ public: bool kartAvailable(int kartid); std::vector getAllAvailableKarts() const; void setUnavailableKarts(std::vector); + /** Sets a kartid to be selected (without any tests). */ + void selectKart(int kartid) {m_selected_karts.push_back(kartid);} + void selectKartName(const std::string &kart_name); bool testAndSetKart(int kartid); std::vector getRandomKartList(int count, RemoteKartInfoList& existing_karts); void removeTextures (); diff --git a/src/main.cpp b/src/main.cpp index 9a46eacf1..e0c5b3259 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -55,7 +55,7 @@ #include "file_manager.hpp" #include "loader.hpp" #include "game_manager.hpp" -#include "widget_manager.hpp" +#include "gui/widget_manager.hpp" #include "material_manager.hpp" #include "sdldrv.hpp" #include "callback_manager.hpp" diff --git a/src/network/character_confirm_message.hpp b/src/network/character_confirm_message.hpp new file mode 100755 index 000000000..92addc51d --- /dev/null +++ b/src/network/character_confirm_message.hpp @@ -0,0 +1,72 @@ +// $Id: character_confirm_message.hpp 2128 2008-06-13 00:53:52Z cosmosninja $ +// +// 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_CHARACTER_CONFIRM_MESSAGE_HPP +#define HEADER_CHARACTER_CONFIRM_MESSAGE_HPP + +#include + +#include "network/message.hpp" + + +/** This message is from the server to all clients to inform them about a + * newly selected character. This means that this character is not available + * anymore. The message contains the hostid of the client who selected this + * character (0 in case of server), so that this message acts as a + * confirmation for the corresponding client (or a reject if the message has + * a different hostid, meaning that another client selected the character + * earlier). + */ +class CharacterConfirmMessage : public Message +{ +private: + /** The host id. */ + int m_host_id; + /** Name of the selected kart. */ + std::string m_kart_name; +public: + /** Constructor, takes the name of the kart name and the host id. + * \param kart_name Name of the kart. + * \param host_id Id of the host who selected this character. + */ + CharacterConfirmMessage(const std::string &kart_name, int host_id) + : Message(Message::MT_CHARACTER_CONFIRM) + { + allocate(getStringLength(kart_name) + getCharLength()); + addString(kart_name); + addChar(host_id); + } // CharacterConfirmMessage + + // ------------------------------------------------------------------------ + /** Unpacks a character confirm message. + * \param pkt Received enet packet. + */ + CharacterConfirmMessage(ENetPacket* pkt):Message(pkt, MT_CHARACTER_CONFIRM) + { + m_kart_name = getString(); + m_host_id = getChar(); + } // CharacterConfirmMessage(EnetPacket) + // ------------------------------------------------------------------------ + /** Returns the kart name contained in a received message. */ + const std::string &getKartName() const { return m_kart_name; } + /** Returns the host id contained in a received message. */ + int getHostId() const { return m_host_id; } + +}; // CharacterConfirmMessage +#endif diff --git a/src/network/character_selected_message.hpp b/src/network/character_selected_message.hpp index db4f671d0..38d891738 100644 --- a/src/network/character_selected_message.hpp +++ b/src/network/character_selected_message.hpp @@ -21,18 +21,42 @@ #define HEADER_CHARACTER_SELECTED_MESSAGE_H #include "network/message.hpp" -#include "user_config.hpp" #include "race_manager.hpp" #include "network/remote_kart_info.hpp" +/** This message is send contains information about selected karts. It is send + * from the client to the server to indicate a selected kart, and from the + * server to the clients to indicate that a kart was selected. In the latter + * case it contains the hostid of the successful selecter. This way a client + * selecting a kart can check if its selection was successful or not, and + * other clients are informed that a certain kart is not available anymore. + */ class CharacterSelectedMessage : public Message { private: + /** Number of local players on a host. If the message is send from the + * server to the clients, this field instead contains the host id of + * the host which selected the kart + */ int m_num_local_players; + /** Stores information about the selected kart. */ RemoteKartInfo m_kart_info; -// For now this is an empty message + public: - CharacterSelectedMessage(int player_id) :Message(Message::MT_CHARACTER_INFO) + /** Contains information about a selected kart. When send from the client + * to the server, it contains the number of local players (which + * technically needs only to be sent once); when send from from the server + * to the clients this field instead contains the host id of the host + * selected the character. This allows the client to detect if a selected + * kart was not confirmed by the server (i.e. another client or the server + * has selected the kart first + * \param player_id The local player id. + * \param host_id If this value is specified (>-1), then this value is + * used in the message instead of the number of local + * players. + */ + CharacterSelectedMessage(int player_id, int host_id=-1) + : Message(Message::MT_CHARACTER_INFO) { m_kart_info = race_manager->getLocalKartInfo(player_id); m_num_local_players = race_manager->getNumLocalPlayers(); @@ -46,9 +70,18 @@ public: addString(m_kart_info.getPlayerName()); // Piggy backing this information saves sending it as a separate // message. It is actually only required in the first message - addChar(race_manager->getNumLocalPlayers()); + if(host_id>-1) + addChar(host_id); + else + addChar(race_manager->getNumLocalPlayers()); } // CharacterSelectedMessage + // ------------------------------------------------------------------------ + /** Unpacks a character selected message. The additional field is either + * the number of local players (when send from client to server), or the + * hostid of the host selected the character. + * \param pkt Received enet packet. + */ CharacterSelectedMessage(ENetPacket* pkt):Message(pkt, MT_CHARACTER_INFO) { m_kart_info.setLocalPlayerId(getChar()); @@ -56,8 +89,18 @@ public: m_kart_info.setPlayerName(getString()); m_num_local_players = getChar(); } // CharacterSelectedMessage(EnetPacket) + // ------------------------------------------------------------------------ + /** Returns the remote kart info structure of the selected kart. */ const RemoteKartInfo& getKartInfo () const { return m_kart_info; } + + /** Returns the number of local players. */ int getNumPlayers() const { return m_num_local_players; } + + /** Returns the host id of the host who selected the kart successfully. + * This information is actually stored in m_num_local_players field, which + * is used when a client receives this message. + */ + int getHostId () const { return m_num_local_players; } }; // CharacterSelectedMessage #endif diff --git a/src/network/message.hpp b/src/network/message.hpp index d1c42b229..39e2ea190 100644 --- a/src/network/message.hpp +++ b/src/network/message.hpp @@ -43,9 +43,9 @@ class Message { public: - enum MessageType {MT_CONNECT=1, MT_CHARACTER_INFO, + enum MessageType {MT_CONNECT=1, MT_CHARACTER_INFO, MT_CHARACTER_CONFIRM, MT_RACE_INFO, MT_RACE_START, MT_WORLD_LOADED, - MT_KART_INFO, MT_KART_CONTROL, + MT_KART_INFO, MT_KART_CONTROL, MT_RACE_STATE}; private: ENetPacket *m_pkt; diff --git a/src/network/network_manager.cpp b/src/network/network_manager.cpp index 017aad211..328464fec 100644 --- a/src/network/network_manager.cpp +++ b/src/network/network_manager.cpp @@ -26,12 +26,14 @@ #include "network/world_loaded_message.hpp" #include "network/race_state.hpp" #include "network/kart_control_message.hpp" +#include "network/character_confirm_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" +#include "gui/menu_manager.hpp" +#include "gui/char_sel.hpp" NetworkManager* network_manager = 0; @@ -220,6 +222,7 @@ void NetworkManager::handleMessageAtServer(ENetEvent *event) m_num_clients++; return; } + case NS_KART_CONFIRMED: // Fall through case NS_CHARACTER_SELECT: { CharacterSelectedMessage m(event->packet); @@ -235,12 +238,22 @@ void NetworkManager::handleMessageAtServer(ENetEvent *event) RemoteKartInfo ki=m.getKartInfo(); ki.setHostId(hostid); m_kart_info.push_back(ki); + + int kart_id = kart_properties_manager->getKartId(ki.getKartName()); + kart_properties_manager->testAndSetKart(kart_id); + CharSel *menu = dynamic_cast(menu_manager->getCurrentMenu()); + if(menu) + menu->updateAvailableCharacters(); + + // Broadcast the information about a selected kart to all clients + CharacterConfirmMessage ccm(ki.getKartName(), hostid); + broadcastToClients(ccm); // 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 == (int)m_num_clients && - m_num_all_players==(int)m_kart_info.size()) + m_num_all_players==(int)m_kart_info.size()) { // we can't send the race info yet, since the server might // not yet have selected all characters! @@ -275,8 +288,47 @@ void NetworkManager::handleMessageAtClient(ENetEvent *event) m_state = NS_CHARACTER_SELECT; break; } + case NS_CHARACTER_SELECT: + { + CharacterConfirmMessage m(event->packet); + kart_properties_manager->selectKartName(m.getKartName()); + CharSel *menu = dynamic_cast(menu_manager->getCurrentMenu()); + if(menu) + menu->updateAvailableCharacters(); + break; + } + case NS_WAIT_FOR_KART_CONFIRMATION: + { + CharacterConfirmMessage m(event->packet); + kart_properties_manager->selectKartName(m.getKartName()); + + // If the current menu is the character selection menu, + // update the menu so that the newly taken character is removed. + CharSel *menu = dynamic_cast(menu_manager->getCurrentMenu()); + if(menu) + menu->updateAvailableCharacters(); + // Check if we received a message about the kart we just selected. + // If so, the menu needs to progress, otherwise a different kart + // must be selected by the current player. + if(m.getKartName()==m_kart_to_confirm) + { + int host_id = m.getHostId(); + m_state = (host_id == getMyHostId()) ? NS_KART_CONFIRMED + : NS_CHARACTER_SELECT; + } // m.getkartName()==m_kart_to_confirm + break; + } // wait for kart confirmation case NS_WAIT_FOR_RACE_DATA: { + // It is possible that character confirm messages arrive at the + // client when it has already left the character selection screen. + // In this case the messages can simply be ignored. + if(Message::peekType(event->packet)==Message::MT_CHARACTER_CONFIRM) + { + // Receiving it will automatically free the memory. + CharacterConfirmMessage m(event->packet); + return; + } RaceInfoMessage m(event->packet); // The constructor actually sets the information in the race manager m_state = NS_LOADING_WORLD; @@ -391,10 +443,28 @@ void NetworkManager::switchToCharacterSelection() } // switchTocharacterSelection // ---------------------------------------------------------------------------- -void NetworkManager::sendCharacterSelected(int player_id) +/** Called on the client to send the data about the selected kart to the + * server and wait for confirmation. + * \param player_id Local id of the player which selected the kart. + * \param kart_id Identifier of the selected kart. this is used to wait till + * a message about this kart is received back from the server. + */ +void NetworkManager::sendCharacterSelected(int player_id, + const std::string &kart_id) { - CharacterSelectedMessage m(player_id); - sendToServer(m); + if(m_mode==NW_SERVER) + { + CharacterConfirmMessage ccm(kart_id, getMyHostId()); + broadcastToClients(ccm); + } + else if(m_mode==NW_CLIENT) + { + CharacterSelectedMessage m(player_id); + sendToServer(m); + // Wait till we receive confirmation about the selected character. + m_state = NS_WAIT_FOR_KART_CONFIRMATION; + m_kart_to_confirm = kart_id; + } } // sendCharacterSelected // ---------------------------------------------------------------------------- diff --git a/src/network/network_manager.hpp b/src/network/network_manager.hpp index 3a323df5b..6e62c4be3 100644 --- a/src/network/network_manager.hpp +++ b/src/network/network_manager.hpp @@ -41,6 +41,9 @@ public: 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_KART_CONFIRMATION, // client: wait for confirmation + // if character selection was ok + NS_KART_CONFIRMED, // Character was confirmed 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 @@ -62,6 +65,8 @@ private: ENetHost *m_host; // me ENetPeer *m_server; // (clients only) std::vector m_clients; // (server only) pos in vector is client host_id + /** Name of the kart that a client is waiting for confirmation for. */ + std::string m_kart_to_confirm; bool initServer(); bool initClient(); @@ -78,15 +83,15 @@ private: public: NetworkManager(); ~NetworkManager(); - void setMode(NetworkMode m) {m_mode = m; } - NetworkMode getMode() const {return m_mode; } + void setMode(NetworkMode m) {m_mode = m; } + NetworkMode getMode() const {return m_mode; } void becomeServer(); void becomeClient(); - void setState(NetworkState s) {m_state = s; } - NetworkState getState() const {return m_state; } - int getMyHostId() const {return m_host_id; } - void setHostId(int host_id) {m_host_id = host_id; } - unsigned int getNumClients() const {return m_num_clients; } + void setState(NetworkState s) {m_state = s; } + NetworkState getState() const {return m_state; } + int getMyHostId() const {return m_host_id; } + void setHostId(int host_id) {m_host_id = host_id; } + unsigned int getNumClients() const {return m_num_clients; } const std::string& getClientName(int i) const {return m_client_names[i];} bool initialiseConnections(); @@ -95,7 +100,7 @@ public: void disableNetworking(); void sendConnectMessage(); // client send initial info to server void switchToCharacterSelection(); - void sendCharacterSelected(int player_id); + void sendCharacterSelected(int player_id, const std::string &kartid); void waitForRaceInformation(); void worldLoaded(); void setupPlayerKartInfo(); @@ -108,4 +113,3 @@ public: extern NetworkManager *network_manager; #endif - diff --git a/src/race_manager.cpp b/src/race_manager.cpp index 07c1b5326..a706e9783 100644 --- a/src/race_manager.cpp +++ b/src/race_manager.cpp @@ -17,12 +17,13 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +#include "race_manager.hpp" + #include #include "track_manager.hpp" #include "game_manager.hpp" #include "kart_properties_manager.hpp" -#include "race_manager.hpp" #include "unlock_manager.hpp" #include "gui/menu_manager.hpp" #include "world.hpp" @@ -58,13 +59,12 @@ RaceManager::~RaceManager() } // ~RaceManager //----------------------------------------------------------------------------- -/** Resets the race manager. +/** Resets the race manager. It is called by world when restarting a race. */ void RaceManager::reset() { m_num_finished_karts = 0; m_num_finished_players = 0; - m_player_karts.clear(); } // reset //----------------------------------------------------------------------------- diff --git a/src/race_manager.hpp b/src/race_manager.hpp index 9576d028c..b0f891f05 100644 --- a/src/race_manager.hpp +++ b/src/race_manager.hpp @@ -82,6 +82,7 @@ private: Difficulty m_difficulty; RaceModeType m_major_mode, m_minor_mode; typedef std::vector PlayerKarts; + /** Stores remote kart information about all player karts. */ std::vector m_player_karts; std::vector m_local_kart_info; std::vector m_tracks; diff --git a/src/sdldrv.cpp b/src/sdldrv.cpp index 7715fa5db..9401ba529 100755 --- a/src/sdldrv.cpp +++ b/src/sdldrv.cpp @@ -38,7 +38,7 @@ #include "projectile_manager.hpp" #include "loader.hpp" #include "gui/menu_manager.hpp" -#include "widget_manager.hpp" +#include "gui/widget_manager.hpp" #include "player.hpp" #include "gui/font.hpp" #include "user_config.hpp" diff --git a/src/unlock_manager.cpp b/src/unlock_manager.cpp index 4051ec97e..0f35704ca 100755 --- a/src/unlock_manager.cpp +++ b/src/unlock_manager.cpp @@ -79,28 +79,28 @@ UnlockManager::UnlockManager() // Load challenges from .../data/karts // ----------------------------------- - file_manager->listFiles(dirs, file_manager->getKartDir(), - /*is_full_path*/ true); - - // Find out which characters are available and load them - for(std::set::iterator i = dirs.begin(); - i != dirs.end(); i++) - { - std::string challenge_file; - try - { - challenge_file = file_manager->getKartFile((*i)+".challenge"); - } - catch (std::exception& e) - { - (void)e; // remove warning about unused variable - continue; - } - FILE *f=fopen(challenge_file.c_str(),"r"); - if(!f) continue; - fclose(f); - addChallenge(new ChallengeData(challenge_file)); - } // for i + file_manager->listFiles(dirs, file_manager->getKartDir(), + /*is_full_path*/ true); + + // Find out which characters are available and load them + for(std::set::iterator i = dirs.begin(); + i != dirs.end(); i++) + { + std::string challenge_file; + try + { + challenge_file = file_manager->getKartFile((*i)+".challenge"); + } + catch (std::exception& e) + { + (void)e; // remove warning about unused variable + continue; + } + FILE *f=fopen(challenge_file.c_str(),"r"); + if(!f) continue; + fclose(f); + addChallenge(new ChallengeData(challenge_file)); + } // for i // Challenges from .../data/grandprix // ----------------------------------