1 #include "ResourcePool.h"
2 
3 #include <boost/lexical_cast.hpp>
4 
5 #include "../universe/ObjectMap.h"
6 #include "../universe/Planet.h"
7 #include "../universe/Enums.h"
8 #include "../util/AppInterface.h"
9 #include "../util/Logger.h"
10 
11 //////////////////////////////////////////////////
12 // ResourcePool
13 //////////////////////////////////////////////////
ResourcePool()14 ResourcePool::ResourcePool() :
15     m_type(INVALID_RESOURCE_TYPE)
16 {}
17 
ResourcePool(ResourceType type)18 ResourcePool::ResourcePool(ResourceType type) :
19     m_type(type)
20 {}
21 
ObjectIDs() const22 const std::vector<int>& ResourcePool::ObjectIDs() const
23 { return m_object_ids; }
24 
Stockpile() const25 float ResourcePool::Stockpile() const
26 { return m_stockpile; }
27 
TotalOutput() const28 float ResourcePool::TotalOutput() const {
29     float retval = 0.0f;
30     for (const auto& entry : m_connected_object_groups_resource_output)
31     { retval += entry.second; }
32     return retval;
33 }
34 
Output() const35 std::map<std::set<int>, float> ResourcePool::Output() const { return m_connected_object_groups_resource_output; }
36 
GroupOutput(int object_id) const37 float ResourcePool::GroupOutput(int object_id) const {
38     // find group containing specified object
39     for (const auto& entry : m_connected_object_groups_resource_output) {
40         if (entry.first.count(object_id))
41             return entry.second;
42     }
43 
44     // default return case:
45     //DebugLogger() << "ResourcePool::GroupOutput passed unknown object id: " << object_id;
46     return 0.0f;
47 }
48 
49 
TargetOutput() const50 float ResourcePool::TargetOutput() const {
51     float retval = 0.0f;
52     for (const auto& entry : m_connected_object_groups_resource_target_output)
53     { retval += entry.second; }
54     return retval;
55 }
56 
GroupTargetOutput(int object_id) const57 float ResourcePool::GroupTargetOutput(int object_id) const {
58     // find group containing specified object
59     for (const auto& entry : m_connected_object_groups_resource_target_output) {
60         if (entry.first.count(object_id))
61             return entry.second;
62     }
63 
64     // default return case:
65     DebugLogger() << "ResourcePool::GroupTargetOutput passed unknown object id: " << object_id;
66     return 0.0f;
67 }
68 
TotalAvailable() const69 float ResourcePool::TotalAvailable() const {
70     float retval = m_stockpile;
71     for (const auto& entry : m_connected_object_groups_resource_output)
72     { retval += entry.second; }
73     return retval;
74 }
75 
Available() const76 std::map<std::set<int>, float> ResourcePool::Available() const {
77     auto retval = m_connected_object_groups_resource_output;
78     return retval;
79 }
80 
GroupAvailable(int object_id) const81 float ResourcePool::GroupAvailable(int object_id) const {
82     TraceLogger() << "ResourcePool::GroupAvailable(" << object_id << ")";
83     // available is production in this group
84     return GroupOutput(object_id);
85 }
86 
Dump() const87 std::string ResourcePool::Dump() const {
88     std::string retval = "ResourcePool type = " + boost::lexical_cast<std::string>(m_type) +
89                          " stockpile = " + std::to_string(m_stockpile) +
90                          " object_ids: ";
91     for (int obj_id : m_object_ids)
92         retval += std::to_string(obj_id) + ", ";
93     return retval;
94 }
95 
SetObjects(const std::vector<int> & object_ids)96 void ResourcePool::SetObjects(const std::vector<int>& object_ids)
97 { m_object_ids = object_ids; }
98 
SetConnectedSupplyGroups(const std::set<std::set<int>> & connected_system_groups)99 void ResourcePool::SetConnectedSupplyGroups(const std::set<std::set<int>>& connected_system_groups)
100 { m_connected_system_groups = connected_system_groups; }
101 
SetStockpile(float d)102 void ResourcePool::SetStockpile(float d)
103 { m_stockpile = d; }
104 
Update()105 void ResourcePool::Update() {
106     //DebugLogger() << "ResourcePool::Update for type " << m_type;
107     // sum production from all ResourceCenters in each group, for resource point type appropriate for this pool
108     MeterType meter_type = ResourceToMeter(m_type);
109     MeterType target_meter_type = ResourceToTargetMeter(m_type);
110 
111     if (INVALID_METER_TYPE == meter_type || INVALID_METER_TYPE == target_meter_type)
112         ErrorLogger() << "ResourcePool::Update() called when m_type can't be converted to a valid MeterType";
113 
114     // zero to start...
115     m_connected_object_groups_resource_output.clear();
116     m_connected_object_groups_resource_target_output.clear();
117 
118     // temporary storage: indexed by group of systems, which objects
119     // are located in that system group?
120     std::map<std::set<int>, std::set<std::shared_ptr<const UniverseObject>>>
121         system_groups_to_object_groups;
122 
123 
124     // for every object, find if a connected system group contains the object's
125     // system.  If a group does, place the object into that system group's set
126     // of objects.  If no group contains the object, place the object in its own
127     // single-object group.
128     for (auto& obj : Objects().find<const UniverseObject>(m_object_ids)) {
129         int object_id = obj->ID();
130         int object_system_id = obj->SystemID();
131         // can't generate resources when not in a system
132         if (object_system_id == INVALID_OBJECT_ID)
133             continue;
134 
135         // is object's system in a system group?
136         std::set<int> object_system_group;
137         for (const auto& sys_group : m_connected_system_groups) {
138             if (sys_group.count(object_system_id)) {
139                 object_system_group = sys_group;
140                 break;
141             }
142         }
143 
144         // if object's system is not in a system group, add it as its
145         // own entry in m_connected_object_groups_resource_output and m_connected_object_groups_resource_target_output
146         // this will allow the object to use its own locally produced
147         // resource when, for instance, distributing pp
148         if (object_system_group.empty()) {
149             object_system_group.insert(object_id);  // just use this already-available set to store the object id, even though it is not likely actually a system
150 
151             const auto* mmt = obj->GetMeter(meter_type);
152             m_connected_object_groups_resource_output[object_system_group] = mmt ? mmt->Current() : 0.0f;
153 
154             const auto* mtmt = obj->GetMeter(target_meter_type);
155             m_connected_object_groups_resource_target_output[object_system_group] = mtmt ? mtmt->Current() : 0.0f;
156 
157             continue;
158         }
159 
160         // if resource center's system is in a system group, record which system
161         // group that is for later
162         system_groups_to_object_groups[object_system_group].insert(obj);
163     }
164 
165     // sum the resource production for object groups, and store the total
166     // group production, indexed by group of object ids
167     for (auto& entry : system_groups_to_object_groups) {
168         const auto& object_group = entry.second;
169         std::set<int> object_group_ids;
170         float total_group_output = 0.0f;
171         float total_group_target_output = 0.0f;
172         for (auto& obj : object_group) {
173             if (const auto* m = obj->GetMeter(meter_type))
174                 total_group_output += m->Current();
175             if (const auto* m = obj->GetMeter(target_meter_type))
176                 total_group_target_output += m->Current();
177             object_group_ids.insert(obj->ID());
178         }
179         m_connected_object_groups_resource_output[object_group_ids] = total_group_output;
180         m_connected_object_groups_resource_target_output[object_group_ids] = total_group_target_output;
181     }
182 
183     ChangedSignal();
184 }
185