aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author CptAlanSmith <123112708+CptAlanSmith@users.noreply.github.com>2023-09-24 20:06:36 +0200
committer GitHub <noreply@github.com>2023-09-24 20:06:36 +0200
commit5b0a02a1bd8caad21caa7d000173270d31df4201 (patch)
tree12d44479a568ece48286b67d6a0d2940495b445e
parent33eeede65f7eede0e89420dbd8d83284ec6de2a7 (diff)
parenteb425a600c03ca02d922a1b20a2815a57104f3cc (diff)
Merge pull request #30 from OpenVicProject/dataloading-production
Implemented ProductionTypes
-rw-r--r--src/openvic-simulation/GameManager.cpp10
-rw-r--r--src/openvic-simulation/GameManager.hpp4
-rw-r--r--src/openvic-simulation/dataloader/Dataloader.cpp7
-rw-r--r--src/openvic-simulation/economy/ProductionType.cpp277
-rw-r--r--src/openvic-simulation/economy/ProductionType.hpp115
5 files changed, 411 insertions, 2 deletions
diff --git a/src/openvic-simulation/GameManager.cpp b/src/openvic-simulation/GameManager.cpp
index e314593..249808d 100644
--- a/src/openvic-simulation/GameManager.cpp
+++ b/src/openvic-simulation/GameManager.cpp
@@ -1,7 +1,5 @@
#include "GameManager.hpp"
-#include "openvic-simulation/utility/Logger.hpp"
-
using namespace OpenVic;
GameManager::GameManager(state_updated_func_t state_updated_callback)
@@ -56,6 +54,14 @@ IssueManager const& GameManager::get_issue_manager() const {
return issue_manager;
}
+ProductionTypeManager& GameManager::get_production_type_manager() {
+ return production_type_manager;
+}
+
+ProductionTypeManager const& GameManager::get_production_type_manager() const {
+ return production_type_manager;
+}
+
UnitManager& GameManager::get_unit_manager() {
return unit_manager;
}
diff --git a/src/openvic-simulation/GameManager.hpp b/src/openvic-simulation/GameManager.hpp
index 9d0c6cd..eb73331 100644
--- a/src/openvic-simulation/GameManager.hpp
+++ b/src/openvic-simulation/GameManager.hpp
@@ -9,6 +9,7 @@
#include "openvic-simulation/economy/Good.hpp"
#include "openvic-simulation/map/Map.hpp"
#include "openvic-simulation/units/Unit.hpp"
+#include "openvic-simulation/economy/ProductionType.hpp"
namespace OpenVic {
struct GameManager {
@@ -21,6 +22,7 @@ namespace OpenVic {
PopManager pop_manager;
IdeologyManager ideology_manager;
IssueManager issue_manager;
+ ProductionTypeManager production_type_manager;
UnitManager unit_manager;
GameAdvancementHook clock;
@@ -48,6 +50,8 @@ namespace OpenVic {
IdeologyManager const& get_ideology_manager() const;
IssueManager& get_issue_manager();
IssueManager const& get_issue_manager() const;
+ ProductionTypeManager& get_production_type_manager();
+ ProductionTypeManager const& get_production_type_manager() const;
UnitManager& get_unit_manager();
UnitManager const& get_unit_manager() const;
GameAdvancementHook& get_clock();
diff --git a/src/openvic-simulation/dataloader/Dataloader.cpp b/src/openvic-simulation/dataloader/Dataloader.cpp
index 4ff190f..6396967 100644
--- a/src/openvic-simulation/dataloader/Dataloader.cpp
+++ b/src/openvic-simulation/dataloader/Dataloader.cpp
@@ -266,6 +266,7 @@ bool Dataloader::load_defines(GameManager& game_manager) const {
static const fs::path religion_file = "common/religion.txt";
static const fs::path ideology_file = "common/ideologies.txt";
static const fs::path issues_file = "common/issues.txt";
+ static const fs::path production_types_file = "common/production_types.txt";
static const fs::path map_directory = "map";
static const fs::path units_directory = "units";
@@ -299,6 +300,12 @@ bool Dataloader::load_defines(GameManager& game_manager) const {
Logger::error("Failed to load issues!");
ret = false;
}
+ if (!game_manager.get_production_type_manager().load_production_types_file(
+ game_manager.get_good_manager(), game_manager.get_pop_manager(),
+ _parse_defines(lookup_file(production_types_file)).get_file_node())) {
+ Logger::error("Failed to load production types!");
+ ret = false;
+ }
if (!_load_units(game_manager, units_directory)) {
Logger::error("Failed to load units!");
ret = false;
diff --git a/src/openvic-simulation/economy/ProductionType.cpp b/src/openvic-simulation/economy/ProductionType.cpp
new file mode 100644
index 0000000..4ea7967
--- /dev/null
+++ b/src/openvic-simulation/economy/ProductionType.cpp
@@ -0,0 +1,277 @@
+#include "ProductionType.hpp"
+#include <string_view>
+#include "dataloader/NodeTools.hpp"
+#include "openvic-dataloader/v2script/AbstractSyntaxTree.hpp"
+#include "pop/Pop.hpp"
+#include "utility/Logger.hpp"
+
+using namespace OpenVic;
+using namespace OpenVic::NodeTools;
+
+EmployedPop::EmployedPop(PopType const* pop_type, bool artisan, effect_t effect, fixed_point_t effect_multiplier, fixed_point_t amount)
+ : pop_type { pop_type }, artisan { artisan }, effect { effect }, effect_multiplier { effect_multiplier }, amount { amount } {}
+
+PopType const* EmployedPop::get_pop_type() {
+ return pop_type;
+}
+
+bool EmployedPop::is_artisan() {
+ return artisan;
+}
+
+EmployedPop::effect_t EmployedPop::get_effect() {
+ return effect;
+}
+
+fixed_point_t EmployedPop::get_effect_multiplier() {
+ return effect_multiplier;
+}
+
+fixed_point_t EmployedPop::get_amount() {
+ return amount;
+}
+
+ProductionType::ProductionType(ARGS(type_t, const Good*)) : HasIdentifier { identifier }, owner { owner },
+ employees { employees }, type { type }, workforce { workforce }, input_goods { input_goods }, output_goods { output_goods },
+ value { value }, bonuses { bonuses }, efficiency { efficiency }, coastal { coastal }, farm { farm }, mine { mine } {}
+
+EmployedPop const& ProductionType::get_owner() const {
+ return owner;
+}
+
+std::vector<EmployedPop> const& ProductionType::get_employees() const {
+ return employees;
+}
+
+ProductionType::type_t ProductionType::get_type() const {
+ return type;
+}
+
+size_t ProductionType::get_workforce() const {
+ return workforce;
+}
+
+std::map<const Good*, fixed_point_t> const& ProductionType::get_input_goods() {
+ return input_goods;
+}
+
+const Good* ProductionType::get_output_goods() const {
+ return output_goods;
+}
+
+fixed_point_t ProductionType::get_value() const {
+ return value;
+}
+
+std::vector<Bonus> const& ProductionType::get_bonuses() {
+ return bonuses;
+}
+
+std::map<const Good*, fixed_point_t> const& ProductionType::get_efficiency() {
+ return efficiency;
+}
+
+bool ProductionType::is_coastal() const {
+ return coastal;
+}
+
+bool ProductionType::is_farm() const {
+ return farm;
+}
+
+bool ProductionType::is_mine() const {
+ return mine;
+}
+
+ProductionTypeManager::ProductionTypeManager() : production_types { "production types" } {}
+
+node_callback_t ProductionTypeManager::_expect_employed_pop(GoodManager& good_manager, PopManager& pop_manager,
+ callback_t<EmployedPop> cb) {
+
+ return [this, &good_manager, &pop_manager, cb](ast::NodeCPtr node) -> bool {
+ std::string_view pop_type, effect;
+ fixed_point_t effect_multiplier = 1, amount = 1;
+
+ bool res = expect_dictionary_keys(
+ "poptype", ONE_EXACTLY, expect_identifier(assign_variable_callback(pop_type)),
+ "effect", ONE_EXACTLY, expect_identifier(assign_variable_callback(effect)),
+ "effect_multiplier", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(effect_multiplier)),
+ "amount", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(amount))
+ )(node);
+
+ const PopType* found_pop_type = pop_manager.get_pop_type_by_identifier(pop_type);
+ bool artisan = false;
+ if (found_pop_type == nullptr) {
+ if (pop_type == "artisan") {
+ artisan = true;
+ } else {
+ Logger::error("Found invalid pop type ", pop_type, " while parsing production types!");
+ return false;
+ }
+ }
+
+ EmployedPop::effect_t found_effect;
+ if (effect == "input") found_effect = EmployedPop::effect_t::INPUT;
+ else if (effect == "output") found_effect = EmployedPop::effect_t::OUTPUT;
+ else if (effect == "throughput") found_effect = EmployedPop::effect_t::THROUGHPUT;
+ else {
+ Logger::error("Found invalid effect ", effect, " while parsing production types!");
+ return false;
+ }
+
+ return res & cb(EmployedPop { found_pop_type, artisan, found_effect, effect_multiplier, amount });
+ };
+}
+
+node_callback_t ProductionTypeManager::_expect_employed_pop_list(GoodManager& good_manager, PopManager& pop_manager,
+ callback_t<std::vector<EmployedPop>> cb) {
+
+ return [this, &good_manager, &pop_manager, cb](ast::NodeCPtr node) -> bool {
+ std::vector<EmployedPop> employed_pops;
+ bool res = expect_list([this, &good_manager, &pop_manager, &employed_pops](ast::NodeCPtr node) -> bool {
+ EmployedPop owner;
+ bool res_partial = _expect_employed_pop(good_manager, pop_manager, assign_variable_callback(owner))(node);
+ employed_pops.push_back(owner);
+ return res_partial;
+ })(node);
+ return res & cb(employed_pops);
+ };
+}
+
+#define POPTYPE_CHECK(employed_pop) \
+ if ((employed_pop.pop_type == nullptr && !employed_pop.artisan) || (employed_pop.pop_type != nullptr && employed_pop.artisan)) {\
+ Logger::error("Invalid pop type parsed for owner of production type ", identifier, "!"); \
+ return false; \
+ }
+
+bool ProductionTypeManager::add_production_type(ARGS(std::string_view, std::string_view), GoodManager& good_manager) {
+ if (identifier.empty()) {
+ Logger::error("Invalid production type identifier - empty!");
+ return false;
+ }
+
+ ProductionType::type_t type_enum;
+ if (type == "factory") type_enum = ProductionType::type_t::FACTORY;
+ else if (type == "rgo") type_enum = ProductionType::type_t::RGO;
+ else if (type == "artisan") type_enum = ProductionType::type_t::ARTISAN;
+ else {
+ Logger::error("Bad type ", type, " for production type ", identifier, "!");
+ return false;
+ }
+
+ if (workforce == 0) {
+ Logger::error("Workforce for production type ", identifier, " was 0 or unset!");
+ return false;
+ }
+
+ if (value == 0) {
+ Logger::error("Value for production type ", identifier, " was 0 or unset!");
+ return false;
+ }
+
+ POPTYPE_CHECK(owner)
+
+ for (int i = 0; i < employees.size(); i++) {
+ POPTYPE_CHECK(employees[i])
+ }
+
+ const Good* output = good_manager.get_good_by_identifier(output_goods);
+ if (output == nullptr) {
+ Logger::error("Invalid output ", output_goods, " for production type ", identifier, "!");
+ return false;
+ }
+
+ return production_types.add_item({
+ identifier, owner, employees, type_enum, workforce, input_goods,
+ output, value, bonuses, efficiency, coastal, farm, mine
+ });
+}
+
+#define PARSE_NODE(target_node) expect_dictionary_keys(ALLOW_OTHER_KEYS, \
+ "owner", ZERO_OR_ONE, _expect_employed_pop(good_manager, pop_manager, move_variable_callback(owner)), \
+ "employees", ZERO_OR_ONE, _expect_employed_pop_list(good_manager, pop_manager, move_variable_callback(employees)), \
+ "type", ZERO_OR_ONE, expect_identifier(assign_variable_callback(type)), \
+ "workforce", ZERO_OR_ONE, expect_uint(assign_variable_callback(workforce)), \
+ "input_goods", ZERO_OR_ONE, good_manager.expect_good_decimal_map(move_variable_callback(input_goods)), \
+ "output_goods", ZERO_OR_ONE, expect_identifier(assign_variable_callback(output_goods)), \
+ "value", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(value)), \
+ "efficiency", ZERO_OR_ONE, good_manager.expect_good_decimal_map(move_variable_callback(efficiency)), \
+ "is_coastal", ZERO_OR_ONE, expect_bool(assign_variable_callback(coastal)), \
+ "farm", ZERO_OR_ONE, expect_bool(assign_variable_callback(farm)), \
+ "mine", ZERO_OR_ONE, expect_bool(assign_variable_callback(mine)) \
+ )(target_node)
+
+bool ProductionTypeManager::load_production_types_file(GoodManager& good_manager, PopManager& pop_manager, ast::NodeCPtr root) {
+ size_t expected_types = 0;
+
+ //pass 1: find and store template identifiers
+ std::set<std::string_view> templates;
+ std::map<std::string_view, std::string_view> template_target_map;
+ bool ret = expect_dictionary(
+ [this, &expected_types, &templates, &template_target_map](std::string_view key, ast::NodeCPtr value) -> bool {
+ std::string_view template_id = "";
+ bool ret = expect_dictionary_keys(ALLOW_OTHER_KEYS,
+ "template", ZERO_OR_ONE, expect_identifier(assign_variable_callback(template_id))
+ )(value);
+
+ if (!template_id.empty()) {
+ templates.emplace(template_id);
+ template_target_map.emplace(key, template_id);
+ }
+
+ expected_types++;
+
+ return ret;
+ }
+ )(root);
+
+ //pass 2: create and populate the template map
+ std::map<std::string_view, ast::NodeCPtr> template_node_map;
+ expect_dictionary(
+ [this, &expected_types, &templates, &template_node_map](std::string_view key, ast::NodeCPtr value) -> bool {
+ if (templates.contains(key)) {
+ template_node_map.emplace(key, value);
+ expected_types--;
+ }
+ return true;
+ }
+ )(root);
+
+ //pass 3: actually load production types
+ production_types.reserve(production_types.size() + expected_types);
+ ret &= expect_dictionary(
+ [this, &good_manager, &pop_manager, &template_target_map, &template_node_map](std::string_view key, ast::NodeCPtr node) -> bool {
+ if (template_node_map.contains(key))
+ return true;
+
+ EmployedPop owner;
+ std::vector<EmployedPop> employees;
+ std::string_view type, output_goods;
+ size_t workforce = 0; //0 is a meaningless value -> unset
+ std::map<const Good*, fixed_point_t> input_goods, efficiency;
+ fixed_point_t value = 0; //0 is a meaningless value -> unset
+ std::vector<Bonus> bonuses;
+ bool coastal = false, farm = false, mine = false;
+
+ bool ret = true;
+
+ //apply template first
+ if (template_target_map.contains(key)) {
+ std::string_view template_id = template_target_map[key];
+ if (template_node_map.contains(template_id)) {
+ ast::NodeCPtr template_node = template_node_map[template_id];
+ ret &= PARSE_NODE(template_node);
+ }
+ }
+
+ return ret & PARSE_NODE(node) & add_production_type(
+ key, owner, employees, type, workforce, input_goods, output_goods, value,
+ bonuses, efficiency, coastal, farm, mine, good_manager
+ );
+ }
+ )(root);
+
+ production_types.lock();
+
+ return ret;
+} \ No newline at end of file
diff --git a/src/openvic-simulation/economy/ProductionType.hpp b/src/openvic-simulation/economy/ProductionType.hpp
new file mode 100644
index 0000000..1e715d8
--- /dev/null
+++ b/src/openvic-simulation/economy/ProductionType.hpp
@@ -0,0 +1,115 @@
+#pragma once
+
+#include <string_view>
+#include <vector>
+#include <set>
+#include "openvic-simulation/economy/Good.hpp"
+#include "openvic-simulation/pop/Pop.hpp"
+#include "openvic-simulation/types/IdentifierRegistry.hpp"
+#include "openvic-simulation/types/fixed_point/FixedPoint.hpp"
+#include "openvic-simulation/dataloader/NodeTools.hpp"
+#include "openvic-dataloader/v2script/AbstractSyntaxTree.hpp"
+
+#define ARGS(enum_type, output) std::string_view identifier, EmployedPop owner, std::vector<EmployedPop> employees, enum_type type, \
+ size_t workforce, std::map<const Good*, fixed_point_t> input_goods, output output_goods, \
+ fixed_point_t value, std::vector<Bonus> bonuses, std::map<const Good*, fixed_point_t> efficiency, \
+ bool coastal, bool farm, bool mine
+
+namespace OpenVic {
+ struct ProductionTypeManager;
+
+ struct EmployedPop {
+ friend struct ProductionTypeManager;
+
+ private:
+ PopType const* pop_type; //poptype
+ bool artisan; //set by the parser if the magic "artisan" poptype is passed
+ enum struct effect_t {
+ INPUT,
+ OUTPUT,
+ THROUGHPUT
+ } effect;
+ fixed_point_t effect_multiplier;
+ fixed_point_t amount;
+
+ EmployedPop(PopType const* pop_type, bool artisan, effect_t effect, fixed_point_t effect_multiplier, fixed_point_t amount);
+
+ public:
+ EmployedPop() = default;
+
+ PopType const* get_pop_type();
+ bool is_artisan();
+ effect_t get_effect();
+ fixed_point_t get_effect_multiplier();
+ fixed_point_t get_amount();
+ };
+
+ struct Bonus {
+ //TODO: trigger condition(s)
+ const fixed_point_t value;
+ };
+
+ struct ProductionType : HasIdentifier {
+ friend struct ProductionTypeManager;
+
+ private:
+ const EmployedPop owner;
+ const std::vector<EmployedPop> employees;
+ const enum struct type_t {
+ FACTORY,
+ RGO,
+ ARTISAN
+ } type;
+ const size_t workforce;
+
+ const std::map<const Good*, fixed_point_t> input_goods; //farms generally lack this
+ const Good* output_goods;
+ const fixed_point_t value;
+ const std::vector<Bonus> bonuses; //some
+
+ const std::map<const Good*, fixed_point_t> efficiency; //some
+ const bool coastal; //is_coastal some(false)
+
+ const bool farm; //some (false)
+ const bool mine; //some (false)
+
+ ProductionType(ARGS(type_t, const Good*));
+
+ public:
+ ProductionType(ProductionType&&) = default;
+
+ EmployedPop const& get_owner() const;
+ std::vector<EmployedPop> const& get_employees() const;
+ type_t get_type() const;
+ size_t get_workforce() const;
+
+ std::map<const Good*, fixed_point_t> const& get_input_goods();
+ const Good* get_output_goods() const;
+ fixed_point_t get_value() const;
+ std::vector<Bonus> const& get_bonuses();
+
+ std::map<const Good*, fixed_point_t> const& get_efficiency();
+ bool is_coastal() const;
+
+ bool is_farm() const;
+ bool is_mine() const;
+ };
+
+ struct ProductionTypeManager {
+ private:
+ IdentifierRegistry<ProductionType> production_types;
+
+ NodeTools::node_callback_t _expect_employed_pop(GoodManager& good_manager, PopManager& pop_manager,
+ NodeTools::callback_t<EmployedPop> cb);
+ NodeTools::node_callback_t _expect_employed_pop_list(GoodManager& good_manager, PopManager& pop_manager,
+ NodeTools::callback_t<std::vector<EmployedPop>> cb);
+
+ public:
+ ProductionTypeManager();
+
+ bool add_production_type(ARGS(std::string_view, std::string_view), GoodManager& good_manager);
+ IDENTIFIER_REGISTRY_ACCESSORS(ProductionType, production_type)
+
+ bool load_production_types_file(GoodManager& good_manager, PopManager& pop_manager, ast::NodeCPtr root);
+ };
+} \ No newline at end of file