aboutsummaryrefslogtreecommitdiff
path: root/src/openvic-simulation/map/TerrainType.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/openvic-simulation/map/TerrainType.cpp')
-rw-r--r--src/openvic-simulation/map/TerrainType.cpp190
1 files changed, 190 insertions, 0 deletions
diff --git a/src/openvic-simulation/map/TerrainType.cpp b/src/openvic-simulation/map/TerrainType.cpp
new file mode 100644
index 0000000..8464421
--- /dev/null
+++ b/src/openvic-simulation/map/TerrainType.cpp
@@ -0,0 +1,190 @@
+#include "TerrainType.hpp"
+
+using namespace OpenVic;
+using namespace OpenVic::NodeTools;
+
+TerrainType::TerrainType(const std::string_view new_identifier, colour_t new_colour, ModifierValue&& new_values, bool new_is_water)
+ : HasIdentifierAndColour { new_identifier, new_colour, true, false }, ModifierValue { std::move(new_values) }, is_water { new_is_water } {}
+
+bool TerrainType::get_is_water() const {
+ return is_water;
+}
+
+TerrainTypeMapping::TerrainTypeMapping(const std::string_view new_identifier, TerrainType const& new_type,
+ std::vector<index_t>&& new_terrain_indicies, index_t new_priority, bool new_has_texture)
+ : HasIdentifier { new_identifier }, type { new_type }, terrain_indicies { std::move(new_terrain_indicies) },
+ priority { new_priority }, has_texture { new_has_texture } {}
+
+TerrainType const& TerrainTypeMapping::get_type() const {
+ return type;
+}
+
+std::vector<TerrainTypeMapping::index_t> const& TerrainTypeMapping::get_terrain_indicies() const {
+ return terrain_indicies;
+}
+
+TerrainTypeMapping::index_t TerrainTypeMapping::get_priority() const {
+ return priority;
+}
+
+bool TerrainTypeMapping::get_has_texture() const {
+ return has_texture;
+}
+
+TerrainTypeManager::TerrainTypeManager() : terrain_types { "terrain types" }, terrain_type_mappings { "terrain type mappings" } {}
+
+bool TerrainTypeManager::add_terrain_type(const std::string_view identifier, colour_t colour, ModifierValue&& values, bool is_water) {
+ if (identifier.empty()) {
+ Logger::error("Invalid terrain type identifier - empty!");
+ return false;
+ }
+ if (colour > MAX_COLOUR_RGB) {
+ Logger::error("Invalid terrain type colour for ", identifier, ": ", colour_to_hex_string(colour));
+ return false;
+ }
+ return terrain_types.add_item({ identifier, colour, std::move(values), is_water });
+}
+
+bool TerrainTypeManager::add_terrain_type_mapping(const std::string_view identifier, TerrainType const* type,
+ std::vector<TerrainTypeMapping::index_t>&& terrain_indicies, TerrainTypeMapping::index_t priority, bool has_texture) {
+ if (!terrain_types.is_locked()) {
+ Logger::error("Cannot register terrain type mappings until terrain types are locked!");
+ return false;
+ }
+ if (identifier.empty()) {
+ Logger::error("Invalid terrain type mapping identifier - empty!");
+ return false;
+ }
+ if (type == nullptr) {
+ Logger::error("Null terrain type for mapping ", identifier);
+ return false;
+ }
+ return terrain_type_mappings.add_item({ identifier, *type, std::move(terrain_indicies), priority, has_texture });
+}
+
+bool TerrainTypeManager::_load_terrain_type_categories(ModifierManager const& modifier_manager, ast::NodeCPtr root) {
+ const bool ret = expect_dictionary_reserve_length(terrain_types,
+ [this, &modifier_manager](std::string_view type_key, ast::NodeCPtr type_node) -> bool {
+ ModifierValue values;
+ colour_t colour = NULL_COLOUR;
+ bool is_water = false;
+ bool has_colour = false, has_is_water = false;
+ bool ret = modifier_manager.expect_modifier_value(move_variable_callback(values),
+ [&colour, &has_colour, &is_water, &has_is_water](std::string_view key, ast::NodeCPtr value) -> bool {
+ if (key == "color") {
+ if (!has_colour) {
+ has_colour = true;
+ return expect_colour(assign_variable_callback(colour))(value);
+ } else {
+ Logger::error("Duplicate terrain type colour key!");
+ return false;
+ }
+ } else if (key == "is_water") {
+ if (!has_is_water) {
+ has_is_water = true;
+ return expect_bool(assign_variable_callback(is_water))(value);
+ } else {
+ Logger::error("Duplicate terrain type is_water key!");
+ return false;
+ }
+ } else {
+ Logger::error("Invalid terrain type entry key: ", key);
+ return false;
+ }
+ }
+ )(type_node);
+ if (!has_colour) {
+ Logger::error("Terrain type missing color key: ", type_key);
+ ret = false;
+ }
+ ret &= add_terrain_type(type_key, colour, std::move(values), is_water);
+ return ret;
+ }
+ )(root);
+ terrain_types.lock();
+ return ret;
+}
+
+bool TerrainTypeManager::_load_terrain_type_mapping(std::string_view mapping_key, ast::NodeCPtr mapping_value) {
+ TerrainType const* type = nullptr;
+ std::vector<TerrainTypeMapping::index_t> terrain_indicies;
+ TerrainTypeMapping::index_t priority = 0;
+ bool has_texture = true;
+
+ bool ret = expect_dictionary_keys(
+ "type", ONE_EXACTLY, expect_terrain_type_identifier(assign_variable_callback_pointer(type)),
+ "color", ONE_EXACTLY, expect_list_reserve_length(terrain_indicies, expect_uint(
+ [&terrain_indicies](uint64_t val) -> bool {
+ if (val <= 1 << 8 * sizeof(TerrainTypeMapping::index_t)) {
+ TerrainTypeMapping::index_t index = val;
+ if (std::find(terrain_indicies.begin(), terrain_indicies.end(), index) == terrain_indicies.end()) {
+ terrain_indicies.push_back(val);
+ return true;
+ }
+ Logger::error("Repeat terrain type mapping index: ", val);
+ return false;
+ }
+ Logger::error("Index too big for terrain type mapping index: ", val);
+ return false;
+ }
+ )),
+ "priority", ZERO_OR_ONE, expect_uint(assign_variable_callback_uint("terrain type mapping priority", priority)),
+ "has_texture", ZERO_OR_ONE, expect_bool(assign_variable_callback(has_texture))
+ )(mapping_value);
+ if (has_texture) {
+ if (++terrain_texture_count == terrain_texture_limit + 1) {
+ Logger::error("More terrain textures than limit!");
+ ret = false;
+ }
+ }
+ ret &= add_terrain_type_mapping(mapping_key, type, std::move(terrain_indicies), priority, has_texture);
+ return true;
+}
+
+TerrainTypeMapping::index_t TerrainTypeManager::get_terrain_texture_limit() const {
+ return terrain_texture_limit;
+}
+
+bool TerrainTypeManager::load_terrain_types(ModifierManager const& modifier_manager, ast::NodeCPtr root) {
+ bool terrain = false, categories = false;
+ bool ret = expect_dictionary_and_length(
+ [this](size_t size) -> size_t {
+ terrain_type_mappings.reserve(size - 2);
+ return size;
+ },
+ [this, &terrain, &categories, &modifier_manager](std::string_view key, ast::NodeCPtr value) -> bool {
+ if (key == "terrain") {
+ if (!terrain) {
+ terrain = true;
+ return expect_uint(assign_variable_callback_uint("terrain texture limit", terrain_texture_limit))(value);
+ } else {
+ Logger::error("Duplicate terrain key!");
+ return false;
+ }
+ } else if (key == "categories") {
+ if (!categories) {
+ categories = true;
+ return _load_terrain_type_categories(modifier_manager, value);
+ } else {
+ Logger::error("Duplicate categories key!");
+ return false;
+ }
+ } else if (terrain && categories) {
+ return _load_terrain_type_mapping(key, value);
+ } else {
+ Logger::error("Cannot define terrain type mapping before terrain and categories keys: ", key);
+ return false;
+ }
+ }
+ )(root);
+ if (!terrain) {
+ Logger::error("Missing expected key: \"terrain\"");
+ ret = false;
+ }
+ if (!categories) {
+ Logger::error("Missing expected key: \"categories\"");
+ ret = false;
+ }
+ terrain_type_mappings.lock();
+ return ret;
+}