1 #include "Message.h"
2 
3 #include "../combat/CombatLogManager.h"
4 #include "../Empire/EmpireManager.h"
5 #include "../Empire/Supply.h"
6 #include "../Empire/Diplomacy.h"
7 #include "../util/Logger.h"
8 #include "../util/ModeratorAction.h"
9 #include "../util/SaveGamePreviewUtils.h"
10 #include "../universe/Species.h"
11 #include "../universe/Universe.h"
12 #include "../util/OptionsDB.h"
13 #include "../util/OrderSet.h"
14 #include "../util/Serialize.h"
15 #include "../util/ScopedTimer.h"
16 #include "../util/i18n.h"
17 #include "../util/Version.h"
18 #include <boost/algorithm/string/erase.hpp>
19 #include <boost/algorithm/string/predicate.hpp>
20 #include <boost/serialization/deque.hpp>
21 #include <boost/serialization/list.hpp>
22 #include <boost/serialization/map.hpp>
23 #include <boost/serialization/set.hpp>
24 #include <boost/serialization/vector.hpp>
25 #include <boost/serialization/weak_ptr.hpp>
26 #include <boost/date_time/posix_time/time_serialize.hpp>
27 #include <boost/uuid/uuid_serialize.hpp>
28 #include <boost/uuid/uuid_io.hpp>
29 
30 #include <zlib.h>
31 
32 #include <iostream>
33 #include <stdexcept>
34 #include <sstream>
35 #include <map>
36 
37 
38 namespace {
39     const std::string DUMMY_EMPTY_MESSAGE = "Lathanda";
40 }
41 
42 ////////////////////////////////////////////////
43 // Free Functions
44 ////////////////////////////////////////////////
operator <<(std::ostream & os,const Message & msg)45 std::ostream& operator<<(std::ostream& os, const Message& msg) {
46     os << "Message: "
47        << msg.Type();
48 
49     os << " \"" << msg.Text() << "\"\n";
50 
51     return os;
52 }
53 
54 
55 ////////////////////////////////////////////////
56 // Message
57 ////////////////////////////////////////////////
Message()58 Message::Message() :
59     m_type(UNDEFINED),
60     m_message_size(0),
61     m_message_text()
62 {}
63 
Message(MessageType type,const std::string & text)64 Message::Message(MessageType type,
65                  const std::string& text) :
66     m_type(type),
67     m_message_size(text.size()),
68     m_message_text(new char[text.size()])
69 { std::copy(text.begin(), text.end(), m_message_text.get()); }
70 
Type() const71 Message::MessageType Message::Type() const
72 { return m_type; }
73 
Size() const74 std::size_t Message::Size() const
75 { return m_message_size; }
76 
Data() const77 const char* Message::Data() const
78 { return m_message_text.get(); }
79 
Text() const80 std::string Message::Text() const
81 { return std::string(m_message_text.get(), m_message_size); }
82 
Resize(std::size_t size)83 void Message::Resize(std::size_t size) {
84     m_message_size = size;
85     m_message_text.reset(new char[m_message_size]);
86 }
87 
Data()88 char* Message::Data()
89 { return m_message_text.get(); }
90 
Swap(Message & rhs)91 void Message::Swap(Message& rhs) {
92     std::swap(m_type, rhs.m_type);
93     std::swap(m_message_size, rhs.m_message_size);
94     std::swap(m_message_text, rhs.m_message_text);
95 }
96 
operator ==(const Message & lhs,const Message & rhs)97 bool operator==(const Message& lhs, const Message& rhs) {
98     return
99         lhs.Type() == rhs.Type() &&
100         lhs.Text() == rhs.Text();
101 }
102 
operator !=(const Message & lhs,const Message & rhs)103 bool operator!=(const Message& lhs, const Message& rhs)
104 { return !(lhs == rhs); }
105 
swap(Message & lhs,Message & rhs)106 void swap(Message& lhs, Message& rhs)
107 { lhs.Swap(rhs); }
108 
BufferToHeader(const Message::HeaderBuffer & buffer,Message & message)109 void BufferToHeader(const Message::HeaderBuffer& buffer, Message& message) {
110     message.m_type = static_cast<Message::MessageType>(buffer[Message::Parts::TYPE]);
111     message.m_message_size = buffer[Message::Parts::SIZE];
112 }
113 
HeaderToBuffer(const Message & message,Message::HeaderBuffer & buffer)114 void HeaderToBuffer(const Message& message, Message::HeaderBuffer& buffer) {
115     buffer[Message::Parts::TYPE] = message.Type();
116     buffer[Message::Parts::SIZE] = message.Size();
117 }
118 
119 ////////////////////////////////////////////////
120 // Message named ctors
121 ////////////////////////////////////////////////
ErrorMessage(const std::string & problem,bool fatal,int player_id)122 Message ErrorMessage(const std::string& problem, bool fatal/* = true*/,
123                      int player_id/* = Networking::INVALID_PLAYER_ID*/) {
124     std::ostringstream os;
125     {
126         freeorion_xml_oarchive oa(os);
127         oa << BOOST_SERIALIZATION_NVP(problem)
128            << BOOST_SERIALIZATION_NVP(fatal)
129            << BOOST_SERIALIZATION_NVP(player_id);
130     }
131     return Message(Message::ERROR_MSG, os.str());
132 }
133 
HostSPGameMessage(const SinglePlayerSetupData & setup_data)134 Message HostSPGameMessage(const SinglePlayerSetupData& setup_data) {
135     std::ostringstream os;
136     {
137         std::string client_version_string = FreeOrionVersionString();
138         freeorion_xml_oarchive oa(os);
139         oa << BOOST_SERIALIZATION_NVP(setup_data)
140            << BOOST_SERIALIZATION_NVP(client_version_string);
141     }
142     return Message(Message::HOST_SP_GAME, os.str());
143 }
144 
HostMPGameMessage(const std::string & host_player_name)145 Message HostMPGameMessage(const std::string& host_player_name)
146 {
147     std::ostringstream os;
148     {
149         std::string client_version_string = FreeOrionVersionString();
150         freeorion_xml_oarchive oa(os);
151         oa << BOOST_SERIALIZATION_NVP(host_player_name)
152            << BOOST_SERIALIZATION_NVP(client_version_string);
153     }
154     return Message(Message::HOST_MP_GAME, os.str());
155 }
156 
JoinGameMessage(const std::string & player_name,Networking::ClientType client_type,boost::uuids::uuid cookie)157 Message JoinGameMessage(const std::string& player_name,
158                         Networking::ClientType client_type,
159                         boost::uuids::uuid cookie) {
160     std::ostringstream os;
161     {
162         freeorion_xml_oarchive oa(os);
163         std::string client_version_string = FreeOrionVersionString();
164         oa << BOOST_SERIALIZATION_NVP(player_name)
165            << BOOST_SERIALIZATION_NVP(client_type)
166            << BOOST_SERIALIZATION_NVP(client_version_string)
167            << BOOST_SERIALIZATION_NVP(cookie);
168     }
169     return Message(Message::JOIN_GAME, os.str());
170 }
171 
HostIDMessage(int host_player_id)172 Message HostIDMessage(int host_player_id) {
173     return Message(Message::HOST_ID,
174                    std::to_string(host_player_id));
175 }
176 
GameStartMessage(bool single_player_game,int empire_id,int current_turn,const EmpireManager & empires,const Universe & universe,const SpeciesManager & species,CombatLogManager & combat_logs,const SupplyManager & supply,const std::map<int,PlayerInfo> & players,GalaxySetupData galaxy_setup_data,bool use_binary_serialization)177 Message GameStartMessage(bool single_player_game, int empire_id,
178                          int current_turn, const EmpireManager& empires,
179                          const Universe& universe, const SpeciesManager& species,
180                          CombatLogManager& combat_logs, const SupplyManager& supply,
181                          const std::map<int, PlayerInfo>& players,
182                          GalaxySetupData galaxy_setup_data,
183                          bool use_binary_serialization)
184 {
185     std::ostringstream os;
186     {
187         if (use_binary_serialization) {
188             freeorion_bin_oarchive oa(os);
189             oa << BOOST_SERIALIZATION_NVP(single_player_game)
190                << BOOST_SERIALIZATION_NVP(empire_id)
191                << BOOST_SERIALIZATION_NVP(current_turn);
192             GetUniverse().EncodingEmpire() = empire_id;
193             oa << BOOST_SERIALIZATION_NVP(empires)
194                << BOOST_SERIALIZATION_NVP(species);
195             combat_logs.SerializeIncompleteLogs(oa, 1);
196             oa << BOOST_SERIALIZATION_NVP(supply);
197             Serialize(oa, universe);
198             bool loaded_game_data = false;
199             oa << BOOST_SERIALIZATION_NVP(players)
200                << BOOST_SERIALIZATION_NVP(loaded_game_data);
201             galaxy_setup_data.m_encoding_empire = empire_id;
202             oa << BOOST_SERIALIZATION_NVP(galaxy_setup_data);
203         } else {
204             freeorion_xml_oarchive oa(os);
205             oa << BOOST_SERIALIZATION_NVP(single_player_game)
206                << BOOST_SERIALIZATION_NVP(empire_id)
207                << BOOST_SERIALIZATION_NVP(current_turn);
208             GetUniverse().EncodingEmpire() = empire_id;
209             oa << BOOST_SERIALIZATION_NVP(empires)
210                << BOOST_SERIALIZATION_NVP(species);
211             combat_logs.SerializeIncompleteLogs(oa, 1);
212             oa << BOOST_SERIALIZATION_NVP(supply);
213             Serialize(oa, universe);
214             bool loaded_game_data = false;
215             oa << BOOST_SERIALIZATION_NVP(players)
216                << BOOST_SERIALIZATION_NVP(loaded_game_data);
217             galaxy_setup_data.m_encoding_empire = empire_id;
218             oa << BOOST_SERIALIZATION_NVP(galaxy_setup_data);
219         }
220     }
221     return Message(Message::GAME_START, os.str());
222 }
223 
GameStartMessage(bool single_player_game,int empire_id,int current_turn,const EmpireManager & empires,const Universe & universe,const SpeciesManager & species,CombatLogManager & combat_logs,const SupplyManager & supply,const std::map<int,PlayerInfo> & players,const OrderSet & orders,const SaveGameUIData * ui_data,GalaxySetupData galaxy_setup_data,bool use_binary_serialization)224 Message GameStartMessage(bool single_player_game, int empire_id,
225                          int current_turn, const EmpireManager& empires,
226                          const Universe& universe, const SpeciesManager& species,
227                          CombatLogManager& combat_logs, const SupplyManager& supply,
228                          const std::map<int, PlayerInfo>& players,
229                          const OrderSet& orders, const SaveGameUIData* ui_data,
230                          GalaxySetupData galaxy_setup_data,
231                          bool use_binary_serialization)
232 {
233     std::ostringstream os;
234     {
235         if (use_binary_serialization) {
236             freeorion_bin_oarchive oa(os);
237             oa << BOOST_SERIALIZATION_NVP(single_player_game)
238                << BOOST_SERIALIZATION_NVP(empire_id)
239                << BOOST_SERIALIZATION_NVP(current_turn);
240             GetUniverse().EncodingEmpire() = empire_id;
241             oa << BOOST_SERIALIZATION_NVP(empires)
242                << BOOST_SERIALIZATION_NVP(species);
243             combat_logs.SerializeIncompleteLogs(oa, 1);
244             oa << BOOST_SERIALIZATION_NVP(supply);
245             Serialize(oa, universe);
246             bool loaded_game_data = true;
247             oa << BOOST_SERIALIZATION_NVP(players)
248                << BOOST_SERIALIZATION_NVP(loaded_game_data);
249             Serialize(oa, orders);
250             bool ui_data_available = (ui_data != nullptr);
251             oa << BOOST_SERIALIZATION_NVP(ui_data_available);
252             if (ui_data_available)
253                 oa << boost::serialization::make_nvp("ui_data", *ui_data);
254             bool save_state_string_available = false;
255             oa << BOOST_SERIALIZATION_NVP(save_state_string_available);
256             galaxy_setup_data.m_encoding_empire = empire_id;
257             oa << BOOST_SERIALIZATION_NVP(galaxy_setup_data);
258         } else {
259             freeorion_xml_oarchive oa(os);
260             oa << BOOST_SERIALIZATION_NVP(single_player_game)
261                << BOOST_SERIALIZATION_NVP(empire_id)
262                << BOOST_SERIALIZATION_NVP(current_turn);
263             GetUniverse().EncodingEmpire() = empire_id;
264             oa << BOOST_SERIALIZATION_NVP(empires)
265                << BOOST_SERIALIZATION_NVP(species);
266             combat_logs.SerializeIncompleteLogs(oa, 1);
267             oa << BOOST_SERIALIZATION_NVP(supply);
268             Serialize(oa, universe);
269             bool loaded_game_data = true;
270             oa << BOOST_SERIALIZATION_NVP(players)
271                << BOOST_SERIALIZATION_NVP(loaded_game_data);
272             Serialize(oa, orders);
273             bool ui_data_available = (ui_data != nullptr);
274             oa << BOOST_SERIALIZATION_NVP(ui_data_available);
275             if (ui_data_available) {
276                 if (ui_data) {
277                     oa << boost::serialization::make_nvp("ui_data", *ui_data);
278                 } else {
279                     ErrorLogger() << "GameStartMessage expected UI data but it was nullptr";
280                     SaveGameUIData temp_UI_data;
281                     oa << boost::serialization::make_nvp("ui_data", temp_UI_data);
282                 }
283             }
284             bool save_state_string_available = false;
285             oa << BOOST_SERIALIZATION_NVP(save_state_string_available);
286             galaxy_setup_data.m_encoding_empire = empire_id;
287             oa << BOOST_SERIALIZATION_NVP(galaxy_setup_data);
288         }
289     }
290     return Message(Message::GAME_START, os.str());
291 }
292 
GameStartMessage(bool single_player_game,int empire_id,int current_turn,const EmpireManager & empires,const Universe & universe,const SpeciesManager & species,CombatLogManager & combat_logs,const SupplyManager & supply,const std::map<int,PlayerInfo> & players,const OrderSet & orders,const std::string * save_state_string,GalaxySetupData galaxy_setup_data,bool use_binary_serialization)293 Message GameStartMessage(bool single_player_game, int empire_id,
294                          int current_turn, const EmpireManager& empires,
295                          const Universe& universe, const SpeciesManager& species,
296                          CombatLogManager& combat_logs, const SupplyManager& supply,
297                          const std::map<int, PlayerInfo>& players,
298                          const OrderSet& orders, const std::string* save_state_string,
299                          GalaxySetupData galaxy_setup_data,
300                          bool use_binary_serialization)
301 {
302     std::ostringstream os;
303     {
304         if (use_binary_serialization) {
305             freeorion_bin_oarchive oa(os);
306             oa << BOOST_SERIALIZATION_NVP(single_player_game)
307                << BOOST_SERIALIZATION_NVP(empire_id)
308                << BOOST_SERIALIZATION_NVP(current_turn);
309             GetUniverse().EncodingEmpire() = empire_id;
310             oa << BOOST_SERIALIZATION_NVP(empires)
311                << BOOST_SERIALIZATION_NVP(species);
312             combat_logs.SerializeIncompleteLogs(oa, 1);
313             oa << BOOST_SERIALIZATION_NVP(supply);
314             Serialize(oa, universe);
315             bool loaded_game_data = true;
316             oa << BOOST_SERIALIZATION_NVP(players)
317                << BOOST_SERIALIZATION_NVP(loaded_game_data);
318             Serialize(oa, orders);
319             bool ui_data_available = false;
320             oa << BOOST_SERIALIZATION_NVP(ui_data_available);
321             bool save_state_string_available = (save_state_string != nullptr);
322             oa << BOOST_SERIALIZATION_NVP(save_state_string_available);
323             if (save_state_string_available)
324                 oa << boost::serialization::make_nvp("save_state_string", *save_state_string);
325             galaxy_setup_data.m_encoding_empire = empire_id;
326             oa << BOOST_SERIALIZATION_NVP(galaxy_setup_data);
327         } else {
328             freeorion_xml_oarchive oa(os);
329             oa << BOOST_SERIALIZATION_NVP(single_player_game)
330                << BOOST_SERIALIZATION_NVP(empire_id)
331                << BOOST_SERIALIZATION_NVP(current_turn);
332             GetUniverse().EncodingEmpire() = empire_id;
333             oa << BOOST_SERIALIZATION_NVP(empires)
334                << BOOST_SERIALIZATION_NVP(species);
335             combat_logs.SerializeIncompleteLogs(oa, 1);
336             oa << BOOST_SERIALIZATION_NVP(supply);
337             Serialize(oa, universe);
338             bool loaded_game_data = true;
339             oa << BOOST_SERIALIZATION_NVP(players)
340                << BOOST_SERIALIZATION_NVP(loaded_game_data);
341             Serialize(oa, orders);
342             bool ui_data_available = false;
343             oa << BOOST_SERIALIZATION_NVP(ui_data_available);
344             bool save_state_string_available = (save_state_string != nullptr);
345             oa << BOOST_SERIALIZATION_NVP(save_state_string_available);
346             if (save_state_string_available) {
347                 if (save_state_string) {
348                     oa << boost::serialization::make_nvp("save_state_string", *save_state_string);
349                 } else {
350                     ErrorLogger() << "GameStartMessage expectes save_state_string but it was nullptr";
351                     std::string temp_sss;
352                     oa << boost::serialization::make_nvp("save_state_string", temp_sss);
353                 }
354             }
355             galaxy_setup_data.m_encoding_empire = empire_id;
356             oa << BOOST_SERIALIZATION_NVP(galaxy_setup_data);
357         }
358     }
359     return Message(Message::GAME_START, os.str());
360 }
361 
HostSPAckMessage(int player_id)362 Message HostSPAckMessage(int player_id)
363 { return Message(Message::HOST_SP_GAME, std::to_string(player_id)); }
364 
HostMPAckMessage(int player_id)365 Message HostMPAckMessage(int player_id)
366 { return Message(Message::HOST_MP_GAME, std::to_string(player_id)); }
367 
JoinAckMessage(int player_id,boost::uuids::uuid cookie)368 Message JoinAckMessage(int player_id, boost::uuids::uuid cookie)
369 {
370     std::ostringstream os;
371     {
372         freeorion_xml_oarchive oa(os);
373         oa << BOOST_SERIALIZATION_NVP(player_id)
374            << BOOST_SERIALIZATION_NVP(cookie);
375     }
376     return Message(Message::JOIN_GAME, os.str());
377 }
378 
TurnOrdersMessage(const OrderSet & orders,const SaveGameUIData & ui_data)379 Message TurnOrdersMessage(const OrderSet& orders, const SaveGameUIData& ui_data) {
380     std::ostringstream os;
381     {
382         freeorion_xml_oarchive oa(os);
383         Serialize(oa, orders);
384         bool ui_data_available = true;
385         bool save_state_string_available = false;
386         oa << BOOST_SERIALIZATION_NVP(ui_data_available)
387            << BOOST_SERIALIZATION_NVP(ui_data)
388            << BOOST_SERIALIZATION_NVP(save_state_string_available);
389     }
390     return Message(Message::TURN_ORDERS, os.str());
391 }
392 
TurnOrdersMessage(const OrderSet & orders,const std::string & save_state_string)393 Message TurnOrdersMessage(const OrderSet& orders, const std::string& save_state_string) {
394     std::ostringstream os;
395     {
396         freeorion_xml_oarchive oa(os);
397         Serialize(oa, orders);
398         bool ui_data_available = false;
399         bool save_state_string_available = true;
400         oa << BOOST_SERIALIZATION_NVP(ui_data_available)
401            << BOOST_SERIALIZATION_NVP(save_state_string_available)
402            << BOOST_SERIALIZATION_NVP(save_state_string);
403     }
404     return Message(Message::TURN_ORDERS, os.str());
405 }
406 
TurnPartialOrdersMessage(const std::pair<OrderSet,std::set<int>> & orders_updates)407 Message TurnPartialOrdersMessage(const std::pair<OrderSet, std::set<int>>& orders_updates) {
408     std::ostringstream os;
409     {
410         freeorion_xml_oarchive oa(os);
411         Serialize(oa, orders_updates.first);
412         oa << boost::serialization::make_nvp("deleted", orders_updates.second);
413     }
414     return Message(Message::TURN_PARTIAL_ORDERS, os.str());
415 }
416 
TurnTimeoutMessage(int timeout_remaining)417 Message TurnTimeoutMessage(int timeout_remaining)
418 { return Message(Message::TURN_TIMEOUT, std::to_string(timeout_remaining)); }
419 
TurnProgressMessage(Message::TurnProgressPhase phase_id)420 Message TurnProgressMessage(Message::TurnProgressPhase phase_id) {
421     std::ostringstream os;
422     {
423         freeorion_xml_oarchive oa(os);
424         oa << BOOST_SERIALIZATION_NVP(phase_id);
425     }
426     return Message(Message::TURN_PROGRESS, os.str());
427 }
428 
PlayerStatusMessage(Message::PlayerStatus player_status,int about_empire_id)429 Message PlayerStatusMessage(Message::PlayerStatus player_status,
430                             int about_empire_id)
431 {
432     std::ostringstream os;
433     {
434         freeorion_xml_oarchive oa(os);
435         oa << BOOST_SERIALIZATION_NVP(player_status)
436            << BOOST_SERIALIZATION_NVP(about_empire_id);
437     }
438     return Message(Message::PLAYER_STATUS, os.str());
439 }
440 
TurnUpdateMessage(int empire_id,int current_turn,const EmpireManager & empires,const Universe & universe,const SpeciesManager & species,CombatLogManager & combat_logs,const SupplyManager & supply,const std::map<int,PlayerInfo> & players,bool use_binary_serialization)441 Message TurnUpdateMessage(int empire_id, int current_turn,
442                           const EmpireManager& empires, const Universe& universe,
443                           const SpeciesManager& species, CombatLogManager& combat_logs,
444                           const SupplyManager& supply,
445                           const std::map<int, PlayerInfo>& players,
446                           bool use_binary_serialization)
447 {
448     std::ostringstream os;
449     {
450         if (use_binary_serialization) {
451             freeorion_bin_oarchive oa(os);
452             GetUniverse().EncodingEmpire() = empire_id;
453             oa << BOOST_SERIALIZATION_NVP(current_turn);
454             oa << BOOST_SERIALIZATION_NVP(empires);
455             oa << BOOST_SERIALIZATION_NVP(species);
456             combat_logs.SerializeIncompleteLogs(oa, 1);
457             oa << BOOST_SERIALIZATION_NVP(supply);
458             Serialize(oa, universe);
459             oa << BOOST_SERIALIZATION_NVP(players);
460         } else {
461             freeorion_xml_oarchive oa(os);
462             GetUniverse().EncodingEmpire() = empire_id;
463             oa << BOOST_SERIALIZATION_NVP(current_turn)
464                << BOOST_SERIALIZATION_NVP(empires)
465                << BOOST_SERIALIZATION_NVP(species);
466             combat_logs.SerializeIncompleteLogs(oa, 1);
467             oa << BOOST_SERIALIZATION_NVP(supply);
468             Serialize(oa, universe);
469             oa << BOOST_SERIALIZATION_NVP(players);
470         }
471     }
472     return Message(Message::TURN_UPDATE, os.str());
473 }
474 
TurnPartialUpdateMessage(int empire_id,const Universe & universe,bool use_binary_serialization)475 Message TurnPartialUpdateMessage(int empire_id, const Universe& universe,
476                                  bool use_binary_serialization) {
477     std::ostringstream os;
478     {
479         if (use_binary_serialization) {
480             freeorion_bin_oarchive oa(os);
481             GetUniverse().EncodingEmpire() = empire_id;
482             Serialize(oa, universe);
483         } else {
484             freeorion_xml_oarchive oa(os);
485             GetUniverse().EncodingEmpire() = empire_id;
486             Serialize(oa, universe);
487         }
488     }
489     return Message(Message::TURN_PARTIAL_UPDATE, os.str());
490 }
491 
HostSaveGameInitiateMessage(const std::string & filename)492 Message HostSaveGameInitiateMessage(const std::string& filename)
493 { return Message(Message::SAVE_GAME_INITIATE, filename); }
494 
ServerSaveGameCompleteMessage(const std::string & save_filename,int bytes_written)495 Message ServerSaveGameCompleteMessage(const std::string& save_filename, int bytes_written) {
496     std::ostringstream os;
497     {
498         freeorion_xml_oarchive oa(os);
499         oa << BOOST_SERIALIZATION_NVP(save_filename)
500            << BOOST_SERIALIZATION_NVP(bytes_written);
501     }
502     return Message(Message::SAVE_GAME_COMPLETE, os.str());
503 }
504 
DiplomacyMessage(const DiplomaticMessage & diplo_message)505 Message DiplomacyMessage(const DiplomaticMessage& diplo_message) {
506     std::ostringstream os;
507     {
508         freeorion_xml_oarchive oa(os);
509         oa << BOOST_SERIALIZATION_NVP(diplo_message);
510     }
511     return Message(Message::DIPLOMACY, os.str());
512 }
513 
DiplomaticStatusMessage(const DiplomaticStatusUpdateInfo & diplo_update)514 Message DiplomaticStatusMessage(const DiplomaticStatusUpdateInfo& diplo_update) {
515     std::ostringstream os;
516     {
517         freeorion_xml_oarchive oa(os);
518         oa << BOOST_SERIALIZATION_NVP(diplo_update.empire1_id)
519            << BOOST_SERIALIZATION_NVP(diplo_update.empire2_id)
520            << BOOST_SERIALIZATION_NVP(diplo_update.diplo_status);
521     }
522     return Message(Message::DIPLOMATIC_STATUS, os.str());
523 }
524 
EndGameMessage(Message::EndGameReason reason,const std::string & reason_player_name)525 Message EndGameMessage(Message::EndGameReason reason,
526                        const std::string& reason_player_name/* = ""*/)
527 {
528     std::ostringstream os;
529     {
530         freeorion_xml_oarchive oa(os);
531         oa << BOOST_SERIALIZATION_NVP(reason)
532            << BOOST_SERIALIZATION_NVP(reason_player_name);
533     }
534     return Message(Message::END_GAME, os.str());
535 }
536 
AIEndGameAcknowledgeMessage()537 Message AIEndGameAcknowledgeMessage()
538 { return Message(Message::AI_END_GAME_ACK, DUMMY_EMPTY_MESSAGE); }
539 
ModeratorActionMessage(const Moderator::ModeratorAction & action)540 Message ModeratorActionMessage(const Moderator::ModeratorAction& action) {
541     std::ostringstream os;
542     {
543         const Moderator::ModeratorAction* mod_action = &action;
544         freeorion_xml_oarchive oa(os);
545         oa << BOOST_SERIALIZATION_NVP(mod_action);
546     }
547     return Message(Message::MODERATOR_ACTION, os.str());
548 }
549 
ShutdownServerMessage()550 Message ShutdownServerMessage()
551 { return Message(Message::SHUT_DOWN_SERVER, DUMMY_EMPTY_MESSAGE); }
552 
553 /** requests previews of savefiles from server synchronously */
RequestSavePreviewsMessage(std::string relative_directory)554 Message RequestSavePreviewsMessage(std::string relative_directory)
555 { return Message(Message::REQUEST_SAVE_PREVIEWS, relative_directory); }
556 
557 /** returns the savegame previews to the client */
DispatchSavePreviewsMessage(const PreviewInformation & previews)558 Message DispatchSavePreviewsMessage(const PreviewInformation& previews) {
559     std::ostringstream os;
560     {
561         freeorion_xml_oarchive oa(os);
562         oa << BOOST_SERIALIZATION_NVP(previews);
563     }
564     return Message(Message::DISPATCH_SAVE_PREVIEWS, os.str());
565 }
566 
RequestCombatLogsMessage(const std::vector<int> & ids)567 Message RequestCombatLogsMessage(const std::vector<int>& ids) {
568     std::ostringstream os;
569     {
570         freeorion_xml_oarchive oa(os);
571         oa << BOOST_SERIALIZATION_NVP(ids);
572     }
573     return Message(Message::REQUEST_COMBAT_LOGS, os.str());
574 }
575 
DispatchCombatLogsMessage(const std::vector<std::pair<int,const CombatLog>> & logs,bool use_binary_serialization)576 Message DispatchCombatLogsMessage(const std::vector<std::pair<int, const CombatLog>>& logs,
577                                   bool use_binary_serialization)
578 {
579     std::ostringstream os;
580     {
581         try {
582             if (use_binary_serialization) {
583                 freeorion_bin_oarchive oa(os);
584                 oa << BOOST_SERIALIZATION_NVP(logs);
585             } else {
586                 freeorion_xml_oarchive oa(os);
587                 oa << BOOST_SERIALIZATION_NVP(logs);
588             }
589         } catch (const std::exception& e) {
590             ErrorLogger() << "Caught exception serializing combat logs: " << e.what();
591         }
592     }
593 
594     return Message(Message::DISPATCH_COMBAT_LOGS, os.str());
595 }
596 
LoggerConfigMessage(int sender,const std::set<std::tuple<std::string,std::string,LogLevel>> & options)597 Message LoggerConfigMessage(int sender, const std::set<std::tuple<std::string, std::string, LogLevel>>& options) {
598     std::ostringstream os;
599     {
600         freeorion_xml_oarchive oa(os);
601         std::size_t size = options.size();
602         oa << BOOST_SERIALIZATION_NVP(size);
603         for (const auto& option_tuple : options) {
604             auto option = std::get<0>(option_tuple);
605             auto name = std::get<1>(option_tuple);
606             auto value = std::get<2>(option_tuple);
607             oa << BOOST_SERIALIZATION_NVP(option);
608             oa << BOOST_SERIALIZATION_NVP(name);
609             oa << BOOST_SERIALIZATION_NVP(value);
610         }
611     }
612     return Message(Message::LOGGER_CONFIG, os.str());
613 }
614 
615 ////////////////////////////////////////////////
616 // Multiplayer Lobby Message named ctors
617 ////////////////////////////////////////////////
LobbyUpdateMessage(const MultiplayerLobbyData & lobby_data)618 Message LobbyUpdateMessage(const MultiplayerLobbyData& lobby_data) {
619     std::ostringstream os;
620     {
621         freeorion_xml_oarchive oa(os);
622         oa << BOOST_SERIALIZATION_NVP(lobby_data);
623     }
624     return Message(Message::LOBBY_UPDATE, os.str());
625 }
626 
ServerLobbyUpdateMessage(const MultiplayerLobbyData & lobby_data)627 Message ServerLobbyUpdateMessage(const MultiplayerLobbyData& lobby_data) {
628     std::ostringstream os;
629     {
630         freeorion_xml_oarchive oa(os);
631         oa << BOOST_SERIALIZATION_NVP(lobby_data);
632     }
633     return Message(Message::LOBBY_UPDATE, os.str());
634 }
635 
ChatHistoryMessage(const std::vector<std::reference_wrapper<const ChatHistoryEntity>> & chat_history)636 Message ChatHistoryMessage(const std::vector<std::reference_wrapper<const ChatHistoryEntity>>& chat_history) {
637     std::ostringstream os;
638     {
639         freeorion_xml_oarchive oa(os);
640         std::size_t size = chat_history.size();
641         oa << BOOST_SERIALIZATION_NVP(size);
642         for (const auto& elem : chat_history) {
643             oa << boost::serialization::make_nvp(BOOST_PP_STRINGIZE(elem), elem.get());
644         }
645     }
646     return Message(Message::CHAT_HISTORY, os.str());
647 }
648 
PlayerChatMessage(const std::string & data,std::set<int> recipients,bool pm)649 Message PlayerChatMessage(const std::string& data, std::set<int> recipients, bool pm) {
650     std::ostringstream os;
651     {
652         freeorion_xml_oarchive oa(os);
653         oa << BOOST_SERIALIZATION_NVP(recipients)
654            << BOOST_SERIALIZATION_NVP(data)
655            << BOOST_SERIALIZATION_NVP(pm);
656     }
657     return Message(Message::PLAYER_CHAT, os.str());
658 }
659 
ServerPlayerChatMessage(int sender,const boost::posix_time::ptime & timestamp,const std::string & data,bool pm)660 Message ServerPlayerChatMessage(int sender, const boost::posix_time::ptime& timestamp,
661                                 const std::string& data, bool pm)
662 {
663     std::ostringstream os;
664     {
665         freeorion_xml_oarchive oa(os);
666         oa << BOOST_SERIALIZATION_NVP(sender)
667            << BOOST_SERIALIZATION_NVP(timestamp)
668            << BOOST_SERIALIZATION_NVP(data)
669            << BOOST_SERIALIZATION_NVP(pm);
670     }
671     return Message(Message::PLAYER_CHAT, os.str());
672 }
673 
StartMPGameMessage()674 Message StartMPGameMessage()
675 { return Message(Message::START_MP_GAME, DUMMY_EMPTY_MESSAGE); }
676 
ContentCheckSumMessage()677 Message ContentCheckSumMessage() {
678     auto checksums = CheckSumContent();
679 
680     std::ostringstream os;
681     {
682         freeorion_xml_oarchive oa(os);
683         oa << BOOST_SERIALIZATION_NVP(checksums);
684     }
685     return Message(Message::CHECKSUM, os.str());
686 }
687 
AuthRequestMessage(const std::string & player_name,const std::string & auth)688 Message AuthRequestMessage(const std::string& player_name, const std::string& auth) {
689     std::ostringstream os;
690     {
691         freeorion_xml_oarchive oa(os);
692         oa << BOOST_SERIALIZATION_NVP(player_name)
693            << BOOST_SERIALIZATION_NVP(auth);
694     }
695     return Message(Message::AUTH_REQUEST, os.str());
696 }
697 
AuthResponseMessage(const std::string & player_name,const std::string & auth)698 Message AuthResponseMessage(const std::string& player_name, const std::string& auth) {
699     std::ostringstream os;
700     {
701         freeorion_xml_oarchive oa(os);
702         oa << BOOST_SERIALIZATION_NVP(player_name)
703            << BOOST_SERIALIZATION_NVP(auth);
704     }
705     return Message(Message::AUTH_RESPONSE, os.str());
706 }
707 
SetAuthorizationRolesMessage(const Networking::AuthRoles & roles)708 Message SetAuthorizationRolesMessage(const Networking::AuthRoles& roles)
709 { return Message(Message::SET_AUTH_ROLES, roles.Text()); }
710 
EliminateSelfMessage()711 Message EliminateSelfMessage()
712 { return Message(Message::ELIMINATE_SELF, DUMMY_EMPTY_MESSAGE); }
713 
UnreadyMessage()714 Message UnreadyMessage()
715 { return Message(Message::UNREADY, DUMMY_EMPTY_MESSAGE); }
716 
PlayerInfoMessage(const std::map<int,PlayerInfo> & players)717 Message PlayerInfoMessage(const std::map<int, PlayerInfo>& players) {
718     std::ostringstream os;
719     {
720         freeorion_xml_oarchive oa(os);
721         oa << BOOST_SERIALIZATION_NVP(players);
722     }
723     return Message(Message::PLAYER_INFO, os.str());
724 }
725 
726 ////////////////////////////////////////////////
727 // Message data extractors
728 ////////////////////////////////////////////////
ExtractErrorMessageData(const Message & msg,int & player_id,std::string & problem,bool & fatal)729 void ExtractErrorMessageData(const Message& msg, int& player_id, std::string& problem, bool& fatal) {
730     try {
731         std::istringstream is(msg.Text());
732         freeorion_xml_iarchive ia(is);
733         ia >> BOOST_SERIALIZATION_NVP(problem)
734            >> BOOST_SERIALIZATION_NVP(fatal)
735            >> BOOST_SERIALIZATION_NVP(player_id);
736     } catch (const std::exception& err) {
737         ErrorLogger() << "ExtractErrorMessageData(const Message& msg, std::string& problem, bool& fatal) failed!  Message:\n"
738                       << msg.Text() << "\n"
739                       << "Error: " << err.what();
740         problem = UserStringNop("SERVER_MESSAGE_NOT_UNDERSTOOD");
741         fatal = false;
742     }
743 }
744 
ExtractHostMPGameMessageData(const Message & msg,std::string & host_player_name,std::string & client_version_string)745 void ExtractHostMPGameMessageData(const Message& msg, std::string& host_player_name, std::string& client_version_string) {
746     try {
747         std::istringstream is(msg.Text());
748         freeorion_xml_iarchive ia(is);
749         ia >> BOOST_SERIALIZATION_NVP(host_player_name)
750            >> BOOST_SERIALIZATION_NVP(client_version_string);
751 
752     } catch (const std::exception& err) {
753         ErrorLogger() << "ExtractHostMPGameMessageData(const Message& msg, std::string& host_player_name, std::string& client_version_string) failed!  Message:\n"
754                       << msg.Text() << "\n"
755                       << "Error: " << err.what();
756         throw err;
757     }
758 }
759 
ExtractLobbyUpdateMessageData(const Message & msg,MultiplayerLobbyData & lobby_data)760 void ExtractLobbyUpdateMessageData(const Message& msg, MultiplayerLobbyData& lobby_data) {
761     try {
762         std::istringstream is(msg.Text());
763         freeorion_xml_iarchive ia(is);
764         ia >> BOOST_SERIALIZATION_NVP(lobby_data);
765 
766     } catch (const std::exception& err) {
767         ErrorLogger() << "ExtractLobbyUpdateMessageData(const Message& msg, MultiplayerLobbyData& lobby_data) failed!  Message:\n"
768                       << msg.Text() << "\n"
769                       << "Error: " << err.what();
770         throw err;
771     }
772 }
773 
ExtractChatHistoryMessage(const Message & msg,std::vector<ChatHistoryEntity> & chat_history)774 void ExtractChatHistoryMessage(const Message& msg, std::vector<ChatHistoryEntity>& chat_history) {
775     try {
776         std::istringstream is(msg.Text());
777         freeorion_xml_iarchive ia(is);
778         std::size_t size;
779         ia >> BOOST_SERIALIZATION_NVP(size);
780         chat_history.clear();
781         chat_history.reserve(size);
782         for (size_t ii = 0; ii < size; ++ii) {
783             ChatHistoryEntity elem;
784             ia >> BOOST_SERIALIZATION_NVP(elem);
785             chat_history.push_back(elem);
786         }
787     } catch (const std::exception& err) {
788         ErrorLogger() << "ExtractChatHistoryMessage(const Message& msg, std::vector<ChatHistoryEntity>& chat_history) failed!  Message:]n"
789                       << msg.Text() << "\n"
790                       << "Error: " << err.what();
791         throw err;
792     }
793 }
794 
ExtractPlayerChatMessageData(const Message & msg,std::set<int> & recipients,std::string & data,bool & pm)795 void ExtractPlayerChatMessageData(const Message& msg, std::set<int>& recipients, std::string& data, bool& pm) {
796     try {
797         std::istringstream is(msg.Text());
798         freeorion_xml_iarchive ia(is);
799         ia >> BOOST_SERIALIZATION_NVP(recipients)
800            >> BOOST_SERIALIZATION_NVP(data)
801            >> BOOST_SERIALIZATION_NVP(pm);
802 
803     } catch (const std::exception& err) {
804         ErrorLogger() << "ExtractPlayerChatMessageData(const Message& msg, int& receiver, std::string& data) failed! Message:\n"
805                       << msg.Text() << "\n"
806                       << "Error: " << err.what();
807         throw err;
808     }
809 }
810 
ExtractServerPlayerChatMessageData(const Message & msg,int & sender,boost::posix_time::ptime & timestamp,std::string & data,bool & pm)811 void ExtractServerPlayerChatMessageData(const Message& msg,
812                                         int& sender, boost::posix_time::ptime& timestamp,
813                                         std::string& data, bool& pm)
814 {
815     try {
816         std::istringstream is(msg.Text());
817         freeorion_xml_iarchive ia(is);
818         ia >> BOOST_SERIALIZATION_NVP(sender)
819            >> BOOST_SERIALIZATION_NVP(timestamp)
820            >> BOOST_SERIALIZATION_NVP(data)
821            >> BOOST_SERIALIZATION_NVP(pm);
822     } catch (const std::exception& err) {
823         ErrorLogger() << "ExtractServerPlayerChatMessageData(const Message& msg, int& sender, std::string& data) failed! Message:\n"
824                       << msg.Text() << "\n"
825                       << "Error: " << err.what();
826         throw err;
827     }
828 }
829 
ExtractGameStartMessageData(const Message & msg,bool & single_player_game,int & empire_id,int & current_turn,EmpireManager & empires,Universe & universe,SpeciesManager & species,CombatLogManager & combat_logs,SupplyManager & supply,std::map<int,PlayerInfo> & players,OrderSet & orders,bool & loaded_game_data,bool & ui_data_available,SaveGameUIData & ui_data,bool & save_state_string_available,std::string & save_state_string,GalaxySetupData & galaxy_setup_data)830 void ExtractGameStartMessageData(const Message& msg, bool& single_player_game, int& empire_id, int& current_turn,
831                                  EmpireManager& empires, Universe& universe, SpeciesManager& species,
832                                  CombatLogManager& combat_logs, SupplyManager& supply,
833                                  std::map<int, PlayerInfo>& players, OrderSet& orders, bool& loaded_game_data,
834                                  bool& ui_data_available, SaveGameUIData& ui_data, bool& save_state_string_available,
835                                  std::string& save_state_string, GalaxySetupData& galaxy_setup_data)
836 {
837     try {
838         bool try_xml = false;
839         if (strncmp(msg.Data(), "<?xml", 5)) {
840             try {
841                 // first attempt binary deserialziation
842                 std::istringstream is(msg.Text());
843 
844                 freeorion_bin_iarchive ia(is);
845                 ia >> BOOST_SERIALIZATION_NVP(single_player_game)
846                    >> BOOST_SERIALIZATION_NVP(empire_id)
847                    >> BOOST_SERIALIZATION_NVP(current_turn);
848                 GetUniverse().EncodingEmpire() = empire_id;
849 
850                 ScopedTimer deserialize_timer;
851                 ia >> BOOST_SERIALIZATION_NVP(empires);
852                 DebugLogger() << "ExtractGameStartMessage empire deserialization time " << deserialize_timer.DurationString();
853 
854                 ia >> BOOST_SERIALIZATION_NVP(species);
855                 combat_logs.Clear();    // only needed when loading new game, not when incrementally serializing logs on turn update
856                 combat_logs.SerializeIncompleteLogs(ia, 1);
857                 ia >> BOOST_SERIALIZATION_NVP(supply);
858 
859                 deserialize_timer.restart();
860                 Deserialize(ia, universe);
861                 DebugLogger() << "ExtractGameStartMessage universe deserialization time " << deserialize_timer.DurationString();
862 
863 
864                 ia >> BOOST_SERIALIZATION_NVP(players)
865                    >> BOOST_SERIALIZATION_NVP(loaded_game_data);
866                 if (loaded_game_data) {
867                     Deserialize(ia, orders);
868                     ia >> BOOST_SERIALIZATION_NVP(ui_data_available);
869                     if (ui_data_available)
870                         ia >> BOOST_SERIALIZATION_NVP(ui_data);
871                     ia >> BOOST_SERIALIZATION_NVP(save_state_string_available);
872                     if (save_state_string_available)
873                         ia >> BOOST_SERIALIZATION_NVP(save_state_string);
874                 } else {
875                     ui_data_available = false;
876                     save_state_string_available = false;
877                 }
878                 ia >> BOOST_SERIALIZATION_NVP(galaxy_setup_data);
879             } catch (...) {
880                 try_xml = true;
881             }
882         } else {
883             try_xml = true;
884         }
885         if (try_xml) {
886             // if binary deserialization failed, try more-portable XML deserialization
887             std::istringstream is(msg.Text());
888 
889             freeorion_xml_iarchive ia(is);
890             ia >> BOOST_SERIALIZATION_NVP(single_player_game)
891                >> BOOST_SERIALIZATION_NVP(empire_id)
892                >> BOOST_SERIALIZATION_NVP(current_turn);
893             GetUniverse().EncodingEmpire() = empire_id;
894 
895             ScopedTimer deserialize_timer;
896             ia >> BOOST_SERIALIZATION_NVP(empires);
897 
898             DebugLogger() << "ExtractGameStartMessage empire deserialization time " << deserialize_timer.DurationString();
899 
900             ia >> BOOST_SERIALIZATION_NVP(species);
901             combat_logs.Clear();    // only needed when loading new game, not when incrementally serializing logs on turn update
902             combat_logs.SerializeIncompleteLogs(ia, 1);
903             ia >> BOOST_SERIALIZATION_NVP(supply);
904 
905             deserialize_timer.restart();
906             Deserialize(ia, universe);
907             DebugLogger() << "ExtractGameStartMessage universe deserialization time " << deserialize_timer.DurationString();;
908 
909 
910             ia >> BOOST_SERIALIZATION_NVP(players)
911                >> BOOST_SERIALIZATION_NVP(loaded_game_data);
912             TraceLogger() << "ExtractGameStartMessage players and loaded_game_data=" << loaded_game_data << " deserialization time " << deserialize_timer.DurationString();
913             if (loaded_game_data) {
914                 Deserialize(ia, orders);
915                 TraceLogger() << "ExtractGameStartMessage orders deserialization time " << deserialize_timer.DurationString();
916                 ia >> BOOST_SERIALIZATION_NVP(ui_data_available);
917                 if (ui_data_available)
918                     ia >> BOOST_SERIALIZATION_NVP(ui_data);
919                 TraceLogger() << "ExtractGameStartMessage UI data " << ui_data_available << " deserialization time " << deserialize_timer.DurationString();
920                 ia >> BOOST_SERIALIZATION_NVP(save_state_string_available);
921                 if (save_state_string_available)
922                     ia >> BOOST_SERIALIZATION_NVP(save_state_string);
923                 TraceLogger() << "ExtractGameStartMessage save state " << save_state_string_available << " deserialization time " << deserialize_timer.DurationString();
924             } else {
925                 ui_data_available = false;
926                 save_state_string_available = false;
927             }
928             ia >> BOOST_SERIALIZATION_NVP(galaxy_setup_data);
929             TraceLogger() << "ExtractGameStartMessage galaxy setup data deserialization time " << deserialize_timer.DurationString();
930         }
931 
932     } catch (const std::exception& err) {
933         ErrorLogger() << "ExtractGameStartMessageData(...) failed!  Message probably long, so not outputting to log.\n"
934                       << "Error: " << err.what();
935         TraceLogger() << "Message: " << msg.Text();
936         throw err;
937     }
938 }
939 
ExtractJoinGameMessageData(const Message & msg,std::string & player_name,Networking::ClientType & client_type,std::string & version_string,boost::uuids::uuid & cookie)940 void ExtractJoinGameMessageData(const Message& msg, std::string& player_name,
941                                 Networking::ClientType& client_type,
942                                 std::string& version_string,
943                                 boost::uuids::uuid& cookie)
944 {
945     DebugLogger() << "ExtractJoinGameMessageData() from " << player_name << " client type " << client_type;
946     try {
947         std::istringstream is(msg.Text());
948         freeorion_xml_iarchive ia(is);
949         ia >> BOOST_SERIALIZATION_NVP(player_name)
950            >> BOOST_SERIALIZATION_NVP(client_type)
951            >> BOOST_SERIALIZATION_NVP(version_string)
952            >> BOOST_SERIALIZATION_NVP(cookie);
953 
954     } catch (const std::exception& err) {
955         ErrorLogger() << "ExtractJoinGameMessageData(const Message& msg, std::string& player_name, "
956                       << "Networking::ClientType client_type, std::string& version_string) failed!  Message:\n"
957                       << msg.Text() << "\n"
958                       << "Error: " << err.what();
959         throw err;
960     }
961 }
962 
ExtractJoinAckMessageData(const Message & msg,int & player_id,boost::uuids::uuid & cookie)963 void ExtractJoinAckMessageData(const Message& msg, int& player_id,
964                                boost::uuids::uuid& cookie)
965 {
966     try {
967         std::istringstream is(msg.Text());
968         freeorion_xml_iarchive ia(is);
969         ia >> BOOST_SERIALIZATION_NVP(player_id)
970            >> BOOST_SERIALIZATION_NVP(cookie);
971     } catch (const std::exception& err) {
972         ErrorLogger() << "ExtractJoinAckMessageData(const Message& msg, int& player_id, "
973                       << "boost::uuids::uuid& cookie) failed!  Message:\n"
974                       << msg.Text() << "\n"
975                       << "Error: " << err.what();
976         throw err;
977     }
978 }
979 
ExtractTurnOrdersMessageData(const Message & msg,OrderSet & orders,bool & ui_data_available,SaveGameUIData & ui_data,bool & save_state_string_available,std::string & save_state_string)980 void ExtractTurnOrdersMessageData(const Message& msg,
981                                   OrderSet& orders,
982                                   bool& ui_data_available,
983                                   SaveGameUIData& ui_data,
984                                   bool& save_state_string_available,
985                                   std::string& save_state_string)
986 {
987     try {
988         std::istringstream is(msg.Text());
989         freeorion_xml_iarchive ia(is);
990         DebugLogger() << "deserializing orders";
991         Deserialize(ia, orders);
992         DebugLogger() << "checking for ui data";
993         ia >> BOOST_SERIALIZATION_NVP(ui_data_available);
994         if (ui_data_available) {
995             DebugLogger() << "deserializing UI data";
996             ia >> BOOST_SERIALIZATION_NVP(ui_data);
997         }
998         DebugLogger() << "checking for save state string";
999         ia >> BOOST_SERIALIZATION_NVP(save_state_string_available);
1000         if (save_state_string_available) {
1001             DebugLogger() << "deserializing save state string";
1002             ia >> BOOST_SERIALIZATION_NVP(save_state_string);
1003         }
1004 
1005     } catch (const std::exception& err) {
1006         ErrorLogger() << "ExtractTurnOrdersMessageData(const Message& msg, ...) failed! Message probably long, so not outputting to log.\n"
1007                       << "Error: " << err.what();
1008         throw err;
1009     }
1010 }
1011 
ExtractTurnPartialOrdersMessageData(const Message & msg,OrderSet & added,std::set<int> & deleted)1012 void ExtractTurnPartialOrdersMessageData(const Message& msg, OrderSet& added, std::set<int>& deleted) {
1013     try {
1014         std::istringstream is(msg.Text());
1015         freeorion_xml_iarchive ia(is);
1016         DebugLogger() << "deserializing partial orders";
1017         Deserialize(ia, added);
1018         ia >> BOOST_SERIALIZATION_NVP(deleted);
1019     } catch (const std::exception& err) {
1020         ErrorLogger() << "ExtractTurnPartialOrdersMessageData(const Message& msg) failed! Message probably long, so not outputting to log.\n"
1021                       << "Error: " << err.what();
1022         throw err;
1023     }
1024 }
1025 
ExtractTurnUpdateMessageData(const Message & msg,int empire_id,int & current_turn,EmpireManager & empires,Universe & universe,SpeciesManager & species,CombatLogManager & combat_logs,SupplyManager & supply,std::map<int,PlayerInfo> & players)1026 void ExtractTurnUpdateMessageData(const Message& msg, int empire_id, int& current_turn, EmpireManager& empires,
1027                                   Universe& universe, SpeciesManager& species, CombatLogManager& combat_logs,
1028                                   SupplyManager& supply, std::map<int, PlayerInfo>& players)
1029 {
1030     try {
1031         ScopedTimer timer("Turn Update Unpacking", true);
1032 
1033         bool try_xml = false;
1034         if (std::strncmp(msg.Data(), "<?xml", 5)) {
1035             try {
1036                 // first attempt binary deserialization
1037                 std::istringstream is(msg.Text());
1038                 freeorion_bin_iarchive ia(is);
1039                 GetUniverse().EncodingEmpire() = empire_id;
1040                 ia >> BOOST_SERIALIZATION_NVP(current_turn)
1041                    >> BOOST_SERIALIZATION_NVP(empires)
1042                    >> BOOST_SERIALIZATION_NVP(species);
1043                 combat_logs.SerializeIncompleteLogs(ia, 1);
1044                 ia >> BOOST_SERIALIZATION_NVP(supply);
1045                 Deserialize(ia, universe);
1046                 ia >> BOOST_SERIALIZATION_NVP(players);
1047             } catch (...) {
1048                 try_xml = true;
1049             }
1050         } else {
1051             try_xml = true;
1052         }
1053         if (try_xml) {
1054             // try again with more-portable XML deserialization
1055             std::istringstream is(msg.Text());
1056             freeorion_xml_iarchive ia(is);
1057             GetUniverse().EncodingEmpire() = empire_id;
1058             ia >> BOOST_SERIALIZATION_NVP(current_turn)
1059                >> BOOST_SERIALIZATION_NVP(empires)
1060                >> BOOST_SERIALIZATION_NVP(species);
1061             combat_logs.SerializeIncompleteLogs(ia, 1);
1062             ia >> BOOST_SERIALIZATION_NVP(supply);
1063             Deserialize(ia, universe);
1064             ia >> BOOST_SERIALIZATION_NVP(players);
1065         }
1066 
1067     } catch (const std::exception& err) {
1068         ErrorLogger() << "ExtractTurnUpdateMessageData(...) failed!  Message probably long, so not outputting to log.\n"
1069                       << "Error: " << err.what();
1070         throw err;
1071     }
1072 }
1073 
ExtractTurnPartialUpdateMessageData(const Message & msg,int empire_id,Universe & universe)1074 void ExtractTurnPartialUpdateMessageData(const Message& msg, int empire_id, Universe& universe) {
1075     try {
1076         ScopedTimer timer("Mid Turn Update Unpacking", true);
1077 
1078         bool try_xml = false;
1079         if (std::strncmp(msg.Data(), "<?xml", 5)) {
1080             try {
1081                 // first attempt binary deserialization
1082                 std::istringstream is(msg.Text());
1083                 freeorion_bin_iarchive ia(is);
1084                 GetUniverse().EncodingEmpire() = empire_id;
1085                 Deserialize(ia, universe);
1086             } catch (...) {
1087                 try_xml = true;
1088             }
1089         } else {
1090             try_xml = true;
1091         }
1092         if (try_xml) {
1093             // try again with more-portable XML deserialization
1094             std::istringstream is(msg.Text());
1095             freeorion_xml_iarchive ia(is);
1096             GetUniverse().EncodingEmpire() = empire_id;
1097             Deserialize(ia, universe);
1098         }
1099 
1100     } catch (const std::exception& err) {
1101         ErrorLogger() << "ExtracturnPartialUpdateMessageData(...) failed!  Message probably long, so not outputting to log.\n"
1102                       << "Error: " << err.what();
1103         throw err;
1104     }
1105 }
1106 
ExtractTurnProgressMessageData(const Message & msg,Message::TurnProgressPhase & phase_id)1107 void ExtractTurnProgressMessageData(const Message& msg, Message::TurnProgressPhase& phase_id) {
1108     try {
1109         std::istringstream is(msg.Text());
1110         freeorion_xml_iarchive ia(is);
1111         ia >> BOOST_SERIALIZATION_NVP(phase_id);
1112 
1113     } catch (const std::exception& err) {
1114         ErrorLogger() << "ExtractTurnProgressMessageData(const Message& msg, Message::TurnProgressPhase& phase_id) failed!  Message:\n"
1115                       << msg.Text() << "\n"
1116                       << "Error: " << err.what();
1117         throw err;
1118     }
1119 }
1120 
ExtractPlayerStatusMessageData(const Message & msg,Message::PlayerStatus & status,int & about_empire_id)1121 void ExtractPlayerStatusMessageData(const Message& msg,
1122                                     Message::PlayerStatus& status,
1123                                     int& about_empire_id) {
1124     try {
1125         std::istringstream is(msg.Text());
1126         freeorion_xml_iarchive ia(is);
1127         ia >> BOOST_SERIALIZATION_NVP(status)
1128            >> BOOST_SERIALIZATION_NVP(about_empire_id);
1129 
1130     } catch (const std::exception& err) {
1131         ErrorLogger() << "ExtractPlayerStatusMessageData(const Message& msg, Message::PlayerStatus&, int& about_empire_id) failed!  Message:\n"
1132                       << msg.Text() << "\n"
1133                       << "Error: " << err.what();
1134         throw err;
1135     }
1136 }
1137 
ExtractHostSPGameMessageData(const Message & msg,SinglePlayerSetupData & setup_data,std::string & client_version_string)1138 void ExtractHostSPGameMessageData(const Message& msg, SinglePlayerSetupData& setup_data, std::string& client_version_string) {
1139     try {
1140         std::istringstream is(msg.Text());
1141         freeorion_xml_iarchive ia(is);
1142         ia >> BOOST_SERIALIZATION_NVP(setup_data)
1143            >> BOOST_SERIALIZATION_NVP(client_version_string);
1144 
1145     } catch (const std::exception& err) {
1146         ErrorLogger() << "ExtractHostSPGameMessageData(const Message& msg, SinglePlayerSetupData& setup_data, std::string& client_version_string) failed!  Message:\n"
1147                       << msg.Text() << "\n"
1148                       << "Error: " << err.what();
1149         throw err;
1150     }
1151 }
1152 
ExtractEndGameMessageData(const Message & msg,Message::EndGameReason & reason,std::string & reason_player_name)1153 void ExtractEndGameMessageData(const Message& msg, Message::EndGameReason& reason, std::string& reason_player_name) {
1154     try {
1155         std::istringstream is(msg.Text());
1156         freeorion_xml_iarchive ia(is);
1157         ia >> BOOST_SERIALIZATION_NVP(reason)
1158            >> BOOST_SERIALIZATION_NVP(reason_player_name);
1159 
1160     } catch (const std::exception& err) {
1161         ErrorLogger() << "ExtractEndGameMessageData(const Message& msg, Message::EndGameReason& reason, "
1162                       << "std::string& reason_player_name) failed!  Message:\n"
1163                       << msg.Text() << "\n"
1164                       << "Error: " << err.what();
1165         throw err;
1166     }
1167 }
1168 
ExtractModeratorActionMessageData(const Message & msg,Moderator::ModeratorAction * & mod_action)1169 void ExtractModeratorActionMessageData(const Message& msg, Moderator::ModeratorAction*& mod_action) {
1170     try {
1171         std::istringstream is(msg.Text());
1172         freeorion_xml_iarchive ia(is);
1173         ia >> BOOST_SERIALIZATION_NVP(mod_action);
1174 
1175     } catch (const std::exception& err) {
1176         ErrorLogger() << "ExtractModeratorActionMessageData(const Message& msg, Moderator::ModeratorAction& mod_act) "
1177                       << "failed!  Message:\n"
1178                       << msg.Text() << "\n"
1179                       << "Error: " << err.what();
1180     }
1181 }
1182 
ExtractDiplomacyMessageData(const Message & msg,DiplomaticMessage & diplo_message)1183 void ExtractDiplomacyMessageData(const Message& msg, DiplomaticMessage& diplo_message) {
1184     try {
1185         std::istringstream is(msg.Text());
1186         freeorion_xml_iarchive ia(is);
1187         ia >> BOOST_SERIALIZATION_NVP(diplo_message);
1188 
1189     } catch (const std::exception& err) {
1190         ErrorLogger() << "ExtractDiplomacyMessageData(const Message& msg, DiplomaticMessage& "
1191                       << "diplo_message) failed!  Message:\n"
1192                       << msg.Text() << "\n"
1193                       << "Error: " << err.what();
1194         throw err;
1195     }
1196 }
1197 
ExtractDiplomaticStatusMessageData(const Message & msg,DiplomaticStatusUpdateInfo & diplo_update)1198 void ExtractDiplomaticStatusMessageData(const Message& msg, DiplomaticStatusUpdateInfo& diplo_update) {
1199     try {
1200         std::istringstream is(msg.Text());
1201         freeorion_xml_iarchive ia(is);
1202         ia >> BOOST_SERIALIZATION_NVP(diplo_update.empire1_id)
1203            >> BOOST_SERIALIZATION_NVP(diplo_update.empire2_id)
1204            >> BOOST_SERIALIZATION_NVP(diplo_update.diplo_status);
1205 
1206     } catch (const std::exception& err) {
1207         ErrorLogger() << "ExtractDiplomaticStatusMessageData(const Message& msg, DiplomaticStatusUpdate& diplo_update) failed!  Message:\n"
1208                       << msg.Text() << "\n"
1209                       << "Error: " << err.what();
1210         throw err;
1211     }
1212 }
1213 
ExtractRequestSavePreviewsMessageData(const Message & msg,std::string & directory)1214 void ExtractRequestSavePreviewsMessageData(const Message& msg, std::string& directory)
1215 { directory = msg.Text(); }
1216 
ExtractDispatchSavePreviewsMessageData(const Message & msg,PreviewInformation & previews)1217 void ExtractDispatchSavePreviewsMessageData(const Message& msg, PreviewInformation& previews) {
1218     try {
1219         std::istringstream is(msg.Text());
1220         freeorion_xml_iarchive ia(is);
1221         ia >> BOOST_SERIALIZATION_NVP(previews);
1222 
1223     } catch(const std::exception& err) {
1224         ErrorLogger() << "ExtractDispatchSavePreviewsMessageData(const Message& msg, PreviewInformation& previews) failed!  Message:\n"
1225                       << msg.Text() << "\n"
1226                       << "Error: " << err.what();
1227         throw err;
1228     }
1229 }
1230 
ExtractServerSaveGameCompleteMessageData(const Message & msg,std::string & save_filename,int & bytes_written)1231 FO_COMMON_API void ExtractServerSaveGameCompleteMessageData(const Message& msg, std::string& save_filename, int& bytes_written) {
1232     try {
1233         std::istringstream is(msg.Text());
1234         freeorion_xml_iarchive ia(is);
1235         ia >> BOOST_SERIALIZATION_NVP(save_filename)
1236            >> BOOST_SERIALIZATION_NVP(bytes_written);
1237 
1238     } catch(const std::exception& err) {
1239         ErrorLogger() << "ExtractServerSaveGameCompleteServerSaveGameCompleteMessageData(const Message& msg, std::string& save_filename, int& bytes_written) failed!  Message:\n"
1240                       << msg.Text() << "\n"
1241                       << "Error: " << err.what();
1242         throw err;
1243     }
1244 }
1245 
ExtractRequestCombatLogsMessageData(const Message & msg,std::vector<int> & ids)1246 FO_COMMON_API void ExtractRequestCombatLogsMessageData(const Message& msg, std::vector<int>& ids) {
1247     try {
1248         std::istringstream is(msg.Text());
1249         freeorion_xml_iarchive ia(is);
1250         ia >> BOOST_SERIALIZATION_NVP(ids);
1251     } catch(const std::exception& err) {
1252         ErrorLogger() << "ExtractRequestCombatLogMessageData(const Message& msg, std::vector<int>& ids) failed!  Message:\n"
1253                       << msg.Text() << "\n"
1254                       << "Error: " << err.what();
1255         throw err;
1256     }
1257 }
1258 
ExtractDispatchCombatLogsMessageData(const Message & msg,std::vector<std::pair<int,CombatLog>> & logs)1259 FO_COMMON_API void ExtractDispatchCombatLogsMessageData(
1260     const Message& msg, std::vector<std::pair<int, CombatLog>>& logs)
1261 {
1262     try {
1263         bool try_xml = false;
1264         if (std::strncmp(msg.Data(), "<?xml", 5)) {
1265             try {
1266                 // first attempt binary deserialization
1267                 std::istringstream is(msg.Text());
1268                 freeorion_bin_iarchive ia(is);
1269                 ia >> BOOST_SERIALIZATION_NVP(logs);
1270             } catch (...) {
1271                 try_xml = true;
1272             }
1273         } else {
1274             try_xml = true;
1275         }
1276         if (try_xml) {
1277             // try again with more-portable XML deserialization
1278             std::istringstream is(msg.Text());
1279             freeorion_xml_iarchive ia(is);
1280             ia >> BOOST_SERIALIZATION_NVP(logs);
1281         }
1282 
1283     } catch(const std::exception& err) {
1284         ErrorLogger() << "ExtractDispatchCombatLogMessageData(const Message& msg, std::vector<std::pair<int, const CombatLog&>>& logs) failed!  Message:\n"
1285                       << msg.Text() << "\n"
1286                       << "Error: " << err.what();
1287         throw err;
1288     }
1289 }
1290 
ExtractLoggerConfigMessageData(const Message & msg,std::set<std::tuple<std::string,std::string,LogLevel>> & options)1291 FO_COMMON_API void ExtractLoggerConfigMessageData(
1292     const Message& msg, std::set<std::tuple<std::string, std::string, LogLevel>>& options)
1293 {
1294     try {
1295         std::istringstream is(msg.Text());
1296         freeorion_xml_iarchive ia(is);
1297         std::size_t size;
1298         ia >> BOOST_SERIALIZATION_NVP(size);
1299         for (size_t ii = 0; ii < size; ++ii) {
1300             std::string option;
1301             std::string name;
1302             LogLevel level;
1303             ia >> BOOST_SERIALIZATION_NVP(option);
1304             ia >> BOOST_SERIALIZATION_NVP(name);
1305             ia >> BOOST_SERIALIZATION_NVP(level);
1306             options.insert(std::make_tuple(option, name, level));
1307         }
1308     } catch (const std::exception& err) {
1309         ErrorLogger() << "ExtractDispatchCombatLogMessageData(const Message& msg, std::vector<std::pair<int, const CombatLog&> >& logs) failed!  Message:\n"
1310                       << msg.Text() << "\n"
1311                       << "Error: " << err.what();
1312         throw err;
1313     }
1314 
1315 }
1316 
ExtractContentCheckSumMessageData(const Message & msg,std::map<std::string,unsigned int> & checksums)1317 void ExtractContentCheckSumMessageData(
1318     const Message& msg, std::map<std::string, unsigned int>& checksums)
1319 {
1320     checksums.clear();
1321     try {
1322         std::istringstream is(msg.Text());
1323         freeorion_xml_iarchive ia(is);
1324         ia >> BOOST_SERIALIZATION_NVP(checksums);
1325 
1326     } catch(const std::exception& err) {
1327         ErrorLogger() << "ExtractContentCheckSumMessageData(const Message& msg, std::string& save_filename, std::map<std::string, unsigned int>) failed!  Message:\n"
1328                       << msg.Text() << "\n"
1329                       << "Error: " << err.what();
1330         throw err;
1331     }
1332 }
1333 
ExtractAuthRequestMessageData(const Message & msg,std::string & player_name,std::string & auth)1334 void ExtractAuthRequestMessageData(const Message& msg, std::string& player_name, std::string& auth) {
1335     try {
1336         std::istringstream is(msg.Text());
1337         freeorion_xml_iarchive ia(is);
1338         ia >> BOOST_SERIALIZATION_NVP(player_name)
1339            >> BOOST_SERIALIZATION_NVP(auth);
1340 
1341     } catch(const std::exception& err) {
1342         ErrorLogger() << "ExtractAuthRequestMessageData(const Message& msg, std::string& player_name, std::string& auth) failed!  Message:\n"
1343                       << msg.Text() << "\n"
1344                       << "Error: " << err.what();
1345         throw err;
1346     }
1347 }
1348 
ExtractAuthResponseMessageData(const Message & msg,std::string & player_name,std::string & auth)1349 void ExtractAuthResponseMessageData(const Message& msg, std::string& player_name, std::string& auth) {
1350     try {
1351         std::istringstream is(msg.Text());
1352         freeorion_xml_iarchive ia(is);
1353         ia >> BOOST_SERIALIZATION_NVP(player_name)
1354            >> BOOST_SERIALIZATION_NVP(auth);
1355 
1356     } catch(const std::exception& err) {
1357         ErrorLogger() << "ExtractAuthResponeMessageData(const Message& msg, std::string& player_name, std::string& auth) failed!  Message:\n"
1358                       << msg.Text() << "\n"
1359                       << "Error: " << err.what();
1360         throw err;
1361     }
1362 }
1363 
ExtractSetAuthorizationRolesMessage(const Message & msg,Networking::AuthRoles & roles)1364 void ExtractSetAuthorizationRolesMessage(const Message &msg, Networking::AuthRoles& roles)
1365 { roles.SetText(msg.Text()); }
1366 
ExtractPlayerInfoMessageData(const Message & msg,std::map<int,PlayerInfo> & players)1367 void ExtractPlayerInfoMessageData(const Message &msg, std::map<int, PlayerInfo>& players) {
1368     try {
1369         std::istringstream is(msg.Text());
1370         freeorion_xml_iarchive ia(is);
1371         ia >> BOOST_SERIALIZATION_NVP(players);
1372     } catch(const std::exception& err) {
1373         ErrorLogger() << "ExtractPlayerInfo(const Message &msg, std::map<int, PlayerInfo>& players) failed!  Message:\n"
1374                       << msg.Text() << "\n"
1375                       << "Error: " << err.what();
1376     }
1377 }
1378