diff --git a/src/modes/linear_world.cpp b/src/modes/linear_world.cpp index 21786f1a7..9e05eab26 100644 --- a/src/modes/linear_world.cpp +++ b/src/modes/linear_world.cpp @@ -33,7 +33,9 @@ #include "physics/physics.hpp" #include "network/network_config.hpp" #include "network/network_string.hpp" +#include "network/protocols/game_events_protocol.hpp" #include "network/server_config.hpp" +#include "network/stk_host.hpp" #include "race/history.hpp" #include "states_screens/race_gui_base.hpp" #include "tracks/check_manager.hpp" @@ -1156,3 +1158,66 @@ void LinearWorld::restoreCompleteState(const BareNetworkString& b) for (unsigned i = 0; i < cc; i++) CheckManager::get()->getCheckStructure(i)->restoreCompleteState(b); } // restoreCompleteState + +// ---------------------------------------------------------------------------- +/** Called in server whenever a kart cross a check line, it send server + * all karts lap count, last triggered checkline and check structure status + * to all players in game (including spectators so that the lap count is + * correct) + */ +void LinearWorld::updateCheckLinesServer() +{ + if (!NetworkConfig::get()->isNetworking() || + NetworkConfig::get()->isClient()) + return; + + NetworkString cl(PROTOCOL_GAME_EVENTS); + cl.setSynchronous(true); + cl.addUInt8(GameEventsProtocol::GE_CHECK_LINE); + + for (KartInfo& ki : m_kart_info) + { + int8_t finished_laps = (int8_t)ki.m_finished_laps; + cl.addUInt8(finished_laps); + } + + for (TrackSector* ts : m_kart_track_sector) + { + int8_t ltcl = (int8_t)ts->getLastTriggeredCheckline(); + cl.addUInt8(ltcl); + } + + const uint8_t cc = (uint8_t)CheckManager::get()->getCheckStructureCount(); + cl.addUInt8(cc); + for (unsigned i = 0; i < cc; i++) + CheckManager::get()->getCheckStructure(i)->saveIsActive(&cl); + + STKHost::get()->sendPacketToAllPeers(&cl, true); +} // updateCheckLinesServer + +// ---------------------------------------------------------------------------- +/* Synchronize with server from the above data. */ +void LinearWorld::updateCheckLinesClient(const BareNetworkString& b) +{ + for (KartInfo& ki : m_kart_info) + { + int8_t finished_laps = b.getUInt8(); + ki.m_finished_laps = finished_laps; + } + + for (TrackSector* ts : m_kart_track_sector) + { + int8_t ltcl = b.getUInt8(); + ts->setLastTriggeredCheckline(ltcl); + } + + const unsigned cc = b.getUInt8(); + if (cc != CheckManager::get()->getCheckStructureCount()) + { + throw std::invalid_argument( + "Server has different check structures size."); + } + for (unsigned i = 0; i < cc; i++) + CheckManager::get()->getCheckStructure(i)->restoreIsActive(b); + +} // updateCheckLinesClient diff --git a/src/modes/linear_world.hpp b/src/modes/linear_world.hpp index 09f2408be..e28cc9297 100644 --- a/src/modes/linear_world.hpp +++ b/src/modes/linear_world.hpp @@ -220,6 +220,10 @@ public: virtual void saveCompleteState(BareNetworkString* bns) OVERRIDE; // ------------------------------------------------------------------------ virtual void restoreCompleteState(const BareNetworkString& b) OVERRIDE; + // ------------------------------------------------------------------------ + void updateCheckLinesServer(); + // ------------------------------------------------------------------------ + void updateCheckLinesClient(const BareNetworkString& b); }; // LinearWorld #endif diff --git a/src/network/protocols/game_events_protocol.cpp b/src/network/protocols/game_events_protocol.cpp index 40dadd2ee..5dacccfe5 100644 --- a/src/network/protocols/game_events_protocol.cpp +++ b/src/network/protocols/game_events_protocol.cpp @@ -3,6 +3,7 @@ #include "karts/abstract_kart.hpp" #include "karts/controller/player_controller.hpp" #include "modes/capture_the_flag.hpp" +#include "modes/linear_world.hpp" #include "modes/soccer_world.hpp" #include "network/event.hpp" #include "network/game_setup.hpp" @@ -52,6 +53,7 @@ bool GameEventsProtocol::notifyEvent(Event* event) CaptureTheFlag* ctf = dynamic_cast(World::getWorld()); FreeForAll* ffa = dynamic_cast(World::getWorld()); SoccerWorld* sw = dynamic_cast(World::getWorld()); + LinearWorld* lw = dynamic_cast(World::getWorld()); switch (type) { case GE_KART_FINISHED_RACE: @@ -126,6 +128,14 @@ bool GameEventsProtocol::notifyEvent(Event* event) } break; } + case GE_CHECK_LINE: + { + if (!lw) + throw std::invalid_argument("No linear world"); + if (NetworkConfig::get()->isClient()) + lw->updateCheckLinesClient(data); + break; + } default: Log::warn("GameEventsProtocol", "Unkown message type."); break; diff --git a/src/network/protocols/game_events_protocol.hpp b/src/network/protocols/game_events_protocol.hpp index a2b9b2d55..830221b01 100644 --- a/src/network/protocols/game_events_protocol.hpp +++ b/src/network/protocols/game_events_protocol.hpp @@ -17,6 +17,7 @@ public: GE_CTF_SCORED = 4, GE_RESET_BALL = 5, GE_PLAYER_GOAL = 6, + GE_CHECK_LINE = 7 }; // GameEventType private: int m_last_finished_position; diff --git a/src/tracks/check_lap.hpp b/src/tracks/check_lap.hpp index d8b6f82f3..5f932a9a7 100644 --- a/src/tracks/check_lap.hpp +++ b/src/tracks/check_lap.hpp @@ -20,6 +20,7 @@ #define HEADER_CHECK_LAP_HPP #include "tracks/check_structure.hpp" +#include "utils/cpp2011.hpp" class XMLNode; class CheckManager; @@ -40,8 +41,9 @@ public: CheckLap(const XMLNode &node, unsigned int index); virtual ~CheckLap() {}; virtual bool isTriggered(const Vec3 &old_pos, const Vec3 &new_pos, - int indx); - virtual void reset(const Track &track); + int indx) OVERRIDE; + virtual void reset(const Track &track) OVERRIDE; + virtual bool triggeringCheckline() const OVERRIDE { return true; } }; // CheckLine #endif diff --git a/src/tracks/check_line.hpp b/src/tracks/check_line.hpp index 7ff751a45..c80ca24a5 100644 --- a/src/tracks/check_line.hpp +++ b/src/tracks/check_line.hpp @@ -26,6 +26,7 @@ using namespace irr; #include "tracks/check_structure.hpp" +#include "utils/cpp2011.hpp" class XMLNode; class CheckManager; @@ -88,11 +89,11 @@ public: CheckLine(const XMLNode &node, unsigned int index); virtual ~CheckLine(); virtual bool isTriggered(const Vec3 &old_pos, const Vec3 &new_pos, - int indx); - virtual void reset(const Track &track); - virtual void resetAfterKartMove(unsigned int kart_index); - virtual void changeDebugColor(bool is_active); - virtual bool triggeringCheckline() const { return true; } + int indx) OVERRIDE; + virtual void reset(const Track &track) OVERRIDE; + virtual void resetAfterKartMove(unsigned int kart_index) OVERRIDE; + virtual void changeDebugColor(bool is_active) OVERRIDE; + virtual bool triggeringCheckline() const OVERRIDE { return true; } // ------------------------------------------------------------------------ /** Returns the actual line data for this checkpoint. */ const core::line2df &getLine2D() const {return m_line;} @@ -102,9 +103,9 @@ public: * be too heigh to otherwise trigger he cannon). */ void setIgnoreHeight(bool b) { m_ignore_height = b; } // ------------------------------------------------------------------------ - virtual void saveCompleteState(BareNetworkString* bns); + virtual void saveCompleteState(BareNetworkString* bns) OVERRIDE; // ------------------------------------------------------------------------ - virtual void restoreCompleteState(const BareNetworkString& b); + virtual void restoreCompleteState(const BareNetworkString& b) OVERRIDE; }; // CheckLine #endif diff --git a/src/tracks/check_structure.cpp b/src/tracks/check_structure.cpp index ca6544ff5..9c31f258c 100644 --- a/src/tracks/check_structure.cpp +++ b/src/tracks/check_structure.cpp @@ -101,6 +101,7 @@ void CheckStructure::reset(const Track &track) void CheckStructure::update(float dt) { World *world = World::getWorld(); + LinearWorld* lw = dynamic_cast(World::getWorld()); for(unsigned int i=0; igetNumKarts(); i++) { const Vec3 &xyz = world->getKart(i)->getFrontXYZ(); @@ -114,6 +115,8 @@ void CheckStructure::update(float dt) m_index, world->getKart(i)->getIdent().c_str(), World::getWorld()->getTime()); trigger(i); + if (triggeringCheckline() && lw) + lw->updateCheckLinesServer(); } m_previous_position[i] = xyz; } // for igetNumKarts(); i++) + bns->addUInt8(m_is_active[i] ? 1 : 0); +} // saveIsActive + +// ---------------------------------------------------------------------------- +void CheckStructure::restoreIsActive(const BareNetworkString& b) +{ + m_is_active.clear(); + World* world = World::getWorld(); + for (unsigned int i = 0; i < world->getNumKarts(); i++) + { + bool is_active = b.getUInt8() == 1; + m_is_active.push_back(is_active); + } +} // restoreIsActive diff --git a/src/tracks/check_structure.hpp b/src/tracks/check_structure.hpp index bc39365bd..e9fb44ed4 100644 --- a/src/tracks/check_structure.hpp +++ b/src/tracks/check_structure.hpp @@ -131,9 +131,15 @@ public: m_check_structures_to_change_state.push_back(i); } // addSuccessor // ------------------------------------------------------------------------ + virtual bool triggeringCheckline() const { return false; } + // ------------------------------------------------------------------------ virtual void saveCompleteState(BareNetworkString* bns); // ------------------------------------------------------------------------ virtual void restoreCompleteState(const BareNetworkString& b); + // ------------------------------------------------------------------------ + void saveIsActive(BareNetworkString* bns); + // ------------------------------------------------------------------------ + void restoreIsActive(const BareNetworkString& b); }; // CheckStructure #endif diff --git a/src/tracks/track_sector.hpp b/src/tracks/track_sector.hpp index f8362edc2..c57389faf 100644 --- a/src/tracks/track_sector.hpp +++ b/src/tracks/track_sector.hpp @@ -90,6 +90,9 @@ public: // ------------------------------------------------------------------------ void setLastTriggeredCheckline(int i) { m_last_triggered_checkline = i; } // ------------------------------------------------------------------------ + int getLastTriggeredCheckline() const + { return m_last_triggered_checkline; } + // ------------------------------------------------------------------------ int getLastValidGraphNode() const { return m_last_valid_graph_node; } // ------------------------------------------------------------------------ void saveState(BareNetworkString* buffer) const;