From: <tz...@us...> - 2008-02-09 20:17:50
|
Revision: 2313 http://freeorion.svn.sourceforge.net/freeorion/revision/?rev=2313&view=rev Author: tzlaine Date: 2008-02-09 12:17:54 -0800 (Sat, 09 Feb 2008) Log Message: ----------- Fixed a bug in the way player eliminations were being handled. Now eliminated players don't end the game for everyone else. In fixing this, it was necessary to add a facility for reporting eliminated empires to all code that needs to know about it -- some data structures have empire-specific data stored in them extrinsic to the Empires proper. ClientApp now has a signal that is emitted by the player-eliminated handler in HumanClientFSM when a player is eliminated. Modified Paths: -------------- trunk/FreeOrion/UI/MapWnd.cpp trunk/FreeOrion/UI/MapWnd.h trunk/FreeOrion/client/ClientApp.cpp trunk/FreeOrion/client/ClientApp.h trunk/FreeOrion/client/human/HumanClientFSM.cpp trunk/FreeOrion/network/Message.cpp trunk/FreeOrion/network/Message.h trunk/FreeOrion/server/ServerApp.cpp trunk/FreeOrion/server/ServerApp.h trunk/FreeOrion/universe/Universe.cpp trunk/FreeOrion/universe/Universe.h Modified: trunk/FreeOrion/UI/MapWnd.cpp =================================================================== --- trunk/FreeOrion/UI/MapWnd.cpp 2008-02-09 03:40:31 UTC (rev 2312) +++ trunk/FreeOrion/UI/MapWnd.cpp 2008-02-09 20:17:54 UTC (rev 2313) @@ -346,6 +346,8 @@ boost::shared_ptr<GG::BrowseInfoWnd> browser_wnd(new BrowseFoo()); GG::Wnd::SetDefaultBrowseInfoWnd(browser_wnd); #endif + + Connect(ClientApp::GetApp()->EmpireEliminatedSignal, &MapWnd::HandleEmpireElimination, this); } MapWnd::~MapWnd() @@ -1742,6 +1744,12 @@ } } +void MapWnd::HandleEmpireElimination(int empire_id) +{ + m_empire_system_fleet_supply.erase(empire_id); + m_empire_fleet_supply_lanes.erase(empire_id); +} + void MapWnd::UniverseObjectDeleted(const UniverseObject *obj) { m_fleet_lines.erase(const_cast<Fleet*>(universe_object_cast<const Fleet*>(obj))); } Modified: trunk/FreeOrion/UI/MapWnd.h =================================================================== --- trunk/FreeOrion/UI/MapWnd.h 2008-02-09 03:40:31 UTC (rev 2312) +++ trunk/FreeOrion/UI/MapWnd.h 2008-02-09 20:17:54 UTC (rev 2313) @@ -205,6 +205,7 @@ void ShowAllPopups(); void FleetWndClosing(FleetWnd* fleet_wnd); + void HandleEmpireElimination(int empire_id); //!< cleans up internal storage of now-invalidated empire ID std::set<GG::Key> m_disabled_accels_list; //!< the list of Accelerators disabled by \a DisableAlphaNumAccels Modified: trunk/FreeOrion/client/ClientApp.cpp =================================================================== --- trunk/FreeOrion/client/ClientApp.cpp 2008-02-09 03:40:31 UTC (rev 2312) +++ trunk/FreeOrion/client/ClientApp.cpp 2008-02-09 20:17:54 UTC (rev 2313) @@ -17,6 +17,10 @@ m_empire_id(-1), m_current_turn(INVALID_GAME_TURN) { +#ifdef FREEORION_BUILD_HUMAN + EmpireEliminatedSignal.connect(boost::bind(&Universe::HandleEmpireElimination, &m_universe, _1)); +#endif + if (s_app) throw std::runtime_error("Attempted to construct a second instance of ClientApp"); s_app = this; Modified: trunk/FreeOrion/client/ClientApp.h =================================================================== --- trunk/FreeOrion/client/ClientApp.h 2008-02-09 03:40:31 UTC (rev 2312) +++ trunk/FreeOrion/client/ClientApp.h 2008-02-09 20:17:54 UTC (rev 2313) @@ -59,6 +59,11 @@ Can return UniverseObject::INVALID_OBJECT_ID if an ID cannot be created. */ int GetNewDesignID(); + /** Emitted when a player is eliminated; in many places in the code, empires + are refered to by ID. This allows such places to listen for + notification that one of these IDs has become invalidated.*/ + mutable boost::signal<void (int)> EmpireEliminatedSignal; + static ClientApp* GetApp(); ///< returns the singleton ClientApp object protected: Modified: trunk/FreeOrion/client/human/HumanClientFSM.cpp =================================================================== --- trunk/FreeOrion/client/human/HumanClientFSM.cpp 2008-02-09 03:40:31 UTC (rev 2312) +++ trunk/FreeOrion/client/human/HumanClientFSM.cpp 2008-02-09 20:17:54 UTC (rev 2313) @@ -305,8 +305,12 @@ boost::statechart::result PlayingGame::react(const PlayerEliminated& msg) { if (TRACE_EXECUTION) Logger().debugStream() << "(HumanClientFSM) PlayingGame.PlayerEliminated"; + int empire_id; + std::string empire_name; + ExtractMessageData(msg.m_message, empire_id, empire_name); + Client().EmpireEliminatedSignal(empire_id); // TODO: replace this with something better - ClientUI::MessageBox(boost::io::str(boost::format(UserString("EMPIRE_DEFEATED")) % msg.m_message.Text())); + ClientUI::MessageBox(boost::io::str(boost::format(UserString("EMPIRE_DEFEATED")) % empire_name)); return discard_event(); } Modified: trunk/FreeOrion/network/Message.cpp =================================================================== --- trunk/FreeOrion/network/Message.cpp 2008-02-09 03:40:31 UTC (rev 2312) +++ trunk/FreeOrion/network/Message.cpp 2008-02-09 20:17:54 UTC (rev 2313) @@ -427,9 +427,15 @@ return Message(Message::HUMAN_PLAYER_CHAT, sender, receiver, msg); } -Message PlayerEliminatedMessage(int receiver, const std::string& empire_name) +Message PlayerEliminatedMessage(int receiver, int empire_id, const std::string& empire_name) { - return Message(Message::PLAYER_ELIMINATED, -1, receiver, empire_name); + std::ostringstream os; + { + FREEORION_OARCHIVE_TYPE oa(os); + oa << BOOST_SERIALIZATION_NVP(empire_id) + << BOOST_SERIALIZATION_NVP(empire_name); + } + return Message(Message::PLAYER_ELIMINATED, -1, receiver, os.str()); } @@ -624,3 +630,17 @@ throw; } } + +void ExtractMessageData(const Message& msg, int& empire_id, std::string& empire_name) +{ + try { + std::istringstream is(msg.Text()); + FREEORION_IARCHIVE_TYPE ia(is); + ia >> BOOST_SERIALIZATION_NVP(empire_id) + >> BOOST_SERIALIZATION_NVP(empire_name); + } catch (const boost::archive::archive_exception &e) { + std::cerr << "ExtractMessageData(const Message& msg, int empire_id, std::string& empire_name) failed! " + << "Message:\n" << msg.Text() << std::endl; + throw; + } +} Modified: trunk/FreeOrion/network/Message.h =================================================================== --- trunk/FreeOrion/network/Message.h 2008-02-09 03:40:31 UTC (rev 2312) +++ trunk/FreeOrion/network/Message.h 2008-02-09 20:17:54 UTC (rev 2313) @@ -220,7 +220,7 @@ /** creates a PLAYER_ELIMINATED message, which is sent to all clients when a client is eliminated from play. This message should only be sent by the server.*/ -Message PlayerEliminatedMessage(int receiver, const std::string& empire_name); +Message PlayerEliminatedMessage(int receiver, int empire_id, const std::string& empire_name); //////////////////////////////////////////////// @@ -280,4 +280,6 @@ void ExtractMessageData(const Message& msg, Message::EndGameReason& reason, std::string& reason_player_name); +void ExtractMessageData(const Message& msg, int& empire_id, std::string& empire_name); + #endif // _Message_h_ Modified: trunk/FreeOrion/server/ServerApp.cpp =================================================================== --- trunk/FreeOrion/server/ServerApp.cpp 2008-02-09 03:40:31 UTC (rev 2312) +++ trunk/FreeOrion/server/ServerApp.cpp 2008-02-09 20:17:54 UTC (rev 2313) @@ -132,7 +132,7 @@ args.push_back("--log-level"); args.push_back(GetOptionsDB().Get<std::string>("log-level")); Logger().debugStream() << "starting " << AI_CLIENT_EXE; - m_ai_clients.push_back(Process(AI_CLIENT_EXE, args)); + m_ai_clients[player_name] = Process(AI_CLIENT_EXE, args); Logger().debugStream() << "done starting " << AI_CLIENT_EXE; } } @@ -165,8 +165,8 @@ void ServerApp::CleanupAIs() { - for (unsigned int i = 0; i < m_ai_clients.size(); ++i) { - m_ai_clients[i].Kill(); + for (std::map<std::string, Process>::iterator it = m_ai_clients.begin(); it != m_ai_clients.end(); ++it) { + it->second.Kill(); } } @@ -709,13 +709,16 @@ object_vec[j]->RemoveOwner(it->second); } + std::map<std::string, Process> processes_copy = m_ai_clients; // notify all players of the eliminated players for (std::map<int, int>::iterator it = eliminations.begin(); it != eliminations.end(); ++it) { for (ServerNetworking::const_established_iterator player_it = m_networking.established_begin(); player_it != m_networking.established_end(); ++player_it) { - if ((*player_it)->ID() == it->first) + if ((*player_it)->ID() == it->first) { + m_ai_clients.erase((*player_it)->PlayerName()); (*player_it)->SendMessage(EndGameMessage((*player_it)->ID(), Message::YOU_ARE_DEFEATED)); - else - (*player_it)->SendMessage(PlayerEliminatedMessage((*player_it)->ID(), Empires().Lookup(it->second)->Name())); + } else { + (*player_it)->SendMessage(PlayerEliminatedMessage((*player_it)->ID(), it->second, Empires().Lookup(it->second)->Name())); + } } } Modified: trunk/FreeOrion/server/ServerApp.h =================================================================== --- trunk/FreeOrion/server/ServerApp.h 2008-02-09 03:40:31 UTC (rev 2312) +++ trunk/FreeOrion/server/ServerApp.h 2008-02-09 20:17:54 UTC (rev 2313) @@ -130,7 +130,8 @@ int m_current_turn; ///< current turn number - std::vector<Process> m_ai_clients; ///< AI client child processes + std::map<std::string, Process> + m_ai_clients; ///< AI client child processes std::set<int> m_ai_IDs; ///< player IDs of AI clients bool m_single_player_game; ///< true when the game being played is single-player Modified: trunk/FreeOrion/universe/Universe.cpp =================================================================== --- trunk/FreeOrion/universe/Universe.cpp 2008-02-09 03:40:31 UTC (rev 2312) +++ trunk/FreeOrion/universe/Universe.cpp 2008-02-09 20:17:54 UTC (rev 2313) @@ -549,9 +549,9 @@ // determine meter max discrepancies for (EffectAccountingMap::iterator obj_it = m_effect_accounting_map.begin(); obj_it != m_effect_accounting_map.end(); ++obj_it) { UniverseObject* obj = Object(obj_it->first); // object that has some meters - std::map<MeterType, std::vector<EffectAccountingInfo> > meters_map = obj_it->second; + std::map<MeterType, std::vector<EffectAccountingInfo> >& meters_map = obj_it->second; - // ever meter has a value at the start of the turn, and a value after updating with known effects + // every meter has a value at the start of the turn, and a value after updating with known effects for (std::map<MeterType, std::vector<EffectAccountingInfo> >::iterator meter_type_it = meters_map.begin(); meter_type_it != meters_map.end(); ++meter_type_it) { MeterType type = meter_type_it->first; Meter* meter = obj->GetMeter(type); @@ -973,6 +973,21 @@ m_marked_destroyed.insert(id); } +void Universe::HandleEmpireElimination(int empire_id) +{ + for (EffectAccountingMap::iterator obj_it = m_effect_accounting_map.begin(); obj_it != m_effect_accounting_map.end(); ++obj_it) { + // ever meter has a value at the start of the turn, and a value after updating with known effects + for (std::map<MeterType, std::vector<EffectAccountingInfo> >::iterator meter_type_it = obj_it->second.begin(); meter_type_it != obj_it->second.end(); ++meter_type_it) { + for (std::size_t i = 0; i < meter_type_it->second.size(); ) { + if (meter_type_it->second[i].caused_by_empire_id == empire_id) + meter_type_it->second.erase(meter_type_it->second.begin() + i); + else + ++i; + } + } + } +} + bool Universe::ConnectedWithin(int system1, int system2, int maxLaneJumps, std::vector<std::set<int> >& laneSetArray) { // list of indices of systems that are accessible from previously visited systems. // when a new system is found to be accessible, it is added to the back of the @@ -1178,6 +1193,7 @@ } } } + ////////////////////////////////////////// // Server-Only General Functions // ////////////////////////////////////////// Modified: trunk/FreeOrion/universe/Universe.h =================================================================== --- trunk/FreeOrion/universe/Universe.h 2008-02-09 03:40:31 UTC (rev 2312) +++ trunk/FreeOrion/universe/Universe.h 2008-02-09 20:17:54 UTC (rev 2313) @@ -249,6 +249,9 @@ /** marks an object for destruction by the Destroy effect. */ void EffectDestroy(int id); + /** cleans up internal storage of now-invalidated empire ID */ + void HandleEmpireElimination(int empire_id); + /** sets whether to inhibit UniverseObjectSignals. Inhibits if \a inhibit is true, and (re)enables UniverseObjectSignals if \a inhibit is false. */ static void InhibitUniverseObjectSignals(bool inhibit = true); //@} |