Merge branch 'hilnius'

git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/trunk@14638 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
deveee 2013-12-05 17:28:55 +00:00
commit ec13bcf802
96 changed files with 2664 additions and 552 deletions

View File

@ -0,0 +1,29 @@
<stkgui>
<div x="1%" y="1%" width="98%" height="99%" layout="vertical-row" >
<header width="80%"
I18N="In the kart selection (player setup) screen"
text="Choose a Kart"
align="center" text_align="center" />
<placeholder id="playerskarts" width="100%" align="center" proportion="4">
<!-- Contents is added programatically -->
</placeholder>
<spacer height="15" width="25"/>
<box proportion="2" width="100%" layout="vertical-row" padding="2">
<ribbon_grid id="karts" proportion="1" square_items="true" width="100%" align="center"
child_width="90" child_height="90" max_rows="3"/>
</box>
<!-- Groups will be added dynamically at runtime -->
<tabs width="98%" x="1%" height="25" id="kartgroups">
</tabs>
<spacer width="100%" height="2%"/>
</div>
<icon-button id="back" x="0" y="0" height="8%" icon="gui/back.png"/>
</stkgui>

Binary file not shown.

View File

@ -157,7 +157,6 @@ src/modes/world_with_rank.cpp
src/network/client_network_manager.cpp
src/network/event.cpp
src/network/game_setup.cpp
src/network/http_functions.cpp
src/network/network_interface.cpp
src/network/network_manager.cpp
src/network/network_string.cpp
@ -183,6 +182,7 @@ src/network/protocols/start_game_protocol.cpp
src/network/protocols/start_server.cpp
src/network/protocols/stop_server.cpp
src/network/protocols/synchronization_protocol.cpp
src/network/race_config.cpp
src/network/server_network_manager.cpp
src/network/stk_host.cpp
src/network/stk_peer.cpp
@ -480,7 +480,6 @@ src/modes/world_with_rank.hpp
src/network/event.hpp
src/network/client_network_manager.hpp
src/network/game_setup.hpp
src/network/http_functions.hpp
src/network/network_interface.hpp
src/network/network_manager.hpp
src/network/network_string.hpp
@ -506,6 +505,7 @@ src/network/protocols/start_game_protocol.hpp
src/network/protocols/start_server.hpp
src/network/protocols/stop_server.hpp
src/network/protocols/synchronization_protocol.hpp
src/network/race_config.hpp
src/network/remote_kart_info.hpp
src/network/server_network_manager.hpp
src/network/singleton.hpp

View File

@ -182,6 +182,162 @@ void GroupUserConfigParam::addChild(UserConfigParam* child)
} // addChild
// ============================================================================
template<typename T>
ListUserConfigParam<T>::ListUserConfigParam(const char* param_name,
const char* comment)
{
m_param_name = param_name;
all_params.push_back(this);
if(comment != NULL) m_comment = comment;
} // ListUserConfigParam
// ============================================================================
template<typename T>
ListUserConfigParam<T>::ListUserConfigParam(const char* param_name,
const char* comment,
int nb_elements,
...)
{
m_param_name = param_name;
all_params.push_back(this);
if(comment != NULL) m_comment = comment;
// add the default list
va_list arguments;
va_start ( arguments, nb_elements );
for ( int i = 0; i < nb_elements; i++ )
m_elements.push_back(va_arg ( arguments, T ));
va_end ( arguments ); // Cleans up the list
} // ListUserConfigParam
// ============================================================================
template<typename T>
ListUserConfigParam<T>::ListUserConfigParam(const char* param_name,
GroupUserConfigParam* group,
const char* comment)
{
m_param_name = param_name;
group->addChild(this);
if(comment != NULL) m_comment = comment;
} // ListUserConfigParam
// ============================================================================
template<typename T>
ListUserConfigParam<T>::ListUserConfigParam(const char* param_name,
GroupUserConfigParam* group,
const char* comment,
int nb_elements,
...)
{
m_param_name = param_name;
group->addChild(this);
if(comment != NULL) m_comment = comment;
// add the default list
va_list arguments;
va_start ( arguments, nb_elements );
for ( int i = 0; i < nb_elements; i++ )
m_elements.push_back(va_arg ( arguments, T ));
va_end ( arguments ); // Cleans up the list
} // ListUserConfigParam
// ----------------------------------------------------------------------------
template<typename T>
void ListUserConfigParam<T>::write(XMLWriter& stream) const
{
const int elts_amount = m_elements.size();
// comment
if(m_comment.size() > 0) stream << " <!-- " << m_comment.c_str();
stream << L" -->\n <" << m_param_name.c_str() << "\n";
stream << L" Size=\"" << elts_amount << "\"\n";
// actual elements
for (int n=0; n<elts_amount; n++)
{
stream << L" " << n << "=\"" << m_elements[n] << "\"\n";
}
stream << L" >\n";
stream << L" </" << m_param_name.c_str() << ">\n\n";
} // write
// ----------------------------------------------------------------------------
// Write your own convert function depending on the type of list you use.
void convert(std::string str, char** str2)
{
*str2 = (char*)(malloc(str.size()+1));
strcpy(*str2, str.c_str());
}
// Write your own equals function depending on the type of list you use.
bool equals(char* str1, char* str2)
{
return (strcmp(str1, str2) == 0);
}
template<typename T>
void ListUserConfigParam<T>::findYourDataInAChildOf(const XMLNode* node)
{
const XMLNode* child = node->getNode( m_param_name );
if (child == NULL)
{
//std::cerr << "/!\\ User Config : Couldn't find parameter group "
// << paramName << std::endl;
return;
}
int attr_count = 0;
child->get( "Size", &attr_count);
for (int n=0; n<attr_count; n++)
{
T elt;
std::ostringstream oss;
oss << n;
std::string str;
child->get( oss.str(), &str);
convert(str, &elt);
// check if the element is already there :
bool there = false;
for (unsigned int i = 0; i < m_elements.size(); i++)
{
if (equals(m_elements[i], elt))
{
there = true;
break;
}
}
if (!there)
{
Log::info("ListUserConfigParam", "New data : %s, \"%s\"", str.c_str(), elt);
m_elements.push_back(elt);
}
}
} // findYourDataInAChildOf
// ----------------------------------------------------------------------------
template<typename T>
void ListUserConfigParam<T>::findYourDataInAnAttributeOf(const XMLNode* node)
{
} // findYourDataInAnAttributeOf
// ----------------------------------------------------------------------------
template<typename T>
void ListUserConfigParam<T>::addElement(T element)
{
m_elements.push_back(element);
} // findYourDataInAnAttributeOf
// ----------------------------------------------------------------------------
template<typename T>
irr::core::stringw ListUserConfigParam<T>::toString() const
{
return "";
} // toString
// ============================================================================
IntUserConfigParam::IntUserConfigParam(int default_value,
const char* param_name,

View File

@ -99,6 +99,45 @@ public:
irr::core::stringw toString() const;
}; // GroupUserConfigParam
// ============================================================================
template<typename T>
class ListUserConfigParam : public UserConfigParam
{
std::vector<T> m_elements;
public:
ListUserConfigParam(const char* param_name,
const char* comment = NULL);
ListUserConfigParam(const char* param_name,
const char* comment,
int nb_elts,
...);
ListUserConfigParam(const char* param_name,
GroupUserConfigParam* group,
const char* comment = NULL);
ListUserConfigParam(const char* param_name,
GroupUserConfigParam* group,
const char* comment,
int nb_elts,
...);
void write(XMLWriter& stream) const;
void findYourDataInAChildOf(const XMLNode* node);
void findYourDataInAnAttributeOf(const XMLNode* node);
void addElement(T element);
irr::core::stringw toString() const;
operator std::vector<T>() const
{ return m_elements; }
float& operator=(const std::vector<T>& v)
{ m_elements = std::vector<T>(v); return m_elements; }
float& operator=(const ListUserConfigParam& v)
{ m_elements = std::vector<T>(v); return m_elements; }
}; // ListUserConfigParam
typedef ListUserConfigParam<char*> StringListUserConfigParam;
// ============================================================================
class IntUserConfigParam : public UserConfigParam
{
@ -489,12 +528,44 @@ namespace UserConfigParams
PARAM_PREFIX IntUserConfigParam m_server_port
PARAM_DEFAULT( IntUserConfigParam(7321, "server_port",
"Information about the port to listen on.") );
PARAM_PREFIX IntUserConfigParam m_server_max_players
PARAM_DEFAULT( IntUserConfigParam(16, "server_max_players",
"Maximum number of players on the server.") );
PARAM_PREFIX StringListUserConfigParam m_stun_servers
PARAM_DEFAULT( StringListUserConfigParam("Stun_servers", "The stun servers"
" that will be used to know the public address.",
24,
"provserver.televolution.net",
"sip1.lakedestiny.cordiaip.com",
"stun1.voiceeclipse.net",
"stun01.sipphone.com",
"stun.callwithus.com",
"stun.counterpath.net",
"stun.endigovoip.com",
"stun.ekiga.net",
"stun.ideasip.com" ,
"stun.internetcalls.com",
"stun.ipns.com",
"stun.noc.ams-ix.net",
"stun.phonepower.com",
"stun.phoneserve.com",
"stun.rnktel.com",
"stun.softjoys.com",
"stunserver.org",
"stun.sipgate.net",
"stun.stunprotocol.org",
"stun.voip.aebc.com",
"stun.voipbuster.com",
"stun.voxalot.com",
"stun.voxgratia.org",
"stun.xten.com") );
PARAM_PREFIX StringUserConfigParam m_packets_log_filename
PARAM_DEFAULT( StringUserConfigParam("packets_log.txt", "packets_log_filename",
"Where to log received and sent packets.") );
// ---- Graphic Quality
PARAM_PREFIX GroupUserConfigParam m_graphics_quality
PARAM_DEFAULT( GroupUserConfigParam("GFX",

View File

@ -26,6 +26,7 @@
#include "input/device_manager.hpp"
#include "input/wiimote.hpp"
#include "utils/string_utils.hpp"
#include "utils/time.hpp"
#include "utils/translation.hpp"
#include "wiiuse.h"
@ -110,7 +111,7 @@ void WiimoteManager::launchDetection(int timeout)
wiiuse_rumble(wiimote_handle, 1);
}
irr_driver->getDevice()->sleep(200);
StkTime::sleep(200);
for(unsigned int i=0 ; i < m_wiimotes.size(); i++)
{
@ -284,7 +285,7 @@ void WiimoteManager::threadFunc()
}
}
irr_driver->getDevice()->sleep(1); // 'cause come on, the whole CPU is not ours :)
StkTime::sleep(1); // 'cause come on, the whole CPU is not ours :)
} // end while
} // threadFunc

View File

@ -29,6 +29,8 @@
#include "io/file_manager.hpp"
#include "karts/abstract_kart.hpp"
#include "modes/linear_world.hpp"
#include "network/network_manager.hpp"
#include "network/network_world.hpp"
#include "tracks/quad_graph.hpp"
#include "tracks/track.hpp"
#include "utils/string_utils.hpp"
@ -309,7 +311,14 @@ void ItemManager::checkItemHit(AbstractKart* kart)
// we pass the kart and the position separately.
if((*i)->hitKart(kart->getXYZ(), kart))
{
collectedItem(*i, kart);
// if we're not playing online, pick the item.
if (!NetworkWorld::getInstance()->isRunning())
collectedItem(*i, kart);
else if (NetworkManager::getInstance()->isServer())
{
collectedItem(*i, kart);
NetworkWorld::getInstance()->collectedItem(*i, kart);
}
} // if hit
} // for m_all_items
} // checkItemHit

View File

@ -393,13 +393,21 @@ void Powerup::hitBonusBox(const Item &item, int add_info)
// Check if two bouncing balls are collected less than getRubberBallTimer()
//seconds apart. If yes, then call getRandomPowerup again. If no, then break.
for(int i=0; i<20; i++)
if (add_info<0)
{
new_powerup = powerup_manager->getRandomPowerup(position, &n);
if(new_powerup != PowerupManager::POWERUP_RUBBERBALL ||
( World::getWorld()->getTime() - powerup_manager->getBallCollectTime()) >
RubberBall::getTimeBetweenRubberBalls() )
break;
for(int i=0; i<20; i++)
{
new_powerup = powerup_manager->getRandomPowerup(position, &n);
if(new_powerup != PowerupManager::POWERUP_RUBBERBALL ||
( World::getWorld()->getTime() - powerup_manager->getBallCollectTime()) >
RubberBall::getTimeBetweenRubberBalls() )
break;
}
}
else // set powerup manually
{
new_powerup = (PowerupManager::PowerupType)((add_info>>4)&0x0f); // highest 4 bits for the type
n = (add_info&0x0f); // last 4 bits for the amount
}
if(new_powerup == PowerupManager::POWERUP_RUBBERBALL)

View File

@ -272,7 +272,7 @@ public:
* \param add_info Additional info, used in networking games to force
* a specific item to be used (instead of a random item) to keep
* all karts in synch. */
virtual void collectedItem(Item *item, int random_attachment) = 0;
virtual void collectedItem(Item *item, int add_info) = 0;
// ------------------------------------------------------------------------
/** Returns the current position of this kart in the race. */
virtual int getPosition() const = 0;

View File

@ -120,6 +120,7 @@
# ifdef __CYGWIN__
# include <unistd.h>
# endif
# define WIN32_LEAN_AND_MEAN
# define _WINSOCKAPI_
# define WIN32_LEAN_AND_MEAN
# include <windows.h>
@ -176,6 +177,12 @@
#include "network/protocols/server_lobby_room_protocol.hpp"
#include "online/current_user.hpp"
#include "online/http_manager.hpp"
#include "network/client_network_manager.hpp"
#include "network/server_network_manager.hpp"
#include "network/protocol_manager.hpp"
#include "network/protocols/server_lobby_room_protocol.hpp"
#include "online/current_user.hpp"
#include "online/http_manager.hpp"
#include "online/profile_manager.hpp"
#include "online/servers_manager.hpp"
#include "race/grand_prix_manager.hpp"
@ -1147,6 +1154,7 @@ int handleCmdLine(int argc, char **argv)
irr::core::stringw s;
Online::CurrentUser::SignInRequest* request =
Online::CurrentUser::get()->requestSignIn(login, password, false, false);
Online::HTTPManager::get()->synchronousRequest(request);
if (request->isSuccess())
@ -1425,6 +1433,9 @@ int main(int argc, char *argv[] )
// load the network manager
// If the server has been created (--server option), this will do nothing (just a warning):
NetworkManager::getInstance<ClientNetworkManager>();
if (NetworkManager::getInstance()->isServer())
ServerNetworkManager::getInstance()->setMaxPlayers(
UserConfigParams::m_server_max_players);
NetworkManager::getInstance()->run();
if (NetworkManager::getInstance()->isServer())
{
@ -1453,11 +1464,8 @@ int main(int argc, char *argv[] )
if (players[n].getName() == UserConfigParams::m_default_player.toString())
unlock_manager->setCurrentSlot(players[n].getUniqueID());
main_loop->run();
throw "salut";
}
if(!UserConfigParams::m_no_start_screen)
else if(!UserConfigParams::m_no_start_screen)
{
StateManager::get()->pushScreen(StoryModeLobbyScreen::getInstance());
#ifdef ENABLE_WIIUSE
@ -1616,6 +1624,7 @@ int main(int argc, char *argv[] )
// so we don't crash later when StateManager tries to access input devices.
StateManager::get()->resetActivePlayers();
if(input_manager) delete input_manager; // if early crash avoid delete NULL
NetworkManager::getInstance()->abort();
cleanSuperTuxKart();

View File

@ -83,7 +83,7 @@ float MainLoop::getLimitedDt()
int wait_time = 1000/max_fps - 1000/current_fps;
if(wait_time < 1) wait_time = 1;
irr_driver->getDevice()->sleep(wait_time);
StkTime::sleep(wait_time);
}
else break;
}
@ -166,6 +166,10 @@ void MainLoop::run()
PROFILER_PUSH_CPU_MARKER("Protocol manager update", 0x7F, 0x00, 0x7F);
ProtocolManager::getInstance()->update();
PROFILER_POP_CPU_MARKER();
PROFILER_PUSH_CPU_MARKER("Database polling update", 0x00, 0x7F, 0x7F);
Online::HTTPManager::get()->update(dt);
PROFILER_POP_CPU_MARKER();
}
PROFILER_SYNC_FRAME();

View File

@ -452,7 +452,7 @@ void SoccerWorld::initKartList()
// Set kart positions, ordering them by team
for(unsigned int n=0; n<kart_amount; n++)
{
SoccerTeam team = race_manager->getLocalKartInfo(n).getSoccerTeam();
m_karts[n]->setPosition(team_cur_position[team]);
team_cur_position[team]++;

View File

@ -21,6 +21,7 @@
#include "items/powerup_manager.hpp"
#include "karts/abstract_kart.hpp"
#include "karts/controller/controller.hpp"
#include "network/network_manager.hpp"
//-----------------------------------------------------------------------------
StandardRace::StandardRace() : LinearWorld()
@ -123,5 +124,6 @@ void StandardRace::endRaceEarly()
} // Finish the active players
endSetKartPositions();
setPhase(RESULT_DISPLAY_PHASE);
terminateRace();
if (!isNetworkWorld() || NetworkManager::getInstance()->isServer())
terminateRace();
} // endRaceEarly

View File

@ -118,6 +118,7 @@ World::World() : WorldStatus(), m_clear_color(255,100,101,140)
m_schedule_exit_race = false;
m_self_destruct = false;
m_schedule_tutorial = false;
m_is_network_world = false;
m_stop_music_when_dialog_open = true;
@ -218,6 +219,7 @@ void World::reset()
m_faster_music_active = false;
m_eliminated_karts = 0;
m_eliminated_players = 0;
m_is_network_world = false;
for ( KartList::iterator i = m_karts.begin(); i != m_karts.end() ; ++i )
{
@ -435,14 +437,17 @@ void World::terminateRace()
int best_finish_time = -1;
std::string highscore_who = "";
StateManager::ActivePlayer* best_player = NULL;
updateHighscores(&best_highscore_rank, &best_finish_time, &highscore_who,
if (!this->isNetworkWorld())
{
updateHighscores(&best_highscore_rank, &best_finish_time, &highscore_who,
&best_player);
unlock_manager->getCurrentSlot()->raceFinished();
}
unlock_manager->getCurrentSlot()->raceFinished();
((MapAchievement *) AchievementsManager::get()->getActive()->getAchievement(1))->increase(getTrack()->getIdent(), 1);
AchievementsManager::get()->onRaceEnd();
if (m_race_gui) m_race_gui->clearAllMessages();
// we can't delete the race gui here, since it is needed in case of
// a restart: the constructor of it creates some textures which assume
@ -947,7 +952,9 @@ void World::updateHighscores(int* best_highscore_rank, int* best_finish_time,
PlayerController *controller = (PlayerController*)(k->getController());
int highscore_rank = highscores->addData(k->getIdent(),
int highscore_rank = 0;
if (controller->getPlayer()->getProfile() != NULL) // if we have the player profile here
highscore_rank = highscores->addData(k->getIdent(),
controller->getPlayer()->getProfile()->getName(),
k->getFinishTime());

View File

@ -152,6 +152,9 @@ protected:
*/
bool m_self_destruct;
/** Set when the world is online and counts network players. */
bool m_is_network_world;
virtual void onGo();
/** Returns true if the race is over. Must be defined by all modes. */
virtual bool isRaceOver() = 0;
@ -197,7 +200,7 @@ public:
* this method in child classes to provide it. */
virtual const std::string& getIdent() const = 0;
// ------------------------------------------------------------------------
/** Returns the number of rescue positions on a given track and game
/** Returns the number of rescue positions on a given track and game
* mode. */
virtual unsigned int getNumberOfRescuePositions() const OVERRIDE = 0;
// ------------------------------------------------------------------------
@ -327,6 +330,10 @@ public:
// ------------------------------------------------------------------------
virtual void escapePressed();
/** Set the network mode (true if networked) */
void setNetworkWorld(bool is_networked) { m_is_network_world = is_networked; }
bool isNetworkWorld() const { return m_is_network_world; }
}; // World
#endif

View File

@ -36,7 +36,6 @@ void* waitInput(void* data)
{
std::string str = "";
bool stop = false;
int n = 0;
while(!stop)
{
@ -45,14 +44,6 @@ void* waitInput(void* data)
{
stop = true;
}
else if (str == "disconnect")
{
NetworkManager::getInstance()->getPeers()[0]->disconnect();
}
else if (str == "connect")
{
ProtocolManager::getInstance()->requestStart(new ConnectToServer());
}
else if (str == "select")
{
std::string str2;
@ -61,9 +52,48 @@ void* waitInput(void* data)
ClientLobbyRoomProtocol* clrp = static_cast<ClientLobbyRoomProtocol*>(protocol);
clrp->requestKartSelection(str2);
}
else if (str == "synchronize")
else if (str == "vote")
{
ProtocolManager::getInstance()->requestStart(new SynchronizationProtocol());
std::cout << "Vote for ? (track/laps/reversed/major/minor/race#) :";
std::string str2;
getline(std::cin, str2);
Protocol* protocol = ProtocolManager::getInstance()->getProtocol(PROTOCOL_LOBBY_ROOM);
ClientLobbyRoomProtocol* clrp = static_cast<ClientLobbyRoomProtocol*>(protocol);
if (str2 == "track")
{
std::cin >> str2;
clrp->voteTrack(str2);
}
else if (str2 == "laps")
{
int cnt;
std::cin >> cnt;
clrp->voteLaps(cnt);
}
else if (str2 == "reversed")
{
bool cnt;
std::cin >> cnt;
clrp->voteReversed(cnt);
}
else if (str2 == "major")
{
int cnt;
std::cin >> cnt;
clrp->voteMajor(cnt);
}
else if (str2 == "minor")
{
int cnt;
std::cin >> cnt;
clrp->voteMinor(cnt);
}
else if (str2 == "race#")
{
int cnt;
std::cin >> cnt;
clrp->voteRaceCount(cnt);
}
}
else if (NetworkManager::getInstance()->getPeers().size() > 0)
{
@ -87,6 +117,7 @@ ClientNetworkManager::ClientNetworkManager()
ClientNetworkManager::~ClientNetworkManager()
{
pthread_cancel(*m_thread_keyboard);
}
void ClientNetworkManager::run()

View File

@ -16,27 +16,58 @@
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
/*! \file client_network_manager.hpp
* \brief Defines a Client Network manager, that will connect to a server.
*/
#ifndef CLIENT_NETWORK_MANAGER_HPP
#define CLIENT_NETWORK_MANAGER_HPP
#include "network/network_manager.hpp"
/*! \class ClientNetworkManager
* \ingroup network
*/
class ClientNetworkManager : public NetworkManager
{
friend class Singleton<NetworkManager>;
public:
/*! \brief Get the instance.
* This is a utility function to avoid passing templates parameters
* to the getInstance singleton method.
*/
static ClientNetworkManager* getInstance()
{
return Singleton<NetworkManager>::getInstance<ClientNetworkManager>();
}
/*! \brief Initializes network.
* This starts the threads and initializes network libraries.
*/
virtual void run();
/*! \brief Resets the network socket. */
virtual void reset();
/*! \brief Sends a packet to the server.
* \param data : The network 8-bit string to send.
* \param reliable : If set to true, ENet will ensure that the packet is received.
*/
virtual void sendPacket(const NetworkString& data, bool reliable = true);
/*! \brief Get the peer (the server)
* \return The peer with whom we're connected (if it exists). NULL elseway.
*/
STKPeer* getPeer();
/*! \brief Function to know if we're a server.
* \return Returns true if we're on a server. False if we're a client.
*/
virtual bool isServer() { return false; }
/*! \brief Function used to notice the manager that we're connected to a server.
* \param value : True if we're connected, false elseway.
*/
void setConnected(bool value) { m_connected = value; }
/*! \brief Function to know if we're a server.
* \return Returns true if we're on a server. False if we're a client.
*/
bool isConnected() { return m_connected; }
protected:
@ -44,7 +75,7 @@ class ClientNetworkManager : public NetworkManager
virtual ~ClientNetworkManager();
bool m_connected; //!< Is the user connected to a server
pthread_t* m_thread_keyboard;
pthread_t* m_thread_keyboard; //!< The thread listening for keyboard console input.
};
#endif // CLIENT_NETWORK_MANAGER_HPP

View File

@ -42,10 +42,7 @@ Event::Event(ENetEvent* event)
}
if (type == EVENT_TYPE_MESSAGE)
{
data = NetworkString(std::string((char*)(event->packet->data), event->packet->dataLength-1));
}
else if (event->data)
{
m_data = NetworkString(std::string((char*)(event->packet->data), event->packet->dataLength-1));
}
m_packet = NULL;
@ -80,7 +77,7 @@ Event::Event(ENetEvent* event)
Event::Event(const Event& event)
{
m_packet = NULL;
data = event.data;
m_data = event.m_data;
// copy the peer
peer = event.peer;
type = event.type;
@ -94,6 +91,6 @@ Event::~Event()
void Event::removeFront(int size)
{
data.removeFront(size);
m_data.removeFront(size);
}

View File

@ -16,6 +16,11 @@
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
/*! \file event.hpp
* \brief Contains an interface to store network events, like connections,
* disconnections and messages.
*/
#ifndef EVENT_HPP
#define EVENT_HPP
@ -65,11 +70,17 @@ class Event
*/
void removeFront(int size);
/*! \brief Get a copy of the data.
* \return A copy of the message data. This is empty for events like
* connection or disconnections.
*/
NetworkString data() const { return m_data; }
EVENT_TYPE type; //!< Type of the event.
NetworkString data; //!< Copy of the data passed by the event.
STKPeer** peer; //!< Pointer to the peer that triggered that event.
private:
NetworkString m_data; //!< Copy of the data passed by the event.
ENetPacket* m_packet; //!< A pointer on the ENetPacket to be deleted.
};

View File

@ -18,12 +18,16 @@
#include "network/game_setup.hpp"
#include "karts/abstract_kart.hpp"
#include "modes/world.hpp"
#include "race/race_manager.hpp"
#include "utils/log.hpp"
//-----------------------------------------------------------------------------
GameSetup::GameSetup()
{
m_race_config = new RaceConfig();
}
//-----------------------------------------------------------------------------
@ -43,7 +47,7 @@ GameSetup::~GameSetup()
void GameSetup::addPlayer(NetworkPlayerProfile* profile)
{
m_players.push_back(profile);
Log::verbose("GameSetup", "New player in the game setup. Global id : %u, "
Log::info("GameSetup", "New player in the game setup. Global id : %u, "
"Race id : %d.", profile->user_profile->getID(), profile->race_id);
}
@ -79,6 +83,10 @@ bool GameSetup::removePlayer(uint8_t id)
"Remains %u.", m_players.size());
return true;
}
if (m_players[i]->race_id > id)
{
m_players[i]->race_id--; // all indices in [0;n[ (n = #players)
}
}
return false;
}
@ -106,6 +114,39 @@ void GameSetup::setPlayerKart(uint8_t id, std::string kart_name)
//-----------------------------------------------------------------------------
void GameSetup::bindKartsToProfiles()
{
World::KartList karts = World::getWorld()->getKarts();
for (unsigned int i = 0; i < m_players.size(); i++)
{
Log::info("GameSetup", "Player %d has id %d and kart %s", i, m_players[i]->race_id, m_players[i]->kart_name.c_str());
}
for (unsigned int i = 0; i < karts.size(); i++)
{
Log::info("GameSetup", "Kart %d has id %d and kart %s", i, karts[i]->getWorldKartId(), karts[i]->getIdent().c_str());
}
for (unsigned int j = 0; j < m_players.size(); j++)
{
bool found = false;
for (unsigned int i = 0 ; i < karts.size(); i++)
{
if (karts[i]->getIdent() == m_players[j]->kart_name)
{
m_players[j]->world_kart_id = karts[i]->getWorldKartId();
found = true;
break;
}
}
if (!found)
{
Log::error("GameSetup", "Error while binding world kart ids to players profiles.");
}
}
}
//-----------------------------------------------------------------------------
const NetworkPlayerProfile* GameSetup::getProfile(uint32_t id)
{
for (unsigned int i = 0; i < m_players.size(); i++)
@ -134,6 +175,20 @@ const NetworkPlayerProfile* GameSetup::getProfile(uint8_t id)
//-----------------------------------------------------------------------------
const NetworkPlayerProfile* GameSetup::getProfile(std::string kart_name)
{
for (unsigned int i = 0; i < m_players.size(); i++)
{
if (m_players[i]->kart_name == kart_name)
{
return m_players[i];
}
}
return NULL;
}
//-----------------------------------------------------------------------------
bool GameSetup::isKartAvailable(std::string kart_name)
{
for (unsigned int i = 0; i < m_players.size(); i++)

View File

@ -23,6 +23,7 @@
#define GAME_SETUP_HPP
#include "online/profile.hpp"
#include "network/race_config.hpp"
#include <vector>
#include <string>
@ -39,6 +40,7 @@ class NetworkPlayerProfile
uint8_t race_id; //!< The id of the player for the race
std::string kart_name; //!< The selected kart.
Online::Profile* user_profile; //!< Pointer to the lobby profile
uint8_t world_kart_id; //!< the kart id in the World class (pointer to AbstractKart)
};
/*! \class GameSetup
@ -55,18 +57,48 @@ class GameSetup
bool removePlayer(uint32_t id); //!< Remove a player by id.
bool removePlayer(uint8_t id); //!< Remove a player by local id.
void setPlayerKart(uint8_t id, std::string kart_name); //!< Set the kart of a player
void bindKartsToProfiles(); //!< Sets the right world_kart_id in profiles
/** \brief Get the players that are in the game
* \return A vector containing pointers on the players profiles.
*/
std::vector<NetworkPlayerProfile*> getPlayers() { return m_players; }
int getPlayerCount() { return m_players.size(); }
const NetworkPlayerProfile* getProfile(uint32_t id); //!< Get a profile by database id
const NetworkPlayerProfile* getProfile(uint8_t id); //!< Get the profile by the lobby id
/*! \brief Get a network player profile matching a universal id.
* \param id : Global id of the player (the one in the SQL database)
* \return The profile of the player matching the id.
*/
const NetworkPlayerProfile* getProfile(uint32_t id);
/*! \brief Get a network player profile matching a kart name.
* \param kart_name : Name of the kart used by the player.
* \return The profile of the player having the kart kart_name
*/
const NetworkPlayerProfile* getProfile(uint8_t id);
/*! \brief Get a network player profile matching a kart name.
* \param kart_name : Name of the kart used by the player.
* \return The profile of the player having the kart kart_name.
*/
const NetworkPlayerProfile* getProfile(std::string kart_name);
/*! \brief Used to know if a kart is available.
* \param kart_name : Name of the kart to check.
* \return True if the kart hasn't been selected yet, false elseway.
*/
bool isKartAvailable(std::string kart_name);
/*! \brief Used to know if a kart is playable.
* \param kart_name : Name of the kart to check.
* \return True if the kart is playable (standard kart).
* Currently this is always true as the kart selection screen shows
* only the standard karts.
*/
bool isKartAllowed(std::string kart_name) {return true; }
RaceConfig* getRaceConfig() { return m_race_config; }
protected:
std::vector<NetworkPlayerProfile*> m_players; //!< Information about players
NetworkPlayerProfile m_self_profile; //!< Information about self (client only)
RaceConfig* m_race_config;
};
#endif // GAME_SETUP_HPP

View File

@ -1,67 +0,0 @@
//
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2013 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 "network/http_functions.hpp"
#include "utils/log.hpp"
#include <string>
#include <curl/curl.h>
#include <stdlib.h>
#include <string.h>
#include <memory.h>
namespace HTTP
{
CURL *curl;
CURLcode res;
static size_t WriteCallback(void *contents, size_t size, size_t nmemb, void *userp)
{
((std::string*)userp)->append((char*)contents, size * nmemb);
return size * nmemb;
}
void init()
{
curl_global_init(CURL_GLOBAL_DEFAULT);
curl = curl_easy_init();
if(!curl)
Log::error("HTTP", "Error while loading cURL library.\n");
}
std::string getPage(std::string url)
{
std::string readBuffer;
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer);
res = curl_easy_perform(curl);
if(res != CURLE_OK)
Log::error("HTTP", "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
return readBuffer;
}
void shutdown()
{
curl_easy_cleanup(curl);
curl_global_cleanup();
}
}

View File

@ -1,35 +0,0 @@
//
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2013 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.
#ifndef HTTP_FUNCTIONS_HPP
#define HTTP_FUNCTIONS_HPP
#include <string>
namespace HTTP
{
void init();
void shutdown();
std::string getPage(std::string url);
}
#endif // HTTP_FUNCTIONS_HPP

View File

@ -16,6 +16,10 @@
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
/*! \file network_interface.hpp
* \brief Defines an interface to network middle-level functions.
*/
#ifndef NETWORK_INTERFACE_H
#define NETWORK_INTERFACE_H
@ -26,19 +30,24 @@
#include <pthread.h>
#include <string>
/** \class NetworkInterface
* \ingroup network
*/
class NetworkInterface : public Singleton<NetworkInterface>
{
friend class Singleton<NetworkInterface>;
public:
/*! \brief Used to init the network.
* \param server : True if we're a server.
*/
void initNetwork(bool server);
protected:
// protected functions
NetworkInterface();
virtual ~NetworkInterface();
};
#endif // NETWORK_INTERFACE_H

View File

@ -76,6 +76,13 @@ void NetworkManager::reset()
}
}
void NetworkManager::abort()
{
m_localhost->stopListening();
reset();
ProtocolManager::getInstance()->abort();
}
//-----------------------------------------------------------------------------
bool NetworkManager::connect(TransportAddress peer)
@ -116,7 +123,7 @@ void NetworkManager::notifyEvent(Event* event)
((addr>>24)&0xff),
((addr>>16)&0xff),
((addr>>8)&0xff),
(addr&0xff), event->data.c_str());
(addr&0xff), event->data().c_str());
}

View File

@ -16,6 +16,10 @@
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
/*! \file network_manager.hpp
* \brief Instantiates the generic functionnalities of a network manager.
*/
#ifndef NETWORKMANAGER_HPP
#define NETWORKMANAGER_HPP
@ -30,22 +34,55 @@
#include <vector>
/** \class NetworkManager
* \brief Gives the general functions to use network communication.
* This class is in charge of storing the peers connected to this host.
* It also stores the host, and brings the functions to send messages to peers.
* It automatically dispatches the events or packets it receives. This class
* also stores the public address when known and the player login.
* Here are defined some functions that will be specifically implemented by
* the ServerNetworkManager and the ClientNetworkManager.
*/
class NetworkManager : public Singleton<NetworkManager>
{
friend class Singleton<NetworkManager>;
public:
/** \brief Function to start the Network Manager (start threads) */
virtual void run();
/** \brief Function to reset the Network Manager.
* This function resets the peers and the listening host.
*/
virtual void reset();
/** \brief Function that aborts the NetworkManager.
* This function will stop the listening, delete the host and stop
* threads that are related to networking.
*/
virtual void abort();
// network management functions
/** \brief Try to establish a connection to a given transport address.
* \param peer : The transport address which you want to connect to.
* \return True if we're successfully connected. False elseway.
*/
virtual bool connect(TransportAddress peer);
/** \brief Changes the socket working mode.
* Sockets can be in two modes : The ENet mode and a mode we will call
* the 'Raw' mode. In the ENet mode, the socket will be read as
* \param peer : The transport address which you want to connect to.
* \return True if we're successfully connected. False elseway.
*/
virtual void setManualSocketsMode(bool manual);
// message/packets related functions
virtual void notifyEvent(Event* event);
virtual void sendPacket(const NetworkString& data, bool reliable = true) = 0;
virtual void sendPacket(STKPeer* peer, const NetworkString& data, bool reliable = true);
virtual void sendPacketExcept(STKPeer* peer, const NetworkString& data, bool reliable = true);
virtual void sendPacket(const NetworkString& data,
bool reliable = true) = 0;
virtual void sendPacket(STKPeer* peer,
const NetworkString& data,
bool reliable = true);
virtual void sendPacketExcept(STKPeer* peer,
const NetworkString& data,
bool reliable = true);
// Game related functions
virtual GameSetup* setupNewGame(); //!< Creates a new game setup and returns it

View File

@ -1,3 +1,25 @@
//
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2013 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.
/*! \file network_string.hpp
* \brief Defines functions to easily manipulate 8-bit network destinated strings.
*/
#ifndef NETWORK_STRING_HPP
#define NETWORK_STRING_HPP
@ -10,6 +32,10 @@
typedef unsigned char uchar;
/** \class NetworkString
* \brief Describes a chain of 8-bit unsigned integers.
* This class allows you to easily create and parse 8-bit strings.
*/
class NetworkString
{
union {

View File

@ -1,8 +1,10 @@
#include "network/network_world.hpp"
#include "network/network_manager.hpp"
#include "network/protocol_manager.hpp"
#include "network/protocols/synchronization_protocol.hpp"
#include "network/protocols/controller_events_protocol.hpp"
#include "network/protocols/game_events_protocol.hpp"
#include "modes/world.hpp"
#include "karts/controller/controller.hpp"
@ -10,6 +12,7 @@
NetworkWorld::NetworkWorld()
{
m_running = false;
m_has_run = false;
}
NetworkWorld::~NetworkWorld()
@ -18,6 +21,8 @@ NetworkWorld::~NetworkWorld()
void NetworkWorld::update(float dt)
{
if (!m_has_run)
m_has_run = true;
SynchronizationProtocol* protocol = static_cast<SynchronizationProtocol*>(
ProtocolManager::getInstance()->getProtocol(PROTOCOL_SYNCHRONIZATION));
if (protocol) // if this protocol exists, that's that we play online
@ -27,8 +32,40 @@ void NetworkWorld::update(float dt)
{
return;
}
World::getWorld()->setNetworkWorld(true);
}
World::getWorld()->updateWorld(dt);
if (World::getWorld()->getPhase() >= WorldStatus::RESULT_DISPLAY_PHASE) // means it's the end
{
// consider the world finished.
stop();
Log::info("NetworkWorld", "The game is considered finish.");
}
}
void NetworkWorld::start()
{
m_running = true;
}
void NetworkWorld::stop()
{
m_running = false;
}
bool NetworkWorld::isRaceOver()
{
if (!World::getWorld())
return false;
return (World::getWorld()->getPhase() > WorldStatus::RACE_PHASE);
}
void NetworkWorld::collectedItem(Item *item, AbstractKart *kart)
{
assert(NetworkManager::getInstance()->isServer()); // this is only called in the server
GameEventsProtocol* protocol = static_cast<GameEventsProtocol*>(
ProtocolManager::getInstance()->getProtocol(PROTOCOL_GAME_EVENTS));
protocol->collectedItem(item,kart);
}
void NetworkWorld::controllerAction(Controller* controller, PlayerAction action, int value)
@ -38,3 +75,4 @@ void NetworkWorld::controllerAction(Controller* controller, PlayerAction action,
if (protocol)
protocol->controllerAction(controller, action, value);
}

View File

@ -1,3 +1,24 @@
//
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2013 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.
/*! \file network_world.hpp
*/
#ifndef NETWORK_WORLD_HPP
#define NETWORK_WORLD_HPP
@ -8,6 +29,7 @@
class Controller;
class KartUpdateProtocol;
class AbstractKart;
class Item;
/*! \brief Manages the world updates during an online game
* This function's update is to be called instead of the normal World update
@ -18,16 +40,19 @@ class NetworkWorld : public Singleton<NetworkWorld>
public:
void update(float dt);
void start() { m_running = true; }
void stop() { m_running = false; }
void start();
void stop();
bool isRunning() { return m_running; }
bool isRaceOver();
void collectedItem(Item *item, AbstractKart *kart);
void controllerAction(Controller* controller, PlayerAction action, int value);
std::string m_self_kart;
protected:
bool m_running;
float m_race_time;
bool m_has_run;
private:
NetworkWorld();

View File

@ -19,6 +19,7 @@
#include "network/protocol.hpp"
#include "network/protocol_manager.hpp"
#include "network/network_manager.hpp"
Protocol::Protocol(CallbackObject* callback_object, PROTOCOL_TYPE type)
{
@ -52,3 +53,47 @@ PROTOCOL_TYPE Protocol::getProtocolType()
{
return m_type;
}
bool Protocol::checkDataSizeAndToken(Event* event, int minimum_size)
{
NetworkString data = event->data();
if (data.size() < minimum_size || data[0] != 4)
{
Log::warn("Protocol", "Receiving a badly "
"formated message. Size is %d and first byte %d",
data.size(), data[0]);
return false;
}
STKPeer* peer = *(event->peer);
uint32_t token = data.gui32(1);
if (token != peer->getClientServerToken())
{
Log::warn("Protocol", "Peer sending bad token. Request "
"aborted.");
return false;
}
return true;
}
bool Protocol::isByteCorrect(Event* event, int byte_nb, int value)
{
NetworkString data = event->data();
if (data[byte_nb] != value)
{
Log::info("Protocol", "Bad byte at pos %d. %d "
"should be %d", byte_nb, data[byte_nb], value);
return false;
}
return true;
}
void Protocol::sendMessageToPeersChangingToken(NetworkString prefix, NetworkString message)
{
std::vector<STKPeer*> peers = NetworkManager::getInstance()->getPeers();
for (unsigned int i = 0; i < peers.size(); i++)
{
prefix.ai8(4).ai32(peers[i]->getClientServerToken());
prefix += message;
m_listener->sendMessage(this, peers[i], prefix);
}
}

View File

@ -16,6 +16,10 @@
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
/*! \file protocol.hpp
* \brief Generic protocols declarations.
*/
#ifndef PROTOCOL_HPP
#define PROTOCOL_HPP
@ -61,55 +65,60 @@ class Protocol
* \param type The type of the protocol.
*/
Protocol(CallbackObject* callback_object, PROTOCOL_TYPE type);
/*!
* \brief Destructor
/*! \brief Destructor
*/
virtual ~Protocol();
/*!
* \brief Notify a protocol matching the Event type of that event.
* \param event : Pointer to the event.
/*! \brief Notify a protocol matching the Event type of that event.
* \param event : Pointer to the event.
* \return True if the event has been treated, false elseway
*/
virtual void notifyEvent(Event* event) = 0;
virtual bool notifyEvent(Event* event) { return false; }
/*!
* \brief Set the protocol listener.
* \param listener : Pointer to the listener.
/*! \brief Notify a protocol matching the Event type of that event.
* This update is done asynchronously :
* \param event : Pointer to the event.
* \return True if the event has been treated, false elseway
*/
virtual bool notifyEventAsynchronous(Event* event) { return false; }
/*! \brief Set the protocol listener.
* \param listener : Pointer to the listener.
*/
void setListener(ProtocolManager* listener);
/*!
* \brief Called when the protocol is going to start. Must be re-defined by subclasses.
/*! \brief Called when the protocol is going to start. Must be re-defined by subclasses.
*/
virtual void setup() = 0;
/*!
* \brief Called when the protocol is paused (by an other entity or by itself).
* This function must be called by the subclasse's pause function if re-defined.
/*! \brief Called when the protocol is paused (by an other entity or by itself).
* This function must be called by the subclasse's pause function if re-defined.
*/
virtual void pause();
/*!
* \brief Called when the protocol is unpaused.
* This function must be called by the subclasse's unpause function if re-defined.
/*! \brief Called when the protocol is unpaused.
* This function must be called by the subclasse's unpause function if re-defined.
*/
virtual void unpause();
/*!
* \brief Called by the protocol listener, synchronously with the main loop. Must be re-defined.
/*! \brief Called by the protocol listener, synchronously with the main loop. Must be re-defined.
*/
virtual void update() = 0;
/*!
* \brief Called by the protocol listener as often as possible. Must be re-defined.
/*! \brief Called by the protocol listener as often as possible. Must be re-defined.
*/
virtual void asynchronousUpdate() = 0;
/*!
* \brief Called when the protocol is to be killed.
/*! \brief Called when the protocol is to be killed.
*/
virtual void kill();
/*!
* \brief Method to get a protocol's type.
* \return The protocol type.
/*! \brief Method to get a protocol's type.
* \return The protocol type.
*/
PROTOCOL_TYPE getProtocolType();
/// functions to check incoming data easily
bool checkDataSizeAndToken(Event* event, int minimum_size);
bool isByteCorrect(Event* event, int byte_nb, int value);
void sendMessageToPeersChangingToken(NetworkString prefix, NetworkString message);
protected:
ProtocolManager* m_listener; //!< The protocol listener
PROTOCOL_TYPE m_type; //!< The type of the protocol

View File

@ -21,7 +21,7 @@
#include "network/protocol.hpp"
#include "network/network_manager.hpp"
#include "utils/log.hpp"
#include "graphics/irr_driver.hpp"
#include "utils/time.hpp"
#include <assert.h>
#include <cstdlib>
@ -31,21 +31,23 @@
void* protocolManagerUpdate(void* data)
{
ProtocolManager* manager = static_cast<ProtocolManager*>(data);
while(!manager->exit())
while(manager && !manager->exit())
{
manager->update();
irr_driver->getDevice()->sleep(20);
StkTime::sleep(2);
}
return NULL;
}
void* protocolManagerAsynchronousUpdate(void* data)
{
ProtocolManager* manager = static_cast<ProtocolManager*>(data);
while(!manager->exit())
manager->m_asynchronous_thread_running = true;
while(manager && !manager->exit())
{
manager->asynchronousUpdate();
irr_driver->getDevice()->sleep(20);
StkTime::sleep(2);
}
manager->m_asynchronous_thread_running = false;
return NULL;
}
@ -73,8 +75,14 @@ ProtocolManager::ProtocolManager()
}
ProtocolManager::~ProtocolManager()
{
}
void ProtocolManager::abort()
{
pthread_mutex_unlock(&m_exit_mutex); // will stop the update function
pthread_join(*m_asynchronous_update_thread, NULL); // wait the thread to finish
pthread_mutex_lock(&m_events_mutex);
pthread_mutex_lock(&m_protocols_mutex);
pthread_mutex_lock(&m_asynchronous_protocols_mutex);
@ -83,7 +91,7 @@ ProtocolManager::~ProtocolManager()
for (unsigned int i = 0; i < m_protocols.size() ; i++)
delete m_protocols[i].protocol;
for (unsigned int i = 0; i < m_events_to_process.size() ; i++)
delete m_events_to_process[i];
delete m_events_to_process[i].event;
m_protocols.clear();
m_requests.clear();
m_events_to_process.clear();
@ -105,7 +113,50 @@ void ProtocolManager::notifyEvent(Event* event)
{
pthread_mutex_lock(&m_events_mutex);
Event* event2 = new Event(*event);
m_events_to_process.push_back(event2); // add the event to the queue
// register protocols that will receive this event
std::vector<int> protocols_ids;
PROTOCOL_TYPE searchedProtocol = PROTOCOL_NONE;
if (event2->type == EVENT_TYPE_MESSAGE)
{
if (event2->data().size() > 0)
{
searchedProtocol = (PROTOCOL_TYPE)(event2->data()[0]);
event2->removeFront(1);
}
else
{
Log::warn("ProtocolManager", "Not enough data.");
}
}
if (event2->type == EVENT_TYPE_CONNECTED)
{
searchedProtocol = PROTOCOL_CONNECTION;
}
Log::verbose("ProtocolManager", "Received event for protocols of type %d", searchedProtocol);
pthread_mutex_lock(&m_protocols_mutex);
for (unsigned int i = 0; i < m_protocols.size() ; i++)
{
if (m_protocols[i].protocol->getProtocolType() == searchedProtocol || event2->type == EVENT_TYPE_DISCONNECTED) // pass data to protocols even when paused
{
protocols_ids.push_back(m_protocols[i].id);
}
}
pthread_mutex_unlock(&m_protocols_mutex);
if (searchedProtocol == PROTOCOL_NONE) // no protocol was aimed, show the msg to debug
{
Log::debug("ProtocolManager", "NO PROTOCOL : Message is \"%s\"", event2->data().c_str());
}
if (protocols_ids.size() != 0)
{
EventProcessingInfo epi;
epi.arrival_time = StkTime::getTimeSinceEpoch();
epi.event = event2;
epi.protocols_ids = protocols_ids;
m_events_to_process.push_back(epi); // add the event to the queue
}
else
Log::warn("ProtocolManager", "Received an event for %d that has no destination protocol.", searchedProtocol);
pthread_mutex_unlock(&m_events_mutex);
}
@ -274,36 +325,50 @@ void ProtocolManager::protocolTerminated(ProtocolInfo protocol)
pthread_mutex_unlock(&m_protocols_mutex);
}
void ProtocolManager::propagateEvent(Event* event)
bool ProtocolManager::propagateEvent(EventProcessingInfo* event, bool synchronous)
{
PROTOCOL_TYPE searchedProtocol = PROTOCOL_NONE;
if (event->type == EVENT_TYPE_MESSAGE)
int index = 0;
for (unsigned int i = 0; i < m_protocols.size(); i++)
{
if (event->data.size() > 0)
searchedProtocol = (PROTOCOL_TYPE)(event->data.getAndRemoveUInt8());
if (event->protocols_ids[index] == m_protocols[i].id)
{
bool result = false;
if (synchronous)
result = m_protocols[i].protocol->notifyEvent(event->event);
else
result = m_protocols[i].protocol->notifyEventAsynchronous(event->event);
if (result)
event->protocols_ids.pop_back();
else
index++;
}
}
if (event->type == EVENT_TYPE_CONNECTED)
if (event->protocols_ids.size() == 0 || (StkTime::getTimeSinceEpoch()-event->arrival_time) >= TIME_TO_KEEP_EVENTS)
{
searchedProtocol = PROTOCOL_CONNECTION;
// because we made a copy of the event
delete event->event->peer; // no more need of that
delete event->event;
return true;
}
Log::verbose("ProtocolManager", "Received event for protocols of type %d", searchedProtocol);
for (unsigned int i = 0; i < m_protocols.size() ; i++)
{
if (m_protocols[i].protocol->getProtocolType() == searchedProtocol || event->type == EVENT_TYPE_DISCONNECTED) // pass data to protocols even when paused
m_protocols[i].protocol->notifyEvent(event);
}
if (searchedProtocol == PROTOCOL_NONE) // no protocol was aimed, show the msg to debug
{
Log::debug("ProtocolManager", "NO PROTOCOL : Message is \"%s\"", event->data.c_str());
}
// because we made a copy of the event
delete event->peer; // no more need of that
delete event;
return false;
}
void ProtocolManager::update()
{
// before updating, notice protocols that they have received events
pthread_mutex_lock(&m_events_mutex); // secure threads
int size = m_events_to_process.size();
int offset = 0;
for (int i = 0; i < size; i++)
{
bool result = propagateEvent(&m_events_to_process[i+offset], true);
if (result)
{
m_events_to_process.erase(m_events_to_process.begin()+i+offset,m_events_to_process.begin()+i+offset+1);
offset --;
}
}
pthread_mutex_unlock(&m_events_mutex); // release the mutex
// now update all protocols
pthread_mutex_lock(&m_protocols_mutex);
for (unsigned int i = 0; i < m_protocols.size(); i++)
@ -317,16 +382,19 @@ void ProtocolManager::update()
void ProtocolManager::asynchronousUpdate()
{
// before updating, notice protocols that they have received information
pthread_mutex_lock(&m_events_mutex); // secure threads
int size = m_events_to_process.size();
int offset = 0;
for (int i = 0; i < size; i++)
{
pthread_mutex_lock(&m_events_mutex); // secure threads
Event* event = m_events_to_process.back();
m_events_to_process.pop_back();
pthread_mutex_unlock(&m_events_mutex); // release the mutex
propagateEvent(event);
bool result = propagateEvent(&m_events_to_process[i+offset], false);
if (result)
{
m_events_to_process.erase(m_events_to_process.begin()+i+offset,m_events_to_process.begin()+i+offset+1);
offset --;
}
}
pthread_mutex_unlock(&m_events_mutex); // release the mutex
// now update all protocols that need to be updated in asynchronous mode
pthread_mutex_lock(&m_asynchronous_protocols_mutex);

View File

@ -31,6 +31,8 @@
#include <vector>
#define TIME_TO_KEEP_EVENTS 1.0
/*!
* \enum PROTOCOL_STATE
* \brief Defines the three states that a protocol can have.
@ -78,6 +80,16 @@ typedef struct ProtocolRequest
ProtocolInfo protocol_info; //!< The concerned protocol information
} ProtocolRequest;
/*! \struct ProtocolRequest
* \brief Used to pass the event to protocols that need it
*/
typedef struct EventProcessingInfo
{
Event* event;
double arrival_time;
std::vector<int> protocols_ids;
} EventProcessingInfo;
/*!
* \class ProtocolManager
* \brief Manages the protocols at runtime.
@ -93,8 +105,11 @@ typedef struct ProtocolRequest
class ProtocolManager : public Singleton<ProtocolManager>
{
friend class Singleton<ProtocolManager>;
friend void* protocolManagerAsynchronousUpdate(void* data);
public:
/*! \brief Stops the protocol manager. */
virtual void abort();
/*!
* \brief Function that processes incoming events.
* This function is called by the network manager each time there is an
@ -269,7 +284,7 @@ class ProtocolManager : public Singleton<ProtocolManager>
*/
virtual void protocolTerminated(ProtocolInfo protocol);
void propagateEvent(Event* event);
bool propagateEvent(EventProcessingInfo* event, bool synchronous);
// protected members
/*!
@ -281,7 +296,7 @@ class ProtocolManager : public Singleton<ProtocolManager>
/*!
* \brief Contains the network events to pass to protocols.
*/
std::vector<Event*> m_events_to_process;
std::vector<EventProcessingInfo> m_events_to_process;
/*!
* \brief Contains the requests to start/stop etc... protocols.
*/
@ -311,6 +326,8 @@ class ProtocolManager : public Singleton<ProtocolManager>
pthread_t* m_update_thread;
/*! Asynchronous update thread.*/
pthread_t* m_asynchronous_update_thread;
/*! True if the thread is running. */
bool m_asynchronous_thread_running;
};

View File

@ -20,6 +20,9 @@
#include "network/network_manager.hpp"
#include "network/protocols/start_game_protocol.hpp"
#include "network/network_world.hpp"
#include "modes/world_with_rank.hpp"
#include "online/current_user.hpp"
#include "states_screens/state_manager.hpp"
#include "states_screens/network_kart_selection.hpp"
@ -43,6 +46,7 @@ ClientLobbyRoomProtocol::~ClientLobbyRoomProtocol()
void ClientLobbyRoomProtocol::setup()
{
m_setup = NetworkManager::getInstance()->setupNewGame(); // create a new setup
m_setup->getRaceConfig()->setPlayerCount(16); //FIXME : this has to be changed when logging into the server
m_state = NONE;
}
@ -53,7 +57,67 @@ void ClientLobbyRoomProtocol::requestKartSelection(std::string kart_name)
NetworkString request;
// 0x02 : kart selection request, size_token (4), token, size kart name, kart name
request.ai8(0x02).ai8(4).ai32(m_server->getClientServerToken()).ai8(kart_name.size()).as(kart_name);
m_listener->sendMessage(this, request);
m_listener->sendMessage(this, request, true);
}
//-----------------------------------------------------------------------------
void ClientLobbyRoomProtocol::voteMajor(uint8_t major)
{
NetworkString request;
// 0xc0 : major vote, size_token (4), token, size major(1),major
request.ai8(0xc0).ai8(4).ai32(m_server->getClientServerToken()).ai8(1).ai8(major);
m_listener->sendMessage(this, request, true);
}
//-----------------------------------------------------------------------------
void ClientLobbyRoomProtocol::voteRaceCount(uint8_t count)
{
NetworkString request;
// 0xc0 : race count vote, size_token (4), token, size race count(1), count
request.ai8(0xc1).ai8(4).ai32(m_server->getClientServerToken()).ai8(1).ai8(count);
m_listener->sendMessage(this, request, true);
}
//-----------------------------------------------------------------------------
void ClientLobbyRoomProtocol::voteMinor(uint8_t minor)
{
NetworkString request;
// 0xc0 : minor vote, size_token (4), token, size minor(1),minor
request.ai8(0xc2).ai8(4).ai32(m_server->getClientServerToken()).ai8(1).ai8(minor);
m_listener->sendMessage(this, request, true);
}
//-----------------------------------------------------------------------------
void ClientLobbyRoomProtocol::voteTrack(std::string track, uint8_t track_nb)
{
NetworkString request;
// 0xc0 : major vote, size_token (4), token, size track, track, size #track, #track
request.ai8(0xc3).ai8(4).ai32(m_server->getClientServerToken()).ai8(track.size()).as(track).ai8(1).ai8(track_nb);
m_listener->sendMessage(this, request, true);
}
//-----------------------------------------------------------------------------
void ClientLobbyRoomProtocol::voteReversed(bool reversed, uint8_t track_nb)
{
NetworkString request;
// 0xc0 : major vote, size_token (4), token, size reversed(1),reversed, size #track, #track
request.ai8(0xc4).ai8(4).ai32(m_server->getClientServerToken()).ai8(1).ai8(reversed).ai8(1).ai8(track_nb);
m_listener->sendMessage(this, request, true);
}
//-----------------------------------------------------------------------------
void ClientLobbyRoomProtocol::voteLaps(uint8_t laps, uint8_t track_nb)
{
NetworkString request;
// 0xc0 : major vote, size_token (4), token, size laps(1),laps, size #track, #track
request.ai8(0xc5).ai8(4).ai32(m_server->getClientServerToken()).ai8(1).ai8(laps).ai8(1).ai8(track_nb);
m_listener->sendMessage(this, request, true);
}
//-----------------------------------------------------------------------------
@ -67,21 +131,50 @@ void ClientLobbyRoomProtocol::leave()
//-----------------------------------------------------------------------------
void ClientLobbyRoomProtocol::notifyEvent(Event* event)
bool ClientLobbyRoomProtocol::notifyEvent(Event* event)
{
assert(m_setup); // assert that the setup exists
if (event->type == EVENT_TYPE_MESSAGE)
{
assert(event->data.size()); // assert that data isn't empty
uint8_t message_type = event->data.getAndRemoveUInt8();
NetworkString data = event->data();
assert(data.size()); // assert that data isn't empty
uint8_t message_type = data[0];
if (message_type != 0x03 &&
message_type != 0x06)
return false; // don't treat the event
Log::info("ClientLobbyRoomProtocol", "Message of type %d", message_type);
event->removeFront(1);
Log::info("ClientLobbyRoomProtocol", "Synchronous message of type %d", message_type);
if (message_type == 0x03) // kart selection update
kartSelectionUpdate(event);
else if (message_type == 0x06) // end of race
raceFinished(event);
return true;
}
return false;
}
//-----------------------------------------------------------------------------
bool ClientLobbyRoomProtocol::notifyEventAsynchronous(Event* event)
{
assert(m_setup); // assert that the setup exists
if (event->type == EVENT_TYPE_MESSAGE)
{
NetworkString data = event->data();
assert(data.size()); // assert that data isn't empty
uint8_t message_type = data[0];
if (message_type == 0x03 ||
message_type == 0x06)
return false; // don't treat the event
event->removeFront(1);
Log::info("ClientLobbyRoomProtocol", "Asynchronous message of type %d", message_type);
if (message_type == 0x01) // new player connected
newPlayer(event);
else if (message_type == 0x02) // player disconnected
disconnectedPlayer(event);
else if (message_type == 0x03) // kart selection update
kartSelectionUpdate(event);
else if (message_type == 0x04) // start race
startGame(event);
else if (message_type == 0x05) // start selection phase
@ -92,10 +185,24 @@ void ClientLobbyRoomProtocol::notifyEvent(Event* event)
connectionAccepted(event);
else if (message_type == 0x82) // kart selection refused
kartSelectionRefused(event);
else if (message_type == 0xc0) // vote for major mode
playerMajorVote(event);
else if (message_type == 0xc1) // vote for race count
playerRaceCountVote(event);
else if (message_type == 0xc2) // vote for minor mode
playerMinorVote(event);
else if (message_type == 0xc3) // vote for track
playerTrackVote(event);
else if (message_type == 0xc4) // vote for reversed mode
playerReversedVote(event);
else if (message_type == 0xc5) // vote for laps
playerLapsVote(event);
return true;
} // message
else if (event->type == EVENT_TYPE_CONNECTED)
{
return true;
} // connection
else if (event->type == EVENT_TYPE_DISCONNECTED) // means we left essentially
{
@ -105,7 +212,9 @@ void ClientLobbyRoomProtocol::notifyEvent(Event* event)
m_listener->requestTerminate(this);
NetworkManager::getInstance()->reset();
NetworkManager::getInstance()->removePeer(*event->peer); // prolly the same as m_server
return true;
} // disconnection
return false;
}
//-----------------------------------------------------------------------------
@ -127,7 +236,8 @@ void ClientLobbyRoomProtocol::update()
ns.ai8(1).ai8(4).ai32(Online::CurrentUser::get()->getID());
m_listener->sendMessage(this, ns);
m_state = REQUESTING_CONNECTION;
} break;
}
break;
case REQUESTING_CONNECTION:
break;
case CONNECTED:
@ -137,10 +247,20 @@ void ClientLobbyRoomProtocol::update()
NetworkKartSelectionScreen* screen = NetworkKartSelectionScreen::getInstance();
StateManager::get()->pushScreen(screen);
m_state = SELECTING_KARTS;
} break;
}
break;
case SELECTING_KARTS:
break;
case PLAYING:
{
if (NetworkWorld::getInstance<NetworkWorld>()->isRaceOver()) // race is now over, kill race protocols and return to connected state
{
Log::info("ClientLobbyRoomProtocol", "Game finished.");
m_state = RACE_FINISHED;
}
}
break;
case RACE_FINISHED:
break;
case DONE:
m_state = EXITING;
@ -165,14 +285,15 @@ void ClientLobbyRoomProtocol::update()
*/
void ClientLobbyRoomProtocol::newPlayer(Event* event)
{
if (event->data.size() != 7 || event->data[0] != 4 || event->data[5] != 1) // 7 bytes remains now
NetworkString data = event->data();
if (data.size() != 7 || data[0] != 4 || data[5] != 1) // 7 bytes remains now
{
Log::error("ClientLobbyRoomProtocol", "A message notifying a new player wasn't formated as expected.");
return;
}
uint32_t global_id = event->data.gui32(1);
uint8_t race_id = event->data.gui8(6);
uint32_t global_id = data.gui32(1);
uint8_t race_id = data.gui8(6);
if (global_id == Online::CurrentUser::get()->getID())
{
@ -207,12 +328,13 @@ void ClientLobbyRoomProtocol::newPlayer(Event* event)
*/
void ClientLobbyRoomProtocol::disconnectedPlayer(Event* event)
{
if (event->data.size() != 2 || event->data[0] != 1)
NetworkString data = event->data();
if (data.size() != 2 || data[0] != 1)
{
Log::error("ClientLobbyRoomProtocol", "A message notifying a new player wasn't formated as expected.");
return;
}
uint8_t id = event->data[1];
uint8_t id = data[1];
if (m_setup->removePlayer(id))
{
Log::info("ClientLobbyRoomProtocol", "Peer removed successfully.");
@ -237,14 +359,15 @@ void ClientLobbyRoomProtocol::disconnectedPlayer(Event* event)
*/
void ClientLobbyRoomProtocol::connectionAccepted(Event* event)
{
if (event->data.size() < 12 || event->data[0] != 1 || event->data[2] != 4 || event->data[7] != 4) // 12 bytes remains now
NetworkString data = event->data();
if (data.size() < 12 || data[0] != 1 || data[2] != 4 || data[7] != 4) // 12 bytes remains now
{
Log::error("ClientLobbyRoomProtocol", "A message notifying an accepted connection wasn't formated as expected.");
return;
}
STKPeer* peer = *(event->peer);
uint32_t global_id = event->data.gui32(8);
uint32_t global_id = data.gui32(8);
if (global_id == Online::CurrentUser::get()->getID())
{
Log::info("ClientLobbyRoomProtocol", "The server accepted the connection.");
@ -252,15 +375,15 @@ void ClientLobbyRoomProtocol::connectionAccepted(Event* event)
// self profile
NetworkPlayerProfile* profile = new NetworkPlayerProfile();
profile->kart_name = "";
profile->race_id = event->data.gui8(1);
profile->race_id = data.gui8(1);
profile->user_profile = Online::CurrentUser::get()->getProfile();
m_setup->addPlayer(profile);
// connection token
uint32_t token = event->data.gui32(3);
uint32_t token = data.gui32(3);
peer->setClientServerToken(token);
// add all players
event->data.removeFront(12); // remove the 12 first bytes
int remaining = event->data.size();
data.removeFront(12); // remove the 12 first bytes
int remaining = data.size();
if (remaining%7 != 0)
{
Log::error("ClientLobbyRoomProtocol", "ConnectionAccepted : Error in the server list");
@ -268,17 +391,19 @@ void ClientLobbyRoomProtocol::connectionAccepted(Event* event)
remaining /= 7;
for (int i = 0; i < remaining; i++)
{
if (event->data[0] != 1 || event->data[2] != 4)
if (data[0] != 1 || data[2] != 4)
Log::error("ClientLobbyRoomProtocol", "Bad format in players list.");
uint8_t race_id = event->data[1];
uint32_t global_id = event->data.gui32(3);
uint8_t race_id = data[1];
uint32_t global_id = data.gui32(3);
Online::Profile* new_user = new Online::Profile(global_id, "");
NetworkPlayerProfile* profile2 = new NetworkPlayerProfile();
profile2->race_id = race_id;
profile2->user_profile = new_user;
profile2->kart_name = "";
m_setup->addPlayer(profile2);
event->data.removeFront(7);
data.removeFront(7);
}
// add self
@ -303,13 +428,14 @@ void ClientLobbyRoomProtocol::connectionAccepted(Event* event)
*/
void ClientLobbyRoomProtocol::connectionRefused(Event* event)
{
if (event->data.size() != 2 || event->data[0] != 1) // 2 bytes remains now
NetworkString data = event->data();
if (data.size() != 2 || data[0] != 1) // 2 bytes remains now
{
Log::error("ClientLobbyRoomProtocol", "A message notifying a refused connection wasn't formated as expected.");
return;
}
switch (event->data[1]) // the second byte
switch (data[1]) // the second byte
{
case 0:
Log::info("ClientLobbyRoomProtocol", "Connection refused : too many players.");
@ -337,13 +463,14 @@ void ClientLobbyRoomProtocol::connectionRefused(Event* event)
*/
void ClientLobbyRoomProtocol::kartSelectionRefused(Event* event)
{
if (event->data.size() != 2 || event->data[0] != 1)
NetworkString data = event->data();
if (data.size() != 2 || data[0] != 1)
{
Log::error("ClientLobbyRoomProtocol", "A message notifying a refused kart selection wasn't formated as expected.");
return;
}
switch (event->data[1]) // the error code
switch (data[1]) // the error code
{
case 0:
Log::info("ClientLobbyRoomProtocol", "Kart selection refused : already taken.");
@ -371,24 +498,26 @@ void ClientLobbyRoomProtocol::kartSelectionRefused(Event* event)
*/
void ClientLobbyRoomProtocol::kartSelectionUpdate(Event* event)
{
if (event->data.size() < 3 || event->data[0] != 1)
NetworkString data = event->data();
if (data.size() < 3 || data[0] != 1)
{
Log::error("ClientLobbyRoomProtocol", "A message notifying a kart selection update wasn't formated as expected.");
return;
}
uint8_t player_id = event->data[1];
uint8_t kart_name_length = event->data[2];
std::string data = event->data.getString(3, kart_name_length);
if (data.size() != kart_name_length)
uint8_t player_id = data[1];
uint8_t kart_name_length = data[2];
std::string kart_name = data.getString(3, kart_name_length);
if (kart_name.size() != kart_name_length)
{
Log::error("ClientLobbyRoomProtocol", "Kart names sizes differ: told: %d, real: %d.", kart_name_length, data.size());
Log::error("ClientLobbyRoomProtocol", "Kart names sizes differ: told: %d, real: %d.", kart_name_length, kart_name.size());
return;
}
if (!m_setup->isKartAvailable(data))
if (!m_setup->isKartAvailable(kart_name))
{
Log::error("ClientLobbyRoomProtocol", "The updated kart is taken already.");
}
m_setup->setPlayerKart(player_id, data);
m_setup->setPlayerKart(player_id, kart_name);
NetworkKartSelectionScreen::getInstance()->playerSelected(player_id, kart_name);
}
//-----------------------------------------------------------------------------
@ -405,13 +534,14 @@ void ClientLobbyRoomProtocol::kartSelectionUpdate(Event* event)
*/
void ClientLobbyRoomProtocol::startGame(Event* event)
{
if (event->data.size() < 5 || event->data[0] != 4)
NetworkString data = event->data();
if (data.size() < 5 || data[0] != 4)
{
Log::error("ClientLobbyRoomProtocol", "A message notifying a kart "
"selection update wasn't formated as expected.");
"selection update wasn't formated as expected.");
return;
}
uint8_t token = event->data.gui32(1);
uint8_t token = data.gui32(1);
if (token == NetworkManager::getInstance()->getPeers()[0]->getClientServerToken())
{
m_state = PLAYING;
@ -437,13 +567,14 @@ void ClientLobbyRoomProtocol::startGame(Event* event)
*/
void ClientLobbyRoomProtocol::startSelection(Event* event)
{
if (event->data.size() < 5 || event->data[0] != 4)
NetworkString data = event->data();
if (data.size() < 5 || data[0] != 4)
{
Log::error("ClientLobbyRoomProtocol", "A message notifying a kart "
"selection update wasn't formated as expected.");
"selection update wasn't formated as expected.");
return;
}
uint8_t token = event->data.gui32(1);
uint8_t token = data.gui32(1);
if (token == NetworkManager::getInstance()->getPeers()[0]->getClientServerToken())
{
m_state = KART_SELECTION;
@ -455,3 +586,221 @@ void ClientLobbyRoomProtocol::startSelection(Event* event)
}
//-----------------------------------------------------------------------------
/*! \brief Called when all karts have finished the race.
* \param event : Event providing the information.
*
* Format of the data :
* Byte 0 1 5 6 7 8 9
* ---------------------------------------------------
* Size | 1 | 4 | 1 | 1 | 1 | 1 | |
* Data | 4 | token | 1 | Kart 1 ID | 1 | kart id 2 | ... |
* ---------------------------------------------------
*/
void ClientLobbyRoomProtocol::raceFinished(Event* event)
{
if (event->data().size() < 5)
{
Log::error("ClientLobbyRoomProtocol", "Not enough data provided.");
return;
}
NetworkString data = event->data();
if ((*event->peer)->getClientServerToken() != data.gui32(1))
{
Log::error("ClientLobbyRoomProtocol", "Bad token");
return;
}
data.removeFront(5);
Log::error("ClientLobbyRoomProtocol", "Server notified that the race is finished.");
// stop race protocols
Protocol* protocol = NULL;
protocol = m_listener->getProtocol(PROTOCOL_CONTROLLER_EVENTS);
if (protocol)
m_listener->requestTerminate(protocol);
else
Log::error("ClientLobbyRoomProtocol", "No controller events protocol registered.");
protocol = m_listener->getProtocol(PROTOCOL_KART_UPDATE);
if (protocol)
m_listener->requestTerminate(protocol);
else
Log::error("ClientLobbyRoomProtocol", "No kart update protocol registered.");
protocol = m_listener->getProtocol(PROTOCOL_GAME_EVENTS);
if (protocol)
m_listener->requestTerminate(protocol);
else
Log::error("ClientLobbyRoomProtocol", "No game events protocol registered.");
// finish the race
WorldWithRank* ranked_world = (WorldWithRank*)(World::getWorld());
ranked_world->beginSetKartPositions();
ranked_world->setPhase(WorldStatus::RESULT_DISPLAY_PHASE);
int position = 1;
while(data.size()>0)
{
if (data.size() < 2)
{
Log::error("ClientLobbyRoomProtocol", "Incomplete field.");
return;
}
if (data[0] != 1)
{
Log::error("ClientLobbyRoomProtocol", "Badly formatted field.");
return;
}
uint8_t kart_id = data[1];
ranked_world->setKartPosition(kart_id,position);
Log::info("ClientLobbyRoomProtocol", "Kart %d has finished #%d", kart_id, position);
data.removeFront(2);
position++;
}
ranked_world->endSetKartPositions();
m_state = RACE_FINISHED;
ranked_world->terminateRace();
}
//-----------------------------------------------------------------------------
/*! \brief Called when a player votes for a major race mode.
* \param event : Event providing the information.
*
* Format of the data :
* Byte 0 1 5 6 7 8 9
* --------------------------------------------------------
* Size | 1 | 4 | 1 | 1 | 1 | 1 |
* Data | 4 | priv token | 1 | player id | 1 | major mode vote |
* --------------------------------------------------------
*/
void ClientLobbyRoomProtocol::playerMajorVote(Event* event)
{
NetworkString data = event->data();
if (!checkDataSizeAndToken(event, 9))
return;
if (!isByteCorrect(event, 5, 1))
return;
if (!isByteCorrect(event, 7, 1))
return;
m_setup->getRaceConfig()->setPlayerMajorVote(data[6], data[8]);
}
//-----------------------------------------------------------------------------
/*! \brief Called when a player votes for the number of races in a GP.
* \param event : Event providing the information.
*
* Format of the data :
* Byte 0 1 5 6 7 8 9
* ----------------------------------------------------
* Size | 1 | 4 | 1 | 1 | 1 | 1 |
* Data | 4 | priv token | 1 | player id | 1 | races count |
* ----------------------------------------------------
*/
void ClientLobbyRoomProtocol::playerRaceCountVote(Event* event)
{
NetworkString data = event->data();
if (!checkDataSizeAndToken(event, 9))
return;
if (!isByteCorrect(event, 5, 1))
return;
if (!isByteCorrect(event, 7, 1))
return;
m_setup->getRaceConfig()->setPlayerRaceCountVote(data[6], data[8]);
}
//-----------------------------------------------------------------------------
/*! \brief Called when a player votes for a minor race mode.
* \param event : Event providing the information.
*
* Format of the data :
* Byte 0 1 5 6 7 8 9
* --------------------------------------------------------
* Size | 1 | 4 | 1 | 1 | 1 | 1 |
* Data | 4 | priv token | 1 | player id | 1 | minor mode vote |
* --------------------------------------------------------
*/
void ClientLobbyRoomProtocol::playerMinorVote(Event* event)
{
NetworkString data = event->data();
if (!checkDataSizeAndToken(event, 9))
return;
if (!isByteCorrect(event, 5, 1))
return;
if (!isByteCorrect(event, 7, 1))
return;
m_setup->getRaceConfig()->setPlayerMinorVote(data[6], data[8]);
}
//-----------------------------------------------------------------------------
/*! \brief Called when a player votes for a track.
* \param event : Event providing the information.
*
* Format of the data :
* Byte 0 1 5 6 7 8 N+8 N+9 N+10
* ---------------------------------------------------------------------------
* Size | 1 | 4 | 1 | 1 | 1 | N | 1 | 1 |
* Data | 4 | priv token | 1 | player id | N | track name | 1 | track number (gp) |
* ---------------------------------------------------------------------------
*/
void ClientLobbyRoomProtocol::playerTrackVote(Event* event)
{
NetworkString data = event->data();
if (!checkDataSizeAndToken(event, 10))
return;
if (!isByteCorrect(event, 5, 1))
return;
int N = data[7];
std::string track_name = data.gs(8, N);
if (!isByteCorrect(event, N+8, 1))
return;
m_setup->getRaceConfig()->setPlayerTrackVote(data[6], track_name, data[N+9]);
}
//-----------------------------------------------------------------------------
/*! \brief Called when a player votes for the reverse mode of a race
* \param event : Event providing the information.
*
* Format of the data :
* Byte 0 1 5 6 7 8 9 10 11
* -------------------------------------------------------------------------
* Size | 1 | 4 | 1 | 1 | 1 | 1 | 1 | 1 |
* Data | 4 | priv token | 1 | player id | 1 | reversed | 1 | track number (gp) |
* -------------------------------------------------------------------------
*/
void ClientLobbyRoomProtocol::playerReversedVote(Event* event)
{
NetworkString data = event->data();
if (!checkDataSizeAndToken(event, 11))
return;
if (!isByteCorrect(event, 5, 1))
return;
if (!isByteCorrect(event, 7, 1))
return;
if (!isByteCorrect(event, 9, 1))
return;
m_setup->getRaceConfig()->setPlayerReversedVote(data[6], data[8]!=0, data[10]);
}
//-----------------------------------------------------------------------------
/*! \brief Called when a player votes for a major race mode.
* \param event : Event providing the information.
*
* Format of the data :
* Byte 0 1 5 6 7 8 9 10 11
* ---------------------------------------------------------------------
* Size | 1 | 4 | 1 | 1 | 1 | 1 | 1 | 1 |
* Data | 4 | priv token | 1 | player id | 1 | laps | 1 | track number (gp) |
* ---------------------------------------------------------------------
*/
void ClientLobbyRoomProtocol::playerLapsVote(Event* event)
{
NetworkString data = event->data();
if (!checkDataSizeAndToken(event, 9))
return;
if (!isByteCorrect(event, 5, 1))
return;
if (!isByteCorrect(event, 7, 1))
return;
m_setup->getRaceConfig()->setPlayerLapsVote(data[6], data[8], data[10]);
}
//-----------------------------------------------------------------------------

View File

@ -10,10 +10,17 @@ class ClientLobbyRoomProtocol : public LobbyRoomProtocol
virtual ~ClientLobbyRoomProtocol();
void requestKartSelection(std::string kart_name);
void voteMajor(uint8_t major);
void voteRaceCount(uint8_t count);
void voteMinor(uint8_t minor);
void voteTrack(std::string track, uint8_t track_nb = 0);
void voteReversed(bool reversed, uint8_t track_nb = 0);
void voteLaps(uint8_t laps, uint8_t track_nb = 0);
void sendMessage(std::string message);
void leave();
virtual void notifyEvent(Event* event);
virtual bool notifyEvent(Event* event);
virtual bool notifyEventAsynchronous(Event* event);
virtual void setup();
virtual void update();
virtual void asynchronousUpdate() {}
@ -27,6 +34,14 @@ class ClientLobbyRoomProtocol : public LobbyRoomProtocol
void kartSelectionUpdate(Event* event);
void startGame(Event* event);
void startSelection(Event* event);
void raceFinished(Event* event);
// race votes
void playerMajorVote(Event* event);
void playerRaceCountVote(Event* event);
void playerMinorVote(Event* event);
void playerTrackVote(Event* event);
void playerReversedVote(Event* event);
void playerLapsVote(Event* event);
TransportAddress m_server_address;
STKPeer* m_server;
@ -40,6 +55,7 @@ class ClientLobbyRoomProtocol : public LobbyRoomProtocol
KART_SELECTION,
SELECTING_KARTS, // in the network kart selection screen
PLAYING,
RACE_FINISHED,
DONE,
EXITING
};

View File

@ -46,13 +46,14 @@ ConnectToPeer::~ConnectToPeer()
// ----------------------------------------------------------------------------
void ConnectToPeer::notifyEvent(Event* event)
bool ConnectToPeer::notifyEventAsynchronous(Event* event)
{
if (event->type == EVENT_TYPE_CONNECTED)
{
Log::debug("ConnectToPeer", "Received event notifying peer connection.");
m_state = CONNECTED; // we received a message, we are connected
}
return true;
}
// ----------------------------------------------------------------------------
@ -85,8 +86,28 @@ void ConnectToPeer::asynchronousUpdate()
{
if (m_peer_address.ip != 0 && m_peer_address.port != 0)
{
// we're in the same lan (same public ip address) !!
if (m_peer_address.ip == NetworkManager::getInstance()->getPublicAddress().ip)
{
// just send a broadcast packet with the string aloha_stk inside, the client will know our ip address and will connect
STKHost* host = NetworkManager::getInstance()->getHost();
TransportAddress broadcast_address;
broadcast_address.ip = -1; // 255.255.255.255
broadcast_address.port = m_peer_address.port; // 0b10101100000101101101111111111111; // for test
char data[] = "aloha_stk\0";
host->sendRawPacket((uint8_t*)(data), 10, broadcast_address);
Log::info("ConnectToPeer", "Broadcast aloha sent.");
StkTime::sleep(1);
broadcast_address.ip = 0x7f000001; // 127.0.0.1 (localhost)
broadcast_address.port = m_peer_address.port;
host->sendRawPacket((uint8_t*)(data), 10, broadcast_address);
Log::info("ConnectToPeer", "Broadcast aloha to self.");
}
else
{
m_current_protocol_id = m_listener->requestStart(new PingProtocol(m_peer_address, 2.0));
}
m_state = CONNECTING;
m_current_protocol_id = m_listener->requestStart(new PingProtocol(m_peer_address, 2.0));
}
else
{
@ -96,9 +117,12 @@ void ConnectToPeer::asynchronousUpdate()
}
break;
case CONNECTING: // waiting the peer to connect
break;
case CONNECTED:
{
m_listener->requestTerminate( m_listener->getProtocol(m_current_protocol_id)); // kill the ping protocol because we're connected
// the ping protocol is there for NAT traversal (disabled when connecting to LAN peer)
if (m_peer_address != NetworkManager::getInstance()->getPublicAddress())
m_listener->requestTerminate( m_listener->getProtocol(m_current_protocol_id)); // kill the ping protocol because we're connected
m_state = DONE;
break;
}

View File

@ -29,7 +29,7 @@ class ConnectToPeer : public Protocol, public CallbackObject
ConnectToPeer(uint32_t peer_id);
virtual ~ConnectToPeer();
virtual void notifyEvent(Event* event);
virtual bool notifyEventAsynchronous(Event* event);
virtual void setup();
virtual void update() {}
virtual void asynchronousUpdate();

View File

@ -31,6 +31,12 @@
#include "utils/time.hpp"
#include "utils/log.hpp"
#ifdef WIN32
# include <iphlpapi.h>
#else
#include <ifaddrs.h>
#endif
// ----------------------------------------------------------------------------
ConnectToServer::ConnectToServer() :
@ -60,7 +66,7 @@ ConnectToServer::~ConnectToServer()
// ----------------------------------------------------------------------------
void ConnectToServer::notifyEvent(Event* event)
bool ConnectToServer::notifyEventAsynchronous(Event* event)
{
if (event->type == EVENT_TYPE_CONNECTED)
{
@ -68,6 +74,7 @@ void ConnectToServer::notifyEvent(Event* event)
"received an event notifying that he's connected to the peer.");
m_state = CONNECTED; // we received a message, we are connected
}
return true;
}
// ----------------------------------------------------------------------------
@ -132,9 +139,11 @@ void ConnectToServer::asynchronousUpdate()
if (m_listener->getProtocolState(m_current_protocol_id)
== PROTOCOL_STATE_TERMINATED) // we know the server address
{
Log::info("ConnectToServer", "Server's address known");
if (m_server_address.ip == m_public_address.ip) // we're in the same lan (same public ip address) !!
Log::info("ConnectToServer", "Server appears to be in the same LAN.");
m_state = REQUESTING_CONNECTION;
m_current_protocol_id = m_listener->requestStart(new RequestConnection(m_server_id));
Log::info("ConnectToServer", "Server's address known");
}
break;
case REQUESTING_CONNECTION:
@ -145,11 +154,90 @@ void ConnectToServer::asynchronousUpdate()
if (m_server_address.ip == 0 || m_server_address.port == 0)
{ // server data not correct, hide address and stop
m_state = HIDING_ADDRESS;
Log::error("ConnectToServer", "Server address is "ADDRESS_FORMAT, ADDRESS_ARGS(m_server_address.ip, m_server_address.port));
m_current_protocol_id = m_listener->requestStart(new HidePublicAddress());
return;
}
m_state = CONNECTING;
m_current_protocol_id = m_listener->requestStart(new PingProtocol(m_server_address, 2.0));
if (m_server_address.ip == m_public_address.ip) // we're in the same lan (same public ip address) !!
{
// just send a broadcast packet, the client will know our ip address and will connect
STKHost* host = NetworkManager::getInstance()->getHost();
host->stopListening(); // stop the listening
TransportAddress sender;
TransportAddress broadcast_address;
broadcast_address.ip = -1; // 255.255.255.255
broadcast_address.port = 7321; // 0b10101100000101101101111111111111; // for test
char data2[] = "aloha_stk\0";
host->sendRawPacket((uint8_t*)(data2), 10, broadcast_address);
Log::info("ConnectToServer", "Waiting broadcast message.");
const uint8_t* received_data = host->receiveRawPacket(&sender); // get the sender
host->startListening(); // start listening again
const char data[] = "aloha_stk\0";
if (strcmp(data, (char*)(received_data)) == 0)
{
Log::info("ConnectToServer", "LAN Server found : %u:%u", sender.ip, sender.port);
#ifndef WIN32
// just check if the ip is ours : if so, then just use localhost (127.0.0.1)
struct ifaddrs *ifap, *ifa;
struct sockaddr_in *sa;
getifaddrs (&ifap); // get the info
for (ifa = ifap; ifa; ifa = ifa->ifa_next)
{
if (ifa->ifa_addr->sa_family==AF_INET)
{
sa = (struct sockaddr_in *) ifa->ifa_addr;
if (ntohl(sa->sin_addr.s_addr) == sender.ip) // this interface is ours
sender.ip = 0x7f000001; // 127.0.0.1
}
}
freeifaddrs(ifap);
#else
// Query the list of all IP addresses on the local host
// First call to GetIpAddrTable with 0 bytes buffer
// will return insufficient buffer error, and size
// will contain the number of bytes needed for all
// data. Repeat the process of querying the size
// using GetIpAddrTable in a while loop since it
// can happen that an interface comes online between
// the previous call to GetIpAddrTable and the next
// call.
MIB_IPADDRTABLE *table = NULL;
unsigned long size = 0;
int error = GetIpAddrTable(table, &size, 0);
// Also add a count to limit the while loop - in
// case that something strange is going on.
int count = 0;
while(error==ERROR_INSUFFICIENT_BUFFER && count < 10)
{
delete table; // deleting NULL is legal
table = (MIB_IPADDRTABLE*)new char[size];
error = GetIpAddrTable(table, &size, 0);
count ++;
} // while insufficient buffer
for(unsigned int i=0; i<table->dwNumEntries; i++)
{
int ip = ntohl(table->table[i].dwAddr);
if(sender.ip == ip) // this interface is ours
{
sender.ip = 0x7f000001; // 127.0.0.1
break;
}
}
delete table;
#endif
m_server_address = sender;
m_state = CONNECTING;
}
}
else
{
m_state = CONNECTING;
m_current_protocol_id = m_listener->requestStart(new PingProtocol(m_server_address, 2.0));
}
}
break;
case CONNECTING: // waiting the server to answer our connection
@ -159,7 +247,7 @@ void ConnectToServer::asynchronousUpdate()
{
timer = StkTime::getRealTime();
NetworkManager::getInstance()->connect(m_server_address);
Log::info("ConnectToServer", "Trying to connect");
Log::info("ConnectToServer", "Trying to connect to %u:%u", m_server_address.ip, m_server_address.port);
}
break;
}
@ -184,6 +272,9 @@ void ConnectToServer::asynchronousUpdate()
break;
case DONE:
m_listener->requestTerminate(this);
m_state = EXITING;
break;
case EXITING:
break;
}
}

View File

@ -30,7 +30,7 @@ class ConnectToServer : public Protocol, public CallbackObject
ConnectToServer(uint32_t server_id, uint32_t host_id); //!< Specify server id
virtual ~ConnectToServer();
virtual void notifyEvent(Event* event);
virtual bool notifyEventAsynchronous(Event* event);
virtual void setup();
virtual void update() {}
virtual void asynchronousUpdate();
@ -53,7 +53,8 @@ class ConnectToServer : public Protocol, public CallbackObject
CONNECTING,
CONNECTED,
HIDING_ADDRESS,
DONE
DONE,
EXITING
};
STATE m_state;
};

View File

@ -42,7 +42,7 @@ void ControllerEventsProtocol::setup()
{
peer = peers[j];
}
Log::info("ControllerEventsProtocol", "Compared %s and %s",
Log::info("ControllerEventsProtocol", "Compared %s and %s",
peers[j]->getPlayerProfile()->kart_name.c_str(), karts[i]->getIdent().c_str());
}
}
@ -61,30 +61,31 @@ void ControllerEventsProtocol::setup()
//-----------------------------------------------------------------------------
void ControllerEventsProtocol::notifyEvent(Event* event)
bool ControllerEventsProtocol::notifyEventAsynchronous(Event* event)
{
if (event->data.size() < 17)
NetworkString data = event->data();
if (data.size() < 17)
{
Log::error("ControllerEventsProtocol", "The data supplied was not complete. Size was %d.", event->data.size());
return;
Log::error("ControllerEventsProtocol", "The data supplied was not complete. Size was %d.", data.size());
return true;
}
uint32_t token = event->data.gui32();
NetworkString pure_message = event->data;
uint32_t token = data.gui32();
NetworkString pure_message = data;
pure_message.removeFront(4);
if (token != (*event->peer)->getClientServerToken())
{
Log::error("ControllerEventsProtocol", "Bad token from peer.");
return;
return true;
}
NetworkString ns = pure_message;
float event_timestamp = ns.getFloat();
ns.removeFront(4);
uint8_t client_index = -1;
while (ns.size() >= 9)
{
uint8_t controller_index = ns.gui8();
client_index = controller_index;
uint8_t serialized_1 = ns.gui8(1), serialized_2 = ns.gui8(2), serialized_3 = ns.gui8(3);
uint8_t serialized_1 = ns.gui8(1);
PlayerAction action = (PlayerAction)(ns.gui8(4));
int action_value = ns.gui32(5);
@ -103,12 +104,12 @@ void ControllerEventsProtocol::notifyEvent(Event* event)
if (ns.size() > 0 && ns.size() != 9)
{
Log::warn("ControllerEventProtocol", "The data seems corrupted. Remains %d", ns.size());
return;
return true;
}
if (client_index < 0)
{
Log::warn("ControllerEventProtocol", "Couldn't have a client id.");
return;
return true;
}
if (m_listener->isServer())
{
@ -124,6 +125,7 @@ void ControllerEventsProtocol::notifyEvent(Event* event)
//Log::info("ControllerEventsProtocol", "Sizes are %d and %d", ns2.size(), pure_message.size());
}
}
return true;
}
//-----------------------------------------------------------------------------
@ -162,6 +164,7 @@ void ControllerEventsProtocol::controllerAction(Controller* controller,
ns.ai8(serialized_1).ai8(serialized_2).ai8(serialized_3);
ns.ai8((uint8_t)(action)).ai32(value);
Log::info("ControllerEventsProtocol", "Action %d value %d", action, value);
m_listener->sendMessage(this, ns, false); // send message to server
}

View File

@ -16,8 +16,8 @@ class ControllerEventsProtocol : public Protocol
ControllerEventsProtocol();
virtual ~ControllerEventsProtocol();
virtual bool notifyEventAsynchronous(Event* event);
virtual void setup();
virtual void notifyEvent(Event* event);
virtual void update();
virtual void asynchronousUpdate() {}

View File

@ -1,5 +1,13 @@
#include "network/protocols/game_events_protocol.hpp"
#include "karts/abstract_kart.hpp"
#include "items/attachment.hpp"
#include "items/item.hpp"
#include "items/item_manager.hpp"
#include "items/powerup.hpp"
#include "modes/world.hpp"
#include "network/network_manager.hpp"
GameEventsProtocol::GameEventsProtocol() : Protocol(NULL, PROTOCOL_GAME_EVENTS)
{
}
@ -8,8 +16,49 @@ GameEventsProtocol::~GameEventsProtocol()
{
}
void GameEventsProtocol::notifyEvent(Event* event)
bool GameEventsProtocol::notifyEvent(Event* event)
{
if (event->type != EVENT_TYPE_MESSAGE)
return true;
NetworkString data = event->data();
if (data.size() < 5) // for token and type
{
Log::warn("GameEventsProtocol", "Too short message.");
return true;
}
if ( (*event->peer)->getClientServerToken() != data.gui32())
{
Log::warn("GameEventsProtocol", "Bad token.");
return true;
}
int8_t type = data.gui8(4);
data.removeFront(5);
switch (type)
{
case 0x01: // item picked
{
if (data.size() < 6)
{
Log::warn("GameEventsProtocol", "Too short message.");
return true;
}
uint32_t item_id = data.gui32();
uint8_t powerup_type = data.gui8(4);
uint8_t kart_race_id = data.gui8(5);
// now set the kart powerup
AbstractKart* kart = World::getWorld()->getKart(
NetworkManager::getInstance()->getGameSetup()->getProfile(kart_race_id)->world_kart_id);
ItemManager::get()->collectedItem(
ItemManager::get()->getItem(item_id),
kart,
powerup_type);
Log::info("GameEventsProtocol", "Item %d picked by a player.", powerup_type);
} break;
default:
Log::warn("GameEventsProtocol", "Unkown message type.");
break;
}
return true;
}
void GameEventsProtocol::setup()
@ -19,3 +68,27 @@ void GameEventsProtocol::setup()
void GameEventsProtocol::update()
{
}
void GameEventsProtocol::collectedItem(Item* item, AbstractKart* kart)
{
GameSetup* setup = NetworkManager::getInstance()->getGameSetup();
assert(setup);
const NetworkPlayerProfile* player_profile = setup->getProfile(kart->getIdent()); // use kart name
std::vector<STKPeer*> peers = NetworkManager::getInstance()->getPeers();
for (unsigned int i = 0; i < peers.size(); i++)
{
NetworkString ns;
ns.ai32(peers[i]->getClientServerToken());
// 0x01 : item picked : send item id, powerup type and kart race id
uint8_t powerup = 0;
if (item->getType() == Item::ITEM_BANANA)
powerup = (int)(kart->getAttachment()->getType());
else if (item->getType() == Item::ITEM_BONUS_BOX)
powerup = (((int)(kart->getPowerup()->getType()) << 4)&0xf0) + (kart->getPowerup()->getNum()&0x0f);
ns.ai8(0x01).ai32(item->getItemId()).ai8(powerup).ai8(player_profile->race_id); // send item,
m_listener->sendMessage(this, peers[i], ns, true); // reliable
Log::info("GameEventsProtocol", "Notified a peer that a kart collected item %d.", (int)(kart->getPowerup()->getType()));
}
}

View File

@ -3,6 +3,8 @@
#include "network/protocol.hpp"
class AbstractKart;
class Item;
class GameEventsProtocol : public Protocol
{
@ -10,11 +12,14 @@ class GameEventsProtocol : public Protocol
GameEventsProtocol();
virtual ~GameEventsProtocol();
virtual void notifyEvent(Event* event);
virtual bool notifyEvent(Event* event);
virtual bool notifyEventAsynchronous(Event* event) { return false; }
virtual void setup();
virtual void update();
virtual void asynchronousUpdate() {}
void collectedItem(Item* item, AbstractKart* kart);
protected:
};

View File

@ -19,7 +19,7 @@
#include "network/protocols/get_peer_address.hpp"
#include "network/protocol_manager.hpp"
#include "network/http_functions.hpp"
#include "network/network_manager.hpp"
#include "online/http_manager.hpp"
#include "online/current_user.hpp"
#include "config/user_config.hpp"
@ -34,11 +34,6 @@ GetPeerAddress::~GetPeerAddress()
{
}
void GetPeerAddress::notifyEvent(Event* event)
{
// nothing there. If we receive events, they must be ignored
}
void GetPeerAddress::setup()
{
m_state = NONE;
@ -70,7 +65,10 @@ void GetPeerAddress::asynchronousUpdate()
{
TransportAddress* addr = static_cast<TransportAddress*>(m_callback_object);
result->get("ip", &addr->ip);
result->get("port", &addr->port);
if (addr->ip == NetworkManager::getInstance()->getPublicAddress().ip)
result->get("private_port", &addr->port);
else
result->get("port", &addr->port);
Log::debug("GetPeerAddress", "Address gotten successfully.");
}
else

View File

@ -28,7 +28,8 @@ class GetPeerAddress : public Protocol
GetPeerAddress(uint32_t peer_id, CallbackObject* callback_object);
virtual ~GetPeerAddress();
virtual void notifyEvent(Event* event);
virtual bool notifyEvent(Event* event) { return true; }
virtual bool notifyEventAsynchronous(Event* event) { return true; }
virtual void setup();
virtual void update() {}
virtual void asynchronousUpdate();

View File

@ -18,14 +18,23 @@
#include "network/protocols/get_public_address.hpp"
#include "config/user_config.hpp"
#include "network/network_manager.hpp"
#include "network/client_network_manager.hpp"
#include "network/protocols/connect_to_server.hpp"
#include "network/network_interface.hpp"
#include "utils/log.hpp"
#include "utils/random_generator.hpp"
#include <assert.h>
#ifdef WIN32
# include <winsock2.h>
# include <ws2tcpip.h>
#else
# include <netdb.h>
#endif
#include <sys/types.h>
int stunRand()
{
@ -46,11 +55,6 @@ GetPublicAddress::~GetPublicAddress()
{
}
void GetPublicAddress::notifyEvent(Event* event)
{
}
void GetPublicAddress::setup()
{
m_state = NOTHING_DONE;
@ -97,16 +101,49 @@ void GetPublicAddress::asynchronousUpdate()
bytes[19] = (uint8_t)(m_stun_tansaction_id[2]);
bytes[20] = '\0';
Log::verbose("GetPublicAddress", "Querrying STUN server 132.177.123.6");
unsigned int dst = (132<<24)+(177<<16)+(123<<8)+6;
NetworkManager::getInstance()->setManualSocketsMode(true);
NetworkManager::getInstance()->getHost()->sendRawPacket(bytes, 20, TransportAddress(dst, 3478));
m_state = TEST_SENT;
// time to pick a random stun server
std::vector<char*> stun_servers = UserConfigParams::m_stun_servers;
RandomGenerator random_gen;
int rand_result = random_gen.get(stun_servers.size());
Log::verbose("GetPublicAddress", "Using STUN server %s", stun_servers[rand_result]);
// resolve the name into an IP address
struct addrinfo hints, *res, *p;
int status;
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC; // AF_INET or AF_INET6 to force version
hints.ai_socktype = SOCK_STREAM;
if ((status = getaddrinfo(stun_servers[rand_result], NULL, &hints, &res)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(status));
return;
}
for(p = res;p != NULL; p = p->ai_next)
{
struct sockaddr_in* current_interface = (struct sockaddr_in*)(p->ai_addr);
m_stun_server_ip = ntohl(current_interface->sin_addr.s_addr);
m_transaction_host = new STKHost();
m_transaction_host->setupClient(1,1,0,0);
m_transaction_host->sendRawPacket(bytes, 20, TransportAddress(m_stun_server_ip, 3478));
m_state = TEST_SENT;
freeaddrinfo(res); // free the linked list
return;
}
freeaddrinfo(res); // free the linked list
}
if (m_state == TEST_SENT)
{
unsigned int dst = (132<<24)+(177<<16)+(123<<8)+6;
uint8_t* data = NetworkManager::getInstance()->getHost()->receiveRawPacket(TransportAddress(dst, 3478));
uint8_t* data = m_transaction_host->receiveRawPacket(TransportAddress(m_stun_server_ip, 3478), 2000);
if (!data)
{
m_state = NOTHING_DONE; // will send the test again to an other server
return;
}
assert(data);
// check that the stun response is a response, contains the magic cookie and the transaction ID
@ -184,7 +221,6 @@ void GetPublicAddress::asynchronousUpdate()
{
Log::debug("GetPublicAddress", "The public address has been found : %i.%i.%i.%i:%i", address>>24&0xff, address>>16&0xff, address>>8&0xff, address&0xff, port);
m_state = ADDRESS_KNOWN;
NetworkManager::getInstance()->setManualSocketsMode(false);
TransportAddress* addr = static_cast<TransportAddress*>(m_callback_object);
addr->ip = address;
addr->port = port;

View File

@ -27,8 +27,8 @@ class GetPublicAddress : public Protocol
GetPublicAddress(CallbackObject* callback_object);
virtual ~GetPublicAddress();
virtual void notifyEvent(Event* event);
virtual bool notifyEvent(Event* event) { return true; }
virtual bool notifyEventAsynchronous(Event* event) { return true; }
virtual void setup();
virtual void update() {}
virtual void asynchronousUpdate();
@ -44,6 +44,8 @@ class GetPublicAddress : public Protocol
STATE m_state;
uint32_t m_stun_tansaction_id[3];
static const uint32_t m_stun_magic_cookie = 0x2112A442;
uint32_t m_stun_server_ip;
STKHost* m_transaction_host;
};
#endif // GET_PUBLIC_ADDRESS_HPP

View File

@ -32,10 +32,6 @@ HidePublicAddress::~HidePublicAddress()
{
}
void HidePublicAddress::notifyEvent(Event* event)
{
}
void HidePublicAddress::setup()
{
m_state = NONE;

View File

@ -29,7 +29,8 @@ class HidePublicAddress : public Protocol
HidePublicAddress();
virtual ~HidePublicAddress();
virtual void notifyEvent(Event* event);
virtual bool notifyEvent(Event* event) { return true; }
virtual bool notifyEventAsynchronous(Event* event) { return true; }
virtual void setup();
virtual void update() {}
virtual void asynchronousUpdate();

View File

@ -28,15 +28,15 @@ KartUpdateProtocol::~KartUpdateProtocol()
{
}
void KartUpdateProtocol::notifyEvent(Event* event)
bool KartUpdateProtocol::notifyEventAsynchronous(Event* event)
{
if (event->type != EVENT_TYPE_MESSAGE)
return;
NetworkString ns = event->data;
return true;
NetworkString ns = event->data();
if (ns.size() < 36)
{
Log::info("KartUpdateProtocol", "Message too short.");
return;
return true;
}
ns.removeFront(4);
while(ns.size() >= 16)
@ -59,6 +59,7 @@ void KartUpdateProtocol::notifyEvent(Event* event)
pthread_mutex_unlock(&m_positions_updates_mutex);
ns.removeFront(32);
}
return true;
}
void KartUpdateProtocol::setup()
@ -67,6 +68,8 @@ void KartUpdateProtocol::setup()
void KartUpdateProtocol::update()
{
if (!World::getWorld())
return;
static double time = 0;
double current_time = StkTime::getRealTime();
if (current_time > time + 0.1) // 10 updates per second

View File

@ -14,7 +14,7 @@ class KartUpdateProtocol : public Protocol
KartUpdateProtocol();
virtual ~KartUpdateProtocol();
virtual void notifyEvent(Event* event);
virtual bool notifyEventAsynchronous(Event* event);
virtual void setup();
virtual void update();
virtual void asynchronousUpdate() {};

View File

@ -35,11 +35,10 @@ class LobbyRoomProtocol : public Protocol
public:
LobbyRoomProtocol(CallbackObject* callback_object);
virtual ~LobbyRoomProtocol();
virtual void notifyEvent(Event* event) = 0;
virtual void setup() = 0;
virtual void update() = 0;
protected:
GameSetup* m_setup; //!< The game setup.
};

View File

@ -31,10 +31,6 @@ PingProtocol::~PingProtocol()
{
}
void PingProtocol::notifyEvent(Event* event)
{
}
void PingProtocol::setup()
{
m_last_ping_time = 0;

View File

@ -10,7 +10,8 @@ class PingProtocol : public Protocol
PingProtocol(const TransportAddress& ping_dst, double delay_between_pings);
virtual ~PingProtocol();
virtual void notifyEvent(Event* event);
virtual bool notifyEvent(Event* event) { return true; }
virtual bool notifyEventAsynchronous(Event* event) { return true; }
virtual void setup();
virtual void update() {}
virtual void asynchronousUpdate();

View File

@ -33,10 +33,6 @@ QuickJoinProtocol::~QuickJoinProtocol()
{
}
void QuickJoinProtocol::notifyEvent(Event* event)
{
}
void QuickJoinProtocol::setup()
{
m_state = NONE;

View File

@ -10,7 +10,8 @@ class QuickJoinProtocol : public Protocol
QuickJoinProtocol(CallbackObject* callback_object, uint32_t* server_id);
virtual ~QuickJoinProtocol();
virtual void notifyEvent(Event* event);
virtual bool notifyEvent(Event* event) { return true; }
virtual bool notifyEventAsynchronous(Event* event) { return true; }
virtual void setup();
virtual void update() {}
virtual void asynchronousUpdate();

View File

@ -32,10 +32,6 @@ RequestConnection::~RequestConnection()
{
}
void RequestConnection::notifyEvent(Event* event)
{
}
void RequestConnection::setup()
{
m_state = NONE;

View File

@ -10,7 +10,8 @@ class RequestConnection : public Protocol
RequestConnection(uint32_t server_id);
virtual ~RequestConnection();
virtual void notifyEvent(Event* event);
virtual bool notifyEvent(Event* event) { return true; }
virtual bool notifyEventAsynchronous(Event* event) { return true; }
virtual void setup();
virtual void update() {}
virtual void asynchronousUpdate();

View File

@ -9,18 +9,29 @@ class ServerLobbyRoomProtocol : public LobbyRoomProtocol
ServerLobbyRoomProtocol();
virtual ~ServerLobbyRoomProtocol();
virtual void notifyEvent(Event* event);
virtual bool notifyEventAsynchronous(Event* event);
virtual void setup();
virtual void update();
virtual void asynchronousUpdate() {};
void startGame();
void startSelection();
void checkIncomingConnectionRequests();
void checkRaceFinished();
protected:
// connection management
void kartDisconnected(Event* event);
void connectionRequested(Event* event);
// kart selection
void kartSelectionRequested(Event* event);
// race votes
void playerMajorVote(Event* event);
void playerRaceCountVote(Event* event);
void playerMinorVote(Event* event);
void playerTrackVote(Event* event);
void playerReversedVote(Event* event);
void playerLapsVote(Event* event);
uint8_t m_next_id; //!< Next id to assign to a peer.
std::vector<TransportAddress> m_peers;
@ -28,6 +39,7 @@ class ServerLobbyRoomProtocol : public LobbyRoomProtocol
uint32_t m_current_protocol_id;
TransportAddress m_public_address;
bool m_selection_enabled;
bool m_in_race;
enum STATE
{

View File

@ -32,10 +32,6 @@ ShowPublicAddress::~ShowPublicAddress()
{
}
void ShowPublicAddress::notifyEvent(Event* event)
{
}
void ShowPublicAddress::setup()
{
m_state = NONE;
@ -52,7 +48,9 @@ void ShowPublicAddress::asynchronousUpdate()
m_request->setParameter("token",Online::CurrentUser::get()->getToken());
m_request->setParameter("address",addr.ip);
m_request->setParameter("port",addr.port);
m_request->setParameter("private_port",NetworkManager::getInstance()->getHost()->getPort());
m_request->setParameter("action","set");
Log::info("ShowPublicAddress", "Showing addr %u and port %d", addr.ip, addr.port);
Online::HTTPManager::get()->addRequest(m_request);
m_state = REQUEST_PENDING;

View File

@ -29,7 +29,8 @@ class ShowPublicAddress : public Protocol
ShowPublicAddress();
virtual ~ShowPublicAddress();
virtual void notifyEvent(Event* event);
virtual bool notifyEvent(Event* event) { return true; }
virtual bool notifyEventAsynchronous(Event* event) { return true; }
virtual void setup();
virtual void update() {}
virtual void asynchronousUpdate();

View File

@ -1,20 +1,21 @@
#include "network/protocols/start_game_protocol.hpp"
#include "input/device_manager.hpp"
#include "input/input_manager.hpp"
#include "challenges/unlock_manager.hpp"
#include "modes/world.hpp"
#include "network/network_manager.hpp"
#include "network/protocol_manager.hpp"
#include "network/game_setup.hpp"
#include "network/network_world.hpp"
#include "network/protocols/synchronization_protocol.hpp"
#include "online/current_user.hpp"
#include "race/race_manager.hpp"
#include "utils/log.hpp"
#include "utils/time.hpp"
#include "input/device_manager.hpp"
#include "input/input_manager.hpp"
#include "challenges/unlock_manager.hpp"
#include "states_screens/state_manager.hpp"
#include "states_screens/kart_selection.hpp"
#include "online/current_user.hpp"
#include "states_screens/network_kart_selection.hpp"
#include "utils/log.hpp"
#include "utils/time.hpp"
StartGameProtocol::StartGameProtocol(GameSetup* game_setup) :
Protocol(NULL, PROTOCOL_START_GAME)
@ -32,20 +33,21 @@ StartGameProtocol::~StartGameProtocol()
{
}
void StartGameProtocol::notifyEvent(Event* event)
bool StartGameProtocol::notifyEventAsynchronous(Event* event)
{
if (event->data.size() < 5)
NetworkString data = event->data();
if (data.size() < 5)
{
Log::error("StartGameProtocol", "Too short message.");
return;
return true;
}
uint32_t token = event->data.gui32();
uint8_t ready = event->data.gui8(4);
uint32_t token = data.gui32();
uint8_t ready = data.gui8(4);
STKPeer* peer = (*(event->peer));
if (peer->getClientServerToken() != token)
{
Log::error("StartGameProtocol", "Bad token received.");
return;
return true;
}
if (m_listener->isServer() && ready) // on server, player is ready
{
@ -61,17 +63,17 @@ void StartGameProtocol::notifyEvent(Event* event)
protocol->startCountdown(5000); // 5 seconds countdown
Log::info("StartGameProtocol", "All players ready, starting countdown.");
m_ready = true;
return;
return true;
}
else
Log::error("StartGameProtocol", "The Synchronization protocol hasn't been started.");
}
}
else
else // on the client, we shouldn't even receive messages.
{
Log::error("StartGameProtocol", "Received a message with bad format.");
}
// on the client, we shouldn't even receive messages.
return true;
}
void StartGameProtocol::setup()
@ -93,7 +95,6 @@ void StartGameProtocol::update()
m_listener->requestStart(new SynchronizationProtocol());
Log::info("StartGameProtocol", "SynchronizationProtocol started.");
// race startup sequence
NetworkWorld::getInstance<NetworkWorld>()->start(); // builds it and starts
race_manager->setNumKarts(m_game_setup->getPlayerCount());
race_manager->setNumPlayers(m_game_setup->getPlayerCount());
@ -115,7 +116,11 @@ void StartGameProtocol::update()
PlayerProfile* profileToUse = unlock_manager->getCurrentPlayer();
assert(profileToUse);
InputDevice* device = input_manager->getDeviceList()->getLatestUsedDevice();
int new_player_id = StateManager::get()->createActivePlayer( profileToUse, device , players[i]->user_profile);
int new_player_id = 0;
if (StateManager::get()->getActivePlayers().size() >= 0) // more than one player, we're the first
new_player_id = 0;
else
new_player_id = StateManager::get()->createActivePlayer( profileToUse, device , players[i]->user_profile);
device->setPlayer(StateManager::get()->getActivePlayer(new_player_id));
input_manager->getDeviceList()->setSinglePlayer(StateManager::get()->getActivePlayer(new_player_id));
@ -162,6 +167,7 @@ void StartGameProtocol::update()
// now the synchronization protocol exists.
Log::info("StartGameProtocol", "Starting the race loading.");
race_manager->startSingleRace("jungle", 1, false);
World::getWorld()->setNetworkWorld(true);
m_state = LOADING;
}
}
@ -174,6 +180,8 @@ void StartGameProtocol::update()
}
else if (m_state == READY)
{
// set karts into the network game setup
NetworkManager::getInstance()->getGameSetup()->bindKartsToProfiles();
m_state = EXITING;
m_listener->requestTerminate(this);
}

View File

@ -24,7 +24,7 @@ class StartGameProtocol : public Protocol
StartGameProtocol(GameSetup* game_setup);
virtual ~StartGameProtocol();
virtual void notifyEvent(Event* event);
virtual bool notifyEventAsynchronous(Event* event);
virtual void setup();
virtual void update();
virtual void asynchronousUpdate() {}

View File

@ -31,10 +31,6 @@ StartServer::~StartServer()
{
}
void StartServer::notifyEvent(Event* event)
{
}
void StartServer::setup()
{
m_state = NONE;
@ -51,8 +47,10 @@ void StartServer::asynchronousUpdate()
m_request->setParameter("token",Online::CurrentUser::get()->getToken());
m_request->setParameter("address",addr.ip);
m_request->setParameter("port",addr.port);
m_request->setParameter("private_port",NetworkManager::getInstance()->getHost()->getPort());
m_request->setParameter("max_players",UserConfigParams::m_server_max_players);
m_request->setParameter("action","start-server");
Log::info("ShowPublicAddress", "Showing addr %u and port %d", addr.ip, addr.port);
Online::HTTPManager::get()->addRequest(m_request);
m_state = REQUEST_PENDING;

View File

@ -14,7 +14,8 @@ class StartServer : public Protocol
StartServer();
virtual ~StartServer();
virtual void notifyEvent(Event* event);
virtual bool notifyEvent(Event* event) { return true; }
virtual bool notifyEventAsynchronous(Event* event) { return true; }
virtual void setup();
virtual void update() {}
virtual void asynchronousUpdate();

View File

@ -31,8 +31,9 @@ StopServer::~StopServer()
{
}
void StopServer::notifyEvent(Event* event)
bool StopServer::notifyEventAsynchronous(Event* event)
{
return true;
}
void StopServer::setup()
@ -52,6 +53,7 @@ void StopServer::asynchronousUpdate()
m_request->setParameter("address",addr.ip);
m_request->setParameter("port",addr.port);
m_request->setParameter("action","stop-server");
Log::info("StopServer", "address %u, port %d", addr.ip, addr.port);
Online::HTTPManager::get()->addRequest(m_request);
m_state = REQUEST_PENDING;

View File

@ -13,7 +13,7 @@ class StopServer : public Protocol
StopServer();
virtual ~StopServer();
virtual void notifyEvent(Event* event);
virtual bool notifyEventAsynchronous(Event* event);
virtual void setup();
virtual void update() {}
virtual void asynchronousUpdate();

View File

@ -3,6 +3,7 @@
#include "network/network_manager.hpp"
#include "network/protocols/kart_update_protocol.hpp"
#include "network/protocols/controller_events_protocol.hpp"
#include "network/protocols/game_events_protocol.hpp"
#include "utils/time.hpp"
//-----------------------------------------------------------------------------
@ -30,19 +31,20 @@ SynchronizationProtocol::~SynchronizationProtocol()
//-----------------------------------------------------------------------------
void SynchronizationProtocol::notifyEvent(Event* event)
bool SynchronizationProtocol::notifyEventAsynchronous(Event* event)
{
if (event->type != EVENT_TYPE_MESSAGE)
return;
if (event->data.size() < 10)
return true;
NetworkString data = event->data();
if (data.size() < 10)
{
Log::warn("SynchronizationProtocol", "Received a message too short.");
return;
return true;
}
uint8_t talk_id = event->data.gui8();
uint32_t token = event->data.gui32(1);
uint32_t request = event->data.gui8(5);
uint32_t sequence = event->data.gui32(6);
uint8_t talk_id = data.gui8();
uint32_t token = data.gui32(1);
uint32_t request = data.gui8(5);
uint32_t sequence = data.gui32(6);
std::vector<STKPeer*> peers = NetworkManager::getInstance()->getPeers();
@ -51,7 +53,7 @@ void SynchronizationProtocol::notifyEvent(Event* event)
if (talk_id > peers.size())
{
Log::warn("SynchronizationProtocol", "The ID isn't known.");
return;
return true;
}
}
@ -66,18 +68,18 @@ void SynchronizationProtocol::notifyEvent(Event* event)
if (peers[peer_id]->getClientServerToken() != token)
{
Log::warn("SynchronizationProtocol", "Bad token from peer %d", talk_id);
return;
return true;
}
if (request)
{
NetworkString response;
response.ai8(event->data.gui8(talk_id)).ai32(token).ai8(0).ai32(sequence);
response.ai8(data.gui8(talk_id)).ai32(token).ai8(0).ai32(sequence);
m_listener->sendMessage(this, peers[peer_id], response, false);
Log::verbose("SynchronizationProtocol", "Answering sequence %u", sequence);
if (event->data.size() == 14 && !m_listener->isServer()) // countdown time in the message
if (data.size() == 14 && !m_listener->isServer()) // countdown time in the message
{
uint32_t time_to_start = event->data.gui32(10);
uint32_t time_to_start = data.gui32(10);
Log::debug("SynchronizationProtocol", "Request to start game in %d.", time_to_start);
if (!m_countdown_activated)
startCountdown(time_to_start);
@ -92,7 +94,7 @@ void SynchronizationProtocol::notifyEvent(Event* event)
if (sequence >= m_pings[peer_id].size())
{
Log::warn("SynchronizationProtocol", "The sequence# %u isn't known.", sequence);
return;
return true;
}
double current_time = StkTime::getRealTime();
m_total_diff[peer_id] += current_time - m_pings[peer_id][sequence];
@ -103,6 +105,7 @@ void SynchronizationProtocol::notifyEvent(Event* event)
Log::debug("SynchronizationProtocol", "Ping is %u", m_average_ping[peer_id]);
}
return true;
}
//-----------------------------------------------------------------------------
@ -131,6 +134,7 @@ void SynchronizationProtocol::asynchronousUpdate()
Log::info("SynchronizationProtocol", "Countdown finished. Starting now.");
m_listener->requestStart(new KartUpdateProtocol());
m_listener->requestStart(new ControllerEventsProtocol());
m_listener->requestStart(new GameEventsProtocol());
m_listener->requestTerminate(this);
return;
}

View File

@ -11,7 +11,7 @@ class SynchronizationProtocol : public Protocol
SynchronizationProtocol();
virtual ~SynchronizationProtocol();
virtual void notifyEvent(Event* event);
virtual bool notifyEventAsynchronous(Event* event);
virtual void setup();
virtual void update() {}
virtual void asynchronousUpdate();

369
src/network/race_config.cpp Normal file
View File

@ -0,0 +1,369 @@
#include "network/race_config.hpp"
#include "race/race_manager.hpp"
#include "utils/log.hpp"
/** \brief Gets the element with the highest count in a std::map<S,int>.
* \param histogram : A pointer to the histogram.
* \return The key of type S that has the highest second value.
*/
template<typename S>
S getHighestInHistogram(std::map<S,int>* histogram)
{
S best_item;
uint8_t highest_count;
for (typename std::map<S, int>::iterator it = histogram->begin();
it != histogram->end(); it++)
{
if (it->second > highest_count)
{
highest_count = it->second;
best_item = it->first;
}
}
return best_item;
}
//-----------------------------------------------------------------------------
//--------------------------------- TrackVote --------------------------------
//-----------------------------------------------------------------------------
TrackVote::TrackVote()
{
has_voted_laps = false;
has_voted_track = false;
has_voted_reversed = false;
}
//-----------------------------------------------------------------------------
void TrackVote::voteTrack(std::string track)
{
track_info.track = track;
has_voted_track = true;
}
//-----------------------------------------------------------------------------
void TrackVote::voteReversed(bool reversed)
{
track_info.reversed = reversed;
has_voted_reversed = true;
}
//-----------------------------------------------------------------------------
void TrackVote::voteLaps(uint8_t laps)
{
track_info.laps = laps;
has_voted_laps = true;
}
//-----------------------------------------------------------------------------
//--------------------------------- RaceVote ---------------------------------
//-----------------------------------------------------------------------------
RaceVote::RaceVote()
{
m_has_voted_major = false;
m_has_voted_minor = false;
m_has_voted_races_count = false;
m_major_mode = 0;
m_minor_mode = 0;
m_races_count = 0;
}
//-----------------------------------------------------------------------------
void RaceVote::voteMajor(uint8_t major)
{
m_has_voted_major = true;
m_major_mode = major;
}
//-----------------------------------------------------------------------------
void RaceVote::voteRaceCount(uint8_t count)
{
m_has_voted_races_count = true;
m_races_count = count;
}
//-----------------------------------------------------------------------------
void RaceVote::voteMinor(uint8_t minor)
{
m_has_voted_minor = true;
m_minor_mode = minor;
}
//-----------------------------------------------------------------------------
void RaceVote::voteTrack(std::string track, uint8_t track_number)
{
m_tracks_vote[track_number].voteTrack(track);
}
//-----------------------------------------------------------------------------
void RaceVote::voteReversed(bool reversed, uint8_t track_number)
{
m_tracks_vote[track_number].voteReversed(reversed);
}
//-----------------------------------------------------------------------------
void RaceVote::voteLaps(uint8_t laps, uint8_t track_number)
{
m_tracks_vote[track_number].voteLaps(laps);
}
//-----------------------------------------------------------------------------
bool RaceVote::hasVotedMajor() const
{
return m_has_voted_major;
}
//-----------------------------------------------------------------------------
bool RaceVote::hasVotedRacesCount() const
{
return m_has_voted_races_count;
}
//-----------------------------------------------------------------------------
bool RaceVote::hasVotedMinor() const
{
return m_has_voted_minor;
}
//-----------------------------------------------------------------------------
bool RaceVote::hasVotedTrack(uint8_t track_number) const
{
return m_tracks_vote[track_number].has_voted_track;
}
//-----------------------------------------------------------------------------
bool RaceVote::hasVotedReversed(uint8_t track_number) const
{
return m_tracks_vote[track_number].has_voted_reversed;
}
//-----------------------------------------------------------------------------
bool RaceVote::hasVotedLaps(uint8_t track_number) const
{
return m_tracks_vote[track_number].has_voted_laps;
}
//-----------------------------------------------------------------------------
uint8_t RaceVote::getMajorVote() const
{
return m_major_mode;
}
//-----------------------------------------------------------------------------
uint8_t RaceVote::getRacesCountVote() const
{
return m_races_count;
}
//-----------------------------------------------------------------------------
uint8_t RaceVote::getMinorVote() const
{
return m_minor_mode;
}
//-----------------------------------------------------------------------------
std::string RaceVote::getTrackVote(uint8_t track_number) const
{
return m_tracks_vote[track_number].track_info.track;
}
//-----------------------------------------------------------------------------
bool RaceVote::getReversedVote(uint8_t track_number) const
{
return m_tracks_vote[track_number].track_info.reversed;
}
//-----------------------------------------------------------------------------
uint8_t RaceVote::getLapsVote(uint8_t track_number) const
{
return m_tracks_vote[track_number].track_info.laps;
}
//-----------------------------------------------------------------------------
//--------------------------------- RaceConfig -------------------------------
//-----------------------------------------------------------------------------
RaceConfig::RaceConfig()
{
m_max_players = 0;
}
//-----------------------------------------------------------------------------
void RaceConfig::setPlayerCount(uint8_t count)
{
m_max_players = count;
m_votes.resize(m_max_players);
}
//-----------------------------------------------------------------------------
void RaceConfig::setPlayerMajorVote(uint8_t player_id, uint8_t major)
{
Log::info("RaceConfig", "Player %d voted for major %d", player_id, major);
m_votes[player_id].voteMajor(major);
}
//-----------------------------------------------------------------------------
void RaceConfig::setPlayerRaceCountVote(uint8_t player_id, uint8_t count)
{
Log::info("RaceConfig", "Player %d voted for %d races in GP", player_id, count);
m_votes[player_id].voteRaceCount(count);
}
//-----------------------------------------------------------------------------
void RaceConfig::setPlayerMinorVote(uint8_t player_id, uint8_t minor)
{
Log::info("RaceConfig", "Player %d voted for minor %d", player_id, minor);
m_votes[player_id].voteMinor(minor);
}
//-----------------------------------------------------------------------------
void RaceConfig::setPlayerTrackVote(uint8_t player_id, std::string track, uint8_t track_nb)
{
Log::info("RaceConfig", "Player %d voted for track %s", player_id, track.c_str());
m_votes[player_id].voteTrack(track, track_nb);
}
//-----------------------------------------------------------------------------
void RaceConfig::setPlayerReversedVote(uint8_t player_id, bool reversed, uint8_t track_nb)
{
if (reversed)
Log::info("RaceConfig", "Player %d voted map %d to be reversed", player_id, track_nb);
else
Log::info("RaceConfig", "Player %d voted map %d NOT to be reversed", player_id, track_nb);
m_votes[player_id].voteReversed(reversed, track_nb);
}
//-----------------------------------------------------------------------------
void RaceConfig::setPlayerLapsVote(uint8_t player_id, uint8_t lap_count, uint8_t track_nb)
{
Log::info("RaceConfig", "Player %d voted map %d to have %d laps", player_id, track_nb, lap_count);
m_votes[player_id].voteLaps(lap_count, track_nb);
}
//-----------------------------------------------------------------------------
void RaceConfig::computeRaceMode()
{
// calculate the race type and number of tracks (in GP mode).
std::map<int,int> major_histogram;
std::map<int,int> races_count_histogram;
std::map<int,int> minor_histogram;
for (unsigned int i = 0; i < m_max_players; i++)
{
// increase the count of votes
if (m_votes[i].hasVotedMajor())
{
try
{
major_histogram.at(m_votes[i].getMajorVote()) ++;
}
catch (const std::out_of_range& oor) // doesn't exist in the map
{
major_histogram[m_votes[i].getMajorVote()] = 1;
}
}
else if (m_votes[i].hasVotedRacesCount())
{
try
{
races_count_histogram.at(m_votes[i].getRacesCountVote()) ++;
}
catch (const std::out_of_range& oor) // doesn't exist in the map
{
races_count_histogram[m_votes[i].getRacesCountVote()] = 1;
}
}
else if (m_votes[i].hasVotedMinor())
{
try
{
minor_histogram.at(m_votes[i].getMinorVote()) ++;
}
catch (const std::out_of_range& oor) // doesn't exist in the map
{
minor_histogram[m_votes[i].getMinorVote()] = 1;
}
}
}
// now we know :
m_major_mode = ((major_histogram.size() > 0) ? getHighestInHistogram<int>(&major_histogram) : 1);
m_races_count = ((minor_histogram.size() > 0) ? getHighestInHistogram<int>(&races_count_histogram) : 1);
m_minor_mode = ((minor_histogram.size() > 0) ? getHighestInHistogram<int>(&minor_histogram) : 0);
if (m_major_mode == RaceManager::MAJOR_MODE_GRAND_PRIX)
m_tracks.resize(m_races_count);
else
{
m_tracks.resize(1);
m_races_count = 1;
}
Log::info("RaceConfig", "Major mode will be %d with %d races. Minor is %d", m_major_mode, m_races_count, m_minor_mode);
}
void RaceConfig::computeNextTrack()
{
for (unsigned int j = 0; j < m_races_count; j++)
{
// first create histograms of the votes
std::map<std::string,int> tracks_histogram;
std::map<bool,int> reversed_histogram;
std::map<int,int> laps_histogram;
for (unsigned int i = 0; i < m_max_players; i++)
{
// increase the count of votes
if (m_votes[i].hasVotedTrack())
{
try // maps
{
tracks_histogram.at(m_votes[i].getTrackVote()) ++;
}
catch (const std::out_of_range& oor) // doesn't exist in the map
{
tracks_histogram[m_votes[i].getTrackVote()] = 1;
}
}
else if (m_votes[i].hasVotedReversed())
{
try // reversed
{
reversed_histogram.at(m_votes[i].getReversedVote()) ++;
}
catch (const std::out_of_range& oor) // doesn't exist in the map
{
reversed_histogram[m_votes[i].getReversedVote()] = 1;
}
}
else if (m_votes[i].hasVotedLaps())
{
try // laps
{
laps_histogram.at(m_votes[i].getLapsVote()) ++;
}
catch (const std::out_of_range& oor) // doesn't exist in the mapt
{
laps_histogram[m_votes[i].getLapsVote()] = 1;
}
}
}
// now find the highest votes
m_tracks[j].track = getHighestInHistogram<std::string>(&tracks_histogram);
m_tracks[j].reversed = getHighestInHistogram<bool>(&reversed_histogram);
m_tracks[j].laps = getHighestInHistogram<int>(&laps_histogram);
if (m_tracks[j].reversed)
Log::info("RaceConfig", "Race %d will be on %s with %d laps and reversed", j, m_tracks[j].track.c_str(), m_tracks[j].laps);
else
Log::info("RaceConfig", "Race %d will be on %s with %d laps", j, m_tracks[j].track.c_str(), m_tracks[j].laps);
}
}
//-----------------------------------------------------------------------------
const TrackInfo* RaceConfig::getNextTrackInfo() const
{
return &m_tracks[0];
}
//-----------------------------------------------------------------------------

View File

@ -0,0 +1,98 @@
#ifndef RACE_CONFIG_HPP
#define RACE_CONFIG_HPP
#include <string>
#include <vector>
#include "utils/types.hpp"
class TrackInfo
{
public:
TrackInfo() { laps = 0; reversed = false; }
std::string track;
bool reversed;
uint8_t laps;
};
class TrackVote
{
public:
TrackVote();
void voteTrack(std::string track);
void voteReversed(bool reversed);
void voteLaps(uint8_t laps);
TrackInfo track_info;
bool has_voted_track;
bool has_voted_reversed;
bool has_voted_laps;
};
class RaceVote
{
public:
RaceVote();
void voteMajor(uint8_t major);
void voteRaceCount(uint8_t count);
void voteMinor(uint8_t minor);
void voteTrack(std::string track, uint8_t track_number = 0);
void voteReversed(bool reversed, uint8_t track_number = 0);
void voteLaps(uint8_t laps, uint8_t track_number = 0);
bool hasVotedMajor() const;
bool hasVotedRacesCount() const;
bool hasVotedMinor() const;
bool hasVotedTrack(uint8_t track_number = 0) const;
bool hasVotedReversed(uint8_t track_number = 0) const;
bool hasVotedLaps(uint8_t track_number = 0) const;
uint8_t getMajorVote() const;
uint8_t getRacesCountVote() const;
uint8_t getMinorVote() const;
std::string getTrackVote(uint8_t track_number = 0) const;
bool getReversedVote(uint8_t track_number = 0) const;
uint8_t getLapsVote(uint8_t track_number = 0) const;
private:
uint8_t m_major_mode;
uint8_t m_minor_mode;
uint8_t m_races_count; //!< Stores the number of races that will be in a GP
bool m_has_voted_major;
bool m_has_voted_minor;
bool m_has_voted_races_count;
std::vector<TrackVote> m_tracks_vote;
};
class RaceConfig
{
public:
RaceConfig();
void setPlayerCount(uint8_t count);
void setPlayerMajorVote(uint8_t player_id, uint8_t major);
void setPlayerRaceCountVote(uint8_t player_id, uint8_t count);
void setPlayerMinorVote(uint8_t player_id, uint8_t minor);
void setPlayerTrackVote(uint8_t player_id, std::string track, uint8_t track_nb = 0);
void setPlayerReversedVote(uint8_t player_id, bool reversed, uint8_t track_nb = 0);
void setPlayerLapsVote(uint8_t player_id, uint8_t lap_count, uint8_t track_nb = 0);
void computeRaceMode();
void computeNextTrack();
const TrackInfo* getNextTrackInfo() const;
bool getReverse() const;
bool getLapCount() const;
protected:
std::vector<TrackInfo> m_tracks;
int m_minor_mode;
int m_major_mode;
int m_races_count;
std::vector<RaceVote> m_votes;
uint8_t m_max_players;
};
#endif // RACE_CONFIG_HPP

View File

@ -1,6 +1,6 @@
//
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2008 Joerg Henrichs
// Copyright (C) 2013 SuperTuxKart-Team
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
@ -16,6 +16,9 @@
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
/*! \file remote_kart_info.hpp
*/
#ifndef HEADER_REMOTE_KART_INFO_HPP
#define HEADER_REMOTE_KART_INFO_HPP

View File

@ -62,15 +62,25 @@ void* waitInput2(void* data)
assert(protocol);
protocol->startSelection();
}
else if (str == "compute_race")
{
GameSetup* setup = NetworkManager::getInstance()->getGameSetup();
setup->getRaceConfig()->computeRaceMode();
}
else if (str == "compute_track")
{
GameSetup* setup = NetworkManager::getInstance()->getGameSetup();
setup->getRaceConfig()->computeNextTrack();
}
}
uint32_t id = ProtocolManager::getInstance()->requestStart(new StopServer());
while(ProtocolManager::getInstance()->getProtocolState(id) != PROTOCOL_STATE_TERMINATED)
{
StkTime::sleep(1);
}
main_loop->abort();
exit(0);
return NULL;
}

View File

@ -16,6 +16,9 @@
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
/*! \file server_network_manager.hpp
*/
#ifndef SERVER_NETWORK_MANAGER_HPP
#define SERVER_NETWORK_MANAGER_HPP
@ -33,6 +36,9 @@ class ServerNetworkManager : public NetworkManager
virtual void run();
void setMaxPlayers(uint8_t count) { m_max_players = count; }
uint8_t getMaxPlayers() {return m_max_players;}
void kickAllPlayers();
virtual void sendPacket(const NetworkString& data, bool reliable = true);
@ -44,6 +50,7 @@ class ServerNetworkManager : public NetworkManager
virtual ~ServerNetworkManager();
pthread_t* m_thread_keyboard;
uint8_t m_max_players;
};

View File

@ -16,22 +16,39 @@
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
/*! \file singleton.hpp
*/
#ifndef SINGLETON_HPP
#define SINGLETON_HPP
#include "utils/log.hpp"
/*! \class ProtocolManager
* \brief Manages the protocols at runtime.
* This has been designed to allow multi-inheritance. This is advised to
* re-declare getInstance, but whithout templates parameters in the inheriting
* classes.
*/
template <typename T>
class Singleton
{
protected:
/*! \brief Constructor */
Singleton () { m_singleton = NULL; }
/*! \brief Destructor */
virtual ~Singleton ()
{
Log::info("Singleton", "Destroyed singleton.");
}
public:
/*! \brief Used to get the instance, after a dynamic cast.
* This is important when making a double-inheritance of this class.
* For example, if A is a singleton inherited by B, you can call
* B::getInstance<A>() to have the instance returned as a A*.
* If the cast fails, a log message will notify it.
*/
template<typename S>
static S *getInstance ()
{
@ -43,11 +60,13 @@ class Singleton
Log::debug("Singleton", "THE SINGLETON HAS NOT BEEN REALOCATED, IT IS NOT OF THE REQUESTED TYPE.");
return result;
}
/*! \brief Used to get the instance. */
static T *getInstance()
{
return (dynamic_cast<T*> (m_singleton));
return m_singleton;
}
/*! \brief Used to kill the singleton, if needed. */
static void kill ()
{
if (m_singleton)

View File

@ -18,9 +18,10 @@
#include "network/stk_host.hpp"
#include "graphics/irr_driver.hpp" // get access to irrlicht sleep function
#include "config/user_config.hpp"
#include "network/network_manager.hpp"
#include "utils/log.hpp"
#include "utils/time.hpp"
#include <string.h>
#ifdef WIN32
@ -28,25 +29,53 @@
# define inet_ntop InetNtop
#else
# include <arpa/inet.h>
# include <errno.h>
#endif
#include <pthread.h>
#include <signal.h>
FILE* STKHost::m_log_file = NULL;
pthread_mutex_t STKHost::m_log_mutex;
void STKHost::logPacket(const NetworkString ns, bool incoming)
{
if (m_log_file == NULL)
return;
pthread_mutex_lock(&m_log_mutex);
if (incoming)
fprintf(m_log_file, "[%d\t] <-- ", (int)(StkTime::getRealTime()));
else
fprintf(m_log_file, "[%d\t] --> ", (int)(StkTime::getRealTime()));
for (int i = 0; i < ns.size(); i++)
{
fprintf(m_log_file, "%d.", ns[i]);
}
fprintf(m_log_file, "\n");
pthread_mutex_unlock(&m_log_mutex);
}
// ----------------------------------------------------------------------------
void* STKHost::receive_data(void* self)
{
ENetEvent event;
ENetHost* host = (((STKHost*)(self))->m_host);
while (1)
STKHost* myself = (STKHost*)(self);
ENetHost* host = myself->m_host;
while (!myself->mustStopListening())
{
while (enet_host_service(host, &event, 20) != 0) {
Event* evt = new Event(&event);
if (evt->type == EVENT_TYPE_MESSAGE)
logPacket(evt->data(), true);
if (event.type != ENET_EVENT_TYPE_NONE)
NetworkManager::getInstance()->notifyEvent(evt);
delete evt;
}
}
myself->m_listening = false;
delete myself->m_listening_thread;
myself->m_listening_thread = NULL;
Log::info("STKHost", "Listening has been stopped");
return NULL;
}
@ -56,17 +85,24 @@ STKHost::STKHost()
{
m_host = NULL;
m_listening_thread = NULL;
m_log_file = NULL;
pthread_mutex_init(&m_exit_mutex, NULL);
pthread_mutex_init(&m_log_mutex, NULL);
if (UserConfigParams::m_packets_log_filename.toString() != "")
m_log_file = fopen(UserConfigParams::m_packets_log_filename.c_str(), "w+");
if (!m_log_file)
Log::warn("STKHost", "Network packets won't be logged: no file.");
}
// ----------------------------------------------------------------------------
STKHost::~STKHost()
{
if (m_listening_thread)
stopListening();
if (m_log_file)
{
pthread_cancel(*m_listening_thread);//, SIGKILL); with kill
delete m_listening_thread;
m_listening_thread = NULL;
fclose(m_log_file);
Log::warn("STKHost", "Packet logging file has been closed.");
}
if (m_host)
{
@ -84,6 +120,13 @@ void STKHost::setupServer(uint32_t address, uint16_t port, int peer_count,
addr->host = address;
addr->port = port;
#ifdef WIN32/*
addr->host = 0;
addr->host += ((unsigned int)(192)<<0); // 192.168.0.11
addr->host += ((unsigned int)(168)<<8); // 192.168.0.11
addr->host += ((unsigned int)(11)<<24); // 192.168.0.11*/
#endif
m_host = enet_host_create(addr, peer_count, channel_limit,
max_incoming_bandwidth, max_outgoing_bandwidth);
if (m_host == NULL)
@ -114,8 +157,10 @@ void STKHost::setupClient(int peer_count, int channel_limit,
void STKHost::startListening()
{
pthread_mutex_lock(&m_exit_mutex); // will let the update function start
m_listening_thread = (pthread_t*)(malloc(sizeof(pthread_t)));
pthread_create(m_listening_thread, NULL, &STKHost::receive_data, this);
m_listening = true;
}
// ----------------------------------------------------------------------------
@ -124,8 +169,8 @@ void STKHost::stopListening()
{
if(m_listening_thread)
{
pthread_cancel(*m_listening_thread);
m_listening_thread = NULL;
pthread_mutex_unlock(&m_exit_mutex); // will stop the update function on its next update
pthread_join(*m_listening_thread, NULL); // wait the thread to end
}
}
@ -144,6 +189,7 @@ void STKHost::sendRawPacket(uint8_t* data, int length, TransportAddress dst)
sendto(m_host->socket, (char*)data, length, 0,(sockaddr*)&to, to_len);
Log::verbose("STKHost", "Raw packet sent to %i.%i.%i.%i:%u", ((dst.ip>>24)&0xff)
, ((dst.ip>>16)&0xff), ((dst.ip>>8)&0xff), ((dst.ip>>0)&0xff), dst.port);
STKHost::logPacket(NetworkString(std::string((char*)(data), length)), false);
}
// ----------------------------------------------------------------------------
@ -161,43 +207,98 @@ uint8_t* STKHost::receiveRawPacket()
{
i++;
len = recv(m_host->socket,(char*)buffer,2048, 0);
irr_driver->getDevice()->sleep(1);
StkTime::sleep(1);
}
STKHost::logPacket(NetworkString(std::string((char*)(buffer), len)), true);
return buffer;
}
// ----------------------------------------------------------------------------
uint8_t* STKHost::receiveRawPacket(TransportAddress sender)
uint8_t* STKHost::receiveRawPacket(TransportAddress* sender)
{
uint8_t* buffer; // max size needed normally (only used for stun)
buffer = (uint8_t*)(malloc(sizeof(uint8_t)*2048));
memset(buffer, 0, 2048);
socklen_t from_len;
struct sockaddr addr;
struct sockaddr_in addr;
from_len = sizeof(addr);
int len = recvfrom(m_host->socket, (char*)buffer, 2048, 0, &addr, &from_len);
int len = recvfrom(m_host->socket, (char*)buffer, 2048, 0, (struct sockaddr*)(&addr), &from_len);
int i = 0;
// wait to receive the message because enet sockets are non-blocking
while(len < 0 || (
(uint8_t)(addr.sa_data[2]) != (sender.ip>>24&0xff)
&& (uint8_t)(addr.sa_data[3]) != (sender.ip>>16&0xff)
&& (uint8_t)(addr.sa_data[4]) != (sender.ip>>8&0xff)
&& (uint8_t)(addr.sa_data[5]) != (sender.ip&0xff)))
while(len == -1) // nothing received
{
i++;
len = recvfrom(m_host->socket, (char*)buffer, 2048, 0, &addr, &from_len);
irr_driver->getDevice()->sleep(1); // wait 1 millisecond between two checks
len = recvfrom(m_host->socket, (char*)buffer, 2048, 0, (struct sockaddr*)(&addr), &from_len);
StkTime::sleep(1); // wait 1 millisecond between two checks
}
if (addr.sa_family == AF_INET)
if (len == SOCKET_ERROR)
{
Log::error("STKHost", "Problem with the socket. Please contact the dev team.");
}
// we received the data
sender->ip = ntohl((uint32_t)(addr.sin_addr.s_addr));
sender->port = ntohs(addr.sin_port);
if (addr.sin_family == AF_INET)
{
char s[20];
inet_ntop(AF_INET, &(((struct sockaddr_in *)&addr)->sin_addr), s, 20);
inet_ntop(AF_INET, &(addr.sin_addr), s, 20);
Log::info("STKHost", "IPv4 Address of the sender was %s", s);
}
STKHost::logPacket(NetworkString(std::string((char*)(buffer), len)), true);
return buffer;
}
// ----------------------------------------------------------------------------
uint8_t* STKHost::receiveRawPacket(TransportAddress sender, int max_tries)
{
uint8_t* buffer; // max size needed normally (only used for stun)
buffer = (uint8_t*)(malloc(sizeof(uint8_t)*2048));
memset(buffer, 0, 2048);
socklen_t from_len;
struct sockaddr_in addr;
from_len = sizeof(addr);
int len = recvfrom(m_host->socket, (char*)buffer, 2048, 0, (struct sockaddr*)(&addr), &from_len);
int i = 0;
// wait to receive the message because enet sockets are non-blocking
while(len < 0 || addr.sin_addr.s_addr == sender.ip)
{
i++;
if (len>=0)
{
Log::info("STKHost", "Message received but the ip address didn't match the expected one.");
}
len = recvfrom(m_host->socket, (char*)buffer, 2048, 0, (struct sockaddr*)(&addr), &from_len);
uint32_t addr1 = addr.sin_addr.s_addr;
uint32_t addr2 = sender.ip;
uint32_t addr3 = ntohl(addr1);
uint32_t addr4 = ntohl(addr2);
StkTime::sleep(1); // wait 1 millisecond between two checks
if (i >= max_tries && max_tries != -1)
{
Log::verbose("STKHost", "No answer from the server on %u.%u.%u.%u:%u", (m_host->address.host&0xff),
(m_host->address.host>>8&0xff),
(m_host->address.host>>16&0xff),
(m_host->address.host>>24&0xff),
(m_host->address.port));
return NULL;
}
}
if (addr.sin_family == AF_INET)
{
char s[20];
inet_ntop(AF_INET, &(addr.sin_addr), s, 20);
Log::info("STKHost", "IPv4 Address of the sender was %s", s);
}
STKHost::logPacket(NetworkString(std::string((char*)(buffer), len)), true);
return buffer;
}
@ -208,6 +309,7 @@ void STKHost::broadcastPacket(const NetworkString& data, bool reliable)
ENetPacket* packet = enet_packet_create(data.c_str(), data.size()+1,
(reliable ? ENET_PACKET_FLAG_RELIABLE : ENET_PACKET_FLAG_UNSEQUENCED));
enet_host_broadcast(m_host, 0, packet);
STKHost::logPacket(data, false);
}
// ----------------------------------------------------------------------------
@ -216,7 +318,7 @@ bool STKHost::peerExists(TransportAddress peer)
{
for (unsigned int i = 0; i < m_host->peerCount; i++)
{
if (m_host->peers[i].address.host == turnEndianness(peer.ip) &&
if (m_host->peers[i].address.host == ntohl(peer.ip) &&
m_host->peers[i].address.port == peer.port)
{
return true;
@ -231,7 +333,7 @@ bool STKHost::isConnectedTo(TransportAddress peer)
{
for (unsigned int i = 0; i < m_host->peerCount; i++)
{
if (m_host->peers[i].address.host == turnEndianness(peer.ip) &&
if (m_host->peers[i].address.host == ntohl(peer.ip) &&
m_host->peers[i].address.port == peer.port &&
m_host->peers[i].state == ENET_PEER_STATE_CONNECTED)
{
@ -240,3 +342,28 @@ bool STKHost::isConnectedTo(TransportAddress peer)
}
return false;
}
// ---------------------------------------------------------------------------
int STKHost::mustStopListening()
{
switch(pthread_mutex_trylock(&m_exit_mutex)) {
case 0: /* if we got the lock, unlock and return 1 (true) */
pthread_mutex_unlock(&m_exit_mutex);
return 1;
case EBUSY: /* return 0 (false) if the mutex was locked */
return 0;
}
return 1;
}
uint16_t STKHost::getPort() const
{
struct sockaddr_in sin;
socklen_t len = sizeof(sin);
if (getsockname(m_host->socket, (struct sockaddr *)&sin, &len) == -1)
Log::error("STKHost", "Error while using getsockname().");
else
return ntohs(sin.sin_port);
return 0;
}

View File

@ -112,7 +112,7 @@ void STKPeer::sendPacket(NetworkString const& data, bool reliable)
uint32_t STKPeer::getAddress() const
{
return turnEndianness(m_peer->address.host);
return ntohl(m_peer->address.host);
}
//-----------------------------------------------------------------------------

View File

@ -16,6 +16,10 @@
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
/*! \file stk_peer.hpp
* \brief Defines functions to easily manipulate 8-bit network destinated strings.
*/
#ifndef STK_PEER_HPP
#define STK_PEER_HPP
@ -24,6 +28,10 @@
#include "network/game_setup.hpp"
#include <enet/enet.h>
/*! \class STKPeer
* \brief Represents a peer.
* This class is used to interface the ENetPeer structure.
*/
class STKPeer
{
friend class Event;
@ -45,7 +53,7 @@ class STKPeer
bool exists() const;
uint32_t getAddress() const;
uint16_t getPort() const;
NetworkPlayerProfile* getPlayerProfile() { return *m_player_profile; }
NetworkPlayerProfile* getPlayerProfile() { return (m_player_profile)?(*m_player_profile):NULL; }
uint32_t getClientServerToken() const { return *m_client_server_token; }
bool isClientServerTokenSet() const { return *m_token_set; }

View File

@ -1,9 +1 @@
#include "network/types.hpp"
uint32_t turnEndianness(uint32_t val)
{
return ((val&0xff000000)>>24)
+((val&0x00ff0000)>>8)
+((val&0x0000ff00)<<8)
+((val&0x000000ff)<<24);
}

View File

@ -16,7 +16,7 @@
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
/*! \file types.hpp
/*! \file types.hpp
* \brief Declares the general types that are used by the network.
*/
#ifndef TYPES_HPP
@ -26,6 +26,10 @@
#include <string>
/*! functions to write easily addresses in logs. */
#define ADDRESS_FORMAT "%d.%d.%d.%d:%d"
#define ADDRESS_ARGS(ip,port) ((ip>>24)&0xff),((ip>>16)&0xff),((ip>>8)&0xff),((ip>>0)&0xff),port
/*! \class CallbackObject
* \brief Class that must be inherited to pass objects to protocols.
*/
@ -34,20 +38,26 @@ class CallbackObject
public:
CallbackObject() {}
~CallbackObject() {}
};
/*! \class TransportAddress
* \brief Describes a transport-layer address.
* For IP networks, a transport address is the couple ip:port.
*/
class TransportAddress : public CallbackObject
class TransportAddress : public CallbackObject
{
public:
TransportAddress(uint32_t p_ip = 0, uint16_t p_port = 0)
TransportAddress(uint32_t p_ip = 0, uint16_t p_port = 0)
{ ip = p_ip; port = p_port; }
~TransportAddress() {}
bool operator==(const TransportAddress& other) const
{ return other.ip == ip && other.port == port; }
bool operator!=(const TransportAddress& other) const
{ return other.ip != ip || other.port != port; }
uint32_t ip; //!< The IPv4 address
uint16_t port; //!< The port number
};
@ -55,17 +65,15 @@ class TransportAddress : public CallbackObject
/*! \class PlayerLogin
* \brief Contains the information needed to authenticate a user.
*/
class PlayerLogin : public CallbackObject
class PlayerLogin : public CallbackObject
{
public:
PlayerLogin() {}
~PlayerLogin() { username.clear(); password.clear(); }
std::string username; //!< Username of the player
std::string password; //!< Password of the player
};
uint32_t turnEndianness(uint32_t val);
#endif // TYPES_HPP

View File

@ -36,14 +36,6 @@
# include <math.h>
#endif
#if defined(WIN32) && !defined(__CYGWIN__)
// Use Sleep, which takes time in msecs. It must be defined after the
// includes, since otherwise irrlicht's sleep function is changed.
# define sleep(s) Sleep(1000*(s))
#else
# include <unistd.h>
#endif
using namespace Online;
namespace Online{
@ -183,7 +175,10 @@ namespace Online{
void HTTPManager::synchronousRequest(Request *request)
{
assert(request->isAllowedToAdd());
request->setBusy();
request->execute();
request->callback();
request->setDone();
} // synchronousRequest
// ---------------------------------------------------------------------------

View File

@ -30,6 +30,7 @@
#include <string>
#ifdef WIN32
# define WIN32_LEAN_AND_MEAN
# include <winsock2.h>
#endif

View File

@ -24,6 +24,8 @@
# include <winsock2.h>
#endif
#include <curl/curl.h>
#include <assert.h>
@ -162,8 +164,8 @@ namespace Online{
setProgress(1.0f);
else
setProgress(-1.0f);
curl_easy_cleanup(m_curl_session);
Request::afterOperation();
curl_easy_cleanup(m_curl_session);
}
size_t HTTPRequest::WriteCallback(void *contents, size_t size, size_t nmemb, void *userp)
@ -261,8 +263,6 @@ namespace Online{
{
if(m_curl_code != CURLE_OK)
Log::error( "XMLRequest::afterOperation", "curl_easy_perform() failed: %s", curl_easy_strerror(m_curl_code));
else
Log::info( "XMLRequest::afterOperation", "Received : %s", m_string_buffer.c_str());
bool success = false;
std::string rec_success;
if(m_result->get("success", &rec_success))

View File

@ -339,7 +339,7 @@ void RaceManager::startNew(bool from_overworld)
}
m_track_number = 0;
if(m_major_mode==MAJOR_MODE_GRAND_PRIX)
if(m_major_mode==MAJOR_MODE_GRAND_PRIX && !NetworkWorld::getInstance()->isRunning()) // offline mode only
{
//We look if Player 1 has a saved version of this GP.
// =================================================
@ -487,7 +487,7 @@ void RaceManager::next()
m_track_number++;
if(m_track_number<(int)m_tracks.size())
{
if(m_major_mode==MAJOR_MODE_GRAND_PRIX)
if(m_major_mode==MAJOR_MODE_GRAND_PRIX && !NetworkWorld::getInstance()->isRunning())
{
//Saving GP state
//We look if Player 1 has already saved this GP.
@ -631,7 +631,7 @@ void RaceManager::exitRace(bool delete_world)
if (m_major_mode==MAJOR_MODE_GRAND_PRIX && m_track_number==(int)m_tracks.size())
{
unlock_manager->getCurrentSlot()->grandPrixFinished();
if(m_major_mode==MAJOR_MODE_GRAND_PRIX)
if(m_major_mode==MAJOR_MODE_GRAND_PRIX&& !NetworkWorld::getInstance()->isRunning())
{
//Delete saved GP
SavedGrandPrix* gp =
@ -730,7 +730,9 @@ void RaceManager::kartFinishedRace(const AbstractKart *kart, float time)
m_kart_status[id].m_overall_time += time;
m_kart_status[id].m_last_time = time;
m_num_finished_karts ++;
if(kart->getController()->isPlayerController()) m_num_finished_players++;
if(kart->getController()->isPlayerController() ||
kart->getController()->isNetworkController())
m_num_finished_players++;
} // kartFinishedRace
//-----------------------------------------------------------------------------
@ -783,7 +785,7 @@ void RaceManager::startSingleRace(const std::string &track_ident,
setCoinTarget( 0 ); // Might still be set from a previous challenge
if (!NetworkWorld::getInstance<NetworkWorld>()->isRunning()) // if not in a network world
race_manager->setupPlayerKartInfo(); // do this setup player kart
race_manager->setupPlayerKartInfo(); // do this setup player kart
startNew(from_overworld);
}

View File

@ -563,6 +563,11 @@ public:
return m_kart_status[kart].m_overall_time;
}
// ------------------------------------------------------------------------
float getKartRaceTime(int kart) const
{
return m_kart_status[kart].m_last_time;
}
// ------------------------------------------------------------------------
KartType getKartType(int kart) const
{
return m_kart_status[kart].m_kart_type;
@ -708,7 +713,7 @@ public:
*/
bool allPlayerFinished() const
{
return m_num_finished_players==m_player_karts.size();
return m_num_finished_players == m_player_karts.size();
}
// ------------------------------------------------------------------------
void kartFinishedRace(const AbstractKart* kart, float time);

View File

@ -45,6 +45,7 @@ using namespace Online;
ServerInfoDialog::ServerInfoDialog(uint32_t server_id, uint32_t host_id, bool from_server_creation)
: ModalDialog(0.8f,0.8f), m_server_id(server_id), m_host_id(host_id)
{
Log::info("ServerInfoDialog", "Server id is %d, Host id is %d", server_id, host_id);
m_self_destroy = false;
m_enter_lobby = false;
m_from_server_creation = from_server_creation;

View File

@ -38,6 +38,7 @@
#include "karts/kart_properties.hpp"
#include "karts/kart_properties_manager.hpp"
#include "modes/overworld.hpp"
#include "online/profile.hpp"
#include "states_screens/race_setup_screen.hpp"
#include "states_screens/state_manager.hpp"
#include "utils/translation.hpp"
@ -182,17 +183,20 @@ void PlayerNameSpinner::markAsCorrect()
PlayerKartWidget::PlayerKartWidget(KartSelectionScreen* parent,
StateManager::ActivePlayer* associatedPlayer,
Online::Profile* associatedUser,
core::recti area, const int playerID,
std::string kartGroup,
const int irrlichtWidgetID) : Widget(WTYPE_DIV)
{
#ifdef DEBUG
assert(associatedPlayer->ok());
if (associatedPlayer)
assert(associatedPlayer->ok());
m_magic_number = 0x33445566;
#endif
m_ready_text = NULL;
m_parent_screen = parent;
m_associated_user = associatedUser;
m_associatedPlayer = associatedPlayer;
x_speed = 1.0f;
y_speed = 1.0f;
@ -214,13 +218,15 @@ PlayerKartWidget::PlayerKartWidget(KartSelectionScreen* parent,
target_h = m_h;
// ---- Player identity spinner
m_player_ident_spinner = NULL;
m_player_ident_spinner = new PlayerNameSpinner(parent, m_playerID);
m_player_ident_spinner->m_x = player_name_x;
m_player_ident_spinner->m_y = player_name_y;
m_player_ident_spinner->m_w = player_name_w;
m_player_ident_spinner->m_h = player_name_h;
if (parent->m_multiplayer)
if (parent->m_multiplayer && associatedPlayer)
{
if (associatedPlayer->getDevice()->getType() == DT_KEYBOARD)
{
@ -231,6 +237,10 @@ PlayerKartWidget::PlayerKartWidget(KartSelectionScreen* parent,
m_player_ident_spinner->setBadge(GAMEPAD_BADGE);
}
}
else if (m_associated_user) // online user, FIXME is that useful ?
{
m_player_ident_spinner->setBadge(OK_BADGE);
}
if (irrlichtWidgetID == -1)
{
@ -420,18 +430,21 @@ void PlayerKartWidget::add()
assert(KartSelectionScreen::getRunningInstance()
->m_kart_widgets.contains(this));
bool mineInList = false;
for (int p=0; p<StateManager::get()->activePlayerCount(); p++)
if (m_associatedPlayer) // if player is local
{
#ifdef DEBUG
assert(StateManager::get()->getActivePlayer(p)->ok());
#endif
if (StateManager::get()->getActivePlayer(p) == m_associatedPlayer)
bool mineInList = false;
for (int p=0; p<StateManager::get()->activePlayerCount(); p++)
{
mineInList = true;
#ifdef DEBUG
assert(StateManager::get()->getActivePlayer(p)->ok());
#endif
if (StateManager::get()->getActivePlayer(p) == m_associatedPlayer)
{
mineInList = true;
}
}
assert(mineInList);
}
assert(mineInList);
//m_player_ID_label->add();
@ -452,6 +465,13 @@ void PlayerKartWidget::add()
m_model_view->update(0);
m_player_ident_spinner->clearLabels();
irr::core::stringw name; // name of the player
if (m_associatedPlayer)
name = m_associatedPlayer->getProfile()->getName();
if (m_associated_user)
name = m_associated_user->getUserName();
if (m_parent_screen->m_multiplayer)
{
const int playerAmount = UserConfigParams::m_all_players.size();
@ -462,17 +482,15 @@ void PlayerKartWidget::add()
}
// select the right player profile in the spinner
m_player_ident_spinner->setValue(m_associatedPlayer->getProfile()
->getName() );
m_player_ident_spinner->setValue(name);
}
else
{
m_player_ident_spinner->addLabel( m_associatedPlayer->getProfile()->getName() );
m_player_ident_spinner->addLabel(name);
m_player_ident_spinner->setVisible(false);
}
assert(m_player_ident_spinner->getStringValue() ==
m_associatedPlayer->getProfile()->getName());
assert(m_player_ident_spinner->getStringValue() == name);
} // add
// ------------------------------------------------------------------------
@ -819,75 +837,7 @@ void KartHoverListener::onSelectionChanged(DynamicRibbonWidget* theWidget,
return;
}
// Update the displayed model
ModelViewWidget* w3 = m_parent->m_kart_widgets[playerID].m_model_view;
assert( w3 != NULL );
if (selectionID == RANDOM_KART_ID)
{
// Random kart
scene::IMesh* model =
ItemManager::getItemModel(Item::ITEM_BONUS_BOX);
w3->clearModels();
w3->addModel( model, Vec3(0.0f, -12.0f, 0.0f),
Vec3(35.0f, 35.0f, 35.0f) );
w3->update(0);
m_parent->m_kart_widgets[playerID].m_kart_name
->setText( _("Random Kart"), false );
}
// selectionID contains the name of the kart, so check only for substr
else if (StringUtils::startsWith(selectionID, ID_LOCKED))
{
w3->clearModels();
w3->addModel(irr_driver->getAnimatedMesh(
file_manager->getDataDir() + "/models/chest.b3d" )->getMesh(20),
Vec3(0,0,0), Vec3(15.0f, 15.0f, 15.0f) );
w3->update(0);
if (m_parent->m_multiplayer)
{
m_parent->m_kart_widgets[playerID].m_kart_name
->setText(_("Locked"), false );
}
else
{
m_parent->m_kart_widgets[playerID].m_kart_name
->setText(_("Locked : solve active challenges to gain "
"access to more!"), false );
}
}
else
{
const KartProperties *kp =
kart_properties_manager->getKart(selectionID);
if (kp != NULL)
{
const KartModel &kart_model = kp->getMasterKartModel();
w3->clearModels();
w3->addModel( kart_model.getModel(), Vec3(0,0,0),
Vec3(35.0f, 35.0f, 35.0f),
kart_model.getBaseFrame() );
w3->addModel( kart_model.getWheelModel(0),
kart_model.getWheelGraphicsPosition(0) );
w3->addModel( kart_model.getWheelModel(1),
kart_model.getWheelGraphicsPosition(1) );
w3->addModel( kart_model.getWheelModel(2),
kart_model.getWheelGraphicsPosition(2) );
w3->addModel( kart_model.getWheelModel(3),
kart_model.getWheelGraphicsPosition(3) );
w3->update(0);
m_parent->m_kart_widgets[playerID].m_kart_name
->setText( selectionText.c_str(), false );
}
else
{
fprintf(stderr, "[KartSelectionScreen] WARNING: could not "
"find a kart named '%s'\n",
selectionID.c_str());
}
}
m_parent->updateKartWidgetModel(playerID, selectionID, selectionText);
m_parent->m_kart_widgets[playerID].setKartInternalName(selectionID);
m_parent->validateKartChoices();
@ -900,7 +850,7 @@ void KartHoverListener::onSelectionChanged(DynamicRibbonWidget* theWidget,
// ============================================================================
KartSelectionScreen::KartSelectionScreen() : Screen("karts.stkgui")
KartSelectionScreen::KartSelectionScreen(const char* filename) : Screen(filename)
{
m_removed_widget = NULL;
m_multiplayer_message = NULL;
@ -989,6 +939,8 @@ void KartSelectionScreen::init()
Widget* placeholder = getWidget("playerskarts");
assert(placeholder != NULL);
// FIXME : The reserved id value is -1 when we switch from KSS to NKSS and vice-versa
g_dispatcher->setRootID(placeholder->m_reserved_id);
g_root_id = placeholder->m_reserved_id;
@ -1184,7 +1136,7 @@ bool KartSelectionScreen::playerJoin(InputDevice* device, bool firstPlayer)
// ---- Create player/kart widget
PlayerKartWidget* newPlayerWidget =
new PlayerKartWidget(this, aplayer, kartsArea, m_kart_widgets.size(),
new PlayerKartWidget(this, aplayer, NULL, kartsArea, m_kart_widgets.size(),
selected_kart_group);
manualAddWidget(newPlayerWidget);
@ -1491,6 +1443,83 @@ void KartSelectionScreen::playerConfirm(const int playerID)
if (allPlayersReady && (!m_multiplayer || amount > 1)) allPlayersDone();
} // playerConfirm
// ----------------------------------------------------------------------------
void KartSelectionScreen::updateKartWidgetModel(uint8_t widget_id,
const std::string& selection,
const irr::core::stringw& selectionText)
{
// Update the displayed model
ModelViewWidget* w3 = m_kart_widgets[widget_id].m_model_view;
assert( w3 != NULL );
if (selection == RANDOM_KART_ID)
{
// Random kart
scene::IMesh* model =
ItemManager::getItemModel(Item::ITEM_BONUS_BOX);
w3->clearModels();
w3->addModel( model, Vec3(0.0f, -12.0f, 0.0f),
Vec3(35.0f, 35.0f, 35.0f) );
w3->update(0);
m_kart_widgets[widget_id].m_kart_name
->setText( _("Random Kart"), false );
}
// selection contains the name of the kart, so check only for substr
else if (StringUtils::startsWith(selection, ID_LOCKED))
{
w3->clearModels();
w3->addModel(irr_driver->getAnimatedMesh(
file_manager->getDataDir() + "/models/chest.b3d" )->getMesh(20),
Vec3(0,0,0), Vec3(15.0f, 15.0f, 15.0f) );
w3->update(0);
if (m_multiplayer)
{
m_kart_widgets[widget_id].m_kart_name
->setText(_("Locked"), false );
}
else
{
m_kart_widgets[widget_id].m_kart_name
->setText(_("Locked : solve active challenges to gain "
"access to more!"), false );
}
}
else
{
const KartProperties *kp =
kart_properties_manager->getKart(selection);
if (kp != NULL)
{
const KartModel &kart_model = kp->getMasterKartModel();
w3->clearModels();
w3->addModel( kart_model.getModel(), Vec3(0,0,0),
Vec3(35.0f, 35.0f, 35.0f),
kart_model.getBaseFrame() );
w3->addModel( kart_model.getWheelModel(0),
kart_model.getWheelGraphicsPosition(0) );
w3->addModel( kart_model.getWheelModel(1),
kart_model.getWheelGraphicsPosition(1) );
w3->addModel( kart_model.getWheelModel(2),
kart_model.getWheelGraphicsPosition(2) );
w3->addModel( kart_model.getWheelModel(3),
kart_model.getWheelGraphicsPosition(3) );
w3->update(0);
m_kart_widgets[widget_id].m_kart_name
->setText( selectionText.c_str(), false );
}
else
{
fprintf(stderr, "[KartSelectionScreen] WARNING: could not "
"find a kart named '%s'\n",
selection.c_str());
}
}
}
// ----------------------------------------------------------------------------
/**
* Callback handling events from the kart selection menu

View File

@ -34,6 +34,10 @@ namespace GUIEngine
class BubbleWidget;
enum EventPropagation;
}
namespace Online
{
class User;
}
class InputDevice;
class PlayerKartWidget;
class KartHoverListener;
@ -66,7 +70,7 @@ protected:
bool m_must_delete_on_back; //!< To delete the screen if back is pressed
KartSelectionScreen();
KartSelectionScreen(const char* filename);
/** Stores whether any player confirmed their choice; then, some things
* are "frozen", for instance the selected kart group tab
@ -99,7 +103,11 @@ protected:
/** Fill the ribbon with the karts from the currently selected group */
void setKartsFromCurrentGroup();
void playerConfirm(const int playerID);
virtual void playerConfirm(const int playerID);
/** updates model of a kart widget, to have the good selection when the user validates */
void updateKartWidgetModel(uint8_t widget_id,
const std::string& selection,
const irr::core::stringw& selectionText);
/** Stores a pointer to the current selection screen */
static KartSelectionScreen* m_instance_ptr;
@ -234,8 +242,9 @@ class PlayerKartWidget : public GUIEngine::Widget,
float x_speed, y_speed, w_speed, h_speed;
/** Object representing this player */
StateManager::ActivePlayer* m_associatedPlayer;
StateManager::ActivePlayer* m_associatedPlayer; // local info
int m_playerID;
Online::Profile* m_associated_user; // network info
/** Internal name of the spinner; useful to interpret spinner events,
* which contain the name of the activated object */
@ -267,6 +276,7 @@ public:
PlayerKartWidget(KartSelectionScreen* parent,
StateManager::ActivePlayer* associatedPlayer,
Online::Profile* associatedUser,
core::recti area, const int playerID,
std::string kartGroup,
const int irrlichtWidgetID=-1);

View File

@ -279,7 +279,7 @@ void MainMenuScreen::eventCallback(Widget* widget, const std::string& name,
}
else if (selection == "multiplayer")
{
KartSelectionScreen* s = NetworkKartSelectionScreen::getInstance();
KartSelectionScreen* s = OfflineKartSelectionScreen::getInstance();
s->setMultiplayer(true);
s->setFromOverworld(false);
StateManager::get()->pushScreen( s );

View File

@ -1,14 +1,24 @@
#include "states_screens/network_kart_selection.hpp"
#include "audio/sfx_manager.hpp"
#include "challenges/unlock_manager.hpp"
#include "items/item_manager.hpp"
#include "karts/kart_properties.hpp"
#include "karts/kart_properties_manager.hpp"
#include "network/protocol_manager.hpp"
#include "network/protocols/client_lobby_room_protocol.hpp"
#include "network/network_manager.hpp"
#include "online/current_user.hpp"
#include "states_screens/state_manager.hpp"
static const char RANDOM_KART_ID[] = "randomkart";
static const char ID_LOCKED[] = "locked/";
using namespace GUIEngine;
DEFINE_SCREEN_SINGLETON( NetworkKartSelectionScreen );
NetworkKartSelectionScreen::NetworkKartSelectionScreen() : KartSelectionScreen()
NetworkKartSelectionScreen::NetworkKartSelectionScreen() : KartSelectionScreen("karts_online.stkgui")
{
KartSelectionScreen::m_instance_ptr = this;
}
@ -24,16 +34,122 @@ void NetworkKartSelectionScreen::init()
RibbonWidget* tabs = getWidget<RibbonWidget>("kartgroups");
assert( tabs != NULL );
tabs->setVisible(false);
tabs->select( "standard", PLAYER_ID_GAME_MASTER); // select standard kart group
tabs->setDeactivated();
tabs->setVisible(false);
// change the back button image (because it makes the game quit)
IconButtonWidget* back_button = getWidget<IconButtonWidget>("back");
back_button->setImage("gui/main_quit.png");
m_multiplayer = false;
// add a widget for each player except self (already exists):
GameSetup* setup = NetworkManager::getInstance()->getGameSetup();
if (!setup)
{
Log::error("NetworkKartSelectionScreen", "No network game setup registered.");
return;
}
std::vector<NetworkPlayerProfile*> players = setup->getPlayers();
Log::info("NKSS", "There are %d players", players.size());
// ---- Get available area for karts
// make a copy of the area, ands move it to be outside the screen
Widget* kartsAreaWidget = getWidget("playerskarts");
// start at the rightmost of the screen
const int shift = irr_driver->getFrameSize().Width;
core::recti kartsArea(kartsAreaWidget->m_x + shift,
kartsAreaWidget->m_y,
kartsAreaWidget->m_x + shift + kartsAreaWidget->m_w,
kartsAreaWidget->m_y + kartsAreaWidget->m_h);
for (unsigned int i = 0; i < players.size(); i++)
{
if (players[i]->user_profile == Online::CurrentUser::get()->getProfile())
{
m_id_mapping.insert(m_id_mapping.begin(),players[i]->race_id); //!< first kart widget always me
Log::info("NKSS", "Insert %d at pos 0", players[i]->race_id);
continue; // it is me, don't add again
}
Log::info("NKSS", "Adding %d at pos %d", players[i]->race_id, i);
m_id_mapping.push_back(players[i]->race_id);
StateManager::ActivePlayer* aplayer = NULL; // player is remote
std::string selected_kart_group = "standard"; // standard group
PlayerKartWidget* newPlayerWidget =
new PlayerKartWidget(this, aplayer, players[i]->user_profile, kartsArea, m_kart_widgets.size(),
selected_kart_group);
manualAddWidget(newPlayerWidget);
m_kart_widgets.push_back(newPlayerWidget);
newPlayerWidget->add();
}
const int amount = m_kart_widgets.size();
Widget* fullarea = getWidget("playerskarts");
const int splitWidth = fullarea->m_w / amount;
for (int n=0; n<amount; n++)
{
m_kart_widgets[n].move( fullarea->m_x + splitWidth*n,
fullarea->m_y, splitWidth, fullarea->m_h);
}
}
void NetworkKartSelectionScreen::playerConfirm(const int playerID)
{
DynamicRibbonWidget* w = getWidget<DynamicRibbonWidget>("karts");
assert(w != NULL);
const std::string selection = w->getSelectionIDString(playerID);
if (StringUtils::startsWith(selection, ID_LOCKED))
{
unlock_manager->playLockSound();
return;
}
if (playerID == PLAYER_ID_GAME_MASTER)
{
UserConfigParams::m_default_kart = selection;
}
if (m_kart_widgets[playerID].getKartInternalName().size() == 0)
{
sfx_manager->quickSound( "anvil" );
return;
}
if(playerID == PLAYER_ID_GAME_MASTER) // self
{
ClientLobbyRoomProtocol* protocol = static_cast<ClientLobbyRoomProtocol*>(
ProtocolManager::getInstance()->getProtocol(PROTOCOL_LOBBY_ROOM));
protocol->requestKartSelection(selection);
}
}
void NetworkKartSelectionScreen::playerSelected(uint8_t race_id, std::string kart_name)
{
uint8_t widget_id = -1;
for (unsigned int i = 0; i < m_id_mapping.size(); i++)
{
Log::info("NKSS", "Checking race id %d : mapped of %d is %d", race_id, i, m_id_mapping[i]);
if (m_id_mapping[i] == race_id)
widget_id = i;
}
assert(widget_id>=0 && widget_id < m_kart_widgets.size());
KartSelectionScreen::updateKartWidgetModel(widget_id, kart_name, irr::core::stringw(kart_name.c_str()));
m_kart_widgets[widget_id].setKartInternalName(kart_name);
m_kart_widgets[widget_id].markAsReady(); // mark player ready
}
/**
* Callback handling events from the kart selection menu
*/
@ -42,7 +158,7 @@ void NetworkKartSelectionScreen::eventCallback(GUIEngine::Widget* widget, const
{
if (name == "karts")
{
KartSelectionScreen::eventCallback(widget, name, playerID);
}
else if (name == "back")
{

View File

@ -8,15 +8,22 @@ class NetworkKartSelectionScreen : public KartSelectionScreen, public GUIEngine:
{
friend class GUIEngine::ScreenSingleton<NetworkKartSelectionScreen>;
protected:
//!< map the id of the kart widgets to race ids
std::vector<uint8_t> m_id_mapping;
NetworkKartSelectionScreen();
virtual ~NetworkKartSelectionScreen();
virtual void playerConfirm(const int playerID);
void considerKartHovered(uint8_t widget_id, std::string selection);
public:
virtual void init() OVERRIDE;
virtual void eventCallback(GUIEngine::Widget* widget, const std::string& name,
const int playerID) OVERRIDE;
virtual bool onEscapePressed() OVERRIDE;
virtual void playerSelected(uint8_t race_id, std::string kart_name);
};
#endif // NETWORK_KART_SELECTION_HPP

View File

@ -2,7 +2,7 @@
DEFINE_SCREEN_SINGLETON( OfflineKartSelectionScreen );
OfflineKartSelectionScreen::OfflineKartSelectionScreen() : KartSelectionScreen()
OfflineKartSelectionScreen::OfflineKartSelectionScreen() : KartSelectionScreen("karts.stkgui")
{
KartSelectionScreen::m_instance_ptr = this;
}

View File

@ -46,6 +46,9 @@
#include "network/protocol_manager.hpp"
#include "network/protocols/connect_to_server.hpp"
#include "network/protocol_manager.hpp"
#include "network/protocols/connect_to_server.hpp"
using namespace GUIEngine;
using namespace Online;

View File

@ -40,7 +40,11 @@
#include "race/highscores.hpp"
#include "states_screens/feature_unlocked.hpp"
#include "states_screens/main_menu_screen.hpp"
#include "states_screens/networking_lobby.hpp"
#include "states_screens/network_kart_selection.hpp"
#include "states_screens/online_screen.hpp"
#include "states_screens/race_setup_screen.hpp"
#include "states_screens/server_selection.hpp"
#include "tracks/track.hpp"
#include "tracks/track_manager.hpp"
#include "utils/string_utils.hpp"
@ -104,6 +108,25 @@ void RaceResultGUI::enableAllButtons()
enableGPProgress();
}
// If we're in a network world, change the buttons text
if (World::getWorld()->isNetworkWorld())
{
Log::info("This work was networked", "This is a network world.");
top->setVisible(false);
middle->setText( _("Continue.") );
middle->setVisible(true);
middle->setFocusForPlayer(PLAYER_ID_GAME_MASTER);
bottom->setText( _("Quit the server.") );
bottom->setVisible(true);
if (race_manager->getMajorMode()==RaceManager::MAJOR_MODE_GRAND_PRIX)
{
middle->setVisible(false); // you have to wait the server to start again
bottom->setFocusForPlayer(PLAYER_ID_GAME_MASTER);
}
return;
}
Log::info("This work was NOT networked", "This is NOT a network world.");
// If something was unlocked
// -------------------------
int n = unlock_manager->getCurrentSlot()->getRecentlyCompletedChallenges().size();
@ -223,6 +246,30 @@ void RaceResultGUI::eventCallback(GUIEngine::Widget* widget,
assert(false);
}
// If we're playing online :
if (World::getWorld()->isNetworkWorld())
{
StateManager::get()->popMenu();
if (name == "middle") // Continue button (return to server lobby)
{
race_manager->exitRace();
race_manager->setAIKartOverride("");
Screen* newStack[] = {MainMenuScreen::getInstance(),
OnlineScreen::getInstance(),
ServerSelection::getInstance(),
NetworkingLobby::getInstance(),
NULL};
StateManager::get()->resetAndSetStack( newStack );
}
if (name == "bottom") // Quit server (return to main menu)
{
race_manager->exitRace();
race_manager->setAIKartOverride("");
StateManager::get()->resetAndGoToScreen(MainMenuScreen::getInstance());
}
return;
}
// Next check for GP
// -----------------
if (race_manager->getMajorMode() == RaceManager::MAJOR_MODE_GRAND_PRIX)
@ -254,6 +301,7 @@ void RaceResultGUI::eventCallback(GUIEngine::Widget* widget,
{
race_manager->exitRace();
race_manager->setAIKartOverride("");
NetworkKartSelectionScreen::getInstance()->tearDown(); // be sure to delete the kart selection screen
Screen* newStack[] = {MainMenuScreen::getInstance(),
RaceSetupScreen::getInstance(),
NULL};
@ -267,6 +315,7 @@ void RaceResultGUI::eventCallback(GUIEngine::Widget* widget,
{
race_manager->exitRace();
race_manager->setAIKartOverride("");
NetworkKartSelectionScreen::getInstance()->tearDown(); // be sure to delete the kart selection screen
StateManager::get()->resetAndGoToScreen(MainMenuScreen::getInstance());
if (race_manager->raceWasStartedFromOverworld())

View File

@ -1197,7 +1197,7 @@ bool Track::loadMainTrack(const XMLNode &root)
convertTrackToBullet(m_all_nodes[i]);
}
// Now convert all objects that are only used for the physics
// Now convert all objects that are only used for the physics
// (like invisible walls).
for(unsigned int i=0; i<m_all_physics_only_nodes.size(); i++)
{
@ -1317,7 +1317,7 @@ void Track::createWater(const XMLNode &node)
// A speed of 0 results in a division by zero, so avoid this.
// The actual time for a wave from one maximum to the next is
// given by 2*M_PI*speed/1000.
Log::warn("Track",
Log::warn("Track",
"Wave-speed or time is 0, resetting it to the default.");
wave_speed =300.0f;
}
@ -2125,7 +2125,7 @@ bool Track::findGround(AbstractKart *kart)
// Material and hit point are not needed;
const Material *m;
Vec3 hit_point, normal;
bool over_ground = m_track_mesh->castRay(kart->getXYZ(), to, &hit_point,
bool over_ground = m_track_mesh->castRay(kart->getXYZ(), to, &hit_point,
&m, &normal);
const Vec3 &xyz = kart->getXYZ();
if(!over_ground || !m)
@ -2149,7 +2149,7 @@ bool Track::findGround(AbstractKart *kart)
// too long.
if(xyz.getY() - hit_point.getY() > 5)
{
Log::warn("physics",
Log::warn("physics",
"Kart at (%f %f %f) is too high above ground at (%f %f %f)",
xyz.getX(),xyz.getY(),xyz.getZ(),
hit_point.getX(),hit_point.getY(),hit_point.getZ());

View File

@ -28,6 +28,7 @@
typedef unsigned __int64 uint64_t;
#else
# include <stdint.h>
#define SOCKET_ERROR -1
#endif
#endif