Merge remote-tracking branch 'origin/master' into fix_replay

This commit is contained in:
Benau
2016-02-16 09:57:41 +08:00
72 changed files with 1000 additions and 824 deletions

View File

@@ -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.
*/

View File

@@ -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:

View File

@@ -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

View File

@@ -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");
}

View File

@@ -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)

View File

@@ -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;

View File

@@ -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();

View File

@@ -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;

View File

@@ -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 &&

View File

@@ -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

View File

@@ -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

View File

@@ -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 ();

View File

@@ -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();

View File

@@ -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 ();

View File

@@ -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
// ----------------------------------------------------------------------------

View File

@@ -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

View File

@@ -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 &&

View File

@@ -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

View File

@@ -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

View File

@@ -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);

View File

@@ -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

View File

@@ -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

View File

@@ -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.");

View File

@@ -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

View File

@@ -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;

View File

@@ -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();

View File

@@ -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 ();

View File

@@ -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);

View File

@@ -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;

View File

@@ -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 {

View File

@@ -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;

View File

@@ -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

View File

@@ -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();
}

View File

@@ -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();

View File

@@ -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*

View File

@@ -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)

View File

@@ -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

View File

@@ -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();

View File

@@ -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. */

View File

@@ -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

View File

@@ -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. */

View File

@@ -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

View File

@@ -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

View File

@@ -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();

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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",

View File

@@ -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);

View File

@@ -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,

View File

@@ -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

View File

@@ -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() {}
// ------------------------------------------------------------------------

View File

@@ -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

View File

@@ -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

View File

@@ -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
//-----------------------------------------------------------------------------

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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
{

View File

@@ -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));

View 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; }

View File

@@ -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
// ----------------------------------------------------------------------------

View File

@@ -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(); }
// --------------------------------------------------------------------

View File

@@ -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

View File

@@ -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

View File

@@ -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,

View File

@@ -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);

View File

@@ -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)

View File

@@ -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

View File

@@ -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
// ----------------------------------------------------------------------------

View File

@@ -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
// ----------------------------------------------------------------------------

View File

@@ -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