1 #ifndef _IDAllocator_h_ 2 #define _IDAllocator_h_ 3 4 #include "../util/Logger.h" 5 #include <unordered_map> 6 #include <vector> 7 #include <random> 8 9 #include <boost/serialization/access.hpp> 10 11 /** The IDAllocator coordinates the allocation of new IDs between the server 12 and a number of empires, id consumers. 13 14 IDs are ints. The id consumers have disjoint id spaces. All consumers have 15 a common m_stride and a unique initial offset modulo m_stride. Each id 16 consumer only receives new ids from the set number of numbers x, where 17 (x % m_stride == consumer's initial offset). 18 19 The IDAllocator is associated with a single empire id. The constructor 20 creates the server association. Once serialized for another empire_id then 21 it is associated with that new (lesser) empire id, and will no longer have 22 the complete table. 23 24 TODO: Replace IDAllocator with using UUID as the id type ID_t instead of int. This does not 25 require coordination between clients and servers and does not leak any information to clients 26 about other client's allocations. 27 */ 28 29 class IDAllocator { 30 public: 31 using ID_t = int; 32 33 /** \p client_ids are all the player ids in the game. \p highest_pre_allocated_id is the used for 34 legacy loads to offset the newly allocated id to after the ones from the save game. 35 */ 36 IDAllocator(const int server_id, 37 const std::vector<int>& client_ids, 38 const ID_t invalid_id, 39 const ID_t temp_id, 40 const ID_t highest_pre_allocated_id); 41 42 /// Return a valid new id. This is used by both clients and servers. 43 ID_t NewID(); 44 45 /** Return {hard_success, soft_success} where \p hard_success determines if 46 \p id is unused and valid and \p soft_success determines if \p id is in 47 the id space of \p empire_id. This allows errors that are probably due 48 to legacy loading and order processing to be ignored for now. 49 */ 50 std::pair<bool, bool> IsIDValidAndUnused(const ID_t id, const int empire_id); 51 52 /** UpdateIDAndCheckIfOwned behaves differently on the server and clients. 53 54 On the server, it determines which client allocated \p id and updates 55 the next allocated id of that client. It then returns true. This means 56 that the server has a master list of the maximum id used by each client 57 and can use all ids as valid ids when executing orders. 58 59 On the client it returns true iff this client allocated \p id and does 60 nothing else. That means that id modulo m_stride == client's offset.*/ 61 bool UpdateIDAndCheckIfOwned(const ID_t id); 62 63 /** ObfuscateBeforeSerialization randomizes which client is using which modulus each turn 64 before IDAllocator is serialized and sent to the clients. */ 65 void ObfuscateBeforeSerialization(); 66 67 /** Serialize while stripping out information not known to \p empire_id. */ 68 template <typename Archive> 69 void SerializeForEmpire(Archive& ar, const unsigned int version, int empire_id); 70 71 private: 72 /** Return the empire that should have assigned \p id. */ 73 ID_t& AssigningEmpireForID(ID_t id); 74 75 /// Increment the next assigned id for an empire until it is past checked_id. 76 void IncrementNextAssignedId(const int assigning_empire, const int checked_id); 77 78 /// Return a string representing the state. 79 std::string StateString() const; 80 81 ID_t m_invalid_id; 82 ID_t m_temp_id; 83 84 /// m_stride is used to partition the id space into modulo m_stride sections. 85 ID_t m_stride; 86 /// The zero point or first allocated id. 87 ID_t m_zero; 88 89 // The server id and the empire id are equal on construction. Serialization 90 // and deserialization may downgrade empire id to one of the lesser (not 91 // server) ids. 92 int m_server_id; 93 int m_empire_id; 94 95 // A map from empire id to next used object id; 96 std::unordered_map<int, ID_t> m_empire_id_to_next_assigned_object_id; 97 98 // An index from id % m_stride to empire ids 99 std::vector<int> m_offset_to_empire_id; 100 101 /// if less than m_next_assigned_id warn about id exhaustion. 102 ID_t m_warn_threshold; 103 /// Stop assigning ids and start generating errors. 104 ID_t m_exhausted_threshold; 105 106 /// Random number generator 107 std::mt19937 m_random_generator; 108 }; 109 110 #endif // _IDAllocator_h_ 111