Merge lp:~widelands-dev/widelands/map_compatibility into lp:widelands

Proposed by GunChleoc
Status: Rejected
Rejected by: GunChleoc
Proposed branch: lp:~widelands-dev/widelands/map_compatibility
Merge into: lp:widelands
Diff against target: 1151 lines (+574/-196)
10 files modified
src/logic/expedition_bootstrap.cc (+25/-13)
src/logic/expedition_bootstrap.h (+3/-2)
src/map_io/map_buildingdata_packet.cc (+302/-95)
src/map_io/map_buildingdata_packet.h (+4/-0)
src/map_io/map_exploration_packet.cc (+15/-1)
src/map_io/map_flagdata_packet.cc (+53/-3)
src/map_io/map_player_names_and_tribes_packet.cc (+1/-2)
src/map_io/map_players_view_packet.cc (+141/-64)
src/map_io/map_roaddata_packet.cc (+22/-5)
src/map_io/map_scripting_packet.cc (+8/-11)
To merge this branch: bzr merge lp:~widelands-dev/widelands/map_compatibility
Reviewer Review Type Date Requested Status
SirVer Needs Information
Review via email: mp+276088@code.launchpad.net

Description of the change

There is a problem with loading older maps, so I put the remaining compatibility code for maps back in.

It was removed in r7558.

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

Hi GunChleoc,

Looking at the changes, I was wondering what kind of problems were faced - I wasn't monitoring the project for roughly 1,5 years, so I am a not that up to date, sorry.
Is there one or more bug reports explaining the problem?

Is this merge request about savegames or about maps? I am asking because a lot of the code handles tribe objects like buildings, workers, wares, etc. However as far as I remember, there was no way to build up an economy in the editor in Build18 (is there now?) - so I wonder whether that code is really needed for loading maps of Build18 or Build17.

Revision history for this message
GunChleoc (gunchleoc) wrote :

Hi Nasenbaer,

the history here is that I recently removed all savegame compatibility code. I assumed te same thing that you do, thet maps would not know about buildings, workers etc. Turns out they do, so we get cpmpatibility problems with maps. I think one of he problematic maps was Together We're Strong - load it in he Editor to trigger the problem.

Revision history for this message
Nasenbaer (nasenbaer) wrote :

Hi GunChleoc,

okay, I see the problem - in this case it's the files below "player" in the map directory. Which aren't loaded when starting a game anyways - that's why the error is triggered in the editor, but not when starting a new game.

Speaking of "Together we're strong" - for some reason I committed the map with the player directory. However I am not sure whether that was on purpose or not. Anyways, as the player directory is not loaded during starting a game, it can clearly be deleted - this will indeed fix the problem in the editor as well.

Anyway this would not fix player created maps from Build18 or before, as these contain the player directory as well. However to those applies the same as to "Together we're strong" - the player directory is not loaded during starting a game.

Long text short sense: I would prefere to handle it the same in the editor - simply do not load the files. And if loading the files is needed for some reason with newer maps - don't load if the map is too old.

What do you think?

Revision history for this message
GunChleoc (gunchleoc) wrote :

Yes, I would like that - you obviously know a lot more about the map loading code than I do. Would you like to take this on?

Revision history for this message
TiborB (tiborb95) wrote :

So this fix is to allow editing of old maps? And all what is needed to edit them is to remove some directory from wmf archive? Then I would not reintroduce logic that was removed, but just left it unfixed or put an info in error test saying what should be done to make the map loadable in editor again. I think there is so little peoples to be affected by this that this would be much better workaround.

Revision history for this message
GunChleoc (gunchleoc) wrote :

I agree - the code control flow is a bit complex though, so I have to find out how to pull this off. I think that this sill probably best done in a fresh branch.

Revision history for this message
bunnybot (widelandsofficial) wrote :

Hi, I am bunnybot (https://github.com/widelands/bunnybot).

I am keeping the source branch lp:~widelands-dev/widelands/map_compatibility mirrored to
  https://github.com/widelands/widelands/tree/_widelands_dev_widelands_map_compatibility

The latest continuous integration build can always be found here:
  https://travis-ci.org/widelands/widelands/branches
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.

Revision history for this message
bunnybot (widelandsofficial) wrote :

Travis build 122 has changed state to: failed. Details: https://travis-ci.org/widelands/widelands/builds/99778652.

Revision history for this message
bunnybot (widelandsofficial) wrote :

Travis build 122 has changed state to: failed. Details: https://travis-ci.org/widelands/widelands/builds/99778652.

Revision history for this message
bunnybot (widelandsofficial) wrote :

Bunnybot encountered an error while working on this merge proposal:

Running 'git push github _widelands_dev_widelands_map_compatibility' failed. Output:

ssh: Could not resolve hostname github.com: Name or service not known
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.

Revision history for this message
bunnybot (widelandsofficial) wrote :

Bunnybot encountered an error while working on this merge proposal:

<urlopen error [Errno -2] Name or service not known>

Revision history for this message
bunnybot (widelandsofficial) wrote :

Travis build 122 has changed state to: failed. Details: https://travis-ci.org/widelands/widelands/builds/99778652.

Revision history for this message
bunnybot (widelandsofficial) wrote :

Travis build 122 has changed state to: failed. Details: https://travis-ci.org/widelands/widelands/builds/99778652.

Revision history for this message
bunnybot (widelandsofficial) wrote :

Bunnybot encountered an error while working on this merge proposal:

<urlopen error [Errno -2] Name or service not known>

Revision history for this message
bunnybot (widelandsofficial) wrote :

Bunnybot encountered an error while working on this merge proposal:

<urlopen error [Errno -2] Name or service not known>

Revision history for this message
SirVer (sirver) wrote :

Is there a way I can trigger the bug this is trying to fix in trunk? Together we're strong loaded just fine in the editor for me and so did every other shipped map I tried.

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

We have updated Together We're Strong because of the artifacts, so you will need to grab the map from Build 18.

I actually want to take a different approach to this: Rather than putting the compatibility code back in, only load needed packages in the editor. So, this branch is now only sitting here as a reminder.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/logic/expedition_bootstrap.cc'
2--- src/logic/expedition_bootstrap.cc 2015-11-11 09:52:55 +0000
3+++ src/logic/expedition_bootstrap.cc 2015-11-21 10:21:30 +0000
4@@ -260,22 +260,34 @@
5 }
6 }
7
8-void ExpeditionBootstrap::load(Warehouse& warehouse, FileRead& fr,
9- Game& game, MapObjectLoader& mol)
10+constexpr uint16_t kCurrentPacketVersionWarehouse = 6;
11+
12+void ExpeditionBootstrap::load
13+ (uint32_t warehouse_packet_version, Warehouse& warehouse, FileRead& fr,
14+ Game& game, MapObjectLoader& mol)
15 {
16- // Expedition workers
17- const uint8_t num_workers = fr.unsigned_8();
18- for (uint8_t i = 0; i < num_workers; ++i) {
19- workers_.emplace_back(new ExpeditionWorker(nullptr));
20- if (fr.unsigned_8() == 1) {
21- Request* worker_request = new Request
22- (warehouse, 0, ExpeditionBootstrap::worker_callback, wwWORKER);
23- workers_.back()->request.reset(worker_request);
24- worker_request->read(fr, game, mol);
25- workers_.back()->worker = nullptr;
26+ try {
27+ if (warehouse_packet_version >= kCurrentPacketVersionWarehouse) {
28+ // Expedition workers
29+ const uint8_t num_workers = fr.unsigned_8();
30+ for (uint8_t i = 0; i < num_workers; ++i) {
31+ workers_.emplace_back(new ExpeditionWorker(nullptr));
32+ if (fr.unsigned_8() == 1) {
33+ Request* worker_request = new Request
34+ (warehouse, 0, ExpeditionBootstrap::worker_callback, wwWORKER);
35+ workers_.back()->request.reset(worker_request);
36+ worker_request->read(fr, game, mol);
37+ workers_.back()->worker = nullptr;
38+ } else {
39+ workers_.back()->worker = &mol.get<Worker>(fr.unsigned_32());
40+ }
41+ }
42 } else {
43- workers_.back()->worker = &mol.get<Worker>(fr.unsigned_32());
44+ throw UnhandledVersionError("ExpeditionBootstrap",
45+ warehouse_packet_version, kCurrentPacketVersionWarehouse);
46 }
47+ } catch (const WException & e) {
48+ throw wexception("expedition bootstrap: %s", e.what());
49 }
50
51 // Expedition WaresQueues
52
53=== modified file 'src/logic/expedition_bootstrap.h'
54--- src/logic/expedition_bootstrap.h 2015-11-11 09:52:55 +0000
55+++ src/logic/expedition_bootstrap.h 2015-11-21 10:21:30 +0000
56@@ -75,8 +75,9 @@
57
58 // Save/Load this into a file. The actual data is stored in the buildingdata
59 // packet, and there in the warehouse data packet.
60- void load(Warehouse& warehouse, FileRead& fr,
61- Game& game, MapObjectLoader& mol);
62+ void load
63+ (uint32_t warehouse_packet_version, Warehouse& warehouse,
64+ FileRead& fr, Game& game, MapObjectLoader& mol);
65 void save(FileWrite& fw, Game& game, MapObjectSaver& mos);
66
67 private:
68
69=== modified file 'src/map_io/map_buildingdata_packet.cc'
70--- src/map_io/map_buildingdata_packet.cc 2015-11-11 09:53:54 +0000
71+++ src/map_io/map_buildingdata_packet.cc 2015-11-21 10:21:30 +0000
72@@ -52,10 +52,12 @@
73 namespace Widelands {
74
75 // Overall package version
76+// Since V3: m_old_buildings vector
77 constexpr uint16_t kCurrentPacketVersion = 4;
78
79 // Building type package versions
80 constexpr uint16_t kCurrentPacketVersionDismantlesite = 1;
81+// Since V3: m_prev_building not written
82 constexpr uint16_t kCurrentPacketVersionConstructionsite = 3;
83 constexpr uint16_t kCurrentPacketPFBuilding = 1;
84 constexpr uint16_t kCurrentPacketVersionWarehouse = 6;
85@@ -77,9 +79,17 @@
86
87 try {
88 uint16_t const packet_version = fr.unsigned_16();
89- if (packet_version == kCurrentPacketVersion) {
90- while (! fr.end_of_file()) {
91+ if (1 <= packet_version && packet_version <= kCurrentPacketVersion) {
92+ for (;;) {
93+ if (2 <= packet_version && fr.end_of_file())
94+ break;
95 Serial const serial = fr.unsigned_32();
96+ if (packet_version < 2 && serial == 0xffffffff) {
97+ if (!fr.end_of_file())
98+ throw GameDataError
99+ ("expected end of file after serial 0xffffffff");
100+ break;
101+ }
102 try {
103 Building & building = mol.get<Building>(serial);
104
105@@ -202,6 +212,10 @@
106 // {ConstructionSite, Warehouse, ProductionSite}
107 assert(false);
108 }
109+ if (packet_version < 3) {
110+ read_formerbuildings_v2(building, fr, game, mol);
111+ }
112+
113 mol.mark_object_as_loaded(building);
114 } catch (const WException & e) {
115 throw GameDataError("building %u: %s", serial, e.what());
116@@ -215,6 +229,46 @@
117 }
118 }
119
120+void MapBuildingdataPacket::read_formerbuildings_v2
121+ (Building& b, FileRead&, Game&, MapObjectLoader&)
122+{
123+ const TribeDescr & t = b.owner().tribe();
124+ DescriptionIndex b_idx = t.building_index(b.descr().name());
125+ if (is_a(ProductionSite, &b)) {
126+ assert(b.m_old_buildings.empty());
127+ b.m_old_buildings.push_back(b_idx);
128+ } else if (is_a(Warehouse, &b)) {
129+ assert(b.m_old_buildings.empty());
130+ b.m_old_buildings.push_back(b_idx);
131+ } else if (is_a(DismantleSite, &b)) {
132+ // Former buildings filled with the current one
133+ // upon building init.
134+ assert(!b.m_old_buildings.empty());
135+ } else if (is_a(ConstructionSite, &b)) {
136+ // Not needed for csite.
137+ return;
138+ } else {
139+ assert(false);
140+ }
141+
142+ // iterate through all buildings to find first predecessor
143+ for (;;) {
144+ DescriptionIndex former_idx = b.m_old_buildings.front();
145+ const BuildingDescr * oldest = t.get_building_descr(former_idx);
146+ if (!oldest->is_enhanced()) {
147+ break;
148+ }
149+ for (DescriptionIndex i = 0; i < t.get_nrbuildings(); ++i) {
150+ BuildingDescr const * ob = t.get_building_descr(i);
151+ if (ob->enhancement() == former_idx) {
152+ b.m_old_buildings.insert(b.m_old_buildings.begin(), i);
153+ break;
154+ }
155+ }
156+ }
157+}
158+
159+
160 void MapBuildingdataPacket::read_partially_finished_building
161 (PartiallyFinishedBuilding & pfb,
162 FileRead & fr,
163@@ -285,9 +339,14 @@
164 {
165 try {
166 uint16_t const packet_version = fr.unsigned_16();
167- if (packet_version >= kCurrentPacketVersionConstructionsite) {
168+ if (packet_version == 1)
169+ return read_constructionsite_v1(constructionsite, fr, game, mol);
170+
171+ if (packet_version >= 2) {
172 read_partially_finished_building(constructionsite, fr, game, mol);
173
174+ const TribeDescr & tribe = constructionsite.owner().tribe();
175+
176 for (ConstructionSite::Wares::iterator wares_iter = constructionsite.m_wares.begin();
177 wares_iter != constructionsite.m_wares.end();
178 ++wares_iter) {
179@@ -296,6 +355,13 @@
180 (ConstructionSite::wares_queue_callback, &constructionsite);
181 }
182
183+ if (packet_version <= 2) {
184+ if (fr.unsigned_8()) {
185+ DescriptionIndex idx = tribe.safe_building_index(fr.c_string());
186+ constructionsite.m_old_buildings.push_back(idx);
187+ }
188+ }
189+
190 constructionsite.m_fetchfromflag = fr. signed_32();
191 } else {
192 throw UnhandledVersionError("MapBuildingdataPacket - Constructionsite",
193@@ -306,6 +372,66 @@
194 }
195 }
196
197+void MapBuildingdataPacket::read_constructionsite_v1
198+ (ConstructionSite & constructionsite,
199+ FileRead & fr,
200+ Game & game,
201+ MapObjectLoader & mol)
202+{
203+ const TribeDescr & tribe = constructionsite.owner().tribe();
204+ constructionsite.m_building =
205+ tribe.get_building_descr(tribe.safe_building_index(fr.c_string()));
206+ if (fr.unsigned_8()) {
207+ DescriptionIndex bidx = tribe.safe_building_index(fr.c_string());
208+ constructionsite.m_old_buildings.push_back(bidx);
209+ }
210+
211+ delete constructionsite.m_builder_request;
212+ if (fr.unsigned_8()) {
213+ constructionsite.m_builder_request =
214+ new Request
215+ (constructionsite,
216+ 0,
217+ ConstructionSite::request_builder_callback,
218+ wwWORKER);
219+ constructionsite.m_builder_request->read(fr, game, mol);
220+ } else
221+ constructionsite.m_builder_request = nullptr;
222+
223+ if (uint32_t const builder_serial = fr.unsigned_32()) {
224+ try {
225+ constructionsite.m_builder = &mol.get<Worker>(builder_serial);
226+ } catch (const WException & e) {
227+ throw GameDataError
228+ ("builder (%u): %s", builder_serial, e.what());
229+ }
230+ } else
231+ constructionsite.m_builder = nullptr;
232+
233+ try {
234+ uint16_t const size = fr.unsigned_16();
235+ constructionsite.m_wares.resize(size);
236+ for (uint16_t i = 0; i < constructionsite.m_wares.size(); ++i)
237+ {
238+ constructionsite.m_wares[i] =
239+ new WaresQueue
240+ (constructionsite, INVALID_INDEX, 0);
241+ constructionsite.m_wares[i]->set_callback
242+ (ConstructionSite::wares_queue_callback, &constructionsite);
243+ constructionsite.m_wares[i]->read(fr, game, mol);
244+ }
245+ } catch (const WException & e) {
246+ throw GameDataError("wares: %s", e.what());
247+ }
248+
249+ constructionsite.m_fetchfromflag = fr. signed_32();
250+
251+ constructionsite.m_working = fr.unsigned_8 ();
252+ constructionsite.m_work_steptime = fr.unsigned_32();
253+ constructionsite.m_work_completed = fr.unsigned_32();
254+ constructionsite.m_work_steps = fr.unsigned_32();
255+}
256+
257 void MapBuildingdataPacket::read_dismantlesite
258 (DismantleSite & dms,
259 FileRead & fr,
260@@ -336,31 +462,59 @@
261 {
262 try {
263 uint16_t const packet_version = fr.unsigned_16();
264- if (packet_version == kCurrentPacketVersionWarehouse) {
265+ if (1 <= packet_version && packet_version <= kCurrentPacketVersionWarehouse) {
266 Player& player = warehouse.owner();
267 warehouse.init_containers(player);
268 const TribeDescr& tribe = player.tribe();
269
270 while (fr.unsigned_8()) {
271- const DescriptionIndex& id = tribe.ware_index(fr.c_string());
272- uint32_t amount = fr.unsigned_32();
273- Warehouse::StockPolicy policy =
274- static_cast<Warehouse::StockPolicy>(fr.unsigned_8());
275-
276- if (game.tribes().ware_exists(id)) {
277- warehouse.insert_wares(id, amount);
278- warehouse.set_ware_policy(id, policy);
279+ DescriptionIndex const id = tribe.ware_index(fr.c_string());
280+ if (packet_version >= 5) {
281+ uint32_t amount = fr.unsigned_32();
282+ Warehouse::StockPolicy policy =
283+ static_cast<Warehouse::StockPolicy>(fr.unsigned_8());
284+
285+ if (game.tribes().ware_exists(id)) {
286+ warehouse.insert_wares(id, amount);
287+ warehouse.set_ware_policy(id, policy);
288+ }
289+ } else {
290+ uint16_t amount = fr.unsigned_16();
291+
292+ if (game.tribes().ware_exists(id))
293+ warehouse.insert_wares(id, amount);
294 }
295 }
296 while (fr.unsigned_8()) {
297- const DescriptionIndex& id = tribe.worker_index(fr.c_string());
298- uint32_t amount = fr.unsigned_32();
299- Warehouse::StockPolicy policy =
300- static_cast<Warehouse::StockPolicy>(fr.unsigned_8());
301-
302- if (game.tribes().worker_exists(id)) {
303- warehouse.insert_workers(id, amount);
304- warehouse.set_worker_policy(id, policy);
305+ DescriptionIndex const id = tribe.worker_index(fr.c_string());
306+ if (packet_version >= 5) {
307+ uint32_t amount = fr.unsigned_32();
308+ Warehouse::StockPolicy policy =
309+ static_cast<Warehouse::StockPolicy>(fr.unsigned_8());
310+
311+ if (game.tribes().worker_exists(id)) {
312+ warehouse.insert_workers(id, amount);
313+ warehouse.set_worker_policy(id, policy);
314+ }
315+ } else {
316+ uint16_t amount = fr.unsigned_16();
317+
318+ if (game.tribes().worker_exists(id))
319+ warehouse.insert_workers(id, amount);
320+ }
321+ }
322+
323+ if (packet_version <= 3) {
324+ // eat the obsolete idle request structures
325+ uint32_t nrrequests = fr.unsigned_16();
326+ while (nrrequests--) {
327+ std::unique_ptr<Request> req
328+ (new Request
329+ (warehouse,
330+ 0,
331+ &Warehouse::request_cb,
332+ wwWORKER));
333+ req->read(fr, game, mol);
334 }
335 }
336
337@@ -372,6 +526,13 @@
338
339 try {
340 Worker & worker = mol.get<Worker>(worker_serial);
341+ if (1 == packet_version) {
342+ char const * const name = fr.c_string();
343+ if (name != worker.descr().name())
344+ throw GameDataError
345+ ("expected %s but found \"%s\"",
346+ worker.descr().name().c_str(), name);
347+ }
348 const DescriptionIndex& worker_index = tribe.worker_index(worker.descr().name().c_str());
349 if (!warehouse.m_incorporated_workers.count(worker_index))
350 warehouse.m_incorporated_workers[worker_index] = std::vector<Worker *>();
351@@ -386,86 +547,130 @@
352
353 const std::vector<DescriptionIndex>& worker_types_without_cost = tribe.worker_types_without_cost();
354
355- for (;;) {
356- char const * const worker_typename = fr.c_string ();
357- if (!*worker_typename) // encountered the terminator ("")
358- break;
359- uint32_t const next_spawn = fr.unsigned_32();
360- DescriptionIndex const worker_index =
361- tribe.safe_worker_index(worker_typename);
362+ if (1 == packet_version) { // a single next_spawn time for "carrier"
363+ uint32_t const next_spawn = fr.unsigned_32();
364+ const DescriptionIndex worker_index = tribe.carrier();
365+
366 if (!game.tribes().worker_exists(worker_index)) {
367 log
368 ("WARNING: %s %u has a next_spawn time for nonexistent "
369 "worker type \"%s\" set to %u, ignoring\n",
370 warehouse.descr().descname().c_str(), warehouse.serial(),
371- worker_typename, next_spawn);
372- continue;
373- }
374- if (tribe.get_worker_descr(worker_index)->buildcost().size()) {
375+ "carrier", next_spawn);
376+ } else if
377+ (tribe.get_worker_descr(worker_index)->buildcost().size())
378+ {
379 log
380 ("WARNING: %s %u has a next_spawn time for worker type "
381 "\"%s\", that costs something to build, set to %u, "
382 "ignoring\n",
383 warehouse.descr().descname().c_str(), warehouse.serial(),
384- worker_typename, next_spawn);
385- continue;
386- }
387- for (uint8_t i = 0;; ++i) {
388- assert(i < worker_types_without_cost.size());
389- if (worker_types_without_cost.at(i) == worker_index) {
390- if
391- (warehouse.m_next_worker_without_cost_spawn[i] != never())
392- throw GameDataError
393- (
394- "%s %u has a next_spawn time for worker type "
395- "\"%s\" set to %u, but it was previously set "
396- "to %u\n",
397- warehouse.descr().descname().c_str(), warehouse.serial(),
398- worker_typename, next_spawn,
399- warehouse.m_next_worker_without_cost_spawn[i]);
400- warehouse.m_next_worker_without_cost_spawn[i] = next_spawn;
401+ "carrier", next_spawn);
402+ } else
403+ for (uint8_t i = 0;; ++i) {
404+ assert(i < worker_types_without_cost.size());
405+ if (worker_types_without_cost.at(i) == worker_index) {
406+ if
407+ (warehouse.m_next_worker_without_cost_spawn[i] != never())
408+ {
409+ warehouse.molog
410+ ("read_warehouse: "
411+ "m_next_worker_without_cost_spawn[%u] = %u\n",
412+ i, warehouse.m_next_worker_without_cost_spawn[i]);
413+ }
414+ assert(warehouse.m_next_worker_without_cost_spawn[i] == never());
415+ warehouse.m_next_worker_without_cost_spawn[i] = next_spawn;
416+ break;
417+ }
418+ }
419+ } else
420+ for (;;) {
421+ char const * const worker_typename = fr.c_string ();
422+ if (!*worker_typename) // encountered the terminator ("")
423 break;
424- }
425- }
426- }
427- // The checks that the warehouse has a next_spawn time for each
428- // worker type that the player is allowed to spawn, is in
429- // Warehouse::load_finish.
430-
431- // Read planned worker data
432- // Consistency checks are in Warehouse::load_finish
433- uint32_t nr_planned_workers = fr.unsigned_32();
434- while (nr_planned_workers--) {
435- warehouse.m_planned_workers.push_back
436- (Warehouse::PlannedWorkers());
437- Warehouse::PlannedWorkers & pw =
438- warehouse.m_planned_workers.back();
439- pw.index = tribe.worker_index(fr.c_string());
440- pw.amount = fr.unsigned_32();
441-
442- uint32_t nr_requests = fr.unsigned_32();
443- while (nr_requests--) {
444- pw.requests.push_back
445- (new Request
446- (warehouse,
447- 0,
448- &Warehouse::request_cb,
449- wwWORKER));
450- pw.requests.back()->read(fr, game, mol);
451- }
452- }
453-
454- warehouse.m_next_stock_remove_act = fr.unsigned_32();
455-
456- if (warehouse.descr().get_isport()) {
457- if (Serial portdock = fr.unsigned_32()) {
458- warehouse.m_portdock = &mol.get<PortDock>(portdock);
459- warehouse.m_portdock->set_economy(warehouse.get_economy());
460- // Expedition specific stuff. This is done in this packet
461- // because the "new style" loader is not supported and
462- // doesn't lend itself to request and other stuff.
463- if (warehouse.m_portdock->expedition_started()) {
464- warehouse.m_portdock->expedition_bootstrap()->load(warehouse, fr, game, mol);
465+ uint32_t const next_spawn = fr.unsigned_32();
466+ DescriptionIndex const worker_index =
467+ tribe.safe_worker_index(worker_typename);
468+ if (!tribe.has_worker(worker_index)) {
469+ log
470+ ("WARNING: %s %u has a next_spawn time for nonexistent "
471+ "worker type \"%s\" set to %u, ignoring\n",
472+ warehouse.descr().descname().c_str(), warehouse.serial(),
473+ worker_typename, next_spawn);
474+ continue;
475+ }
476+ if (tribe.get_worker_descr(worker_index)->buildcost().size()) {
477+ log
478+ ("WARNING: %s %u has a next_spawn time for worker type "
479+ "\"%s\", that costs something to build, set to %u, "
480+ "ignoring\n",
481+ warehouse.descr().descname().c_str(), warehouse.serial(),
482+ worker_typename, next_spawn);
483+ continue;
484+ }
485+ for (uint8_t i = 0;; ++i) {
486+ assert(i < worker_types_without_cost.size());
487+ if (worker_types_without_cost.at(i) == worker_index) {
488+ if
489+ (warehouse.m_next_worker_without_cost_spawn[i] != never())
490+ throw GameDataError
491+ (
492+ "%s %u has a next_spawn time for worker type "
493+ "\"%s\" set to %u, but it was previously set "
494+ "to %u\n",
495+ warehouse.descr().descname().c_str(), warehouse.serial(),
496+ worker_typename, next_spawn,
497+ warehouse.m_next_worker_without_cost_spawn[i]);
498+ warehouse.m_next_worker_without_cost_spawn[i] =
499+ next_spawn;
500+ break;
501+ }
502+ }
503+ }
504+ // The checks that the warehouse has a next_spawn time for each
505+ // worker type that the player is allowed to spawn, is in
506+ // Warehouse::load_finish.
507+
508+ if (packet_version >= 3) {
509+ // Read planned worker data
510+ // Consistency checks are in Warehouse::load_finish
511+ uint32_t nr_planned_workers = fr.unsigned_32();
512+ while (nr_planned_workers--) {
513+ warehouse.m_planned_workers.push_back
514+ (Warehouse::PlannedWorkers());
515+ Warehouse::PlannedWorkers & pw =
516+ warehouse.m_planned_workers.back();
517+ pw.index = tribe.worker_index(fr.c_string());
518+ pw.amount = fr.unsigned_32();
519+
520+ uint32_t nr_requests = fr.unsigned_32();
521+ while (nr_requests--) {
522+ pw.requests.push_back
523+ (new Request
524+ (warehouse,
525+ 0,
526+ &Warehouse::request_cb,
527+ wwWORKER));
528+ pw.requests.back()->read(fr, game, mol);
529+ }
530+ }
531+ }
532+
533+ if (packet_version >= 5)
534+ warehouse.m_next_stock_remove_act = fr.unsigned_32();
535+
536+ if (packet_version >= 6) {
537+ if (warehouse.descr().get_isport()) {
538+ if (Serial portdock = fr.unsigned_32()) {
539+ warehouse.m_portdock = &mol.get<PortDock>(portdock);
540+ warehouse.m_portdock->set_economy(warehouse.get_economy());
541+ // Expedition specific stuff. This is done in this packet
542+ // because the "new style" loader is not supported and
543+ // doesn't lend itself to request and other stuff.
544+ if (warehouse.m_portdock->expedition_started()) {
545+ warehouse.m_portdock->expedition_bootstrap()->load
546+ (packet_version, warehouse, fr, game, mol);
547+ }
548 }
549 }
550 }
551@@ -613,7 +818,7 @@
552 {
553 try {
554 uint16_t const packet_version = fr.unsigned_16();
555- if (packet_version == kCurrentPacketVersionProductionsite) {
556+ if (1 <= packet_version && packet_version <= kCurrentPacketVersionProductionsite) {
557 ProductionSite::WorkingPosition & wp_begin =
558 *productionsite.m_working_positions;
559 const ProductionSiteDescr & pr_descr = productionsite.descr();
560@@ -707,7 +912,7 @@
561
562 // skipped programs
563 uint32_t const gametime = game.get_gametime();
564- for (uint8_t i = fr.unsigned_8(); i; --i) {
565+ for (uint8_t i = 3 <= packet_version ? fr.unsigned_8() : 0; i; --i) {
566 char const * const program_name = fr.c_string();
567 if (pr_descr.programs().count(program_name)) {
568 uint32_t const skip_time = fr.unsigned_32();
569@@ -742,10 +947,12 @@
570 productionsite.m_stack[i].phase = fr. signed_32();
571 productionsite.m_stack[i].flags = fr.unsigned_32();
572
573- uint32_t serial = fr.unsigned_32();
574- if (serial)
575- productionsite.m_stack[i].objvar = &mol.get<MapObject>(serial);
576- productionsite.m_stack[i].coord = read_coords_32_allow_null(&fr, game.map().extent());
577+ if (packet_version >= 5) {
578+ uint32_t serial = fr.unsigned_32();
579+ if (serial)
580+ productionsite.m_stack[i].objvar = &mol.get<MapObject>(serial);
581+ productionsite.m_stack[i].coord = read_coords_32_allow_null(&fr, game.map().extent());
582+ }
583 }
584 productionsite.m_program_timer = fr.unsigned_8();
585 productionsite.m_program_time = fr.signed_32();
586
587=== modified file 'src/map_io/map_buildingdata_packet.h'
588--- src/map_io/map_buildingdata_packet.h 2015-10-18 20:23:10 +0000
589+++ src/map_io/map_buildingdata_packet.h 2015-11-21 10:21:30 +0000
590@@ -52,6 +52,8 @@
591 (DismantleSite &, FileRead &, Game &, MapObjectLoader &);
592 void read_partially_finished_building
593 (PartiallyFinishedBuilding &, FileRead &, Game &, MapObjectLoader &);
594+ void read_constructionsite_v1
595+ (ConstructionSite &, FileRead &, Game &, MapObjectLoader &);
596 void read_warehouse
597 (Warehouse &, FileRead &, Game &, MapObjectLoader &);
598 void read_militarysite
599@@ -60,6 +62,8 @@
600 (TrainingSite &, FileRead &, Game &, MapObjectLoader &);
601 void read_productionsite
602 (ProductionSite &, FileRead &, Game &, MapObjectLoader &);
603+ void read_formerbuildings_v2
604+ (Building &, FileRead &, Game &, MapObjectLoader &);
605
606 void write_constructionsite
607 (const ConstructionSite &, FileWrite &, Game &, MapObjectSaver &);
608
609=== modified file 'src/map_io/map_exploration_packet.cc'
610--- src/map_io/map_exploration_packet.cc 2015-10-24 15:42:37 +0000
611+++ src/map_io/map_exploration_packet.cc 2015-11-21 10:21:30 +0000
612@@ -58,7 +58,21 @@
613 MapIndex const max_index = map.max_index();
614 try {
615 uint16_t const packet_version = fr.unsigned_16();
616- if (packet_version == kCurrentPacketVersion) {
617+ if (packet_version == 1) {
618+ for (MapIndex i = 0; i < max_index; ++i) {
619+ uint32_t const data = fr.unsigned_16();
620+ for (uint8_t j = 0; j < nr_players; ++j) {
621+ bool const see = data & (1 << j);
622+ if (Player * const player = egbase.get_player(j + 1))
623+ player->m_fields[i].vision = see ? 1 : 0;
624+ else if (see)
625+ log
626+ ("MapExplorationPacket::read: WARNING: Player %u, "
627+ "which does not exist, sees field %u.\n",
628+ j + 1, i);
629+ }
630+ }
631+ } else if (packet_version == kCurrentPacketVersion) {
632 for (MapIndex i = 0; i < max_index; ++i) {
633 uint32_t const data = fr.unsigned_32();
634 for (uint8_t j = 0; j < nr_players; ++j) {
635
636=== modified file 'src/map_io/map_flagdata_packet.cc'
637--- src/map_io/map_flagdata_packet.cc 2015-10-24 15:42:37 +0000
638+++ src/map_io/map_flagdata_packet.cc 2015-11-21 10:21:30 +0000
639@@ -54,15 +54,42 @@
640
641 try {
642 uint16_t const packet_version = fr.unsigned_16();
643- if (packet_version == kCurrentPacketVersion) {
644+ if (1 <= packet_version && packet_version <= kCurrentPacketVersion) {
645 const Map & map = egbase.map();
646- while (! fr.end_of_file()) {
647+ Extent const extent = map.extent();
648+ for (;;) {
649+ if (2 <= packet_version && fr.end_of_file())
650+ break;
651 Serial const serial = fr.unsigned_32();
652+ if (packet_version < 2 && serial == 0xffffffff) {
653+ if (!fr.end_of_file())
654+ throw GameDataError
655+ ("expected end of file after serial 0xffffffff");
656+ break;
657+ }
658 try {
659 Flag & flag = mol.get<Flag>(serial);
660
661 // Owner is already set, nothing to do from PlayerImmovable.
662
663+ if (packet_version < 3) {
664+ if
665+ (upcast
666+ (Flag const,
667+ mf,
668+ map[flag.m_position = read_coords_32(&fr, extent)]
669+ .get_immovable()))
670+ {
671+ if (mf != &flag)
672+ throw GameDataError
673+ ("wrong flag (%u) at given position (%i, %i)",
674+ mf->serial(),
675+ flag.m_position.x, flag.m_position.y);
676+ } else
677+ throw GameDataError
678+ ("no flag at given position (%i, %i)",
679+ flag.m_position.x, flag.m_position.y);
680+ }
681 flag.m_animstart = fr.unsigned_16();
682
683 {
684@@ -72,6 +99,26 @@
685 dynamic_cast<Building *>
686 (building_position.field->get_immovable());
687 }
688+ if (packet_version < 3) {
689+ if (uint32_t const building_serial = fr.unsigned_32())
690+ try {
691+ const Building & building =
692+ mol.get<Building>(building_serial);
693+ if (flag.m_building != &building)
694+ throw GameDataError
695+ (
696+ "has building %u at (%i, %i), which is not "
697+ "at the top left node",
698+ building_serial,
699+ building.get_position().x,
700+ building.get_position().y);
701+ } catch (const WException & e) {
702+ throw GameDataError
703+ ("building (%u): %s", building_serial, e.what());
704+ }
705+ else
706+ flag.m_building = nullptr;
707+ }
708
709 // Roads are set somewhere else.
710
711@@ -87,7 +134,10 @@
712 flag.m_ware_filled = wares_filled;
713 for (uint32_t i = 0; i < wares_filled; ++i) {
714 flag.m_wares[i].pending = fr.unsigned_8();
715- flag.m_wares[i].priority = fr.signed_32();
716+ if (packet_version < 4)
717+ flag.m_wares[i].priority = 0;
718+ else
719+ flag.m_wares[i].priority = fr.signed_32();
720 uint32_t const ware_serial = fr.unsigned_32();
721 try {
722 flag.m_wares[i].ware =
723
724=== modified file 'src/map_io/map_player_names_and_tribes_packet.cc'
725--- src/map_io/map_player_names_and_tribes_packet.cc 2015-10-24 15:42:37 +0000
726+++ src/map_io/map_player_names_and_tribes_packet.cc 2015-11-21 10:21:30 +0000
727@@ -63,8 +63,7 @@
728 try {
729 int32_t const packet_version =
730 prof.get_safe_section("global").get_int("packet_version");
731- // Supporting older versions for map loading
732- if (1 <= packet_version && packet_version <= kCurrentPacketVersion) {
733+ if (packet_version <= kCurrentPacketVersion) {
734 PlayerNumber const nr_players = map->get_nrplayers();
735 iterate_player_numbers(p, nr_players) {
736 Section & s = prof.get_safe_section((boost::format("player_%u")
737
738=== modified file 'src/map_io/map_players_view_packet.cc'
739--- src/map_io/map_players_view_packet.cc 2015-11-14 13:18:24 +0000
740+++ src/map_io/map_players_view_packet.cc 2015-11-21 10:21:30 +0000
741@@ -174,6 +174,29 @@
742 static_cast<long unsigned int>((file).get_size() - (file).get_pos()), \
743 filename);
744
745+// TODO(unknown): Legacy code deprecated since build18
746+template <uint8_t const Size> struct BitInBuffer {
747+ static_assert(Size == 1 || Size == 2 || Size == 4, "Unexpected Size.");
748+ BitInBuffer(FileRead* fr) : buffer(0), mask(0x00) {
749+ m_fr = fr;
750+ }
751+
752+ uint8_t get() {
753+ if (mask == 0x00) {
754+ buffer = m_fr->unsigned_8();
755+ mask = 0xff;
756+ }
757+ uint8_t const result = buffer >> (8 - Size);
758+ buffer <<= Size;
759+ mask <<= Size;
760+ assert(result < (1 << Size));
761+ return result;
762+ }
763+
764+private:
765+ FileRead* m_fr;
766+ uint8_t buffer, mask;
767+};
768
769 // Errors for the Read* functions.
770 struct TribeNonexistent : public FileRead::DataError {
771@@ -511,6 +534,15 @@
772 BORDER_FILENAME_TEMPLATE,
773 kCurrentPacketVersionBorder);
774
775+ // TODO(unknown): Legacy code deprecated since build18
776+ BitInBuffer<2> legacy_node_immovable_kinds_bitbuffer(&node_immovable_kinds_file);
777+ BitInBuffer<2> legacy_road_bitbuffer(&roads_file);
778+ BitInBuffer<4> legacy_terrains_bitbuffer(&terrains_file);
779+ BitInBuffer<2> legacy_triangle_immovable_kinds_bitbuffer(&triangle_immovable_kinds_file);
780+ BitInBuffer<1> legacy_surveys_bitbuffer(&surveys_file);
781+ BitInBuffer<4> legacy_surveys_amount_bitbuffer(&survey_amounts_file);
782+ BitInBuffer<1> legacy_border_bitbuffer(&border_file);
783+
784 for
785 (FCoords first_in_row(Coords(0, 0), &first_field);
786 first_in_row.y < mapheight;
787@@ -589,12 +621,10 @@
788 f.x, f.y, owner, nr_players);
789 }
790 uint8_t imm_kind = 0;
791- if (node_immovable_kinds_file_version == kCurrentPacketVersionImmovableKinds) {
792+ if (node_immovable_kinds_file_version < kCurrentPacketVersionImmovableKinds) {
793+ imm_kind = legacy_node_immovable_kinds_bitbuffer.get();
794+ } else {
795 imm_kind = node_immovable_kinds_file.unsigned_8();
796- } else {
797- throw UnhandledVersionError("MapPlayersViewPacket - Node Immovable kinds",
798- node_immovable_kinds_file_version,
799- kCurrentPacketVersionImmovableKinds);
800 }
801 MapObjectData mod =
802 read_unseen_immovable
803@@ -602,17 +632,24 @@
804 f_player_field.map_object_descr[TCoords<>::None] = mod.map_object_descr;
805 f_player_field.constructionsite = mod.csi;
806
807- // Read in whether this field had a border the last time it was seen
808- if (border_file_version == kCurrentPacketVersionBorder) {
809- uint8_t borders = border_file.unsigned_8();
810- f_player_field.border = borders & 1;
811- f_player_field.border_r = borders & 2;
812- f_player_field.border_br = borders & 4;
813- f_player_field.border_bl = borders & 8;
814- } else {
815- throw UnhandledVersionError("MapPlayersViewPacket - Border file",
816- border_file_version, kCurrentPacketVersionBorder);
817- }
818+ // if there is a border file, read in whether this field had a border the last time it was seen
819+ if (border_file_version >= 0) {
820+ if (border_file_version < 1) {
821+ f_player_field.border = (legacy_border_bitbuffer.get() == 1);
822+ f_player_field.border_r = (legacy_border_bitbuffer.get() == 1);
823+ f_player_field.border_br = (legacy_border_bitbuffer.get() == 1);
824+ f_player_field.border_bl = (legacy_border_bitbuffer.get() == 1);
825+ } else {
826+ uint8_t borders = border_file.unsigned_8();
827+ f_player_field.border = borders & 1;
828+ f_player_field.border_r = borders & 2;
829+ f_player_field.border_br = borders & 4;
830+ f_player_field.border_bl = borders & 8;
831+ }
832+ } else {
833+ throw UnhandledVersionError("MapPlayersViewPacket - Border file",
834+ border_file_version, kCurrentPacketVersionBorder);
835+ }
836 break;
837 }
838 default:
839@@ -651,19 +688,23 @@
840 } else if (f_everseen | bl_everseen | br_everseen) {
841 // The player has seen the D triangle but does not see it now.
842 // Load his information about the triangle from file.
843- if (terrains_file_version == kCurrentPacketVersionTerrains) {
844+ if (terrains_file_version < kCurrentPacketVersionTerrains) {
845+ try {f_player_field.terrains.d = legacy_terrains_bitbuffer.get();}
846+ catch (const FileRead::FileBoundaryExceeded &) {
847+ throw GameDataError
848+ ("MapPlayersViewPacket::read: player %u: in "
849+ "\"%s\": node (%i, %i) t = D: unexpected end of file "
850+ "while reading terrain",
851+ plnum, terrains_filename, f.x, f.y);
852+ }
853+ } else {
854 f_player_field.terrains.d = terrains_file.unsigned_8();
855- } else {
856- throw UnhandledVersionError("MapPlayersViewPacket - Terrains",
857- terrains_file_version, kCurrentPacketVersionTerrains);
858 }
859 uint8_t im_kind = 0;
860- if (triangle_immovable_kinds_file_version == kCurrentPacketVersionImmovableKinds) {
861+ if (triangle_immovable_kinds_file_version < kCurrentPacketVersionImmovableKinds) {
862+ im_kind = legacy_triangle_immovable_kinds_bitbuffer.get();
863+ } else {
864 im_kind = triangle_immovable_kinds_file.unsigned_8();
865- } else {
866- throw UnhandledVersionError("MapPlayersViewPacket - Triangle Immovable kinds",
867- triangle_immovable_kinds_file_version,
868- kCurrentPacketVersionImmovableKinds);
869 }
870 MapObjectData mod =
871 read_unseen_immovable
872@@ -680,19 +721,23 @@
873 } else if (f_everseen | br_everseen | r_everseen) {
874 // The player has seen the R triangle but does not see it now.
875 // Load his information about the triangle from file.
876- if (terrains_file_version == kCurrentPacketVersionTerrains) {
877+ if (terrains_file_version < kCurrentPacketVersionTerrains) {
878+ try {f_player_field.terrains.r = legacy_terrains_bitbuffer.get();}
879+ catch (const FileRead::FileBoundaryExceeded &) {
880+ throw GameDataError
881+ ("MapPlayersViewPacket::read: player %u: in "
882+ "\"%s\": node (%i, %i) t = R: unexpected end of file "
883+ "while reading terrain",
884+ plnum, terrains_filename, f.x, f.y);
885+ }
886+ } else {
887 f_player_field.terrains.r = terrains_file.unsigned_8();
888- } else {
889- throw UnhandledVersionError("MapPlayersViewPacket - Terrains",
890- terrains_file_version, kCurrentPacketVersionTerrains);
891 }
892 uint8_t im_kind = 0;
893- if (triangle_immovable_kinds_file_version == kCurrentPacketVersionImmovableKinds) {
894+ if (triangle_immovable_kinds_file_version < kCurrentPacketVersionImmovableKinds) {
895+ im_kind = legacy_triangle_immovable_kinds_bitbuffer.get();
896+ } else {
897 im_kind = triangle_immovable_kinds_file.unsigned_8();
898- } else {
899- throw UnhandledVersionError("MapPlayersViewPacket - Triangle Immovable kinds",
900- triangle_immovable_kinds_file_version,
901- kCurrentPacketVersionImmovableKinds);
902 }
903 MapObjectData mod =
904 read_unseen_immovable
905@@ -707,11 +752,17 @@
906 } else if (f_everseen | bl_everseen) {
907 // The player has seen the SouthWest edge but does not see
908 // it now. Load his information about this edge from file.
909- if (road_file_version == kCurrentPacketVersionRoads) {
910+ if (road_file_version < kCurrentPacketVersionRoads) {
911+ try {roads = legacy_road_bitbuffer.get() << RoadType::kSouthWest;}
912+ catch (const FileRead::FileBoundaryExceeded &) {
913+ throw GameDataError
914+ ("MapPlayersViewPacket::read: player %u: in "
915+ "\"%s\": node (%i, %i): unexpected end of file while "
916+ "reading RoadType::kSouthWest",
917+ plnum, roads_filename, f.x, f.y);
918+ }
919+ } else {
920 roads = roads_file.unsigned_8();
921- } else {
922- throw UnhandledVersionError("MapPlayersViewPacket - Road file",
923- road_file_version, kCurrentPacketVersionRoads);
924 }
925 }
926 if (f_seen | br_seen) {
927@@ -719,11 +770,17 @@
928 } else if (f_everseen | br_everseen) {
929 // The player has seen the SouthEast edge but does not see
930 // it now. Load his information about this edge from file.
931- if (road_file_version == kCurrentPacketVersionRoads) {
932+ if (road_file_version < kCurrentPacketVersionRoads) {
933+ try {roads |= legacy_road_bitbuffer.get() << RoadType::kSouthEast;}
934+ catch (const FileRead::FileBoundaryExceeded &) {
935+ throw GameDataError
936+ ("MapPlayersViewPacket::read: player %u: in "
937+ "\"%s\": node (%i, %i): unexpected end of file while "
938+ "reading RoadType::kSouthEast",
939+ plnum, roads_filename, f.x, f.y);
940+ }
941+ } else {
942 roads |= roads_file.unsigned_8();
943- } else {
944- throw UnhandledVersionError("MapPlayersViewPacket - Road file",
945- road_file_version, kCurrentPacketVersionRoads);
946 }
947 }
948 if (f_seen | r_seen) {
949@@ -731,11 +788,17 @@
950 } else if (f_everseen | r_everseen) {
951 // The player has seen the East edge but does not see
952 // it now. Load his information about this edge from file.
953- if (road_file_version == kCurrentPacketVersionRoads) {
954+ if (road_file_version < kCurrentPacketVersionRoads) {
955+ try {roads |= legacy_road_bitbuffer.get() << RoadType::kEast;}
956+ catch (const FileRead::FileBoundaryExceeded &) {
957+ throw GameDataError
958+ ("MapPlayersViewPacket::read: player %u: in "
959+ "\"%s\": node (%i, %i): unexpected end of file while "
960+ "reading RoadType::kEast",
961+ plnum, roads_filename, f.x, f.y);
962+ }
963+ } else {
964 roads |= roads_file.unsigned_8();
965- } else {
966- throw UnhandledVersionError("MapPlayersViewPacket - Road file",
967- road_file_version, kCurrentPacketVersionRoads);
968 }
969 }
970 roads |= f.field->get_roads() & mask;
971@@ -748,20 +811,27 @@
972 // geologic survey
973 try {
974 bool survey = false;
975- if (surveys_file_version == kCurrentPacketVersionSurveys) {
976+ if (surveys_file_version < kCurrentPacketVersionSurveys) {
977+ survey = (f_everseen & bl_everseen & br_everseen)
978+ && legacy_surveys_bitbuffer.get();
979+ } else {
980 survey = (f_everseen & bl_everseen & br_everseen)
981 && surveys_file.unsigned_8();
982- } else {
983- throw UnhandledVersionError("MapPlayersViewPacket - Surveys file",
984- surveys_file_version, kCurrentPacketVersionSurveys);
985 }
986 if (survey) {
987- if (survey_amounts_file_version == kCurrentPacketVersionSurveyAmounts) {
988+ if (survey_amounts_file_version < kCurrentPacketVersionSurveyAmounts) {
989+ try {
990+ f_player_field.resource_amounts.d =
991+ legacy_surveys_amount_bitbuffer.get();
992+ } catch (const FileRead::FileBoundaryExceeded &) {
993+ throw GameDataError
994+ ("MapPlayersViewPacket::read: player %u: in "
995+ "\"%s\": node (%i, %i) t = D: unexpected end of file "
996+ "while reading resource amount of surveyed triangle",
997+ plnum, survey_amounts_filename, f.x, f.y);
998+ }
999+ } else {
1000 f_player_field.resource_amounts.d = survey_amounts_file.unsigned_8();
1001- } else {
1002- throw UnhandledVersionError("MapPlayersViewPacket - Survey amounts",
1003- survey_amounts_file_version,
1004- kCurrentPacketVersionSurveyAmounts);
1005 }
1006 try {
1007 f_player_field.time_triangle_last_surveyed[TCoords<>::D] =
1008@@ -786,20 +856,27 @@
1009 }
1010 try {
1011 bool survey = false;
1012- if (surveys_file_version == kCurrentPacketVersionSurveys) {
1013+ if (surveys_file_version < kCurrentPacketVersionSurveys) {
1014+ survey = (f_everseen & br_everseen & r_everseen)
1015+ && legacy_surveys_bitbuffer.get();
1016+ } else {
1017 survey = (f_everseen & br_everseen & r_everseen)
1018 && surveys_file.unsigned_8();
1019- } else {
1020- throw UnhandledVersionError("MapPlayersViewPacket - Surveys file",
1021- surveys_file_version, kCurrentPacketVersionSurveys);
1022 }
1023 if (survey) {
1024- if (survey_amounts_file_version == kCurrentPacketVersionSurveyAmounts) {
1025+ if (survey_amounts_file_version < kCurrentPacketVersionSurveyAmounts) {
1026+ try {
1027+ f_player_field.resource_amounts.r =
1028+ legacy_surveys_amount_bitbuffer.get();
1029+ } catch (const FileRead::FileBoundaryExceeded &) {
1030+ throw GameDataError
1031+ ("MapPlayersViewPacket::read: player %u: in "
1032+ "\"%s\": node (%i, %i) t = R: unexpected end of file "
1033+ "while reading resource amount of surveyed triangle",
1034+ plnum, survey_amounts_filename, f.x, f.y);
1035+ }
1036+ } else {
1037 f_player_field.resource_amounts.r = survey_amounts_file.unsigned_8();
1038- } else {
1039- throw UnhandledVersionError("MapPlayersViewPacket - Survey amounts",
1040- survey_amounts_file_version,
1041- kCurrentPacketVersionSurveyAmounts);
1042 }
1043 try {
1044 f_player_field.time_triangle_last_surveyed[TCoords<>::R] =
1045
1046=== modified file 'src/map_io/map_roaddata_packet.cc'
1047--- src/map_io/map_roaddata_packet.cc 2015-10-25 08:06:00 +0000
1048+++ src/map_io/map_roaddata_packet.cc 2015-11-21 10:21:30 +0000
1049@@ -55,11 +55,19 @@
1050
1051 try {
1052 uint16_t const packet_version = fr.unsigned_16();
1053- if (packet_version == kCurrentPacketVersion) {
1054+ if (1 <= packet_version && packet_version <= kCurrentPacketVersion) {
1055 const Map & map = egbase.map();
1056 PlayerNumber const nr_players = map.get_nrplayers();
1057- while (! fr.end_of_file()) {
1058+ for (;;) {
1059+ if (2 <= packet_version && fr.end_of_file())
1060+ break;
1061 Serial const serial = fr.unsigned_32();
1062+ if (packet_version < 2 && serial == 0xffffffff) {
1063+ if (!fr.end_of_file())
1064+ throw GameDataError
1065+ ("expected end of file after serial 0xffffffff");
1066+ break;
1067+ }
1068 try {
1069 Game& game = dynamic_cast<Game&>(egbase);
1070 Road & road = mol.get<Road>(serial);
1071@@ -72,8 +80,10 @@
1072 Player & plr = egbase.player(player_index);
1073
1074 road.set_owner(&plr);
1075- road.m_busyness = fr.unsigned_32();
1076- road.m_busyness_last_update = fr.unsigned_32();
1077+ if (4 <= packet_version) {
1078+ road.m_busyness = fr.unsigned_32();
1079+ road.m_busyness_last_update = fr.unsigned_32();
1080+ }
1081 road.m_type = fr.unsigned_32();
1082 {
1083 uint32_t const flag_0_serial = fr.unsigned_32();
1084@@ -122,6 +132,12 @@
1085 uint32_t const count = fr.unsigned_32();
1086 if (!count)
1087 throw GameDataError("no carrier slot");
1088+ if (packet_version <= 2 && 1 < count)
1089+ throw GameDataError
1090+ (
1091+ "expected 1 but found %u carrier slots in road saved "
1092+ "with packet version 2 (old)",
1093+ count);
1094
1095 for (uint32_t i = 0; i < count; ++i) {
1096 Carrier * carrier = nullptr;
1097@@ -149,7 +165,8 @@
1098 } else {
1099 carrier_request = nullptr;
1100 }
1101- uint8_t const carrier_type = fr.unsigned_32();
1102+ uint8_t const carrier_type =
1103+ packet_version < 3 ? 1 : fr.unsigned_32();
1104
1105 if
1106 (i < road.m_carrier_slots.size() &&
1107
1108=== modified file 'src/map_io/map_scripting_packet.cc'
1109--- src/map_io/map_scripting_packet.cc 2015-11-01 10:11:56 +0000
1110+++ src/map_io/map_scripting_packet.cc 2015-11-21 10:21:30 +0000
1111@@ -37,7 +37,7 @@
1112 namespace Widelands {
1113
1114 namespace {
1115-constexpr uint32_t kCurrentPacketVersion = 2;
1116+constexpr uint32_t kCurrentPacketVersion = 1;
1117 } // namespace
1118 /*
1119 * ========================================================================
1120@@ -57,17 +57,13 @@
1121 FileRead fr;
1122 if (g && fr.try_open(fs, "scripting/globals.dump"))
1123 {
1124- try {
1125- const uint32_t packet_version = fr.unsigned_32();
1126- if (packet_version == kCurrentPacketVersion) {
1127- upcast(LuaGameInterface, lgi, &g->lua());
1128- lgi->read_global_env(fr, mol, fr.unsigned_32());
1129- } else {
1130- throw UnhandledVersionError("MapScriptingPacket", packet_version, kCurrentPacketVersion);
1131- }
1132- } catch (const WException & e) {
1133- throw GameDataError("scripting: %s", e.what());
1134+ const uint32_t sentinel = fr.unsigned_32();
1135+ const uint32_t packet_version = fr.unsigned_32();
1136+ if (sentinel != 0xDEADBEEF && packet_version != kCurrentPacketVersion) {
1137+ throw UnhandledVersionError("MapScriptingPacket", packet_version, kCurrentPacketVersion);
1138 }
1139+ upcast(LuaGameInterface, lgi, &g->lua());
1140+ lgi->read_global_env(fr, mol, fr.unsigned_32());
1141 }
1142 }
1143
1144@@ -94,6 +90,7 @@
1145 // Dump the global environment if this is a game and not in the editor
1146 if (upcast(Game, g, &egbase)) {
1147 FileWrite fw;
1148+ fw.unsigned_32(0xDEADBEEF); // Sentinel, because there was no packet version.
1149 fw.unsigned_32(kCurrentPacketVersion);
1150 const FileWrite::Pos pos = fw.get_pos();
1151 fw.unsigned_32(0); // N bytes written, follows below

Subscribers

People subscribed via source and target branches

to status/vote changes: