Merge lp:~widelands-dev/widelands/bug-1732765-economy-refactoring into lp:widelands

Proposed by GunChleoc
Status: Merged
Merged at revision: 8748
Proposed branch: lp:~widelands-dev/widelands/bug-1732765-economy-refactoring
Merge into: lp:widelands
Diff against target: 1502 lines (+314/-260)
26 files modified
src/ai/defaultai.cc (+1/-1)
src/ai/defaultai.h (+1/-1)
src/ai/defaultai_warfare.cc (+2/-2)
src/economy/economy.cc (+19/-18)
src/economy/economy.h (+13/-3)
src/economy/economy_data_packet.cc (+11/-1)
src/economy/economy_data_packet.h (+3/-0)
src/economy/flag.cc (+14/-8)
src/economy/flag.h (+6/-2)
src/game_io/game_player_economies_packet.cc (+30/-36)
src/io/filesystem/filesystem.cc (+6/-7)
src/logic/game.cc (+3/-4)
src/logic/map_objects/tribes/ship.cc (+30/-23)
src/logic/map_objects/tribes/ship.h (+4/-1)
src/logic/player.cc (+45/-35)
src/logic/player.h (+8/-14)
src/logic/playercommand.cc (+8/-8)
src/logic/playercommand.h (+2/-2)
src/logic/widelands.h (+1/-0)
src/map_io/map_flag_packet.cc (+14/-3)
src/scripting/lua_bases.cc (+4/-4)
src/scripting/lua_game.cc (+7/-9)
src/scripting/lua_map.cc (+4/-4)
src/wui/economy_options_window.cc (+57/-50)
src/wui/economy_options_window.h (+14/-9)
src/wui/stock_menu.cc (+7/-15)
To merge this branch: bzr merge lp:~widelands-dev/widelands/bug-1732765-economy-refactoring
Reviewer Review Type Date Requested Status
Klaus Halfmann Approve
Review via email: mp+345277@code.launchpad.net

Commit message

Economies are now mapped to global serials and kept as unique_ptr in the Player objects.

Description of the change

Big redesign of economy tracking, hoping that it will fix some bugs.

NOTE: This will break savegame compatibility, so we should take care to deal with all bugs that have interesting savegames attached before merging this. Implementing compatibility would be very complicated.

We used to have economy numbers per player, now we have 1 global serial number.

To post a comment you must log in.
Revision history for this message
TiborB (tiborb95) wrote :

Do you want it in Build 20?

Revision history for this message
GunChleoc (gunchleoc) wrote :

Oops, found a failing test

Revision history for this message
GunChleoc (gunchleoc) wrote :

Yes, I'd like to have it in Build 20 if possible, especially because it breaks savegame compatibility. It will make it easier to deal with future bugs, because we can expect to get sample savegames for Build 20 down the road.

Revision history for this message
bunnybot (widelandsofficial) wrote :

Continuous integration builds have changed state:

Travis build 3497. State: failed. Details: https://travis-ci.org/widelands/widelands/builds/378009513.
Appveyor build 3302. State: success. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_bug_1732765_economy_refactoring-3302.

Revision history for this message
bunnybot (widelandsofficial) wrote :

Continuous integration builds have changed state:

Travis build 3506. State: passed. Details: https://travis-ci.org/widelands/widelands/builds/378289393.
Appveyor build 3311. State: success. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_bug_1732765_economy_refactoring-3311.

Revision history for this message
Klaus Halfmann (klaus-halfmann) wrote :

Some comments:

* This depends or includes https://code.launchpad.net/~widelands-dev/widelands/bug-1690519-economy-unique_ptr ?

* As Serial is uint32_t so we have 2^32 different Economies, ok
* Please respond tho the inline comments, espcially using unordere_map should bet better.

This was a lot of change to digest, in general the code looks better this way.
Do we have a testcase with a lot of Economies to get an Idea of the Performance change?

I will now check the Attached Bugs, and check the code again how it fixes the issues.

Revision history for this message
Klaus Halfmann (klaus-halfmann) wrote :

Loading an old save game fails as expected:

UnhandledVersionError: This game was saved using an older version of Widelands and cannot be loaded anymore, or it's a new version that can't be handled yet.

Packet Name: MapFlagPacket
Saved Version: 1
Current Version: 2

Revision history for this message
GunChleoc (gunchleoc) wrote :

* This depends or includes https://code.launchpad.net/~widelands-dev/widelands/bug-1690519-economy-unique_ptr ?

No, that was a failed attempt at fixing something and will be scrapped once this is merged

* As Serial is uint32_t so we have 2^32 different Economies, ok

I hope that is enough - maybe we need a stress test?

* Do we have a testcase with a lot of Economies to get an Idea of the Performance change?

I don't expect any performance changes really - we access economies from containers in both cases.

Revision history for this message
GunChleoc (gunchleoc) wrote :

Answers to comments

Revision history for this message
GunChleoc (gunchleoc) wrote :

We do iterate over the economies a lot, so an unordered_map is not possible. e.g. in the stock menu:

    for (const auto& economy : player.economies()) {

Revision history for this message
Klaus Halfmann (klaus-halfmann) wrote :

Played this now for about 30 Minutes again, did not notice any Problems.
Ran the regression tests: Ran 41 tests in 739.863s,
all fine.

GUn: I will leave it up to you to merge this,
it will for sure break savegames.

Should we do some stress testing with a Mutiplayergame
placing and removing flags and roads like mad?

review: Approve
Revision history for this message
GunChleoc (gunchleoc) wrote :

I have had 8 AIs battle it out on Ice Wars for 100+ hours and have attached the savegame to the bug. We could run this some more to see if we ever hit the limit

Revision history for this message
Klaus Halfmann (klaus-halfmann) wrote :

Got a conflcit merging test/maps/plain.wmf/scripting/test_campaign_data.lua.
I used the versison from trunk, but actually there was no difference.

Regression tests: Ran 42 tests in 1125.653s

We should get his in soon now, merging can become difficult.
And this is (?) the last savegame breaking change, is it not?

Will testplay this again for my second english
youtube video today.

review: Approve
Revision history for this message
bunnybot (widelandsofficial) wrote :

Continuous integration builds have changed state:

Travis build 3574. State: failed. Details: https://travis-ci.org/widelands/widelands/builds/387006015.
Appveyor build 3377. State: success. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_bug_1732765_economy_refactoring-3377.

Revision history for this message
Klaus Halfmann (klaus-halfmann) wrote :

Any Codechecker around?
I think I fixed it but _some_ compilers still dont like me?
Why is it that differetn with some compilers?

Revision history for this message
ypopezios (ypopezios) wrote :

> * As Serial is uint32_t so we have 2^32 different Economies, ok

> Should we do some stress testing with a Mutiplayergame
placing and removing flags and roads like mad?

> We could run this some more to see if we ever hit the limit

If by testing the limit you mean the number 2^32, this is probably pointless. Cause that's a huge number, bigger than the number of seconds in a lifetime...

Revision history for this message
bunnybot (widelandsofficial) wrote :

Continuous integration builds have changed state:

Travis build 3575. State: passed. Details: https://travis-ci.org/widelands/widelands/builds/387075948.
Appveyor build 3378. State: success. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_bug_1732765_economy_refactoring-3378.

Revision history for this message
GunChleoc (gunchleoc) wrote :

We still have some crash reports with attached savegames. I'd like those to be sorted out first before merging this branch, because they will become unreproducible once this branch hits trunk.

Revision history for this message
Klaus Halfmann (klaus-halfmann) wrote :

I tried to load some old savegame (for my youtube channel) but it failed to display
the correct files, loading the other files failed, of course.

I assume some versioncheck was lost during the latest merge?

I will merge trunk again now

Revision history for this message
Klaus Halfmann (klaus-halfmann) wrote :

Uhm I checked ~/.widelands/save, my save files are there,
where is that code to check the file versions?

Revision history for this message
GunChleoc (gunchleoc) wrote :

There are 3 packets that have changed version - I have added comments to the diff so that you can find them. Savegames from other branches will be incompatible with this one.

Revision history for this message
Klaus Halfmann (klaus-halfmann) wrote :

My Bad, was playing Singleplayer/Frisians for too long.
this was a multiplay game. Looks I will create the next
Youtube video tomorrow, then.

Revision history for this message
bunnybot (widelandsofficial) wrote :

Continuous integration builds have changed state:

Travis build 3623. State: failed. Details: https://travis-ci.org/widelands/widelands/builds/399752394.
Appveyor build 3422. State: success. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_bug_1732765_economy_refactoring-3422.

Revision history for this message
bunnybot (widelandsofficial) wrote :

Continuous integration builds have changed state:

Travis build 3624. State: errored. Details: https://travis-ci.org/widelands/widelands/builds/400510697.
Appveyor build 3423. State: success. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_bug_1732765_economy_refactoring-3423.

Revision history for this message
GunChleoc (gunchleoc) wrote :

We only have 1 bug left now with a savegame that's needed:

https://bugs.launchpad.net/widelands/+bug/1678987

So, let's have this branch now to give it some more testing exposure.

@bunnybot merge

Revision history for this message
GunChleoc (gunchleoc) wrote :

Transient failure on Travis

@bunnybot merge force

Revision history for this message
bunnybot (widelandsofficial) wrote :

Continuous integration builds have changed state:

Travis build 3658. State: failed. Details: https://travis-ci.org/widelands/widelands/builds/402567175.
Appveyor build 3457. State: failed. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_bug_1732765_economy_refactoring-3457.

Revision history for this message
bunnybot (widelandsofficial) wrote :

Refusing to merge, since Travis is not green. Use @bunnybot merge force for merging anyways.

Travis build 3658. State: failed. Details: https://travis-ci.org/widelands/widelands/builds/402567175.

Revision history for this message
GunChleoc (gunchleoc) wrote :

@bunnybot merge force

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/ai/defaultai.cc'
2--- src/ai/defaultai.cc 2018-06-19 08:52:49 +0000
3+++ src/ai/defaultai.cc 2018-07-11 08:33:43 +0000
4@@ -6565,7 +6565,7 @@
5 assert(new_target > 1);
6
7 game().send_player_command(*new Widelands::CmdSetWareTargetQuantity(
8- gametime, player_number(), player_->get_economy_number(&observer->economy), id,
9+ gametime, player_number(), observer->economy.serial(), id,
10 new_target));
11 }
12 }
13
14=== modified file 'src/ai/defaultai.h'
15--- src/ai/defaultai.h 2018-04-16 07:03:12 +0000
16+++ src/ai/defaultai.h 2018-07-11 08:33:43 +0000
17@@ -155,7 +155,7 @@
18 // common for defaultai.cc and defaultai_seafaring.cc
19 static constexpr uint32_t kExpeditionMinDuration = 60 * 60 * 1000;
20 static constexpr uint32_t kExpeditionMaxDuration = 210 * 60 * 1000;
21- static constexpr uint32_t kNoShip = std::numeric_limits<uint32_t>::max();
22+ static constexpr Widelands::Serial kNoShip = Widelands::kInvalidSerial;
23 static constexpr int kShipCheckInterval = 5 * 1000;
24
25 // used by defaultai_warfare.cc
26
27=== modified file 'src/ai/defaultai_warfare.cc'
28--- src/ai/defaultai_warfare.cc 2018-04-09 01:50:48 +0000
29+++ src/ai/defaultai_warfare.cc 2018-07-11 08:33:43 +0000
30@@ -85,7 +85,7 @@
31 }
32
33 // now we update some of them
34- uint32_t best_target = std::numeric_limits<uint32_t>::max();
35+ Widelands::Serial best_target = Widelands::kInvalidSerial;
36 uint8_t best_score = 0;
37 uint32_t count = 0;
38 // sites that were either conquered or destroyed
39@@ -463,7 +463,7 @@
40 }
41
42 // if coordinates hash is not set
43- if (best_target == std::numeric_limits<uint32_t>::max()) {
44+ if (best_target == Widelands::kInvalidSerial) {
45 return false;
46 }
47
48
49=== modified file 'src/economy/economy.cc'
50--- src/economy/economy.cc 2018-04-07 16:59:00 +0000
51+++ src/economy/economy.cc 2018-07-11 08:33:43 +0000
52@@ -41,15 +41,19 @@
53
54 namespace Widelands {
55
56-Economy::Economy(Player& player) : owner_(player), request_timerid_(0), has_window_(false) {
57+Serial Economy::last_economy_serial_ = 0;
58+
59+Economy::Economy(Player& player) : Economy(player, last_economy_serial_++) {
60+}
61+
62+Economy::Economy(Player& player, Serial init_serial) : serial_(init_serial), owner_(player), request_timerid_(0), has_window_(false) {
63+ last_economy_serial_ = std::max(last_economy_serial_, serial_ + 1);
64 const TribeDescr& tribe = player.tribe();
65 DescriptionIndex const nr_wares = player.egbase().tribes().nrwares();
66 DescriptionIndex const nr_workers = player.egbase().tribes().nrworkers();
67 wares_.set_nrwares(nr_wares);
68 workers_.set_nrwares(nr_workers);
69
70- player.add_economy(*this);
71-
72 ware_target_quantities_ = new TargetQuantity[nr_wares];
73 for (DescriptionIndex i = 0; i < nr_wares; ++i) {
74 TargetQuantity tq;
75@@ -69,12 +73,11 @@
76 worker_target_quantities_[i] = tq;
77 }
78
79- router_ = new Router(boost::bind(&Economy::reset_all_pathfinding_cycles, this));
80+ router_.reset(new Router(boost::bind(&Economy::reset_all_pathfinding_cycles, this)));
81 }
82
83 Economy::~Economy() {
84- Notifications::publish(NoteEconomy{this, this, NoteEconomy::Action::kDeleted});
85- owner_.remove_economy(*this);
86+ Notifications::publish(NoteEconomy{serial_, serial_, NoteEconomy::Action::kDeleted});
87
88 if (requests_.size())
89 log("Warning: Economy still has requests left on destruction\n");
90@@ -85,8 +88,6 @@
91
92 delete[] ware_target_quantities_;
93 delete[] worker_target_quantities_;
94-
95- delete router_;
96 }
97
98 /**
99@@ -269,8 +270,9 @@
100 do_remove_flag(flag);
101
102 // automatically delete the economy when it becomes empty.
103- if (flags_.empty())
104- delete this;
105+ if (flags_.empty()) {
106+ owner_.remove_economy(serial_);
107+ }
108 }
109
110 /**
111@@ -528,7 +530,8 @@
112 // If the options window for e is open, but not the one for this, the user
113 // should still have an options window after the merge.
114 if (e.has_window() && !has_window()) {
115- Notifications::publish(NoteEconomy{&e, this, NoteEconomy::Action::kMerged});
116+ Notifications::publish(
117+ NoteEconomy{e.serial(), serial_, NoteEconomy::Action::kMerged});
118 }
119
120 for (std::vector<Flag*>::size_type i = e.get_nrflags() + 1; --i;) {
121@@ -542,9 +545,7 @@
122
123 // Remember that the other economy may not have been connected before the merge
124 split_checks_.insert(split_checks_.end(), e.split_checks_.begin(), e.split_checks_.end());
125-
126- // implicitly delete the economy
127- delete &e;
128+ owner_.remove_economy(e.serial());
129 }
130
131 /**
132@@ -553,21 +554,21 @@
133 void Economy::split(const std::set<OPtr<Flag>>& flags) {
134 assert(!flags.empty());
135
136- Economy& e = *new Economy(owner_);
137+ Economy* e = owner_.create_economy();
138
139 for (const DescriptionIndex& ware_index : owner_.tribe().wares()) {
140- e.ware_target_quantities_[ware_index] = ware_target_quantities_[ware_index];
141+ e->ware_target_quantities_[ware_index] = ware_target_quantities_[ware_index];
142 }
143
144 for (const DescriptionIndex& worker_index : owner_.tribe().workers()) {
145- e.worker_target_quantities_[worker_index] = worker_target_quantities_[worker_index];
146+ e->worker_target_quantities_[worker_index] = worker_target_quantities_[worker_index];
147 }
148
149 for (const OPtr<Flag>& temp_flag : flags) {
150 Flag& flag = *temp_flag.get(owner().egbase());
151 assert(flags_.size() > 1); // We will not be deleted in remove_flag, right?
152 remove_flag(flag);
153- e.add_flag(flag);
154+ e->add_flag(flag);
155 }
156
157 // As long as rebalance commands are tied to specific flags, we
158
159=== modified file 'src/economy/economy.h'
160--- src/economy/economy.h 2018-04-07 16:59:00 +0000
161+++ src/economy/economy.h 2018-07-11 08:33:43 +0000
162@@ -56,8 +56,8 @@
163 // When 2 economies have been merged, this is the economy number that has
164 // been removed, while the other one is the number of the resulting economy.
165 // For all other messages old_economy == new_economy.
166- Economy* old_economy;
167- Economy* new_economy;
168+ Widelands::Serial old_economy;
169+ Widelands::Serial new_economy;
170
171 enum class Action { kMerged, kDeleted };
172 const Action action;
173@@ -108,8 +108,13 @@
174 };
175
176 explicit Economy(Player&);
177+ explicit Economy(Player&, Serial serial); // For saveloading
178 ~Economy();
179
180+ Serial serial() const {
181+ return serial_;
182+ }
183+
184 Player& owner() const {
185 return owner_;
186 }
187@@ -209,6 +214,9 @@
188 start_request_timer();
189 }
190
191+protected:
192+ static Serial last_economy_serial_;
193+
194 private:
195 // This structs is to store distance from supply to request(or), but to allow unambiguous
196 // sorting if distances are the same, we use also serial number of provider and type of provider
197@@ -251,6 +259,8 @@
198 /*************/
199 using RequestList = std::vector<Request*>;
200
201+ const Serial serial_;
202+
203 Player& owner_;
204
205 using Flags = std::vector<Flag*>;
206@@ -264,7 +274,7 @@
207
208 TargetQuantity* ware_target_quantities_;
209 TargetQuantity* worker_target_quantities_;
210- Router* router_;
211+ std::unique_ptr<Router> router_;
212
213 using SplitPair = std::pair<OPtr<Flag>, OPtr<Flag>>;
214 std::vector<SplitPair> split_checks_;
215
216=== modified file 'src/economy/economy_data_packet.cc'
217--- src/economy/economy_data_packet.cc 2018-04-07 16:59:00 +0000
218+++ src/economy/economy_data_packet.cc 2018-07-11 08:33:43 +0000
219@@ -27,7 +27,7 @@
220 #include "map_io/map_object_loader.h"
221 #include "map_io/map_object_saver.h"
222
223-constexpr uint16_t kCurrentPacketVersion = 3;
224+constexpr uint16_t kCurrentPacketVersion = 4;
225
226 namespace Widelands {
227
228@@ -35,6 +35,11 @@
229 try {
230 uint16_t const packet_version = fr.unsigned_16();
231 if (packet_version == kCurrentPacketVersion) {
232+ const Serial saved_serial = fr.unsigned_32();
233+ if (eco_->serial_ != saved_serial) {
234+ throw GameDataError("Representative flag/ship has economy serial %d, but the data packet has %d", eco_->serial_, saved_serial);
235+ }
236+ assert(Economy::last_economy_serial_ >= eco_->serial_);
237 try {
238 const TribeDescr& tribe = eco_->owner().tribe();
239 while (Time const last_modified = fr.unsigned_32()) {
240@@ -94,6 +99,11 @@
241
242 void EconomyDataPacket::write(FileWrite& fw) {
243 fw.unsigned_16(kCurrentPacketVersion);
244+
245+ // We save the serial number for sanity checks
246+ fw.unsigned_32(eco_->serial());
247+
248+ // Requests etc.
249 const TribeDescr& tribe = eco_->owner().tribe();
250 for (const DescriptionIndex& ware_index : tribe.wares()) {
251 const Economy::TargetQuantity& tq = eco_->ware_target_quantities_[ware_index];
252
253=== modified file 'src/economy/economy_data_packet.h'
254--- src/economy/economy_data_packet.h 2018-04-07 16:59:00 +0000
255+++ src/economy/economy_data_packet.h 2018-07-11 08:33:43 +0000
256@@ -20,6 +20,8 @@
257 #ifndef WL_ECONOMY_ECONOMY_DATA_PACKET_H
258 #define WL_ECONOMY_ECONOMY_DATA_PACKET_H
259
260+#include <cassert>
261+
262 class FileRead;
263 class FileWrite;
264
265@@ -32,6 +34,7 @@
266 class EconomyDataPacket {
267 public:
268 explicit EconomyDataPacket(Economy* e) : eco_(e) {
269+ assert(eco_);
270 }
271
272 void read(FileRead&);
273
274=== modified file 'src/economy/flag.cc'
275--- src/economy/flag.cc 2018-07-07 09:05:13 +0000
276+++ src/economy/flag.cc 2018-07-11 08:33:43 +0000
277@@ -44,7 +44,7 @@
278 }
279
280 /**
281- * Create the flag. Initially, it doesn't have any attachments.
282+ * A bare flag, used for testing only.
283 */
284 Flag::Flag()
285 : PlayerImmovable(g_flag_descr),
286@@ -106,7 +106,7 @@
287 /**
288 * Create a flag at the given location
289 */
290-Flag::Flag(EditorGameBase& egbase, Player* owning_player, const Coords& coords)
291+Flag::Flag(EditorGameBase& egbase, Player* owning_player, const Coords& coords, Economy* eco)
292 : PlayerImmovable(g_flag_descr),
293 building_(nullptr),
294 ware_capacity_(8),
295@@ -124,17 +124,23 @@
296 upcast(Game, game, &egbase);
297
298 if (game) {
299- // we split a road, or a new, standalone flag is created
300- (road ? road->get_economy() : new Economy(*owning_player))->add_flag(*this);
301-
302- if (road)
303- road->presplit(*game, coords);
304+ if (eco) {
305+ // We're saveloading
306+ eco->add_flag(*this);
307+ } else {
308+ // we split a road, or a new, standalone flag is created
309+ (road ? road->get_economy() : owning_player->create_economy())->add_flag(*this);
310+ if (road) {
311+ road->presplit(*game, coords);
312+ }
313+ }
314 }
315
316 init(egbase);
317
318- if (road && game)
319+ if (!eco && road && game) {
320 road->postsplit(*game, *this);
321+ }
322 }
323
324 void Flag::set_flag_position(Coords coords) {
325
326=== modified file 'src/economy/flag.h'
327--- src/economy/flag.h 2018-05-15 04:28:36 +0000
328+++ src/economy/flag.h 2018-07-11 08:33:43 +0000
329@@ -74,8 +74,12 @@
330
331 const FlagDescr& descr() const;
332
333- Flag(); /// empty flag for savegame loading
334- Flag(EditorGameBase&, Player* owner, const Coords&); /// create a new flag
335+ /// Empty flag, for unit tests only.
336+ Flag();
337+
338+ /// Create a new flag. Only specify an economy during saveloading.
339+ /// Otherwise, a new economy will be created automatically if needed.
340+ Flag(EditorGameBase&, Player* owner, const Coords&, Economy* economy = nullptr);
341 ~Flag() override;
342
343 void load_finish(EditorGameBase&) override;
344
345=== modified file 'src/game_io/game_player_economies_packet.cc'
346--- src/game_io/game_player_economies_packet.cc 2018-04-07 16:59:00 +0000
347+++ src/game_io/game_player_economies_packet.cc 2018-07-11 08:33:43 +0000
348@@ -34,7 +34,7 @@
349 namespace Widelands {
350 namespace {
351
352-constexpr uint16_t kCurrentPacketVersion = 4;
353+constexpr uint16_t kCurrentPacketVersion = 5;
354
355 bool write_expedition_ship_economy(Economy* economy, const Map& map, FileWrite* fw) {
356 for (Field const* field = &map[0]; field < &map[map.max_index()]; ++field) {
357@@ -67,31 +67,21 @@
358 FileRead fr;
359 fr.open(fs, "binary/player_economies");
360 uint16_t const packet_version = fr.unsigned_16();
361- if (packet_version == 3 || packet_version == kCurrentPacketVersion) {
362+ if (packet_version == kCurrentPacketVersion) {
363 iterate_players_existing(p, nr_players, game, player) try {
364- // In packet_version 4 we dump the number of economies a player had at
365- // save time to debug
366- // https://bugs.launchpad.net/widelands/+bug/1654897 which is likely
367- // caused by players having more economies at load than they had at
368- // save.
369- Player::Economies& economies = player->economies_;
370- if (packet_version > 3) {
371- const size_t num_economies = fr.unsigned_16();
372- if (num_economies != economies.size()) {
373- throw GameDataError("Num economies on save (%" PRIuS
374- ") != Num economies on load (%" PRIuS ")",
375- num_economies, economies.size());
376- }
377- }
378-
379- for (uint32_t i = 0; i < economies.size(); ++i) {
380+ const size_t num_economies = fr.unsigned_32();
381+ for (uint32_t i = 0; i < num_economies; ++i) {
382 uint32_t value = fr.unsigned_32();
383 if (value < 0xffffffff) {
384 if (upcast(Flag const, flag, map[value].get_immovable())) {
385- assert(flag->get_economy()->owner().player_number() ==
386- player->player_number());
387- EconomyDataPacket d(flag->get_economy());
388- d.read(fr);
389+ try {
390+ assert(flag->get_economy()->owner().player_number() ==
391+ player->player_number());
392+ EconomyDataPacket d(flag->get_economy());
393+ d.read(fr);
394+ } catch (const GameDataError& e) {
395+ throw GameDataError("error reading economy data for flag at map index %d: %s", value, e.what());
396+ }
397 } else {
398 throw GameDataError("there is no flag at the specified location");
399 }
400@@ -102,13 +92,17 @@
401 if (upcast(Ship const, ship, bob)) {
402 // We are interested only in current player's ships
403 if (ship->get_owner() == player) {
404- assert(ship->get_economy());
405- assert(ship->get_economy()->owner().player_number() ==
406- player->player_number());
407- EconomyDataPacket d(ship->get_economy());
408- d.read(fr);
409- read_this_economy = true;
410- break;
411+ try {
412+ assert(ship->get_economy());
413+ assert(ship->get_economy()->owner().player_number() ==
414+ player->player_number());
415+ EconomyDataPacket d(ship->get_economy());
416+ d.read(fr);
417+ read_this_economy = true;
418+ break;
419+ } catch (const GameDataError& e) {
420+ throw GameDataError("error reading economy data for ship %s: %s", ship->get_shipname().c_str(), e.what());
421+ }
422 }
423 }
424 bob = bob->get_next_bob();
425@@ -140,13 +134,13 @@
426 const Map& map = game.map();
427 PlayerNumber const nr_players = map.get_nrplayers();
428 iterate_players_existing_const(p, nr_players, game, player) {
429- const Player::Economies& economies = player->economies_;
430- fw.unsigned_16(economies.size());
431- for (Economy* economy : economies) {
432- Flag* arbitrary_flag = economy->get_arbitrary_flag();
433+ const auto& economies = player->economies();
434+ fw.unsigned_32(economies.size());
435+ for (const auto& economy : economies) {
436+ Flag* arbitrary_flag = economy.second->get_arbitrary_flag();
437 if (arbitrary_flag != nullptr) {
438 fw.unsigned_32(map.get_fcoords(arbitrary_flag->get_position()).field - &map[0]);
439- EconomyDataPacket d(economy);
440+ EconomyDataPacket d(economy.second.get());
441 d.write(fw);
442 continue;
443 }
444@@ -154,8 +148,8 @@
445 // No flag found, let's look for a representative Ship. Expeditions
446 // ships are special and have their own economy (which will not have a
447 // flag), therefore we have to special case them.
448- if (!write_expedition_ship_economy(economy, map, &fw)) {
449- throw GameDataError("economy without representative");
450+ if (!write_expedition_ship_economy(economy.second.get(), map, &fw)) {
451+ throw GameDataError("Player %d: economy %d has no representative", player->player_number(), economy.first);
452 }
453 }
454 }
455
456=== modified file 'src/io/filesystem/filesystem.cc'
457--- src/io/filesystem/filesystem.cc 2018-06-06 19:45:06 +0000
458+++ src/io/filesystem/filesystem.cc 2018-07-11 08:33:43 +0000
459@@ -200,25 +200,24 @@
460 }
461 }
462 const std::string illegal_start(as_listitem(
463- /** TRANSLATORS: Tooltip entry for characters in illegal filenames. %s is a list of illegal
464- * characters */
465+ /** TRANSLATORS: Tooltip entry for characters in illegal filenames.
466+ * %s is a list of illegal characters */
467 (boost::format(pgettext("illegal_filename_characters", "%s at the start of the filename")) %
468 richtext_escape(i18n::localize_list(starting_characters, i18n::ConcatenateWith::OR)))
469 .str(),
470 UI_FONT_SIZE_MESSAGE));
471
472 const std::string illegal(as_listitem(
473- /** TRANSLATORS: Tooltip entry for characters in illegal filenames. %s is a list of illegal
474- * characters */
475+ /** TRANSLATORS: Tooltip entry for characters in illegal filenames.
476+ * %s is a list of illegal characters */
477 (boost::format(pgettext("illegal_filename_characters", "%s anywhere in the filename")) %
478 richtext_escape(i18n::localize_list(illegal_filename_characters, i18n::ConcatenateWith::OR)))
479 .str(),
480 UI_FONT_SIZE_MESSAGE));
481
482 return (boost::format("%s%s%s") %
483- /** TRANSLATORS: Tooltip header for characters in illegal filenames. This is followed by
484- * a list
485- * of bullet points */
486+ /** TRANSLATORS: Tooltip header for characters in illegal filenames.
487+ * This is followed by a list of bullet points */
488 pgettext("illegal_filename_characters", "The following characters are not allowed:") %
489 illegal_start % illegal)
490 .str();
491
492=== modified file 'src/logic/game.cc'
493--- src/logic/game.cc 2018-04-30 15:38:48 +0000
494+++ src/logic/game.cc 2018-07-11 08:33:43 +0000
495@@ -911,17 +911,16 @@
496 uint32_t wostock = 0;
497 uint32_t wastock = 0;
498
499- for (uint32_t j = 0; j < plr->get_nr_economies(); ++j) {
500- Economy* const eco = plr->get_economy_by_number(j);
501+ for (const auto& economy : plr->economies()) {
502 const TribeDescr& tribe = plr->tribe();
503
504 for (const DescriptionIndex& ware_index : tribe.wares()) {
505- wastock += eco->stock_ware(ware_index);
506+ wastock += economy.second->stock_ware(ware_index);
507 }
508
509 for (const DescriptionIndex& worker_index : tribe.workers()) {
510 if (tribe.get_worker_descr(worker_index)->type() != MapObjectType::CARRIER) {
511- wostock += eco->stock_worker(worker_index);
512+ wostock += economy.second->stock_worker(worker_index);
513 }
514 }
515 }
516
517=== modified file 'src/logic/map_objects/tribes/ship.cc'
518--- src/logic/map_objects/tribes/ship.cc 2018-04-30 15:38:48 +0000
519+++ src/logic/map_objects/tribes/ship.cc 2018-07-11 08:33:43 +0000
520@@ -826,14 +826,14 @@
521 expedition_->scouting_direction = WalkingDir::IDLE;
522 expedition_->exploration_start = Coords(0, 0);
523 expedition_->island_explore_direction = IslandExploreDirection::kClockwise;
524- expedition_->economy.reset(new Economy(*get_owner()));
525+ expedition_->economy = get_owner()->create_economy();
526
527 // We are no longer in any other economy, but instead are an economy of our
528 // own.
529 fleet_->remove_ship(game, this);
530 assert(fleet_ == nullptr);
531
532- set_economy(game, expedition_->economy.get());
533+ set_economy(game, expedition_->economy);
534
535 for (int i = items_.size() - 1; i >= 0; --i) {
536 WareInstance* ware;
537@@ -943,7 +943,7 @@
538 if (!get_fleet() || !get_fleet()->has_ports()) {
539 // We lost our last reachable port, so we reset the expedition's state
540 ship_state_ = ShipStates::kExpeditionWaiting;
541- set_economy(game, expedition_->economy.get());
542+ set_economy(game, expedition_->economy);
543
544 worker = nullptr;
545 for (ShippingItem& item : items_) {
546@@ -957,7 +957,7 @@
547 Notifications::publish(NoteShip(this, NoteShip::Action::kNoPortLeft));
548 return;
549 }
550- assert(get_economy() && get_economy() != expedition_->economy.get());
551+ assert(get_economy() && get_economy() != expedition_->economy);
552
553 send_signal(game, "cancel_expedition");
554
555@@ -1096,6 +1096,12 @@
556 heading, rt_description, get_position(), serial_)));
557 }
558
559+Ship::Expedition::~Expedition() {
560+ if (economy) {
561+ economy->owner().remove_economy(economy->serial());
562+ }
563+}
564+
565 /*
566 ==============================
567
568@@ -1104,7 +1110,7 @@
569 ==============================
570 */
571
572-constexpr uint8_t kCurrentPacketVersion = 6;
573+constexpr uint8_t kCurrentPacketVersion = 7;
574
575 const Bob::Task* Ship::Loader::get_task(const std::string& name) {
576 if (name == "shipidle" || name == "ship")
577@@ -1115,6 +1121,9 @@
578 void Ship::Loader::load(FileRead& fr) {
579 Bob::Loader::load(fr);
580
581+ // Economy
582+ economy_serial_ = fr.unsigned_32();
583+
584 // The state the ship is in
585 ship_state_ = static_cast<ShipStates>(fr.unsigned_8());
586
587@@ -1175,6 +1184,14 @@
588
589 Ship& ship = get<Ship>();
590
591+ // The economy can sometimes be nullptr (e.g. when there are no ports).
592+ if (economy_serial_ != kInvalidSerial) {
593+ ship.economy_ = ship.get_owner()->get_economy(economy_serial_);
594+ if (!ship.economy_) {
595+ ship.economy_ = ship.get_owner()->create_economy(economy_serial_);
596+ }
597+ }
598+
599 // restore the state the ship is in
600 ship.ship_state_ = ship_state_;
601
602@@ -1184,8 +1201,7 @@
603 // if the ship is on an expedition, restore the expedition specific data
604 if (expedition_) {
605 ship.expedition_.swap(expedition_);
606- ship.expedition_->economy.reset(new Economy(*ship.get_owner()));
607- ship.economy_ = ship.expedition_->economy.get();
608+ ship.expedition_->economy = ship.economy_;
609 } else
610 assert(ship_state_ == ShipStates::kTransport);
611
612@@ -1201,28 +1217,16 @@
613
614 MapObject::Loader* Ship::load(EditorGameBase& egbase, MapObjectLoader& mol, FileRead& fr) {
615 std::unique_ptr<Loader> loader(new Loader);
616-
617 try {
618 // The header has been peeled away by the caller
619 uint8_t const packet_version = fr.unsigned_8();
620- if (1 <= packet_version && packet_version <= kCurrentPacketVersion) {
621+ if (packet_version == kCurrentPacketVersion) {
622 try {
623 const ShipDescr* descr = nullptr;
624 // Removing this will break the test suite
625- if (packet_version < 5) {
626- std::string tribe_name = fr.string();
627- fr.c_string(); // This used to be the ship's name, which we don't need any more.
628- if (!Widelands::tribe_exists(tribe_name)) {
629- throw GameDataError("Tribe %s does not exist for ship", tribe_name.c_str());
630- }
631- const DescriptionIndex& tribe_index = egbase.tribes().tribe_index(tribe_name);
632- const TribeDescr& tribe_descr = *egbase.tribes().get_tribe_descr(tribe_index);
633- descr = egbase.tribes().get_ship_descr(tribe_descr.ship());
634- } else {
635- std::string name = fr.c_string();
636- const DescriptionIndex& ship_index = egbase.tribes().safe_ship_index(name);
637- descr = egbase.tribes().get_ship_descr(ship_index);
638- }
639+ std::string name = fr.c_string();
640+ const DescriptionIndex& ship_index = egbase.tribes().safe_ship_index(name);
641+ descr = egbase.tribes().get_ship_descr(ship_index);
642 loader->init(egbase, mol, descr->create_object());
643 loader->load(fr);
644 } catch (const WException& e) {
645@@ -1245,6 +1249,9 @@
646
647 Bob::save(egbase, mos, fw);
648
649+ // The economy can sometimes be nullptr (e.g. when there are no ports).
650+ fw.unsigned_32(economy_ != nullptr ? economy_->serial() : kInvalidSerial);
651+
652 // state the ship is in
653 fw.unsigned_8(static_cast<uint8_t>(ship_state_));
654
655
656=== modified file 'src/logic/map_objects/tribes/ship.h'
657--- src/logic/map_objects/tribes/ship.h 2018-04-29 09:20:29 +0000
658+++ src/logic/map_objects/tribes/ship.h 2018-07-11 08:33:43 +0000
659@@ -271,13 +271,15 @@
660 std::string shipname_;
661
662 struct Expedition {
663+ ~Expedition();
664+
665 std::vector<Coords> seen_port_buildspaces;
666 bool swimmable[LAST_DIRECTION];
667 bool island_exploration;
668 WalkingDir scouting_direction;
669 Coords exploration_start;
670 IslandExploreDirection island_explore_direction;
671- std::unique_ptr<Economy> economy;
672+ Economy* economy; // Owned by Player
673 };
674 std::unique_ptr<Expedition> expedition_;
675
676@@ -295,6 +297,7 @@
677 // Initialize everything to make cppcheck happy.
678 uint32_t lastdock_ = 0U;
679 uint32_t destination_ = 0U;
680+ Serial economy_serial_;
681 ShipStates ship_state_ = ShipStates::kTransport;
682 std::string shipname_;
683 std::unique_ptr<Expedition> expedition_;
684
685=== modified file 'src/logic/player.cc'
686--- src/logic/player.cc 2018-04-29 09:20:29 +0000
687+++ src/logic/player.cc 2018-07-11 08:33:43 +0000
688@@ -798,37 +798,50 @@
689 /*
690 * Economy stuff below
691 */
692-void Player::add_economy(Economy& economy) {
693- if (!has_economy(economy))
694- economies_.push_back(&economy);
695-}
696-
697-void Player::remove_economy(Economy& economy) {
698- for (std::vector<Economy*>::iterator economy_iter = economies_.begin();
699- economy_iter != economies_.end(); ++economy_iter)
700- if (*economy_iter == &economy) {
701- economies_.erase(economy_iter);
702- return;
703- }
704-}
705-
706-bool Player::has_economy(Economy& economy) const {
707- for (Economy* temp_economy : economies_) {
708- if (temp_economy == &economy) {
709- return true;
710- }
711+Economy* Player::create_economy() {
712+ std::unique_ptr<Economy> eco(new Economy(*this));
713+ const Serial serial = eco->serial();
714+
715+ assert(economies_.count(serial) == 0);
716+ economies_.emplace(std::make_pair(serial, std::move(eco)));
717+ assert(economies_.at(serial)->serial() == serial);
718+ assert(economies_.count(serial) == 1);
719+
720+ return get_economy(serial);
721+}
722+
723+Economy* Player::create_economy(Serial serial) {
724+ std::unique_ptr<Economy> eco(new Economy(*this, serial));
725+
726+ assert(economies_.count(serial) == 0);
727+ economies_.emplace(std::make_pair(serial, std::move(eco)));
728+ assert(economies_.at(serial)->serial() == serial);
729+ assert(economies_.count(serial) == 1);
730+
731+ return get_economy(serial);
732+}
733+
734+void Player::remove_economy(Serial serial) {
735+ assert(has_economy(serial));
736+ economies_.erase(economies_.find(serial));
737+ assert(!has_economy(serial));
738+}
739+
740+const std::map<Serial, std::unique_ptr<Economy>>& Player::economies() const {
741+ return economies_;
742+}
743+
744+Economy* Player::get_economy(Widelands::Serial serial) const {
745+ if (economies_.count(serial) == 0) {
746+ return nullptr;
747 }
748- return false;
749-}
750-
751-Player::Economies::size_type Player::get_economy_number(Economy const* const economy) const {
752- Economies::const_iterator const economies_end = economies_.end(),
753- economies_begin = economies_.begin();
754- for (Economies::const_iterator it = economies_begin; it != economies_end; ++it)
755- if (*it == economy)
756- return it - economies_begin;
757- NEVER_HERE();
758-}
759+ return economies_.at(serial).get();
760+}
761+
762+bool Player::has_economy(Widelands::Serial serial) const {
763+ return economies_.count(serial) != 0;
764+}
765+
766
767 /************ Military stuff **********/
768
769@@ -1156,11 +1169,8 @@
770 // Calculate stocks
771 std::vector<uint32_t> stocks(egbase().tribes().nrwares());
772
773- const uint32_t nrecos = get_nr_economies();
774- for (uint32_t i = 0; i < nrecos; ++i) {
775- const std::vector<Widelands::Warehouse*>& warehouses = get_economy_by_number(i)->warehouses();
776-
777- for (Widelands::Warehouse* warehouse : warehouses) {
778+ for (const auto& economy : economies()) {
779+ for (Widelands::Warehouse* warehouse : economy.second->warehouses()) {
780 const Widelands::WareList& wares = warehouse->get_wares();
781 for (size_t id = 0; id < stocks.size(); ++id) {
782 stocks[id] += wares.stock(DescriptionIndex(id));
783
784=== modified file 'src/logic/player.h'
785--- src/logic/player.h 2018-04-29 09:20:29 +0000
786+++ src/logic/player.h 2018-07-11 08:33:43 +0000
787@@ -25,6 +25,7 @@
788 #include <unordered_map>
789
790 #include "base/macros.h"
791+#include "economy/economy.h"
792 #include "graphic/color.h"
793 #include "graphic/playercolor.h"
794 #include "logic/editor_game_base.h"
795@@ -40,7 +41,6 @@
796 class Node;
797 namespace Widelands {
798
799-class Economy;
800 struct Path;
801 struct PlayerImmovable;
802 class Soldier;
803@@ -515,18 +515,12 @@
804 void enhance_building(Building*, DescriptionIndex index_of_new_building);
805 void dismantle_building(Building*);
806
807- // Economy stuff
808- void add_economy(Economy&);
809- void remove_economy(Economy&);
810- bool has_economy(Economy&) const;
811- using Economies = std::vector<Economy*>;
812- Economies::size_type get_economy_number(Economy const*) const;
813- Economy* get_economy_by_number(Economies::size_type const i) const {
814- return economies_[i];
815- }
816- uint32_t get_nr_economies() const {
817- return economies_.size();
818- }
819+ Economy* create_economy();
820+ Economy* create_economy(Serial serial); // For saveloading only
821+ void remove_economy(Serial serial);
822+ const std::map<Serial, std::unique_ptr<Economy>>& economies() const;
823+ Economy* get_economy(Widelands::Serial serial) const;
824+ bool has_economy(Widelands::Serial serial) const;
825
826 uint32_t get_current_produced_statistics(uint8_t);
827
828@@ -644,7 +638,7 @@
829 Field* fields_;
830 std::vector<bool> allowed_worker_types_;
831 std::vector<bool> allowed_building_types_;
832- Economies economies_;
833+ std::map<Serial, std::unique_ptr<Economy>> economies_;
834 std::set<Serial> ships_;
835 std::string name_; // Player name
836 std::string ai_; /**< Name of preferred AI implementation */
837
838=== modified file 'src/logic/playercommand.cc'
839--- src/logic/playercommand.cc 2018-04-07 16:59:00 +0000
840+++ src/logic/playercommand.cc 2018-07-11 08:33:43 +0000
841@@ -1229,8 +1229,8 @@
842
843 void CmdSetWareTargetQuantity::execute(Game& game) {
844 Player* player = game.get_player(sender());
845- if (economy() < player->get_nr_economies() && game.tribes().ware_exists(ware_type())) {
846- player->get_economy_by_number(economy())->set_ware_target_quantity(
847+ if (player->has_economy(economy()) && game.tribes().ware_exists(ware_type())) {
848+ player->get_economy(economy())->set_ware_target_quantity(
849 ware_type(), permanent_, duetime());
850 }
851 }
852@@ -1280,9 +1280,9 @@
853 void CmdResetWareTargetQuantity::execute(Game& game) {
854 Player* player = game.get_player(sender());
855 const TribeDescr& tribe = player->tribe();
856- if (economy() < player->get_nr_economies() && game.tribes().ware_exists(ware_type())) {
857+ if (player->has_economy(economy()) && game.tribes().ware_exists(ware_type())) {
858 const int count = tribe.get_ware_descr(ware_type())->default_target_quantity(tribe.name());
859- player->get_economy_by_number(economy())->set_ware_target_quantity(
860+ player->get_economy(economy())->set_ware_target_quantity(
861 ware_type(), count, duetime());
862 }
863 }
864@@ -1328,8 +1328,8 @@
865
866 void CmdSetWorkerTargetQuantity::execute(Game& game) {
867 Player* player = game.get_player(sender());
868- if (economy() < player->get_nr_economies() && game.tribes().worker_exists(ware_type())) {
869- player->get_economy_by_number(economy())->set_worker_target_quantity(
870+ if (player->has_economy(economy()) && game.tribes().worker_exists(ware_type())) {
871+ player->get_economy(economy())->set_worker_target_quantity(
872 ware_type(), permanent_, duetime());
873 }
874 }
875@@ -1379,9 +1379,9 @@
876 void CmdResetWorkerTargetQuantity::execute(Game& game) {
877 Player* player = game.get_player(sender());
878 const TribeDescr& tribe = player->tribe();
879- if (economy() < player->get_nr_economies() && game.tribes().ware_exists(ware_type())) {
880+ if (player->has_economy(economy()) && game.tribes().ware_exists(ware_type())) {
881 const int count = tribe.get_ware_descr(ware_type())->default_target_quantity(tribe.name());
882- player->get_economy_by_number(economy())->set_worker_target_quantity(
883+ player->get_economy(economy())->set_worker_target_quantity(
884 ware_type(), count, duetime());
885 }
886 }
887
888=== modified file 'src/logic/playercommand.h'
889--- src/logic/playercommand.h 2018-04-07 16:59:00 +0000
890+++ src/logic/playercommand.h 2018-07-11 08:33:43 +0000
891@@ -543,7 +543,7 @@
892 void serialize(StreamWrite&) override;
893
894 protected:
895- uint32_t economy() const {
896+ Serial economy() const {
897 return economy_;
898 }
899 DescriptionIndex ware_type() const {
900@@ -551,7 +551,7 @@
901 }
902
903 private:
904- uint32_t economy_;
905+ Serial economy_;
906 DescriptionIndex ware_type_;
907 };
908
909
910=== modified file 'src/logic/widelands.h'
911--- src/logic/widelands.h 2018-04-07 16:59:00 +0000
912+++ src/logic/widelands.h 2018-07-11 08:33:43 +0000
913@@ -84,6 +84,7 @@
914 }
915
916 using Serial = uint32_t; /// Serial number for MapObject.
917+constexpr Serial kInvalidSerial = std::numeric_limits<uint32_t>::max();
918
919 using Direction = uint8_t;
920
921
922=== modified file 'src/map_io/map_flag_packet.cc'
923--- src/map_io/map_flag_packet.cc 2018-04-07 16:59:00 +0000
924+++ src/map_io/map_flag_packet.cc 2018-07-11 08:33:43 +0000
925@@ -35,7 +35,7 @@
926
927 namespace Widelands {
928
929-constexpr uint16_t kCurrentPacketVersion = 1;
930+constexpr uint16_t kCurrentPacketVersion = 2;
931
932 void MapFlagPacket::read(FileSystem& fs,
933 EditorGameBase& egbase,
934@@ -63,6 +63,8 @@
935 throw GameDataError("Invalid player number: %i.", owner);
936 }
937
938+ const Serial economy_serial = fr.unsigned_32();
939+
940 Serial const serial = fr.unsigned_32();
941
942 try {
943@@ -94,13 +96,21 @@
944
945 // No flag lives on more than one place.
946
947+ // Get economy from serial
948+ Player* player = egbase.get_player(owner);
949+ Economy* economy = player->get_economy(economy_serial);
950+ if (!economy) {
951+ economy = player->create_economy(economy_serial);
952+ }
953+
954 // Now, create this Flag. Directly create it, do not call
955 // the player class since we recreate the data in another
956 // packet. We always create this, no matter what skip is
957 // since we have to read the data packets. We delete this
958 // object later again, if it is not wanted.
959- mol.register_object<Flag>(
960- serial, *new Flag(dynamic_cast<Game&>(egbase), egbase.get_player(owner), fc));
961+ Flag* flag = new Flag(dynamic_cast<Game&>(egbase), player, fc, economy);
962+ mol.register_object<Flag>(serial, *flag);
963+
964 } catch (const WException& e) {
965 throw GameDataError(
966 "%u (at (%i, %i), owned by player %u): %s", serial, fc.x, fc.y, owner, e.what());
967@@ -133,6 +143,7 @@
968
969 fw.unsigned_8(1);
970 fw.unsigned_8(flag->owner().player_number());
971+ fw.unsigned_32(flag->economy().serial());
972 fw.unsigned_32(mos.register_object(*flag));
973 } else // no existence, no owner
974 fw.unsigned_8(0);
975
976=== modified file 'src/scripting/lua_bases.cc'
977--- src/scripting/lua_bases.cc 2018-07-07 09:06:55 +0000
978+++ src/scripting/lua_bases.cc 2018-07-11 08:33:43 +0000
979@@ -875,8 +875,8 @@
980 const DescriptionIndex worker = player.tribe().worker_index(workername);
981
982 uint32_t nworkers = 0;
983- for (uint32_t i = 0; i < player.get_nr_economies(); ++i) {
984- nworkers += player.get_economy_by_number(i)->stock_worker(worker);
985+ for (const auto& economy : player.economies()) {
986+ nworkers += economy.second->stock_worker(worker);
987 }
988 lua_pushuint32(L, nworkers);
989 return 1;
990@@ -901,8 +901,8 @@
991 const DescriptionIndex ware = egbase.tribes().ware_index(warename);
992
993 uint32_t nwares = 0;
994- for (uint32_t i = 0; i < player.get_nr_economies(); ++i) {
995- nwares += player.get_economy_by_number(i)->stock_ware(ware);
996+ for (const auto& economy : player.economies()) {
997+ nwares += economy.second->stock_ware(ware);
998 }
999 lua_pushuint32(L, nwares);
1000 return 1;
1001
1002=== modified file 'src/scripting/lua_game.cc'
1003--- src/scripting/lua_game.cc 2018-04-16 07:03:12 +0000
1004+++ src/scripting/lua_game.cc 2018-07-11 08:33:43 +0000
1005@@ -174,16 +174,16 @@
1006 */
1007 int LuaPlayer::get_defeated(lua_State* L) {
1008 Player& p = get(L, get_egbase(L));
1009- bool have_warehouses = false;
1010+ bool is_defeated = true;
1011
1012- for (uint32_t economy_nr = 0; economy_nr < p.get_nr_economies(); economy_nr++) {
1013- if (!p.get_economy_by_number(economy_nr)->warehouses().empty()) {
1014- have_warehouses = true;
1015+ for (const auto& economy : p.economies()) {
1016+ if (!economy.second->warehouses().empty()) {
1017+ is_defeated = false;
1018 break;
1019 }
1020 }
1021
1022- lua_pushboolean(L, !have_warehouses);
1023+ lua_pushboolean(L, is_defeated);
1024 return 1;
1025 }
1026
1027@@ -812,10 +812,8 @@
1028 break;
1029 }
1030 }
1031- for (uint32_t j = player.get_nr_economies(); j;) {
1032- Economy& economy = *player.get_economy_by_number(--j);
1033-
1034- for (Warehouse* warehouse : economy.warehouses()) {
1035+ for (const auto& economy: player.economies()) {
1036+ for (Warehouse* warehouse : economy.second->warehouses()) {
1037 warehouse->enable_spawn(game, worker_types_without_cost_index);
1038 }
1039 }
1040
1041=== modified file 'src/scripting/lua_map.cc'
1042--- src/scripting/lua_map.cc 2018-07-07 11:03:56 +0000
1043+++ src/scripting/lua_map.cc 2018-07-11 08:33:43 +0000
1044@@ -3568,16 +3568,16 @@
1045 const Widelands::Economy* economy = get();
1046 const Widelands::Player& player = economy->owner();
1047 PERS_UINT32("player", player.player_number());
1048- PERS_UINT32("economy", player.get_economy_number(economy));
1049+ PERS_UINT32("economy", economy->serial());
1050 }
1051
1052 void LuaEconomy::__unpersist(lua_State* L) {
1053 Widelands::PlayerNumber player_number;
1054- size_t economy_number;
1055+ Widelands::Serial economy_serial;
1056 UNPERS_UINT32("player", player_number);
1057- UNPERS_UINT32("economy", economy_number);
1058+ UNPERS_UINT32("economy", economy_serial);
1059 const Widelands::Player& player = get_egbase(L).player(player_number);
1060- set_economy_pointer(player.get_economy_by_number(economy_number));
1061+ set_economy_pointer(player.get_economy(economy_serial));
1062 }
1063
1064 /* RST
1065
1066=== modified file 'src/wui/economy_options_window.cc'
1067--- src/wui/economy_options_window.cc 2018-05-13 07:15:39 +0000
1068+++ src/wui/economy_options_window.cc 2018-07-11 08:33:43 +0000
1069@@ -36,10 +36,11 @@
1070 Widelands::Economy* economy,
1071 bool can_act)
1072 : UI::Window(parent, "economy_options", 0, 0, 0, 0, _("Economy options")),
1073- economy_(economy),
1074+ serial_(economy->serial()),
1075+ player_(&economy->owner()),
1076 tabpanel_(this, UI::TabPanelStyle::kWuiDark),
1077- ware_panel_(new EconomyOptionsPanel(&tabpanel_, can_act, Widelands::wwWARE, economy)),
1078- worker_panel_(new EconomyOptionsPanel(&tabpanel_, can_act, Widelands::wwWORKER, economy)) {
1079+ ware_panel_(new EconomyOptionsPanel(&tabpanel_, serial_, player_, can_act, Widelands::wwWARE)),
1080+ worker_panel_(new EconomyOptionsPanel(&tabpanel_, serial_, player_, can_act, Widelands::wwWORKER)) {
1081 set_center_panel(&tabpanel_);
1082
1083 tabpanel_.add("wares", g_gr->images().get(pic_tab_wares), ware_panel_, _("Wares"));
1084@@ -50,27 +51,29 @@
1085 }
1086
1087 EconomyOptionsWindow::~EconomyOptionsWindow() {
1088- if (economy_ != nullptr) {
1089- economy_->set_has_window(false);
1090+ Widelands::Economy* economy = player_->get_economy(serial_);
1091+ if (economy != nullptr) {
1092+ economy->set_has_window(false);
1093 }
1094 }
1095
1096 void EconomyOptionsWindow::on_economy_note(const Widelands::NoteEconomy& note) {
1097- if (note.old_economy == economy_) {
1098+ if (note.old_economy == serial_) {
1099 switch (note.action) {
1100- case Widelands::NoteEconomy::Action::kMerged:
1101- economy_ = note.new_economy;
1102+ case Widelands::NoteEconomy::Action::kMerged: {
1103+ serial_ = note.new_economy;
1104+ Widelands::Economy* economy = player_->get_economy(serial_);
1105+ if (economy == nullptr) {
1106+ die();
1107+ return;
1108+ }
1109+ economy->set_has_window(true);
1110 ware_panel_->set_economy(note.new_economy);
1111 worker_panel_->set_economy(note.new_economy);
1112- economy_->set_has_window(true);
1113 move_to_top();
1114- break;
1115+ } break;
1116 case Widelands::NoteEconomy::Action::kDeleted:
1117 // Make sure that the panels stop thinking first.
1118- ware_panel_->die();
1119- worker_panel_->die();
1120- economy_->set_has_window(false);
1121- economy_ = nullptr;
1122 die();
1123 break;
1124 }
1125@@ -80,12 +83,13 @@
1126 EconomyOptionsWindow::TargetWaresDisplay::TargetWaresDisplay(UI::Panel* const parent,
1127 int32_t const x,
1128 int32_t const y,
1129+ Widelands::Serial serial,
1130+ Widelands::Player* player,
1131 Widelands::WareWorker type,
1132- bool selectable,
1133- Widelands::Economy* economy)
1134- : AbstractWaresDisplay(parent, x, y, economy->owner().tribe(), type, selectable),
1135- economy_(economy) {
1136- const Widelands::TribeDescr& owner_tribe = economy->owner().tribe();
1137+ bool selectable)
1138+ : AbstractWaresDisplay(parent, x, y, player->tribe(), type, selectable),
1139+ serial_(serial), player_(player) {
1140+ const Widelands::TribeDescr& owner_tribe = player->tribe();
1141 if (type == Widelands::wwWORKER) {
1142 for (const Widelands::DescriptionIndex& worker_index : owner_tribe.workers()) {
1143 const Widelands::WorkerDescr* worker_descr = owner_tribe.get_worker_descr(worker_index);
1144@@ -103,29 +107,36 @@
1145 }
1146 }
1147
1148-void EconomyOptionsWindow::TargetWaresDisplay::set_economy(Widelands::Economy* economy) {
1149- economy_ = economy;
1150+void EconomyOptionsWindow::TargetWaresDisplay::set_economy(Widelands::Serial serial) {
1151+ serial_ = serial;
1152 }
1153
1154 std::string
1155 EconomyOptionsWindow::TargetWaresDisplay::info_for_ware(Widelands::DescriptionIndex const ware) {
1156+ Widelands::Economy* economy = player_->get_economy(serial_);
1157+ if (economy == nullptr) {
1158+ die();
1159+ return *(new std::string());
1160+ }
1161 return boost::lexical_cast<std::string>(get_type() == Widelands::wwWORKER ?
1162- economy_->worker_target_quantity(ware).permanent :
1163- economy_->ware_target_quantity(ware).permanent);
1164+ economy->worker_target_quantity(ware).permanent :
1165+ economy->ware_target_quantity(ware).permanent);
1166 }
1167
1168 /**
1169 * Wraps the wares/workers display together with some buttons
1170 */
1171 EconomyOptionsWindow::EconomyOptionsPanel::EconomyOptionsPanel(UI::Panel* parent,
1172+ Widelands::Serial serial,
1173+ Widelands::Player* player,
1174 bool can_act,
1175- Widelands::WareWorker type,
1176- Widelands::Economy* economy)
1177+ Widelands::WareWorker type)
1178 : UI::Box(parent, 0, 0, UI::Box::Vertical),
1179+ serial_(serial),
1180+ player_(player),
1181 type_(type),
1182- economy_(economy),
1183 can_act_(can_act),
1184- display_(this, 0, 0, type_, can_act_, economy) {
1185+ display_(this, 0, 0, serial_, player_, type_, can_act_) {
1186 add(&display_, UI::Box::Resizing::kFullSize);
1187
1188 if (!can_act_) {
1189@@ -154,37 +165,34 @@
1190 buttons->add(b);
1191 }
1192
1193-void EconomyOptionsWindow::EconomyOptionsPanel::set_economy(Widelands::Economy* economy) {
1194- economy_ = economy;
1195- display_.set_economy(economy);
1196+void EconomyOptionsWindow::EconomyOptionsPanel::set_economy(Widelands::Serial serial) {
1197+ serial_ = serial;
1198+ display_.set_economy(serial);
1199 }
1200
1201 void EconomyOptionsWindow::EconomyOptionsPanel::change_target(int amount) {
1202- auto& owner = economy_->owner();
1203- Widelands::Game& game = dynamic_cast<Widelands::Game&>(owner.egbase());
1204+ Widelands::Economy* economy = player_->get_economy(serial_);
1205+ if (economy == nullptr) {
1206+ die();
1207+ return;
1208+ }
1209+ Widelands::Game& game = dynamic_cast<Widelands::Game&>(player_->egbase());
1210 const bool is_wares = type_ == Widelands::wwWARE;
1211- const auto& items = is_wares ? owner.tribe().wares() : owner.tribe().workers();
1212+ const auto& items = is_wares ? player_->tribe().wares() : player_->tribe().workers();
1213 for (const Widelands::DescriptionIndex& index : items) {
1214 if (display_.ware_selected(index)) {
1215- const Widelands::Economy::TargetQuantity& tq = is_wares ?
1216- economy_->ware_target_quantity(index) :
1217- economy_->worker_target_quantity(index);
1218+ const Widelands::Economy::TargetQuantity& tq =
1219+ is_wares ? economy->ware_target_quantity(index) : economy->worker_target_quantity(index);
1220 // Don't allow negative new amount.
1221 if (amount >= 0 || -amount <= static_cast<int>(tq.permanent)) {
1222 if (is_wares) {
1223- // TODO(sirver): This is crashy. Nobody guarantees that the
1224- // economy_number_ is still the same when this command finally
1225- // is executed. Player::remove_economy relabels economies on
1226- // deletion. Economies require a unique, never changing id, same
1227- // as map objects.
1228 game.send_player_command(*new Widelands::CmdSetWareTargetQuantity(
1229- game.get_gametime(), owner.player_number(), owner.get_economy_number(economy_),
1230+ game.get_gametime(), player_->player_number(), serial_,
1231 index, tq.permanent + amount));
1232 } else {
1233- // TODO(sirver): Same as above
1234 game.send_player_command(*new Widelands::CmdSetWorkerTargetQuantity(
1235- game.get_gametime(), owner.player_number(), owner.get_economy_number(economy_),
1236- index, tq.permanent + amount));
1237+ game.get_gametime(), player_->player_number(), serial_, index,
1238+ tq.permanent + amount));
1239 }
1240 }
1241 }
1242@@ -192,19 +200,18 @@
1243 }
1244
1245 void EconomyOptionsWindow::EconomyOptionsPanel::reset_target() {
1246- auto& owner = economy_->owner();
1247- Widelands::Game& game = dynamic_cast<Widelands::Game&>(owner.egbase());
1248+ Widelands::Game& game = dynamic_cast<Widelands::Game&>(player_->egbase());
1249 const bool is_wares = type_ == Widelands::wwWARE;
1250- const auto& items = is_wares ? owner.tribe().wares() : owner.tribe().workers();
1251+ const auto& items = is_wares ? player_->tribe().wares() : player_->tribe().workers();
1252 for (const Widelands::DescriptionIndex& index : items) {
1253 if (display_.ware_selected(index)) {
1254 if (is_wares) {
1255 game.send_player_command(*new Widelands::CmdResetWareTargetQuantity(
1256- game.get_gametime(), owner.player_number(), owner.get_economy_number(economy_),
1257+ game.get_gametime(), player_->player_number(), serial_,
1258 index));
1259 } else {
1260 game.send_player_command(*new Widelands::CmdResetWorkerTargetQuantity(
1261- game.get_gametime(), owner.player_number(), owner.get_economy_number(economy_),
1262+ game.get_gametime(), player_->player_number(), serial_,
1263 index));
1264 }
1265 }
1266
1267=== modified file 'src/wui/economy_options_window.h'
1268--- src/wui/economy_options_window.h 2018-04-07 16:59:00 +0000
1269+++ src/wui/economy_options_window.h 2018-07-11 08:33:43 +0000
1270@@ -39,17 +39,19 @@
1271 TargetWaresDisplay(UI::Panel* const parent,
1272 int32_t const x,
1273 int32_t const y,
1274+ Widelands::Serial serial,
1275+ Widelands::Player* player,
1276 Widelands::WareWorker type,
1277- bool selectable,
1278- Widelands::Economy* economy);
1279+ bool selectable);
1280
1281- void set_economy(Widelands::Economy*);
1282+ void set_economy(Widelands::Serial serial);
1283
1284 protected:
1285 std::string info_for_ware(Widelands::DescriptionIndex const ware) override;
1286
1287 private:
1288- Widelands::Economy* economy_;
1289+ Widelands::Serial serial_;
1290+ Widelands::Player* player_;
1291 };
1292
1293 /**
1294@@ -57,17 +59,19 @@
1295 */
1296 struct EconomyOptionsPanel : UI::Box {
1297 EconomyOptionsPanel(UI::Panel* parent,
1298+ Widelands::Serial serial,
1299+ Widelands::Player* player,
1300 bool can_act,
1301- Widelands::WareWorker type,
1302- Widelands::Economy* economy);
1303+ Widelands::WareWorker type);
1304
1305- void set_economy(Widelands::Economy*);
1306+ void set_economy(Widelands::Serial serial);
1307 void change_target(int amount);
1308 void reset_target();
1309
1310 private:
1311+ Widelands::Serial serial_;
1312+ Widelands::Player* player_;
1313 Widelands::WareWorker type_;
1314- Widelands::Economy* economy_;
1315 bool can_act_;
1316 TargetWaresDisplay display_;
1317 };
1318@@ -75,7 +79,8 @@
1319 /// Actions performed when a NoteEconomyWindow is received.
1320 void on_economy_note(const Widelands::NoteEconomy& note);
1321
1322- Widelands::Economy* economy_;
1323+ Widelands::Serial serial_;
1324+ Widelands::Player* player_;
1325 UI::TabPanel tabpanel_;
1326 EconomyOptionsPanel* ware_panel_;
1327 EconomyOptionsPanel* worker_panel_;
1328
1329=== modified file 'src/wui/stock_menu.cc'
1330--- src/wui/stock_menu.cc 2018-04-27 06:11:05 +0000
1331+++ src/wui/stock_menu.cc 2018-07-11 08:33:43 +0000
1332@@ -75,11 +75,9 @@
1333 void StockMenu::fill_total_waresdisplay(WaresDisplay* waresdisplay, Widelands::WareWorker type) {
1334 waresdisplay->remove_all_warelists();
1335 const Widelands::Player& player = *player_.get_player();
1336- const uint32_t nrecos = player.get_nr_economies();
1337- for (uint32_t i = 0; i < nrecos; ++i)
1338- waresdisplay->add_warelist(type == Widelands::wwWARE ?
1339- player.get_economy_by_number(i)->get_wares() :
1340- player.get_economy_by_number(i)->get_workers());
1341+ for (const auto& economy : player.economies()) {
1342+ waresdisplay->add_warelist(type == Widelands::wwWARE ? economy.second->get_wares() : economy.second->get_workers());
1343+ }
1344 }
1345
1346 /**
1347@@ -89,16 +87,10 @@
1348 void StockMenu::fill_warehouse_waresdisplay(WaresDisplay* waresdisplay,
1349 Widelands::WareWorker type) {
1350 waresdisplay->remove_all_warelists();
1351- const Widelands::Player& player = *player_.get_player();
1352- const uint32_t nrecos = player.get_nr_economies();
1353- for (uint32_t i = 0; i < nrecos; ++i) {
1354- const std::vector<Widelands::Warehouse*>& warehouses =
1355- player.get_economy_by_number(i)->warehouses();
1356-
1357- for (std::vector<Widelands::Warehouse*>::const_iterator it = warehouses.begin();
1358- it != warehouses.end(); ++it) {
1359- waresdisplay->add_warelist(type == Widelands::wwWARE ? (*it)->get_wares() :
1360- (*it)->get_workers());
1361+ for (const auto& economy : player_.player().economies()) {
1362+ for (const auto* warehouse: economy.second->warehouses()) {
1363+ waresdisplay->add_warelist(type == Widelands::wwWARE ? warehouse->get_wares() :
1364+ warehouse->get_workers());
1365 }
1366 }
1367 }
1368
1369=== removed file 'test/maps/Aquila.wmf/binary/bob'
1370Binary files test/maps/Aquila.wmf/binary/bob 2016-08-13 18:47:51 +0000 and test/maps/Aquila.wmf/binary/bob 1970-01-01 00:00:00 +0000 differ
1371=== removed file 'test/maps/Aquila.wmf/binary/bob_data'
1372Binary files test/maps/Aquila.wmf/binary/bob_data 2016-08-13 18:47:51 +0000 and test/maps/Aquila.wmf/binary/bob_data 1970-01-01 00:00:00 +0000 differ
1373=== removed file 'test/maps/Aquila.wmf/binary/building'
1374Binary files test/maps/Aquila.wmf/binary/building 2016-08-13 18:47:51 +0000 and test/maps/Aquila.wmf/binary/building 1970-01-01 00:00:00 +0000 differ
1375=== added file 'test/maps/Aquila.wmf/binary/exploration'
1376Binary files test/maps/Aquila.wmf/binary/exploration 1970-01-01 00:00:00 +0000 and test/maps/Aquila.wmf/binary/exploration 2018-07-11 08:33:43 +0000 differ
1377=== removed file 'test/maps/Aquila.wmf/binary/exploration'
1378Binary files test/maps/Aquila.wmf/binary/exploration 2016-08-13 18:47:51 +0000 and test/maps/Aquila.wmf/binary/exploration 1970-01-01 00:00:00 +0000 differ
1379=== removed file 'test/maps/Aquila.wmf/binary/flag'
1380Binary files test/maps/Aquila.wmf/binary/flag 2016-08-13 18:47:51 +0000 and test/maps/Aquila.wmf/binary/flag 1970-01-01 00:00:00 +0000 differ
1381=== modified file 'test/maps/Aquila.wmf/binary/mapobjects'
1382Binary files test/maps/Aquila.wmf/binary/mapobjects 2016-08-13 18:47:51 +0000 and test/maps/Aquila.wmf/binary/mapobjects 2018-07-11 08:33:43 +0000 differ
1383=== added file 'test/maps/Aquila.wmf/binary/node_ownership'
1384Binary files test/maps/Aquila.wmf/binary/node_ownership 1970-01-01 00:00:00 +0000 and test/maps/Aquila.wmf/binary/node_ownership 2018-07-11 08:33:43 +0000 differ
1385=== removed file 'test/maps/Aquila.wmf/binary/node_ownership'
1386Binary files test/maps/Aquila.wmf/binary/node_ownership 2016-08-13 18:47:51 +0000 and test/maps/Aquila.wmf/binary/node_ownership 1970-01-01 00:00:00 +0000 differ
1387=== modified file 'test/maps/Aquila.wmf/binary/resource'
1388Binary files test/maps/Aquila.wmf/binary/resource 2016-08-13 18:47:51 +0000 and test/maps/Aquila.wmf/binary/resource 2018-07-11 08:33:43 +0000 differ
1389=== removed file 'test/maps/Aquila.wmf/binary/road'
1390Binary files test/maps/Aquila.wmf/binary/road 2016-08-13 18:47:51 +0000 and test/maps/Aquila.wmf/binary/road 1970-01-01 00:00:00 +0000 differ
1391=== modified file 'test/maps/Aquila.wmf/binary/terrain'
1392Binary files test/maps/Aquila.wmf/binary/terrain 2016-08-13 18:47:51 +0000 and test/maps/Aquila.wmf/binary/terrain 2018-07-11 08:33:43 +0000 differ
1393=== removed file 'test/maps/Aquila.wmf/binary/ware'
1394Binary files test/maps/Aquila.wmf/binary/ware 2016-08-13 18:47:51 +0000 and test/maps/Aquila.wmf/binary/ware 1970-01-01 00:00:00 +0000 differ
1395=== removed file 'test/maps/expedition.wmf/binary/building'
1396Binary files test/maps/expedition.wmf/binary/building 2013-10-05 07:50:17 +0000 and test/maps/expedition.wmf/binary/building 1970-01-01 00:00:00 +0000 differ
1397=== added file 'test/maps/expedition.wmf/binary/exploration'
1398Binary files test/maps/expedition.wmf/binary/exploration 1970-01-01 00:00:00 +0000 and test/maps/expedition.wmf/binary/exploration 2018-07-11 08:33:43 +0000 differ
1399=== removed file 'test/maps/expedition.wmf/binary/exploration'
1400Binary files test/maps/expedition.wmf/binary/exploration 2013-10-05 07:50:17 +0000 and test/maps/expedition.wmf/binary/exploration 1970-01-01 00:00:00 +0000 differ
1401=== removed file 'test/maps/expedition.wmf/binary/flag'
1402Binary files test/maps/expedition.wmf/binary/flag 2013-10-05 07:50:17 +0000 and test/maps/expedition.wmf/binary/flag 1970-01-01 00:00:00 +0000 differ
1403=== modified file 'test/maps/expedition.wmf/binary/mapobjects'
1404Binary files test/maps/expedition.wmf/binary/mapobjects 2013-10-05 07:50:17 +0000 and test/maps/expedition.wmf/binary/mapobjects 2018-07-11 08:33:43 +0000 differ
1405=== added file 'test/maps/expedition.wmf/binary/node_ownership'
1406Binary files test/maps/expedition.wmf/binary/node_ownership 1970-01-01 00:00:00 +0000 and test/maps/expedition.wmf/binary/node_ownership 2018-07-11 08:33:43 +0000 differ
1407=== removed file 'test/maps/expedition.wmf/binary/node_ownership'
1408Binary files test/maps/expedition.wmf/binary/node_ownership 2013-10-05 07:50:17 +0000 and test/maps/expedition.wmf/binary/node_ownership 1970-01-01 00:00:00 +0000 differ
1409=== modified file 'test/maps/expedition.wmf/binary/resource'
1410Binary files test/maps/expedition.wmf/binary/resource 2015-04-14 19:03:11 +0000 and test/maps/expedition.wmf/binary/resource 2018-07-11 08:33:43 +0000 differ
1411=== removed file 'test/maps/expedition.wmf/binary/road'
1412Binary files test/maps/expedition.wmf/binary/road 2013-10-05 07:50:17 +0000 and test/maps/expedition.wmf/binary/road 1970-01-01 00:00:00 +0000 differ
1413=== modified file 'test/maps/expedition.wmf/binary/terrain'
1414Binary files test/maps/expedition.wmf/binary/terrain 2015-04-14 19:03:11 +0000 and test/maps/expedition.wmf/binary/terrain 2018-07-11 08:33:43 +0000 differ
1415=== removed file 'test/maps/lua_persistence.wmf/binary/bob'
1416Binary files test/maps/lua_persistence.wmf/binary/bob 2012-02-15 21:25:34 +0000 and test/maps/lua_persistence.wmf/binary/bob 1970-01-01 00:00:00 +0000 differ
1417=== removed file 'test/maps/lua_persistence.wmf/binary/building'
1418Binary files test/maps/lua_persistence.wmf/binary/building 2015-04-15 10:06:45 +0000 and test/maps/lua_persistence.wmf/binary/building 1970-01-01 00:00:00 +0000 differ
1419=== added file 'test/maps/lua_persistence.wmf/binary/exploration'
1420Binary files test/maps/lua_persistence.wmf/binary/exploration 1970-01-01 00:00:00 +0000 and test/maps/lua_persistence.wmf/binary/exploration 2018-07-11 08:33:43 +0000 differ
1421=== removed file 'test/maps/lua_persistence.wmf/binary/exploration'
1422Binary files test/maps/lua_persistence.wmf/binary/exploration 2012-02-15 21:25:34 +0000 and test/maps/lua_persistence.wmf/binary/exploration 1970-01-01 00:00:00 +0000 differ
1423=== removed file 'test/maps/lua_persistence.wmf/binary/flag'
1424Binary files test/maps/lua_persistence.wmf/binary/flag 2012-02-15 21:25:34 +0000 and test/maps/lua_persistence.wmf/binary/flag 1970-01-01 00:00:00 +0000 differ
1425=== modified file 'test/maps/lua_persistence.wmf/binary/mapobjects'
1426Binary files test/maps/lua_persistence.wmf/binary/mapobjects 2012-02-15 21:25:34 +0000 and test/maps/lua_persistence.wmf/binary/mapobjects 2018-07-11 08:33:43 +0000 differ
1427=== added file 'test/maps/lua_persistence.wmf/binary/node_ownership'
1428Binary files test/maps/lua_persistence.wmf/binary/node_ownership 1970-01-01 00:00:00 +0000 and test/maps/lua_persistence.wmf/binary/node_ownership 2018-07-11 08:33:43 +0000 differ
1429=== removed file 'test/maps/lua_persistence.wmf/binary/node_ownership'
1430Binary files test/maps/lua_persistence.wmf/binary/node_ownership 2012-02-15 21:25:34 +0000 and test/maps/lua_persistence.wmf/binary/node_ownership 1970-01-01 00:00:00 +0000 differ
1431=== modified file 'test/maps/lua_persistence.wmf/binary/resource'
1432Binary files test/maps/lua_persistence.wmf/binary/resource 2012-02-15 21:25:34 +0000 and test/maps/lua_persistence.wmf/binary/resource 2018-07-11 08:33:43 +0000 differ
1433=== removed file 'test/maps/lua_persistence.wmf/binary/road'
1434Binary files test/maps/lua_persistence.wmf/binary/road 2012-02-15 21:25:34 +0000 and test/maps/lua_persistence.wmf/binary/road 1970-01-01 00:00:00 +0000 differ
1435=== modified file 'test/maps/lua_persistence.wmf/binary/terrain'
1436Binary files test/maps/lua_persistence.wmf/binary/terrain 2012-02-15 21:25:34 +0000 and test/maps/lua_persistence.wmf/binary/terrain 2018-07-11 08:33:43 +0000 differ
1437=== removed file 'test/maps/lua_testsuite.wmf/binary/bob'
1438Binary files test/maps/lua_testsuite.wmf/binary/bob 2012-02-15 21:25:34 +0000 and test/maps/lua_testsuite.wmf/binary/bob 1970-01-01 00:00:00 +0000 differ
1439=== removed file 'test/maps/lua_testsuite.wmf/binary/building'
1440Binary files test/maps/lua_testsuite.wmf/binary/building 2015-04-14 18:34:40 +0000 and test/maps/lua_testsuite.wmf/binary/building 1970-01-01 00:00:00 +0000 differ
1441=== added file 'test/maps/lua_testsuite.wmf/binary/exploration'
1442Binary files test/maps/lua_testsuite.wmf/binary/exploration 1970-01-01 00:00:00 +0000 and test/maps/lua_testsuite.wmf/binary/exploration 2018-07-11 08:33:43 +0000 differ
1443=== removed file 'test/maps/lua_testsuite.wmf/binary/exploration'
1444Binary files test/maps/lua_testsuite.wmf/binary/exploration 2015-04-14 18:34:40 +0000 and test/maps/lua_testsuite.wmf/binary/exploration 1970-01-01 00:00:00 +0000 differ
1445=== removed file 'test/maps/lua_testsuite.wmf/binary/flag'
1446Binary files test/maps/lua_testsuite.wmf/binary/flag 2015-04-14 18:34:40 +0000 and test/maps/lua_testsuite.wmf/binary/flag 1970-01-01 00:00:00 +0000 differ
1447=== modified file 'test/maps/lua_testsuite.wmf/binary/mapobjects'
1448Binary files test/maps/lua_testsuite.wmf/binary/mapobjects 2015-04-14 18:34:40 +0000 and test/maps/lua_testsuite.wmf/binary/mapobjects 2018-07-11 08:33:43 +0000 differ
1449=== added file 'test/maps/lua_testsuite.wmf/binary/node_ownership'
1450Binary files test/maps/lua_testsuite.wmf/binary/node_ownership 1970-01-01 00:00:00 +0000 and test/maps/lua_testsuite.wmf/binary/node_ownership 2018-07-11 08:33:43 +0000 differ
1451=== removed file 'test/maps/lua_testsuite.wmf/binary/node_ownership'
1452Binary files test/maps/lua_testsuite.wmf/binary/node_ownership 2015-04-14 18:34:40 +0000 and test/maps/lua_testsuite.wmf/binary/node_ownership 1970-01-01 00:00:00 +0000 differ
1453=== modified file 'test/maps/lua_testsuite.wmf/binary/resource'
1454Binary files test/maps/lua_testsuite.wmf/binary/resource 2015-04-14 18:34:40 +0000 and test/maps/lua_testsuite.wmf/binary/resource 2018-07-11 08:33:43 +0000 differ
1455=== removed file 'test/maps/lua_testsuite.wmf/binary/road'
1456Binary files test/maps/lua_testsuite.wmf/binary/road 2015-04-14 18:34:40 +0000 and test/maps/lua_testsuite.wmf/binary/road 1970-01-01 00:00:00 +0000 differ
1457=== modified file 'test/maps/lua_testsuite.wmf/binary/terrain'
1458Binary files test/maps/lua_testsuite.wmf/binary/terrain 2015-04-14 18:34:40 +0000 and test/maps/lua_testsuite.wmf/binary/terrain 2018-07-11 08:33:43 +0000 differ
1459=== removed file 'test/maps/plain.wmf/binary/building'
1460Binary files test/maps/plain.wmf/binary/building 2014-06-20 14:38:48 +0000 and test/maps/plain.wmf/binary/building 1970-01-01 00:00:00 +0000 differ
1461=== added file 'test/maps/plain.wmf/binary/exploration'
1462Binary files test/maps/plain.wmf/binary/exploration 1970-01-01 00:00:00 +0000 and test/maps/plain.wmf/binary/exploration 2018-07-11 08:33:43 +0000 differ
1463=== removed file 'test/maps/plain.wmf/binary/exploration'
1464Binary files test/maps/plain.wmf/binary/exploration 2014-06-20 14:38:48 +0000 and test/maps/plain.wmf/binary/exploration 1970-01-01 00:00:00 +0000 differ
1465=== removed file 'test/maps/plain.wmf/binary/flag'
1466Binary files test/maps/plain.wmf/binary/flag 2014-06-20 14:38:48 +0000 and test/maps/plain.wmf/binary/flag 1970-01-01 00:00:00 +0000 differ
1467=== modified file 'test/maps/plain.wmf/binary/mapobjects'
1468Binary files test/maps/plain.wmf/binary/mapobjects 2014-06-20 14:38:48 +0000 and test/maps/plain.wmf/binary/mapobjects 2018-07-11 08:33:43 +0000 differ
1469=== added file 'test/maps/plain.wmf/binary/node_ownership'
1470Binary files test/maps/plain.wmf/binary/node_ownership 1970-01-01 00:00:00 +0000 and test/maps/plain.wmf/binary/node_ownership 2018-07-11 08:33:43 +0000 differ
1471=== removed file 'test/maps/plain.wmf/binary/node_ownership'
1472Binary files test/maps/plain.wmf/binary/node_ownership 2014-06-20 14:38:48 +0000 and test/maps/plain.wmf/binary/node_ownership 1970-01-01 00:00:00 +0000 differ
1473=== modified file 'test/maps/plain.wmf/binary/resource'
1474Binary files test/maps/plain.wmf/binary/resource 2014-06-22 17:09:42 +0000 and test/maps/plain.wmf/binary/resource 2018-07-11 08:33:43 +0000 differ
1475=== removed file 'test/maps/plain.wmf/binary/road'
1476Binary files test/maps/plain.wmf/binary/road 2014-06-20 14:38:48 +0000 and test/maps/plain.wmf/binary/road 1970-01-01 00:00:00 +0000 differ
1477=== modified file 'test/maps/plain.wmf/binary/terrain'
1478Binary files test/maps/plain.wmf/binary/terrain 2014-06-22 17:09:42 +0000 and test/maps/plain.wmf/binary/terrain 2018-07-11 08:33:43 +0000 differ
1479=== modified file 'test/maps/port_space.wmf/binary/mapobjects'
1480Binary files test/maps/port_space.wmf/binary/mapobjects 2016-02-08 20:44:17 +0000 and test/maps/port_space.wmf/binary/mapobjects 2018-07-11 08:33:43 +0000 differ
1481=== modified file 'test/maps/port_space.wmf/binary/terrain'
1482Binary files test/maps/port_space.wmf/binary/terrain 2016-02-08 20:44:17 +0000 and test/maps/port_space.wmf/binary/terrain 2018-07-11 08:33:43 +0000 differ
1483=== removed file 'test/maps/ship_transportation.wmf/binary/building'
1484Binary files test/maps/ship_transportation.wmf/binary/building 2013-10-31 18:52:52 +0000 and test/maps/ship_transportation.wmf/binary/building 1970-01-01 00:00:00 +0000 differ
1485=== added file 'test/maps/ship_transportation.wmf/binary/exploration'
1486Binary files test/maps/ship_transportation.wmf/binary/exploration 1970-01-01 00:00:00 +0000 and test/maps/ship_transportation.wmf/binary/exploration 2018-07-11 08:33:43 +0000 differ
1487=== removed file 'test/maps/ship_transportation.wmf/binary/exploration'
1488Binary files test/maps/ship_transportation.wmf/binary/exploration 2013-10-31 18:52:52 +0000 and test/maps/ship_transportation.wmf/binary/exploration 1970-01-01 00:00:00 +0000 differ
1489=== removed file 'test/maps/ship_transportation.wmf/binary/flag'
1490Binary files test/maps/ship_transportation.wmf/binary/flag 2013-10-31 18:52:52 +0000 and test/maps/ship_transportation.wmf/binary/flag 1970-01-01 00:00:00 +0000 differ
1491=== modified file 'test/maps/ship_transportation.wmf/binary/mapobjects'
1492Binary files test/maps/ship_transportation.wmf/binary/mapobjects 2013-10-31 18:52:52 +0000 and test/maps/ship_transportation.wmf/binary/mapobjects 2018-07-11 08:33:43 +0000 differ
1493=== added file 'test/maps/ship_transportation.wmf/binary/node_ownership'
1494Binary files test/maps/ship_transportation.wmf/binary/node_ownership 1970-01-01 00:00:00 +0000 and test/maps/ship_transportation.wmf/binary/node_ownership 2018-07-11 08:33:43 +0000 differ
1495=== removed file 'test/maps/ship_transportation.wmf/binary/node_ownership'
1496Binary files test/maps/ship_transportation.wmf/binary/node_ownership 2013-10-31 18:52:52 +0000 and test/maps/ship_transportation.wmf/binary/node_ownership 1970-01-01 00:00:00 +0000 differ
1497=== modified file 'test/maps/ship_transportation.wmf/binary/resource'
1498Binary files test/maps/ship_transportation.wmf/binary/resource 2013-10-31 18:52:52 +0000 and test/maps/ship_transportation.wmf/binary/resource 2018-07-11 08:33:43 +0000 differ
1499=== removed file 'test/maps/ship_transportation.wmf/binary/road'
1500Binary files test/maps/ship_transportation.wmf/binary/road 2013-10-31 18:52:52 +0000 and test/maps/ship_transportation.wmf/binary/road 1970-01-01 00:00:00 +0000 differ
1501=== modified file 'test/maps/ship_transportation.wmf/binary/terrain'
1502Binary files test/maps/ship_transportation.wmf/binary/terrain 2013-10-31 18:52:52 +0000 and test/maps/ship_transportation.wmf/binary/terrain 2018-07-11 08:33:43 +0000 differ

Subscribers

People subscribed via source and target branches

to status/vote changes: