widelands-dev team mailing list archive
-
widelands-dev team
-
Mailing list archive
-
Message #13395
[Merge] lp:~widelands-dev/widelands/bug-1732765-economy-refactoring into lp:widelands
GunChleoc has proposed merging lp:~widelands-dev/widelands/bug-1732765-economy-refactoring into lp:widelands.
Commit message:
Economies are now mapped to global serials and kept as unique_ptr in the Player objects.
Requested reviews:
Widelands Developers (widelands-dev)
Related bugs:
Bug #1631738 in widelands: "Memory leak in economy/economy.cc split"
https://bugs.launchpad.net/widelands/+bug/1631738
Bug #1654897 in widelands: "corrupted saved game: "string ended unexpectedly""
https://bugs.launchpad.net/widelands/+bug/1654897
Bug #1732765 in widelands: "Configure economy window disappears if only headquarter is available"
https://bugs.launchpad.net/widelands/+bug/1732765
Bug #1762260 in widelands: "number of economies on save != number of economies on load"
https://bugs.launchpad.net/widelands/+bug/1762260
For more details, see:
https://code.launchpad.net/~widelands-dev/widelands/bug-1732765-economy-refactoring/+merge/345277
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.
--
Your team Widelands Developers is requested to review the proposed merge of lp:~widelands-dev/widelands/bug-1732765-economy-refactoring into lp:widelands.
=== modified file 'src/ai/defaultai.cc'
--- src/ai/defaultai.cc 2018-04-29 09:20:29 +0000
+++ src/ai/defaultai.cc 2018-05-12 04:24:42 +0000
@@ -6423,7 +6423,7 @@
assert(new_target > 1);
game().send_player_command(*new Widelands::CmdSetWareTargetQuantity(
- gametime, player_number(), player_->get_economy_number(&observer->economy), id,
+ gametime, player_number(), observer->economy.serial(), id,
new_target));
}
}
=== modified file 'src/ai/defaultai.h'
--- src/ai/defaultai.h 2018-04-16 07:03:12 +0000
+++ src/ai/defaultai.h 2018-05-12 04:24:42 +0000
@@ -155,7 +155,7 @@
// common for defaultai.cc and defaultai_seafaring.cc
static constexpr uint32_t kExpeditionMinDuration = 60 * 60 * 1000;
static constexpr uint32_t kExpeditionMaxDuration = 210 * 60 * 1000;
- static constexpr uint32_t kNoShip = std::numeric_limits<uint32_t>::max();
+ static constexpr Widelands::Serial kNoShip = Widelands::kInvalidSerial;
static constexpr int kShipCheckInterval = 5 * 1000;
// used by defaultai_warfare.cc
=== modified file 'src/ai/defaultai_warfare.cc'
--- src/ai/defaultai_warfare.cc 2018-04-09 01:50:48 +0000
+++ src/ai/defaultai_warfare.cc 2018-05-12 04:24:42 +0000
@@ -85,7 +85,7 @@
}
// now we update some of them
- uint32_t best_target = std::numeric_limits<uint32_t>::max();
+ Widelands::Serial best_target = Widelands::kInvalidSerial;
uint8_t best_score = 0;
uint32_t count = 0;
// sites that were either conquered or destroyed
@@ -463,7 +463,7 @@
}
// if coordinates hash is not set
- if (best_target == std::numeric_limits<uint32_t>::max()) {
+ if (best_target == Widelands::kInvalidSerial) {
return false;
}
=== modified file 'src/economy/economy.cc'
--- src/economy/economy.cc 2018-04-07 16:59:00 +0000
+++ src/economy/economy.cc 2018-05-12 04:24:42 +0000
@@ -41,15 +41,19 @@
namespace Widelands {
-Economy::Economy(Player& player) : owner_(player), request_timerid_(0), has_window_(false) {
+Serial Economy::last_economy_serial_ = 0;
+
+Economy::Economy(Player& player) : Economy(player, last_economy_serial_++) {
+}
+
+Economy::Economy(Player& player, Serial init_serial) : serial_(init_serial), owner_(player), request_timerid_(0), has_window_(false) {
+ last_economy_serial_ = std::max(last_economy_serial_, serial_ + 1);
const TribeDescr& tribe = player.tribe();
DescriptionIndex const nr_wares = player.egbase().tribes().nrwares();
DescriptionIndex const nr_workers = player.egbase().tribes().nrworkers();
wares_.set_nrwares(nr_wares);
workers_.set_nrwares(nr_workers);
- player.add_economy(*this);
-
ware_target_quantities_ = new TargetQuantity[nr_wares];
for (DescriptionIndex i = 0; i < nr_wares; ++i) {
TargetQuantity tq;
@@ -69,12 +73,11 @@
worker_target_quantities_[i] = tq;
}
- router_ = new Router(boost::bind(&Economy::reset_all_pathfinding_cycles, this));
+ router_.reset(new Router(boost::bind(&Economy::reset_all_pathfinding_cycles, this)));
}
Economy::~Economy() {
- Notifications::publish(NoteEconomy{this, this, NoteEconomy::Action::kDeleted});
- owner_.remove_economy(*this);
+ Notifications::publish(NoteEconomy{serial_, serial_, NoteEconomy::Action::kDeleted});
if (requests_.size())
log("Warning: Economy still has requests left on destruction\n");
@@ -85,8 +88,6 @@
delete[] ware_target_quantities_;
delete[] worker_target_quantities_;
-
- delete router_;
}
/**
@@ -269,8 +270,9 @@
do_remove_flag(flag);
// automatically delete the economy when it becomes empty.
- if (flags_.empty())
- delete this;
+ if (flags_.empty()) {
+ owner_.remove_economy(serial_);
+ }
}
/**
@@ -528,7 +530,8 @@
// If the options window for e is open, but not the one for this, the user
// should still have an options window after the merge.
if (e.has_window() && !has_window()) {
- Notifications::publish(NoteEconomy{&e, this, NoteEconomy::Action::kMerged});
+ Notifications::publish(
+ NoteEconomy{e.serial(), serial_, NoteEconomy::Action::kMerged});
}
for (std::vector<Flag*>::size_type i = e.get_nrflags() + 1; --i;) {
@@ -542,9 +545,7 @@
// Remember that the other economy may not have been connected before the merge
split_checks_.insert(split_checks_.end(), e.split_checks_.begin(), e.split_checks_.end());
-
- // implicitly delete the economy
- delete &e;
+ owner_.remove_economy(e.serial());
}
/**
@@ -553,21 +554,21 @@
void Economy::split(const std::set<OPtr<Flag>>& flags) {
assert(!flags.empty());
- Economy& e = *new Economy(owner_);
+ Economy* e = owner_.create_economy();
for (const DescriptionIndex& ware_index : owner_.tribe().wares()) {
- e.ware_target_quantities_[ware_index] = ware_target_quantities_[ware_index];
+ e->ware_target_quantities_[ware_index] = ware_target_quantities_[ware_index];
}
for (const DescriptionIndex& worker_index : owner_.tribe().workers()) {
- e.worker_target_quantities_[worker_index] = worker_target_quantities_[worker_index];
+ e->worker_target_quantities_[worker_index] = worker_target_quantities_[worker_index];
}
for (const OPtr<Flag>& temp_flag : flags) {
Flag& flag = *temp_flag.get(owner().egbase());
assert(flags_.size() > 1); // We will not be deleted in remove_flag, right?
remove_flag(flag);
- e.add_flag(flag);
+ e->add_flag(flag);
}
// As long as rebalance commands are tied to specific flags, we
=== modified file 'src/economy/economy.h'
--- src/economy/economy.h 2018-04-07 16:59:00 +0000
+++ src/economy/economy.h 2018-05-12 04:24:42 +0000
@@ -56,8 +56,8 @@
// When 2 economies have been merged, this is the economy number that has
// been removed, while the other one is the number of the resulting economy.
// For all other messages old_economy == new_economy.
- Economy* old_economy;
- Economy* new_economy;
+ Widelands::Serial old_economy;
+ Widelands::Serial new_economy;
enum class Action { kMerged, kDeleted };
const Action action;
@@ -108,8 +108,13 @@
};
explicit Economy(Player&);
+ explicit Economy(Player&, Serial serial); // For saveloading
~Economy();
+ Serial serial() const {
+ return serial_;
+ }
+
Player& owner() const {
return owner_;
}
@@ -209,6 +214,9 @@
start_request_timer();
}
+protected:
+ static Serial last_economy_serial_;
+
private:
// This structs is to store distance from supply to request(or), but to allow unambiguous
// sorting if distances are the same, we use also serial number of provider and type of provider
@@ -251,6 +259,8 @@
/*************/
using RequestList = std::vector<Request*>;
+ const Serial serial_;
+
Player& owner_;
using Flags = std::vector<Flag*>;
@@ -264,7 +274,7 @@
TargetQuantity* ware_target_quantities_;
TargetQuantity* worker_target_quantities_;
- Router* router_;
+ std::unique_ptr<Router> router_;
using SplitPair = std::pair<OPtr<Flag>, OPtr<Flag>>;
std::vector<SplitPair> split_checks_;
=== modified file 'src/economy/economy_data_packet.cc'
--- src/economy/economy_data_packet.cc 2018-04-07 16:59:00 +0000
+++ src/economy/economy_data_packet.cc 2018-05-12 04:24:42 +0000
@@ -27,7 +27,7 @@
#include "map_io/map_object_loader.h"
#include "map_io/map_object_saver.h"
-constexpr uint16_t kCurrentPacketVersion = 3;
+constexpr uint16_t kCurrentPacketVersion = 4;
namespace Widelands {
@@ -35,6 +35,11 @@
try {
uint16_t const packet_version = fr.unsigned_16();
if (packet_version == kCurrentPacketVersion) {
+ const Serial saved_serial = fr.unsigned_32();
+ if (eco_->serial_ != saved_serial) {
+ throw GameDataError("Representative flag/ship has economy serial %d, but the data packet has %d", eco_->serial_, saved_serial);
+ }
+ assert(Economy::last_economy_serial_ >= eco_->serial_);
try {
const TribeDescr& tribe = eco_->owner().tribe();
while (Time const last_modified = fr.unsigned_32()) {
@@ -94,6 +99,11 @@
void EconomyDataPacket::write(FileWrite& fw) {
fw.unsigned_16(kCurrentPacketVersion);
+
+ // We save the serial number for sanity checks
+ fw.unsigned_32(eco_->serial());
+
+ // Requests etc.
const TribeDescr& tribe = eco_->owner().tribe();
for (const DescriptionIndex& ware_index : tribe.wares()) {
const Economy::TargetQuantity& tq = eco_->ware_target_quantities_[ware_index];
=== modified file 'src/economy/economy_data_packet.h'
--- src/economy/economy_data_packet.h 2018-04-07 16:59:00 +0000
+++ src/economy/economy_data_packet.h 2018-05-12 04:24:42 +0000
@@ -20,6 +20,8 @@
#ifndef WL_ECONOMY_ECONOMY_DATA_PACKET_H
#define WL_ECONOMY_ECONOMY_DATA_PACKET_H
+#include <cassert>
+
class FileRead;
class FileWrite;
@@ -32,6 +34,7 @@
class EconomyDataPacket {
public:
explicit EconomyDataPacket(Economy* e) : eco_(e) {
+ assert(eco_);
}
void read(FileRead&);
=== modified file 'src/economy/flag.cc'
--- src/economy/flag.cc 2018-04-07 16:59:00 +0000
+++ src/economy/flag.cc 2018-05-12 04:24:42 +0000
@@ -44,7 +44,7 @@
}
/**
- * Create the flag. Initially, it doesn't have any attachments.
+ * A bare flag, used for testing only.
*/
Flag::Flag()
: PlayerImmovable(g_flag_descr),
@@ -106,7 +106,7 @@
/**
* Create a flag at the given location
*/
-Flag::Flag(EditorGameBase& egbase, Player* owning_player, const Coords& coords)
+Flag::Flag(EditorGameBase& egbase, Player* owning_player, const Coords& coords, Economy* economy)
: PlayerImmovable(g_flag_descr),
building_(nullptr),
ware_capacity_(8),
@@ -124,17 +124,23 @@
upcast(Game, game, &egbase);
if (game) {
- // we split a road, or a new, standalone flag is created
- (road ? road->get_economy() : new Economy(*owning_player))->add_flag(*this);
-
- if (road)
- road->presplit(*game, coords);
+ if (economy) {
+ // We're saveloading
+ economy->add_flag(*this);
+ } else {
+ // we split a road, or a new, standalone flag is created
+ (road ? road->get_economy() : owning_player->create_economy())->add_flag(*this);
+ if (road) {
+ road->presplit(*game, coords);
+ }
+ }
}
init(egbase);
- if (road && game)
+ if (!economy && road && game) {
road->postsplit(*game, *this);
+ }
}
void Flag::set_flag_position(Coords coords) {
=== modified file 'src/economy/flag.h'
--- src/economy/flag.h 2018-04-07 16:59:00 +0000
+++ src/economy/flag.h 2018-05-12 04:24:42 +0000
@@ -73,8 +73,12 @@
const FlagDescr& descr() const;
- Flag(); /// empty flag for savegame loading
- Flag(EditorGameBase&, Player* owner, const Coords&); /// create a new flag
+ /// Empty flag, for unit tests only.
+ Flag();
+
+ /// Create a new flag. Only specify an economy during saveloading.
+ /// Otherwise, a new economy will be created automatically if needed.
+ Flag(EditorGameBase&, Player* owner, const Coords&, Economy* economy = nullptr);
~Flag() override;
void load_finish(EditorGameBase&) override;
=== modified file 'src/game_io/game_player_economies_packet.cc'
--- src/game_io/game_player_economies_packet.cc 2018-04-07 16:59:00 +0000
+++ src/game_io/game_player_economies_packet.cc 2018-05-12 04:24:42 +0000
@@ -34,7 +34,7 @@
namespace Widelands {
namespace {
-constexpr uint16_t kCurrentPacketVersion = 4;
+constexpr uint16_t kCurrentPacketVersion = 5;
bool write_expedition_ship_economy(Economy* economy, const Map& map, FileWrite* fw) {
for (Field const* field = &map[0]; field < &map[map.max_index()]; ++field) {
@@ -67,31 +67,21 @@
FileRead fr;
fr.open(fs, "binary/player_economies");
uint16_t const packet_version = fr.unsigned_16();
- if (packet_version == 3 || packet_version == kCurrentPacketVersion) {
+ if (packet_version == kCurrentPacketVersion) {
iterate_players_existing(p, nr_players, game, player) try {
- // In packet_version 4 we dump the number of economies a player had at
- // save time to debug
- // https://bugs.launchpad.net/widelands/+bug/1654897 which is likely
- // caused by players having more economies at load than they had at
- // save.
- Player::Economies& economies = player->economies_;
- if (packet_version > 3) {
- const size_t num_economies = fr.unsigned_16();
- if (num_economies != economies.size()) {
- throw GameDataError("Num economies on save (%" PRIuS
- ") != Num economies on load (%" PRIuS ")",
- num_economies, economies.size());
- }
- }
-
- for (uint32_t i = 0; i < economies.size(); ++i) {
+ const size_t num_economies = fr.unsigned_32();
+ for (uint32_t i = 0; i < num_economies; ++i) {
uint32_t value = fr.unsigned_32();
if (value < 0xffffffff) {
if (upcast(Flag const, flag, map[value].get_immovable())) {
- assert(flag->get_economy()->owner().player_number() ==
- player->player_number());
- EconomyDataPacket d(flag->get_economy());
- d.read(fr);
+ try {
+ assert(flag->get_economy()->owner().player_number() ==
+ player->player_number());
+ EconomyDataPacket d(flag->get_economy());
+ d.read(fr);
+ } catch (const GameDataError& e) {
+ throw GameDataError("error reading economy data for flag at map index %d: %s", value, e.what());
+ }
} else {
throw GameDataError("there is no flag at the specified location");
}
@@ -102,13 +92,17 @@
if (upcast(Ship const, ship, bob)) {
// We are interested only in current player's ships
if (ship->get_owner() == player) {
- assert(ship->get_economy());
- assert(ship->get_economy()->owner().player_number() ==
- player->player_number());
- EconomyDataPacket d(ship->get_economy());
- d.read(fr);
- read_this_economy = true;
- break;
+ try {
+ assert(ship->get_economy());
+ assert(ship->get_economy()->owner().player_number() ==
+ player->player_number());
+ EconomyDataPacket d(ship->get_economy());
+ d.read(fr);
+ read_this_economy = true;
+ break;
+ } catch (const GameDataError& e) {
+ throw GameDataError("error reading economy data for ship %s: %s", ship->get_shipname().c_str(), e.what());
+ }
}
}
bob = bob->get_next_bob();
@@ -140,13 +134,13 @@
const Map& map = game.map();
PlayerNumber const nr_players = map.get_nrplayers();
iterate_players_existing_const(p, nr_players, game, player) {
- const Player::Economies& economies = player->economies_;
- fw.unsigned_16(economies.size());
- for (Economy* economy : economies) {
- Flag* arbitrary_flag = economy->get_arbitrary_flag();
+ const auto& economies = player->economies();
+ fw.unsigned_32(economies.size());
+ for (const auto& economy : economies) {
+ Flag* arbitrary_flag = economy.second->get_arbitrary_flag();
if (arbitrary_flag != nullptr) {
fw.unsigned_32(map.get_fcoords(arbitrary_flag->get_position()).field - &map[0]);
- EconomyDataPacket d(economy);
+ EconomyDataPacket d(economy.second.get());
d.write(fw);
continue;
}
@@ -154,8 +148,8 @@
// No flag found, let's look for a representative Ship. Expeditions
// ships are special and have their own economy (which will not have a
// flag), therefore we have to special case them.
- if (!write_expedition_ship_economy(economy, map, &fw)) {
- throw GameDataError("economy without representative");
+ if (!write_expedition_ship_economy(economy.second.get(), map, &fw)) {
+ throw GameDataError("Player %d: economy %d has no representative", player->player_number(), economy.first);
}
}
}
=== modified file 'src/logic/game.cc'
--- src/logic/game.cc 2018-04-27 20:12:08 +0000
+++ src/logic/game.cc 2018-05-12 04:24:42 +0000
@@ -912,17 +912,16 @@
uint32_t wostock = 0;
uint32_t wastock = 0;
- for (uint32_t j = 0; j < plr->get_nr_economies(); ++j) {
- Economy* const eco = plr->get_economy_by_number(j);
+ for (const auto& economy : plr->economies()) {
const TribeDescr& tribe = plr->tribe();
for (const DescriptionIndex& ware_index : tribe.wares()) {
- wastock += eco->stock_ware(ware_index);
+ wastock += economy.second->stock_ware(ware_index);
}
for (const DescriptionIndex& worker_index : tribe.workers()) {
if (tribe.get_worker_descr(worker_index)->type() != MapObjectType::CARRIER) {
- wostock += eco->stock_worker(worker_index);
+ wostock += economy.second->stock_worker(worker_index);
}
}
}
=== modified file 'src/logic/map_objects/tribes/ship.cc'
--- src/logic/map_objects/tribes/ship.cc 2018-04-29 09:20:29 +0000
+++ src/logic/map_objects/tribes/ship.cc 2018-05-12 04:24:42 +0000
@@ -827,14 +827,14 @@
expedition_->scouting_direction = WalkingDir::IDLE;
expedition_->exploration_start = Coords(0, 0);
expedition_->island_explore_direction = IslandExploreDirection::kClockwise;
- expedition_->economy.reset(new Economy(*get_owner()));
+ expedition_->economy = get_owner()->create_economy();
// We are no longer in any other economy, but instead are an economy of our
// own.
fleet_->remove_ship(game, this);
assert(fleet_ == nullptr);
- set_economy(game, expedition_->economy.get());
+ set_economy(game, expedition_->economy);
for (int i = items_.size() - 1; i >= 0; --i) {
WareInstance* ware;
@@ -944,7 +944,7 @@
if (!get_fleet() || !get_fleet()->has_ports()) {
// We lost our last reachable port, so we reset the expedition's state
ship_state_ = ShipStates::kExpeditionWaiting;
- set_economy(game, expedition_->economy.get());
+ set_economy(game, expedition_->economy);
worker = nullptr;
for (ShippingItem& item : items_) {
@@ -958,7 +958,7 @@
Notifications::publish(NoteShip(this, NoteShip::Action::kNoPortLeft));
return;
}
- assert(get_economy() && get_economy() != expedition_->economy.get());
+ assert(get_economy() && get_economy() != expedition_->economy);
send_signal(game, "cancel_expedition");
@@ -1097,6 +1097,12 @@
heading, rt_description, get_position(), serial_)));
}
+Ship::Expedition::~Expedition() {
+ if (economy) {
+ economy->owner().remove_economy(economy->serial());
+ }
+}
+
/*
==============================
@@ -1105,7 +1111,7 @@
==============================
*/
-constexpr uint8_t kCurrentPacketVersion = 6;
+constexpr uint8_t kCurrentPacketVersion = 7;
const Bob::Task* Ship::Loader::get_task(const std::string& name) {
if (name == "shipidle" || name == "ship")
@@ -1116,6 +1122,9 @@
void Ship::Loader::load(FileRead& fr) {
Bob::Loader::load(fr);
+ // Economy
+ economy_serial_ = fr.unsigned_32();
+
// The state the ship is in
ship_state_ = static_cast<ShipStates>(fr.unsigned_8());
@@ -1176,6 +1185,14 @@
Ship& ship = get<Ship>();
+ // The economy can sometimes be nullptr (e.g. when there are no ports).
+ if (economy_serial_ != kInvalidSerial) {
+ ship.economy_ = ship.get_owner()->get_economy(economy_serial_);
+ if (!ship.economy_) {
+ ship.economy_ = ship.get_owner()->create_economy(economy_serial_);
+ }
+ }
+
// restore the state the ship is in
ship.ship_state_ = ship_state_;
@@ -1185,8 +1202,7 @@
// if the ship is on an expedition, restore the expedition specific data
if (expedition_) {
ship.expedition_.swap(expedition_);
- ship.expedition_->economy.reset(new Economy(*ship.get_owner()));
- ship.economy_ = ship.expedition_->economy.get();
+ ship.expedition_->economy = ship.economy_;
} else
assert(ship_state_ == ShipStates::kTransport);
@@ -1202,28 +1218,16 @@
MapObject::Loader* Ship::load(EditorGameBase& egbase, MapObjectLoader& mol, FileRead& fr) {
std::unique_ptr<Loader> loader(new Loader);
-
try {
// The header has been peeled away by the caller
uint8_t const packet_version = fr.unsigned_8();
- if (1 <= packet_version && packet_version <= kCurrentPacketVersion) {
+ if (packet_version == kCurrentPacketVersion) {
try {
const ShipDescr* descr = nullptr;
// Removing this will break the test suite
- if (packet_version < 5) {
- std::string tribe_name = fr.string();
- fr.c_string(); // This used to be the ship's name, which we don't need any more.
- if (!Widelands::tribe_exists(tribe_name)) {
- throw GameDataError("Tribe %s does not exist for ship", tribe_name.c_str());
- }
- const DescriptionIndex& tribe_index = egbase.tribes().tribe_index(tribe_name);
- const TribeDescr& tribe_descr = *egbase.tribes().get_tribe_descr(tribe_index);
- descr = egbase.tribes().get_ship_descr(tribe_descr.ship());
- } else {
- std::string name = fr.c_string();
- const DescriptionIndex& ship_index = egbase.tribes().safe_ship_index(name);
- descr = egbase.tribes().get_ship_descr(ship_index);
- }
+ std::string name = fr.c_string();
+ const DescriptionIndex& ship_index = egbase.tribes().safe_ship_index(name);
+ descr = egbase.tribes().get_ship_descr(ship_index);
loader->init(egbase, mol, descr->create_object());
loader->load(fr);
} catch (const WException& e) {
@@ -1246,6 +1250,9 @@
Bob::save(egbase, mos, fw);
+ // The economy can sometimes be nullptr (e.g. when there are no ports).
+ fw.unsigned_32(economy_ != nullptr ? economy_->serial() : kInvalidSerial);
+
// state the ship is in
fw.unsigned_8(static_cast<uint8_t>(ship_state_));
=== modified file 'src/logic/map_objects/tribes/ship.h'
--- src/logic/map_objects/tribes/ship.h 2018-04-29 09:20:29 +0000
+++ src/logic/map_objects/tribes/ship.h 2018-05-12 04:24:42 +0000
@@ -271,13 +271,15 @@
std::string shipname_;
struct Expedition {
+ ~Expedition();
+
std::vector<Coords> seen_port_buildspaces;
bool swimmable[LAST_DIRECTION];
bool island_exploration;
WalkingDir scouting_direction;
Coords exploration_start;
IslandExploreDirection island_explore_direction;
- std::unique_ptr<Economy> economy;
+ Economy* economy; // Owned by Player
};
std::unique_ptr<Expedition> expedition_;
@@ -295,6 +297,7 @@
// Initialize everything to make cppcheck happy.
uint32_t lastdock_ = 0U;
uint32_t destination_ = 0U;
+ Serial economy_serial_;
ShipStates ship_state_ = ShipStates::kTransport;
std::string shipname_;
std::unique_ptr<Expedition> expedition_;
=== modified file 'src/logic/player.cc'
--- src/logic/player.cc 2018-04-29 09:20:29 +0000
+++ src/logic/player.cc 2018-05-12 04:24:42 +0000
@@ -798,37 +798,50 @@
/*
* Economy stuff below
*/
-void Player::add_economy(Economy& economy) {
- if (!has_economy(economy))
- economies_.push_back(&economy);
-}
-
-void Player::remove_economy(Economy& economy) {
- for (std::vector<Economy*>::iterator economy_iter = economies_.begin();
- economy_iter != economies_.end(); ++economy_iter)
- if (*economy_iter == &economy) {
- economies_.erase(economy_iter);
- return;
- }
-}
-
-bool Player::has_economy(Economy& economy) const {
- for (Economy* temp_economy : economies_) {
- if (temp_economy == &economy) {
- return true;
- }
+Economy* Player::create_economy() {
+ std::unique_ptr<Economy> eco(new Economy(*this));
+ const Serial serial = eco->serial();
+
+ assert(economies_.count(serial) == 0);
+ economies_.emplace(std::make_pair(serial, std::move(eco)));
+ assert(economies_.at(serial)->serial() == serial);
+ assert(economies_.count(serial) == 1);
+
+ return get_economy(serial);
+}
+
+Economy* Player::create_economy(Serial serial) {
+ std::unique_ptr<Economy> eco(new Economy(*this, serial));
+
+ assert(economies_.count(serial) == 0);
+ economies_.emplace(std::make_pair(serial, std::move(eco)));
+ assert(economies_.at(serial)->serial() == serial);
+ assert(economies_.count(serial) == 1);
+
+ return get_economy(serial);
+}
+
+void Player::remove_economy(Serial serial) {
+ assert(has_economy(serial));
+ economies_.erase(economies_.find(serial));
+ assert(!has_economy(serial));
+}
+
+const std::map<Serial,std::unique_ptr<Economy>>& Player::economies() const {
+ return economies_;
+}
+
+Economy* Player::get_economy(Widelands::Serial serial) const {
+ if (economies_.count(serial) == 0) {
+ return nullptr;
}
- return false;
-}
-
-Player::Economies::size_type Player::get_economy_number(Economy const* const economy) const {
- Economies::const_iterator const economies_end = economies_.end(),
- economies_begin = economies_.begin();
- for (Economies::const_iterator it = economies_begin; it != economies_end; ++it)
- if (*it == economy)
- return it - economies_begin;
- NEVER_HERE();
-}
+ return economies_.at(serial).get();
+}
+
+bool Player::has_economy(Widelands::Serial serial) const {
+ return economies_.count(serial) != 0;
+}
+
/************ Military stuff **********/
@@ -1156,11 +1169,8 @@
// Calculate stocks
std::vector<uint32_t> stocks(egbase().tribes().nrwares());
- const uint32_t nrecos = get_nr_economies();
- for (uint32_t i = 0; i < nrecos; ++i) {
- const std::vector<Widelands::Warehouse*>& warehouses = get_economy_by_number(i)->warehouses();
-
- for (Widelands::Warehouse* warehouse : warehouses) {
+ for (const auto& economy : economies()) {
+ for (Widelands::Warehouse* warehouse : economy.second->warehouses()) {
const Widelands::WareList& wares = warehouse->get_wares();
for (size_t id = 0; id < stocks.size(); ++id) {
stocks[id] += wares.stock(DescriptionIndex(id));
=== modified file 'src/logic/player.h'
--- src/logic/player.h 2018-04-29 09:20:29 +0000
+++ src/logic/player.h 2018-05-12 04:24:42 +0000
@@ -25,6 +25,7 @@
#include <unordered_map>
#include "base/macros.h"
+#include "economy/economy.h"
#include "graphic/color.h"
#include "graphic/playercolor.h"
#include "logic/editor_game_base.h"
@@ -40,7 +41,6 @@
class Node;
namespace Widelands {
-class Economy;
struct Path;
struct PlayerImmovable;
class Soldier;
@@ -515,18 +515,12 @@
void enhance_building(Building*, DescriptionIndex index_of_new_building);
void dismantle_building(Building*);
- // Economy stuff
- void add_economy(Economy&);
- void remove_economy(Economy&);
- bool has_economy(Economy&) const;
- using Economies = std::vector<Economy*>;
- Economies::size_type get_economy_number(Economy const*) const;
- Economy* get_economy_by_number(Economies::size_type const i) const {
- return economies_[i];
- }
- uint32_t get_nr_economies() const {
- return economies_.size();
- }
+ Economy* create_economy();
+ Economy* create_economy(Serial serial); // For saveloading only
+ void remove_economy(Serial serial);
+ const std::map<Serial,std::unique_ptr<Economy>>& economies() const;
+ Economy* get_economy(Widelands::Serial serial) const;
+ bool has_economy(Widelands::Serial serial) const;
uint32_t get_current_produced_statistics(uint8_t);
@@ -644,7 +638,7 @@
Field* fields_;
std::vector<bool> allowed_worker_types_;
std::vector<bool> allowed_building_types_;
- Economies economies_;
+ std::map<Serial,std::unique_ptr<Economy>> economies_;
std::set<Serial> ships_;
std::string name_; // Player name
std::string ai_; /**< Name of preferred AI implementation */
=== modified file 'src/logic/playercommand.cc'
--- src/logic/playercommand.cc 2018-04-07 16:59:00 +0000
+++ src/logic/playercommand.cc 2018-05-12 04:24:42 +0000
@@ -1229,8 +1229,8 @@
void CmdSetWareTargetQuantity::execute(Game& game) {
Player* player = game.get_player(sender());
- if (economy() < player->get_nr_economies() && game.tribes().ware_exists(ware_type())) {
- player->get_economy_by_number(economy())->set_ware_target_quantity(
+ if (player->has_economy(economy()) && game.tribes().ware_exists(ware_type())) {
+ player->get_economy(economy())->set_ware_target_quantity(
ware_type(), permanent_, duetime());
}
}
@@ -1280,9 +1280,9 @@
void CmdResetWareTargetQuantity::execute(Game& game) {
Player* player = game.get_player(sender());
const TribeDescr& tribe = player->tribe();
- if (economy() < player->get_nr_economies() && game.tribes().ware_exists(ware_type())) {
+ if (player->has_economy(economy()) && game.tribes().ware_exists(ware_type())) {
const int count = tribe.get_ware_descr(ware_type())->default_target_quantity(tribe.name());
- player->get_economy_by_number(economy())->set_ware_target_quantity(
+ player->get_economy(economy())->set_ware_target_quantity(
ware_type(), count, duetime());
}
}
@@ -1328,8 +1328,8 @@
void CmdSetWorkerTargetQuantity::execute(Game& game) {
Player* player = game.get_player(sender());
- if (economy() < player->get_nr_economies() && game.tribes().worker_exists(ware_type())) {
- player->get_economy_by_number(economy())->set_worker_target_quantity(
+ if (player->has_economy(economy()) && game.tribes().worker_exists(ware_type())) {
+ player->get_economy(economy())->set_worker_target_quantity(
ware_type(), permanent_, duetime());
}
}
@@ -1379,9 +1379,9 @@
void CmdResetWorkerTargetQuantity::execute(Game& game) {
Player* player = game.get_player(sender());
const TribeDescr& tribe = player->tribe();
- if (economy() < player->get_nr_economies() && game.tribes().ware_exists(ware_type())) {
+ if (player->has_economy(economy()) && game.tribes().ware_exists(ware_type())) {
const int count = tribe.get_ware_descr(ware_type())->default_target_quantity(tribe.name());
- player->get_economy_by_number(economy())->set_worker_target_quantity(
+ player->get_economy(economy())->set_worker_target_quantity(
ware_type(), count, duetime());
}
}
=== modified file 'src/logic/playercommand.h'
--- src/logic/playercommand.h 2018-04-07 16:59:00 +0000
+++ src/logic/playercommand.h 2018-05-12 04:24:42 +0000
@@ -543,7 +543,7 @@
void serialize(StreamWrite&) override;
protected:
- uint32_t economy() const {
+ Serial economy() const {
return economy_;
}
DescriptionIndex ware_type() const {
@@ -551,7 +551,7 @@
}
private:
- uint32_t economy_;
+ Serial economy_;
DescriptionIndex ware_type_;
};
=== modified file 'src/logic/widelands.h'
--- src/logic/widelands.h 2018-04-07 16:59:00 +0000
+++ src/logic/widelands.h 2018-05-12 04:24:42 +0000
@@ -84,6 +84,7 @@
}
using Serial = uint32_t; /// Serial number for MapObject.
+constexpr Serial kInvalidSerial = std::numeric_limits<uint32_t>::max();
using Direction = uint8_t;
=== modified file 'src/map_io/map_flag_packet.cc'
--- src/map_io/map_flag_packet.cc 2018-04-07 16:59:00 +0000
+++ src/map_io/map_flag_packet.cc 2018-05-12 04:24:42 +0000
@@ -35,7 +35,7 @@
namespace Widelands {
-constexpr uint16_t kCurrentPacketVersion = 1;
+constexpr uint16_t kCurrentPacketVersion = 2;
void MapFlagPacket::read(FileSystem& fs,
EditorGameBase& egbase,
@@ -63,6 +63,8 @@
throw GameDataError("Invalid player number: %i.", owner);
}
+ const Serial economy_serial = fr.unsigned_32();
+
Serial const serial = fr.unsigned_32();
try {
@@ -94,13 +96,21 @@
// No flag lives on more than one place.
+ // Get economy from serial
+ Player* player = egbase.get_player(owner);
+ Economy* economy = player->get_economy(economy_serial);
+ if (!economy) {
+ economy = player->create_economy(economy_serial);
+ }
+
// Now, create this Flag. Directly create it, do not call
// the player class since we recreate the data in another
// packet. We always create this, no matter what skip is
// since we have to read the data packets. We delete this
// object later again, if it is not wanted.
- mol.register_object<Flag>(
- serial, *new Flag(dynamic_cast<Game&>(egbase), egbase.get_player(owner), fc));
+ Flag* flag = new Flag(dynamic_cast<Game&>(egbase), player, fc, economy);
+ mol.register_object<Flag>(serial, *flag);
+
} catch (const WException& e) {
throw GameDataError(
"%u (at (%i, %i), owned by player %u): %s", serial, fc.x, fc.y, owner, e.what());
@@ -133,6 +143,7 @@
fw.unsigned_8(1);
fw.unsigned_8(flag->owner().player_number());
+ fw.unsigned_32(flag->economy().serial());
fw.unsigned_32(mos.register_object(*flag));
} else // no existence, no owner
fw.unsigned_8(0);
=== modified file 'src/scripting/lua_bases.cc'
--- src/scripting/lua_bases.cc 2018-04-07 16:59:00 +0000
+++ src/scripting/lua_bases.cc 2018-05-12 04:24:42 +0000
@@ -655,8 +655,8 @@
const DescriptionIndex worker = player.tribe().worker_index(workername);
uint32_t nworkers = 0;
- for (uint32_t i = 0; i < player.get_nr_economies(); ++i) {
- nworkers += player.get_economy_by_number(i)->stock_worker(worker);
+ for (const auto& economy : player.economies()) {
+ nworkers += economy.second->stock_worker(worker);
}
lua_pushuint32(L, nworkers);
return 1;
@@ -681,8 +681,8 @@
const DescriptionIndex ware = egbase.tribes().ware_index(warename);
uint32_t nwares = 0;
- for (uint32_t i = 0; i < player.get_nr_economies(); ++i) {
- nwares += player.get_economy_by_number(i)->stock_ware(ware);
+ for (const auto& economy : player.economies()) {
+ nwares += economy.second->stock_ware(ware);
}
lua_pushuint32(L, nwares);
return 1;
=== modified file 'src/scripting/lua_game.cc'
--- src/scripting/lua_game.cc 2018-04-16 07:03:12 +0000
+++ src/scripting/lua_game.cc 2018-05-12 04:24:42 +0000
@@ -174,16 +174,16 @@
*/
int LuaPlayer::get_defeated(lua_State* L) {
Player& p = get(L, get_egbase(L));
- bool have_warehouses = false;
+ bool is_defeated = true;
- for (uint32_t economy_nr = 0; economy_nr < p.get_nr_economies(); economy_nr++) {
- if (!p.get_economy_by_number(economy_nr)->warehouses().empty()) {
- have_warehouses = true;
+ for (const auto& economy : p.economies()) {
+ if (!economy.second->warehouses().empty()) {
+ is_defeated = false;
break;
}
}
- lua_pushboolean(L, !have_warehouses);
+ lua_pushboolean(L, is_defeated);
return 1;
}
@@ -812,10 +812,8 @@
break;
}
}
- for (uint32_t j = player.get_nr_economies(); j;) {
- Economy& economy = *player.get_economy_by_number(--j);
-
- for (Warehouse* warehouse : economy.warehouses()) {
+ for (const auto& economy: player.economies()) {
+ for (Warehouse* warehouse : economy.second->warehouses()) {
warehouse->enable_spawn(game, worker_types_without_cost_index);
}
}
=== modified file 'src/scripting/lua_map.cc'
--- src/scripting/lua_map.cc 2018-04-11 18:42:55 +0000
+++ src/scripting/lua_map.cc 2018-05-12 04:24:42 +0000
@@ -3569,16 +3569,16 @@
const Widelands::Economy* economy = get();
const Widelands::Player& player = economy->owner();
PERS_UINT32("player", player.player_number());
- PERS_UINT32("economy", player.get_economy_number(economy));
+ PERS_UINT32("economy", economy->serial());
}
void LuaEconomy::__unpersist(lua_State* L) {
Widelands::PlayerNumber player_number;
- size_t economy_number;
+ Widelands::Serial economy_serial;
UNPERS_UINT32("player", player_number);
- UNPERS_UINT32("economy", economy_number);
+ UNPERS_UINT32("economy", economy_serial);
const Widelands::Player& player = get_egbase(L).player(player_number);
- set_economy_pointer(player.get_economy_by_number(economy_number));
+ set_economy_pointer(player.get_economy(economy_serial));
}
/* RST
=== modified file 'src/wui/economy_options_window.cc'
--- src/wui/economy_options_window.cc 2018-04-07 16:59:00 +0000
+++ src/wui/economy_options_window.cc 2018-05-12 04:24:42 +0000
@@ -36,10 +36,11 @@
Widelands::Economy* economy,
bool can_act)
: UI::Window(parent, "economy_options", 0, 0, 0, 0, _("Economy options")),
- economy_(economy),
+ serial_(economy->serial()),
+ player_(&economy->owner()),
tabpanel_(this, g_gr->images().get("images/ui_basic/but1.png")),
- ware_panel_(new EconomyOptionsPanel(&tabpanel_, can_act, Widelands::wwWARE, economy)),
- worker_panel_(new EconomyOptionsPanel(&tabpanel_, can_act, Widelands::wwWORKER, economy)) {
+ ware_panel_(new EconomyOptionsPanel(&tabpanel_, serial_, player_, can_act, Widelands::wwWARE)),
+ worker_panel_(new EconomyOptionsPanel(&tabpanel_, serial_, player_, can_act, Widelands::wwWORKER)) {
set_center_panel(&tabpanel_);
tabpanel_.add("wares", g_gr->images().get(pic_tab_wares), ware_panel_, _("Wares"));
@@ -50,27 +51,29 @@
}
EconomyOptionsWindow::~EconomyOptionsWindow() {
- if (economy_ != nullptr) {
- economy_->set_has_window(false);
+ Widelands::Economy* economy = player_->get_economy(serial_);
+ if (economy != nullptr) {
+ economy->set_has_window(false);
}
}
void EconomyOptionsWindow::on_economy_note(const Widelands::NoteEconomy& note) {
- if (note.old_economy == economy_) {
+ if (note.old_economy == serial_) {
switch (note.action) {
- case Widelands::NoteEconomy::Action::kMerged:
- economy_ = note.new_economy;
+ case Widelands::NoteEconomy::Action::kMerged: {
+ serial_ = note.new_economy;
+ Widelands::Economy* economy = player_->get_economy(serial_);
+ if (economy == nullptr) {
+ die();
+ return;
+ }
+ economy->set_has_window(true);
ware_panel_->set_economy(note.new_economy);
worker_panel_->set_economy(note.new_economy);
- economy_->set_has_window(true);
move_to_top();
- break;
+ } break;
case Widelands::NoteEconomy::Action::kDeleted:
// Make sure that the panels stop thinking first.
- ware_panel_->die();
- worker_panel_->die();
- economy_->set_has_window(false);
- economy_ = nullptr;
die();
break;
}
@@ -80,12 +83,13 @@
EconomyOptionsWindow::TargetWaresDisplay::TargetWaresDisplay(UI::Panel* const parent,
int32_t const x,
int32_t const y,
+ Widelands::Serial serial,
+ Widelands::Player* player,
Widelands::WareWorker type,
- bool selectable,
- Widelands::Economy* economy)
- : AbstractWaresDisplay(parent, x, y, economy->owner().tribe(), type, selectable),
- economy_(economy) {
- const Widelands::TribeDescr& owner_tribe = economy->owner().tribe();
+ bool selectable)
+ : AbstractWaresDisplay(parent, x, y, player->tribe(), type, selectable),
+ serial_(serial), player_(player) {
+ const Widelands::TribeDescr& owner_tribe = player->tribe();
if (type == Widelands::wwWORKER) {
for (const Widelands::DescriptionIndex& worker_index : owner_tribe.workers()) {
const Widelands::WorkerDescr* worker_descr = owner_tribe.get_worker_descr(worker_index);
@@ -103,29 +107,36 @@
}
}
-void EconomyOptionsWindow::TargetWaresDisplay::set_economy(Widelands::Economy* economy) {
- economy_ = economy;
+void EconomyOptionsWindow::TargetWaresDisplay::set_economy(Widelands::Serial serial) {
+ serial_ = serial;
}
std::string
EconomyOptionsWindow::TargetWaresDisplay::info_for_ware(Widelands::DescriptionIndex const ware) {
+ Widelands::Economy* economy = player_->get_economy(serial_);
+ if (economy == nullptr) {
+ die();
+ return *(new std::string());
+ }
return boost::lexical_cast<std::string>(get_type() == Widelands::wwWORKER ?
- economy_->worker_target_quantity(ware).permanent :
- economy_->ware_target_quantity(ware).permanent);
+ economy->worker_target_quantity(ware).permanent :
+ economy->ware_target_quantity(ware).permanent);
}
/**
* Wraps the wares/workers display together with some buttons
*/
EconomyOptionsWindow::EconomyOptionsPanel::EconomyOptionsPanel(UI::Panel* parent,
+ Widelands::Serial serial,
+ Widelands::Player* player,
bool can_act,
- Widelands::WareWorker type,
- Widelands::Economy* economy)
+ Widelands::WareWorker type)
: UI::Box(parent, 0, 0, UI::Box::Vertical),
+ serial_(serial),
+ player_(player),
type_(type),
- economy_(economy),
can_act_(can_act),
- display_(this, 0, 0, type_, can_act_, economy) {
+ display_(this, 0, 0, serial_, player_, type_, can_act_) {
add(&display_, UI::Box::Resizing::kFullSize);
if (!can_act_) {
@@ -155,37 +166,34 @@
buttons->add(b);
}
-void EconomyOptionsWindow::EconomyOptionsPanel::set_economy(Widelands::Economy* economy) {
- economy_ = economy;
- display_.set_economy(economy);
+void EconomyOptionsWindow::EconomyOptionsPanel::set_economy(Widelands::Serial serial) {
+ serial_ = serial;
+ display_.set_economy(serial);
}
void EconomyOptionsWindow::EconomyOptionsPanel::change_target(int amount) {
- auto& owner = economy_->owner();
- Widelands::Game& game = dynamic_cast<Widelands::Game&>(owner.egbase());
+ Widelands::Economy* economy = player_->get_economy(serial_);
+ if (economy == nullptr) {
+ die();
+ return;
+ }
+ Widelands::Game& game = dynamic_cast<Widelands::Game&>(player_->egbase());
const bool is_wares = type_ == Widelands::wwWARE;
- const auto& items = is_wares ? owner.tribe().wares() : owner.tribe().workers();
+ const auto& items = is_wares ? player_->tribe().wares() : player_->tribe().workers();
for (const Widelands::DescriptionIndex& index : items) {
if (display_.ware_selected(index)) {
- const Widelands::Economy::TargetQuantity& tq = is_wares ?
- economy_->ware_target_quantity(index) :
- economy_->worker_target_quantity(index);
+ const Widelands::Economy::TargetQuantity& tq =
+ is_wares ? economy->ware_target_quantity(index) : economy->worker_target_quantity(index);
// Don't allow negative new amount.
if (amount >= 0 || -amount <= static_cast<int>(tq.permanent)) {
if (is_wares) {
- // TODO(sirver): This is crashy. Nobody guarantees that the
- // economy_number_ is still the same when this command finally
- // is executed. Player::remove_economy relabels economies on
- // deletion. Economies require a unique, never changing id, same
- // as map objects.
game.send_player_command(*new Widelands::CmdSetWareTargetQuantity(
- game.get_gametime(), owner.player_number(), owner.get_economy_number(economy_),
+ game.get_gametime(), player_->player_number(), serial_,
index, tq.permanent + amount));
} else {
- // TODO(sirver): Same as above
game.send_player_command(*new Widelands::CmdSetWorkerTargetQuantity(
- game.get_gametime(), owner.player_number(), owner.get_economy_number(economy_),
- index, tq.permanent + amount));
+ game.get_gametime(), player_->player_number(), serial_, index,
+ tq.permanent + amount));
}
}
}
@@ -193,19 +201,18 @@
}
void EconomyOptionsWindow::EconomyOptionsPanel::reset_target() {
- auto& owner = economy_->owner();
- Widelands::Game& game = dynamic_cast<Widelands::Game&>(owner.egbase());
+ Widelands::Game& game = dynamic_cast<Widelands::Game&>(player_->egbase());
const bool is_wares = type_ == Widelands::wwWARE;
- const auto& items = is_wares ? owner.tribe().wares() : owner.tribe().workers();
+ const auto& items = is_wares ? player_->tribe().wares() : player_->tribe().workers();
for (const Widelands::DescriptionIndex& index : items) {
if (display_.ware_selected(index)) {
if (is_wares) {
game.send_player_command(*new Widelands::CmdResetWareTargetQuantity(
- game.get_gametime(), owner.player_number(), owner.get_economy_number(economy_),
+ game.get_gametime(), player_->player_number(), serial_,
index));
} else {
game.send_player_command(*new Widelands::CmdResetWorkerTargetQuantity(
- game.get_gametime(), owner.player_number(), owner.get_economy_number(economy_),
+ game.get_gametime(), player_->player_number(), serial_,
index));
}
}
=== modified file 'src/wui/economy_options_window.h'
--- src/wui/economy_options_window.h 2018-04-07 16:59:00 +0000
+++ src/wui/economy_options_window.h 2018-05-12 04:24:42 +0000
@@ -39,17 +39,19 @@
TargetWaresDisplay(UI::Panel* const parent,
int32_t const x,
int32_t const y,
+ Widelands::Serial serial,
+ Widelands::Player* player,
Widelands::WareWorker type,
- bool selectable,
- Widelands::Economy* economy);
+ bool selectable);
- void set_economy(Widelands::Economy*);
+ void set_economy(Widelands::Serial serial);
protected:
std::string info_for_ware(Widelands::DescriptionIndex const ware) override;
private:
- Widelands::Economy* economy_;
+ Widelands::Serial serial_;
+ Widelands::Player* player_;
};
/**
@@ -57,17 +59,19 @@
*/
struct EconomyOptionsPanel : UI::Box {
EconomyOptionsPanel(UI::Panel* parent,
+ Widelands::Serial serial,
+ Widelands::Player* player,
bool can_act,
- Widelands::WareWorker type,
- Widelands::Economy* economy);
+ Widelands::WareWorker type);
- void set_economy(Widelands::Economy*);
+ void set_economy(Widelands::Serial serial);
void change_target(int amount);
void reset_target();
private:
+ Widelands::Serial serial_;
+ Widelands::Player* player_;
Widelands::WareWorker type_;
- Widelands::Economy* economy_;
bool can_act_;
TargetWaresDisplay display_;
};
@@ -75,7 +79,8 @@
/// Actions performed when a NoteEconomyWindow is received.
void on_economy_note(const Widelands::NoteEconomy& note);
- Widelands::Economy* economy_;
+ Widelands::Serial serial_;
+ Widelands::Player* player_;
UI::TabPanel tabpanel_;
EconomyOptionsPanel* ware_panel_;
EconomyOptionsPanel* worker_panel_;
=== modified file 'src/wui/stock_menu.cc'
--- src/wui/stock_menu.cc 2018-04-07 16:59:00 +0000
+++ src/wui/stock_menu.cc 2018-05-12 04:24:42 +0000
@@ -75,11 +75,9 @@
void StockMenu::fill_total_waresdisplay(WaresDisplay* waresdisplay, Widelands::WareWorker type) {
waresdisplay->remove_all_warelists();
const Widelands::Player& player = *player_.get_player();
- const uint32_t nrecos = player.get_nr_economies();
- for (uint32_t i = 0; i < nrecos; ++i)
- waresdisplay->add_warelist(type == Widelands::wwWARE ?
- player.get_economy_by_number(i)->get_wares() :
- player.get_economy_by_number(i)->get_workers());
+ for (const auto& economy : player.economies()) {
+ waresdisplay->add_warelist(type == Widelands::wwWARE ? economy.second->get_wares() : economy.second->get_workers());
+ }
}
/**
@@ -89,16 +87,10 @@
void StockMenu::fill_warehouse_waresdisplay(WaresDisplay* waresdisplay,
Widelands::WareWorker type) {
waresdisplay->remove_all_warelists();
- const Widelands::Player& player = *player_.get_player();
- const uint32_t nrecos = player.get_nr_economies();
- for (uint32_t i = 0; i < nrecos; ++i) {
- const std::vector<Widelands::Warehouse*>& warehouses =
- player.get_economy_by_number(i)->warehouses();
-
- for (std::vector<Widelands::Warehouse*>::const_iterator it = warehouses.begin();
- it != warehouses.end(); ++it) {
- waresdisplay->add_warelist(type == Widelands::wwWARE ? (*it)->get_wares() :
- (*it)->get_workers());
+ for (const auto& economy : player_.player().economies()) {
+ for (const auto* warehouse: economy.second->warehouses()) {
+ waresdisplay->add_warelist(type == Widelands::wwWARE ? warehouse->get_wares() :
+ warehouse->get_workers());
}
}
}
=== removed file 'test/maps/Aquila.wmf/binary/bob'
Binary 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
=== removed file 'test/maps/Aquila.wmf/binary/bob_data'
Binary 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
=== removed file 'test/maps/Aquila.wmf/binary/building'
Binary 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
=== added file 'test/maps/Aquila.wmf/binary/exploration'
Binary files test/maps/Aquila.wmf/binary/exploration 1970-01-01 00:00:00 +0000 and test/maps/Aquila.wmf/binary/exploration 2018-05-12 04:24:42 +0000 differ
=== removed file 'test/maps/Aquila.wmf/binary/exploration'
Binary 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
=== removed file 'test/maps/Aquila.wmf/binary/flag'
Binary 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
=== modified file 'test/maps/Aquila.wmf/binary/mapobjects'
Binary files test/maps/Aquila.wmf/binary/mapobjects 2016-08-13 18:47:51 +0000 and test/maps/Aquila.wmf/binary/mapobjects 2018-05-12 04:24:42 +0000 differ
=== added file 'test/maps/Aquila.wmf/binary/node_ownership'
Binary files test/maps/Aquila.wmf/binary/node_ownership 1970-01-01 00:00:00 +0000 and test/maps/Aquila.wmf/binary/node_ownership 2018-05-12 04:24:42 +0000 differ
=== removed file 'test/maps/Aquila.wmf/binary/node_ownership'
Binary 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
=== modified file 'test/maps/Aquila.wmf/binary/resource'
Binary files test/maps/Aquila.wmf/binary/resource 2016-08-13 18:47:51 +0000 and test/maps/Aquila.wmf/binary/resource 2018-05-12 04:24:42 +0000 differ
=== removed file 'test/maps/Aquila.wmf/binary/road'
Binary 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
=== modified file 'test/maps/Aquila.wmf/binary/terrain'
Binary files test/maps/Aquila.wmf/binary/terrain 2016-08-13 18:47:51 +0000 and test/maps/Aquila.wmf/binary/terrain 2018-05-12 04:24:42 +0000 differ
=== removed file 'test/maps/Aquila.wmf/binary/ware'
Binary 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
=== removed file 'test/maps/expedition.wmf/binary/building'
Binary 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
=== added file 'test/maps/expedition.wmf/binary/exploration'
Binary files test/maps/expedition.wmf/binary/exploration 1970-01-01 00:00:00 +0000 and test/maps/expedition.wmf/binary/exploration 2018-05-12 04:24:42 +0000 differ
=== removed file 'test/maps/expedition.wmf/binary/exploration'
Binary 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
=== removed file 'test/maps/expedition.wmf/binary/flag'
Binary 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
=== modified file 'test/maps/expedition.wmf/binary/mapobjects'
Binary files test/maps/expedition.wmf/binary/mapobjects 2013-10-05 07:50:17 +0000 and test/maps/expedition.wmf/binary/mapobjects 2018-05-12 04:24:42 +0000 differ
=== added file 'test/maps/expedition.wmf/binary/node_ownership'
Binary files test/maps/expedition.wmf/binary/node_ownership 1970-01-01 00:00:00 +0000 and test/maps/expedition.wmf/binary/node_ownership 2018-05-12 04:24:42 +0000 differ
=== removed file 'test/maps/expedition.wmf/binary/node_ownership'
Binary 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
=== modified file 'test/maps/expedition.wmf/binary/resource'
Binary files test/maps/expedition.wmf/binary/resource 2015-04-14 19:03:11 +0000 and test/maps/expedition.wmf/binary/resource 2018-05-12 04:24:42 +0000 differ
=== removed file 'test/maps/expedition.wmf/binary/road'
Binary 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
=== modified file 'test/maps/expedition.wmf/binary/terrain'
Binary files test/maps/expedition.wmf/binary/terrain 2015-04-14 19:03:11 +0000 and test/maps/expedition.wmf/binary/terrain 2018-05-12 04:24:42 +0000 differ
=== removed file 'test/maps/lua_persistence.wmf/binary/bob'
Binary 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
=== removed file 'test/maps/lua_persistence.wmf/binary/building'
Binary 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
=== added file 'test/maps/lua_persistence.wmf/binary/exploration'
Binary files test/maps/lua_persistence.wmf/binary/exploration 1970-01-01 00:00:00 +0000 and test/maps/lua_persistence.wmf/binary/exploration 2018-05-12 04:24:42 +0000 differ
=== removed file 'test/maps/lua_persistence.wmf/binary/exploration'
Binary 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
=== removed file 'test/maps/lua_persistence.wmf/binary/flag'
Binary 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
=== modified file 'test/maps/lua_persistence.wmf/binary/mapobjects'
Binary files test/maps/lua_persistence.wmf/binary/mapobjects 2012-02-15 21:25:34 +0000 and test/maps/lua_persistence.wmf/binary/mapobjects 2018-05-12 04:24:42 +0000 differ
=== added file 'test/maps/lua_persistence.wmf/binary/node_ownership'
Binary 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-05-12 04:24:42 +0000 differ
=== removed file 'test/maps/lua_persistence.wmf/binary/node_ownership'
Binary 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
=== modified file 'test/maps/lua_persistence.wmf/binary/resource'
Binary files test/maps/lua_persistence.wmf/binary/resource 2012-02-15 21:25:34 +0000 and test/maps/lua_persistence.wmf/binary/resource 2018-05-12 04:24:42 +0000 differ
=== removed file 'test/maps/lua_persistence.wmf/binary/road'
Binary 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
=== modified file 'test/maps/lua_persistence.wmf/binary/terrain'
Binary files test/maps/lua_persistence.wmf/binary/terrain 2012-02-15 21:25:34 +0000 and test/maps/lua_persistence.wmf/binary/terrain 2018-05-12 04:24:42 +0000 differ
=== removed file 'test/maps/lua_testsuite.wmf/binary/bob'
Binary 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
=== removed file 'test/maps/lua_testsuite.wmf/binary/building'
Binary 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
=== added file 'test/maps/lua_testsuite.wmf/binary/exploration'
Binary files test/maps/lua_testsuite.wmf/binary/exploration 1970-01-01 00:00:00 +0000 and test/maps/lua_testsuite.wmf/binary/exploration 2018-05-12 04:24:42 +0000 differ
=== removed file 'test/maps/lua_testsuite.wmf/binary/exploration'
Binary 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
=== removed file 'test/maps/lua_testsuite.wmf/binary/flag'
Binary 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
=== modified file 'test/maps/lua_testsuite.wmf/binary/mapobjects'
Binary files test/maps/lua_testsuite.wmf/binary/mapobjects 2015-04-14 18:34:40 +0000 and test/maps/lua_testsuite.wmf/binary/mapobjects 2018-05-12 04:24:42 +0000 differ
=== added file 'test/maps/lua_testsuite.wmf/binary/node_ownership'
Binary 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-05-12 04:24:42 +0000 differ
=== removed file 'test/maps/lua_testsuite.wmf/binary/node_ownership'
Binary 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
=== modified file 'test/maps/lua_testsuite.wmf/binary/resource'
Binary files test/maps/lua_testsuite.wmf/binary/resource 2015-04-14 18:34:40 +0000 and test/maps/lua_testsuite.wmf/binary/resource 2018-05-12 04:24:42 +0000 differ
=== removed file 'test/maps/lua_testsuite.wmf/binary/road'
Binary 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
=== modified file 'test/maps/lua_testsuite.wmf/binary/terrain'
Binary files test/maps/lua_testsuite.wmf/binary/terrain 2015-04-14 18:34:40 +0000 and test/maps/lua_testsuite.wmf/binary/terrain 2018-05-12 04:24:42 +0000 differ
=== removed file 'test/maps/plain.wmf/binary/building'
Binary 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
=== added file 'test/maps/plain.wmf/binary/exploration'
Binary files test/maps/plain.wmf/binary/exploration 1970-01-01 00:00:00 +0000 and test/maps/plain.wmf/binary/exploration 2018-05-12 04:24:42 +0000 differ
=== removed file 'test/maps/plain.wmf/binary/exploration'
Binary 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
=== removed file 'test/maps/plain.wmf/binary/flag'
Binary 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
=== modified file 'test/maps/plain.wmf/binary/mapobjects'
Binary files test/maps/plain.wmf/binary/mapobjects 2014-06-20 14:38:48 +0000 and test/maps/plain.wmf/binary/mapobjects 2018-05-12 04:24:42 +0000 differ
=== added file 'test/maps/plain.wmf/binary/node_ownership'
Binary files test/maps/plain.wmf/binary/node_ownership 1970-01-01 00:00:00 +0000 and test/maps/plain.wmf/binary/node_ownership 2018-05-12 04:24:42 +0000 differ
=== removed file 'test/maps/plain.wmf/binary/node_ownership'
Binary 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
=== modified file 'test/maps/plain.wmf/binary/resource'
Binary files test/maps/plain.wmf/binary/resource 2014-06-22 17:09:42 +0000 and test/maps/plain.wmf/binary/resource 2018-05-12 04:24:42 +0000 differ
=== removed file 'test/maps/plain.wmf/binary/road'
Binary 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
=== modified file 'test/maps/plain.wmf/binary/terrain'
Binary files test/maps/plain.wmf/binary/terrain 2014-06-22 17:09:42 +0000 and test/maps/plain.wmf/binary/terrain 2018-05-12 04:24:42 +0000 differ
=== modified file 'test/maps/port_space.wmf/binary/mapobjects'
Binary files test/maps/port_space.wmf/binary/mapobjects 2016-02-08 20:44:17 +0000 and test/maps/port_space.wmf/binary/mapobjects 2018-05-12 04:24:42 +0000 differ
=== modified file 'test/maps/port_space.wmf/binary/terrain'
Binary files test/maps/port_space.wmf/binary/terrain 2016-02-08 20:44:17 +0000 and test/maps/port_space.wmf/binary/terrain 2018-05-12 04:24:42 +0000 differ
=== removed file 'test/maps/ship_transportation.wmf/binary/building'
Binary 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
=== added file 'test/maps/ship_transportation.wmf/binary/exploration'
Binary files test/maps/ship_transportation.wmf/binary/exploration 1970-01-01 00:00:00 +0000 and test/maps/ship_transportation.wmf/binary/exploration 2018-05-12 04:24:42 +0000 differ
=== removed file 'test/maps/ship_transportation.wmf/binary/exploration'
Binary 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
=== removed file 'test/maps/ship_transportation.wmf/binary/flag'
Binary 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
=== modified file 'test/maps/ship_transportation.wmf/binary/mapobjects'
Binary files test/maps/ship_transportation.wmf/binary/mapobjects 2013-10-31 18:52:52 +0000 and test/maps/ship_transportation.wmf/binary/mapobjects 2018-05-12 04:24:42 +0000 differ
=== added file 'test/maps/ship_transportation.wmf/binary/node_ownership'
Binary 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-05-12 04:24:42 +0000 differ
=== removed file 'test/maps/ship_transportation.wmf/binary/node_ownership'
Binary 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
=== modified file 'test/maps/ship_transportation.wmf/binary/resource'
Binary files test/maps/ship_transportation.wmf/binary/resource 2013-10-31 18:52:52 +0000 and test/maps/ship_transportation.wmf/binary/resource 2018-05-12 04:24:42 +0000 differ
=== removed file 'test/maps/ship_transportation.wmf/binary/road'
Binary 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
=== modified file 'test/maps/ship_transportation.wmf/binary/terrain'
Binary files test/maps/ship_transportation.wmf/binary/terrain 2013-10-31 18:52:52 +0000 and test/maps/ship_transportation.wmf/binary/terrain 2018-05-12 04:24:42 +0000 differ
Follow ups
-
[Merge] lp:~widelands-dev/widelands/bug-1732765-economy-refactoring into lp:widelands
From: noreply, 2018-07-12
-
Re: [Merge] lp:~widelands-dev/widelands/bug-1732765-economy-refactoring into lp:widelands
From: GunChleoc, 2018-07-12
-
[Merge] lp:~widelands-dev/widelands/bug-1732765-economy-refactoring into lp:widelands
From: bunnybot, 2018-07-11
-
[Merge] lp:~widelands-dev/widelands/bug-1732765-economy-refactoring into lp:widelands
From: bunnybot, 2018-07-11
-
Re: [Merge] lp:~widelands-dev/widelands/bug-1732765-economy-refactoring into lp:widelands
From: GunChleoc, 2018-07-11
-
Re: [Merge] lp:~widelands-dev/widelands/bug-1732765-economy-refactoring into lp:widelands
From: GunChleoc, 2018-07-11
-
[Merge] lp:~widelands-dev/widelands/bug-1732765-economy-refactoring into lp:widelands
From: bunnybot, 2018-07-05
-
[Merge] lp:~widelands-dev/widelands/bug-1732765-economy-refactoring into lp:widelands
From: bunnybot, 2018-07-04
-
Re: [Merge] lp:~widelands-dev/widelands/bug-1732765-economy-refactoring into lp:widelands
From: Klaus Halfmann, 2018-06-19
-
Re: [Merge] lp:~widelands-dev/widelands/bug-1732765-economy-refactoring into lp:widelands
From: GunChleoc, 2018-06-19
-
Re: [Merge] lp:~widelands-dev/widelands/bug-1732765-economy-refactoring into lp:widelands
From: Klaus Halfmann, 2018-06-19
-
Re: [Merge] lp:~widelands-dev/widelands/bug-1732765-economy-refactoring into lp:widelands
From: Klaus Halfmann, 2018-06-19
-
Re: [Merge] lp:~widelands-dev/widelands/bug-1732765-economy-refactoring into lp:widelands
From: GunChleoc, 2018-06-04
-
[Merge] lp:~widelands-dev/widelands/bug-1732765-economy-refactoring into lp:widelands
From: bunnybot, 2018-06-02
-
Re: [Merge] lp:~widelands-dev/widelands/bug-1732765-economy-refactoring into lp:widelands
From: ypopezios, 2018-06-02
-
Re: [Merge] lp:~widelands-dev/widelands/bug-1732765-economy-refactoring into lp:widelands
From: Klaus Halfmann, 2018-06-02
-
[Merge] lp:~widelands-dev/widelands/bug-1732765-economy-refactoring into lp:widelands
From: bunnybot, 2018-06-02
-
Re: [Merge] lp:~widelands-dev/widelands/bug-1732765-economy-refactoring into lp:widelands
From: Klaus Halfmann, 2018-06-02
-
Re: [Merge] lp:~widelands-dev/widelands/bug-1732765-economy-refactoring into lp:widelands
From: GunChleoc, 2018-05-28
-
Re: [Merge] lp:~widelands-dev/widelands/bug-1732765-economy-refactoring into lp:widelands
From: Klaus Halfmann, 2018-05-27
-
Re: [Merge] lp:~widelands-dev/widelands/bug-1732765-economy-refactoring into lp:widelands
From: GunChleoc, 2018-05-26
-
Re: [Merge] lp:~widelands-dev/widelands/bug-1732765-economy-refactoring into lp:widelands
From: GunChleoc, 2018-05-25
-
Re: [Merge] lp:~widelands-dev/widelands/bug-1732765-economy-refactoring into lp:widelands
From: GunChleoc, 2018-05-25
-
Re: [Merge] lp:~widelands-dev/widelands/bug-1732765-economy-refactoring into lp:widelands
From: Klaus Halfmann, 2018-05-23
-
Re: [Merge] lp:~widelands-dev/widelands/bug-1732765-economy-refactoring into lp:widelands
From: Klaus Halfmann, 2018-05-22
-
[Merge] lp:~widelands-dev/widelands/bug-1732765-economy-refactoring into lp:widelands
From: bunnybot, 2018-05-13
-
[Merge] lp:~widelands-dev/widelands/bug-1732765-economy-refactoring into lp:widelands
From: bunnybot, 2018-05-12