Merge lp:~widelands-dev/widelands/request_supply_opt into lp:widelands
- request_supply_opt
- Merge into trunk
Status: | Merged |
---|---|
Merged at revision: | 7695 |
Proposed branch: | lp:~widelands-dev/widelands/request_supply_opt |
Merge into: | lp:widelands |
Diff against target: |
314 lines (+123/-18) 8 files modified
src/economy/economy.cc (+76/-18) src/economy/economy.h (+20/-0) src/economy/idleworkersupply.cc (+5/-0) src/economy/idleworkersupply.h (+1/-0) src/economy/supply.h (+8/-0) src/economy/ware_instance.cc (+11/-0) src/economy/warehousesupply.h (+1/-0) src/logic/warehouse.cc (+1/-0) |
To merge this branch: | bzr merge lp:~widelands-dev/widelands/request_supply_opt |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
SirVer | Approve | ||
Tino | Approve | ||
Review via email: mp+280193@code.launchpad.net |
Commit message
Description of the change
This is small redesign of delivery of wares to requestors.
1. Engine now evenly distributes wares to all warehouses that are preferred for this type of ware (in other words, ware goes to a warehouse with lower stock of the material/worker)
2. Engine now test supplies in order starting from nearest one. This itself should lead to lesser computation. Additionaly I implemented a treshold (now 5) that test only 5 nearest supplies. The goal is to reduce CPU usage, especially on big maps. Routing is very expensive on long maps.
This was discussed on forum and must be yet considered.
GunChleoc (gunchleoc) wrote : | # |
TiborB (tiborb95) wrote : | # |
Resubmit.
I removed controversial treshold, and added two features
a) if more wares (of the same type) on one flag, only one ware is considered
b) wares on ships are ignored. Routing is deceived because it considers port's flag as a actual location of ware/worker.
bunnybot (widelandsofficial) wrote : | # |
Hi, I am bunnybot (https:/
I am keeping the source branch lp:~widelands-dev/widelands/request_supply_opt mirrored to
https:/
The latest continuous integration build can always be found here:
https:/
Please do not merge without making sure that it passes.
You can give me commands by starting a line with @bunnybot <command>. I understand:
merge: Merges the source branch into the target branch, closing the pull request.
bunnybot (widelandsofficial) wrote : | # |
Travis build 119 has changed state to: failed. Details: https:/
bunnybot (widelandsofficial) wrote : | # |
Travis build 162 has changed state to: created. Details: https:/
bunnybot (widelandsofficial) wrote : | # |
Travis build 162 has changed state to: started. Details: https:/
bunnybot (widelandsofficial) wrote : | # |
Travis build 162 has changed state to: errored. Details: https:/
Tino (tino79) wrote : | # |
LGTM.
I cannot really quantify the performance gain, but i did not find any regression.
bunnybot (widelandsofficial) wrote : | # |
Travis build 162 has changed state to: errored. Details: https:/
SirVer (sirver) wrote : | # |
I think this is broken in the current state. The problem is that logic depends on available_supply which is a multimap. The problem is that the map is sorted by distance, then by a pointer.
In a replay or in a multiplayer games, the order of elements in this map is different, yielding therefore different routing results. This will desync the game.
Change the ordering to use a tie-breaker, for example the game object id before the pointer.
bunnybot (widelandsofficial) wrote : | # |
Travis build 162 has changed state to: passed. Details: https:/
TiborB (tiborb95) wrote : | # |
@SirVer
What about:
std::multimap<
Where <uint32_t,int32_t> is <distance, serial>, serial should be the same across the network clients, I presume...
SirVer (sirver) wrote : | # |
That should work - but I would suggest to make a tiny private struct to improve readability.
struct SupplyQuality {
uint32 distance;
uint32 serial;
bool operator<(const SupplyQuality& other) const {
return std::forward_
}
}
TiborB (tiborb95) wrote : | # |
Well I am not that skillful in C++, I want(ed) to use trivial:
bool operator() (const uint32_t & p1, const uint32_t & p2) const {
return p1.distance == p2.distance ? p1.serial < p2.serial : p1.distance < p2.distance;
}
(not tested of course)
TiborB (tiborb95) wrote : | # |
Oh, I just read about comparison of tuples, so I understand your example now, thanks..
TiborB (tiborb95) wrote : | # |
@SirVer
I reworked it and testing it. I am not satisfied with performance though. Perhaps you know that I proposed a treshold (f.e. 5) that would check only 5 nearest (as crow fly) wares and pick a one from them. This could improve performance, but was rejected and currently is not in the code.
However I have another suggestion - let revive the treshold and X nearest wares are checked all, and from other wares only the ones that are in the warehouses. It used to be this way before AFAIK. I mean only wares in warehouses were used for delivery.
I currently test 512x512 map and after 5 hours it can barely run at 2x speed. I dont say that the routing is culprit but I believe it has its share...
I have not pushed new code yet.
SirVer (sirver) wrote : | # |
[threshold]
I did not follow the discussion about the threshold though, on a quick thought I can see downsides to this approach. I suggest doing more timing analysis (with AI disabled) to figure out what actually takes time here and if there are ways of improving the situation.
> I dont say that the routing is culprit but I believe it has its share...
you have to proof that to make me believe it :). In my benchmarks about timing with the drawing code, AI is always dwarfing everything else in profiles, especially in longer games - but I rarely look at very large maps, so I'd need to proof what actually takes the most time too.
If you feel this approach is an improvement, how about we merge it soonish and then go back and try timing a large map with AI disabled to see what actually eats cycles.
TiborB (tiborb95) wrote : | # |
So I made a bit of profiling, first of all it seems the game (drawing itself) takes quite a lot of CPU time - perhaps problem on my side? Tests run for 3 minutes of gameplay, but loading took also quite a bit of time (not counted in 3 minutes)....
But results:
I compared
1. trunk + crater (small map after 45 min)
2. trunk + Cristobals sea (512x512 after 4 hours)
3. request_supply_opt + Cristobals sea (512x512 after 4 hours)
I used savegames...
I picked only 3 functions here, look at second column (cummulative %)
trunk+crater:
[79] 1.8 0.00 0.17 4530 DefaultAI::think() [79]
[90] 1.6 0.00 0.14 37761 Widelands:
[94] 1.6 0.00 0.14 5494 Widelands:
trunk + big map (Cristobals sea)
[16] 22.8 0.00 8.43 105284 Widelands:
[24] 17.5 0.26 6.20 1145776 Widelands:
[65] 3.8 0.02 1.38 22120 DefaultAI::think()
this branch + big map (Cristobals sea)
[20] 15.7 0.00 5.76 112254 Widelands:
[24] 14.8 0.39 5.06 1302844 Widelands:
[61] 4.3 0.00 1.59 33740 DefaultAI::think() [61]
My conclusions:
On big maps, _find_best_supply takes significant portion of CPU time, many fold then AI.
My changes as they are now, brings reduction about 20% of _find_best_supply and about 35% of find_route() + on big maps.
I believe implementing a treshold would help to further reduction.....
SirVer (sirver) wrote : | # |
> So I made a bit of profiling, first of all it seems the game (drawing itself) takes quite a lot of CPU time - perhaps problem on my side?
No, that is accurate. The render_queue branch makes this already better, but only a full texture_atlas will make this really fast. I picked up working on this today again.
The threshold will at most cut the time in half for find_best_supply if i understood correctly. How much will that actually buy us? I suggest getting the change in as is without the threshold - as it should be correct in all cases and then experiment on threshold or even completely different approaches. Let us know if you think it is ready for another look.
TiborB (tiborb95) wrote : | # |
> The threshold will at most cut the time in half for find_best_supply if i understood correctly.
I dont think there is mathematical reason for 'half' but if it was half it would be great....
It depends on number of supplies - if supplies count<=treshold - no change at all. Or rather - savings depend on the size of player's teritorry/
I did some changes today so you can look at the code again now
SirVer (sirver) wrote : | # |
code lgtm now. A couple of minor nits, feel free to merge after addressing these.
TiborB (tiborb95) wrote : | # |
Added a comment to your comment, see in diff
TiborB (tiborb95) wrote : | # |
@SirVer
I incorporated your comments, with one exception, can I merge it?
SirVer (sirver) wrote : | # |
Tibor, sure, go ahead and merge.
> I looked at other examples f.e. here: http://
Ah, that is a philosophical question, really. Does local style trump global style? Should better paradigms be adapted peu-a-peu or in one big refactoring? There are many school of thoughts here. I think once you identified a better approach, you should start using it for new code and fix old code over time. Other people think that you should keep the old ways until you can change a full code base to new ways.
So there are really two questions for you here:
1) do you agree that passing mutable values by pointer is better than passing them by non-const reference? I find foo(&game) vs foo(game) a clear advantage for readability, so I'd say yes. This also follows the google style guide which I find a great reference of how and why to do things anyways. But you might disagree and I am in no position to enforce a 'true' widelands code style.
2) do you agree that new code should adopt new paradigms immediately at the cost of inconsistency in the code base or not?
As said, I answer yes to both questions, so I'd change the code to using a pointer. But it is entirely your call. I will not think any worse of you if you decide against changing the code :)
> Also note the 'const' at the end of line, does it not guarantee immutability of Game?
no, the const at the end of the line means that the object represented by 'this' cannot change, but does not say anything about the arguments of the method - they can change.
TiborB (tiborb95) wrote : | # |
You are right, I will rework it, though I am not that good programmer so it is not as simple for me as for you. This is only reason why I opted to mimic the existing code.
But as there is no need to hurry with this branch so it can wait a bit again
GunChleoc (gunchleoc) wrote : | # |
Changing a reference to a pointer can be a bit of a pain, but it isn't complex - the compiler will tell you if anything goes wrong, so you can't mess it up. What you need to do is change foo.bar to foo->bar within the function, and add & or * in front of foo when calling the function - I can never remember which symbol to use here, but the compiler will tell me :)
TiborB (tiborb95) wrote : | # |
reworked, tested (not long time). Can you please look at it once more?
SirVer (sirver) wrote : | # |
there are still NOCOM in the diff which need removing, otherwise lgtm.
TiborB (tiborb95) wrote : | # |
Thanks!
@bunnybot merge
Preview Diff
1 | === modified file 'src/economy/economy.cc' | |||
2 | --- src/economy/economy.cc 2015-11-11 09:52:55 +0000 | |||
3 | +++ src/economy/economy.cc 2016-01-07 18:40:19 +0000 | |||
4 | @@ -20,6 +20,7 @@ | |||
5 | 20 | #include "economy/economy.h" | 20 | #include "economy/economy.h" |
6 | 21 | 21 | ||
7 | 22 | #include <memory> | 22 | #include <memory> |
8 | 23 | #include <unordered_set> | ||
9 | 23 | 24 | ||
10 | 24 | #include <boost/bind.hpp> | 25 | #include <boost/bind.hpp> |
11 | 25 | 26 | ||
12 | @@ -664,14 +665,40 @@ | |||
13 | 664 | Route * best_route = nullptr; | 665 | Route * best_route = nullptr; |
14 | 665 | int32_t best_cost = -1; | 666 | int32_t best_cost = -1; |
15 | 666 | Flag & target_flag = req.target_flag(); | 667 | Flag & target_flag = req.target_flag(); |
16 | 668 | Map & map = game.map(); | ||
17 | 669 | |||
18 | 670 | available_supplies.clear(); | ||
19 | 667 | 671 | ||
20 | 668 | for (size_t i = 0; i < m_supplies.get_nrsupplies(); ++i) { | 672 | for (size_t i = 0; i < m_supplies.get_nrsupplies(); ++i) { |
21 | 669 | Supply & supp = m_supplies[i]; | 673 | Supply & supp = m_supplies[i]; |
22 | 670 | 674 | ||
24 | 671 | // Check requirements | 675 | // Just skip if supply does not provide required ware |
25 | 672 | if (!supp.nr_supplies(game, req)) | 676 | if (!supp.nr_supplies(game, req)) |
26 | 673 | continue; | 677 | continue; |
27 | 674 | 678 | ||
28 | 679 | const SupplyProviders provider = supp.provider_type(&game); | ||
29 | 680 | |||
30 | 681 | // We generally ignore disponible wares on ship as it is not possible to reliably | ||
31 | 682 | // calculate route (transportation time) | ||
32 | 683 | if (provider == SupplyProviders::kShip) { | ||
33 | 684 | continue; | ||
34 | 685 | } | ||
35 | 686 | |||
36 | 687 | const Widelands::Coords provider_position = supp.get_position(game)->base_flag().get_position(); | ||
37 | 688 | |||
38 | 689 | const uint32_t dist = map.calc_distance(target_flag.get_position(), provider_position); | ||
39 | 690 | |||
40 | 691 | UniqueDistance ud = {dist, supp.get_position(game)->serial(), provider}; | ||
41 | 692 | |||
42 | 693 | // std::map quarantees uniqueness, practically it means that if more wares are on the same flag, only | ||
43 | 694 | // first one will be inserted into available_supplies | ||
44 | 695 | available_supplies.insert(std::make_pair(ud, &m_supplies[i])); | ||
45 | 696 | } | ||
46 | 697 | |||
47 | 698 | // Now available supplies have been sorted by distance to requestor | ||
48 | 699 | for (auto& supplypair : available_supplies) { | ||
49 | 700 | Supply & supp = *supplypair.second; | ||
50 | 701 | |||
51 | 675 | Route * const route = | 702 | Route * const route = |
52 | 676 | best_route != &buf_route0 ? &buf_route0 : &buf_route1; | 703 | best_route != &buf_route0 ? &buf_route0 : &buf_route1; |
53 | 677 | // will be cleared by find_route() | 704 | // will be cleared by find_route() |
54 | @@ -685,11 +712,17 @@ | |||
55 | 685 | req.get_type(), | 712 | req.get_type(), |
56 | 686 | best_cost)) | 713 | best_cost)) |
57 | 687 | { | 714 | { |
60 | 688 | if (!best_route) | 715 | if (!best_route) { |
61 | 689 | log ("Economy::find_best_supply: Error, COULD NOT FIND A ROUTE!"); | 716 | log ("Economy::find_best_supply: Error, COULD NOT FIND A ROUTE!"); |
62 | 717 | // To help to debug this a bit: | ||
63 | 718 | log (" ... ware at: %3dx%3d, requestor at: %3dx%3d!", | ||
64 | 719 | supp.get_position(game)->base_flag().get_position().x, | ||
65 | 720 | supp.get_position(game)->base_flag().get_position().y, | ||
66 | 721 | target_flag.get_position().x, | ||
67 | 722 | target_flag.get_position().y); | ||
68 | 723 | } | ||
69 | 690 | continue; | 724 | continue; |
70 | 691 | } | 725 | } |
71 | 692 | |||
72 | 693 | best_supply = &supp; | 726 | best_supply = &supp; |
73 | 694 | best_route = route; | 727 | best_route = route; |
74 | 695 | best_cost = route->get_totalcost(); | 728 | best_cost = route->get_totalcost(); |
75 | @@ -776,8 +809,9 @@ | |||
76 | 776 | } | 809 | } |
77 | 777 | 810 | ||
78 | 778 | int32_t const priority = req.get_priority(cost); | 811 | int32_t const priority = req.get_priority(cost); |
80 | 779 | if (priority < 0) | 812 | if (priority < 0) { |
81 | 780 | continue; | 813 | continue; |
82 | 814 | } | ||
83 | 781 | 815 | ||
84 | 782 | // Otherwise, consider this request/supply pair for queueing | 816 | // Otherwise, consider this request/supply pair for queueing |
85 | 783 | RequestSupplyPair rsp; | 817 | RequestSupplyPair rsp; |
86 | @@ -825,8 +859,9 @@ | |||
87 | 825 | rsps.nexttimer = 200; | 859 | rsps.nexttimer = 200; |
88 | 826 | } | 860 | } |
89 | 827 | 861 | ||
91 | 828 | if (rsps.nexttimer > 0) // restart the timer, if necessary | 862 | if (rsps.nexttimer > 0) { // restart the timer, if necessary |
92 | 829 | _start_request_timer(rsps.nexttimer); | 863 | _start_request_timer(rsps.nexttimer); |
93 | 864 | } | ||
94 | 830 | } | 865 | } |
95 | 831 | 866 | ||
96 | 832 | 867 | ||
97 | @@ -1037,12 +1072,30 @@ | |||
98 | 1037 | 1072 | ||
99 | 1038 | bool haveprefer = false; | 1073 | bool haveprefer = false; |
100 | 1039 | bool havenormal = false; | 1074 | bool havenormal = false; |
101 | 1075 | |||
102 | 1076 | // One of preferred warehouses (if any) with lowest stock of ware/worker | ||
103 | 1077 | Warehouse * preferred_wh = nullptr; | ||
104 | 1078 | // Stock of particular ware in preferred warehouse | ||
105 | 1079 | uint32_t preferred_wh_stock = std::numeric_limits<uint32_t>::max(); | ||
106 | 1080 | |||
107 | 1040 | for (uint32_t nwh = 0; nwh < m_warehouses.size(); ++nwh) { | 1081 | for (uint32_t nwh = 0; nwh < m_warehouses.size(); ++nwh) { |
108 | 1041 | Warehouse * wh = m_warehouses[nwh]; | 1082 | Warehouse * wh = m_warehouses[nwh]; |
109 | 1042 | Warehouse::StockPolicy policy = wh->get_stock_policy(type, ware); | 1083 | Warehouse::StockPolicy policy = wh->get_stock_policy(type, ware); |
110 | 1043 | if (policy == Warehouse::SP_Prefer) { | 1084 | if (policy == Warehouse::SP_Prefer) { |
111 | 1044 | haveprefer = true; | 1085 | haveprefer = true; |
113 | 1045 | break; | 1086 | |
114 | 1087 | // Getting count of worker/ware | ||
115 | 1088 | uint32_t current_stock; | ||
116 | 1089 | if (type == WareWorker::wwWARE) { | ||
117 | 1090 | current_stock = wh->get_wares().stock(ware); | ||
118 | 1091 | } else { | ||
119 | 1092 | current_stock = wh->get_workers().stock(ware); | ||
120 | 1093 | } | ||
121 | 1094 | // Stocks lower then in previous one? | ||
122 | 1095 | if (current_stock < preferred_wh_stock) { | ||
123 | 1096 | preferred_wh = wh; | ||
124 | 1097 | preferred_wh_stock = current_stock; | ||
125 | 1098 | } | ||
126 | 1046 | } | 1099 | } |
127 | 1047 | if (policy == Warehouse::SP_Normal) | 1100 | if (policy == Warehouse::SP_Normal) |
128 | 1048 | havenormal = true; | 1101 | havenormal = true; |
129 | @@ -1050,17 +1103,22 @@ | |||
130 | 1050 | if (!havenormal && !haveprefer && type == wwWARE) | 1103 | if (!havenormal && !haveprefer && type == wwWARE) |
131 | 1051 | continue; | 1104 | continue; |
132 | 1052 | 1105 | ||
144 | 1053 | Warehouse * wh = find_closest_warehouse | 1106 | // We either have one preferred warehouse picked up or walk on roads to find nearest one |
145 | 1054 | (supply.get_position(game)->base_flag(), type, nullptr, 0, | 1107 | Warehouse * wh = nullptr; |
146 | 1055 | (!haveprefer && !havenormal) | 1108 | if (preferred_wh) { |
147 | 1056 | ? | 1109 | wh = preferred_wh; |
148 | 1057 | WarehouseAcceptFn() | 1110 | } else { |
149 | 1058 | : | 1111 | wh = find_closest_warehouse |
150 | 1059 | boost::bind | 1112 | (supply.get_position(game)->base_flag(), type, nullptr, 0, |
151 | 1060 | (&accept_warehouse_if_policy, | 1113 | (!havenormal) |
152 | 1061 | _1, type, ware, | 1114 | ? |
153 | 1062 | haveprefer ? Warehouse::SP_Prefer : Warehouse::SP_Normal)); | 1115 | WarehouseAcceptFn() |
154 | 1063 | 1116 | : | |
155 | 1117 | boost::bind | ||
156 | 1118 | (&accept_warehouse_if_policy, | ||
157 | 1119 | _1, type, ware, | ||
158 | 1120 | Warehouse::SP_Normal)); | ||
159 | 1121 | } | ||
160 | 1064 | if (!wh) { | 1122 | if (!wh) { |
161 | 1065 | log | 1123 | log |
162 | 1066 | ("Warning: Economy::_handle_active_supplies " | 1124 | ("Warning: Economy::_handle_active_supplies " |
163 | 1067 | 1125 | ||
164 | === modified file 'src/economy/economy.h' | |||
165 | --- src/economy/economy.h 2015-11-11 09:52:55 +0000 | |||
166 | +++ src/economy/economy.h 2016-01-07 18:40:19 +0000 | |||
167 | @@ -31,6 +31,7 @@ | |||
168 | 31 | #include "logic/instances.h" | 31 | #include "logic/instances.h" |
169 | 32 | #include "logic/warelist.h" | 32 | #include "logic/warelist.h" |
170 | 33 | #include "logic/wareworker.h" | 33 | #include "logic/wareworker.h" |
171 | 34 | #include "economy/supply.h" | ||
172 | 34 | #include "economy/supply_list.h" | 35 | #include "economy/supply_list.h" |
173 | 35 | #include "ui_basic/unique_window.h" | 36 | #include "ui_basic/unique_window.h" |
174 | 36 | 37 | ||
175 | @@ -184,6 +185,22 @@ | |||
176 | 184 | void rebalance_supply() {_start_request_timer();} | 185 | void rebalance_supply() {_start_request_timer();} |
177 | 185 | 186 | ||
178 | 186 | private: | 187 | private: |
179 | 188 | |||
180 | 189 | // This structs is to store distance from supply to request(or), but to allow unambiguous | ||
181 | 190 | // sorting if distances are the same, we use also serial number of provider and type of provider (flag, | ||
182 | 191 | // warehouse) | ||
183 | 192 | struct UniqueDistance { | ||
184 | 193 | bool operator<(const UniqueDistance& other) const { | ||
185 | 194 | return std::forward_as_tuple(distance, serial, provider_type) | ||
186 | 195 | < | ||
187 | 196 | std::forward_as_tuple(other.distance, other.serial, other.provider_type); | ||
188 | 197 | } | ||
189 | 198 | |||
190 | 199 | uint32_t distance; | ||
191 | 200 | uint32_t serial; | ||
192 | 201 | SupplyProviders provider_type; | ||
193 | 202 | }; | ||
194 | 203 | |||
195 | 187 | /*************/ | 204 | /*************/ |
196 | 188 | /* Functions */ | 205 | /* Functions */ |
197 | 189 | /*************/ | 206 | /*************/ |
198 | @@ -237,6 +254,9 @@ | |||
199 | 237 | static std::unique_ptr<Soldier> m_soldier_prototype; | 254 | static std::unique_ptr<Soldier> m_soldier_prototype; |
200 | 238 | UI::UniqueWindow::Registry m_optionswindow_registry; | 255 | UI::UniqueWindow::Registry m_optionswindow_registry; |
201 | 239 | 256 | ||
202 | 257 | // 'list' of unique providers | ||
203 | 258 | std::map<UniqueDistance, Supply*> available_supplies; | ||
204 | 259 | |||
205 | 240 | DISALLOW_COPY_AND_ASSIGN(Economy); | 260 | DISALLOW_COPY_AND_ASSIGN(Economy); |
206 | 241 | }; | 261 | }; |
207 | 242 | 262 | ||
208 | 243 | 263 | ||
209 | === modified file 'src/economy/idleworkersupply.cc' | |||
210 | --- src/economy/idleworkersupply.cc 2015-11-11 09:52:55 +0000 | |||
211 | +++ src/economy/idleworkersupply.cc 2016-01-07 18:40:19 +0000 | |||
212 | @@ -71,6 +71,11 @@ | |||
213 | 71 | return true; | 71 | return true; |
214 | 72 | } | 72 | } |
215 | 73 | 73 | ||
216 | 74 | SupplyProviders IdleWorkerSupply::provider_type(Game *) const | ||
217 | 75 | { | ||
218 | 76 | return SupplyProviders::kFlagOrRoad; | ||
219 | 77 | } | ||
220 | 78 | |||
221 | 74 | bool IdleWorkerSupply::has_storage() const | 79 | bool IdleWorkerSupply::has_storage() const |
222 | 75 | { | 80 | { |
223 | 76 | return m_worker.get_transfer(); | 81 | return m_worker.get_transfer(); |
224 | 77 | 82 | ||
225 | === modified file 'src/economy/idleworkersupply.h' | |||
226 | --- src/economy/idleworkersupply.h 2015-11-11 09:52:55 +0000 | |||
227 | +++ src/economy/idleworkersupply.h 2016-01-07 18:40:19 +0000 | |||
228 | @@ -34,6 +34,7 @@ | |||
229 | 34 | PlayerImmovable * get_position(Game &) override; | 34 | PlayerImmovable * get_position(Game &) override; |
230 | 35 | 35 | ||
231 | 36 | bool is_active() const override; | 36 | bool is_active() const override; |
232 | 37 | SupplyProviders provider_type(Game *) const override; | ||
233 | 37 | bool has_storage() const override; | 38 | bool has_storage() const override; |
234 | 38 | void get_ware_type(WareWorker & type, DescriptionIndex & ware) const override; | 39 | void get_ware_type(WareWorker & type, DescriptionIndex & ware) const override; |
235 | 39 | void send_to_storage(Game &, Warehouse * wh) override; | 40 | void send_to_storage(Game &, Warehouse * wh) override; |
236 | 40 | 41 | ||
237 | === modified file 'src/economy/supply.h' | |||
238 | --- src/economy/supply.h 2015-11-11 09:52:55 +0000 | |||
239 | +++ src/economy/supply.h 2016-01-07 18:40:19 +0000 | |||
240 | @@ -33,6 +33,8 @@ | |||
241 | 33 | class WareInstance; | 33 | class WareInstance; |
242 | 34 | class Worker; | 34 | class Worker; |
243 | 35 | 35 | ||
244 | 36 | enum class SupplyProviders {kWarehouse, kFlagOrRoad, kShip}; | ||
245 | 37 | |||
246 | 36 | /** | 38 | /** |
247 | 37 | * A Supply is a virtual base class representing something that can offer | 39 | * A Supply is a virtual base class representing something that can offer |
248 | 38 | * wares of any type for any purpose. | 40 | * wares of any type for any purpose. |
249 | @@ -57,6 +59,12 @@ | |||
250 | 57 | virtual bool is_active() const = 0; | 59 | virtual bool is_active() const = 0; |
251 | 58 | 60 | ||
252 | 59 | /** | 61 | /** |
253 | 62 | * Return the type of player im/movable where the ware is now (warehouse, | ||
254 | 63 | * flag or ship). | ||
255 | 64 | */ | ||
256 | 65 | virtual SupplyProviders provider_type(Game *) const = 0; | ||
257 | 66 | |||
258 | 67 | /** | ||
259 | 60 | * Indicates whether this supply is in storage or on its way to | 68 | * Indicates whether this supply is in storage or on its way to |
260 | 61 | * storage. | 69 | * storage. |
261 | 62 | * | 70 | * |
262 | 63 | 71 | ||
263 | === modified file 'src/economy/ware_instance.cc' | |||
264 | --- src/economy/ware_instance.cc 2015-12-28 10:08:39 +0000 | |||
265 | +++ src/economy/ware_instance.cc 2016-01-07 18:40:19 +0000 | |||
266 | @@ -55,6 +55,7 @@ | |||
267 | 55 | // implementation of Supply | 55 | // implementation of Supply |
268 | 56 | PlayerImmovable * get_position(Game &) override; | 56 | PlayerImmovable * get_position(Game &) override; |
269 | 57 | bool is_active() const override; | 57 | bool is_active() const override; |
270 | 58 | SupplyProviders provider_type(Game *) const override; | ||
271 | 58 | bool has_storage() const override; | 59 | bool has_storage() const override; |
272 | 59 | void get_ware_type(WareWorker & type, DescriptionIndex & ware) const override; | 60 | void get_ware_type(WareWorker & type, DescriptionIndex & ware) const override; |
273 | 60 | void send_to_storage(Game &, Warehouse * wh) override; | 61 | void send_to_storage(Game &, Warehouse * wh) override; |
274 | @@ -126,6 +127,16 @@ | |||
275 | 126 | return true; | 127 | return true; |
276 | 127 | } | 128 | } |
277 | 128 | 129 | ||
278 | 130 | SupplyProviders IdleWareSupply::provider_type(Game* game) const | ||
279 | 131 | { | ||
280 | 132 | MapObject * const loc = m_ware.get_location(*game); | ||
281 | 133 | if (is_a(Ship, loc)) { | ||
282 | 134 | return SupplyProviders::kShip; | ||
283 | 135 | } | ||
284 | 136 | |||
285 | 137 | return SupplyProviders::kFlagOrRoad; | ||
286 | 138 | } | ||
287 | 139 | |||
288 | 129 | bool IdleWareSupply::has_storage() const | 140 | bool IdleWareSupply::has_storage() const |
289 | 130 | { | 141 | { |
290 | 131 | return m_ware.is_moving(); | 142 | return m_ware.is_moving(); |
291 | 132 | 143 | ||
292 | === modified file 'src/economy/warehousesupply.h' | |||
293 | --- src/economy/warehousesupply.h 2015-11-11 09:52:55 +0000 | |||
294 | +++ src/economy/warehousesupply.h 2016-01-07 18:40:19 +0000 | |||
295 | @@ -55,6 +55,7 @@ | |||
296 | 55 | // Supply implementation | 55 | // Supply implementation |
297 | 56 | PlayerImmovable * get_position(Game &) override; | 56 | PlayerImmovable * get_position(Game &) override; |
298 | 57 | bool is_active() const override; | 57 | bool is_active() const override; |
299 | 58 | SupplyProviders provider_type(Game *) const override; | ||
300 | 58 | bool has_storage() const override; | 59 | bool has_storage() const override; |
301 | 59 | void get_ware_type(WareWorker & type, DescriptionIndex & ware) const override; | 60 | void get_ware_type(WareWorker & type, DescriptionIndex & ware) const override; |
302 | 60 | 61 | ||
303 | 61 | 62 | ||
304 | === modified file 'src/logic/warehouse.cc' | |||
305 | --- src/logic/warehouse.cc 2015-11-21 11:34:10 +0000 | |||
306 | +++ src/logic/warehouse.cc 2016-01-07 18:40:19 +0000 | |||
307 | @@ -183,6 +183,7 @@ | |||
308 | 183 | 183 | ||
309 | 184 | /// Warehouse supplies are never active. | 184 | /// Warehouse supplies are never active. |
310 | 185 | bool WarehouseSupply::is_active() const {return false;} | 185 | bool WarehouseSupply::is_active() const {return false;} |
311 | 186 | SupplyProviders WarehouseSupply::provider_type(Game *) const {return SupplyProviders::kWarehouse;} | ||
312 | 186 | 187 | ||
313 | 187 | bool WarehouseSupply::has_storage() const | 188 | bool WarehouseSupply::has_storage() const |
314 | 188 | { | 189 | { |
Forum thread: https:/ /wl.widelands. org/forum/ topic/1856/
We still need to think about the threshold, but the rest of the code LGTM :)
This still needs testing, but I think we can wait with that until we have decided how to solve this.