Skip to content

Commit 82757cf

Browse files
authored
Merge pull request #661 from OpenVicProject/fix_province_number_mess
Fix province number vs index issues
2 parents d0b3fcb + 765363a commit 82757cf

File tree

5 files changed

+72
-52
lines changed

5 files changed

+72
-52
lines changed

src/openvic-simulation/map/MapDefinition.cpp

Lines changed: 54 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include <algorithm>
77
#include <cstddef>
88
#include <cstdint>
9+
#include <limits>
910
#include <system_error>
1011
#include <vector>
1112

@@ -21,6 +22,7 @@
2122
#include "openvic-simulation/modifier/ModifierManager.hpp"
2223
#include "openvic-simulation/types/Colour.hpp"
2324
#include "openvic-simulation/types/OrderedContainersMath.hpp"
25+
#include "openvic-simulation/types/TypedSpan.hpp"
2426
#include "openvic-simulation/types/Vector.hpp"
2527
#include "openvic-simulation/utility/BMP.hpp"
2628
#include "openvic-simulation/utility/FormatValidate.hpp"
@@ -48,11 +50,14 @@ ProvinceDefinition const* MapDefinition::get_province_definition_from_number(
4850
RiverSegment::RiverSegment(uint8_t new_size, memory::vector<ivec2_t>&& new_points)
4951
: size { new_size }, points { std::move(new_points) } {}
5052

53+
//1 entry reserved for null province
54+
static constexpr province_index_t MAX_PROVINCE_COUNT = std::numeric_limits<province_index_t>().max() - 1;
55+
5156
bool MapDefinition::add_province_definition(std::string_view identifier, colour_t colour) {
5257
if (province_definitions.size() >= type_safe::get(max_provinces)) {
5358
spdlog::error_s(
5459
"The map's province list is full - maximum number of provinces is {} (this can be at most {})",
55-
max_provinces, ProvinceDefinition::MAX_INDEX
60+
max_provinces, MAX_PROVINCE_COUNT
5661
);
5762
return false;
5863
}
@@ -71,24 +76,24 @@ bool MapDefinition::add_province_definition(std::string_view identifier, colour_
7176
spdlog::error_s("Invalid province colour for {} - null! ({})", identifier, colour);
7277
return false;
7378
}
74-
const ProvinceDefinition::index_t province_number = get_province_number_from_colour(colour);
75-
if (province_number != ProvinceDefinition::NULL_INDEX) {
79+
const ProvinceDefinition::province_number_t province_number = get_province_number_from_colour(colour);
80+
if (province_number != ProvinceDefinition::NULL_PROVINCE_NUMBER) {
7681
spdlog::error_s(
7782
"Duplicate province colours: {} and {}",
78-
get_province_definition_from_number(type_safe::get(province_number))->to_string(), identifier
83+
get_province_definition_from_number(province_number)->to_string(), identifier
7984
);
8085
return false;
8186
}
8287

8388
if (!province_definitions.emplace_item(
8489
identifier,
85-
identifier, colour, ProvinceDefinition::index_t(get_province_definition_count())
90+
identifier, colour, province_index_t(get_province_definition_count())
8691
)) {
8792
return false;
8893
}
8994

9095
ProvinceDefinition const& new_province = province_definitions.back();
91-
colour_index_map[new_province.get_colour()] = ProvinceDefinition::index_t(new_province.get_province_number());
96+
colour_index_map[new_province.get_colour()] = province_index_t(new_province.get_province_number());
9297
return true;
9398
}
9499

@@ -468,34 +473,42 @@ bool MapDefinition::add_region(std::string_view identifier, memory::vector<Provi
468473
return ret;
469474
}
470475

471-
ProvinceDefinition::index_t MapDefinition::get_province_number_from_colour(colour_t colour) const {
476+
ProvinceDefinition::province_number_t MapDefinition::get_province_number_from_colour(colour_t colour) const {
472477
const colour_index_map_t::const_iterator it = colour_index_map.find(colour);
473478
if (it != colour_index_map.end()) {
474-
return it->second;
479+
return ProvinceDefinition::get_province_number_from_index(it.value());
475480
}
476-
return ProvinceDefinition::NULL_INDEX;
481+
return ProvinceDefinition::NULL_PROVINCE_NUMBER;
477482
}
478483

479-
ProvinceDefinition::index_t MapDefinition::get_province_number_at(ivec2_t pos) const {
484+
ProvinceDefinition::province_number_t MapDefinition::get_province_number_at(ivec2_t pos) const {
480485
if (pos.nonnegative() && pos.is_within_bound(dims)) {
481486
return province_shape_image[get_pixel_index_from_pos(pos)].province_number;
482487
}
483-
return ProvinceDefinition::NULL_INDEX;
488+
return ProvinceDefinition::NULL_PROVINCE_NUMBER;
484489
}
485490

486491
ProvinceDefinition* MapDefinition::get_province_definition_at(ivec2_t pos) {
487-
return get_province_definition_from_number(type_safe::get(get_province_number_at(pos)));
492+
return get_province_definition_from_number(get_province_number_at(pos));
488493
}
489494

490495
ProvinceDefinition const* MapDefinition::get_province_definition_at(ivec2_t pos) const {
491-
return get_province_definition_from_number(type_safe::get(get_province_number_at(pos)));
496+
return get_province_definition_from_number(get_province_number_at(pos));
492497
}
493498

494-
bool MapDefinition::set_max_provinces(ProvinceDefinition::index_t new_max_provinces) {
495-
if (new_max_provinces <= ProvinceDefinition::NULL_INDEX) {
499+
bool MapDefinition::set_max_provinces(province_index_t new_max_provinces) {
500+
if (new_max_provinces <= province_index_t(0)) {
501+
spdlog::error_s(
502+
"Trying to set max province count to an invalid value {} (must be greater than 0)",
503+
new_max_provinces
504+
);
505+
return false;
506+
}
507+
if (new_max_provinces > MAX_PROVINCE_COUNT) {
496508
spdlog::error_s(
497-
"Trying to set max province count to an invalid value {} (must be greater than {})",
498-
new_max_provinces, ProvinceDefinition::NULL_INDEX
509+
"Trying to set max province count to an invalid value {} (must <= {})",
510+
new_max_provinces,
511+
MAX_PROVINCE_COUNT
499512
);
500513
return false;
501514
}
@@ -847,19 +860,22 @@ bool MapDefinition::load_map_images(fs::path const& province_path, fs::path cons
847860
uint8_t const* province_data = province_bmp.get_pixel_data().data();
848861
uint8_t const* terrain_data = terrain_bmp.get_pixel_data().data();
849862

850-
memory::vector<fixed_point_map_t<TerrainType const*>> terrain_type_pixels_list(province_definitions.size());
863+
memory::FixedVector<fixed_point_map_t<TerrainType const*>> _terrain_type_pixels_list(province_definitions.size());
864+
TypedSpan<province_index_t, fixed_point_map_t<TerrainType const*>> terrain_type_pixels_list { _terrain_type_pixels_list };
851865

852866
bool ret = true;
853867
ordered_set<colour_t> unrecognised_province_colours;
854868

855-
memory::vector<fixed_point_t> pixels_per_province(province_definitions.size());
856-
memory::vector<fvec2_t> pixel_position_sum_per_province(province_definitions.size());
869+
memory::FixedVector<fixed_point_t> _pixels_per_province(province_definitions.size());
870+
TypedSpan<province_index_t, fixed_point_t> pixels_per_province { _pixels_per_province };
871+
memory::FixedVector<fvec2_t> _pixel_position_sum_per_province(province_definitions.size());
872+
TypedSpan<province_index_t, fvec2_t> pixel_position_sum_per_province { _pixel_position_sum_per_province };
857873

858874
for (ivec2_t pos {}; pos.y < get_height(); ++pos.y) {
859875
for (pos.x = 0; pos.x < get_width(); ++pos.x) {
860876
const size_t pixel_index = get_pixel_index_from_pos(pos);
861877
const colour_t province_colour = colour_at(province_data, pixel_index);
862-
ProvinceDefinition::index_t province_number = ProvinceDefinition::NULL_INDEX;
878+
ProvinceDefinition::province_number_t province_number = ProvinceDefinition::NULL_PROVINCE_NUMBER;
863879

864880
if (pos.x > 0) {
865881
const size_t jdx = pixel_index - 1;
@@ -879,7 +895,7 @@ bool MapDefinition::load_map_images(fs::path const& province_path, fs::path cons
879895

880896
province_number = get_province_number_from_colour(province_colour);
881897

882-
if (province_number == ProvinceDefinition::NULL_INDEX && !unrecognised_province_colours.contains(province_colour)) {
898+
if (province_number == ProvinceDefinition::NULL_PROVINCE_NUMBER && !unrecognised_province_colours.contains(province_colour)) {
883899
unrecognised_province_colours.insert(province_colour);
884900
if (detailed_errors) {
885901
spdlog::warn_s(
@@ -892,17 +908,18 @@ bool MapDefinition::load_map_images(fs::path const& province_path, fs::path cons
892908
index_found:
893909
province_shape_image[pixel_index].province_number = province_number;
894910

895-
if (province_number != ProvinceDefinition::NULL_INDEX) {
896-
const ProvinceDefinition::index_t array_index = province_number - 1;
897-
pixels_per_province[type_safe::get(array_index)]++;
898-
pixel_position_sum_per_province[type_safe::get(array_index)] += static_cast<fvec2_t>(pos);
911+
if (province_number != ProvinceDefinition::NULL_PROVINCE_NUMBER) {
912+
const province_index_t province_index = ProvinceDefinition::get_index_from_province_number(province_number);
913+
pixels_per_province[province_index]++;
914+
pixel_position_sum_per_province[province_index] += static_cast<fvec2_t>(pos);
899915
}
900916

901917
const TerrainTypeMapping::index_t terrain = terrain_data[pixel_index];
902918
TerrainTypeMapping const* mapping = terrain_type_manager.get_terrain_type_mapping_for(terrain);
903919
if (mapping != nullptr) {
904-
if (province_number != ProvinceDefinition::NULL_INDEX) {
905-
terrain_type_pixels_list[type_safe::get(province_number - 1)][&mapping->type]++;
920+
if (province_number != ProvinceDefinition::NULL_PROVINCE_NUMBER) {
921+
const province_index_t province_index = ProvinceDefinition::get_index_from_province_number(province_number);
922+
terrain_type_pixels_list[province_index][&mapping->type]++;
906923
}
907924
if (mapping->has_texture && terrain < terrain_type_manager.get_terrain_texture_limit()) {
908925
province_shape_image[pixel_index].terrain = terrain + 1;
@@ -920,21 +937,20 @@ bool MapDefinition::load_map_images(fs::path const& province_path, fs::path cons
920937
}
921938

922939
size_t missing = 0;
923-
for (size_t array_index = 0; array_index < province_definitions.size(); ++array_index) {
924-
ProvinceDefinition* province = province_definitions.get_item_by_index(array_index);
925-
926-
fixed_point_map_t<TerrainType const*> const& terrain_type_pixels = terrain_type_pixels_list[array_index];
940+
for (ProvinceDefinition& province : province_definitions.get_items()) {
941+
const province_index_t province_index = province.index;
942+
fixed_point_map_t<TerrainType const*> const& terrain_type_pixels = terrain_type_pixels_list[province_index];
927943
const fixed_point_map_const_iterator_t<TerrainType const*> largest = get_largest_item(terrain_type_pixels);
928-
province->default_terrain_type = largest != terrain_type_pixels.end() ? largest->first : nullptr;
944+
province.default_terrain_type = largest != terrain_type_pixels.end() ? largest->first : nullptr;
929945

930-
const fixed_point_t pixel_count = pixels_per_province[array_index];
931-
province->on_map = pixel_count > 0;
946+
const fixed_point_t pixel_count = pixels_per_province[province_index];
947+
province.on_map = pixel_count > 0;
932948

933-
if (province->on_map) {
934-
province->centre = pixel_position_sum_per_province[array_index] / pixel_count;
949+
if (province.on_map) {
950+
province.centre = pixel_position_sum_per_province[province_index] / pixel_count;
935951
} else {
936952
if (detailed_errors) {
937-
spdlog::warn_s("Province missing from shape image: {}", province->to_string());
953+
spdlog::warn_s("Province missing from shape image: {}", province.to_string());
938954
}
939955
missing++;
940956
}

src/openvic-simulation/map/MapDefinition.hpp

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,10 @@ namespace OpenVic {
4040
* MAP-4
4141
*/
4242
struct MapDefinition {
43-
4443
#pragma pack(push, 1)
4544
/* Used to represent tightly packed 3-byte integer pixel information. */
4645
struct shape_pixel_t {
47-
ProvinceDefinition::index_t province_number;
46+
ProvinceDefinition::province_number_t province_number;
4847
TerrainTypeMapping::index_t terrain;
4948
};
5049
#pragma pack(pop)
@@ -67,12 +66,12 @@ namespace OpenVic {
6766
memory::vector<shape_pixel_t> PROPERTY(province_shape_image);
6867
colour_index_map_t colour_index_map;
6968

70-
ProvinceDefinition::index_t PROPERTY(max_provinces, ProvinceDefinition::MAX_INDEX);
69+
ProvinceDefinition::index_t PROPERTY(max_provinces);
7170

7271
PointMap PROPERTY_REF(path_map_land);
7372
PointMap PROPERTY_REF(path_map_sea);
7473

75-
ProvinceDefinition::index_t get_province_number_from_colour(colour_t colour) const;
74+
ProvinceDefinition::province_number_t get_province_number_from_colour(colour_t colour) const;
7675
bool _generate_standard_province_adjacencies();
7776

7877
inline constexpr int32_t get_pixel_index_from_pos(ivec2_t pos) const {
@@ -85,10 +84,10 @@ namespace OpenVic {
8584
MapDefinition();
8685

8786
ProvinceDefinition* get_province_definition_from_number(
88-
decltype(std::declval<ProvinceDefinition>().get_province_number())province_number
87+
const ProvinceDefinition::province_number_t province_number
8988
);
9089
ProvinceDefinition const* get_province_definition_from_number(
91-
decltype(std::declval<ProvinceDefinition>().get_province_number())province_number
90+
const ProvinceDefinition::province_number_t province_number
9291
) const;
9392

9493
inline constexpr int32_t get_width() const { return dims.x; }
@@ -112,7 +111,7 @@ namespace OpenVic {
112111
size_t get_land_province_count() const;
113112
size_t get_water_province_count() const;
114113

115-
ProvinceDefinition::index_t get_province_number_at(ivec2_t pos) const;
114+
ProvinceDefinition::province_number_t get_province_number_at(ivec2_t pos) const;
116115

117116
private:
118117
ProvinceDefinition* get_province_definition_at(ivec2_t pos);

src/openvic-simulation/map/Mapmode.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ bool MapmodeManager::generate_mapmode_colours(
8888

8989
Mapmode::base_stripe_t* target_stripes = reinterpret_cast<Mapmode::base_stripe_t*>(target);
9090

91-
target_stripes[type_safe::get(ProvinceDefinition::NULL_INDEX)] = colour_argb_t::null();
91+
target_stripes[ProvinceDefinition::NULL_PROVINCE_NUMBER] = colour_argb_t::null();
9292

9393
for (ProvinceInstance const& province : map_instance.get_province_instances()) {
9494
target_stripes[province.province_definition.get_province_number()] = mapmode->get_base_stripe_colours(

src/openvic-simulation/map/Mapmode.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,8 @@ namespace OpenVic {
7070
/* The mapmode colour image contains of a list of base colours and stripe colours. Each colour is four bytes
7171
* in RGBA format, with the alpha value being used to interpolate with the terrain colour, so A = 0 is fully terrain
7272
* and A = 255 is fully the RGB colour packaged with A. The base and stripe colours for each province are packed
73-
* together adjacently, so each province's entry is 8 bytes long. The list contains ProvinceDefinition::MAX_INDEX + 1
74-
* entries, that is the maximum allowed number of provinces plus one for the index-zero "null province". */
73+
* together adjacently, so each province's entry is 8 bytes long.
74+
* The list contains all provinces indexed by their number + index 0 for the "null province". */
7575
bool generate_mapmode_colours(
7676
MapInstance const& map_instance, Mapmode const* mapmode,
7777
CountryInstance const* player_country, ProvinceInstance const* selected_province,

src/openvic-simulation/map/ProvinceDefinition.hpp

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "openvic-simulation/types/TypedIndices.hpp"
1313
#include "openvic-simulation/types/Vector.hpp"
1414
#include "openvic-simulation/utility/Containers.hpp"
15+
#include "type_safe/strong_typedef.hpp"
1516

1617
namespace OpenVic {
1718

@@ -84,9 +85,10 @@ namespace OpenVic {
8485
fixed_point_map_t<BuildingType const*> building_rotation;
8586
};
8687

87-
static constexpr index_t NULL_INDEX { 0 }, MAX_INDEX = std::numeric_limits<index_t>::max();
88+
static constexpr type_safe::underlying_type<index_t> NULL_PROVINCE_NUMBER { 0 };
8889

8990
private:
91+
using province_number_t = type_safe::underlying_type<province_index_t>;
9092
/* Immutable attributes (unchanged after initial game load) */
9193
Region const* PROPERTY(region, nullptr);
9294
Climate const* PROPERTY(climate, nullptr);
@@ -114,10 +116,13 @@ namespace OpenVic {
114116
return region != nullptr;
115117
}
116118

117-
constexpr std::size_t get_province_number() const {
118-
return index.value_ + 1;
119+
constexpr province_number_t get_province_number() const {
120+
return get_province_number_from_index(index);
119121
}
120-
static constexpr index_t get_index_from_province_number(const std::size_t province_number) {
122+
static constexpr province_number_t get_province_number_from_index(const province_index_t index) {
123+
return type_safe::get(index) + 1;
124+
}
125+
static constexpr index_t get_index_from_province_number(const province_number_t province_number) {
121126
return index_t(province_number - 1);
122127
}
123128

0 commit comments

Comments
 (0)