Let only the server decide when a kart finished the race. Notify

all clients if this happens.
This commit is contained in:
hiker
2016-02-15 17:45:24 +11:00
parent 1ad782e6a6
commit d15a234ace
7 changed files with 83 additions and 7 deletions

View File

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

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

View File

@@ -271,8 +271,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

@@ -44,7 +44,7 @@ bool GameEventsProtocol::notifyEvent(Event* event)
data.removeFront(5);
switch (type)
{
case 0x01: // item picked
case GE_ITEM_COLLECTED:
{
if (data.size() < 6)
{
@@ -65,6 +65,9 @@ bool GameEventsProtocol::notifyEvent(Event* event)
Log::info("GameEventsProtocol", "Item %d picked by a player.",
powerup_type);
} break;
case GE_KART_FINISHED_RACE:
kartFinishedRace(data);
break;
default:
Log::warn("GameEventsProtocol", "Unkown message type.");
break;
@@ -104,8 +107,8 @@ 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(player_profile->getGlobalPlayerId());
ProtocolManager::getInstance()->sendMessage(this, peers[i], ns,
/*reliable*/true,
/*synchronous*/true);
@@ -114,3 +117,39 @@ void GameEventsProtocol::collectedItem(Item* item, AbstractKart* kart)
(int)(kart->getPowerup()->getType()));
}
} // 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,8 @@ public:
virtual void setup();
virtual void update();
void collectedItem(Item* item, AbstractKart* kart);
void kartFinishedRace(AbstractKart *kart, float time);
void kartFinishedRace(const NetworkString &ns);
// ------------------------------------------------------------------------
virtual void asynchronousUpdate() {}
// ------------------------------------------------------------------------

View File

@@ -76,6 +76,14 @@ bool RaceEventManager::isRaceOver()
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.

View File

@@ -58,6 +58,7 @@ public:
void collectedItem(Item *item, AbstractKart *kart);
void controllerAction(Controller* controller, PlayerAction action,
int value);
void kartFinishedRace(AbstractKart *kart, float time);
// ------------------------------------------------------------------------
/** Returns if this instance is in running state or not. */
bool isRunning() { return m_running; }