diff options
Diffstat (limited to 'extension/src/openvic-extension/GameSingleton.cpp')
-rw-r--r-- | extension/src/openvic-extension/GameSingleton.cpp | 173 |
1 files changed, 159 insertions, 14 deletions
diff --git a/extension/src/openvic-extension/GameSingleton.cpp b/extension/src/openvic-extension/GameSingleton.cpp index 2d6f784..ade6ec9 100644 --- a/extension/src/openvic-extension/GameSingleton.cpp +++ b/extension/src/openvic-extension/GameSingleton.cpp @@ -4,20 +4,12 @@ #include <openvic-simulation/utility/Logger.hpp> +#include "openvic-extension/LoadLocalisation.hpp" #include "openvic-extension/Utilities.hpp" using namespace godot; using namespace OpenVic; -TerrainVariant::TerrainVariant(const std::string_view new_identfier, - colour_t new_colour, Ref<Image> const& new_image) - : HasIdentifierAndColour { new_identfier, new_colour, true, false }, - image { new_image } {} - -Ref<Image> TerrainVariant::get_image() const { - return image; -} - GameSingleton* GameSingleton::singleton = nullptr; void GameSingleton::_bind_methods() { @@ -60,6 +52,7 @@ void GameSingleton::_bind_methods() { ClassDB::bind_static_method("GameSingleton", D_METHOD("get_province_info_province_key"), &GameSingleton::get_province_info_province_key); ClassDB::bind_static_method("GameSingleton", D_METHOD("get_province_info_region_key"), &GameSingleton::get_province_info_region_key); ClassDB::bind_static_method("GameSingleton", D_METHOD("get_province_info_life_rating_key"), &GameSingleton::get_province_info_life_rating_key); + ClassDB::bind_static_method("GameSingleton", D_METHOD("get_province_info_terrain_type_key"), &GameSingleton::get_province_info_terrain_type_key); ClassDB::bind_static_method("GameSingleton", D_METHOD("get_province_info_total_population_key"), &GameSingleton::get_province_info_total_population_key); ClassDB::bind_static_method("GameSingleton", D_METHOD("get_province_info_pop_types_key"), &GameSingleton::get_province_info_pop_types_key); ClassDB::bind_static_method("GameSingleton", D_METHOD("get_province_info_pop_ideologies_key"), &GameSingleton::get_province_info_pop_ideologies_key); @@ -81,6 +74,7 @@ void GameSingleton::_bind_methods() { "shadow_displacement", "shadow_tightness", "shadow_radius", "shadow_thickness", "trim_colour", "trim_size", "gradient_falloff", "gradient_base", "donut", "donut_inner_trim", "donut_inner_radius"), &GameSingleton::draw_pie_chart); + ClassDB::bind_static_method("GameSingleton", D_METHOD("load_image", "path"), &GameSingleton::load_image); } void GameSingleton::draw_pie_chart(Ref<Image> image, @@ -94,6 +88,10 @@ void GameSingleton::draw_pie_chart(Ref<Image> image, donut, donut_inner_trim, donut_inner_radius); } +Ref<Image> GameSingleton::load_image(String const& path) { + return load_godot_image(path); +} + GameSingleton* GameSingleton::get_singleton() { return singleton; } @@ -106,8 +104,7 @@ void GameSingleton::_on_state_updated() { /* REQUIREMENTS: * MAP-21, MAP-23, MAP-25, MAP-32, MAP-33, MAP-34 */ -GameSingleton::GameSingleton() : game_manager { [this]() { _on_state_updated(); } }, - terrain_variants { "terrain variants" } { +GameSingleton::GameSingleton() : game_manager { [this]() { _on_state_updated(); } } { ERR_FAIL_COND(singleton != nullptr); singleton = this; } @@ -147,6 +144,10 @@ StringName const& GameSingleton::get_province_info_life_rating_key() { static const StringName key = "life_rating"; return key; } +StringName const& GameSingleton::get_province_info_terrain_type_key() { + static const StringName key = "terrain_type"; + return key; +} StringName const& GameSingleton::get_province_info_total_population_key() { static const StringName key = "total_population"; return key; @@ -231,6 +232,10 @@ Dictionary GameSingleton::get_province_info_from_index(int32_t index) const { if (rgo != nullptr) ret[get_province_info_rgo_key()] = std_to_godot_string(rgo->get_identifier()); ret[get_province_info_life_rating_key()] = province->get_life_rating(); + + TerrainType const* terrain_type = province->get_terrain_type(); + if (terrain_type != nullptr) ret[get_province_info_terrain_type_key()] = std_to_godot_string(terrain_type->get_identifier()); + ret[get_province_info_total_population_key()] = province->get_total_population(); distribution_t const& pop_types = province->get_pop_type_distribution(); if (!pop_types.empty()) ret[get_province_info_pop_types_key()] = _distribution_to_dictionary(pop_types); @@ -239,16 +244,16 @@ Dictionary GameSingleton::get_province_info_from_index(int32_t index) const { distribution_t const& cultures = province->get_culture_distribution(); if (!cultures.empty()) ret[get_province_info_pop_cultures_key()] = _distribution_to_dictionary(cultures); - std::vector<Building> const& buildings = province->get_buildings(); + std::vector<BuildingInstance> const& buildings = province->get_buildings(); if (!buildings.empty()) { Array buildings_array; buildings_array.resize(buildings.size()); for (size_t idx = 0; idx < buildings.size(); ++idx) { - Building const& building = buildings[idx]; + BuildingInstance const& building = buildings[idx]; Dictionary building_dict; building_dict[get_building_info_building_key()] = std_to_godot_string(building.get_identifier()); - building_dict[get_building_info_level_key()] = static_cast<int32_t>(building.get_level()); + building_dict[get_building_info_level_key()] = static_cast<int32_t>(building.get_current_level()); building_dict[get_building_info_expansion_state_key()] = static_cast<int32_t>(building.get_expansion_state()); building_dict[get_building_info_start_date_key()] = std_to_godot_string(building.get_start_date().to_string()); building_dict[get_building_info_end_date_key()] = std_to_godot_string(building.get_end_date().to_string()); @@ -388,3 +393,143 @@ String GameSingleton::get_longform_date() const { void GameSingleton::try_tick() { game_manager.get_clock().conditionallyAdvanceGame(); } + +Error GameSingleton::_load_map_images(bool flip_vertical) { + if (province_shape_texture.is_valid()) { + UtilityFunctions::push_error("Map images have already been loaded!"); + return FAILED; + } + + Error err = OK; + + const Vector2i province_dims { + static_cast<int32_t>(game_manager.get_map().get_width()), + static_cast<int32_t>(game_manager.get_map().get_height()) }; + + static constexpr int32_t GPU_DIM_LIMIT = 0x3FFF; + // For each dimension of the image, this finds the small number of equal subdivisions required get the individual texture dims under GPU_DIM_LIMIT + for (int i = 0; i < 2; ++i) + for (image_subdivisions[i] = 1; province_dims[i] / image_subdivisions[i] > GPU_DIM_LIMIT || + province_dims[i] % image_subdivisions[i] != 0; ++image_subdivisions[i]); + + Map::shape_pixel_t const* province_shape_data = game_manager.get_map().get_province_shape_image().data(); + const Vector2i divided_dims = province_dims / image_subdivisions; + Array province_shape_images; + province_shape_images.resize(image_subdivisions.x * image_subdivisions.y); + for (int32_t v = 0; v < image_subdivisions.y; ++v) { + for (int32_t u = 0; u < image_subdivisions.x; ++u) { + PackedByteArray index_data_array; + index_data_array.resize(divided_dims.x * divided_dims.y * sizeof(Map::shape_pixel_t)); + + for (int32_t y = 0; y < divided_dims.y; ++y) + memcpy(index_data_array.ptrw() + y * divided_dims.x * sizeof(Map::shape_pixel_t), + province_shape_data + (v * divided_dims.y + y) * province_dims.x + u * divided_dims.x, + divided_dims.x * sizeof(Map::shape_pixel_t)); + + const Ref<Image> province_shape_subimage = Image::create_from_data(divided_dims.x, divided_dims.y, false, Image::FORMAT_RGB8, index_data_array); + if (province_shape_subimage.is_null()) { + UtilityFunctions::push_error("Failed to create province shape image (", u, ", ", v, ")"); + err = FAILED; + } + province_shape_images[u + v * image_subdivisions.x] = province_shape_subimage; + } + } + + province_shape_texture.instantiate(); + if (province_shape_texture->create_from_images(province_shape_images) != OK) { + UtilityFunctions::push_error("Failed to create terrain texture array!"); + err = FAILED; + } + + if (_update_colour_image() != OK) err = FAILED; + + return err; +} + +Error GameSingleton::_load_terrain_variants_compatibility_mode(String const& terrain_texturesheet_path) { + static constexpr int32_t SHEET_DIMS = 8, SHEET_SIZE = SHEET_DIMS * SHEET_DIMS; + + // Load the terrain texture sheet and prepare to slice it up + Ref<Image> terrain_sheet = load_godot_image(terrain_texturesheet_path); + if (terrain_sheet.is_null()) { + UtilityFunctions::push_error("Failed to load terrain texture sheet: ", terrain_texturesheet_path); + return FAILED; + } + terrain_sheet->flip_y(); + const int32_t sheet_width = terrain_sheet->get_width(), sheet_height = terrain_sheet->get_height(); + if (sheet_width < 1 || sheet_width % SHEET_DIMS != 0 || sheet_width != sheet_height) { + UtilityFunctions::push_error("Invalid terrain texture sheet dims: ", sheet_width, "x", sheet_height, " (must be square with dims positive multiples of ", SHEET_DIMS, ")"); + return FAILED; + } + const int32_t slice_size = sheet_width / SHEET_DIMS; + + Array terrain_images; + { + static constexpr colour_t TERRAIN_WATER_INDEX_COLOUR = 0xFFFFFF; + Ref<Image> water_image = Image::create(slice_size, slice_size, false, terrain_sheet->get_format()); + ERR_FAIL_NULL_V_EDMSG(water_image, FAILED, "Failed to create water terrain image"); + water_image->fill({ 0.1f, 0.1f, 0.5f }); + terrain_images.append(water_image); + } + Error err = OK; + for (int32_t idx = 0; idx < SHEET_SIZE; ++idx) { + const Rect2i slice { (idx % SHEET_DIMS) * slice_size, (7 - (idx / SHEET_DIMS)) * slice_size, slice_size, slice_size }; + const Ref<Image> terrain_image = terrain_sheet->get_region(slice); + if (terrain_image.is_null() || terrain_image->is_empty()) { + UtilityFunctions::push_error("Failed to extract terrain texture slice ", slice, " from ", terrain_texturesheet_path); + err = FAILED; + } + terrain_images.append(terrain_image); + } + + terrain_texture.instantiate(); + if (terrain_texture->create_from_images(terrain_images) != OK) { + UtilityFunctions::push_error("Failed to create terrain texture array!"); + return FAILED; + } + return err; +} + +Error GameSingleton::load_defines_compatibility_mode(PackedStringArray const& file_paths) { + static const fs::path terrain_texture_file = "map/terrain/texturesheet.tga"; + + Dataloader::path_vector_t roots; + for (String const& path : file_paths) { + roots.push_back(godot_to_std_string(path)); + } + + Error err = OK; + + if (!dataloader.set_roots(roots)) { + Logger::error("Failed to set dataloader roots!"); + err = FAILED; + } + if (!dataloader.load_defines(game_manager)) { + UtilityFunctions::push_error("Failed to load defines!"); + err = FAILED; + } + if (_load_terrain_variants_compatibility_mode( + std_to_godot_string(dataloader.lookup_file(terrain_texture_file).string()) + ) != OK) { + UtilityFunctions::push_error("Failed to load terrain variants!"); + err = FAILED; + } + if (_load_map_images(true) != OK) { + UtilityFunctions::push_error("Failed to load map images!"); + err = FAILED; + } + if (!game_manager.load_hardcoded_defines()) { + UtilityFunctions::push_error("Failed to hardcoded defines!"); + err = FAILED; + } + if (!dataloader.load_localisation_files(LoadLocalisation::add_message)) { + UtilityFunctions::push_error("Failed to load localisation!"); + err = FAILED; + } + + return err; +} + +String GameSingleton::lookup_file(String const& path) const { + return std_to_godot_string(dataloader.lookup_file(godot_to_std_string(path)).string()); +} |