Merge remote-tracking branch 'origin/master' into fix_replay
This commit is contained in:
@@ -158,8 +158,21 @@ public:
|
||||
bool initialize();
|
||||
void save();
|
||||
|
||||
StateManager::ActivePlayer* getSinglePlayer() { return m_single_player; }
|
||||
void setSinglePlayer(StateManager::ActivePlayer* p) { m_single_player = p; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the active player if there is only a single local player. It
|
||||
* returns NULL if multiplayer is active. */
|
||||
StateManager::ActivePlayer* getSinglePlayer() { return m_single_player; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Sets the ActivePlayer if there is only a single local player. p must
|
||||
* be NULL in case of splitscreen. A single player will receive events
|
||||
* from all connected devices. This allows for example a single player
|
||||
* to select a kart with the keyboard, but then use a gamepad for
|
||||
* the actual racing. In splitscreen each player will only receive
|
||||
* events from the device used to connect in the kart selection screen. */
|
||||
void setSinglePlayer(StateManager::ActivePlayer* p)
|
||||
{
|
||||
m_single_player = p;
|
||||
} // setSinglePlayer
|
||||
// ------------------------------------------------------------------------
|
||||
/** Sets or reset the 'map fire to select' option.
|
||||
*/
|
||||
|
||||
@@ -225,10 +225,7 @@ void Attachment::clear()
|
||||
*/
|
||||
void Attachment::hitBanana(Item *item, int new_attachment)
|
||||
{
|
||||
const KartProperties *kp = m_kart->getKartProperties();
|
||||
const StateManager::ActivePlayer *const ap = m_kart->getController()
|
||||
->getPlayer();
|
||||
if(ap && ap->getConstProfile()==PlayerManager::getCurrentPlayer())
|
||||
if(m_kart->getController()->canGetAchievements())
|
||||
PlayerManager::increaseAchievement(AchievementInfo::ACHIEVE_BANANA,
|
||||
"banana",1 );
|
||||
//Bubble gum shield effect:
|
||||
@@ -250,6 +247,7 @@ void Attachment::hitBanana(Item *item, int new_attachment)
|
||||
return;
|
||||
}
|
||||
|
||||
const KartProperties *kp = m_kart->getKartProperties();
|
||||
switch(getType()) // If there already is an attachment, make it worse :)
|
||||
{
|
||||
case ATTACH_BOMB:
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
#include "karts/abstract_kart.hpp"
|
||||
#include "modes/linear_world.hpp"
|
||||
#include "network/network_config.hpp"
|
||||
#include "network/network_world.hpp"
|
||||
#include "network/race_event_manager.hpp"
|
||||
#include "tracks/quad_graph.hpp"
|
||||
#include "tracks/track.hpp"
|
||||
#include "utils/string_utils.hpp"
|
||||
@@ -285,8 +285,10 @@ Item* ItemManager::newItem(const Vec3& xyz, float distance,
|
||||
void ItemManager::collectedItem(Item *item, AbstractKart *kart, int add_info)
|
||||
{
|
||||
assert(item);
|
||||
if((item->getType() == Item::ITEM_BUBBLEGUM || item->getType() == Item::ITEM_BUBBLEGUM_NOLOK) && kart->isShielded())
|
||||
{// shielded karts can simply drive over bubble gums without any effect.
|
||||
if( (item->getType() == Item::ITEM_BUBBLEGUM ||
|
||||
item->getType() == Item::ITEM_BUBBLEGUM_NOLOK) && kart->isShielded())
|
||||
{
|
||||
// shielded karts can simply drive over bubble gums without any effect.
|
||||
return;
|
||||
}
|
||||
item->collected(kart);
|
||||
@@ -318,7 +320,7 @@ void ItemManager::checkItemHit(AbstractKart* kart)
|
||||
if((*i)->hitKart(kart->getXYZ(), kart))
|
||||
{
|
||||
// if we're not playing online, pick the item.
|
||||
if (!NetworkWorld::getInstance()->isRunning())
|
||||
if (!RaceEventManager::getInstance()->isRunning())
|
||||
collectedItem(*i, kart);
|
||||
else if (NetworkConfig::get()->isServer())
|
||||
{
|
||||
@@ -326,7 +328,7 @@ void ItemManager::checkItemHit(AbstractKart* kart)
|
||||
// A client does the collection upon receiving the
|
||||
// event from the server!
|
||||
collectedItem(*i, kart);
|
||||
NetworkWorld::getInstance()->collectedItem(*i, kart);
|
||||
RaceEventManager::getInstance()->collectedItem(*i, kart);
|
||||
}
|
||||
} // if hit
|
||||
} // for m_all_items
|
||||
|
||||
@@ -174,9 +174,8 @@ void Powerup::use()
|
||||
const KartProperties *kp = m_owner->getKartProperties();
|
||||
|
||||
// The player gets an achievement point for using a powerup
|
||||
StateManager::ActivePlayer * player = m_owner->getController()->getPlayer();
|
||||
if (m_type != PowerupManager::POWERUP_NOTHING &&
|
||||
player != NULL && player->getConstProfile() == PlayerManager::getCurrentPlayer())
|
||||
if (m_type != PowerupManager::POWERUP_NOTHING &&
|
||||
m_owner->getController()->canGetAchievements() )
|
||||
{
|
||||
PlayerManager::increaseAchievement(AchievementInfo::ACHIEVE_POWERUP_LOVER, "poweruplover");
|
||||
}
|
||||
|
||||
@@ -302,13 +302,11 @@ void Swatter::squashThingsAround()
|
||||
m_closest_kart->setSquash(kp->getSwatterSquashDuration(),
|
||||
kp->getSwatterSquashSlowdown());
|
||||
|
||||
//Handle achievement if the swatter is used by the current player
|
||||
const StateManager::ActivePlayer *const ap = m_kart->getController()
|
||||
->getPlayer();
|
||||
if (ap && ap->getConstProfile() == PlayerManager::getCurrentPlayer())
|
||||
// Handle achievement if the swatter is used by the current player
|
||||
if (m_kart->getController()->canGetAchievements())
|
||||
{
|
||||
PlayerManager::increaseAchievement(AchievementInfo::ACHIEVE_MOSQUITO,
|
||||
"swatter", 1);
|
||||
"swatter", 1);
|
||||
}
|
||||
|
||||
if (m_closest_kart->getAttachment()->getType()==Attachment::ATTACH_BOMB)
|
||||
|
||||
@@ -248,7 +248,7 @@ public:
|
||||
/** Marks this kart to be eliminated. */
|
||||
virtual void eliminate() = 0;
|
||||
// ------------------------------------------------------------------------
|
||||
virtual void finishedRace(float time) = 0;
|
||||
virtual void finishedRace(float time, bool from_server=false) = 0;
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the finished time for a kart. */
|
||||
virtual float getFinishTime() const = 0;
|
||||
|
||||
@@ -31,9 +31,8 @@
|
||||
|
||||
bool AIBaseController::m_ai_debug = false;
|
||||
|
||||
AIBaseController::AIBaseController(AbstractKart *kart,
|
||||
StateManager::ActivePlayer *player)
|
||||
: Controller(kart, player)
|
||||
AIBaseController::AIBaseController(AbstractKart *kart)
|
||||
: Controller(kart)
|
||||
{
|
||||
m_kart = kart;
|
||||
m_kart_length = m_kart->getKartLength();
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
#define HEADER_AI_BASE_CONTROLLER_HPP
|
||||
|
||||
#include "karts/controller/controller.hpp"
|
||||
#include "states_screens/state_manager.hpp"
|
||||
|
||||
class AIProperties;
|
||||
class Track;
|
||||
@@ -74,8 +73,7 @@ protected:
|
||||
void checkPosition(const Vec3&, posData*, Vec3* lc = NULL) const;
|
||||
|
||||
public:
|
||||
AIBaseController(AbstractKart *kart,
|
||||
StateManager::ActivePlayer *player=NULL);
|
||||
AIBaseController(AbstractKart *kart);
|
||||
virtual ~AIBaseController() {};
|
||||
virtual void reset();
|
||||
virtual bool disableSlipstreamBonus() const;
|
||||
|
||||
@@ -82,9 +82,8 @@ in all AIs, e.g.:
|
||||
in [-1,1].
|
||||
|
||||
*/
|
||||
AIBaseLapController::AIBaseLapController(AbstractKart *kart,
|
||||
StateManager::ActivePlayer *player)
|
||||
: AIBaseController(kart, player)
|
||||
AIBaseLapController::AIBaseLapController(AbstractKart *kart)
|
||||
: AIBaseController(kart)
|
||||
{
|
||||
|
||||
if (race_manager->getMinorMode()!=RaceManager::MINOR_MODE_3_STRIKES &&
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
#define HEADER_AI_BASE_LAP_CONTROLLER_HPP
|
||||
|
||||
#include "karts/controller/ai_base_controller.hpp"
|
||||
#include "states_screens/state_manager.hpp"
|
||||
|
||||
class AIProperties;
|
||||
class LinearWorld;
|
||||
@@ -68,8 +67,7 @@ protected:
|
||||
virtual void raceFinished() {};
|
||||
|
||||
public:
|
||||
AIBaseLapController(AbstractKart *kart,
|
||||
StateManager::ActivePlayer *player=NULL);
|
||||
AIBaseLapController(AbstractKart *kart);
|
||||
virtual ~AIBaseLapController() {};
|
||||
virtual void reset();
|
||||
}; // AIBaseLapController
|
||||
|
||||
@@ -29,9 +29,8 @@
|
||||
#include "tracks/battle_graph.hpp"
|
||||
#include "utils/log.hpp"
|
||||
|
||||
ArenaAI::ArenaAI(AbstractKart *kart,
|
||||
StateManager::ActivePlayer *player)
|
||||
: AIBaseController(kart, player)
|
||||
ArenaAI::ArenaAI(AbstractKart *kart)
|
||||
: AIBaseController(kart)
|
||||
{
|
||||
m_debug_sphere = NULL;
|
||||
} // ArenaAI
|
||||
|
||||
@@ -125,8 +125,7 @@ private:
|
||||
virtual void findClosestKart(bool use_difficulty) = 0;
|
||||
virtual void findTarget() = 0;
|
||||
public:
|
||||
ArenaAI(AbstractKart *kart,
|
||||
StateManager::ActivePlayer *player = NULL);
|
||||
ArenaAI(AbstractKart *kart);
|
||||
virtual ~ArenaAI() {};
|
||||
virtual void update (float delta);
|
||||
virtual void reset ();
|
||||
|
||||
@@ -33,9 +33,14 @@ using namespace irr;
|
||||
using namespace std;
|
||||
#endif
|
||||
|
||||
BattleAI::BattleAI(AbstractKart *kart,
|
||||
StateManager::ActivePlayer *player)
|
||||
: ArenaAI(kart, player)
|
||||
#if defined(WIN32) && !defined(__CYGWIN__) && !defined(__MINGW32__)
|
||||
#define isnan _isnan
|
||||
#else
|
||||
#include <math.h>
|
||||
#endif
|
||||
|
||||
BattleAI::BattleAI(AbstractKart *kart)
|
||||
: ArenaAI(kart)
|
||||
{
|
||||
|
||||
reset();
|
||||
|
||||
@@ -44,8 +44,7 @@ private:
|
||||
virtual bool isWaiting() const;
|
||||
virtual bool canSkid(float steer_fraction) { return m_mini_skid; }
|
||||
public:
|
||||
BattleAI(AbstractKart *kart,
|
||||
StateManager::ActivePlayer *player = NULL);
|
||||
BattleAI(AbstractKart *kart);
|
||||
~BattleAI();
|
||||
virtual void update (float delta);
|
||||
virtual void reset ();
|
||||
|
||||
@@ -22,19 +22,15 @@
|
||||
|
||||
#include "karts/controller/controller.hpp"
|
||||
|
||||
#include "config/player_manager.hpp"
|
||||
#include "karts/abstract_kart.hpp"
|
||||
|
||||
/** Constructor, saves the kart pointer and a pointer to the KartControl
|
||||
* of the kart.
|
||||
*/
|
||||
Controller::Controller(AbstractKart *kart, StateManager::ActivePlayer *player)
|
||||
Controller::Controller(AbstractKart *kart)
|
||||
{
|
||||
m_controls = &(kart->getControls());
|
||||
m_kart = kart;
|
||||
m_player = player;
|
||||
if(player)
|
||||
player->setKart(kart);
|
||||
setControllerName("Controller");
|
||||
} // Controller
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
@@ -42,9 +42,6 @@ class Material;
|
||||
class Controller
|
||||
{
|
||||
private:
|
||||
/** If this belongs to a player, it stores the active player data
|
||||
* structure. Otherwise it is 0. */
|
||||
StateManager::ActivePlayer *m_player;
|
||||
|
||||
protected:
|
||||
/** Pointer to the kart that is controlled by this controller. */
|
||||
@@ -58,8 +55,7 @@ protected:
|
||||
std::string m_controller_name;
|
||||
|
||||
public:
|
||||
Controller (AbstractKart *kart,
|
||||
StateManager::ActivePlayer *player=NULL);
|
||||
Controller (AbstractKart *kart);
|
||||
virtual ~Controller () {};
|
||||
virtual void reset () = 0;
|
||||
virtual void update (float dt) = 0;
|
||||
@@ -85,15 +81,6 @@ public:
|
||||
// ---------------------------------------------------------------------------
|
||||
/** Returns the name of this controller. */
|
||||
const std::string &getControllerName() const { return m_controller_name; }
|
||||
// ---------------------------------------------------------------------------
|
||||
/** Returns the active player for this controller (NULL
|
||||
* if this controller does not belong to a player. */
|
||||
StateManager::ActivePlayer *getPlayer () {return m_player;}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** Returns the player object (or NULL if it's a computer controller). */
|
||||
const StateManager::ActivePlayer *getPlayer () const { return m_player; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Default: ignore actions. Only PlayerController get them. */
|
||||
virtual void action(PlayerAction action, int value) = 0;
|
||||
@@ -110,6 +97,18 @@ public:
|
||||
/** Get a pointer on the kart controls. */
|
||||
virtual KartControl* getControls() { return m_controls; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Only local players can get achievements. */
|
||||
virtual bool canGetAchievements () const { return false; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** This should only be called for End- and LocalPlayer-Controller. */
|
||||
virtual core::stringw getName() const
|
||||
{
|
||||
assert(false);
|
||||
return core::stringw("");
|
||||
} // getName
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the kart controlled by this controller. */
|
||||
AbstractKart *getKart() const { return m_kart; }
|
||||
}; // Controller
|
||||
|
||||
#endif
|
||||
|
||||
@@ -50,9 +50,9 @@
|
||||
#include "utils/constants.hpp"
|
||||
#include "utils/log.hpp"
|
||||
|
||||
EndController::EndController(AbstractKart *kart, StateManager::ActivePlayer *player,
|
||||
EndController::EndController(AbstractKart *kart,
|
||||
Controller *prev_controller)
|
||||
: AIBaseLapController(kart, player)
|
||||
: AIBaseLapController(kart)
|
||||
{
|
||||
m_previous_controller = prev_controller;
|
||||
if(race_manager->getMinorMode()!=RaceManager::MINOR_MODE_3_STRIKES &&
|
||||
|
||||
@@ -82,18 +82,38 @@ private:
|
||||
int calcSteps();
|
||||
virtual bool canSkid(float steer_fraction) { return false; }
|
||||
public:
|
||||
EndController(AbstractKart *kart,
|
||||
StateManager::ActivePlayer* player,
|
||||
Controller *prev_controller);
|
||||
~EndController();
|
||||
virtual void update (float delta) ;
|
||||
virtual void reset ();
|
||||
EndController(AbstractKart *kart,
|
||||
Controller *prev_controller);
|
||||
~EndController();
|
||||
virtual void update (float delta) ;
|
||||
virtual void reset ();
|
||||
virtual void action (PlayerAction action, int value);
|
||||
virtual void newLap (int lap);
|
||||
// ------------------------------------------------------------------------
|
||||
virtual bool canGetAchievements() const
|
||||
{
|
||||
return m_previous_controller->canGetAchievements();
|
||||
} // canGetAchievements
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns if the original controller of the kart was a player
|
||||
* controller. This way e.g. highscores can still be assigned
|
||||
* to the right player. */
|
||||
virtual bool isPlayerController () const { return getPlayer() != NULL; }
|
||||
virtual void action (PlayerAction action, int value);
|
||||
virtual void newLap (int lap);
|
||||
virtual bool isPlayerController () const
|
||||
{
|
||||
return m_previous_controller->isPlayerController();
|
||||
} // isPlayerController
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns if the original controller of the kart was a local player
|
||||
* controller. This way e.g. highscores can still be assigned
|
||||
* to the right player. */
|
||||
virtual bool isLocalPlayerController () const
|
||||
{
|
||||
return m_previous_controller->isLocalPlayerController();
|
||||
} // isLocalPlayerController
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the name of the previous controller (which has the right
|
||||
* player name associated). */
|
||||
core::stringw getName() const { return m_previous_controller->getName(); }
|
||||
|
||||
}; // EndKart
|
||||
|
||||
|
||||
@@ -19,9 +19,8 @@
|
||||
#include "karts/controller/ghost_controller.hpp"
|
||||
#include "modes/world.hpp"
|
||||
|
||||
GhostController::GhostController(AbstractKart *kart,
|
||||
StateManager::ActivePlayer *player)
|
||||
: Controller(kart, player)
|
||||
GhostController::GhostController(AbstractKart *kart)
|
||||
: Controller(kart)
|
||||
{
|
||||
} // GhostController
|
||||
|
||||
|
||||
@@ -41,8 +41,7 @@ private:
|
||||
std::vector<float> m_all_times;
|
||||
|
||||
public:
|
||||
GhostController(AbstractKart *kart,
|
||||
StateManager::ActivePlayer *player=NULL);
|
||||
GhostController(AbstractKart *kart);
|
||||
virtual ~GhostController() {};
|
||||
virtual void reset();
|
||||
virtual void update (float dt);
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "karts/controller/local_player_controller.hpp"
|
||||
|
||||
#include "audio/sfx_base.hpp"
|
||||
#include "config/player_manager.hpp"
|
||||
#include "config/stk_config.hpp"
|
||||
#include "config/user_config.hpp"
|
||||
#include "graphics/camera.hpp"
|
||||
@@ -36,7 +37,7 @@
|
||||
#include "karts/rescue_animation.hpp"
|
||||
#include "modes/world.hpp"
|
||||
#include "network/network_config.hpp"
|
||||
#include "network/network_world.hpp"
|
||||
#include "network/race_event_manager.hpp"
|
||||
#include "race/history.hpp"
|
||||
#include "states_screens/race_gui_base.hpp"
|
||||
#include "utils/constants.hpp"
|
||||
@@ -52,8 +53,12 @@
|
||||
*/
|
||||
LocalPlayerController::LocalPlayerController(AbstractKart *kart,
|
||||
StateManager::ActivePlayer *player)
|
||||
: PlayerController(kart, player)
|
||||
: PlayerController(kart)
|
||||
{
|
||||
m_player = player;
|
||||
if(player)
|
||||
player->setKart(kart);
|
||||
|
||||
// Keep a pointer to the camera to remove the need to search for
|
||||
// the right camera once per frame later.
|
||||
m_camera = Camera::createCamera(kart);
|
||||
@@ -116,9 +121,9 @@ void LocalPlayerController::action(PlayerAction action, int value)
|
||||
// If this is a client, send the action to the server
|
||||
if (World::getWorld()->isNetworkWorld() &&
|
||||
NetworkConfig::get()->isClient() &&
|
||||
NetworkWorld::getInstance()->isRunning() )
|
||||
RaceEventManager::getInstance()->isRunning() )
|
||||
{
|
||||
NetworkWorld::getInstance()->controllerAction(this, action, value);
|
||||
RaceEventManager::getInstance()->controllerAction(this, action, value);
|
||||
}
|
||||
|
||||
} // action
|
||||
@@ -309,3 +314,15 @@ void LocalPlayerController::collectedItem(const Item &item, int add_info,
|
||||
}
|
||||
}
|
||||
} // collectedItem
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Returns true if the player of this controller can collect achievements.
|
||||
* At the moment only the current player can collect them.
|
||||
* TODO: check this, possible all local players should be able to
|
||||
* collect achievements - synching to online account will happen
|
||||
* next time the account gets online.
|
||||
*/
|
||||
bool LocalPlayerController::canGetAchievements() const
|
||||
{
|
||||
return m_player->getConstProfile() == PlayerManager::getCurrentPlayer();
|
||||
} // canGetAchievements
|
||||
|
||||
@@ -37,6 +37,9 @@ class LocalPlayerController : public PlayerController
|
||||
{
|
||||
private:
|
||||
|
||||
/** Stores the active player data structure. */
|
||||
StateManager::ActivePlayer *m_player;
|
||||
|
||||
bool m_sound_schedule;
|
||||
|
||||
/** The camera attached to the kart for this controller. The camera
|
||||
@@ -64,10 +67,16 @@ public:
|
||||
virtual void reset () OVERRIDE;
|
||||
virtual void finishedRace (float time) OVERRIDE;
|
||||
virtual void resetInputState () OVERRIDE;
|
||||
virtual bool canGetAchievements() const OVERRIDE;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
virtual bool isPlayerController() const OVERRIDE {return true;}
|
||||
// ------------------------------------------------------------------------
|
||||
virtual bool isLocalPlayerController() const OVERRIDE {return true;}
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the name of the player profile. */
|
||||
core::stringw getName() const { return m_player->getProfile()->getName(); }
|
||||
|
||||
|
||||
}; // LocalPlayerController
|
||||
|
||||
|
||||
@@ -25,9 +25,7 @@ class Player;
|
||||
class NetworkPlayerController : public PlayerController
|
||||
{
|
||||
public:
|
||||
NetworkPlayerController(AbstractKart *kart,
|
||||
StateManager::ActivePlayer *player)
|
||||
: PlayerController(kart, player)
|
||||
NetworkPlayerController(AbstractKart *kart) : PlayerController(kart)
|
||||
{
|
||||
Log::info("NetworkPlayerController",
|
||||
"New network player controller.");
|
||||
|
||||
@@ -38,11 +38,9 @@
|
||||
#include "utils/log.hpp"
|
||||
#include "utils/translation.hpp"
|
||||
|
||||
PlayerController::PlayerController(AbstractKart *kart,
|
||||
StateManager::ActivePlayer *player)
|
||||
: Controller(kart, player)
|
||||
PlayerController::PlayerController(AbstractKart *kart)
|
||||
: Controller(kart)
|
||||
{
|
||||
assert(player != NULL);
|
||||
m_penalty_time = 0.0f;
|
||||
} // PlayerController
|
||||
|
||||
|
||||
@@ -41,8 +41,7 @@ protected:
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
public:
|
||||
PlayerController(AbstractKart *kart,
|
||||
StateManager::ActivePlayer *_player);
|
||||
PlayerController(AbstractKart *kart);
|
||||
virtual ~PlayerController ();
|
||||
virtual void update (float) OVERRIDE;
|
||||
virtual void action (PlayerAction action, int value) OVERRIDE;
|
||||
|
||||
@@ -33,9 +33,8 @@ using namespace irr;
|
||||
using namespace std;
|
||||
#endif
|
||||
|
||||
SoccerAI::SoccerAI(AbstractKart *kart,
|
||||
StateManager::ActivePlayer *player)
|
||||
: ArenaAI(kart, player)
|
||||
SoccerAI::SoccerAI(AbstractKart *kart)
|
||||
: ArenaAI(kart)
|
||||
{
|
||||
|
||||
reset();
|
||||
|
||||
@@ -45,8 +45,7 @@ private:
|
||||
virtual bool isWaiting() const;
|
||||
virtual bool canSkid(float steer_fraction) { return m_saving_ball; }
|
||||
public:
|
||||
SoccerAI(AbstractKart *kart,
|
||||
StateManager::ActivePlayer *player = NULL);
|
||||
SoccerAI(AbstractKart *kart);
|
||||
~SoccerAI();
|
||||
virtual void update (float delta);
|
||||
virtual void reset ();
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
#include "karts/skidding.hpp"
|
||||
#include "modes/linear_world.hpp"
|
||||
#include "network/network_config.hpp"
|
||||
#include "network/network_world.hpp"
|
||||
#include "network/race_event_manager.hpp"
|
||||
#include "physics/btKart.hpp"
|
||||
#include "physics/btKartRaycast.hpp"
|
||||
#include "physics/physics.hpp"
|
||||
@@ -824,14 +824,34 @@ float Kart::getMaxSteerAngle(float speed) const
|
||||
* world->getTime()), or the estimated time in case that all
|
||||
* player kart have finished the race and all AI karts get
|
||||
* an estimated finish time set.
|
||||
* \param from_server In a network game, only the server can notify
|
||||
* about a kart finishing a race. This parameter is to distinguish
|
||||
* between a local detection (which is ignored on clients in a
|
||||
* network game), and a server notification.
|
||||
*/
|
||||
void Kart::finishedRace(float time)
|
||||
void Kart::finishedRace(float time, bool from_server)
|
||||
{
|
||||
// m_finished_race can be true if e.g. an AI kart was set to finish
|
||||
// because the race was over (i.e. estimating the finish time). If
|
||||
// this kart then crosses the finish line (with the end controller)
|
||||
// it would trigger a race end again.
|
||||
if(m_finished_race) return;
|
||||
|
||||
if(!from_server)
|
||||
{
|
||||
if(NetworkConfig::get()->isServer())
|
||||
{
|
||||
RaceEventManager::getInstance()->kartFinishedRace(this, time);
|
||||
} // isServer
|
||||
|
||||
// Ignore local detection of a kart finishing a race in a
|
||||
// network game.
|
||||
else if(NetworkConfig::get()->isClient())
|
||||
{
|
||||
return;
|
||||
}
|
||||
} // !from_server
|
||||
|
||||
m_finished_race = true;
|
||||
m_finish_time = time;
|
||||
m_controller->finishedRace(time);
|
||||
@@ -871,8 +891,7 @@ void Kart::finishedRace(float time)
|
||||
setRaceResult();
|
||||
if(!isGhostKart())
|
||||
{
|
||||
setController(new EndController(this, m_controller->getPlayer(),
|
||||
m_controller));
|
||||
setController(new EndController(this, m_controller));
|
||||
}
|
||||
// Skip animation if this kart is eliminated
|
||||
if (m_eliminated || isGhostKart()) return;
|
||||
@@ -1397,7 +1416,7 @@ void Kart::update(float dt)
|
||||
// Check if any item was hit.
|
||||
// check it if we're not in a network world, or if we're on the server
|
||||
// (when network mode is on)
|
||||
if (!NetworkWorld::getInstance()->isRunning() ||
|
||||
if (!RaceEventManager::getInstance()->isRunning() ||
|
||||
NetworkConfig::get()->isServer())
|
||||
ItemManager::get()->checkItemHit(this);
|
||||
|
||||
|
||||
@@ -272,8 +272,8 @@ public:
|
||||
virtual void crashed (const Material *m, const Vec3 &normal);
|
||||
virtual float getHoT () const;
|
||||
virtual void update (float dt);
|
||||
virtual void finishedRace(float time);
|
||||
virtual void setPosition(int p);
|
||||
virtual void finishedRace (float time, bool from_server=false);
|
||||
virtual void setPosition (int p);
|
||||
virtual void beep ();
|
||||
virtual void showZipperFire ();
|
||||
virtual float getCurrentMaxSpeed() const;
|
||||
|
||||
@@ -415,10 +415,10 @@ void Skidding::update(float dt, bool is_on_ground,
|
||||
bonus_force, bonus_time,
|
||||
/*fade-out-time*/ 1.0f);
|
||||
|
||||
StateManager::ActivePlayer *c = m_kart->getController()->getPlayer();
|
||||
if (c && c->getConstProfile() == PlayerManager::getCurrentPlayer())
|
||||
if (m_kart->getController()->canGetAchievements())
|
||||
{
|
||||
PlayerManager::increaseAchievement(AchievementInfo::ACHIEVE_SKIDDING, "skidding");
|
||||
PlayerManager::increaseAchievement(
|
||||
AchievementInfo::ACHIEVE_SKIDDING, "skidding");
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -532,6 +532,7 @@ void cmdLineHelp()
|
||||
// " n=2: recorded key strokes\n"
|
||||
" --server=name Start a server (not a playing client).\n"
|
||||
" --lan-server=name Start a LAN server (not a playing client).\n"
|
||||
" --server-password= Sets a password for a server (both client&server).\n"
|
||||
" --login=s Automatically log in (set the login).\n"
|
||||
" --password=s Automatically log in (set the password).\n"
|
||||
" --port=n Port number to use.\n"
|
||||
@@ -791,6 +792,10 @@ int handleCmdLine()
|
||||
STKHost::create();
|
||||
Log::info("main", "Creating a LAN server '%s'.", s.c_str());
|
||||
}
|
||||
if (CommandLine::has("--server-password", &s))
|
||||
{
|
||||
NetworkConfig::get()->setPassword(s);
|
||||
}
|
||||
|
||||
if(CommandLine::has("--max-players", &n))
|
||||
UserConfigParams::m_server_max_players=n;
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
#include "modes/world.hpp"
|
||||
#include "network/network_config.hpp"
|
||||
#include "network/protocol_manager.hpp"
|
||||
#include "network/network_world.hpp"
|
||||
#include "network/race_event_manager.hpp"
|
||||
#include "network/stk_host.hpp"
|
||||
#include "online/request_manager.hpp"
|
||||
#include "race/race_manager.hpp"
|
||||
@@ -121,8 +121,9 @@ void MainLoop::updateRace(float dt)
|
||||
{
|
||||
if(ProfileWorld::isProfileMode()) dt=1.0f/60.0f;
|
||||
|
||||
if (NetworkWorld::getInstance<NetworkWorld>()->isRunning())
|
||||
NetworkWorld::getInstance<NetworkWorld>()->update(dt);
|
||||
// The race event manager will update world in case of an online race
|
||||
if (RaceEventManager::getInstance<RaceEventManager>()->isRunning())
|
||||
RaceEventManager::getInstance<RaceEventManager>()->update(dt);
|
||||
else
|
||||
World::getWorld()->updateWorld(dt);
|
||||
} // updateRace
|
||||
|
||||
@@ -248,9 +248,8 @@ void LinearWorld::newLap(unsigned int kart_index)
|
||||
AbstractKart *kart = m_karts[kart_index];
|
||||
|
||||
// Reset reset-after-lap achievements
|
||||
StateManager::ActivePlayer *c = kart->getController()->getPlayer();
|
||||
PlayerProfile *p = PlayerManager::getCurrentPlayer();
|
||||
if (c && c->getConstProfile() == p)
|
||||
if (kart->getController()->canGetAchievements())
|
||||
{
|
||||
p->getAchievementsStatus()->onLapEnd();
|
||||
}
|
||||
|
||||
@@ -328,8 +328,7 @@ AbstractKart *World::createKart(const std::string &kart_ident, int index,
|
||||
m_num_players ++;
|
||||
break;
|
||||
case RaceManager::KT_NETWORK_PLAYER:
|
||||
controller = new NetworkPlayerController(new_kart,
|
||||
StateManager::get()->getActivePlayer(local_player_id));
|
||||
controller = new NetworkPlayerController(new_kart);
|
||||
m_num_players++;
|
||||
break;
|
||||
case RaceManager::KT_AI:
|
||||
@@ -495,13 +494,10 @@ void World::terminateRace()
|
||||
// Update highscores, and retrieve the best highscore if relevant
|
||||
// to show it in the GUI
|
||||
int best_highscore_rank = -1;
|
||||
int best_finish_time = -1;
|
||||
std::string highscore_who = "";
|
||||
StateManager::ActivePlayer* best_player = NULL;
|
||||
if (!this->isNetworkWorld())
|
||||
{
|
||||
updateHighscores(&best_highscore_rank, &best_finish_time, &highscore_who,
|
||||
&best_player);
|
||||
updateHighscores(&best_highscore_rank);
|
||||
}
|
||||
|
||||
// Check achievements
|
||||
@@ -527,8 +523,7 @@ void World::terminateRace()
|
||||
for(unsigned int i = 0; i < kart_amount; i++)
|
||||
{
|
||||
// Retrieve the current player
|
||||
StateManager::ActivePlayer* p = m_karts[i]->getController()->getPlayer();
|
||||
if (p && p->getConstProfile() == PlayerManager::getCurrentPlayer())
|
||||
if (m_karts[i]->getController()->canGetAchievements())
|
||||
{
|
||||
// Check if the player has won
|
||||
if (m_karts[i]->getPosition() == winner_position && kart_amount > opponents )
|
||||
@@ -552,8 +547,7 @@ void World::terminateRace()
|
||||
for(unsigned int i = 0; i < kart_amount; i++)
|
||||
{
|
||||
// Retrieve the current player
|
||||
StateManager::ActivePlayer* p = m_karts[i]->getController()->getPlayer();
|
||||
if (p && p->getConstProfile() == PlayerManager::getCurrentPlayer())
|
||||
if (m_karts[i]->getController()->canGetAchievements())
|
||||
{
|
||||
// Check if the player has won
|
||||
if (m_karts[i]->getPosition() == 1 )
|
||||
@@ -586,8 +580,7 @@ void World::terminateRace()
|
||||
|
||||
if (best_highscore_rank > 0)
|
||||
{
|
||||
results->setHighscore(highscore_who, best_player, best_highscore_rank,
|
||||
best_finish_time);
|
||||
results->setHighscore(best_highscore_rank);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1063,12 +1056,9 @@ Highscores* World::getHighscores() const
|
||||
* score, if so it notifies the HighscoreManager so the new score is added
|
||||
* and saved.
|
||||
*/
|
||||
void World::updateHighscores(int* best_highscore_rank, int* best_finish_time,
|
||||
std::string* highscore_who,
|
||||
StateManager::ActivePlayer** best_player)
|
||||
void World::updateHighscores(int* best_highscore_rank)
|
||||
{
|
||||
*best_highscore_rank = -1;
|
||||
*best_player = NULL;
|
||||
|
||||
if(!m_use_highscores) return;
|
||||
|
||||
@@ -1120,14 +1110,11 @@ void World::updateHighscores(int* best_highscore_rank, int* best_finish_time,
|
||||
|
||||
Highscores* highscores = getHighscores();
|
||||
|
||||
LocalPlayerController *controller =
|
||||
(LocalPlayerController*)(k->getController());
|
||||
|
||||
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());
|
||||
// The player is a local player, so there is a name:
|
||||
highscore_rank = highscores->addData(k->getIdent(),
|
||||
k->getController()->getName(),
|
||||
k->getFinishTime() );
|
||||
|
||||
if (highscore_rank > 0)
|
||||
{
|
||||
@@ -1135,9 +1122,6 @@ void World::updateHighscores(int* best_highscore_rank, int* best_finish_time,
|
||||
highscore_rank < *best_highscore_rank)
|
||||
{
|
||||
*best_highscore_rank = highscore_rank;
|
||||
*best_finish_time = (int)(k->getFinishTime());
|
||||
*best_player = controller->getPlayer();
|
||||
*highscore_who = k->getIdent();
|
||||
}
|
||||
|
||||
highscore_manager->saveHighscores();
|
||||
|
||||
@@ -115,9 +115,7 @@ protected:
|
||||
*/
|
||||
bool m_use_highscores;
|
||||
|
||||
void updateHighscores (int* best_highscore_rank, int* best_finish_time,
|
||||
std::string* highscore_who,
|
||||
StateManager::ActivePlayer** best_player);
|
||||
void updateHighscores (int* best_highscore_rank);
|
||||
void resetAllKarts ();
|
||||
void eliminateKart (int kart_number, bool notifyOfElimination=true);
|
||||
Controller*
|
||||
|
||||
@@ -59,7 +59,6 @@ Event::Event(ENetEvent* event)
|
||||
}
|
||||
m_packet = NULL;
|
||||
|
||||
const std::vector<STKPeer*> &peers = STKHost::get()->getPeers();
|
||||
m_peer = STKHost::get()->getPeer(event->peer);
|
||||
} // Event(ENetEvent)
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ GameSetup::~GameSetup()
|
||||
void GameSetup::addPlayer(NetworkPlayerProfile* profile)
|
||||
{
|
||||
m_players.push_back(profile);
|
||||
Log::info("GameSetup", "New player in the game setup. Race id : %d.",
|
||||
Log::info("GameSetup", "New player in the game setup. Player id : %d.",
|
||||
profile->getGlobalPlayerId());
|
||||
} // addPlayer
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@ NetworkConfig::NetworkConfig()
|
||||
m_max_players = 4;
|
||||
m_is_registered = false;
|
||||
m_server_name = "";
|
||||
m_password = "";
|
||||
m_private_port = 0;
|
||||
m_my_address.lock();
|
||||
m_my_address.getData().clear();
|
||||
|
||||
@@ -42,6 +42,9 @@ private:
|
||||
/** True if this host is a server, false otherwise. */
|
||||
bool m_is_server;
|
||||
|
||||
/** The password for a server (or to authenticate to a server). */
|
||||
std::string m_password;
|
||||
|
||||
/** This is either this computer's public IP address, or the LAN
|
||||
* address in case of a LAN game. With lock since it can
|
||||
* be updated from a separate thread. */
|
||||
@@ -83,6 +86,12 @@ public:
|
||||
// ------------------------------------------------------------------------
|
||||
void setMyAddress(const TransportAddress& addr);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Sets the password for a server. */
|
||||
void setPassword(const std::string &password) { m_password = password; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the password. */
|
||||
const std::string& getPassword() const { return m_password; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Return if a network setting is happening. A network setting is active
|
||||
* if a host (server or client) exists. */
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
#include "network/network_player_profile.hpp"
|
||||
|
||||
#include "network/stk_host.hpp"
|
||||
#include "online/online_player_profile.hpp"
|
||||
|
||||
/** Constructor.
|
||||
@@ -39,3 +40,12 @@ NetworkPlayerProfile::NetworkPlayerProfile(int global_player_id,
|
||||
NetworkPlayerProfile::~NetworkPlayerProfile()
|
||||
{
|
||||
} // ~NetworkPlayerProfile
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Returns true if this player is local, i.e. running on this computer. This
|
||||
* is done by comparing the host id of this player with the host id of this
|
||||
* computer.
|
||||
*/
|
||||
bool NetworkPlayerProfile::isLocalPlayer() const
|
||||
{
|
||||
return m_host_id == STKHost::get()->getMyHostId();
|
||||
} // isLocalPlayer
|
||||
@@ -60,6 +60,7 @@ public:
|
||||
NetworkPlayerProfile(int global_player_id,
|
||||
const irr::core::stringw &name);
|
||||
~NetworkPlayerProfile();
|
||||
bool isLocalPlayer() const;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Sets the global player id of this player. */
|
||||
|
||||
@@ -24,6 +24,9 @@
|
||||
#define NETWORK_STRING_HPP
|
||||
|
||||
#include "utils/types.hpp"
|
||||
#include "utils/vec3.hpp"
|
||||
|
||||
#include "LinearMath/btQuaternion.h"
|
||||
|
||||
#include "irrString.h"
|
||||
|
||||
@@ -256,6 +259,19 @@ public:
|
||||
return *this;
|
||||
} // operator+=
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Adds the xyz components of a Vec3 to the string. */
|
||||
NetworkString& add(const Vec3 &xyz)
|
||||
{
|
||||
return addFloat(xyz.getX()).addFloat(xyz.getY()).addFloat(xyz.getZ());
|
||||
} // add
|
||||
// ------------------------------------------------------------------------
|
||||
/** Adds the four components of a quaternion. */
|
||||
NetworkString& add(const btQuaternion &quat)
|
||||
{
|
||||
return addFloat(quat.getX()).addFloat(quat.getY())
|
||||
.addFloat(quat.getZ()).addFloat(quat.getW());
|
||||
} // add
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the content of the network string as a std::string. */
|
||||
const std::string std_string() const
|
||||
@@ -500,6 +516,25 @@ public:
|
||||
*dst = getAndRemoveUChar(0);
|
||||
return *this;
|
||||
} // guc
|
||||
// ------------------------------------------------------------------------
|
||||
/** Reads the three components of a Vec3 from the given position. */
|
||||
NetworkString& get(Vec3 *xyz, int pos)
|
||||
{
|
||||
xyz->setX(getFloat(pos ));
|
||||
xyz->setY(getFloat(pos+4));
|
||||
xyz->setZ(getFloat(pos+8));
|
||||
return *this;
|
||||
} // addVec3
|
||||
// ------------------------------------------------------------------------
|
||||
/** Reads the four components of a quaternion from the given position. */
|
||||
NetworkString& get(btQuaternion *quat, int pos)
|
||||
{
|
||||
quat->setX(getFloat(pos ));
|
||||
quat->setY(getFloat(pos+ 4));
|
||||
quat->setZ(getFloat(pos+ 8));
|
||||
quat->setW(getFloat(pos+12));
|
||||
return *this;
|
||||
} // addVec3
|
||||
|
||||
}; // class NetworkString
|
||||
|
||||
|
||||
@@ -114,27 +114,53 @@ void Protocol::requestTerminate()
|
||||
} // requestTerminate
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void Protocol::sendMessageToPeersChangingToken(NetworkString prefix,
|
||||
NetworkString message)
|
||||
/** Sends a message to all peers, inserting the peer's token into the message.
|
||||
* The message is composed of a 1-byte message (usually the message type)
|
||||
* followed by the token of this client and then actual message).
|
||||
* \param type The first byte of the combined message.
|
||||
* \param message The actual message content.
|
||||
*/
|
||||
void Protocol::sendMessageToPeersChangingToken(uint8_t type,
|
||||
const NetworkString &message)
|
||||
{
|
||||
const std::vector<STKPeer*> &peers = STKHost::get()->getPeers();
|
||||
for (unsigned int i = 0; i < peers.size(); i++)
|
||||
{
|
||||
prefix.ai8(4).ai32(peers[i]->getClientServerToken());
|
||||
prefix += message;
|
||||
ProtocolManager::getInstance()->sendMessage(this, peers[i], prefix);
|
||||
NetworkString combined(1+4+message.size());
|
||||
combined.addUInt8(type).addUInt8(4)
|
||||
.addUInt32(peers[i]->getClientServerToken());
|
||||
combined+=message;
|
||||
ProtocolManager::getInstance()->sendMessage(this, peers[i], combined);
|
||||
}
|
||||
} // sendMessageToPeersChangingToken
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void Protocol::sendMessage(const NetworkString& message, bool reliable)
|
||||
{
|
||||
ProtocolManager::getInstance()->sendMessage(this, message, reliable);
|
||||
ProtocolManager::getInstance()->sendMessage(this, message, reliable,
|
||||
/*synchronous*/false);
|
||||
} // sendMessage
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void Protocol::sendSynchronousMessage(const NetworkString& message,
|
||||
bool reliable)
|
||||
{
|
||||
ProtocolManager::getInstance()->sendMessage(this, message, reliable,
|
||||
/*synchron*/true);
|
||||
} // sendMessage
|
||||
// ----------------------------------------------------------------------------
|
||||
void Protocol::sendMessage(STKPeer* peer, const NetworkString& message,
|
||||
bool reliable)
|
||||
{
|
||||
ProtocolManager::getInstance()->sendMessage(this, peer, message, reliable);
|
||||
ProtocolManager::getInstance()->sendMessage(this, peer, message, reliable,
|
||||
/*synchronous*/false);
|
||||
} // sendMessage
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void Protocol::sendSynchronousMessage(STKPeer* peer,
|
||||
const NetworkString& message,
|
||||
bool reliable)
|
||||
{
|
||||
ProtocolManager::getInstance()->sendMessage(this, peer, message, reliable,
|
||||
/*synchronous*/true);
|
||||
} // sendSynchronousMessage
|
||||
|
||||
@@ -39,15 +39,16 @@ class STKPeer;
|
||||
*/
|
||||
enum ProtocolType
|
||||
{
|
||||
PROTOCOL_NONE = 0, //!< No protocol type assigned.
|
||||
PROTOCOL_CONNECTION = 1, //!< Protocol that deals with client-server connection.
|
||||
PROTOCOL_LOBBY_ROOM = 2, //!< Protocol that is used during the lobby room phase.
|
||||
PROTOCOL_START_GAME = 3, //!< Protocol used when starting the game.
|
||||
PROTOCOL_SYNCHRONIZATION = 4, //!<Protocol used to synchronize clocks.
|
||||
PROTOCOL_KART_UPDATE = 5, //!< Protocol to update karts position, rotation etc...
|
||||
PROTOCOL_GAME_EVENTS = 6, //!< Protocol to communicate the game events.
|
||||
PROTOCOL_CONTROLLER_EVENTS = 7, //!< Protocol to transfer controller modifications
|
||||
PROTOCOL_SILENT = 0xffff //!< Used for protocols that do not subscribe to any network event.
|
||||
PROTOCOL_NONE = 0x00, //!< No protocol type assigned.
|
||||
PROTOCOL_CONNECTION = 0x01, //!< Protocol that deals with client-server connection.
|
||||
PROTOCOL_LOBBY_ROOM = 0x02, //!< Protocol that is used during the lobby room phase.
|
||||
PROTOCOL_START_GAME = 0x03, //!< Protocol used when starting the game.
|
||||
PROTOCOL_SYNCHRONIZATION = 0x04, //!<Protocol used to synchronize clocks.
|
||||
PROTOCOL_KART_UPDATE = 0x05, //!< Protocol to update karts position, rotation etc...
|
||||
PROTOCOL_GAME_EVENTS = 0x06, //!< Protocol to communicate the game events.
|
||||
PROTOCOL_CONTROLLER_EVENTS = 0x07, //!< Protocol to transfer controller modifications
|
||||
PROTOCOL_SYNCHRONOUS = 0x80, //!< Flag, indicates synchronous delivery
|
||||
PROTOCOL_SILENT = 0xff //!< Used for protocols that do not subscribe to any network event.
|
||||
}; // ProtocolType
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@@ -122,12 +123,16 @@ public:
|
||||
/// 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);
|
||||
void sendMessageToPeersChangingToken(uint8_t type,
|
||||
const NetworkString &message);
|
||||
void sendMessage(const NetworkString& message,
|
||||
bool reliable = true);
|
||||
void sendMessage(STKPeer* peer, const NetworkString& message,
|
||||
bool reliable = true);
|
||||
void sendSynchronousMessage(const NetworkString& message,
|
||||
bool reliable=true);
|
||||
void sendSynchronousMessage(STKPeer* peer, const NetworkString& message,
|
||||
bool reliable = true);
|
||||
void requestStart();
|
||||
void requestPause();
|
||||
void requestUnpause();
|
||||
|
||||
@@ -35,12 +35,8 @@
|
||||
ProtocolManager::ProtocolManager()
|
||||
{
|
||||
pthread_mutex_init(&m_asynchronous_protocols_mutex, NULL);
|
||||
pthread_mutex_init(&m_requests_mutex, NULL);
|
||||
pthread_mutex_init(&m_id_mutex, NULL);
|
||||
pthread_mutex_init(&m_exit_mutex, NULL);
|
||||
m_next_protocol_id = 0;
|
||||
|
||||
pthread_mutex_lock(&m_exit_mutex); // will let the update function run
|
||||
m_exit.setAtomic(false);
|
||||
m_next_protocol_id.setAtomic(0);
|
||||
|
||||
m_asynchronous_update_thread = (pthread_t*)(malloc(sizeof(pthread_t)));
|
||||
pthread_create(m_asynchronous_update_thread, NULL,
|
||||
@@ -54,13 +50,11 @@ void* ProtocolManager::mainLoop(void* data)
|
||||
VS::setThreadName("ProtocolManager");
|
||||
|
||||
ProtocolManager* manager = static_cast<ProtocolManager*>(data);
|
||||
manager->m_asynchronous_thread_running = true;
|
||||
while(manager && !manager->exit())
|
||||
while(manager && !manager->m_exit.getAtomic())
|
||||
{
|
||||
manager->asynchronousUpdate();
|
||||
StkTime::sleep(2);
|
||||
}
|
||||
manager->m_asynchronous_thread_running = false;
|
||||
return NULL;
|
||||
} // protocolManagerAsynchronousUpdate
|
||||
|
||||
@@ -75,30 +69,30 @@ 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
|
||||
m_events_to_process.lock();
|
||||
m_protocols.lock();
|
||||
m_exit.setAtomic(true);
|
||||
pthread_mutex_lock(&m_asynchronous_protocols_mutex);
|
||||
pthread_mutex_lock(&m_requests_mutex);
|
||||
pthread_mutex_lock(&m_id_mutex);
|
||||
|
||||
m_protocols.lock();
|
||||
for (unsigned int i = 0; i < m_protocols.getData().size() ; i++)
|
||||
delete m_protocols.getData()[i];
|
||||
m_protocols.getData().clear();
|
||||
m_protocols.unlock();
|
||||
|
||||
m_events_to_process.lock();
|
||||
for (unsigned int i = 0; i < m_events_to_process.getData().size() ; i++)
|
||||
delete m_events_to_process.getData()[i].m_event;
|
||||
m_protocols.getData().clear();
|
||||
m_requests.clear();
|
||||
m_events_to_process.getData().clear();
|
||||
m_events_to_process.unlock();
|
||||
m_protocols.unlock();
|
||||
|
||||
|
||||
m_requests.lock();
|
||||
m_requests.getData().clear();
|
||||
m_requests.unlock();
|
||||
|
||||
pthread_mutex_unlock(&m_asynchronous_protocols_mutex);
|
||||
pthread_mutex_unlock(&m_requests_mutex);
|
||||
pthread_mutex_unlock(&m_id_mutex);
|
||||
|
||||
pthread_mutex_destroy(&m_asynchronous_protocols_mutex);
|
||||
pthread_mutex_destroy(&m_requests_mutex);
|
||||
pthread_mutex_destroy(&m_id_mutex);
|
||||
pthread_mutex_destroy(&m_exit_mutex);
|
||||
pthread_join(*m_asynchronous_update_thread, NULL); // wait the thread to finish
|
||||
} // abort
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@@ -131,6 +125,14 @@ void ProtocolManager::propagateEvent(Event* event)
|
||||
Log::verbose("ProtocolManager", "Received event for protocols of type %d",
|
||||
searched_protocol);
|
||||
|
||||
bool is_synchronous = false;
|
||||
if(searched_protocol & PROTOCOL_SYNCHRONOUS)
|
||||
{
|
||||
is_synchronous = true;
|
||||
// Reset synchronous flag to restore original protocol id
|
||||
searched_protocol = ProtocolType(searched_protocol &
|
||||
~PROTOCOL_SYNCHRONOUS );
|
||||
}
|
||||
std::vector<unsigned int> protocols_ids;
|
||||
m_protocols.lock();
|
||||
for (unsigned int i = 0; i < m_protocols.getData().size() ; i++)
|
||||
@@ -155,9 +157,10 @@ void ProtocolManager::propagateEvent(Event* event)
|
||||
if (protocols_ids.size() != 0)
|
||||
{
|
||||
EventProcessingInfo epi;
|
||||
epi.m_arrival_time = (double)StkTime::getTimeSinceEpoch();
|
||||
epi.m_event = event;
|
||||
epi.m_protocols_ids = protocols_ids;
|
||||
epi.m_arrival_time = (double)StkTime::getTimeSinceEpoch();
|
||||
epi.m_is_synchronous = is_synchronous;
|
||||
epi.m_event = event;
|
||||
epi.m_protocols_ids = protocols_ids;
|
||||
// Add the event to the queue. After the event is handled
|
||||
// its memory will be freed.
|
||||
m_events_to_process.getData().push_back(epi);
|
||||
@@ -175,20 +178,29 @@ void ProtocolManager::propagateEvent(Event* event)
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void ProtocolManager::sendMessage(Protocol* sender, const NetworkString& message,
|
||||
bool reliable)
|
||||
bool reliable, bool send_synchronously)
|
||||
{
|
||||
NetworkString new_message(1+message.size());
|
||||
new_message.ai8(sender->getProtocolType()); // add one byte to add protocol type
|
||||
ProtocolType type = sender->getProtocolType();
|
||||
// Set flag if the message must be handled synchronously on arrivat
|
||||
if(send_synchronously)
|
||||
type = ProtocolType(type | PROTOCOL_SYNCHRONOUS);
|
||||
new_message.ai8(type); // add one byte to add protocol type
|
||||
new_message += message;
|
||||
STKHost::get()->sendMessage(new_message, reliable);
|
||||
} // sendMessage
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void ProtocolManager::sendMessage(Protocol* sender, STKPeer* peer,
|
||||
const NetworkString& message, bool reliable)
|
||||
const NetworkString& message, bool reliable,
|
||||
bool send_synchronously)
|
||||
{
|
||||
NetworkString new_message(1+message.size());
|
||||
new_message.ai8(sender->getProtocolType()); // add one byte to add protocol type
|
||||
ProtocolType type = sender->getProtocolType();
|
||||
// Set flag if the message must be handled synchronously on arrivat
|
||||
if(send_synchronously)
|
||||
type = ProtocolType(type | PROTOCOL_SYNCHRONOUS);
|
||||
new_message.ai8(type); // add one byte to add protocol type
|
||||
new_message += message;
|
||||
peer->sendPacket(new_message, reliable);
|
||||
} // sendMessage
|
||||
@@ -218,9 +230,9 @@ uint32_t ProtocolManager::requestStart(Protocol* protocol)
|
||||
// create the request
|
||||
ProtocolRequest req(PROTOCOL_REQUEST_START, protocol);
|
||||
// add it to the request stack
|
||||
pthread_mutex_lock(&m_requests_mutex);
|
||||
m_requests.push_back(req);
|
||||
pthread_mutex_unlock(&m_requests_mutex);
|
||||
m_requests.lock();
|
||||
m_requests.getData().push_back(req);
|
||||
m_requests.unlock();
|
||||
|
||||
return req.getProtocol()->getId();
|
||||
} // requestStart
|
||||
@@ -238,9 +250,9 @@ void ProtocolManager::requestPause(Protocol* protocol)
|
||||
// create the request
|
||||
ProtocolRequest req(PROTOCOL_REQUEST_PAUSE, protocol);
|
||||
// add it to the request stack
|
||||
pthread_mutex_lock(&m_requests_mutex);
|
||||
m_requests.push_back(req);
|
||||
pthread_mutex_unlock(&m_requests_mutex);
|
||||
m_requests.lock();
|
||||
m_requests.getData().push_back(req);
|
||||
m_requests.unlock();
|
||||
} // requestPause
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@@ -256,9 +268,9 @@ void ProtocolManager::requestUnpause(Protocol* protocol)
|
||||
// create the request
|
||||
ProtocolRequest req(PROTOCOL_REQUEST_UNPAUSE, protocol);;
|
||||
// add it to the request stack
|
||||
pthread_mutex_lock(&m_requests_mutex);
|
||||
m_requests.push_back(req);
|
||||
pthread_mutex_unlock(&m_requests_mutex);
|
||||
m_requests.lock();
|
||||
m_requests.getData().push_back(req);
|
||||
m_requests.unlock();
|
||||
} // requestUnpause
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@@ -274,18 +286,18 @@ void ProtocolManager::requestTerminate(Protocol* protocol)
|
||||
// create the request
|
||||
ProtocolRequest req(PROTOCOL_REQUEST_TERMINATE, protocol);
|
||||
// add it to the request stack
|
||||
pthread_mutex_lock(&m_requests_mutex);
|
||||
m_requests.lock();
|
||||
// check that the request does not already exist :
|
||||
for (unsigned int i = 0; i < m_requests.size(); i++)
|
||||
for (unsigned int i = 0; i < m_requests.getData().size(); i++)
|
||||
{
|
||||
if (m_requests[i].m_protocol == protocol)
|
||||
if (m_requests.getData()[i].m_protocol == protocol)
|
||||
{
|
||||
pthread_mutex_unlock(&m_requests_mutex);
|
||||
m_requests.unlock();
|
||||
return;
|
||||
}
|
||||
}
|
||||
m_requests.push_back(req);
|
||||
pthread_mutex_unlock(&m_requests_mutex);
|
||||
m_requests.getData().push_back(req);
|
||||
m_requests.unlock();
|
||||
} // requestTerminate
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@@ -295,7 +307,6 @@ void ProtocolManager::requestTerminate(Protocol* protocol)
|
||||
*/
|
||||
void ProtocolManager::startProtocol(Protocol *protocol)
|
||||
{
|
||||
// assert(protocol_info.m_state == PROTOCOL_STATE_INITIALISING);
|
||||
// add the protocol to the protocol vector so that it's updated
|
||||
m_protocols.lock();
|
||||
pthread_mutex_lock(&m_asynchronous_protocols_mutex);
|
||||
@@ -370,7 +381,6 @@ void ProtocolManager::terminateProtocol(Protocol *protocol)
|
||||
*/
|
||||
bool ProtocolManager::sendEvent(EventProcessingInfo* event, bool synchronous)
|
||||
{
|
||||
m_protocols.lock();
|
||||
unsigned int index = 0;
|
||||
while(index < event->m_protocols_ids.size())
|
||||
{
|
||||
@@ -389,7 +399,6 @@ bool ProtocolManager::sendEvent(EventProcessingInfo* event, bool synchronous)
|
||||
else // !result
|
||||
index++;
|
||||
}
|
||||
m_protocols.unlock();
|
||||
|
||||
if (event->m_protocols_ids.size() == 0 ||
|
||||
(StkTime::getTimeSinceEpoch()-event->m_arrival_time) >= TIME_TO_KEEP_EVENTS)
|
||||
@@ -418,12 +427,14 @@ void ProtocolManager::update()
|
||||
int offset = 0;
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
// Don't handle asynchronous events here.
|
||||
if(!m_events_to_process.getData()[i+offset].m_is_synchronous) continue;
|
||||
bool result = sendEvent(&m_events_to_process.getData()[i+offset], true);
|
||||
if (result)
|
||||
{
|
||||
m_events_to_process.getData()
|
||||
.erase(m_events_to_process.getData().begin()+i+offset,
|
||||
m_events_to_process.getData().begin()+i+offset+1);
|
||||
.erase(m_events_to_process.getData().begin()+(i+offset),
|
||||
m_events_to_process.getData().begin()+(i+offset+1));
|
||||
offset --;
|
||||
}
|
||||
}
|
||||
@@ -455,6 +466,8 @@ void ProtocolManager::asynchronousUpdate()
|
||||
int offset = 0;
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
// Don't handle synchronous events here.
|
||||
if(m_events_to_process.getData()[i+offset].m_is_synchronous) continue;
|
||||
bool result = sendEvent(&m_events_to_process.getData()[i+offset], false);
|
||||
if (result)
|
||||
{
|
||||
@@ -478,12 +491,12 @@ void ProtocolManager::asynchronousUpdate()
|
||||
|
||||
// Process queued events for protocols
|
||||
// these requests are asynchronous
|
||||
pthread_mutex_lock(&m_requests_mutex);
|
||||
while(m_requests.size()>0)
|
||||
m_requests.lock();
|
||||
while(m_requests.getData().size()>0)
|
||||
{
|
||||
ProtocolRequest request = m_requests[0];
|
||||
m_requests.erase(m_requests.begin());
|
||||
pthread_mutex_unlock(&m_requests_mutex);
|
||||
ProtocolRequest request = m_requests.getData()[0];
|
||||
m_requests.getData().erase(m_requests.getData().begin());
|
||||
m_requests.unlock();
|
||||
// Make sure new requests can be queued up while handling requests.
|
||||
// This is often used that terminating a protocol unpauses another,
|
||||
// so the m_requests queue must not be locked while executing requests.
|
||||
@@ -502,27 +515,11 @@ void ProtocolManager::asynchronousUpdate()
|
||||
terminateProtocol(request.getProtocol());
|
||||
break;
|
||||
} // switch (type)
|
||||
pthread_mutex_lock(&m_requests_mutex);
|
||||
m_requests.lock();
|
||||
} // while m_requests.size()>0
|
||||
pthread_mutex_unlock(&m_requests_mutex);
|
||||
m_requests.unlock();
|
||||
} // asynchronousUpdate
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** \brief Get the id of a protocol.
|
||||
* \param protocol : A pointer to the protocol you seek the id.
|
||||
* \return The id of the protocol pointed by the protocol parameter.
|
||||
*/
|
||||
uint32_t ProtocolManager::getProtocolID(Protocol* protocol)
|
||||
{
|
||||
// FIXME: Does this need to be locked?
|
||||
for (unsigned int i = 0; i < m_protocols.getData().size(); i++)
|
||||
{
|
||||
if (m_protocols.getData()[i] == protocol)
|
||||
return m_protocols.getData()[i]->getId();
|
||||
}
|
||||
return 0;
|
||||
} // getProtocolID
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** \brief Get a protocol using its id.
|
||||
* \param id : Unique ID of the seek protocol.
|
||||
@@ -555,21 +552,6 @@ Protocol* ProtocolManager::getProtocol(ProtocolType type)
|
||||
return NULL;
|
||||
} // getProtocol
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/*! \brief Tells if we need to stop the update thread.
|
||||
*/
|
||||
int ProtocolManager::exit()
|
||||
{
|
||||
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;
|
||||
} // exit
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** \brief Assign an id to a protocol.
|
||||
* This function will assign m_next_protocol_id as the protocol id.
|
||||
@@ -579,10 +561,10 @@ int ProtocolManager::exit()
|
||||
*/
|
||||
uint32_t ProtocolManager::getNextProtocolId()
|
||||
{
|
||||
pthread_mutex_lock(&m_id_mutex);
|
||||
uint32_t id = m_next_protocol_id;
|
||||
m_next_protocol_id++;
|
||||
pthread_mutex_unlock(&m_id_mutex);
|
||||
m_next_protocol_id.lock();
|
||||
uint32_t id = m_next_protocol_id.getData();
|
||||
m_next_protocol_id.getData()++;
|
||||
m_next_protocol_id.unlock();
|
||||
return id;
|
||||
} // getNextProtocolId
|
||||
|
||||
|
||||
@@ -78,18 +78,29 @@ public:
|
||||
Protocol *getProtocol() { return m_protocol; }
|
||||
}; // class ProtocolRequest;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// ============================================================================
|
||||
/** \struct ProtocolRequest
|
||||
* \brief Used to pass the event to protocols that need it
|
||||
*/
|
||||
typedef struct EventProcessingInfo
|
||||
struct EventProcessingInfo
|
||||
{
|
||||
/** The event to process. */
|
||||
Event* m_event;
|
||||
double m_arrival_time;
|
||||
std::vector<unsigned int> m_protocols_ids;
|
||||
} EventProcessingInfo;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Arrival time of the event. Used to time out events that are not
|
||||
* handled in time (e.g. because the receiving protocol is not running).*/
|
||||
double m_arrival_time;
|
||||
|
||||
/** The list of protocol ids to which this event can be
|
||||
* sent to. */
|
||||
std::vector<unsigned int> m_protocols_ids;
|
||||
|
||||
/** Indicates if this received message must be handled synchronously or
|
||||
* asynchronously. */
|
||||
bool m_is_synchronous;
|
||||
}; // EventProcessingInfo
|
||||
|
||||
// ============================================================================
|
||||
/** \class ProtocolManager
|
||||
* \brief Manages the protocols at runtime.
|
||||
*
|
||||
@@ -105,84 +116,70 @@ class ProtocolManager : public AbstractSingleton<ProtocolManager>,
|
||||
public NoCopy
|
||||
{
|
||||
friend class AbstractSingleton<ProtocolManager>;
|
||||
private:
|
||||
|
||||
/** Contains the running protocols.
|
||||
* This stores the protocols that are either running or paused, their
|
||||
* state and their unique id. */
|
||||
Synchronised<std::vector<Protocol*> >m_protocols;
|
||||
|
||||
/** Contains the network events to pass asynchronously to protocols
|
||||
* (i.e. from the separate ProtocolManager thread). */
|
||||
Synchronised<std::vector<EventProcessingInfo> > m_events_to_process;
|
||||
|
||||
/** Contains the requests to start/pause etc... protocols. */
|
||||
Synchronised< std::vector<ProtocolRequest> > m_requests;
|
||||
|
||||
/*! \brief The next id to assign to a protocol.
|
||||
* This value is incremented by 1 each time a protocol is started.
|
||||
* If a protocol has an id lower than this value, it means that it has
|
||||
* been formerly started.
|
||||
*/
|
||||
Synchronised<uint32_t> m_next_protocol_id;
|
||||
|
||||
/** When set to true, the main thread will exit. */
|
||||
Synchronised<bool> m_exit;
|
||||
|
||||
// mutexes:
|
||||
/*! Used to ensure that the protocol vector is used thread-safely. */
|
||||
pthread_mutex_t m_asynchronous_protocols_mutex;
|
||||
|
||||
/*! Asynchronous update thread.*/
|
||||
pthread_t* m_asynchronous_update_thread;
|
||||
|
||||
ProtocolManager();
|
||||
virtual ~ProtocolManager();
|
||||
static void* mainLoop(void *data);
|
||||
public:
|
||||
|
||||
virtual void abort();
|
||||
virtual void propagateEvent(Event* event);
|
||||
virtual void sendMessage(Protocol* sender,
|
||||
const NetworkString& message,
|
||||
bool reliable = true);
|
||||
virtual void sendMessage(Protocol* sender, STKPeer* peer,
|
||||
const NetworkString& message,
|
||||
bool reliable = true);
|
||||
virtual void sendMessageExcept(Protocol* sender, STKPeer* peer,
|
||||
const NetworkString& message,
|
||||
bool reliable = true);
|
||||
virtual uint32_t requestStart(Protocol* protocol);
|
||||
virtual void requestPause(Protocol* protocol);
|
||||
virtual void requestUnpause(Protocol* protocol);
|
||||
virtual void requestTerminate(Protocol* protocol);
|
||||
virtual void startProtocol(Protocol *protocol);
|
||||
virtual void pauseProtocol(Protocol *protocol);
|
||||
virtual void unpauseProtocol(Protocol *protocol);
|
||||
virtual void terminateProtocol(Protocol *protocol);
|
||||
virtual void update();
|
||||
virtual void asynchronousUpdate();
|
||||
virtual uint32_t getProtocolID(Protocol* protocol);
|
||||
virtual Protocol* getProtocol(uint32_t id);
|
||||
virtual Protocol* getProtocol(ProtocolType type);
|
||||
int exit();
|
||||
uint32_t getNextProtocolId();
|
||||
bool sendEvent(EventProcessingInfo* event, bool synchronous);
|
||||
|
||||
protected:
|
||||
// protected functions
|
||||
/*!
|
||||
* \brief Constructor
|
||||
*/
|
||||
ProtocolManager();
|
||||
/*!
|
||||
* \brief Destructor
|
||||
*/
|
||||
virtual ~ProtocolManager();
|
||||
uint32_t getNextProtocolId();
|
||||
virtual void startProtocol(Protocol *protocol);
|
||||
virtual void terminateProtocol(Protocol *protocol);
|
||||
virtual void asynchronousUpdate();
|
||||
virtual void pauseProtocol(Protocol *protocol);
|
||||
virtual void unpauseProtocol(Protocol *protocol);
|
||||
|
||||
bool sendEvent(EventProcessingInfo* event, bool synchronous);
|
||||
|
||||
// protected members
|
||||
/** Contains the running protocols.
|
||||
* This stores the protocols that are either running or paused, their
|
||||
* state and their unique id. */
|
||||
Synchronised<std::vector<Protocol*> >m_protocols;
|
||||
|
||||
/** Contains the network events to pass to protocols. */
|
||||
Synchronised<std::vector<EventProcessingInfo> > m_events_to_process;
|
||||
|
||||
/** Contains the requests to start/pause etc... protocols. */
|
||||
std::vector<ProtocolRequest> m_requests;
|
||||
/*! \brief The next id to assign to a protocol.
|
||||
* This value is incremented by 1 each time a protocol is started.
|
||||
* If a protocol has an id lower than this value, it means that it have
|
||||
* been formerly started.
|
||||
*/
|
||||
uint32_t m_next_protocol_id;
|
||||
|
||||
// mutexes:
|
||||
/*! Used to ensure that the protocol vector is used thread-safely. */
|
||||
pthread_mutex_t m_asynchronous_protocols_mutex;
|
||||
/*! Used to ensure that the request vector is used thread-safely. */
|
||||
pthread_mutex_t m_requests_mutex;
|
||||
/*! Used to ensure that the protocol id is used in a thread-safe way.*/
|
||||
pthread_mutex_t m_id_mutex;
|
||||
/*! Used when need to quit.*/
|
||||
pthread_mutex_t m_exit_mutex;
|
||||
|
||||
/*! Update thread.*/
|
||||
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;
|
||||
|
||||
};
|
||||
public:
|
||||
virtual void abort();
|
||||
virtual void propagateEvent(Event* event);
|
||||
virtual void sendMessage(Protocol* sender,
|
||||
const NetworkString& message,
|
||||
bool reliable = true,
|
||||
bool send_synchronously = false);
|
||||
virtual void sendMessage(Protocol* sender, STKPeer* peer,
|
||||
const NetworkString& message,
|
||||
bool reliable = true,
|
||||
bool send_synchronously = false);
|
||||
virtual void sendMessageExcept(Protocol* sender, STKPeer* peer,
|
||||
const NetworkString& message,
|
||||
bool reliable = true);
|
||||
virtual uint32_t requestStart(Protocol* protocol);
|
||||
virtual void requestPause(Protocol* protocol);
|
||||
virtual void requestUnpause(Protocol* protocol);
|
||||
virtual void requestTerminate(Protocol* protocol);
|
||||
virtual void update();
|
||||
virtual Protocol* getProtocol(uint32_t id);
|
||||
virtual Protocol* getProtocol(ProtocolType type);
|
||||
}; // class ProtocolManager
|
||||
|
||||
#endif // PROTOCOL_MANAGER_HPP
|
||||
|
||||
@@ -21,10 +21,11 @@
|
||||
#include "config/player_manager.hpp"
|
||||
#include "modes/world_with_rank.hpp"
|
||||
#include "network/event.hpp"
|
||||
#include "network/network_config.hpp"
|
||||
#include "network/network_player_profile.hpp"
|
||||
#include "network/network_world.hpp"
|
||||
#include "network/protocols/start_game_protocol.hpp"
|
||||
#include "network/protocol_manager.hpp"
|
||||
#include "network/race_event_manager.hpp"
|
||||
#include "network/stk_host.hpp"
|
||||
#include "network/stk_peer.hpp"
|
||||
#include "online/online_profile.hpp"
|
||||
@@ -180,9 +181,6 @@ bool ClientLobbyRoomProtocol::notifyEventAsynchronous(Event* event)
|
||||
const NetworkString &data = event->data();
|
||||
assert(data.size()); // assert that data isn't empty
|
||||
uint8_t message_type = data[0];
|
||||
if (message_type == LE_KART_SELECTION_UPDATE ||
|
||||
message_type == LE_RACE_FINISHED )
|
||||
return false; // don't treat the event
|
||||
|
||||
event->removeFront(1);
|
||||
Log::info("ClientLobbyRoomProtocol", "Asynchronous message of type %d",
|
||||
@@ -245,9 +243,11 @@ void ClientLobbyRoomProtocol::update()
|
||||
name = PlayerManager::getCurrentPlayer()->getName();
|
||||
|
||||
std::string name_u8 = StringUtils::wideToUtf8(name);
|
||||
NetworkString ns(6+1+name_u8.size());
|
||||
const std::string &password = NetworkConfig::get()->getPassword();
|
||||
NetworkString ns(6+1+name_u8.size()+1+password.size());
|
||||
// 4 (size of id), global id
|
||||
ns.ai8(LE_CONNECTION_REQUESTED).encodeString(name);
|
||||
ns.ai8(LE_CONNECTION_REQUESTED).encodeString(name)
|
||||
.encodeString(NetworkConfig::get()->getPassword());
|
||||
sendMessage(ns);
|
||||
m_state = REQUESTING_CONNECTION;
|
||||
}
|
||||
@@ -269,7 +269,7 @@ void ClientLobbyRoomProtocol::update()
|
||||
case PLAYING:
|
||||
{
|
||||
// race is now over, kill race protocols and return to connected state
|
||||
if (NetworkWorld::getInstance<NetworkWorld>()->isRaceOver())
|
||||
if (RaceEventManager::getInstance<RaceEventManager>()->isRaceOver())
|
||||
{
|
||||
Log::info("ClientLobbyRoomProtocol", "Game finished.");
|
||||
m_state = RACE_FINISHED;
|
||||
@@ -375,17 +375,17 @@ void ClientLobbyRoomProtocol::disconnectedPlayer(Event* event)
|
||||
* \param event : Event providing the information.
|
||||
*
|
||||
* Format of the data :
|
||||
* Byte 0 1 2 3 7 8
|
||||
* ------------------------------------------------------------------
|
||||
* Size | 1 | 1 | 1 | 4 | 1 | |
|
||||
* Data | 1 | 0 <= race id < 16 | 4 | priv token | hostid | playernames* |
|
||||
* ------------------------------------------------------------------
|
||||
* Byte 0 1 2 3 7 8 9
|
||||
* -----------------------------------------------------------------------------
|
||||
* Size | 1 | 1 | 1 | 4 | 1 | 1 | |
|
||||
* Data | 1 | 0 <= race id < 16 | 4 | priv token | hostid | authorised |playernames* |
|
||||
* ------------------------------------------------------------------------------
|
||||
*/
|
||||
void ClientLobbyRoomProtocol::connectionAccepted(Event* event)
|
||||
{
|
||||
NetworkString &data = event->data();
|
||||
// At least 12 bytes should remain now
|
||||
if (data.size() < 8|| data[0] != 1 || data[2] != 4)
|
||||
if (data.size() < 9|| data[0] != 1 || data[2] != 4)
|
||||
{
|
||||
Log::error("ClientLobbyRoomProtocol",
|
||||
"A message notifying an accepted connection wasn't "
|
||||
@@ -407,22 +407,23 @@ void ClientLobbyRoomProtocol::connectionAccepted(Event* event)
|
||||
name = PlayerManager::getCurrentPlayer()->getName();
|
||||
uint8_t my_player_id = data.getUInt8(1);
|
||||
uint8_t my_host_id = data.getUInt8(7);
|
||||
uint8_t authorised = data.getUInt8(8);
|
||||
// Store this client's authorisation status in the peer information
|
||||
// for the server.
|
||||
event->getPeer()->setAuthorised(authorised!=0);
|
||||
STKHost::get()->setMyHostId(my_host_id);
|
||||
|
||||
NetworkPlayerProfile* profile = new NetworkPlayerProfile(my_player_id, name);
|
||||
profile->setHostId(my_host_id);
|
||||
STKHost::get()->getGameSetup()->setLocalMaster(my_player_id);
|
||||
m_setup->setNumLocalPlayers(1);
|
||||
m_setup->addPlayer(profile);
|
||||
// connection token
|
||||
uint32_t token = data.gui32(3);
|
||||
peer->setClientServerToken(token);
|
||||
NetworkingLobby::getInstance()->addPlayer(profile);
|
||||
|
||||
|
||||
// Add all players
|
||||
// ===============
|
||||
int n = 8;
|
||||
int n = 9;
|
||||
while (n < data.size())
|
||||
{
|
||||
if (data[n] != 1 )
|
||||
@@ -436,6 +437,7 @@ void ClientLobbyRoomProtocol::connectionAccepted(Event* event)
|
||||
|
||||
NetworkPlayerProfile* profile2 =
|
||||
new NetworkPlayerProfile(player_id, name);
|
||||
profile2->setHostId(host_id);
|
||||
m_setup->addPlayer(profile2);
|
||||
n += bytes_read+3;
|
||||
// Inform the network lobby of all players so that the GUI can
|
||||
@@ -443,7 +445,10 @@ void ClientLobbyRoomProtocol::connectionAccepted(Event* event)
|
||||
NetworkingLobby::getInstance()->addPlayer(profile2);
|
||||
}
|
||||
|
||||
// add self
|
||||
// Add self after other players so that player order is identical
|
||||
// on server and all clients.
|
||||
m_setup->addPlayer(profile);
|
||||
NetworkingLobby::getInstance()->addPlayer(profile);
|
||||
m_server = event->getPeer();
|
||||
m_state = CONNECTED;
|
||||
} // connectionAccepted
|
||||
|
||||
@@ -111,7 +111,7 @@ void ConnectToServer::asynchronousUpdate()
|
||||
m_current_protocol->requestStart();
|
||||
// This protocol will be unpaused in the callback from
|
||||
// GetPublicAddress
|
||||
ProtocolManager::getInstance()->pauseProtocol(this);
|
||||
requestPause();
|
||||
m_state = GETTING_SELF_ADDRESS;
|
||||
break;
|
||||
}
|
||||
@@ -138,7 +138,7 @@ void ConnectToServer::asynchronousUpdate()
|
||||
m_state = GOT_SERVER_ADDRESS;
|
||||
// Pause this protocol till GetPeerAddress finishes.
|
||||
// The callback then will unpause this protocol/
|
||||
ProtocolManager::getInstance()->pauseProtocol(this);
|
||||
requestPause();
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -266,12 +266,12 @@ void ConnectToServer::callback(Protocol *protocol)
|
||||
case GETTING_SELF_ADDRESS:
|
||||
// The GetPublicAddress protocol stores our address in
|
||||
// STKHost, so we only need to unpause this protocol
|
||||
ProtocolManager::getInstance()->unpauseProtocol(this);
|
||||
requestUnpause();
|
||||
break;
|
||||
case GOT_SERVER_ADDRESS:
|
||||
// Get the server address from the protocol.
|
||||
m_server_address.copy(((GetPeerAddress*)protocol)->getAddress());
|
||||
ProtocolManager::getInstance()->unpauseProtocol(this);
|
||||
requestUnpause();
|
||||
break;
|
||||
default:
|
||||
Log::error("ConnectToServer",
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
#include "network/network_player_profile.hpp"
|
||||
#include "network/game_setup.hpp"
|
||||
#include "network/network_config.hpp"
|
||||
#include "network/network_world.hpp"
|
||||
#include "network/protocol_manager.hpp"
|
||||
#include "network/stk_host.hpp"
|
||||
#include "network/stk_peer.hpp"
|
||||
@@ -44,51 +43,6 @@ ControllerEventsProtocol::~ControllerEventsProtocol()
|
||||
{
|
||||
} // ~ControllerEventsProtocol
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Sets up the mapping of KartController and STKPeer.
|
||||
*/
|
||||
void ControllerEventsProtocol::setup()
|
||||
{
|
||||
m_self_controller_index = 0;
|
||||
std::vector<AbstractKart*> karts = World::getWorld()->getKarts();
|
||||
const std::vector<STKPeer*> &peers = STKHost::get()->getPeers();
|
||||
for (unsigned int i = 0; i < karts.size(); i++)
|
||||
{
|
||||
if (karts[i]->getIdent() == NetworkWorld::getInstance()->getSelfKart())
|
||||
{
|
||||
Log::info("ControllerEventsProtocol", "My id is %d", i);
|
||||
m_self_controller_index = i;
|
||||
}
|
||||
STKPeer* peer = NULL;
|
||||
if (NetworkConfig::get()->isServer())
|
||||
{
|
||||
for (unsigned int j = 0; j < peers.size(); j++)
|
||||
{
|
||||
if (peers[j]->getPlayerProfile()->getKartName()
|
||||
== karts[i]->getIdent())
|
||||
{
|
||||
peer = peers[j];
|
||||
}
|
||||
Log::info("ControllerEventsProtocol", "Compared %s and %s",
|
||||
peers[j]->getPlayerProfile()->getKartName().c_str(),
|
||||
karts[i]->getIdent().c_str());
|
||||
} // for j in peers
|
||||
}
|
||||
else // isClient
|
||||
{
|
||||
if (peers.size() > 0)
|
||||
peer = peers[0];
|
||||
}
|
||||
if (peer == NULL)
|
||||
{
|
||||
Log::error("ControllerEventsProtocol",
|
||||
"Could not find the peer corresponding to the kart.");
|
||||
}
|
||||
m_controllers.push_back(
|
||||
std::pair<Controller*, STKPeer*>(karts[i]->getController(), peer));
|
||||
}
|
||||
} // setup
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
bool ControllerEventsProtocol::notifyEventAsynchronous(Event* event)
|
||||
@@ -118,22 +72,28 @@ bool ControllerEventsProtocol::notifyEventAsynchronous(Event* event)
|
||||
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);
|
||||
PlayerAction action = (PlayerAction)(ns.gui8(4));
|
||||
int action_value = ns.gui32(5);
|
||||
//uint8_t controller_index = ns.gui8();
|
||||
uint8_t kart_id = ns.getUInt8();
|
||||
if (kart_id >=World::getWorld()->getNumKarts())
|
||||
{
|
||||
Log::warn("ControllerEventProtocol", "No valid kart id (%s).",
|
||||
kart_id);
|
||||
return true;
|
||||
}
|
||||
uint8_t serialized_1 = ns.gui8(1);
|
||||
PlayerAction action = (PlayerAction)(ns.gui8(4));
|
||||
int action_value = ns.gui32(5);
|
||||
Controller *controller = World::getWorld()->getKart(kart_id)
|
||||
->getController();
|
||||
KartControl *controls = controller->getControls();
|
||||
controls->m_brake = (serialized_1 & 0x40)!=0;
|
||||
controls->m_nitro = (serialized_1 & 0x20)!=0;
|
||||
controls->m_rescue = (serialized_1 & 0x10)!=0;
|
||||
controls->m_fire = (serialized_1 & 0x08)!=0;
|
||||
controls->m_look_back = (serialized_1 & 0x04)!=0;
|
||||
controls->m_skid = KartControl::SkidControl(serialized_1 & 0x03);
|
||||
|
||||
KartControl* controls = m_controllers[controller_index].first
|
||||
->getControls();
|
||||
controls->m_brake = (serialized_1 & 0x40)!=0;
|
||||
controls->m_nitro = (serialized_1 & 0x20)!=0;
|
||||
controls->m_rescue = (serialized_1 & 0x10)!=0;
|
||||
controls->m_fire = (serialized_1 & 0x08)!=0;
|
||||
controls->m_look_back = (serialized_1 & 0x04)!=0;
|
||||
controls->m_skid = KartControl::SkidControl(serialized_1 & 0x03);
|
||||
|
||||
m_controllers[controller_index].first->action(action, action_value);
|
||||
controller->action(action, action_value);
|
||||
ns.removeFront(9);
|
||||
//Log::info("ControllerEventProtocol", "Registered one action.");
|
||||
}
|
||||
@@ -143,26 +103,24 @@ bool ControllerEventsProtocol::notifyEventAsynchronous(Event* event)
|
||||
"The data seems corrupted. Remains %d", ns.size());
|
||||
return true;
|
||||
}
|
||||
if (client_index < 0)
|
||||
{
|
||||
Log::warn("ControllerEventProtocol", "Couldn't have a client id.");
|
||||
return true;
|
||||
}
|
||||
if (NetworkConfig::get()->isServer())
|
||||
{
|
||||
// notify everybody of the event :
|
||||
for (unsigned int i = 0; i < m_controllers.size(); i++)
|
||||
const std::vector<STKPeer*> &peers = STKHost::get()->getPeers();
|
||||
for(unsigned int i=0; i<peers.size(); i++)
|
||||
{
|
||||
if (i == client_index) // don't send that message to the sender
|
||||
continue;
|
||||
NetworkString ns2(4+pure_message.size());
|
||||
ns2.ai32(m_controllers[i].second->getClientServerToken());
|
||||
ns2 += pure_message;
|
||||
ProtocolManager::getInstance()
|
||||
->sendMessage(this, m_controllers[i].second, ns2,
|
||||
false);
|
||||
}
|
||||
}
|
||||
STKPeer *peer = peers[i];
|
||||
// Don't send message to the host from which the message
|
||||
// was sent from originally
|
||||
if(peer != event->getPeer())
|
||||
{
|
||||
NetworkString ns2(4+pure_message.size());
|
||||
ns2.ai32(peer->getClientServerToken());
|
||||
ns2 += pure_message;
|
||||
ProtocolManager::getInstance()->sendMessage(this, peer,
|
||||
ns2, false);
|
||||
} // if peer != event->getPeer()
|
||||
} // for i in peers
|
||||
} // if server
|
||||
return true;
|
||||
} // notifyEventAsynchronous
|
||||
|
||||
@@ -202,10 +160,10 @@ void ControllerEventsProtocol::controllerAction(Controller* controller,
|
||||
uint8_t serialized_3 = (uint8_t)(controls->m_steer*127.0);
|
||||
|
||||
NetworkString ns(17);
|
||||
ns.ai32(m_controllers[m_self_controller_index].second
|
||||
->getClientServerToken());
|
||||
uint32_t token = STKHost::get()->getPeers()[0]->getClientServerToken();
|
||||
ns.ai32(token);
|
||||
ns.af(World::getWorld()->getTime());
|
||||
ns.ai8(m_self_controller_index);
|
||||
ns.addUInt8(controller->getKart()->getWorldKartId());
|
||||
ns.ai8(serialized_1).ai8(serialized_2).ai8(serialized_3);
|
||||
ns.ai8((uint8_t)(action)).ai32(value);
|
||||
|
||||
|
||||
@@ -28,17 +28,14 @@ class STKPeer;
|
||||
|
||||
class ControllerEventsProtocol : public Protocol
|
||||
{
|
||||
protected:
|
||||
std::vector<std::pair<Controller*, STKPeer*> > m_controllers;
|
||||
uint32_t m_self_controller_index;
|
||||
|
||||
public:
|
||||
ControllerEventsProtocol();
|
||||
ControllerEventsProtocol();
|
||||
virtual ~ControllerEventsProtocol();
|
||||
|
||||
virtual bool notifyEventAsynchronous(Event* event);
|
||||
virtual void setup();
|
||||
virtual void update();
|
||||
virtual void setup() {};
|
||||
virtual void asynchronousUpdate() {}
|
||||
|
||||
void controllerAction(Controller* controller, PlayerAction action,
|
||||
|
||||
@@ -8,13 +8,22 @@
|
||||
#include "modes/world.hpp"
|
||||
#include "network/event.hpp"
|
||||
#include "network/game_setup.hpp"
|
||||
#include "network/network_player_profile.hpp"
|
||||
#include "network/protocol_manager.hpp"
|
||||
#include "network/stk_host.hpp"
|
||||
#include "network/stk_peer.hpp"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/** This class handles all 'major' game events. E.g. collecting an item,
|
||||
* finishing a race etc. The game events manager is notified from the
|
||||
* game code, and it calls the corresponding function in this class.
|
||||
* The server then notifies all clients. Clients receive the message
|
||||
* in the synchronous notifyEvent function here, decode the message
|
||||
* and call the original game code. The functions name are identical,
|
||||
* e.g. kartFinishedRace(some parameter) is called from the GameEventManager
|
||||
* on the server, and the received message is then handled by
|
||||
* kartFinishedRace(const NetworkString &).
|
||||
*/
|
||||
GameEventsProtocol::GameEventsProtocol() : Protocol(PROTOCOL_GAME_EVENTS)
|
||||
{
|
||||
} // GameEventsProtocol
|
||||
@@ -44,27 +53,10 @@ bool GameEventsProtocol::notifyEvent(Event* event)
|
||||
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 player_id = data.gui8(5);
|
||||
// now set the kart powerup
|
||||
AbstractKart* kart = World::getWorld()->getKart(
|
||||
STKHost::get()->getGameSetup()
|
||||
->getProfile(player_id)->getWorldKartID());
|
||||
ItemManager::get()->collectedItem(
|
||||
ItemManager::get()->getItem(item_id),
|
||||
kart,
|
||||
powerup_type);
|
||||
Log::info("GameEventsProtocol", "Item %d picked by a player.",
|
||||
powerup_type);
|
||||
} break;
|
||||
case GE_ITEM_COLLECTED:
|
||||
collectedItem(data); break;
|
||||
case GE_KART_FINISHED_RACE:
|
||||
kartFinishedRace(data); break;
|
||||
default:
|
||||
Log::warn("GameEventsProtocol", "Unkown message type.");
|
||||
break;
|
||||
@@ -83,20 +75,19 @@ void GameEventsProtocol::update()
|
||||
} // update
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Called on the server when an item is collected.
|
||||
*/
|
||||
void GameEventsProtocol::collectedItem(Item* item, AbstractKart* kart)
|
||||
{
|
||||
GameSetup* setup = STKHost::get()->getGameSetup();
|
||||
assert(setup);
|
||||
// use kart name
|
||||
const NetworkPlayerProfile* player_profile =
|
||||
setup->getProfile(kart->getIdent());
|
||||
|
||||
const std::vector<STKPeer*> &peers = STKHost::get()->getPeers();
|
||||
for (unsigned int i = 0; i < peers.size(); i++)
|
||||
{
|
||||
NetworkString ns(11);
|
||||
ns.ai32(peers[i]->getClientServerToken());
|
||||
// 0x01 : item picked : send item id, powerup type and kart race id
|
||||
// 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());
|
||||
@@ -104,12 +95,69 @@ void GameEventsProtocol::collectedItem(Item* item, AbstractKart* kart)
|
||||
powerup = (((int)(kart->getPowerup()->getType()) << 4) & 0xf0)
|
||||
+ (kart->getPowerup()->getNum() & 0x0f);
|
||||
|
||||
ns.ai8(0x01).ai32(item->getItemId()).ai8(powerup)
|
||||
.ai8(player_profile->getGlobalPlayerId());
|
||||
ns.ai8(GE_ITEM_COLLECTED).ai32(item->getItemId()).ai8(powerup)
|
||||
.ai8(kart->getWorldKartId());
|
||||
ProtocolManager::getInstance()->sendMessage(this, peers[i], ns,
|
||||
/*reliable*/true);
|
||||
/*reliable*/true,
|
||||
/*synchronous*/true);
|
||||
Log::info("GameEventsProtocol",
|
||||
"Notified a peer that a kart collected item %d.",
|
||||
(int)(kart->getPowerup()->getType()));
|
||||
}
|
||||
} // collectedItem
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Called on the client when an itemCollected message is received.
|
||||
*/
|
||||
void GameEventsProtocol::collectedItem(const NetworkString &data)
|
||||
{
|
||||
if (data.size() < 6)
|
||||
{
|
||||
Log::warn("GameEventsProtocol", "Too short message.");
|
||||
}
|
||||
uint32_t item_id = data.gui32();
|
||||
uint8_t powerup_type = data.gui8(4);
|
||||
uint8_t kart_id = data.gui8(5);
|
||||
// now set the kart powerup
|
||||
AbstractKart* kart = World::getWorld()->getKart(kart_id);
|
||||
ItemManager::get()->collectedItem(ItemManager::get()->getItem(item_id),
|
||||
kart, powerup_type);
|
||||
Log::info("GameEventsProtocol", "Item %d picked by a player.",
|
||||
powerup_type);
|
||||
} // collectedItem
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** This function is called from the server when a kart finishes a race. It
|
||||
* sends a notification to all clients about this event.
|
||||
* \param kart The kart that finished the race.
|
||||
* \param time The time at which the kart finished.
|
||||
*/
|
||||
void GameEventsProtocol::kartFinishedRace(AbstractKart *kart, float time)
|
||||
{
|
||||
NetworkString ns(20);
|
||||
|
||||
const std::vector<STKPeer*> &peers = STKHost::get()->getPeers();
|
||||
for (unsigned int i = 0; i < peers.size(); i++)
|
||||
{
|
||||
ns.addUInt32(peers[i]->getClientServerToken())
|
||||
.addUInt8(GE_KART_FINISHED_RACE)
|
||||
.addUInt8(kart->getWorldKartId()).addFloat(time);
|
||||
|
||||
ProtocolManager::getInstance()->sendMessage(this, peers[i], ns,
|
||||
/*reliable*/true,
|
||||
/*synchronous*/true);
|
||||
} // for i in peers
|
||||
} // kartFinishedRace
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** This function is called on a client when it receives a kartFinishedRace
|
||||
* event from the server. It updates the game with this information.
|
||||
* \param ns The message from the server.
|
||||
*/
|
||||
void GameEventsProtocol::kartFinishedRace(const NetworkString &ns)
|
||||
{
|
||||
uint8_t kart_id = ns.getUInt8(0);
|
||||
float time = ns.getFloat(1);
|
||||
World::getWorld()->getKart(kart_id)->finishedRace(time,
|
||||
/*from_server*/true);
|
||||
} // kartFinishedRace
|
||||
|
||||
@@ -8,6 +8,12 @@ class Item;
|
||||
|
||||
class GameEventsProtocol : public Protocol
|
||||
{
|
||||
private:
|
||||
enum GameEventType {
|
||||
GE_ITEM_COLLECTED = 0x01,
|
||||
GE_KART_FINISHED_RACE = 0x02
|
||||
}; // GameEventType
|
||||
|
||||
public:
|
||||
GameEventsProtocol();
|
||||
virtual ~GameEventsProtocol();
|
||||
@@ -16,6 +22,9 @@ public:
|
||||
virtual void setup();
|
||||
virtual void update();
|
||||
void collectedItem(Item* item, AbstractKart* kart);
|
||||
void collectedItem(const NetworkString &ns);
|
||||
void kartFinishedRace(AbstractKart *kart, float time);
|
||||
void kartFinishedRace(const NetworkString &ns);
|
||||
// ------------------------------------------------------------------------
|
||||
virtual void asynchronousUpdate() {}
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
@@ -1,75 +1,74 @@
|
||||
#include "network/protocols/kart_update_protocol.hpp"
|
||||
|
||||
#include "karts/abstract_kart.hpp"
|
||||
#include "karts/controller/controller.hpp"
|
||||
#include "modes/world.hpp"
|
||||
#include "network/event.hpp"
|
||||
#include "network/network_config.hpp"
|
||||
#include "network/network_world.hpp"
|
||||
#include "network/protocol_manager.hpp"
|
||||
#include "utils/time.hpp"
|
||||
|
||||
KartUpdateProtocol::KartUpdateProtocol() : Protocol(PROTOCOL_KART_UPDATE)
|
||||
{
|
||||
m_karts = World::getWorld()->getKarts();
|
||||
for (unsigned int i = 0; i < m_karts.size(); i++)
|
||||
{
|
||||
//if (m_karts[i]->getWorldKartId())
|
||||
{
|
||||
Log::info("KartUpdateProtocol", "Kart %d has id %d and name %s",
|
||||
i, m_karts[i]->getWorldKartId(),
|
||||
m_karts[i]->getIdent().c_str());
|
||||
}
|
||||
if (m_karts[i]->getIdent() == NetworkWorld::getInstance()->getSelfKart())
|
||||
{
|
||||
Log::info("KartUpdateProtocol", "My id is %d", i);
|
||||
m_self_kart_index = i;
|
||||
}
|
||||
}
|
||||
pthread_mutex_init(&m_positions_updates_mutex, NULL);
|
||||
}
|
||||
// Allocate arrays to store one position and rotation for each kart
|
||||
// (which is the update information from the server to the client).
|
||||
m_next_positions.resize(World::getWorld()->getNumKarts());
|
||||
m_next_quaternions.resize(World::getWorld()->getNumKarts());
|
||||
|
||||
// This flag keeps track if valid data for an update is in
|
||||
// the arrays
|
||||
m_was_updated = false;
|
||||
} // KartUpdateProtocol
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
KartUpdateProtocol::~KartUpdateProtocol()
|
||||
{
|
||||
}
|
||||
} // ~KartUpdateProtocol
|
||||
|
||||
bool KartUpdateProtocol::notifyEventAsynchronous(Event* event)
|
||||
// ----------------------------------------------------------------------------
|
||||
void KartUpdateProtocol::setup()
|
||||
{
|
||||
} // setup
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Store the update events in the queue. Since the events are handled in the
|
||||
* synchronous notify function, there is no lock necessary to
|
||||
*/
|
||||
bool KartUpdateProtocol::notifyEvent(Event* event)
|
||||
{
|
||||
if (event->getType() != EVENT_TYPE_MESSAGE)
|
||||
return true;
|
||||
NetworkString &ns = event->data();
|
||||
if (ns.size() < 36)
|
||||
if (ns.size() < 33)
|
||||
{
|
||||
Log::info("KartUpdateProtocol", "Message too short.");
|
||||
return true;
|
||||
}
|
||||
ns.removeFront(4);
|
||||
while(ns.size() >= 16)
|
||||
while(ns.size() >= 29)
|
||||
{
|
||||
uint32_t kart_id = ns.getUInt32(0);
|
||||
uint8_t kart_id = ns.getUInt8(0);
|
||||
Vec3 xyz;
|
||||
btQuaternion quat;
|
||||
ns.get(&xyz, 1).get(&quat, 13);
|
||||
m_next_positions [kart_id] = xyz;
|
||||
m_next_quaternions[kart_id] = quat;
|
||||
ns.removeFront(29);
|
||||
} // while ns.size()>29
|
||||
|
||||
float a,b,c;
|
||||
a = ns.getFloat(4);
|
||||
b = ns.getFloat(8);
|
||||
c = ns.getFloat(12);
|
||||
float d,e,f,g;
|
||||
d = ns.getFloat(16);
|
||||
e = ns.getFloat(20);
|
||||
f = ns.getFloat(24);
|
||||
g = ns.getFloat(28);
|
||||
pthread_mutex_trylock(&m_positions_updates_mutex);
|
||||
m_next_positions.push_back(Vec3(a,b,c));
|
||||
m_next_quaternions.push_back(btQuaternion(d,e,f,g));
|
||||
m_karts_ids.push_back(kart_id);
|
||||
pthread_mutex_unlock(&m_positions_updates_mutex);
|
||||
ns.removeFront(32);
|
||||
}
|
||||
// Set the flag that a new update was received
|
||||
m_was_updated = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void KartUpdateProtocol::setup()
|
||||
{
|
||||
}
|
||||
} // notifyEvent
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Sends regular update events from the server to all clients and from the
|
||||
* clients to the server (FIXME - is that actually necessary??)
|
||||
* Then it applies all update events that have been received in notifyEvent.
|
||||
* This two-part implementation means that if the server should send two
|
||||
* or more updates before this client handles them, only the last one will
|
||||
* actually be handled (i.e. outdated kart position updates are discarded).
|
||||
*/
|
||||
void KartUpdateProtocol::update()
|
||||
{
|
||||
if (!World::getWorld())
|
||||
@@ -81,66 +80,61 @@ void KartUpdateProtocol::update()
|
||||
time = current_time;
|
||||
if (NetworkConfig::get()->isServer())
|
||||
{
|
||||
NetworkString ns(4+m_karts.size()*32);
|
||||
ns.af( World::getWorld()->getTime());
|
||||
for (unsigned int i = 0; i < m_karts.size(); i++)
|
||||
World *world = World::getWorld();
|
||||
NetworkString ns(4+world->getNumKarts()*29);
|
||||
ns.af( world->getTime() );
|
||||
for (unsigned int i = 0; i < world->getNumKarts(); i++)
|
||||
{
|
||||
AbstractKart* kart = m_karts[i];
|
||||
Vec3 v = kart->getXYZ();
|
||||
btQuaternion quat = kart->getRotation();
|
||||
ns.ai32( kart->getWorldKartId());
|
||||
ns.af(v[0]).af(v[1]).af(v[2]); // add position
|
||||
ns.af(quat.x()).af(quat.y()).af(quat.z()).af(quat.w()); // add rotation
|
||||
AbstractKart* kart = world->getKart(i);
|
||||
Vec3 xyz = kart->getXYZ();
|
||||
ns.addUInt8( kart->getWorldKartId());
|
||||
ns.add(xyz).add(kart->getRotation());
|
||||
Log::verbose("KartUpdateProtocol",
|
||||
"Sending %d's positions %f %f %f",
|
||||
kart->getWorldKartId(), v[0], v[1], v[2]);
|
||||
kart->getWorldKartId(), xyz[0], xyz[1], xyz[2]);
|
||||
}
|
||||
sendMessage(ns, false);
|
||||
sendSynchronousMessage(ns, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
AbstractKart* kart = m_karts[m_self_kart_index];
|
||||
Vec3 v = kart->getXYZ();
|
||||
btQuaternion quat = kart->getRotation();
|
||||
NetworkString ns(36);
|
||||
ns.af( World::getWorld()->getTime());
|
||||
ns.ai32( kart->getWorldKartId());
|
||||
ns.af(v[0]).af(v[1]).af(v[2]); // add position
|
||||
ns.af(quat.x()).af(quat.y()).af(quat.z()).af(quat.w()); // add rotation
|
||||
Log::verbose("KartUpdateProtocol",
|
||||
"Sending %d's positions %f %f %f",
|
||||
kart->getWorldKartId(), v[0], v[1], v[2]);
|
||||
sendMessage(ns, false);
|
||||
}
|
||||
}
|
||||
switch(pthread_mutex_trylock(&m_positions_updates_mutex))
|
||||
{
|
||||
case 0: /* if we got the lock */
|
||||
while (!m_next_positions.empty())
|
||||
NetworkString ns(4+29*race_manager->getNumLocalPlayers());
|
||||
ns.af(World::getWorld()->getTime());
|
||||
for(unsigned int i=0; i<race_manager->getNumLocalPlayers(); i++)
|
||||
{
|
||||
uint32_t id = m_karts_ids.back();
|
||||
// server takes all updates
|
||||
if (id != m_self_kart_index || NetworkConfig::get()->isServer())
|
||||
{
|
||||
Vec3 pos = m_next_positions.back();
|
||||
btTransform transform = m_karts[id]->getBody()->getInterpolationWorldTransform();
|
||||
transform.setOrigin(pos);
|
||||
transform.setRotation(m_next_quaternions.back());
|
||||
m_karts[id]->getBody()->setCenterOfMassTransform(transform);
|
||||
//m_karts[id]->getBody()->setLinearVelocity(Vec3(0,0,0));
|
||||
Log::verbose("KartUpdateProtocol", "Update kart %i pos to %f %f %f", id, pos[0], pos[1], pos[2]);
|
||||
}
|
||||
m_next_positions.pop_back();
|
||||
m_next_quaternions.pop_back();
|
||||
m_karts_ids.pop_back();
|
||||
AbstractKart *kart = World::getWorld()->getLocalPlayerKart(i);
|
||||
const Vec3 &xyz = kart->getXYZ();
|
||||
ns.addUInt8(kart->getWorldKartId());
|
||||
ns.add(xyz).add(kart->getRotation());
|
||||
Log::verbose("KartUpdateProtocol",
|
||||
"Sending %d's positions %f %f %f",
|
||||
kart->getWorldKartId(), xyz[0], xyz[1], xyz[2]);
|
||||
}
|
||||
pthread_mutex_unlock(&m_positions_updates_mutex);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
sendSynchronousMessage(ns, false);
|
||||
} // if server
|
||||
} // if (current_time > time + 0.1)
|
||||
|
||||
|
||||
// Now handle all update events that have been received.
|
||||
// There is no lock necessary, since receiving new positions is done in
|
||||
// notifyEvent, which is called from the same thread that calls this
|
||||
// function.
|
||||
if(m_was_updated)
|
||||
{
|
||||
for (unsigned id = 0; id < m_next_positions.size(); id++)
|
||||
{
|
||||
AbstractKart *kart = World::getWorld()->getKart(id);
|
||||
if (!kart->getController()->isLocalPlayerController())
|
||||
{
|
||||
btTransform transform = kart->getBody()
|
||||
->getInterpolationWorldTransform();
|
||||
transform.setOrigin(m_next_positions[id]);
|
||||
transform.setRotation(m_next_quaternions[id]);
|
||||
kart->getBody()->setCenterOfMassTransform(transform);
|
||||
Log::verbose("KartUpdateProtocol", "Update kart %i pos",
|
||||
id);
|
||||
} // if not local player
|
||||
} // for id < num_karts
|
||||
m_was_updated = false; // mark that all updates were applied
|
||||
} // if m_was_updated
|
||||
} // update
|
||||
|
||||
|
||||
@@ -5,31 +5,33 @@
|
||||
#include "utils/vec3.hpp"
|
||||
#include "LinearMath/btQuaternion.h"
|
||||
|
||||
#include <list>
|
||||
#include <vector>
|
||||
#include "pthread.h"
|
||||
|
||||
class AbstractKart;
|
||||
|
||||
class KartUpdateProtocol : public Protocol
|
||||
{
|
||||
public:
|
||||
KartUpdateProtocol();
|
||||
virtual ~KartUpdateProtocol();
|
||||
private:
|
||||
|
||||
virtual bool notifyEventAsynchronous(Event* event);
|
||||
virtual void setup();
|
||||
virtual void update();
|
||||
virtual void asynchronousUpdate() {};
|
||||
/** Stores the last updated position for a kart. */
|
||||
std::vector<Vec3> m_next_positions;
|
||||
|
||||
protected:
|
||||
std::vector<AbstractKart*> m_karts;
|
||||
uint32_t m_self_kart_index;
|
||||
/** Stores the last updated rotation for a kart. */
|
||||
std::vector<btQuaternion> m_next_quaternions;
|
||||
|
||||
std::list<Vec3> m_next_positions;
|
||||
std::list<btQuaternion> m_next_quaternions;
|
||||
std::list<uint32_t> m_karts_ids;
|
||||
/** True if a new update for the kart positions was received. */
|
||||
bool m_was_updated;
|
||||
|
||||
pthread_mutex_t m_positions_updates_mutex;
|
||||
};
|
||||
public:
|
||||
KartUpdateProtocol();
|
||||
virtual ~KartUpdateProtocol();
|
||||
|
||||
virtual bool notifyEvent(Event* event);
|
||||
virtual void setup();
|
||||
virtual void update();
|
||||
virtual void asynchronousUpdate() {};
|
||||
|
||||
}; // KartUpdateProtocol
|
||||
|
||||
#endif // KART_UPDATE_PROTOCOL_HPP
|
||||
|
||||
@@ -23,12 +23,12 @@
|
||||
#include "modes/world.hpp"
|
||||
#include "network/event.hpp"
|
||||
#include "network/network_config.hpp"
|
||||
#include "network/network_world.hpp"
|
||||
#include "network/network_player_profile.hpp"
|
||||
#include "network/protocols/get_public_address.hpp"
|
||||
#include "network/protocols/connect_to_peer.hpp"
|
||||
#include "network/protocols/start_game_protocol.hpp"
|
||||
#include "network/protocol_manager.hpp"
|
||||
#include "network/race_event_manager.hpp"
|
||||
#include "network/stk_host.hpp"
|
||||
#include "network/stk_peer.hpp"
|
||||
#include "online/online_profile.hpp"
|
||||
@@ -124,7 +124,7 @@ void ServerLobbyRoomProtocol::update()
|
||||
m_current_protocol->requestStart();
|
||||
m_state = GETTING_PUBLIC_ADDRESS;
|
||||
// The callback from GetPublicAddress will wake this protocol up
|
||||
ProtocolManager::getInstance()->pauseProtocol(this);
|
||||
requestPause();
|
||||
break;
|
||||
case GETTING_PUBLIC_ADDRESS:
|
||||
{
|
||||
@@ -146,7 +146,7 @@ void ServerLobbyRoomProtocol::update()
|
||||
if(NetworkConfig::get()->isWAN())
|
||||
checkIncomingConnectionRequests();
|
||||
if (m_in_race && World::getWorld() &&
|
||||
NetworkWorld::getInstance<NetworkWorld>()->isRunning())
|
||||
RaceEventManager::getInstance<RaceEventManager>()->isRunning())
|
||||
{
|
||||
checkRaceFinished();
|
||||
}
|
||||
@@ -166,11 +166,11 @@ void ServerLobbyRoomProtocol::update()
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Callback when the GetPublicAddress terminates. It will unpause this
|
||||
* protocol, which triggers the next state of the finite state machine.
|
||||
* protocol, which triggers the next state of the finite state machine.
|
||||
*/
|
||||
void ServerLobbyRoomProtocol::callback(Protocol *protocol)
|
||||
{
|
||||
ProtocolManager::getInstance()->unpauseProtocol(this);
|
||||
requestUnpause();
|
||||
} // callback
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -241,7 +241,7 @@ void ServerLobbyRoomProtocol::startGame()
|
||||
*/
|
||||
void ServerLobbyRoomProtocol::startSelection(const Event *event)
|
||||
{
|
||||
if(event && !STKHost::get()->isAuthorisedToControl(event->getPeer()))
|
||||
if(event && !event->getPeer()->isAuthorised())
|
||||
{
|
||||
Log::warn("ServerLobby",
|
||||
"Client %lx is not authorised to start selection.",
|
||||
@@ -313,10 +313,10 @@ void ServerLobbyRoomProtocol::checkIncomingConnectionRequests()
|
||||
|
||||
void ServerLobbyRoomProtocol::checkRaceFinished()
|
||||
{
|
||||
assert(NetworkWorld::getInstance()->isRunning());
|
||||
assert(RaceEventManager::getInstance()->isRunning());
|
||||
assert(World::getWorld());
|
||||
// if race is over, give the final score to everybody
|
||||
if (NetworkWorld::getInstance()->isRaceOver())
|
||||
if (RaceEventManager::getInstance()->isRaceOver())
|
||||
{
|
||||
// calculate karts ranks :
|
||||
int num_players = race_manager->getNumberOfKarts();
|
||||
@@ -348,9 +348,9 @@ void ServerLobbyRoomProtocol::checkRaceFinished()
|
||||
for (unsigned int i = 0; i < peers.size(); i++)
|
||||
{
|
||||
NetworkString ns(6);
|
||||
ns.ai8(0x06).ai8(4).ai32(peers[i]->getClientServerToken());
|
||||
ns.ai8(LE_RACE_FINISHED).ai8(4).ai32(peers[i]->getClientServerToken());
|
||||
NetworkString total = ns + queue;
|
||||
sendMessage(peers[i], total, true);
|
||||
sendSynchronousMessage(peers[i], total, true);
|
||||
}
|
||||
Log::info("ServerLobbyRoomProtocol", "End of game message sent");
|
||||
m_in_race = false;
|
||||
@@ -381,7 +381,7 @@ void ServerLobbyRoomProtocol::checkRaceFinished()
|
||||
"No game events protocol registered.");
|
||||
|
||||
// notify the network world that it is stopped
|
||||
NetworkWorld::getInstance()->stop();
|
||||
RaceEventManager::getInstance()->stop();
|
||||
// exit the race now
|
||||
race_manager->exitRace();
|
||||
race_manager->setAIKartOverride("");
|
||||
@@ -445,8 +445,11 @@ void ServerLobbyRoomProtocol::connectionRequested(Event* event)
|
||||
// Connection accepted.
|
||||
// ====================
|
||||
std::string name_u8;
|
||||
data.decodeString(0, &name_u8);
|
||||
int len = data.decodeString(0, &name_u8);
|
||||
core::stringw name = StringUtils::utf8ToWide(name_u8);
|
||||
std::string password;
|
||||
data.decodeString(len, &password);
|
||||
bool is_authorised = (password==NetworkConfig::get()->getPassword());
|
||||
|
||||
// Get the unique global ID for this player.
|
||||
m_next_player_id.lock();
|
||||
@@ -456,7 +459,9 @@ void ServerLobbyRoomProtocol::connectionRequested(Event* event)
|
||||
if(m_setup->getLocalMasterID()==0)
|
||||
m_setup->setLocalMaster(new_player_id);
|
||||
|
||||
int new_host_id = STKHost::get()->getPeerCount();
|
||||
// The host id has already been incremented when the peer
|
||||
// was added, so it is the right id now.
|
||||
int new_host_id = STKHost::get()->getNextHostId();
|
||||
|
||||
// Notify everybody that there is a new player
|
||||
// -------------------------------------------
|
||||
@@ -478,10 +483,10 @@ void ServerLobbyRoomProtocol::connectionRequested(Event* event)
|
||||
const std::vector<NetworkPlayerProfile*> &players = m_setup->getPlayers();
|
||||
// send a message to the one that asked to connect
|
||||
// Size is overestimated, probably one player's data will not be sent
|
||||
NetworkString message_ack(13 + players.size() * 7);
|
||||
NetworkString message_ack(14 + players.size() * 7);
|
||||
// connection success -- size of token -- token
|
||||
message_ack.ai8(LE_CONNECTION_ACCEPTED).ai8(1).ai8(new_player_id).ai8(4)
|
||||
.ai32(token).addUInt8(new_host_id);
|
||||
.ai32(token).addUInt8(new_host_id).addUInt8(is_authorised);
|
||||
// Add all players so that this user knows (this new player is only added
|
||||
// to the list of players later, so the new player's info is not included)
|
||||
for (unsigned int i = 0; i < players.size(); i++)
|
||||
@@ -497,6 +502,8 @@ void ServerLobbyRoomProtocol::connectionRequested(Event* event)
|
||||
m_setup->addPlayer(profile);
|
||||
peer->setPlayerProfile(profile);
|
||||
peer->setClientServerToken(token);
|
||||
peer->setAuthorised(is_authorised);
|
||||
peer->setHostId(new_host_id);
|
||||
|
||||
Log::verbose("ServerLobbyRoomProtocol", "New player.");
|
||||
|
||||
@@ -563,7 +570,8 @@ void ServerLobbyRoomProtocol::kartSelectionRequested(Event* event)
|
||||
uint8_t player_id = peer->getPlayerProfile()->getGlobalPlayerId();
|
||||
answer.ai8(LE_KART_SELECTION_UPDATE).ai8(1).ai8(player_id)
|
||||
.encodeString(kart_name);
|
||||
sendMessage(answer);
|
||||
// This message must be handled synchronously on the client.
|
||||
sendSynchronousMessage(answer);
|
||||
m_setup->setPlayerKart(player_id, kart_name);
|
||||
} // kartSelectionRequested
|
||||
|
||||
@@ -595,9 +603,7 @@ void ServerLobbyRoomProtocol::playerMajorVote(Event* event)
|
||||
NetworkString other(5+data.size());
|
||||
other.ai8(1).ai8(player_id); // add the player id
|
||||
other += data; // add the data
|
||||
NetworkString prefix(1);
|
||||
prefix.ai8(LE_VOTE_MAJOR); // prefix the token with the type
|
||||
sendMessageToPeersChangingToken(prefix, other);
|
||||
sendMessageToPeersChangingToken(LE_VOTE_MAJOR, other);
|
||||
} // playerMajorVote
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -627,9 +633,7 @@ void ServerLobbyRoomProtocol::playerRaceCountVote(Event* event)
|
||||
NetworkString other(2+data.size());
|
||||
other.ai8(1).ai8(player_id); // add the player id
|
||||
other += data; // add the data
|
||||
NetworkString prefix(1);
|
||||
prefix.ai8(LE_VOTE_RACE_COUNT); // prefix the token with the type
|
||||
sendMessageToPeersChangingToken(prefix, other);
|
||||
sendMessageToPeersChangingToken(LE_VOTE_RACE_COUNT, other);
|
||||
} // playerRaceCountVote
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -660,9 +664,7 @@ void ServerLobbyRoomProtocol::playerMinorVote(Event* event)
|
||||
NetworkString other(2+data.size());
|
||||
other.ai8(1).ai8(player_id); // add the player id
|
||||
other += data; // add the data
|
||||
NetworkString prefix(1);
|
||||
prefix.ai8(LE_VOTE_MINOR); // prefix the token with the ype
|
||||
sendMessageToPeersChangingToken(prefix, other);
|
||||
sendMessageToPeersChangingToken(LE_VOTE_MINOR, other);
|
||||
} // playerMinorVote
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -694,9 +696,7 @@ void ServerLobbyRoomProtocol::playerTrackVote(Event* event)
|
||||
NetworkString other(2+data.size());
|
||||
other.ai8(1).ai8(player_id); // add the player id
|
||||
other += data; // add the data
|
||||
NetworkString prefix(1);
|
||||
prefix.ai8(LE_VOTE_TRACK); // prefix the token with the ype
|
||||
sendMessageToPeersChangingToken(prefix, other);
|
||||
sendMessageToPeersChangingToken(LE_VOTE_TRACK, other);
|
||||
if(m_setup->getRaceConfig()->getNumTrackVotes()==m_setup->getPlayerCount())
|
||||
startGame();
|
||||
} // playerTrackVote
|
||||
@@ -731,9 +731,7 @@ void ServerLobbyRoomProtocol::playerReversedVote(Event* event)
|
||||
NetworkString other(2+data.size());
|
||||
other.ai8(1).ai8(player_id); // add the player id
|
||||
other += data; // add the data
|
||||
NetworkString prefix(1);
|
||||
prefix.ai8(LE_VOTE_REVERSE); // prefix the token with the ype
|
||||
sendMessageToPeersChangingToken(prefix, other);
|
||||
sendMessageToPeersChangingToken(LE_VOTE_REVERSE, other);
|
||||
} // playerReversedVote
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -765,9 +763,7 @@ void ServerLobbyRoomProtocol::playerLapsVote(Event* event)
|
||||
NetworkString other(2+data.size());
|
||||
other.ai8(1).ai8(player_id); // add the player id
|
||||
other += data; // add the data
|
||||
NetworkString prefix(1);
|
||||
prefix.ai8(LE_VOTE_LAPS); // prefix the token with the ype
|
||||
sendMessageToPeersChangingToken(prefix, other);
|
||||
sendMessageToPeersChangingToken(LE_VOTE_LAPS, other);
|
||||
} // playerLapsVote
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#include "network/game_setup.hpp"
|
||||
#include "network/network_config.hpp"
|
||||
#include "network/network_player_profile.hpp"
|
||||
#include "network/network_world.hpp"
|
||||
#include "network/race_event_manager.hpp"
|
||||
#include "network/protocol_manager.hpp"
|
||||
#include "network/protocols/synchronization_protocol.hpp"
|
||||
#include "network/stk_host.hpp"
|
||||
@@ -57,8 +57,8 @@ void StartGameProtocol::setup()
|
||||
|
||||
// Race startup sequence
|
||||
// ---------------------
|
||||
// builds it and starts
|
||||
NetworkWorld::getInstance<NetworkWorld>()->start();
|
||||
// This creates the network world.
|
||||
RaceEventManager::getInstance<RaceEventManager>()->start();
|
||||
|
||||
// The number of karts includes the AI karts, which are not supported atn
|
||||
race_manager->setNumKarts(m_game_setup->getPlayerCount());
|
||||
@@ -74,50 +74,47 @@ void StartGameProtocol::setup()
|
||||
for (unsigned int i = 0; i < players.size(); i++)
|
||||
{
|
||||
NetworkPlayerProfile* profile = players[i];
|
||||
bool is_local = profile->getHostId()
|
||||
== STKHost::get()->getMyHostId();
|
||||
RemoteKartInfo rki(profile->getGlobalPlayerId(),
|
||||
bool is_local = profile->isLocalPlayer();
|
||||
|
||||
// All non-local players are created here. This means all players
|
||||
// on the server, and all non-local players on a client (the local
|
||||
// karts are created in the NetworkingLobby).
|
||||
if(!is_local)
|
||||
{
|
||||
// On the server no device or player profile is needed.
|
||||
StateManager::get()->createActivePlayer(NULL, NULL);
|
||||
}
|
||||
|
||||
// Adjust the local player id so that local players have the numbers
|
||||
// 0 to num-1; and all other karts start with num. This way the local
|
||||
// players get the first ActivePlayers assigned (which have the
|
||||
// corresponding device associated with it).
|
||||
RemoteKartInfo rki(is_local ? local_player_id
|
||||
: i-local_player_id+STKHost::get()->getGameSetup()->getNumLocalPlayers(),
|
||||
profile->getKartName(),
|
||||
profile->getName(),
|
||||
profile->getHostId(),
|
||||
!is_local);
|
||||
rki.setGlobalPlayerId(profile->getGlobalPlayerId());
|
||||
rki.setPerPlayerDifficulty(profile->getPerPlayerDifficulty());
|
||||
rki.setLocalPlayerId(local_player_id);
|
||||
if(is_local) local_player_id++;
|
||||
if(is_local)
|
||||
{
|
||||
rki.setLocalPlayerId(local_player_id);
|
||||
local_player_id++;
|
||||
}
|
||||
|
||||
// Inform the race manager about the data for this kart.
|
||||
race_manager->setPlayerKart(i, rki);
|
||||
|
||||
if(is_local)
|
||||
{
|
||||
PlayerProfile* profile_to_use = PlayerManager::getCurrentPlayer();
|
||||
assert(profile_to_use);
|
||||
InputDevice* device = input_manager->getDeviceManager()
|
||||
->getLatestUsedDevice();
|
||||
int new_player_id = 0;
|
||||
|
||||
// more than one player, we're the first
|
||||
if (StateManager::get()->getActivePlayers().size() >= 1)
|
||||
new_player_id = 0;
|
||||
else
|
||||
new_player_id = StateManager::get()
|
||||
->createActivePlayer(profile_to_use, device);
|
||||
StateManager::ActivePlayer *ap =
|
||||
StateManager::get()->getActivePlayer(new_player_id);
|
||||
device->setPlayer(ap);
|
||||
input_manager->getDeviceManager()->setSinglePlayer(ap);
|
||||
race_manager->setPlayerKart(new_player_id,
|
||||
profile->getKartName());
|
||||
NetworkWorld::getInstance()->setSelfKart(profile->getKartName());
|
||||
} // if is_local
|
||||
else
|
||||
{
|
||||
StateManager::get()->createActivePlayer( NULL, NULL );
|
||||
race_manager->setPlayerKart(i, rki);
|
||||
}
|
||||
} // for i in players
|
||||
|
||||
race_manager->computeRandomKartList();
|
||||
// Make sure that if there is only a single local player this player can
|
||||
// use all input devices.
|
||||
StateManager::ActivePlayer *ap = race_manager->getNumLocalPlayers()>1
|
||||
? NULL
|
||||
: StateManager::get()->getActivePlayer(0);
|
||||
|
||||
input_manager->getDeviceManager()->setSinglePlayer(ap);
|
||||
|
||||
Log::info("StartGameProtocol", "Player configuration ready.");
|
||||
m_state = SYNCHRONIZATION_WAIT;
|
||||
|
||||
|
||||
@@ -16,10 +16,10 @@ SynchronizationProtocol::SynchronizationProtocol()
|
||||
{
|
||||
unsigned int size = STKHost::get()->getPeerCount();
|
||||
m_pings.resize(size, std::map<uint32_t,double>());
|
||||
m_pings_count.resize(size, 0);
|
||||
m_successed_pings.resize(size, 0);
|
||||
m_total_diff.resize(size, 0);
|
||||
m_average_ping.resize(size, 0);
|
||||
m_pings_count = 0;
|
||||
m_countdown_activated = false;
|
||||
m_last_time = -1;
|
||||
} // SynchronizationProtocol
|
||||
@@ -30,6 +30,13 @@ SynchronizationProtocol::~SynchronizationProtocol()
|
||||
} // ~SynchronizationProtocol
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void SynchronizationProtocol::setup()
|
||||
{
|
||||
Log::info("SynchronizationProtocol", "Ready !");
|
||||
m_countdown = 5.0; // init the countdown to 5s
|
||||
m_has_quit = false;
|
||||
} // setup
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
bool SynchronizationProtocol::notifyEventAsynchronous(Event* event)
|
||||
{
|
||||
@@ -37,29 +44,22 @@ bool SynchronizationProtocol::notifyEventAsynchronous(Event* event)
|
||||
return true;
|
||||
|
||||
const NetworkString &data = event->data();
|
||||
if (data.size() < 10)
|
||||
if (data.size() < 9)
|
||||
{
|
||||
Log::warn("SynchronizationProtocol", "Received a too short message.");
|
||||
return true;
|
||||
}
|
||||
uint8_t talk_id = data.gui8();
|
||||
uint32_t token = data.gui32(1);
|
||||
uint32_t request = data.gui8(5);
|
||||
uint32_t sequence = data.gui32(6);
|
||||
uint32_t token = data.gui32(0);
|
||||
uint32_t request = data.gui8(4);
|
||||
uint32_t sequence = data.gui32(5);
|
||||
|
||||
const std::vector<STKPeer*> &peers = STKHost::get()->getPeers();
|
||||
assert(peers.size() > 0);
|
||||
|
||||
if (NetworkConfig::get()->isServer())
|
||||
{
|
||||
if (talk_id > peers.size())
|
||||
{
|
||||
Log::warn("SynchronizationProtocol", "The ID isn't known.");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t peer_id = 0;
|
||||
// Find the right peer id. The host id (i.e. each host sendings its
|
||||
// host id) can not be used here, since host ids can have gaps (if a
|
||||
// host should disconnect)
|
||||
uint8_t peer_id = -1;
|
||||
for (unsigned int i = 0; i < peers.size(); i++)
|
||||
{
|
||||
if (peers[i]->isSamePeer(event->getPeer()))
|
||||
@@ -68,37 +68,45 @@ bool SynchronizationProtocol::notifyEventAsynchronous(Event* event)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (peers[peer_id]->getClientServerToken() != token)
|
||||
if (event->getPeer()->getClientServerToken() != token)
|
||||
{
|
||||
Log::warn("SynchronizationProtocol", "Bad token from peer %d",
|
||||
talk_id);
|
||||
peer_id);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (request)
|
||||
{
|
||||
// Only a client should receive a request for a ping response
|
||||
assert(NetworkConfig::get()->isClient());
|
||||
NetworkString response(10);
|
||||
response.ai8(data.gui8(talk_id)).ai32(token).ai8(0).ai32(sequence);
|
||||
sendMessage(peers[peer_id], response, false);
|
||||
Log::verbose("SynchronizationProtocol", "Answering sequence %u",
|
||||
sequence);
|
||||
// The '0' indicates a response to a ping request
|
||||
response.ai32(token).ai8(0).ai32(sequence);
|
||||
sendMessage(event->getPeer(), response, false);
|
||||
Log::verbose("SynchronizationProtocol", "Answering sequence %u at %lf",
|
||||
sequence, StkTime::getRealTime());
|
||||
|
||||
// countdown time in the message
|
||||
if (data.size() == 14 && !NetworkConfig::get()->isServer())
|
||||
if (data.size() == 13)
|
||||
{
|
||||
uint32_t time_to_start = data.gui32(10);
|
||||
uint32_t time_to_start = data.gui32(9);
|
||||
Log::debug("SynchronizationProtocol",
|
||||
"Request to start game in %d.", time_to_start);
|
||||
if (!m_countdown_activated)
|
||||
startCountdown(time_to_start);
|
||||
else
|
||||
{
|
||||
// Adjust the time based on the value sent from the server.
|
||||
m_countdown = (double)(time_to_start/1000.0);
|
||||
}
|
||||
}
|
||||
else
|
||||
Log::verbose("SynchronizationProtocol", "No countdown for now.");
|
||||
}
|
||||
else // response
|
||||
else // receive response to a ping request
|
||||
{
|
||||
// Only a server should receive this kind of message
|
||||
assert(NetworkConfig::get()->isServer());
|
||||
if (sequence >= m_pings[peer_id].size())
|
||||
{
|
||||
Log::warn("SynchronizationProtocol",
|
||||
@@ -107,29 +115,22 @@ bool SynchronizationProtocol::notifyEventAsynchronous(Event* event)
|
||||
}
|
||||
double current_time = StkTime::getRealTime();
|
||||
m_total_diff[peer_id] += current_time - m_pings[peer_id][sequence];
|
||||
Log::verbose("SynchronizationProtocol", "InstantPing is %u",
|
||||
(unsigned int)((current_time - m_pings[peer_id][sequence])*1000));
|
||||
m_successed_pings[peer_id]++;
|
||||
m_average_ping[peer_id] =
|
||||
(int)((m_total_diff[peer_id]/m_successed_pings[peer_id])*1000.0);
|
||||
|
||||
Log::debug("SynchronizationProtocol", "Ping is %u",
|
||||
m_average_ping[peer_id]);
|
||||
Log::debug("SynchronizationProtocol",
|
||||
"Peer %d sequence %d ping %u average %u at %lf",
|
||||
peer_id, sequence,
|
||||
(unsigned int)((current_time - m_pings[peer_id][sequence])*1000),
|
||||
m_average_ping[peer_id],
|
||||
StkTime::getRealTime());
|
||||
}
|
||||
return true;
|
||||
} // notifyEventAsynchronous
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void SynchronizationProtocol::setup()
|
||||
{
|
||||
Log::info("SynchronizationProtocol", "Ready !");
|
||||
m_countdown = 5.0; // init the countdown to 5s
|
||||
m_has_quit = false;
|
||||
} // setup
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void SynchronizationProtocol::asynchronousUpdate()
|
||||
{
|
||||
double current_time = StkTime::getRealTime();
|
||||
@@ -161,35 +162,44 @@ void SynchronizationProtocol::asynchronousUpdate()
|
||||
Log::info("SynchronizationProtocol", "Starting in %d seconds.",
|
||||
seconds);
|
||||
}
|
||||
}
|
||||
if (current_time > m_last_time+0.1)
|
||||
} // if m_countdown_activated
|
||||
|
||||
if (NetworkConfig::get()->isServer() && current_time > m_last_time+1)
|
||||
{
|
||||
const std::vector<STKPeer*> &peers = STKHost::get()->getPeers();
|
||||
for (unsigned int i = 0; i < peers.size(); i++)
|
||||
{
|
||||
NetworkString ns(14);
|
||||
ns.ai8(i).addUInt32(peers[i]->getClientServerToken()).addUInt8(1)
|
||||
.addUInt32(m_pings[i].size());
|
||||
// now add the countdown if necessary
|
||||
if (m_countdown_activated && NetworkConfig::get()->isServer())
|
||||
NetworkString ping_request(13);
|
||||
ping_request.addUInt32(peers[i]->getClientServerToken())
|
||||
.addUInt8(1).addUInt32(m_pings[i].size());
|
||||
// Server adds the countdown if it has started. This will indicate
|
||||
// to the client to start the countdown as well (first time the
|
||||
// message is received), or to update the countdown time.
|
||||
if (m_countdown_activated )
|
||||
{
|
||||
ns.addUInt32((int)(m_countdown*1000.0));
|
||||
ping_request.addUInt32((int)(m_countdown*1000.0));
|
||||
Log::debug("SynchronizationProtocol",
|
||||
"CNTActivated: Countdown value : %f", m_countdown);
|
||||
}
|
||||
Log::verbose("SynchronizationProtocol",
|
||||
"Added sequence number %u for peer %d",
|
||||
m_pings[i].size(), i);
|
||||
m_last_time = current_time;
|
||||
m_pings[i].insert(std::pair<int,double>(m_pings_count[i], m_last_time));
|
||||
sendMessage(peers[i], ns, false);
|
||||
m_pings_count[i]++;
|
||||
"Added sequence number %u for peer %d at %lf",
|
||||
m_pings[i].size(), i, StkTime::getRealTime());
|
||||
m_pings[i] [ m_pings_count ] = current_time;
|
||||
sendMessage(peers[i], ping_request, false);
|
||||
} // for i M peers
|
||||
m_last_time = current_time;
|
||||
m_pings_count++;
|
||||
} // if current_time > m_last_time + 0.1
|
||||
} // asynchronousUpdate
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/** Starts the countdown on this machine. On the server side this function
|
||||
* is called from the StartGameProtocol (when all players have confirmed that
|
||||
* they are ready to play). On the client side this function is called from
|
||||
* this protocol when a message from the server is received indicating that
|
||||
* the countdown has to be started.
|
||||
* \param ms_countdown Countdown to use in ms.
|
||||
*/
|
||||
void SynchronizationProtocol::startCountdown(int ms_countdown)
|
||||
{
|
||||
m_countdown_activated = true;
|
||||
|
||||
@@ -10,7 +10,9 @@ class SynchronizationProtocol : public Protocol
|
||||
private:
|
||||
std::vector<std::map<uint32_t, double> > m_pings;
|
||||
std::vector<uint32_t> m_average_ping;
|
||||
std::vector<uint32_t> m_pings_count;
|
||||
|
||||
/** Counts the number of pings sent. */
|
||||
uint32_t m_pings_count;
|
||||
std::vector<uint32_t> m_successed_pings;
|
||||
std::vector<double> m_total_diff;
|
||||
bool m_countdown_activated;
|
||||
|
||||
@@ -389,7 +389,7 @@ void RaceConfig::computeNextTrack()
|
||||
tracks_histogram[m_votes[i].getTrackVote()] = 1;
|
||||
}
|
||||
}
|
||||
else if (m_votes[i].hasVotedReversed())
|
||||
if (m_votes[i].hasVotedReversed())
|
||||
{
|
||||
try // reversed
|
||||
{
|
||||
@@ -400,7 +400,7 @@ void RaceConfig::computeNextTrack()
|
||||
reversed_histogram[m_votes[i].getReversedVote()] = 1;
|
||||
}
|
||||
}
|
||||
else if (m_votes[i].hasVotedLaps())
|
||||
if (m_votes[i].hasVotedLaps())
|
||||
{
|
||||
try // laps
|
||||
{
|
||||
|
||||
@@ -1,32 +1,43 @@
|
||||
#include "network/network_world.hpp"
|
||||
|
||||
#include "network/race_event_manager.hpp"
|
||||
|
||||
#include "karts/controller/controller.hpp"
|
||||
#include "modes/world.hpp"
|
||||
#include "network/network_config.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"
|
||||
|
||||
|
||||
NetworkWorld::NetworkWorld()
|
||||
RaceEventManager::RaceEventManager()
|
||||
{
|
||||
m_running = false;
|
||||
} // NetworkWorld
|
||||
} // RaceEventManager
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
#include "karts/controller/controller.hpp"
|
||||
NetworkWorld::~NetworkWorld()
|
||||
RaceEventManager::~RaceEventManager()
|
||||
{
|
||||
} // ~NetworkWorld
|
||||
} // ~RaceEventManager
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void NetworkWorld::update(float dt)
|
||||
/** In network games this update function is called instead of
|
||||
* World::updateWorld(). This allow this function to postpone calling
|
||||
* the worl update while the countdown from the SynchronisationProtocol is
|
||||
* running.
|
||||
*/
|
||||
void RaceEventManager::update(float dt)
|
||||
{
|
||||
// This can happen in case of disconnects - protocol manager is
|
||||
// shut down, but still events to process.
|
||||
if(!ProtocolManager::getInstance())
|
||||
return;
|
||||
|
||||
SynchronizationProtocol* protocol = static_cast<SynchronizationProtocol*>(
|
||||
ProtocolManager::getInstance()->getProtocol(PROTOCOL_SYNCHRONIZATION));
|
||||
if (protocol) // if this protocol exists, that's that we play online
|
||||
if (protocol) // The existance of this protocol indicates that we play online
|
||||
{
|
||||
Log::debug("NetworkWorld", "Coutdown value is %f",
|
||||
Log::debug("RaceEventManager", "Coutdown value is %f",
|
||||
protocol->getCountdown());
|
||||
if (protocol->getCountdown() > 0.0)
|
||||
{
|
||||
@@ -41,37 +52,45 @@ void NetworkWorld::update(float dt)
|
||||
{
|
||||
// consider the world finished.
|
||||
stop();
|
||||
Log::info("NetworkWorld", "The game is considered finish.");
|
||||
Log::info("RaceEventManager", "The game is considered finish.");
|
||||
}
|
||||
} // update
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void NetworkWorld::start()
|
||||
void RaceEventManager::start()
|
||||
{
|
||||
m_running = true;
|
||||
} // start
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void NetworkWorld::stop()
|
||||
void RaceEventManager::stop()
|
||||
{
|
||||
m_running = false;
|
||||
} // stop
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
bool NetworkWorld::isRaceOver()
|
||||
bool RaceEventManager::isRaceOver()
|
||||
{
|
||||
if(!World::getWorld())
|
||||
return false;
|
||||
return (World::getWorld()->getPhase() > WorldStatus::RACE_PHASE);
|
||||
} // isRaceOver
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void RaceEventManager::kartFinishedRace(AbstractKart *kart, float time)
|
||||
{
|
||||
GameEventsProtocol* protocol = static_cast<GameEventsProtocol*>(
|
||||
ProtocolManager::getInstance()->getProtocol(PROTOCOL_GAME_EVENTS));
|
||||
protocol->kartFinishedRace(kart, time);
|
||||
} // kartFinishedRace
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Called from the item manager on a server. It triggers a notification to
|
||||
* all clients in the GameEventsProtocol.
|
||||
* \param item The item that was collected.
|
||||
* \param kart The kart that collected the item.
|
||||
*/
|
||||
void NetworkWorld::collectedItem(Item *item, AbstractKart *kart)
|
||||
void RaceEventManager::collectedItem(Item *item, AbstractKart *kart)
|
||||
{
|
||||
// this is only called in the server
|
||||
assert(NetworkConfig::get()->isServer());
|
||||
@@ -82,8 +101,8 @@ void NetworkWorld::collectedItem(Item *item, AbstractKart *kart)
|
||||
} // collectedItem
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void NetworkWorld::controllerAction(Controller* controller,
|
||||
PlayerAction action, int value)
|
||||
void RaceEventManager::controllerAction(Controller* controller,
|
||||
PlayerAction action, int value)
|
||||
{
|
||||
ControllerEventsProtocol* protocol = static_cast<ControllerEventsProtocol*>(
|
||||
ProtocolManager::getInstance()->getProtocol(PROTOCOL_CONTROLLER_EVENTS));
|
||||
22
src/network/network_world.hpp → src/network/race_event_manager.hpp
Normal file → Executable file
22
src/network/network_world.hpp → src/network/race_event_manager.hpp
Normal file → Executable file
@@ -31,20 +31,22 @@ 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
|
||||
/** \brief This is the interface between the main game and the online
|
||||
* implementation. The main game informs this object about important
|
||||
* events (e.g. item collected), which need to be forwarded from the
|
||||
* server to all clients. This object then triggers the right message
|
||||
* from the various running protocols.
|
||||
*/
|
||||
class NetworkWorld : public AbstractSingleton<NetworkWorld>
|
||||
class RaceEventManager : public AbstractSingleton<RaceEventManager>
|
||||
{
|
||||
private:
|
||||
bool m_running;
|
||||
float m_race_time;
|
||||
std::string m_self_kart;
|
||||
|
||||
friend class AbstractSingleton<NetworkWorld>;
|
||||
friend class AbstractSingleton<RaceEventManager>;
|
||||
|
||||
NetworkWorld();
|
||||
virtual ~NetworkWorld();
|
||||
RaceEventManager();
|
||||
virtual ~RaceEventManager();
|
||||
|
||||
public:
|
||||
void update(float dt);
|
||||
@@ -56,11 +58,7 @@ public:
|
||||
void collectedItem(Item *item, AbstractKart *kart);
|
||||
void controllerAction(Controller* controller, PlayerAction action,
|
||||
int value);
|
||||
// ------------------------------------------------------------------------
|
||||
/** Sets the name of the kart of this player. */
|
||||
void setSelfKart(const std::string &name) { m_self_kart = name; }
|
||||
// ------------------------------------------------------------------------
|
||||
const std::string& getSelfKart() const { return m_self_kart; }
|
||||
void kartFinishedRace(AbstractKart *kart, float time);
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns if this instance is in running state or not. */
|
||||
bool isRunning() { return m_running; }
|
||||
@@ -181,7 +181,9 @@ void STKHost::create()
|
||||
* When the authorised clients starts the kart selection, the SLR
|
||||
* informs all clients to start the kart selection (SLR::startSelection).
|
||||
* This triggers the creation of the kart selection screen in
|
||||
* CLR::startSelection / CLR::update. The kart selection in a client calls
|
||||
* CLR::startSelection / CLR::update for all clients. The clients create
|
||||
* the ActivePlayer object (which stores which device is used by which
|
||||
* plauyer). The kart selection in a client calls
|
||||
* (NetworkKartSelection::playerConfirm) which calls CLR::requestKartSelection.
|
||||
* This sends a message to SLR::kartSelectionRequested, which verifies the
|
||||
* selected kart and sends this information to all clients (including the
|
||||
@@ -208,6 +210,14 @@ void STKHost::create()
|
||||
* StartGameProtocol and the clients will be informed to start the game.
|
||||
* In a client the StartGame protocol will be started in CLR::startGame.
|
||||
*
|
||||
* The StartGame protocol will create the ActivePlayers for all non-local
|
||||
* players: on a server, all karts are non-local. On a client, the
|
||||
* ActivePlayer objects for each local players have been created (to store
|
||||
* the device used by each player when joining), so they are used to create
|
||||
* the LocalPlayerController for each kart. Each remote player gets a
|
||||
* NULL ActivePlayer (the ActivePlayer is only used for assigning the input
|
||||
* device to each kart, achievements and highscores, so it's not needed for
|
||||
* remote players).
|
||||
*/
|
||||
|
||||
// ============================================================================
|
||||
@@ -215,6 +225,7 @@ void STKHost::create()
|
||||
*/
|
||||
STKHost::STKHost(uint32_t server_id, uint32_t host_id)
|
||||
{
|
||||
m_next_unique_host_id = -1;
|
||||
// Will be overwritten with the correct value once a connection with the
|
||||
// server is made.
|
||||
m_host_id = 0;
|
||||
@@ -239,6 +250,9 @@ STKHost::STKHost(uint32_t server_id, uint32_t host_id)
|
||||
STKHost::STKHost(const irr::core::stringw &server_name)
|
||||
{
|
||||
init();
|
||||
// The host id will be increased whenever a new peer is added, so the
|
||||
// first client will have host id 1 (host id 0 is the server).
|
||||
m_next_unique_host_id = 0;
|
||||
m_host_id = 0; // indicates a server host.
|
||||
|
||||
ENetAddress addr;
|
||||
@@ -478,35 +492,21 @@ int STKHost::mustStopListening()
|
||||
return 1;
|
||||
} // mustStopListening
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
/** Returns true if this instance is allowed to control the server.
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Returns true if this client instance is allowed to control the server.
|
||||
* A client can authorise itself by providing the server's password. It is
|
||||
* then allowed to control the server (e.g. start kart selection).
|
||||
* The information if this client was authorised by the server is actually
|
||||
* stored in the peer (which is the server peer on a client).
|
||||
*/
|
||||
bool STKHost::isAuthorisedToControl() const
|
||||
{
|
||||
assert(NetworkConfig::get()->isClient());
|
||||
// If we are not properly connected (i.e. only enet connection, but not
|
||||
// stk logic), no peer is authorised.
|
||||
if(m_peers.size()==0)
|
||||
return false;
|
||||
Server *server = ServersManager::get()->getJoinedServer();
|
||||
return NetworkConfig::get()->getMyAddress().getIP() ==
|
||||
server->getAddress().getIP();
|
||||
|
||||
} // isAuthorisedToControl
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Server-side check if the client sending a command is really authorised
|
||||
* to do so.
|
||||
* \param peer Peer sending the command.
|
||||
*/
|
||||
bool STKHost::isAuthorisedToControl(const STKPeer *peer) const
|
||||
{
|
||||
// If we are not properly connected (i.e. only enet connection, but not
|
||||
// stk logic), no peer is authorised.
|
||||
if(m_peers.size()==0)
|
||||
return false;
|
||||
// FIXME peer has ip 0
|
||||
return true;
|
||||
return peer->getAddress()==NetworkConfig::get()->getMyAddress().getIP();
|
||||
return m_peers[0]->isAuthorised();
|
||||
} // isAuthorisedToControl
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@@ -661,6 +661,7 @@ STKPeer* STKHost::getPeer(ENetPeer *enet_peer)
|
||||
peer, enet_peer);
|
||||
|
||||
m_peers.push_back(peer);
|
||||
m_next_unique_host_id ++;
|
||||
return peer;
|
||||
} // getPeer
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
@@ -74,6 +74,12 @@ private:
|
||||
/** The list of peers connected to this instance. */
|
||||
std::vector<STKPeer*> m_peers;
|
||||
|
||||
/** Next unique host id. It is increased whenever a new peer is added (see
|
||||
* getPeer()), but not decreased whena host (=peer) disconnects. This
|
||||
* results in a unique host id for each host, even when a host should
|
||||
* disconnect and then reconnect. */
|
||||
int m_next_unique_host_id;
|
||||
|
||||
/** Host id of this host. */
|
||||
uint8_t m_host_id;
|
||||
|
||||
@@ -156,7 +162,6 @@ public:
|
||||
uint16_t getPort() const;
|
||||
void setErrorMessage(const irr::core::stringw &message);
|
||||
bool isAuthorisedToControl() const;
|
||||
bool isAuthorisedToControl(const STKPeer *peer) const;
|
||||
const irr::core::stringw&
|
||||
getErrorMessage() const;
|
||||
|
||||
@@ -201,6 +206,13 @@ public:
|
||||
/** Returns a const reference to the list of peers. */
|
||||
const std::vector<STKPeer*> &getPeers() { return m_peers; }
|
||||
// --------------------------------------------------------------------
|
||||
/** Returns the next (unique) host id. */
|
||||
unsigned int getNextHostId() const
|
||||
{
|
||||
assert(m_next_unique_host_id >= 0);
|
||||
return m_next_unique_host_id;
|
||||
}
|
||||
// --------------------------------------------------------------------
|
||||
/** Returns the number of currently connected peers. */
|
||||
unsigned int getPeerCount() { return (int)m_peers.size(); }
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
@@ -30,8 +30,10 @@
|
||||
STKPeer::STKPeer(ENetPeer *enet_peer)
|
||||
{
|
||||
m_enet_peer = enet_peer;
|
||||
m_is_authorised = false;
|
||||
m_player_profile = NULL;
|
||||
m_client_server_token = 0;
|
||||
m_host_id = 0;
|
||||
m_token_set = false;
|
||||
} // STKPeer
|
||||
|
||||
|
||||
@@ -50,6 +50,11 @@ protected:
|
||||
/** True if the token for this peer has been set. */
|
||||
bool m_token_set;
|
||||
|
||||
/** Host id of this peer. */
|
||||
int m_host_id;
|
||||
|
||||
/** True if this peer is authorised to control a server. */
|
||||
bool m_is_authorised;
|
||||
public:
|
||||
STKPeer(ENetPeer *enet_peer);
|
||||
virtual ~STKPeer();
|
||||
@@ -89,7 +94,22 @@ public:
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns if the token for this client is known. */
|
||||
bool isClientServerTokenSet() const { return m_token_set; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Sets the host if of this peer. */
|
||||
void setHostId(int host_id) { m_host_id = host_id; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the host id of this peer. */
|
||||
int getHostId() const { return m_host_id; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Sets if this peer is authorised to control the server. */
|
||||
void setAuthorised(bool authorised) { m_is_authorised = authorised; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns if this peer is authorised to control the server. The server
|
||||
* uses this to check if a peer is allowed certain commands; and a client
|
||||
* uses this function (in which case this peer is actually the server
|
||||
* peer) to see if this client is allowed certain command (i.e. to
|
||||
* display additional GUI elements). */
|
||||
bool isAuthorised() const { return m_is_authorised; }
|
||||
}; // STKPeer
|
||||
|
||||
#endif // STK_PEER_HPP
|
||||
|
||||
@@ -307,15 +307,14 @@ void Physics::update(float dt)
|
||||
|
||||
// Check for achievements
|
||||
AbstractKart * kart = World::getWorld()->getKart(f->getOwnerId());
|
||||
LocalPlayerController *c =
|
||||
LocalPlayerController *lpc =
|
||||
dynamic_cast<LocalPlayerController*>(kart->getController());
|
||||
|
||||
// Check that it's not a kart hitting itself (this can
|
||||
// happen at the time a flyable is shot - release too close
|
||||
// to the kart, and it's the current player. At this stage
|
||||
// only the current player can get achievements.
|
||||
if (target_kart != kart && c &&
|
||||
c->getPlayer()->getConstProfile() == PlayerManager::getCurrentPlayer())
|
||||
if (target_kart != kart && lpc && lpc->canGetAchievements())
|
||||
{
|
||||
// Compare the current value of hits with the 'hit' goal value
|
||||
// (otherwise it would be compared with the kart id goal value,
|
||||
|
||||
@@ -45,8 +45,8 @@
|
||||
#include "modes/soccer_world.hpp"
|
||||
#include "network/protocol_manager.hpp"
|
||||
#include "network/network_config.hpp"
|
||||
#include "network/network_world.hpp"
|
||||
#include "network/protocols/start_game_protocol.hpp"
|
||||
#include "network/race_event_manager.hpp"
|
||||
#include "replay/replay_play.hpp"
|
||||
#include "scriptengine/property_animator.hpp"
|
||||
#include "states_screens/grand_prix_cutscene.hpp"
|
||||
@@ -325,7 +325,7 @@ void RaceManager::startNew(bool from_overworld)
|
||||
m_num_laps = m_grand_prix.getLaps();
|
||||
m_reverse_track = m_grand_prix.getReverse();
|
||||
|
||||
if (!NetworkWorld::getInstance<NetworkWorld>()->isRunning())
|
||||
if (!RaceEventManager::getInstance<RaceEventManager>()->isRunning())
|
||||
{
|
||||
// We look if Player 1 has a saved version of this GP.
|
||||
m_saved_gp = SavedGrandPrix::getSavedGP(
|
||||
@@ -462,8 +462,8 @@ void RaceManager::startNextRace()
|
||||
IrrlichtDevice* device = irr_driver->getDevice();
|
||||
GUIEngine::renderLoading();
|
||||
device->getVideoDriver()->endScene();
|
||||
device->getVideoDriver()->beginScene(true, true, video::SColor(255,100,101,140));
|
||||
|
||||
device->getVideoDriver()->beginScene(true, true,
|
||||
video::SColor(255,100,101,140));
|
||||
|
||||
m_num_finished_karts = 0;
|
||||
m_num_finished_players = 0;
|
||||
@@ -577,7 +577,8 @@ void RaceManager::next()
|
||||
m_track_number++;
|
||||
if(m_track_number<(int)m_tracks.size())
|
||||
{
|
||||
if(m_major_mode==MAJOR_MODE_GRAND_PRIX && !NetworkWorld::getInstance()->isRunning())
|
||||
if( m_major_mode==MAJOR_MODE_GRAND_PRIX &&
|
||||
!RaceEventManager::getInstance()->isRunning() )
|
||||
{
|
||||
// Saving GP state
|
||||
saveGP();
|
||||
@@ -622,7 +623,8 @@ void RaceManager::saveGP()
|
||||
{
|
||||
// Delete other save files (and random GP, which should never
|
||||
// have been saved in the first place)
|
||||
const SavedGrandPrix &sgp = UserConfigParams::m_saved_grand_prix_list[i];
|
||||
const SavedGrandPrix &sgp =
|
||||
UserConfigParams::m_saved_grand_prix_list[i];
|
||||
if (sgp.getGPID() == "random" ||
|
||||
(sgp.getGPID() == m_saved_gp->getGPID() &&
|
||||
sgp.getDifficulty() == m_saved_gp->getDifficulty()) )
|
||||
@@ -700,9 +702,10 @@ void RaceManager::computeGPRanks()
|
||||
sort_data.push_back(sd);
|
||||
if(UserConfigParams::m_ftl_debug)
|
||||
{
|
||||
Log::debug("Race Manager","[ftl] kart '%s' has position %d score %d.",
|
||||
World::getWorld()->getKart(kart_id)->getIdent().c_str(),
|
||||
sd->m_position, sd->m_score);
|
||||
Log::debug("Race Manager",
|
||||
"[ftl] kart '%s' has position %d score %d.",
|
||||
World::getWorld()->getKart(kart_id)->getIdent().c_str(),
|
||||
sd->m_position, sd->m_score);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -731,10 +734,12 @@ void RaceManager::exitRace(bool delete_world)
|
||||
{
|
||||
// Only display the grand prix result screen if all tracks
|
||||
// were finished, and not when a race is aborted.
|
||||
if (m_major_mode==MAJOR_MODE_GRAND_PRIX && m_track_number==(int)m_tracks.size())
|
||||
if ( m_major_mode==MAJOR_MODE_GRAND_PRIX &&
|
||||
m_track_number==(int)m_tracks.size() )
|
||||
{
|
||||
PlayerManager::getCurrentPlayer()->grandPrixFinished();
|
||||
if(m_major_mode==MAJOR_MODE_GRAND_PRIX&& !NetworkWorld::getInstance()->isRunning())
|
||||
if( m_major_mode==MAJOR_MODE_GRAND_PRIX &&
|
||||
!RaceEventManager::getInstance()->isRunning() )
|
||||
{
|
||||
if(m_saved_gp != NULL)
|
||||
m_saved_gp->remove();
|
||||
@@ -747,7 +752,8 @@ void RaceManager::exitRace(bool delete_world)
|
||||
const int loserThreshold = 3;
|
||||
|
||||
std::string winners[3];
|
||||
std::vector<std::string> humanLosers; // because we don't care about AIs that lost
|
||||
// because we don't care about AIs that lost
|
||||
std::vector<std::string> humanLosers;
|
||||
for (unsigned int i=0; i < kart_status_count; ++i)
|
||||
{
|
||||
if(UserConfigParams::logMisc())
|
||||
@@ -790,14 +796,16 @@ void RaceManager::exitRace(bool delete_world)
|
||||
|
||||
if (some_human_player_won)
|
||||
{
|
||||
race_manager->startSingleRace("gpwin", 999, race_manager->raceWasStartedFromOverworld());
|
||||
race_manager->startSingleRace("gpwin", 999,
|
||||
race_manager->raceWasStartedFromOverworld());
|
||||
GrandPrixWin* scene = GrandPrixWin::getInstance();
|
||||
scene->push();
|
||||
scene->setKarts(winners);
|
||||
}
|
||||
else
|
||||
{
|
||||
race_manager->startSingleRace("gplose", 999, race_manager->raceWasStartedFromOverworld());
|
||||
race_manager->startSingleRace("gplose", 999,
|
||||
race_manager->raceWasStartedFromOverworld());
|
||||
GrandPrixLose* scene = GrandPrixLose::getInstance();
|
||||
scene->push();
|
||||
|
||||
@@ -851,7 +859,8 @@ void RaceManager::kartFinishedRace(const AbstractKart *kart, float time)
|
||||
m_kart_status[id].m_score += wwr->getScoreForPosition(pos);
|
||||
else
|
||||
{
|
||||
Log::error("RaceManager", "World with scores that is not a WorldWithRank??");
|
||||
Log::error("RaceManager",
|
||||
"World with scores that is not a WorldWithRank??");
|
||||
}
|
||||
|
||||
m_kart_status[id].m_overall_time += time;
|
||||
@@ -912,7 +921,9 @@ void RaceManager::startSingleRace(const std::string &track_ident,
|
||||
setMajorMode(RaceManager::MAJOR_MODE_SINGLE);
|
||||
|
||||
setCoinTarget( 0 ); // Might still be set from a previous challenge
|
||||
if (!NetworkWorld::getInstance<NetworkWorld>()->isRunning()) // if not in a network world
|
||||
|
||||
// if not in a network world, setup player karts
|
||||
if (!RaceEventManager::getInstance<RaceEventManager>()->isRunning())
|
||||
race_manager->setupPlayerKartInfo(); // do this setup player kart
|
||||
|
||||
startNew(from_overworld);
|
||||
|
||||
@@ -1205,15 +1205,10 @@ void KartSelectionScreen::allPlayersDone()
|
||||
// ---- Switch to assign mode
|
||||
input_manager->getDeviceManager()->setAssignMode(ASSIGN);
|
||||
|
||||
if (!m_multiplayer)
|
||||
{
|
||||
input_manager->getDeviceManager()
|
||||
->setSinglePlayer( StateManager::get()->getActivePlayer(0) );
|
||||
}
|
||||
else
|
||||
{
|
||||
input_manager->getDeviceManager()->setSinglePlayer( NULL );
|
||||
}
|
||||
StateManager::ActivePlayer *ap = m_multiplayer
|
||||
? NULL
|
||||
: StateManager::get()->getActivePlayer(0);
|
||||
input_manager->getDeviceManager()->setSinglePlayer(ap);
|
||||
|
||||
// ---- Go to next screen or return to overworld
|
||||
if (m_from_overworld || m_go_to_overworld_next)
|
||||
|
||||
@@ -68,8 +68,6 @@ void NetworkKartSelectionScreen::init()
|
||||
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 = STKHost::get()->getGameSetup();
|
||||
if (!setup)
|
||||
@@ -95,6 +93,7 @@ void NetworkKartSelectionScreen::init()
|
||||
// FIXME: atm only adds the local master, split screen supports
|
||||
// needs to be added
|
||||
int player_id = game_setup->getLocalMasterID();
|
||||
m_id_mapping.clear();
|
||||
m_id_mapping.insert(m_id_mapping.begin(), player_id);
|
||||
|
||||
const int amount = m_kart_widgets.size();
|
||||
@@ -180,6 +179,8 @@ void NetworkKartSelectionScreen::playerSelected(uint8_t player_id,
|
||||
clrp->voteMinor(race_manager->getMinorMode());
|
||||
clrp->voteReversed(race_manager->getReverseTrack());
|
||||
clrp->voteRaceCount(1);
|
||||
// FIXME: for debugging set only 0 laps
|
||||
clrp->voteLaps(0);
|
||||
}
|
||||
TracksScreen::getInstance()->push();
|
||||
} // playerSelected
|
||||
|
||||
@@ -47,8 +47,18 @@ using namespace GUIEngine;
|
||||
|
||||
DEFINE_SCREEN_SINGLETON( NetworkingLobby );
|
||||
|
||||
/** This is the lobby screen that is shown on all clients, but not on the
|
||||
* server. It shows currently connected clients, and allows the 'master'
|
||||
* client (i.e. the stk instance that created the server) to control the
|
||||
* server. This especially means that it can initialise the actual start
|
||||
* of the racing.
|
||||
* This class is responsible for creating the ActivePlayers data structure
|
||||
* for all local players (the ActivePlayer maps device to player, i.e.
|
||||
* controls which device is used by which player). Note that a server
|
||||
* does not create an instance of this class and will create the ActivePlayer
|
||||
* data structure in the StartGameProtocol.
|
||||
*/
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
NetworkingLobby::NetworkingLobby() : Screen("online/networking_lobby.stkgui")
|
||||
{
|
||||
m_server = NULL;
|
||||
@@ -88,9 +98,11 @@ void NetworkingLobby::beforeAddingWidget()
|
||||
|
||||
} // beforeAddingWidget
|
||||
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** This function is a callback from the parent class, and is called each time
|
||||
* this screen is shown to initialise the screen. This class is responsible
|
||||
* for creating the active players and binding them to the right device.
|
||||
*/
|
||||
void NetworkingLobby::init()
|
||||
{
|
||||
Screen::init();
|
||||
@@ -98,9 +110,13 @@ void NetworkingLobby::init()
|
||||
m_server = ServersManager::get()->getJoinedServer();
|
||||
if(m_server)
|
||||
m_server_name_widget->setText(m_server->getName(), false);
|
||||
|
||||
m_start_button->setVisible(STKHost::get()->isAuthorisedToControl());
|
||||
|
||||
// For now create the active player and bind it to the right
|
||||
// input device.
|
||||
InputDevice *device = input_manager->getDeviceManager()->getLatestUsedDevice();
|
||||
PlayerProfile* profile = PlayerManager::getCurrentPlayer();
|
||||
StateManager::get()->createActivePlayer(profile, device);
|
||||
} // init
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
@@ -485,9 +485,6 @@ void RaceResultGUI::determineTableLayout()
|
||||
else
|
||||
ri->m_kart_name = translations->fribidize(kart->getName());
|
||||
|
||||
ri->m_player = ri->m_is_player_kart
|
||||
? kart->getController()->getPlayer() : NULL;
|
||||
|
||||
video::ITexture *icon =
|
||||
kart->getKartProperties()->getIconMaterial()->getTexture();
|
||||
ri->m_kart_icon = icon;
|
||||
@@ -861,8 +858,6 @@ void RaceResultGUI::determineGPLayout()
|
||||
ri->m_kart_name = translations->fribidize(kart->getName());
|
||||
|
||||
ri->m_is_player_kart = kart->getController()->isLocalPlayerController();
|
||||
ri->m_player = ri->m_is_player_kart
|
||||
? kart->getController()->getPlayer() : NULL;
|
||||
|
||||
// In FTL karts do have a time, which is shown even when the kart
|
||||
// is eliminated
|
||||
@@ -1171,22 +1166,14 @@ void RaceResultGUI::displaySoccerResults()
|
||||
|
||||
void RaceResultGUI::clearHighscores()
|
||||
{
|
||||
m_highscore_who = "";
|
||||
m_highscore_player = NULL;
|
||||
m_highscore_rank = 0;
|
||||
m_highscore_time = -1;
|
||||
} // clearHighscores
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void RaceResultGUI::setHighscore(const std::string &who,
|
||||
StateManager::ActivePlayer* player, int rank,
|
||||
int time)
|
||||
void RaceResultGUI::setHighscore(int rank)
|
||||
{
|
||||
m_highscore_who = who;
|
||||
m_highscore_player = player;
|
||||
m_highscore_rank = rank;
|
||||
m_highscore_time = time;
|
||||
} // setHighscore
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
@@ -82,8 +82,6 @@ private:
|
||||
float m_y_pos;
|
||||
/** True if kart is a player kart. */
|
||||
bool m_is_player_kart;
|
||||
/** Only if m_is_player_kart is true */
|
||||
const StateManager::ActivePlayer* m_player;
|
||||
/** The radius to use when sorting the entries. Positive values
|
||||
will rotate downwards, negatives are upwards. */
|
||||
float m_radius;
|
||||
@@ -170,18 +168,9 @@ private:
|
||||
/** Music to be played after race ended. */
|
||||
MusicInformation *m_race_over_music;
|
||||
|
||||
/** For highscores */
|
||||
std::string m_highscore_who;
|
||||
|
||||
/** For highscores */
|
||||
StateManager::ActivePlayer *m_highscore_player;
|
||||
|
||||
/** For highscores */
|
||||
int m_highscore_rank;
|
||||
|
||||
/** For highscores */
|
||||
int m_highscore_time;
|
||||
|
||||
unsigned int m_width_all_points;
|
||||
|
||||
int m_max_tracks;
|
||||
@@ -261,8 +250,7 @@ public:
|
||||
* \param rank Highscore rank (first highscore, second highscore, etc.). This is not the race rank
|
||||
* \param time Finish time in seconds
|
||||
*/
|
||||
void setHighscore(const std::string &kart,
|
||||
StateManager::ActivePlayer* player, int rank, int time);
|
||||
void setHighscore(int rank);
|
||||
|
||||
virtual void onConfirm();
|
||||
}; // RaceResultGUI
|
||||
|
||||
Reference in New Issue
Block a user