← Back to team overview

widelands-dev team mailing list archive

Re: [Merge] lp:~widelands-dev/widelands/constructionsite_options into lp:widelands

 

The changes look good - there are still some open comments, though. Sorry it took me a while to get back to this.

Diff comments:

> 
> === added file 'src/logic/map_objects/tribes/building_settings.cc'
> --- src/logic/map_objects/tribes/building_settings.cc	1970-01-01 00:00:00 +0000
> +++ src/logic/map_objects/tribes/building_settings.cc	2019-05-28 15:09:01 +0000
> @@ -0,0 +1,346 @@
> +/*
> + * Copyright (C) 2002-2019 by the Widelands Development Team
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * as published by the Free Software Foundation; either version 2
> + * of the License, or (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
> + *
> + */
> +
> +#include "logic/map_objects/tribes/building_settings.h"
> +
> +#include "io/fileread.h"
> +#include "io/filewrite.h"
> +#include "logic/game.h"
> +#include "logic/game_data_error.h"
> +#include "logic/map_objects/tribes/militarysite.h"
> +#include "logic/map_objects/tribes/productionsite.h"
> +#include "logic/map_objects/tribes/trainingsite.h"
> +#include "logic/map_objects/tribes/tribe_descr.h"
> +#include "logic/map_objects/tribes/warehouse.h"
> +
> +namespace Widelands {
> +
> +ProductionsiteSettings::ProductionsiteSettings(const ProductionSiteDescr& descr)
> +		: BuildingSettings(descr.name()), stopped(false) {
> +	for (WareRange i(descr.input_wares()); i; ++i) {

The WareRange struct still exists and is being used in productionsites - please get rid of it completely.

> +		ware_queues.push_back(std::make_pair(i.current->first,
> +				InputQueueSetting{i.current->second, i.current->second, kPriorityNormal}));
> +	}
> +	for (WareRange i(descr.input_workers()); i; ++i) {
> +		worker_queues.push_back(std::make_pair(i.current->first,
> +				InputQueueSetting{i.current->second, i.current->second, kPriorityNormal}));
> +	}
> +}
> +
> +MilitarysiteSettings::MilitarysiteSettings(const MilitarySiteDescr& descr)
> +		: BuildingSettings(descr.name()),
> +	  max_capacity(descr.get_max_number_of_soldiers()),
> +	  desired_capacity(descr.get_max_number_of_soldiers()),
> +	  prefer_heroes(descr.prefers_heroes_at_start_) {
> +}
> +
> +TrainingsiteSettings::TrainingsiteSettings(const TrainingSiteDescr& descr)
> +	: ProductionsiteSettings(descr),
> +	  max_capacity(descr.get_max_number_of_soldiers()),
> +	  desired_capacity(descr.get_max_number_of_soldiers()) {
> +}
> +
> +WarehouseSettings::WarehouseSettings(const WarehouseDescr& wh, const TribeDescr& tribe)
> +		: BuildingSettings(wh.name()), launch_expedition_allowed(wh.get_isport()), launch_expedition(false) {
> +	for (const DescriptionIndex di : tribe.wares()) {
> +		ware_preferences.emplace(di, StockPolicy::kNormal);

Duh, forget that I mentioned it - I got confused with the economy settings window.

> +	}
> +	for (const DescriptionIndex di : tribe.workers()) {
> +		worker_preferences.emplace(di, StockPolicy::kNormal);

This has not been cleaned up yet

> +	}
> +	for (const DescriptionIndex di : tribe.worker_types_without_cost()) {
> +		worker_preferences.erase(di);
> +	}
> +}
> +
> +void ProductionsiteSettings::apply(const BuildingSettings& bs) {
> +	BuildingSettings::apply(bs);
> +	if (upcast(const ProductionsiteSettings, s, &bs)) {
> +		stopped = s->stopped;
> +		for (auto& pair : ware_queues) {
> +			for (const auto& other : s->ware_queues) {
> +				if (pair.first == other.first) {
> +					pair.second.priority = other.second.priority;
> +					pair.second.desired_fill = std::min(pair.second.max_fill, other.second.desired_fill);
> +					break;
> +				}
> +			}
> +		}
> +		for (auto& pair : worker_queues) {
> +			for (const auto& other : s->worker_queues) {
> +				if (pair.first == other.first) {
> +					pair.second.priority = other.second.priority;
> +					pair.second.desired_fill = std::min(pair.second.max_fill, other.second.desired_fill);
> +					break;
> +				}
> +			}
> +		}
> +	}
> +}
> +
> +void TrainingsiteSettings::apply(const BuildingSettings& bs) {
> +	ProductionsiteSettings::apply(bs);
> +	if (upcast(const TrainingsiteSettings, s, &bs)) {
> +		desired_capacity = std::min(max_capacity, s->desired_capacity);
> +	}
> +}
> +
> +void MilitarysiteSettings::apply(const BuildingSettings& bs) {
> +	BuildingSettings::apply(bs);
> +	if (upcast(const MilitarysiteSettings, s, &bs)) {
> +		desired_capacity = std::min(max_capacity, s->desired_capacity);
> +		prefer_heroes = s->prefer_heroes;
> +	}
> +}
> +
> +void WarehouseSettings::apply(const BuildingSettings& bs) {
> +	BuildingSettings::apply(bs);
> +	if (upcast(const WarehouseSettings, s, &bs)) {
> +		for (auto& pair : ware_preferences) {
> +			const auto it = s->ware_preferences.find(pair.first);
> +			if (it != s->ware_preferences.end()) {
> +				pair.second = it->second;
> +			}
> +		}
> +		for (auto& pair : worker_preferences) {
> +			const auto it = s->worker_preferences.find(pair.first);
> +			if (it != s->worker_preferences.end()) {
> +				pair.second = it->second;
> +			}
> +		}
> +		launch_expedition = launch_expedition_allowed && s->launch_expedition;
> +	}
> +}
> +
> +// Saveloading
> +
> +constexpr uint8_t kCurrentPacketVersion = 1;
> +constexpr uint8_t kCurrentPacketVersionMilitarysite = 1;
> +constexpr uint8_t kCurrentPacketVersionProductionsite = 1;
> +constexpr uint8_t kCurrentPacketVersionTrainingsite = 1;
> +constexpr uint8_t kCurrentPacketVersionWarehouse = 1;
> +
> +enum class BuildingType : uint8_t {
> +	kWarehouse = 1,
> +	kProductionsite = 2,
> +	kTrainingsite = 3,
> +	kMilitarysite = 4,
> +};
> +
> +// static
> +BuildingSettings* BuildingSettings::load(const Game& game, const TribeDescr& tribe, FileRead& fr) {
> +	try {
> +		const uint8_t packet_version = fr.unsigned_8();
> +		if (packet_version == kCurrentPacketVersion) {
> +			const std::string name(fr.c_string());
> +			const DescriptionIndex index = game.tribes().building_index(name);
> +			const BuildingType type = static_cast<BuildingType>(fr.unsigned_8());
> +			BuildingSettings* result = nullptr;
> +			switch (type) {
> +				case BuildingType::kTrainingsite: {
> +					result = new TrainingsiteSettings(*dynamic_cast<const TrainingSiteDescr*>(
> +							game.tribes().get_building_descr(index)));
> +					break;
> +				}
> +				case BuildingType::kProductionsite: {
> +					result = new ProductionsiteSettings(*dynamic_cast<const ProductionSiteDescr*>(
> +							game.tribes().get_building_descr(index)));
> +					break;
> +				}
> +				case BuildingType::kMilitarysite: {
> +					result = new MilitarysiteSettings(*dynamic_cast<const MilitarySiteDescr*>(
> +							game.tribes().get_building_descr(index)));
> +					break;
> +				}
> +				case BuildingType::kWarehouse: {
> +					result = new WarehouseSettings(*dynamic_cast<const WarehouseDescr*>(
> +							game.tribes().get_building_descr(index)), tribe);
> +					break;
> +				}
> +			}
> +			if (!result) {
> +				throw wexception("Unknown building category %u (%s)", static_cast<uint8_t>(type), name.c_str());
> +			}
> +			result->read(game, fr);
> +			return result;
> +		} else {
> +			throw UnhandledVersionError(
> +			   "BuildingSettings_load", packet_version, kCurrentPacketVersion);
> +		}
> +	} catch (const WException& e) {
> +		throw GameDataError("BuildingSettings_load: %s", e.what());
> +	}
> +	NEVER_HERE();
> +}
> +
> +void BuildingSettings::read(const Game&, FileRead&) {
> +	// Header was peeled away by load()
> +}
> +
> +void BuildingSettings::save(const Game&, FileWrite& fw) const {
> +	fw.unsigned_8(kCurrentPacketVersion);
> +	fw.c_string(descr_.c_str());
> +}
> +
> +void MilitarysiteSettings::read(const Game& game, FileRead& fr) {
> +	BuildingSettings::read(game, fr);
> +	try {
> +		const uint8_t packet_version = fr.unsigned_8();
> +		if (packet_version == kCurrentPacketVersionMilitarysite) {
> +			desired_capacity = fr.unsigned_32();
> +			prefer_heroes = fr.unsigned_8();
> +		} else {
> +			throw UnhandledVersionError(
> +			   "MilitarysiteSettings", packet_version, kCurrentPacketVersionMilitarysite);
> +		}
> +	} catch (const WException& e) {
> +		throw GameDataError("MilitarysiteSettings: %s", e.what());
> +	}
> +}
> +
> +void MilitarysiteSettings::save(const Game& game, FileWrite& fw) const {
> +	BuildingSettings::save(game, fw);
> +	fw.unsigned_8(static_cast<uint8_t>(BuildingType::kMilitarysite));
> +	fw.unsigned_8(kCurrentPacketVersionMilitarysite);
> +
> +	fw.unsigned_32(desired_capacity);
> +	fw.unsigned_8(prefer_heroes ? 1 : 0);
> +}
> +
> +void ProductionsiteSettings::read(const Game& game, FileRead& fr) {
> +	BuildingSettings::read(game, fr);
> +	try {
> +		const uint8_t packet_version = fr.unsigned_8();
> +		if (packet_version == kCurrentPacketVersionProductionsite) {
> +			stopped = fr.unsigned_8();
> +			const uint32_t nr_wares = fr.unsigned_32();
> +			const uint32_t nr_workers = fr.unsigned_32();
> +			for (uint32_t i = 0; i < nr_wares; ++i) {
> +				const DescriptionIndex di = fr.unsigned_32();
> +				const uint32_t fill = fr.unsigned_32();
> +				const int32_t priority = fr.signed_32();
> +				ware_queues.at(i).first = di;
> +				ware_queues.at(i).second.desired_fill = fill;
> +				ware_queues.at(i).second.priority = priority;
> +			}
> +			for (uint32_t i = 0; i < nr_workers; ++i) {
> +				const DescriptionIndex di = fr.unsigned_32();
> +				const uint32_t fill = fr.unsigned_32();
> +				const int32_t priority = fr.signed_32();
> +				worker_queues.at(i).first = di;
> +				worker_queues.at(i).second.desired_fill = fill;
> +				worker_queues.at(i).second.priority = priority;
> +			}
> +		} else {
> +			throw UnhandledVersionError(
> +			   "ProductionsiteSettings", packet_version, kCurrentPacketVersionProductionsite);
> +		}
> +	} catch (const WException& e) {
> +		throw GameDataError("ProductionsiteSettings: %s", e.what());
> +	}
> +}
> +
> +void ProductionsiteSettings::save(const Game& game, FileWrite& fw) const {
> +	BuildingSettings::save(game, fw);
> +	fw.unsigned_8(static_cast<uint8_t>(BuildingType::kProductionsite));
> +	fw.unsigned_8(kCurrentPacketVersionProductionsite);
> +
> +	fw.unsigned_8(stopped ? 1 : 0);
> +	fw.unsigned_32(ware_queues.size());
> +	fw.unsigned_32(worker_queues.size());
> +	for (const auto& pair : ware_queues) {
> +		fw.unsigned_32(pair.first);
> +		fw.unsigned_32(pair.second.desired_fill);
> +		fw.signed_32(pair.second.priority);
> +	}
> +	for (const auto& pair : worker_queues) {
> +		fw.unsigned_32(pair.first);
> +		fw.unsigned_32(pair.second.desired_fill);
> +		fw.signed_32(pair.second.priority);
> +	}
> +}
> +
> +void TrainingsiteSettings::read(const Game& game, FileRead& fr) {
> +	ProductionsiteSettings::read(game, fr);
> +	try {
> +		const uint8_t packet_version = fr.unsigned_8();
> +		if (packet_version == kCurrentPacketVersionTrainingsite) {
> +			desired_capacity = fr.unsigned_32();
> +		} else {
> +			throw UnhandledVersionError(
> +			   "TrainingsiteSettings", packet_version, kCurrentPacketVersionTrainingsite);
> +		}
> +	} catch (const WException& e) {
> +		throw GameDataError("TrainingsiteSettings: %s", e.what());
> +	}
> +}
> +
> +void TrainingsiteSettings::save(const Game& game, FileWrite& fw) const {
> +	ProductionsiteSettings::save(game, fw);
> +	fw.unsigned_8(static_cast<uint8_t>(BuildingType::kTrainingsite));
> +	fw.unsigned_8(kCurrentPacketVersionTrainingsite);
> +	fw.unsigned_32(desired_capacity);
> +}
> +
> +void WarehouseSettings::read(const Game& game, FileRead& fr) {
> +	BuildingSettings::read(game, fr);
> +	try {
> +		const uint8_t packet_version = fr.unsigned_8();
> +		if (packet_version == kCurrentPacketVersionWarehouse) {
> +			launch_expedition = fr.unsigned_8();
> +			const uint32_t nr_wares = fr.unsigned_32();
> +			const uint32_t nr_workers = fr.unsigned_32();
> +			for (uint32_t i = 0; i < nr_wares; ++i) {
> +				const DescriptionIndex di = fr.unsigned_32();
> +				const uint8_t pref = fr.unsigned_8();
> +				ware_preferences[di] = static_cast<StockPolicy>(pref);
> +			}
> +			for (uint32_t i = 0; i < nr_workers; ++i) {
> +				const DescriptionIndex di = fr.unsigned_32();
> +				const uint8_t pref = fr.unsigned_8();
> +				worker_preferences[di] = static_cast<StockPolicy>(pref);
> +			}
> +		} else {
> +			throw UnhandledVersionError(
> +			   "WarehouseSettings", packet_version, kCurrentPacketVersionWarehouse);
> +		}
> +	} catch (const WException& e) {
> +		throw GameDataError("WarehouseSettings: %s", e.what());
> +	}
> +}
> +
> +void WarehouseSettings::save(const Game& game, FileWrite& fw) const {
> +	BuildingSettings::save(game, fw);
> +	fw.unsigned_8(static_cast<uint8_t>(BuildingType::kWarehouse));
> +	fw.unsigned_8(kCurrentPacketVersionWarehouse);
> +
> +	fw.unsigned_8(launch_expedition ? 1 : 0);
> +	fw.unsigned_32(ware_preferences.size());
> +	fw.unsigned_32(worker_preferences.size());
> +	for (const auto& pair : ware_preferences) {
> +		fw.unsigned_32(pair.first);
> +		fw.unsigned_8(static_cast<uint8_t>(pair.second));
> +	}
> +	for (const auto& pair : worker_preferences) {
> +		fw.unsigned_32(pair.first);
> +		fw.unsigned_8(static_cast<uint8_t>(pair.second));
> +	}
> +}
> +
> +} // namespace Widelands
> 
> === modified file 'src/logic/map_objects/tribes/constructionsite.cc'
> --- src/logic/map_objects/tribes/constructionsite.cc	2019-05-26 17:21:15 +0000
> +++ src/logic/map_objects/tribes/constructionsite.cc	2019-05-28 15:09:01 +0000
> @@ -214,6 +321,138 @@
>  
>  /*
>  ===============
> +Start building the next enhancement even before the base building is completed.
> +===============
> +*/
> +void ConstructionSite::enhance(Game&) {
> +	assert(building_->enhancement() != INVALID_INDEX);
> +	Notifications::publish(NoteImmovable(this, NoteImmovable::Ownership::LOST));
> +
> +	info_.intermediates.push_back(building_);
> +	old_buildings_.push_back(owner().tribe().building_index(building_->name()));
> +	building_ = owner().tribe().get_building_descr(building_->enhancement());
> +	assert(building_);
> +	info_.becomes = building_;
> +
> +	const std::map<DescriptionIndex, uint8_t>& buildcost = building_->enhancement_cost();
> +	const size_t buildcost_size = buildcost.size();
> +	std::set<DescriptionIndex> new_ware_types;
> +	for (std::map<DescriptionIndex, uint8_t>::const_iterator it = buildcost.begin(); it != buildcost.end(); ++it) {
> +		bool found = false;
> +		for (const auto& queue : wares_) {
> +			if (queue->get_index() == it->first) {
> +				found = true;
> +				break;
> +			}
> +		}
> +		if (!found) {
> +			new_ware_types.insert(it->first);
> +		}
> +	}
> +
> +	const size_t old_size = wares_.size();
> +	wares_.resize(old_size + new_ware_types.size());
> +	std::map<DescriptionIndex, uint8_t>::const_iterator it = buildcost.begin();
> +
> +	size_t new_wares_index = 0;
> +	for (size_t i = 0; i < buildcost_size; ++i, ++it) {
> +		if (new_ware_types.count(it->first)) {
> +			WaresQueue& wq = *(wares_[old_size + new_wares_index] = new WaresQueue(*this, it->first, it->second));
> +			wq.set_callback(ConstructionSite::wares_queue_callback, this);
> +			wq.set_consume_interval(CONSTRUCTIONSITE_STEP_TIME);
> +			++new_wares_index;
> +		} else {
> +			assert(i >= new_wares_index);
> +			WaresQueue& wq = *wares_[i - new_wares_index];
> +			wq.set_max_size(wq.get_max_size() + it->second);
> +			wq.set_max_fill(wq.get_max_fill() + it->second);
> +		}
> +		work_steps_ += it->second;
> +	}
> +
> +	BuildingSettings* old_settings = settings_.release();
> +	if (upcast(const WarehouseDescr, wd, building_)) {
> +		WarehouseSettings* new_settings = new WarehouseSettings(*wd, owner().tribe());
> +		settings_.reset(new_settings);
> +		if (upcast(WarehouseSettings, ws, old_settings)) {
> +			for (const auto& pair : ws->ware_preferences) {
> +				new_settings->ware_preferences[pair.first] = pair.second;
> +			}
> +			for (const auto& pair : ws->worker_preferences) {
> +				new_settings->worker_preferences[pair.first] = pair.second;
> +			}
> +			new_settings->launch_expedition = ws->launch_expedition && building_->get_isport();
> +		}
> +	} else if (upcast(const TrainingSiteDescr, td, building_)) {
> +		TrainingsiteSettings* new_settings = new TrainingsiteSettings(*td);
> +		settings_.reset(new_settings);
> +		if (upcast(ProductionsiteSettings, ps, old_settings)) {
> +			new_settings->stopped = ps->stopped;
> +			for (const auto& pair_old : ps->ware_queues) {
> +				for (auto& pair_new : new_settings->ware_queues) {

I'm wondering whether they always get added to the vectors in the same order, in which case we could assert() that the DescriptionIndex matches.

> +					if (pair_new.first == pair_old.first) {
> +						pair_new.second.priority = pair_old.second.priority;
> +						pair_new.second.desired_fill = std::min(pair_old.second.desired_fill, pair_new.second.max_fill);
> +						break;
> +					}
> +				}
> +			}
> +			for (const auto& pair_old : ps->worker_queues) {
> +				for (auto& pair_new : new_settings->worker_queues) {
> +					if (pair_new.first == pair_old.first) {
> +						pair_new.second.priority = pair_old.second.priority;
> +						pair_new.second.desired_fill = std::min(pair_old.second.desired_fill, pair_new.second.max_fill);
> +						break;
> +					}
> +				}
> +			}
> +			if (upcast(TrainingsiteSettings, ts, old_settings)) {
> +				new_settings->desired_capacity = std::min(new_settings->max_capacity, ts->desired_capacity);
> +			}
> +		}
> +	} else if (upcast(const ProductionSiteDescr, pd, building_)) {
> +		ProductionsiteSettings* new_settings = new ProductionsiteSettings(*pd);
> +		settings_.reset(new_settings);
> +		if (upcast(ProductionsiteSettings, ps, old_settings)) {
> +			new_settings->stopped = ps->stopped;
> +			for (const auto& pair_old : ps->ware_queues) {
> +				for (auto& pair_new : new_settings->ware_queues) {
> +					if (pair_new.first == pair_old.first) {
> +						pair_new.second.priority = pair_old.second.priority;
> +						pair_new.second.desired_fill = std::min(pair_old.second.desired_fill, pair_new.second.max_fill);
> +						break;
> +					}
> +				}
> +			}
> +			for (const auto& pair_old : ps->worker_queues) {
> +				for (auto& pair_new : new_settings->worker_queues) {
> +					if (pair_new.first == pair_old.first) {
> +						pair_new.second.priority = pair_old.second.priority;
> +						pair_new.second.desired_fill = std::min(pair_old.second.desired_fill, pair_new.second.max_fill);
> +						break;
> +					}
> +				}
> +			}
> +		}
> +	} else if (upcast(const MilitarySiteDescr, md, building_)) {
> +		MilitarysiteSettings* new_settings = new MilitarysiteSettings(*md);
> +		settings_.reset(new_settings);
> +		if (upcast(MilitarysiteSettings, ms, old_settings)) {
> +			new_settings->desired_capacity = std::max<uint32_t>(1, std::min<uint32_t>(
> +					new_settings->max_capacity, ms->desired_capacity));
> +			new_settings->prefer_heroes = ms->prefer_heroes;
> +		}
> +	} else {
> +		// TODO(Nordfriese): Add support for markets when trading is implemented
> +		log("WARNING: Enhanced constructionsite to a %s, which is not of any known building type\n",
> +				building_->name().c_str());
> +	}
> +	Notifications::publish(NoteImmovable(this, NoteImmovable::Ownership::GAINED));
> +	Notifications::publish(NoteBuilding(serial(), NoteBuilding::Action::kChanged));
> +}
> +
> +/*
> +===============
>  Construction sites only burn if some of the work has been completed.
>  ===============
>  */
> 
> === modified file 'src/logic/map_objects/tribes/militarysite.cc'
> --- src/logic/map_objects/tribes/militarysite.cc	2019-05-26 17:21:15 +0000
> +++ src/logic/map_objects/tribes/militarysite.cc	2019-05-28 15:09:01 +0000
> @@ -982,6 +982,13 @@
>  	return false;
>  }
>  
> +const BuildingSettings* MilitarySite::create_building_settings() const {
> +	MilitarysiteSettings* settings = new MilitarysiteSettings(descr());
> +	settings->desired_capacity = std::min(settings->max_capacity, soldier_control_.soldier_capacity());
> +	settings->prefer_heroes = soldier_preference_ == SoldierPreference::kHeroes;

Have you looked into this?

> +	return settings;
> +}
> +
>  // setters
>  
>  void MilitarySite::set_soldier_preference(SoldierPreference p) {


-- 
https://code.launchpad.net/~widelands-dev/widelands/constructionsite_options/+merge/367428
Your team Widelands Developers is subscribed to branch lp:~widelands-dev/widelands/constructionsite_options.


References