1 #include "EmpireManager.h"
2 
3 #include "Empire.h"
4 #include "../util/Directories.h"
5 #include "../util/GameRules.h"
6 #include "../util/i18n.h"
7 #include "../util/Logger.h"
8 #include "../util/XMLDoc.h"
9 #include "../universe/Enums.h"
10 
11 #include <boost/filesystem/fstream.hpp>
12 
13 namespace {
14     // sorted pair, so order of empire IDs specified doesn't matter
DiploKey(int id1,int ind2)15     std::pair<int, int> DiploKey(int id1, int ind2)
16     { return std::make_pair(std::max(id1, ind2), std::min(id1, ind2)); }
17 
18     const std::string EMPTY_STRING;
19 }
20 
EmpireManager()21 EmpireManager::EmpireManager()
22 {}
23 
~EmpireManager()24 EmpireManager::~EmpireManager()
25 { Clear(); }
26 
operator =(EmpireManager & rhs)27 const EmpireManager& EmpireManager::operator=(EmpireManager& rhs) {
28     Clear();
29     m_empire_map = rhs.m_empire_map;
30     rhs.m_empire_map.clear();
31 
32     m_empire_diplomatic_statuses = rhs.m_empire_diplomatic_statuses;
33     rhs.m_empire_diplomatic_statuses.clear();
34 
35     m_diplomatic_messages = rhs.m_diplomatic_messages;
36     rhs.m_diplomatic_messages.clear();
37 
38     return *this;
39 }
40 
GetEmpire(int id) const41 const Empire* EmpireManager::GetEmpire(int id) const {
42     auto it = m_empire_map.find(id);
43     return it == m_empire_map.end() ? nullptr : it->second;
44 }
45 
GetSource(int id) const46 std::shared_ptr<const UniverseObject> EmpireManager::GetSource(int id) const {
47     auto it = m_empire_map.find(id);
48     return it != m_empire_map.end() ? it->second->Source() : nullptr;
49 }
50 
GetEmpireName(int id) const51 const std::string& EmpireManager::GetEmpireName(int id) const {
52     auto it = m_empire_map.find(id);
53     return it == m_empire_map.end() ? EMPTY_STRING : it->second->Name();
54 }
55 
begin() const56 EmpireManager::const_iterator EmpireManager::begin() const
57 { return m_empire_map.begin(); }
58 
end() const59 EmpireManager::const_iterator EmpireManager::end() const
60 { return m_empire_map.end(); }
61 
NumEmpires() const62 int EmpireManager::NumEmpires() const
63 { return m_empire_map.size(); }
64 
NumEliminatedEmpires() const65 int EmpireManager::NumEliminatedEmpires() const {
66     int eliminated_count = 0;
67 
68     for (const auto& empire : m_empire_map)
69         if (empire.second->Eliminated())
70             eliminated_count++;
71 
72     return eliminated_count;
73 }
74 
Dump() const75 std::string EmpireManager::Dump() const {
76     std::string retval = "Empires:\n";
77     for (const auto& entry : m_empire_map)
78         retval += entry.second->Dump();
79     retval += DumpDiplomacy();
80     return retval;
81 }
82 
DumpDiplomacy() const83 std::string EmpireManager::DumpDiplomacy() const {
84     std::string retval = "Diplomatic Statuses:\n";
85     for (const auto& entry : m_empire_diplomatic_statuses) {
86         const Empire* empire1 = GetEmpire(entry.first.first);
87         const Empire* empire2 = GetEmpire(entry.first.second);
88         if (!empire1 || !empire2)
89             continue;
90         retval += " * " + empire1->Name() + " / " + empire2->Name() + " : ";
91         switch (entry.second) {
92         case DIPLO_WAR:     retval += "War";    break;
93         case DIPLO_PEACE:   retval += "Peace";  break;
94         case DIPLO_ALLIED:  retval += "Allied";  break;
95         default:            retval += "?";      break;
96         }
97         retval += "\n";
98     }
99     retval += "Diplomatic Messages:\n";
100     for (const auto& message : m_diplomatic_messages) {
101         if (message.second.GetType() == DiplomaticMessage::INVALID_DIPLOMATIC_MESSAGE_TYPE)
102             continue;   // don't print non-messages and pollute the log files...
103         retval += "From: " + std::to_string(message.first.first)
104                + " to: " + std::to_string(message.first.second)
105                + " message: " + message.second.Dump() + "\n";
106     }
107 
108     return retval;
109 }
110 
GetEmpire(int id)111 Empire* EmpireManager::GetEmpire(int id) {
112     iterator it = m_empire_map.find(id);
113     return it == end() ? nullptr : it->second;
114 }
115 
begin()116 EmpireManager::iterator EmpireManager::begin()
117 { return m_empire_map.begin(); }
118 
end()119 EmpireManager::iterator EmpireManager::end()
120 { return m_empire_map.end(); }
121 
BackPropagateMeters()122 void EmpireManager::BackPropagateMeters() {
123     for (auto& entry : m_empire_map)
124         entry.second->BackPropagateMeters();
125 }
126 
CreateEmpire(int empire_id,const std::string & name,const std::string & player_name,const GG::Clr & color,bool authenticated)127 Empire* EmpireManager::CreateEmpire(int empire_id, const std::string& name,
128                                     const std::string& player_name,
129                                     const GG::Clr& color, bool authenticated)
130 {
131     Empire* empire = new Empire(name, player_name, empire_id, color, authenticated);
132     InsertEmpire(empire);
133     return empire;
134 }
135 
InsertEmpire(Empire * empire)136 void EmpireManager::InsertEmpire(Empire* empire) {
137     if (!empire) {
138         ErrorLogger() << "EmpireManager::InsertEmpire passed null empire";
139         return;
140     }
141 
142     int empire_id = empire->EmpireID();
143 
144     if (m_empire_map.count(empire_id)) {
145         ErrorLogger() << "EmpireManager::InsertEmpire passed empire with id (" << empire_id << ") for which there already is an empire.";
146         return;
147     }
148 
149     m_empire_map[empire_id] = empire;
150 }
151 
Clear()152 void EmpireManager::Clear() {
153     for (auto& entry : m_empire_map)
154         delete entry.second;
155     m_empire_map.clear();
156     m_empire_diplomatic_statuses.clear();
157 }
158 
GetDiplomaticStatus(int empire1,int empire2) const159 DiplomaticStatus EmpireManager::GetDiplomaticStatus(int empire1, int empire2) const {
160     if (empire1 == ALL_EMPIRES || empire2 == ALL_EMPIRES || empire1 == empire2)
161         return INVALID_DIPLOMATIC_STATUS;
162 
163     auto it = m_empire_diplomatic_statuses.find(DiploKey(empire1, empire2));
164     if (it != m_empire_diplomatic_statuses.end())
165         return it->second;
166     ErrorLogger() << "Couldn't find diplomatic status between empires " << empire1 << " and " << empire2;
167     return INVALID_DIPLOMATIC_STATUS;
168 }
169 
GetEmpireIDsWithDiplomaticStatusWithEmpire(int empire_id,DiplomaticStatus diplo_status) const170 std::set<int> EmpireManager::GetEmpireIDsWithDiplomaticStatusWithEmpire(
171     int empire_id, DiplomaticStatus diplo_status) const
172 {
173     std::set<int> retval;
174     if (empire_id == ALL_EMPIRES || diplo_status == INVALID_DIPLOMATIC_STATUS)
175         return retval;
176     // find ids of empires with the specified diplomatic status with the specified empire
177     for (auto const& id_pair_status : m_empire_diplomatic_statuses) {
178         if (id_pair_status.second != diplo_status)
179             continue;
180         if (id_pair_status.first.first == empire_id)
181             retval.insert(id_pair_status.first.second);
182         else if (id_pair_status.first.second == empire_id)
183             retval.insert(id_pair_status.first.first);
184     }
185     return retval;
186 }
187 
DiplomaticMessageAvailable(int sender_id,int recipient_id) const188 bool EmpireManager::DiplomaticMessageAvailable(int sender_id, int recipient_id) const {
189     auto it = m_diplomatic_messages.find({sender_id, recipient_id});
190     return it != m_diplomatic_messages.end() &&
191            it->second.GetType() != DiplomaticMessage::INVALID_DIPLOMATIC_MESSAGE_TYPE;
192 }
193 
GetDiplomaticMessage(int sender_id,int recipient_id) const194 const DiplomaticMessage& EmpireManager::GetDiplomaticMessage(int sender_id, int recipient_id) const {
195     auto it = m_diplomatic_messages.find({sender_id, recipient_id});
196     if (it != m_diplomatic_messages.end())
197         return it->second;
198     static DiplomaticMessage DEFAULT_DIPLOMATIC_MESSAGE;
199     //WarnLogger() << "Couldn't find requested diplomatic message between empires " << sender_id << " and " << recipient_id;
200     return DEFAULT_DIPLOMATIC_MESSAGE;
201 }
202 
SetDiplomaticStatus(int empire1,int empire2,DiplomaticStatus status)203 void EmpireManager::SetDiplomaticStatus(int empire1, int empire2, DiplomaticStatus status) {
204     DiplomaticStatus initial_status = GetDiplomaticStatus(empire1, empire2);
205     if (status != initial_status) {
206         m_empire_diplomatic_statuses[DiploKey(empire1, empire2)] = status;
207         DiplomaticStatusChangedSignal(empire1, empire2);
208     }
209 }
210 
SetDiplomaticMessage(const DiplomaticMessage & message)211 void EmpireManager::SetDiplomaticMessage(const DiplomaticMessage& message) {
212     int empire1 = message.SenderEmpireID();
213     int empire2 = message.RecipientEmpireID();
214     const DiplomaticMessage& initial_message = GetDiplomaticMessage(empire1, empire2);
215     if (message != initial_message) {
216         m_diplomatic_messages[{empire1, empire2}] = message;
217         DiplomaticMessageChangedSignal(empire1, empire2);
218     }
219 }
220 
RemoveDiplomaticMessage(int sender_id,int recipient_id)221 void EmpireManager::RemoveDiplomaticMessage(int sender_id, int recipient_id) {
222     auto it = m_diplomatic_messages.find({sender_id, recipient_id});
223     bool changed = (it != m_diplomatic_messages.end()) &&
224                    (it->second.GetType() != DiplomaticMessage::INVALID_DIPLOMATIC_MESSAGE_TYPE);
225 
226     m_diplomatic_messages[{sender_id, recipient_id}] =
227         DiplomaticMessage(sender_id, recipient_id, DiplomaticMessage::INVALID_DIPLOMATIC_MESSAGE_TYPE);
228 
229     // if there already was a message, and it wasn't already a non-message, notify about change
230     if (changed)
231         DiplomaticMessageChangedSignal(sender_id, recipient_id);
232 }
233 
HandleDiplomaticMessage(const DiplomaticMessage & message)234 void EmpireManager::HandleDiplomaticMessage(const DiplomaticMessage& message) {
235     int sender_empire_id = message.SenderEmpireID();
236     int recipient_empire_id = message.RecipientEmpireID();
237 
238     if (!message.IsAllowed())
239         return;
240 
241     DiplomaticStatus diplo_status = GetDiplomaticStatus(sender_empire_id, recipient_empire_id);
242     bool message_from_recipient_to_sender_available = DiplomaticMessageAvailable(recipient_empire_id, sender_empire_id);
243     const DiplomaticMessage& existing_message_from_recipient_to_sender = GetDiplomaticMessage(recipient_empire_id, sender_empire_id);
244     //bool message_from_sender_to_recipient_available = DiplomaticMessageAvailable(sender_empire_id, recipient_empire_id);
245 
246     switch (message.GetType()) {
247     case DiplomaticMessage::WAR_DECLARATION: {
248         if (diplo_status == DIPLO_PEACE) {
249             // cancels any previous messages, sets empires at war
250             RemoveDiplomaticMessage(sender_empire_id, recipient_empire_id);
251             RemoveDiplomaticMessage(recipient_empire_id, sender_empire_id);
252             SetDiplomaticStatus(sender_empire_id, recipient_empire_id, DIPLO_WAR);
253         }
254         break;
255     }
256 
257     case DiplomaticMessage::PEACE_PROPOSAL: {
258         if (diplo_status == DIPLO_WAR && !message_from_recipient_to_sender_available) {
259             SetDiplomaticMessage(message);
260 
261         } else if (diplo_status == DIPLO_WAR && message_from_recipient_to_sender_available) {
262             if (existing_message_from_recipient_to_sender.GetType() ==
263                 DiplomaticMessage::PEACE_PROPOSAL)
264             {
265                 // somehow multiple peace proposals sent by players to eachother
266                 // cancel and remove
267                 RemoveDiplomaticMessage(recipient_empire_id, sender_empire_id);
268                 RemoveDiplomaticMessage(sender_empire_id, recipient_empire_id);
269                 SetDiplomaticStatus(sender_empire_id, recipient_empire_id, DIPLO_PEACE);
270             }
271         }
272         break;
273     }
274 
275     case DiplomaticMessage::ACCEPT_PEACE_PROPOSAL: {
276         if (message_from_recipient_to_sender_available &&
277             existing_message_from_recipient_to_sender.GetType() == DiplomaticMessage::PEACE_PROPOSAL)
278         {
279             // one player proposed peace and the other accepted
280             RemoveDiplomaticMessage(recipient_empire_id, sender_empire_id);
281             RemoveDiplomaticMessage(sender_empire_id, recipient_empire_id);
282             SetDiplomaticStatus(sender_empire_id, recipient_empire_id, DIPLO_PEACE);
283         }
284         break;
285     }
286 
287     case DiplomaticMessage::ALLIES_PROPOSAL: {
288         if (diplo_status == DIPLO_PEACE && !message_from_recipient_to_sender_available) {
289             SetDiplomaticMessage(message);
290 
291         } else if (diplo_status == DIPLO_PEACE && message_from_recipient_to_sender_available) {
292             if (existing_message_from_recipient_to_sender.GetType() ==
293                 DiplomaticMessage::ALLIES_PROPOSAL)
294             {
295                 // somehow multiple allies proposals sent by players to eachother
296                 // cancel and remove
297                 RemoveDiplomaticMessage(recipient_empire_id, sender_empire_id);
298                 RemoveDiplomaticMessage(sender_empire_id, recipient_empire_id);
299                 SetDiplomaticStatus(sender_empire_id, recipient_empire_id, DIPLO_ALLIED);
300             }
301         }
302         break;
303     }
304 
305     case DiplomaticMessage::ACCEPT_ALLIES_PROPOSAL: {
306         if (message_from_recipient_to_sender_available &&
307             existing_message_from_recipient_to_sender.GetType() == DiplomaticMessage::ALLIES_PROPOSAL)
308         {
309             // one player proposed alliance and the other accepted
310             RemoveDiplomaticMessage(recipient_empire_id, sender_empire_id);
311             RemoveDiplomaticMessage(sender_empire_id, recipient_empire_id);
312             SetDiplomaticStatus(sender_empire_id, recipient_empire_id, DIPLO_ALLIED);
313         }
314         break;
315     }
316 
317     case DiplomaticMessage::END_ALLIANCE_DECLARATION: {
318         if (diplo_status == DIPLO_ALLIED) {
319             // cancels any previous messages, sets empires to peace
320             RemoveDiplomaticMessage(sender_empire_id, recipient_empire_id);
321             RemoveDiplomaticMessage(recipient_empire_id, sender_empire_id);
322             SetDiplomaticStatus(sender_empire_id, recipient_empire_id, DIPLO_PEACE);
323         }
324         break;
325     }
326 
327     case DiplomaticMessage::CANCEL_PROPOSAL: {
328         RemoveDiplomaticMessage(sender_empire_id, recipient_empire_id);
329         break;
330     }
331 
332     case DiplomaticMessage::REJECT_PROPOSAL: {
333         RemoveDiplomaticMessage(sender_empire_id, recipient_empire_id);
334         RemoveDiplomaticMessage(recipient_empire_id, sender_empire_id);
335         break;
336     }
337 
338     default:
339         break;
340     }
341 }
342 
ResetDiplomacy()343 void EmpireManager::ResetDiplomacy() {
344     // remove messages
345     m_diplomatic_messages.clear();
346 
347     // set all empires at war with each other (but not themselves)
348     m_empire_diplomatic_statuses.clear();
349     for (auto id_empire_1 : m_empire_map) {
350         for (auto id_empire_2 : m_empire_map) {
351             if (id_empire_1.first == id_empire_2.first)
352                 continue;
353             const std::pair<int, int> diplo_key = DiploKey(id_empire_1.first, id_empire_2.first);
354             m_empire_diplomatic_statuses[diplo_key] = DIPLO_WAR;
355         }
356     }
357 }
358 
GetDiplomaticMessagesToSerialize(std::map<std::pair<int,int>,DiplomaticMessage> & messages,int encoding_empire) const359 void EmpireManager::GetDiplomaticMessagesToSerialize(std::map<std::pair<int, int>, DiplomaticMessage>& messages,
360                                                      int encoding_empire) const
361 {
362     messages.clear();
363 
364     // return all messages for general case
365     if (encoding_empire == ALL_EMPIRES) {
366         messages = m_diplomatic_messages;
367         return;
368     }
369 
370     // find all messages involving encoding empire
371     for (const auto& entry : m_diplomatic_messages) {
372         if (entry.first.first == encoding_empire || entry.first.second == encoding_empire)
373             messages.insert(entry);
374     }
375 }
376 
EmpireColorsNonConst()377 std::vector<GG::Clr>& EmpireColorsNonConst() {
378     static std::vector<GG::Clr> colors;
379     return colors;
380 }
381 
InitEmpireColors(const boost::filesystem::path & path)382 void InitEmpireColors(const boost::filesystem::path& path) {
383     auto& colors = EmpireColorsNonConst();
384 
385     XMLDoc doc;
386 
387     boost::filesystem::ifstream ifs(path);
388     if (ifs) {
389         doc.ReadDoc(ifs);
390         ifs.close();
391     } else {
392         ErrorLogger() << "Unable to open data file " << path.filename();
393         return;
394     }
395 
396     for (const XMLElement& elem : doc.root_node.children) {
397         try {
398             std::string hex_colour("#");
399             hex_colour.append(elem.attributes.at("hex"));
400             colors.push_back(GG::HexClr(hex_colour));
401         } catch(const std::exception& e) {
402             ErrorLogger() << "empire_colors.xml: " << e.what() << std::endl;
403         }
404     }
405 }
EmpireColors()406 const std::vector<GG::Clr>& EmpireColors() {
407     auto& colors = EmpireColorsNonConst();
408     if (colors.empty()) {
409         colors = {  GG::Clr(  0, 255,   0, 255),    GG::Clr(  0,   0, 255, 255),    GG::Clr(255,   0,   0, 255),
410                     GG::Clr(  0, 255, 255, 255),    GG::Clr(255, 255,   0, 255),    GG::Clr(255,   0, 255, 255)};
411     }
412     return colors;
413 }
414