Let only the server decide when a kart finished the race. Notify
all clients if this happens.
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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() {}
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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; }
|
||||
|
||||
Reference in New Issue
Block a user